Reviewed the new BrowserImport service, its Chromium cookie helper, and the IPC/layer wiring against the Effect service conventions.
Service shape, module layout (Context.Service tag + inline interface, make, layer), namespace imports, and layer composition in main.ts all look correct. The findings below are about the error model: the new failure type is unstructured (reason: Schema.String) and every construction discards the underlying cause, including one that erases a structured BrowserSession error.
Posted via Macroscope — Effect Service Conventions
| … | … | @@ -0,0 +1,237 @@ | |
| 55 | + | this.name = "ChromiumCookieReadError"; | |
| 56 | + | this.failure = failure; | |
| 57 | + | } | |
| 58 | + | } | |
BrowserImport/ChromiumCookies.ts:58
This failure is translated straight into the BrowserImport service error channel, but it is a plain Error (the only one in apps/desktop/src) whose only data is a nested failure object, and readMacKeychainPassword throws it without retaining the keychain error as cause. Consider declaring it with Schema.TaggedErrorClass and flat structural attributes, e.g. reason: Schema.Literals([...]) plus cause: Schema.optional(Schema.Defect()), with message derived from reason, and pass the caught keychain error through as cause.
No longer relevant as of 58530950a4e4ec0a1743ac0ee2826ceba41af020
| … | … | @@ -0,0 +1,177 @@ | |
| 128 | + | new BrowserImportFailedError({ | |
| 129 | + | sourceId: definition.id, | |
| 130 | + | reason: cause instanceof ChromiumCookieReadError ? cause.failure.reason : "readFailed", | |
| 131 | + | }), | |
BrowserImport/BrowserImport.ts:131
The ChromiumCookieReadError (and any unexpected defect) is reduced to a reason string and the original error is dropped, so the stack and keychain details are unrecoverable. Suggest keeping it as cause alongside the structural fields, as BrowserSession does.
| 1 | catch: (cause) => |
| 2 | new BrowserImportFailedError({ |
| 3 | sourceId: definition.id, |
| 4 | reason: cause instanceof ChromiumCookieReadError ? cause.failure.reason : "readFailed", |
| 5 | cause, |
| 6 | }), |
No longer relevant as of 58530950a4e4ec0a1743ac0ee2826ceba41af020
| … | … | @@ -0,0 +1,177 @@ | |
| 137 | + | Effect.mapError( | |
| 138 | + | () => new BrowserImportFailedError({ sourceId: definition.id, reason: "readFailed" }), | |
| 139 | + | ), | |
| 140 | + | ); | |
BrowserImport/BrowserImport.ts:140
This discards a structured domain error (BrowserSessionPartitionDerivationError / BrowserSessionCreationError) and relabels it as "readFailed", which reports a cookie-read problem for a partition/session failure. Suggest preserving the upstream error as cause and using a distinct reason.
| 1 | const session = yield* browserSession.getSession(input.scope, input.persistent).pipe( |
| 2 | Effect.mapError( |
| 3 | (cause) => |
| 4 | new BrowserImportFailedError({ |
| 5 | sourceId: definition.id, |
| 6 | reason: "sessionUnavailable", |
| 7 | cause, |
| 8 | }), |
| 9 | ), |
| 10 | ); |
No longer relevant as of 58530950a4e4ec0a1743ac0ee2826ceba41af020
| … | … | @@ -0,0 +1,177 @@ | |
| 42 | + | override get message(): string { | |
| 43 | + | return `Importing cookies from ${this.sourceId} failed: ${this.reason}.`; | |
| 44 | + | } | |
| 45 | + | } | |
BrowserImport/BrowserImport.ts:45
reason: Schema.String is an unstructured attribute, and the error carries no cause, so the real failure (keychain error, session creation error, Electron rejection) is lost. Consider typing reason as a literal union and adding an optional cause; the renderer currently recovers the reason by substring-matching this message (IntegrationsSettings.tsx runImport), which is exactly the fragility a typed discriminator avoids.
| 1 | { |
| 2 | - sourceId: Schema.String, |
| 3 | - reason: Schema.String, |
| 4 | + sourceId: Schema.String, |
| 5 | + reason: Schema.Literals([ |
| 6 | + "unknownSource", |
| 7 | + "notInstalled", |
| 8 | + "needsKeychainApproval", |
| 9 | + "keychainItemMissing", |
| 10 | + "browserRunning", |
| 11 | + "unsupportedPlatform", |
| 12 | + "readFailed", |
| 13 | + "sessionUnavailable", |
| 14 | + ]), |
| 15 | + cause: Schema.optional(Schema.Defect()), |
| 16 | }, |
The "unknown source" construction below would become "unknownSource".
No longer relevant as of 58530950a4e4ec0a1743ac0ee2826ceba41af020