| ... | @@ -37,7 +37,6 @@ import { | ... | @@ -37,7 +37,6 @@ import { |
| 37 | import * as Cause from "effect/Cause"; | 37 | import * as Cause from "effect/Cause"; |
| 38 | import * as Clock from "effect/Clock"; | 38 | import * as Clock from "effect/Clock"; |
| 39 | import * as Context from "effect/Context"; | 39 | import * as Context from "effect/Context"; |
| 40 | import * as Data from "effect/Data"; | | |
| 41 | import * as DateTime from "effect/DateTime"; | 40 | import * as DateTime from "effect/DateTime"; |
| 42 | import * as Effect from "effect/Effect"; | 41 | import * as Effect from "effect/Effect"; |
| 43 | import * as Exit from "effect/Exit"; | 42 | import * as Exit from "effect/Exit"; |
| ... | @@ -432,15 +431,17 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function | ... | @@ -432,15 +431,17 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function |
| 432 | ) { | 431 | ) { |
| 433 | const tabs = yield* SynchronizedRef.get(tabsRef); | 432 | const tabs = yield* SynchronizedRef.get(tabsRef); |
| 434 | const tab = tabs.get(tabId); | 433 | const tab = tabs.get(tabId); |
| 435 | if (!tab) return yield* fail("requireWebContents", new PreviewTabNotFoundError(tabId)); | 434 | if (!tab) { |
| | 435 | return yield* fail("requireWebContents", new PreviewTabNotFoundError({ tabId })); |
| | 436 | } |
| 436 | if (tab.webContentsId == null) { | 437 | if (tab.webContentsId == null) { |
| 437 | return yield* fail("requireWebContents", new PreviewWebviewNotInitializedError(tabId)); | 438 | return yield* fail("requireWebContents", new PreviewWebviewNotInitializedError({ tabId })); |
| 438 | } | 439 | } |
| 439 | const wc = webContents.fromId(tab.webContentsId); | 440 | const wc = webContents.fromId(tab.webContentsId); |
| 440 | if (!wc) { | 441 | if (!wc) { |
| 441 | return yield* fail( | 442 | return yield* fail( |
| 442 | "requireWebContents", | 443 | "requireWebContents", |
| 443 | new PreviewWebContentsNotFoundError(tabId, tab.webContentsId), | 444 | new PreviewWebContentsNotFoundError({ tabId, webContentsId: tab.webContentsId }), |
| 444 | ); | 445 | ); |
| 445 | } | 446 | } |
| 446 | return wc; | 447 | return wc; |
| ... | @@ -845,7 +846,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function | ... | @@ -845,7 +846,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function |
| 845 | }); | 846 | }); |
| 846 | } else { | 847 | } else { |
| 847 | const error = Option.getOrNull(Cause.findErrorOption(exit.cause)); | 848 | const error = Option.getOrNull(Cause.findErrorOption(exit.cause)); |
| 848 | const underlying = error instanceof PreviewManagerError ? error.cause : error; | 849 | const underlying = isPreviewManagerError(error) ? error.cause : error; |
| 849 | const interrupted = | 850 | const interrupted = |
| 850 | underlying instanceof Error && | 851 | underlying instanceof Error && |
| 851 | underlying.name === "PreviewAutomationControlInterruptedError"; | 852 | underlying.name === "PreviewAutomationControlInterruptedError"; |
| ... | @@ -1161,7 +1162,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function | ... | @@ -1161,7 +1162,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function |
| 1161 | ) { | 1162 | ) { |
| 1162 | const tab = (yield* SynchronizedRef.get(tabsRef)).get(tabId); | 1163 | const tab = (yield* SynchronizedRef.get(tabsRef)).get(tabId); |
| 1163 | if (!tab) { | 1164 | if (!tab) { |
| 1164 | return yield* fail("registerWebview", new PreviewTabNotFoundError(tabId)); | 1165 | return yield* fail("registerWebview", new PreviewTabNotFoundError({ tabId })); |
| 1165 | } | 1166 | } |
| 1166 | const wc = webContents.fromId(webContentsId); | 1167 | const wc = webContents.fromId(webContentsId); |
| 1167 | const mainWindow = yield* Ref.get(mainWindowRef); | 1168 | const mainWindow = yield* Ref.get(mainWindowRef); |
| ... | @@ -1172,7 +1173,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function | ... | @@ -1172,7 +1173,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function |
| 1172 | ) { | 1173 | ) { |
| 1173 | return yield* fail( | 1174 | return yield* fail( |
| 1174 | "registerWebview", | 1175 | "registerWebview", |
| 1175 | new PreviewWebContentsNotFoundError(tabId, webContentsId), | 1176 | new PreviewWebContentsNotFoundError({ tabId, webContentsId }), |
| 1176 | ); | 1177 | ); |
| 1177 | } | 1178 | } |
| 1178 | const attached = yield* Ref.get(attachedRef); | 1179 | const attached = yield* Ref.get(attachedRef); |
| ... | @@ -1224,7 +1225,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function | ... | @@ -1224,7 +1225,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function |
| 1224 | ] as const; | 1225 | ] as const; |
| 1225 | }); | 1226 | }); |
| 1226 | if (Option.isNone(registration)) { | 1227 | if (Option.isNone(registration)) { |
| 1227 | return yield* fail("registerWebview", new PreviewTabNotFoundError(tabId)); | 1228 | return yield* fail("registerWebview", new PreviewTabNotFoundError({ tabId })); |
| 1228 | } | 1229 | } |
| 1229 | const { state: registered, pendingUrl } = registration.value; | 1230 | const { state: registered, pendingUrl } = registration.value; |
| 1230 | yield* emit(tabId, registered); | 1231 | yield* emit(tabId, registered); |
| ... | @@ -2200,129 +2201,131 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function | ... | @@ -2200,129 +2201,131 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function |
| 2200 | }; | 2201 | }; |
| 2201 | }); | 2202 | }); |
| 2202 | | 2203 | |
| 2203 | export class PreviewTabNotFoundError extends Error { | 2204 | export class PreviewTabNotFoundError extends Schema.TaggedErrorClass<PreviewTabNotFoundError>()( |
| 2204 | readonly tabId: string; | 2205 | "PreviewTabNotFoundError", |
| 2205 | constructor(tabId: string) { | 2206 | { tabId: Schema.String }, |
| 2206 | super(`Preview tab not found: ${tabId}`); | 2207 | ) { |
| 2207 | this.name = "PreviewTabNotFoundError"; | 2208 | override get message(): string { |
| 2208 | this.tabId = tabId; | 2209 | return `Preview tab not found: ${this.tabId}`; |
| 2209 | } | 2210 | } |
| 2210 | } | 2211 | } |
| 2211 | | 2212 | |
| 2212 | export class PreviewWebContentsNotFoundError extends Error { | 2213 | export class PreviewWebContentsNotFoundError extends Schema.TaggedErrorClass<PreviewWebContentsNotFoundError>()( |
| 2213 | readonly tabId: string; | 2214 | "PreviewWebContentsNotFoundError", |
| 2214 | readonly webContentsId: number; | 2215 | { tabId: Schema.String, webContentsId: Schema.Number }, |
| 2215 | constructor(tabId: string, webContentsId: number) { | 2216 | ) { |
| 2216 | super(`WebContents ${webContentsId} not found for preview tab ${tabId}`); | 2217 | override get message(): string { |
| 2217 | this.name = "PreviewWebContentsNotFoundError"; | 2218 | return `WebContents ${this.webContentsId} not found for preview tab ${this.tabId}`; |
| 2218 | this.tabId = tabId; | | |
| 2219 | this.webContentsId = webContentsId; | | |
| 2220 | } | 2219 | } |
| 2221 | } | 2220 | } |
| 2222 | | 2221 | |
| 2223 | export class PreviewWebviewNotInitializedError extends Error { | 2222 | export class PreviewWebviewNotInitializedError extends Schema.TaggedErrorClass<PreviewWebviewNotInitializedError>()( |
| 2224 | readonly tabId: string; | 2223 | "PreviewWebviewNotInitializedError", |
| 2225 | constructor(tabId: string) { | 2224 | { tabId: Schema.String }, |
| 2226 | super(`Preview tab "${tabId}" has no webview registered`); | 2225 | ) { |
| 2227 | this.name = "PreviewWebviewNotInitializedError"; | 2226 | override get message(): string { |
| 2228 | this.tabId = tabId; | 2227 | return `Preview tab "${this.tabId}" has no webview registered`; |
| 2229 | } | 2228 | } |
| 2230 | } | 2229 | } |
| 2231 | | 2230 | |
| 2232 | export class PreviewManagerError extends Data.TaggedError("PreviewManagerError")<{ | 2231 | export class PreviewManagerError extends Schema.TaggedErrorClass<PreviewManagerError>()( |
| 2233 | readonly operation: string; | 2232 | "PreviewManagerError", |
| 2234 | readonly cause: unknown; | 2233 | { |
| 2235 | }> { | 2234 | operation: Schema.String, |
| 2236 | override get message() { | 2235 | cause: Schema.Defect(), |
| | 2236 | }, |
| | 2237 | ) { |
| | 2238 | override get message(): string { |
| 2237 | return `Desktop preview operation failed: ${this.operation}`; | 2239 | return `Desktop preview operation failed: ${this.operation}`; |
| 2238 | } | 2240 | } |
| 2239 | } | 2241 | } |
| 2240 | | 2242 | |
| 2241 | export interface PreviewManagerShape { | 2243 | const isPreviewManagerError = Schema.is(PreviewManagerError); |
| 2242 | readonly setMainWindow: (window: BrowserWindow) => Effect.Effect<void, PreviewManagerError>; | 2244 | |
| 2243 | readonly getBrowserSession: (scope?: string) => Effect.Effect<Session, PreviewManagerError>; | 2245 | export class PreviewManager extends Context.Service< |
| 2244 | readonly isBrowserPartition: (partition: string) => boolean; | 2246 | PreviewManager, |
| 2245 | readonly createTab: (tabId: string) => Effect.Effect<PreviewTabState, PreviewManagerError>; | 2247 | { |
| 2246 | readonly closeTab: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2248 | readonly setMainWindow: (window: BrowserWindow) => Effect.Effect<void, PreviewManagerError>; |
| 2247 | readonly registerWebview: ( | 2249 | readonly getBrowserSession: (scope?: string) => Effect.Effect<Session, PreviewManagerError>; |
| 2248 | tabId: string, | 2250 | readonly isBrowserPartition: (partition: string) => boolean; |
| 2249 | webContentsId: number, | 2251 | readonly createTab: (tabId: string) => Effect.Effect<PreviewTabState, PreviewManagerError>; |
| 2250 | ) => Effect.Effect<void, PreviewManagerError>; | 2252 | readonly closeTab: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2251 | readonly navigate: (tabId: string, url: string) => Effect.Effect<void, PreviewManagerError>; | 2253 | readonly registerWebview: ( |
| 2252 | readonly goBack: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2254 | tabId: string, |
| 2253 | readonly goForward: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2255 | webContentsId: number, |
| 2254 | readonly refresh: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2256 | ) => Effect.Effect<void, PreviewManagerError>; |
| 2255 | readonly zoomIn: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2257 | readonly navigate: (tabId: string, url: string) => Effect.Effect<void, PreviewManagerError>; |
| 2256 | readonly zoomOut: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2258 | readonly goBack: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2257 | readonly resetZoom: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2259 | readonly goForward: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2258 | readonly hardReload: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2260 | readonly refresh: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2259 | readonly openDevTools: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2261 | readonly zoomIn: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2260 | readonly clearCookies: () => Effect.Effect<void, PreviewManagerError>; | 2262 | readonly zoomOut: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2261 | readonly clearCache: () => Effect.Effect<void, PreviewManagerError>; | 2263 | readonly resetZoom: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2262 | readonly getBrowserPartition: (scope?: string) => Effect.Effect<string, PreviewManagerError>; | 2264 | readonly hardReload: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2263 | readonly setAnnotationTheme: ( | 2265 | readonly openDevTools: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2264 | theme: DesktopPreviewAnnotationTheme, | 2266 | readonly clearCookies: () => Effect.Effect<void, PreviewManagerError>; |
| 2265 | ) => Effect.Effect<void, PreviewManagerError>; | 2267 | readonly clearCache: () => Effect.Effect<void, PreviewManagerError>; |
| 2266 | readonly pickElement: ( | 2268 | readonly getBrowserPartition: (scope?: string) => Effect.Effect<string, PreviewManagerError>; |
| 2267 | tabId: string, | 2269 | readonly setAnnotationTheme: ( |
| 2268 | ) => Effect.Effect<PreviewAnnotationPayload | null, PreviewManagerError>; | 2270 | theme: DesktopPreviewAnnotationTheme, |
| 2269 | readonly cancelPickElement: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2271 | ) => Effect.Effect<void, PreviewManagerError>; |
| 2270 | readonly captureScreenshot: ( | 2272 | readonly pickElement: ( |
| 2271 | tabId: string, | 2273 | tabId: string, |
| 2272 | ) => Effect.Effect<DesktopPreviewScreenshotArtifact, PreviewManagerError>; | 2274 | ) => Effect.Effect<PreviewAnnotationPayload | null, PreviewManagerError>; |
| 2273 | readonly revealArtifact: (path: string) => Effect.Effect<void, PreviewManagerError>; | 2275 | readonly cancelPickElement: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2274 | readonly copyArtifactToClipboard: (path: string) => Effect.Effect<void, PreviewManagerError>; | 2276 | readonly captureScreenshot: ( |
| 2275 | readonly startRecording: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2277 | tabId: string, |
| 2276 | readonly stopRecording: (tabId: string) => Effect.Effect<void, PreviewManagerError>; | 2278 | ) => Effect.Effect<DesktopPreviewScreenshotArtifact, PreviewManagerError>; |
| 2277 | readonly saveRecording: ( | 2279 | readonly revealArtifact: (path: string) => Effect.Effect<void, PreviewManagerError>; |
| 2278 | tabId: string, | 2280 | readonly copyArtifactToClipboard: (path: string) => Effect.Effect<void, PreviewManagerError>; |
| 2279 | mimeType: string, | 2281 | readonly startRecording: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2280 | data: Uint8Array, | 2282 | readonly stopRecording: (tabId: string) => Effect.Effect<void, PreviewManagerError>; |
| 2281 | ) => Effect.Effect<DesktopPreviewRecordingArtifact, PreviewManagerError>; | 2283 | readonly saveRecording: ( |
| 2282 | readonly automationStatus: ( | 2284 | tabId: string, |
| 2283 | tabId: string, | 2285 | mimeType: string, |
| 2284 | ) => Effect.Effect<PreviewAutomationStatus, PreviewManagerError>; | 2286 | data: Uint8Array, |
| 2285 | readonly automationSnapshot: ( | 2287 | ) => Effect.Effect<DesktopPreviewRecordingArtifact, PreviewManagerError>; |
| 2286 | tabId: string, | 2288 | readonly automationStatus: ( |
| 2287 | ) => Effect.Effect<PreviewAutomationSnapshot, PreviewManagerError>; | 2289 | tabId: string, |
| 2288 | readonly automationClick: ( | 2290 | ) => Effect.Effect<PreviewAutomationStatus, PreviewManagerError>; |
| 2289 | tabId: string, | 2291 | readonly automationSnapshot: ( |
| 2290 | input: PreviewAutomationClickInput, | 2292 | tabId: string, |
| 2291 | ) => Effect.Effect<void, PreviewManagerError>; | 2293 | ) => Effect.Effect<PreviewAutomationSnapshot, PreviewManagerError>; |
| 2292 | readonly automationType: ( | 2294 | readonly automationClick: ( |
| 2293 | tabId: string, | 2295 | tabId: string, |
| 2294 | input: PreviewAutomationTypeInput, | 2296 | input: PreviewAutomationClickInput, |
| 2295 | ) => Effect.Effect<void, PreviewManagerError>; | 2297 | ) => Effect.Effect<void, PreviewManagerError>; |
| 2296 | readonly automationPress: ( | 2298 | readonly automationType: ( |
| 2297 | tabId: string, | 2299 | tabId: string, |
| 2298 | input: PreviewAutomationPressInput, | 2300 | input: PreviewAutomationTypeInput, |
| 2299 | ) => Effect.Effect<void, PreviewManagerError>; | 2301 | ) => Effect.Effect<void, PreviewManagerError>; |
| 2300 | readonly automationScroll: ( | 2302 | readonly automationPress: ( |
| 2301 | tabId: string, | 2303 | tabId: string, |
| 2302 | input: PreviewAutomationScrollInput, | 2304 | input: PreviewAutomationPressInput, |
| 2303 | ) => Effect.Effect<void, PreviewManagerError>; | 2305 | ) => Effect.Effect<void, PreviewManagerError>; |
| 2304 | readonly automationEvaluate: ( | 2306 | readonly automationScroll: ( |
| 2305 | tabId: string, | 2307 | tabId: string, |
| 2306 | input: PreviewAutomationEvaluateInput, | 2308 | input: PreviewAutomationScrollInput, |
| 2307 | ) => Effect.Effect<unknown, PreviewManagerError>; | 2309 | ) => Effect.Effect<void, PreviewManagerError>; |
| 2308 | readonly automationWaitFor: ( | 2310 | readonly automationEvaluate: ( |
| 2309 | tabId: string, | 2311 | tabId: string, |
| 2310 | input: PreviewAutomationWaitForInput, | 2312 | input: PreviewAutomationEvaluateInput, |
| 2311 | ) => Effect.Effect<void, PreviewManagerError>; | 2313 | ) => Effect.Effect<unknown, PreviewManagerError>; |
| 2312 | readonly subscribeStateChanges: (listener: Listener) => Effect.Effect<void, never, Scope.Scope>; | 2314 | readonly automationWaitFor: ( |
| 2313 | readonly subscribePointerEvents: ( | 2315 | tabId: string, |
| 2314 | listener: PointerEventListener, | 2316 | input: PreviewAutomationWaitForInput, |
| 2315 | ) => Effect.Effect<void, never, Scope.Scope>; | 2317 | ) => Effect.Effect<void, PreviewManagerError>; |
| 2316 | readonly subscribeRecordingFrames: ( | 2318 | readonly subscribeStateChanges: (listener: Listener) => Effect.Effect<void, never, Scope.Scope>; |
| 2317 | listener: RecordingFrameListener, | 2319 | readonly subscribePointerEvents: ( |
| 2318 | ) => Effect.Effect<void, never, Scope.Scope>; | 2320 | listener: PointerEventListener, |
| 2319 | } | 2321 | ) => Effect.Effect<void, never, Scope.Scope>; |
| 2320 | | 2322 | readonly subscribeRecordingFrames: ( |
| 2321 | export class PreviewManager extends Context.Service<PreviewManager, PreviewManagerShape>()( | 2323 | listener: RecordingFrameListener, |
| 2322 | "@t3tools/desktop/preview/Manager/PreviewManager", | 2324 | ) => Effect.Effect<void, never, Scope.Scope>; |
| 2323 | ) {} | 2325 | } |
| | 2326 | >()("@t3tools/desktop/preview/Manager/PreviewManager") {} |
| 2324 | | 2327 | |
| 2325 | const make = Effect.gen(function* PreviewManagerMake() { | 2328 | export const make = Effect.gen(function* PreviewManagerMake() { |
| 2326 | const environment = yield* DesktopEnvironment.DesktopEnvironment; | 2329 | const environment = yield* DesktopEnvironment.DesktopEnvironment; |
| 2327 | const browserSession = yield* BrowserSession.BrowserSession; | 2330 | const browserSession = yield* BrowserSession.BrowserSession; |
| 2328 | const operations = yield* makeNativeOperations(environment.browserArtifactsDir); | 2331 | const operations = yield* makeNativeOperations(environment.browserArtifactsDir); |