effect-browser 0.2.0-beta.6 → 0.2.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +507 -130
  2. package/dist/Browser-n-bKgBNN.d.mts +372 -0
  3. package/dist/Browser.d.mts +3 -189
  4. package/dist/Browser.mjs +9 -1
  5. package/dist/Browser.mjs.map +1 -1
  6. package/dist/{BrowserData-DPh3Oaof.d.mts → BrowserData-CPIIIHol.d.mts} +84 -10
  7. package/dist/BrowserData.d.mts +2 -2
  8. package/dist/BrowserData.mjs +106 -7
  9. package/dist/BrowserData.mjs.map +1 -1
  10. package/dist/{BrowserRuntime-BBAjpVFa.d.mts → BrowserRuntime-CFe9uUTv.d.mts} +16 -11
  11. package/dist/{BrowserRuntime-DImn_Oe_.mjs → BrowserRuntime-HJ1yYlFS.mjs} +4977 -4134
  12. package/dist/BrowserRuntime-HJ1yYlFS.mjs.map +1 -0
  13. package/dist/BrowserRuntime.d.mts +2 -2
  14. package/dist/BrowserRuntime.mjs +2 -1
  15. package/dist/Capture.d.mts +9 -7
  16. package/dist/Capture.mjs +157 -32
  17. package/dist/Capture.mjs.map +1 -1
  18. package/dist/{CaptureData-Dys0Ko9d.mjs → CaptureData-CYriZHX1.mjs} +25 -6
  19. package/dist/CaptureData-CYriZHX1.mjs.map +1 -0
  20. package/dist/CaptureData.d.mts +62 -3
  21. package/dist/CaptureData.mjs +2 -2
  22. package/dist/Chromium.d.mts +2 -2
  23. package/dist/Chromium.mjs +19 -10
  24. package/dist/Chromium.mjs.map +1 -1
  25. package/dist/Errors.d.mts +69 -17
  26. package/dist/Errors.mjs +57 -6
  27. package/dist/Errors.mjs.map +1 -1
  28. package/dist/Images-CaaPNeed.mjs +76 -0
  29. package/dist/Images-CaaPNeed.mjs.map +1 -0
  30. package/dist/OperationOptions-DAeRS6O9.mjs +55 -0
  31. package/dist/OperationOptions-DAeRS6O9.mjs.map +1 -0
  32. package/dist/PageControl.d.mts +6 -6
  33. package/dist/PageControl.mjs +16 -10
  34. package/dist/PageControl.mjs.map +1 -1
  35. package/dist/PageRegistry-B3q9DS3g.mjs +164 -0
  36. package/dist/PageRegistry-B3q9DS3g.mjs.map +1 -0
  37. package/dist/Plan-D8qQ48Ic.mjs +512 -0
  38. package/dist/Plan-D8qQ48Ic.mjs.map +1 -0
  39. package/dist/Plan.d.mts +3 -0
  40. package/dist/Plan.mjs +2 -0
  41. package/dist/PlanData-B668RxbQ.d.mts +4831 -0
  42. package/dist/PlanData.d.mts +3 -0
  43. package/dist/PlanData.mjs +268 -0
  44. package/dist/PlanData.mjs.map +1 -0
  45. package/dist/PlanInput-BJcPPncs.mjs +75 -0
  46. package/dist/PlanInput-BJcPPncs.mjs.map +1 -0
  47. package/dist/PublicSession-Bs61Eal8.mjs +5601 -0
  48. package/dist/PublicSession-Bs61Eal8.mjs.map +1 -0
  49. package/dist/Testing.d.mts +48 -6
  50. package/dist/Testing.mjs +675 -123
  51. package/dist/Testing.mjs.map +1 -1
  52. package/dist/Timeline-fV22Xk-S.d.mts +29 -0
  53. package/dist/Timeline.d.mts +4 -0
  54. package/dist/Timeline.mjs +20 -0
  55. package/dist/Timeline.mjs.map +1 -0
  56. package/dist/TimelineData-BsOn-YGZ.d.mts +3818 -0
  57. package/dist/TimelineData.d.mts +3 -0
  58. package/dist/TimelineData.mjs +482 -0
  59. package/dist/TimelineData.mjs.map +1 -0
  60. package/dist/index.d.mts +5 -1
  61. package/dist/index.mjs +5 -1
  62. package/package.json +17 -1
  63. package/dist/Association-BsSfBYVx.mjs +0 -138
  64. package/dist/Association-BsSfBYVx.mjs.map +0 -1
  65. package/dist/BrowserRuntime-DImn_Oe_.mjs.map +0 -1
  66. package/dist/CaptureData-Dys0Ko9d.mjs.map +0 -1
  67. package/dist/PageControlAssociation-DabEg5AR.mjs +0 -10
  68. package/dist/PageControlAssociation-DabEg5AR.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Capture.mjs","names":[],"sources":["../src/internal/capture/FrameBuffer.ts","../src/internal/capture/Capture.ts","../src/Capture.ts"],"sourcesContent":["import { CaptureMaxima } from \"./Options.ts\";\n\n/** Callback-side bounded retention. No Promise, Effect, blocked producer, or per-frame fiber. */\nexport class FrameBuffer<A extends { readonly bytes: Uint8Array }> {\n readonly maximumFrames: number;\n readonly maximumBytes: number;\n private readonly items: A[] = [];\n private retained = 0;\n dropped = 0;\n received = 0;\n highWaterBytes = 0;\n highWaterFrames = 0;\n\n constructor(maximumFrames: number, maximumBytes: number) {\n if (\n !Number.isSafeInteger(maximumFrames) ||\n maximumFrames < 1 ||\n maximumFrames > CaptureMaxima.frames ||\n !Number.isSafeInteger(maximumBytes) ||\n maximumBytes < 1 ||\n maximumBytes > 64 * 1024 * 1024\n ) {\n throw new RangeError(\"Invalid capture retention limits\");\n }\n this.maximumFrames = maximumFrames;\n this.maximumBytes = maximumBytes;\n }\n\n offer(frame: A): boolean {\n this.received++;\n if (frame.bytes.byteLength > this.maximumBytes) {\n this.dropped++;\n\n return false;\n }\n while (\n this.items.length >= this.maximumFrames ||\n this.retained + frame.bytes.byteLength > this.maximumBytes\n ) {\n const removed = this.items.shift();\n\n if (removed === undefined) break;\n this.retained -= removed.bytes.byteLength;\n this.dropped++;\n }\n this.items.push(frame);\n this.retained += frame.bytes.byteLength;\n this.highWaterBytes = Math.max(this.highWaterBytes, this.retained);\n this.highWaterFrames = Math.max(this.highWaterFrames, this.items.length);\n\n return true;\n }\n\n take(): A | undefined {\n const frame = this.items.shift();\n\n if (frame !== undefined) this.retained -= frame.bytes.byteLength;\n\n return frame;\n }\n\n clear(): void {\n this.items.length = 0;\n this.retained = 0;\n }\n\n get size(): number {\n return this.items.length;\n }\n get bytes(): number {\n return this.retained;\n }\n}\n","import { Cause, Clock, Deferred, Effect, Exit, Option, Queue, Schema, Stream } from \"effect\";\n\nimport type { Target } from \"../../BrowserData.ts\";\nimport type { CaptureInterval } from \"../../Capture.ts\";\nimport {\n CaptureSize,\n CaptureSnapshot,\n CaptureSummary,\n type CaptureOptions,\n type CapturedFrame,\n} from \"../../CaptureData.ts\";\nimport { BrowserError, Reasons } from \"../../Errors.ts\";\nimport { type CaptureLease, type CaptureParent } from \"../browser/Association.ts\";\nimport type { CaptureSource, NativeFrame } from \"../browser/Driver.ts\";\nimport { jpegGeometry } from \"../browser/Images.ts\";\nimport { FrameBuffer } from \"./FrameBuffer.ts\";\nimport { CaptureDefaults, CaptureLimits } from \"./Options.ts\";\n\nconst MaxParentCaptures = 4;\nconst MaxParentBufferedBytes = 64 * 1024 * 1024;\nconst MaxDocumentBoundaries = 64;\nconst MaxDocumentUrlLength = 8192;\n\n/** An over-long address is recorded as null rather than cut into one that was never shown. */\nconst documentUrl = (url: unknown): string | null =>\n typeof url === \"string\" && url.length <= MaxDocumentUrlLength ? url : null;\n\n/**\n * Chromium stamps a screencast frame on its UI thread, encodes it on an unsequenced thread\n * pool, and emits it when that encode completes. It admits a new frame while at most two are\n * unacknowledged (`kMaxScreencastFramesInFlight`), so up to three encode at once and two\n * frames stamped close together can complete in either order. Every frame stamped before an\n * accepted one was already in flight when that one was stamped, so at most two late frames\n * can arrive in a row. A longer run is source time that really went backwards.\n */\nconst MaxConsecutiveLateFrames = 2;\n\n// Synchronous Schema decoding at the callback boundary; no Effect/Fiber is allocated for each frame.\nconst Metadata = Schema.Struct({\n timestamp: Schema.Finite.check(Schema.isGreaterThan(0)),\n viewportWidth: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 16384 })),\n viewportHeight: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 16384 })),\n});\n\nconst decodeMetadata = Schema.decodeUnknownOption(Metadata);\n\n/** Private seam for deterministic callback/lifetime tests. The public start accepts a real live session. */\nexport const startCapture = Effect.fnUntraced(function* (\n parent: CaptureParent,\n options: CaptureOptions = {},\n) {\n const maxFrames = options.maxFrames ?? CaptureDefaults.maxFrames;\n const maxBytes = options.maxBufferedBytes ?? CaptureDefaults.maxBufferedBytes;\n const maxFrameBytes = options.maxFrameBytes ?? CaptureDefaults.maxFrameBytes;\n const duration = options.maxDurationMillis ?? CaptureDefaults.maxDurationMillis;\n const quality = options.quality ?? CaptureDefaults.quality;\n\n const size =\n options.size === undefined\n ? undefined\n : yield* Schema.decodeEffect(CaptureSize)(options.size, { onExcessProperty: \"error\" }).pipe(\n Effect.map(({ width, height }) => Object.freeze({ width, height })),\n Effect.mapError(() =>\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n }),\n ),\n );\n\n yield* Schema.decodeEffect(CaptureLimits)({\n maxFrames,\n maxBufferedBytes: maxBytes,\n maxFrameBytes,\n maxDurationMillis: duration,\n quality,\n }).pipe(\n Effect.mapError(() =>\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n }),\n ),\n );\n const clock = yield* Clock.Clock;\n const wake = yield* Queue.dropping<void>(1);\n const finished = yield* Queue.dropping<void>(1);\n const completed = yield* Deferred.make<void>();\n\n yield* Effect.addFinalizer(() =>\n Queue.shutdown(wake).pipe(Effect.andThen(Queue.shutdown(finished)), Effect.asVoid),\n );\n const buffer = new FrameBuffer<CapturedFrame>(maxFrames, maxBytes);\n let source: CaptureSource | undefined;\n let startPromise: Promise<void> | undefined;\n let startSettled = true;\n let target: Target | undefined;\n let leaseKey: string | undefined;\n\n let ended = false,\n subscribed = false,\n cleanupFinished = false;\n\n let reason = \"stopped\";\n let error: BrowserError | undefined;\n\n let received = 0,\n delivered = 0,\n rejected = 0,\n duplicates = 0,\n late = 0,\n lateRun = 0;\n\n let first: number | undefined, last: number | undefined;\n let document = 0;\n let initialUrl: string | null = null;\n let documentBoundariesTruncated = false;\n const documentBoundaries: Array<CaptureSummary[\"documentBoundaries\"][number]> = [];\n\n /** A URL change is recorded; only a new document advances the frame attribution. */\n const nextDocument = (url: string, sameDocument = false): void => {\n if (ended) return;\n if (!sameDocument) document++;\n // The latest boundaries are kept: a live consumer needs the address of what it is showing now.\n if (documentBoundaries.length >= MaxDocumentBoundaries) {\n documentBoundaries.shift();\n documentBoundariesTruncated = true;\n }\n documentBoundaries.push({\n document,\n sameDocument,\n observedMonotonicNanos: clock.monotonicTimeNanosUnsafe(),\n afterSequence: received === 0 ? null : received - 1,\n url: documentUrl(url),\n });\n };\n\n let geometry:\n | { width: number; height: number; viewportWidth: number; viewportHeight: number }\n | undefined;\n\n let nativeStop: CaptureSummary[\"nativeStop\"] = \"unconfirmed\";\n let lease: CaptureLease | undefined;\n let reservationReleased = false;\n let preStartStopConfirmed = false;\n let postStartStopStarted = false;\n\n const releaseReservation = () => {\n if (reservationReleased) return;\n reservationReleased = true;\n source?.release?.();\n if (\n leaseKey !== undefined &&\n lease !== undefined &&\n parent.captureLeases.get(leaseKey) === lease\n ) {\n parent.captureLeases.delete(leaseKey);\n parent.captureReservedBytes = Math.max(0, parent.captureReservedBytes - lease.reservedBytes);\n }\n };\n\n let confirmPostStartStop = () => {};\n\n const observeStop = (stopping: Promise<void>, afterStart: boolean) => {\n void stopping.then(\n () => {\n if (afterStart) {\n nativeStop = \"confirmed\";\n releaseReservation();\n } else {\n preStartStopConfirmed = true;\n confirmPostStartStop();\n }\n },\n () => {},\n );\n };\n\n confirmPostStartStop = () => {\n const stoppingSource = source;\n\n if (\n !preStartStopConfirmed ||\n !startSettled ||\n postStartStopStarted ||\n stoppingSource === undefined ||\n leaseKey === undefined ||\n lease === undefined ||\n parent.captureLeases.get(leaseKey) !== lease\n )\n return;\n\n postStartStopStarted = true;\n observeStop(\n Promise.resolve().then(() => stoppingSource.stop()),\n true,\n );\n };\n\n const finish = (why: string, failure?: BrowserError) => {\n if (ended) return;\n ended = true;\n reason = why;\n error = failure;\n Queue.offerUnsafe(wake, undefined);\n Queue.offerUnsafe(finished, undefined);\n };\n\n const snapshot = (): CaptureSummary => {\n if (target === undefined) throw new Error(\"Capture target was not admitted\");\n\n return CaptureSummary.make({\n target,\n reason,\n received,\n delivered,\n discarded: buffer.dropped + rejected + late + duplicates,\n overflow: buffer.dropped,\n duplicates,\n late,\n rejected,\n peakBufferedFrames: buffer.highWaterFrames,\n peakBufferedBytes: buffer.highWaterBytes,\n bufferedFrames: buffer.size,\n bufferedBytes: buffer.bytes,\n sourceFirstMillis: first ?? null,\n sourceLastMillis: last ?? null,\n initialUrl,\n documentBoundaries: documentBoundaries.map((boundary) => ({ ...boundary })),\n documentBoundariesTruncated,\n nativeStop,\n upstreamDrops: \"unknown\",\n ...(error === undefined\n ? {}\n : {\n error: BrowserError.make({\n operation: error.operation,\n reason: { ...error.reason },\n outcome: error.outcome,\n }),\n }),\n });\n };\n\n const performStop = yield* Effect.cached(\n Effect.uninterruptibleMask((restore) =>\n Effect.gen(function* () {\n finish(\"stopped\");\n // Wait for an in-flight start before stop. If it will not settle, quarantine this page lease.\n if (startPromise !== undefined && !startSettled) {\n const starting = startPromise;\n\n yield* restore(\n Effect.tryPromise({\n try: () => starting,\n catch: () =>\n BrowserError.make({\n operation: \"capture-start\",\n reason: Reasons.Provider.make({}),\n outcome: \"unknown\",\n }),\n }).pipe(Effect.timeout(2000), Effect.exit),\n );\n }\n if (source !== undefined) {\n const stopping = source;\n const afterStart = startSettled;\n const stop = Promise.resolve().then(() => stopping.stop());\n\n observeStop(stop, afterStart);\n\n const stopped = yield* restore(\n Effect.tryPromise({\n try: () => stop,\n catch: () =>\n BrowserError.make({\n operation: \"capture-stop\",\n reason: Reasons.Provider.make({}),\n outcome: \"unknown\",\n }),\n }).pipe(Effect.timeout(3000)),\n ).pipe(Effect.exit);\n\n if (Exit.isSuccess(stopped) && afterStart) {\n nativeStop = \"confirmed\";\n releaseReservation();\n }\n } else nativeStop = \"confirmed\";\n if (nativeStop === \"confirmed\") releaseReservation();\n cleanupFinished = true;\n\n return snapshot();\n }),\n ),\n );\n\n // Publish completion only after the cached cleanup Exit has settled. Publishing\n // inside it lets the caller close Scope and interrupt the caching fiber first.\n const stopNative = performStop.pipe(Effect.tap(() => Deferred.succeed(completed, undefined)));\n\n const receive = (frame: NativeFrame): void => {\n if (ended) return;\n if (\n target === undefined ||\n parent.owner.state.generation !== target.generation ||\n parent.owner.state.phase !== \"open\"\n ) {\n finish(\n \"parent-unavailable\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Closed.make({}),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n const sequence = received++;\n\n try {\n const decoded = decodeMetadata(frame);\n\n if (Option.isNone(decoded)) {\n rejected++;\n finish(\n \"malformed-frame\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Malformed.make({}),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n const meta = decoded.value;\n\n if (!(frame.data instanceof Uint8Array)) {\n rejected++;\n finish(\n \"malformed-frame\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Malformed.make({ path: \"bytes\" }),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n if (frame.data.length > maxFrameBytes) {\n rejected++;\n finish(\n \"frame-limit\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Limit.make({\n dimension: \"frame-bytes\",\n maximum: maxFrameBytes,\n observed: frame.data.length,\n }),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n if (last !== undefined && meta.timestamp < last) {\n // A newer frame is already accepted, so this one can no longer be presented in order.\n // It is discarded and counted rather than sorted in or given an invented time.\n late++;\n if (++lateRun > MaxConsecutiveLateFrames) {\n finish(\n \"timestamp-discontinuity\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Timestamp.make({}),\n outcome: \"undispatched\",\n }),\n );\n }\n\n return;\n }\n if (last === meta.timestamp) {\n duplicates++;\n\n return;\n }\n const dimensions = jpegGeometry(frame.data);\n\n if (frame.data[frame.data.length - 2] !== 255 || frame.data[frame.data.length - 1] !== 217) {\n rejected++;\n finish(\n \"malformed-frame\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Malformed.make({ path: \"bytes\" }),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n const maximumWidth = Math.min(16384, size?.width ?? 16384);\n const maximumHeight = Math.min(16384, size?.height ?? 16384);\n\n const excessive =\n dimensions.width > maximumWidth\n ? Reasons.Limit.make({\n dimension: \"width\",\n maximum: maximumWidth,\n observed: dimensions.width,\n })\n : dimensions.height > maximumHeight\n ? Reasons.Limit.make({\n dimension: \"height\",\n maximum: maximumHeight,\n observed: dimensions.height,\n })\n : dimensions.width * dimensions.height > 33_554_432\n ? Reasons.Limit.make({\n dimension: \"pixels\",\n maximum: 33_554_432,\n observed: dimensions.width * dimensions.height,\n })\n : undefined;\n\n if (excessive !== undefined) {\n rejected++;\n finish(\n \"frame-limit\",\n BrowserError.make({ operation: \"capture\", reason: excessive, outcome: \"undispatched\" }),\n );\n\n return;\n }\n if (\n geometry !== undefined &&\n (geometry.width !== dimensions.width ||\n geometry.height !== dimensions.height ||\n geometry.viewportWidth !== meta.viewportWidth ||\n geometry.viewportHeight !== meta.viewportHeight)\n ) {\n rejected++;\n finish(\n \"resized\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Resized.make({}),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n geometry ??= {\n ...dimensions,\n viewportWidth: meta.viewportWidth,\n viewportHeight: meta.viewportHeight,\n };\n first ??= meta.timestamp;\n last = meta.timestamp;\n lateRun = 0;\n buffer.offer({\n bytes: new Uint8Array(frame.data),\n mediaType: \"image/jpeg\",\n target,\n sequence,\n document,\n sourceTimeMillis: meta.timestamp,\n sourceClock: \"presentation-unix-millis\",\n receivedMonotonicNanos: clock.monotonicTimeNanosUnsafe(),\n ...dimensions,\n viewportWidth: meta.viewportWidth,\n viewportHeight: meta.viewportHeight,\n });\n Queue.offerUnsafe(wake, undefined);\n } catch {\n rejected++;\n finish(\n \"malformed-frame\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Malformed.make({}),\n outcome: \"undispatched\",\n }),\n );\n }\n };\n\n yield* parent.owner\n .guard(\n \"capture-start\",\n (ticket) =>\n Effect.gen(function* () {\n const resolved = yield* parent.resolve(ticket, options.target);\n\n // Frames and summaries share this identity with the generation guard. It must not\n // become writable through consumer-owned frame data.\n target = Object.freeze(resolved.target);\n const resolvedSource = resolved.source;\n\n source = resolvedSource;\n leaseKey = resolved.key;\n if (parent.captureLeases.has(leaseKey)) {\n return yield* BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Busy.make({}),\n outcome: \"undispatched\",\n });\n }\n if (\n parent.captureLeases.size >= MaxParentCaptures ||\n parent.captureReservedBytes + maxBytes > MaxParentBufferedBytes\n ) {\n return yield* BrowserError.make({\n operation: \"capture\",\n reason:\n parent.captureLeases.size >= MaxParentCaptures\n ? Reasons.Limit.make({\n dimension: \"captures\",\n maximum: MaxParentCaptures,\n observed: parent.captureLeases.size + 1,\n })\n : Reasons.Limit.make({\n dimension: \"buffered-bytes\",\n maximum: MaxParentBufferedBytes,\n observed: parent.captureReservedBytes + maxBytes,\n }),\n outcome: \"undispatched\",\n });\n }\n lease = {\n reservedBytes: maxBytes,\n stop: stopNative.pipe(Effect.asVoid),\n invalidate: (why) => {\n if (why === \"target-closed\") releaseReservation();\n finish(\n why === \"resized\" ? \"resized\" : \"target-changed\",\n BrowserError.make({\n operation: \"capture\",\n reason:\n why === \"resized\" ? Reasons.Resized.make({}) : Reasons.TargetChanged.make({}),\n outcome: \"undispatched\",\n }),\n );\n },\n };\n parent.captureLeases.set(leaseKey, lease);\n parent.captureReservedBytes += maxBytes;\n // Installed before native acquisition. A cancelled capture cannot escape its caller's scope.\n yield* Effect.addFinalizer(() =>\n stopNative.pipe(\n Effect.andThen(\n Effect.sync(() => {\n rejected += buffer.size;\n buffer.clear();\n }),\n ),\n ),\n );\n startSettled = false;\n yield* Effect.tryPromise({\n try: () => {\n try {\n startPromise = resolvedSource.start({\n receive,\n quality,\n invalidate: (why) => lease?.invalidate(why),\n opened: (url) => {\n initialUrl = documentUrl(url);\n },\n ...(size === undefined ? {} : { size }),\n ...(options.lifetime === \"page\" ? { document: nextDocument } : {}),\n });\n } catch (error) {\n startSettled = true;\n\n throw error;\n }\n\n const cleanupAfterLateStart = () => {\n startSettled = true;\n // A pre-start stop must settle successfully before a post-start stop is sent.\n confirmPostStartStop();\n };\n\n void startPromise.then(cleanupAfterLateStart, cleanupAfterLateStart);\n\n return startPromise;\n },\n catch: () =>\n BrowserError.make({\n operation: \"capture-start\",\n reason: Reasons.Provider.make({}),\n outcome: \"unknown\",\n }),\n });\n ticket.check();\n }),\n { charge: false },\n )\n .pipe(\n Effect.onError(() => (lease === undefined ? Effect.void : stopNative.pipe(Effect.asVoid))),\n Effect.onInterrupt(() =>\n lease === undefined ? Effect.void : stopNative.pipe(Effect.asVoid),\n ),\n );\n // One monitor, not a fiber per frame. The finalizer also calls stop directly if this monitor is interrupted.\n // The timeout and explicit-finish branches intentionally carry different\n // values before shared cleanup; preserve the proven first-completion semantics.\n // @effect-diagnostics-next-line raceFirstWithSleepToTimeout:off\n yield* Effect.raceFirst(\n Queue.take(finished).pipe(Effect.as(false)),\n Effect.sleep(duration).pipe(Effect.as(true)),\n ).pipe(\n Effect.tap((expired) => (expired ? Effect.sync(() => finish(\"duration-limit\")) : Effect.void)),\n Effect.andThen(stopNative),\n Effect.forkScoped,\n );\n\n const next: Effect.Effect<CapturedFrame, BrowserError | Cause.Done> = Effect.suspend(() => {\n const frame = buffer.take();\n\n if (frame !== undefined) {\n delivered++;\n\n return Effect.succeed(frame);\n }\n if (ended) return error === undefined ? Cause.done() : Effect.fail(error);\n\n return Queue.take(wake).pipe(Effect.andThen(next));\n });\n\n const frames = Stream.unwrap(\n Effect.suspend(() => {\n if (subscribed)\n return Effect.fail(\n BrowserError.make({\n operation: \"capture-consume\",\n reason: Reasons.Busy.make({}),\n outcome: \"undispatched\",\n }),\n );\n subscribed = true;\n\n return Effect.succeed(\n Stream.fromEffectRepeat(next).pipe(Stream.ensuring(stopNative.pipe(Effect.asVoid))),\n );\n }),\n );\n\n return {\n frames,\n snapshot: Effect.sync(() => {\n const { reason, nativeStop, ...metadata } = snapshot();\n\n return CaptureSnapshot.make({\n ...metadata,\n phase: cleanupFinished ? \"stopped\" : ended ? \"stopping\" : \"capturing\",\n observedMonotonicNanos: clock.monotonicTimeNanosUnsafe(),\n currentDocument: document,\n reason: ended ? reason : null,\n nativeStop: cleanupFinished ? nativeStop : null,\n });\n }),\n stop: stopNative,\n completed: Deferred.await(completed).pipe(Effect.map(snapshot)),\n } satisfies CaptureInterval;\n});\n","import { Crypto, Effect, type PlatformError, Schema, type Scope, Stream } from \"effect\";\n\nimport type { BrowserSession } from \"./Browser.ts\";\nimport { PageInfo } from \"./BrowserData.ts\";\nimport type {\n CapturedFrame,\n CaptureOptions,\n CaptureSnapshot,\n CaptureSummary,\n} from \"./CaptureData.ts\";\nimport { BrowserError, Reasons } from \"./Errors.ts\";\nimport { captureParent } from \"./internal/browser/Association.ts\";\nimport { startCapture } from \"./internal/capture/Capture.ts\";\n\nexport {\n CapturedFrame,\n CaptureOptions,\n CaptureSize,\n CaptureSnapshot,\n CaptureSummary,\n} from \"./CaptureData.ts\";\n\n/** Live stream/Effect capabilities intentionally have no data schema or serialization contract. */\nexport interface CaptureInterval {\n /** Single subscription. Ending or interrupting it stops this interval, not its browser. */\n readonly frames: Stream.Stream<CapturedFrame, BrowserError>;\n /**\n * A bounded copy of recorded metadata, available during capture and after cleanup. No native\n * work, budget charge or subscription. Drain frames, then read `completed` for final accounting.\n */\n readonly snapshot: Effect.Effect<CaptureSnapshot>;\n readonly stop: Effect.Effect<CaptureSummary>;\n readonly completed: Effect.Effect<CaptureSummary>;\n}\n\n/**\n * Capture one remote page independently of the session's selected page.\n *\n * Requires the exact live session returned by the host; copying a session object or decoding\n * a durable reference cannot copy its capture authority. The private owner is not frame data.\n * `CapturedFrame` and `CaptureOptions` are Schema values as well as structural types. Frame\n * decoding checks binary/metadata fields, not the complete JPEG bitstream or target authority,\n * and does not copy bytes. Options decoding preserves omissions; admission applies defaults.\n * `CaptureInterval` remains a live scoped capability, not a schema or JSON/Tool value.\n */\nexport const start = <E>(\n session: BrowserSession<E>,\n options: CaptureOptions = {},\n): Effect.Effect<CaptureInterval, BrowserError, Scope.Scope> =>\n Effect.suspend(() => {\n const parent = captureParent(session);\n\n if (parent === undefined)\n return Effect.fail(\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.UnregisteredSession.make({}),\n outcome: \"undispatched\",\n }),\n );\n if (options.target === undefined) return startCapture(parent, options);\n\n return Schema.decodeEffect(PageInfo)(options.target, { onExcessProperty: \"error\" }).pipe(\n Effect.mapError(() =>\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n }),\n ),\n Effect.flatMap((target) => startCapture(parent, { ...options, target })),\n );\n });\n\n/**\n * A lazy, scoped frame stream. Each subscription acquires one interval and finalizes it when\n * consumption ends, fails or is interrupted; the browser remains owned by its caller.\n * Concurrent subscriptions on the same page are refused by the existing capture reservation.\n * Unconfirmed native cleanup retains the page reservation. Use start when the host needs\n * explicit stop acknowledgement, interval snapshots and the final capture summary.\n */\nexport const stream = <E>(\n session: BrowserSession<E>,\n options: CaptureOptions = {},\n): Stream.Stream<CapturedFrame, BrowserError> =>\n Stream.unwrap(start(session, options).pipe(Effect.map((interval) => interval.frames)));\n\n/** A `multipart/x-mixed-replace` body and the content type that names its boundary. */\nexport interface MultipartBody<E, R> {\n readonly contentType: string;\n readonly body: Stream.Stream<Uint8Array, E, R>;\n}\n\n/**\n * Frames as motion JPEG for an `<img>`: one `multipart/x-mixed-replace` response, as WHATWG HTML\n * defines it for images. Each frame is followed at once by the next part's delimiter and headers,\n * because a browser shows a part only when it has read the headers of the one after it; without\n * that, a still page's last picture would never be shown. Parts carry no metadata, so nothing\n * but the pictures reaches a viewer. The boundary is drawn from `Crypto` for each response, so a\n * page cannot shape its pixels into it. Call it once per viewer.\n */\nexport const multipart = <E, R>(\n frames: Stream.Stream<CapturedFrame, E, R>,\n): Effect.Effect<MultipartBody<E, R>, PlatformError.PlatformError, Crypto.Crypto> =>\n Effect.map(\n Effect.flatMap(Crypto.Crypto, (crypto) => crypto.randomUUIDv4),\n (uuid) => {\n const boundary = `frame-${uuid.replaceAll(\"-\", \"\")}`;\n const encoder = new TextEncoder();\n const opening = encoder.encode(`--${boundary}\\r\\nContent-Type: image/jpeg\\r\\n\\r\\n`);\n const next = encoder.encode(`\\r\\n--${boundary}\\r\\nContent-Type: image/jpeg\\r\\n\\r\\n`);\n\n return {\n contentType: `multipart/x-mixed-replace; boundary=${boundary}`,\n body: Stream.make(opening).pipe(\n Stream.concat(frames.pipe(Stream.flatMap((frame) => Stream.make(frame.bytes, next)))),\n Stream.concat(Stream.make(encoder.encode(`--${boundary}--\\r\\n`))),\n ),\n };\n },\n );\n"],"mappings":"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"}
1
+ {"version":3,"file":"Capture.mjs","names":["Trace.span","Trace.start","Trace.stream"],"sources":["../src/internal/capture/FrameBuffer.ts","../src/internal/capture/Capture.ts","../src/Capture.ts"],"sourcesContent":["import { CaptureMaxima } from \"./Options.ts\";\n\n/** Callback-side bounded retention. No Promise, Effect, blocked producer, or per-frame fiber. */\nexport class FrameBuffer<A extends { readonly bytes: Uint8Array }> {\n readonly maximumFrames: number;\n readonly maximumBytes: number;\n private readonly items: A[] = [];\n private retained = 0;\n dropped = 0;\n received = 0;\n highWaterBytes = 0;\n highWaterFrames = 0;\n\n constructor(maximumFrames: number, maximumBytes: number) {\n if (\n !Number.isSafeInteger(maximumFrames) ||\n maximumFrames < 1 ||\n maximumFrames > CaptureMaxima.frames ||\n !Number.isSafeInteger(maximumBytes) ||\n maximumBytes < 1 ||\n maximumBytes > 64 * 1024 * 1024\n ) {\n throw new RangeError(\"Invalid capture retention limits\");\n }\n this.maximumFrames = maximumFrames;\n this.maximumBytes = maximumBytes;\n }\n\n offer(frame: A): boolean {\n this.received++;\n if (frame.bytes.byteLength > this.maximumBytes) {\n this.dropped++;\n\n return false;\n }\n while (\n this.items.length >= this.maximumFrames ||\n this.retained + frame.bytes.byteLength > this.maximumBytes\n ) {\n const removed = this.items.shift();\n\n if (removed === undefined) break;\n this.retained -= removed.bytes.byteLength;\n this.dropped++;\n }\n this.items.push(frame);\n this.retained += frame.bytes.byteLength;\n this.highWaterBytes = Math.max(this.highWaterBytes, this.retained);\n this.highWaterFrames = Math.max(this.highWaterFrames, this.items.length);\n\n return true;\n }\n\n take(): A | undefined {\n const frame = this.items.shift();\n\n if (frame !== undefined) this.retained -= frame.bytes.byteLength;\n\n return frame;\n }\n\n clear(): void {\n this.items.length = 0;\n this.retained = 0;\n }\n\n get size(): number {\n return this.items.length;\n }\n get bytes(): number {\n return this.retained;\n }\n}\n","import {\n Cause,\n Clock,\n Deferred,\n Duration,\n Effect,\n Exit,\n Option,\n Queue,\n Schema,\n Stream,\n} from \"effect\";\n\nimport type { Target } from \"../../BrowserData.ts\";\nimport type { CaptureInterval } from \"../../Capture.ts\";\nimport {\n CaptureSize,\n CaptureSnapshot,\n CaptureSummary,\n type CaptureQualification,\n type CaptureOptions,\n type CapturedFrame,\n} from \"../../CaptureData.ts\";\nimport { BrowserError, Reasons } from \"../../Errors.ts\";\nimport type { CaptureReason } from \"../../TimelineData.ts\";\nimport {\n type CaptureLease,\n type CaptureResolution,\n type CaptureMetadata,\n type PageCaptureParent,\n} from \"../browser/Association.ts\";\nimport type { CaptureSource, NativeFrame } from \"../browser/Driver.ts\";\nimport { jpegGeometry } from \"../browser/Images.ts\";\nimport * as Trace from \"../Trace.ts\";\nimport { FrameBuffer } from \"./FrameBuffer.ts\";\nimport { CaptureDefaults, CaptureLimits } from \"./Options.ts\";\n\nconst MaxParentCaptures = 4;\nconst MaxParentBufferedBytes = 64 * 1024 * 1024;\nconst MaxDocumentBoundaries = 64;\nconst MaxDocumentUrlLength = 8192;\n\n/** An over-long address is recorded as null rather than cut into one that was never shown. */\nconst documentUrl = (url: unknown): string | null =>\n typeof url === \"string\" && url.length <= MaxDocumentUrlLength ? url : null;\n\n/**\n * Chromium stamps a screencast frame on its UI thread, encodes it on an unsequenced thread\n * pool, and emits it when that encode completes. It admits a new frame while at most two are\n * unacknowledged (`kMaxScreencastFramesInFlight`), so up to three encode at once and two\n * frames stamped close together can complete in either order. Every frame stamped before an\n * accepted one was already in flight when that one was stamped, so at most two late frames\n * can arrive in a row. A longer run is source time that really went backwards.\n */\nconst MaxConsecutiveLateFrames = 2;\n\n// Synchronous Schema decoding at the callback boundary; no Effect/Fiber is allocated for each frame.\nconst Metadata = Schema.Struct({\n timestamp: Schema.Finite.check(Schema.isGreaterThan(0)),\n viewportWidth: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 16384 })),\n viewportHeight: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 16384 })),\n});\n\nconst decodeMetadata = Schema.decodeUnknownOption(Metadata);\n\n/** Private seam for deterministic callback/lifetime tests. The public start accepts a real live session. */\nconst acquireCapture = Effect.fnUntraced(function* (\n parent: PageCaptureParent,\n options: CaptureOptions = {},\n) {\n const maxFrames = options.maxFrames ?? CaptureDefaults.maxFrames;\n const maxBytes = options.maxBufferedBytes ?? CaptureDefaults.maxBufferedBytes;\n const maxFrameBytes = options.maxFrameBytes ?? CaptureDefaults.maxFrameBytes;\n const duration = options.maxDurationMillis ?? CaptureDefaults.maxDurationMillis;\n const quality = options.quality ?? CaptureDefaults.quality;\n\n const size =\n options.size === undefined\n ? undefined\n : yield* Schema.decodeEffect(CaptureSize)(options.size, { onExcessProperty: \"error\" }).pipe(\n Effect.map(({ width, height }) => Object.freeze({ width, height })),\n Effect.mapError(() =>\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n }),\n ),\n );\n\n yield* Schema.decodeEffect(CaptureLimits)({\n maxFrames,\n maxBufferedBytes: maxBytes,\n maxFrameBytes,\n maxDurationMillis: duration,\n quality,\n }).pipe(\n Effect.mapError(() =>\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n }),\n ),\n );\n let interval: Trace.Started | undefined;\n\n yield* Effect.addFinalizer((exit) => Effect.sync(() => interval?.end(exit)));\n const clock = parent.owner.clock;\n const captureId = yield* parent.newCaptureId;\n const wake = yield* Queue.dropping<void>(1);\n const finished = yield* Queue.dropping<void>(1);\n const completed = yield* Deferred.make<void>();\n\n yield* Effect.addFinalizer(() =>\n Queue.shutdown(wake).pipe(Effect.andThen(Queue.shutdown(finished)), Effect.asVoid),\n );\n const buffer = new FrameBuffer<CapturedFrame>(maxFrames, maxBytes);\n let source: CaptureSource | undefined;\n let startPromise: Promise<void> | undefined;\n let startSettled = true;\n let target: Target | undefined;\n let leaseKey: string | undefined;\n let targetStatus: CaptureResolution[\"status\"];\n let metadata: CaptureResolution[\"metadata\"];\n let terminalAuthority: \"closing\" | \"closed\" | undefined;\n\n let ended = false,\n subscribed = false,\n cleanupFinished = false;\n\n let reason: CaptureReason = \"stopped\";\n let error: BrowserError | undefined;\n\n let received = 0,\n delivered = 0,\n rejected = 0,\n duplicates = 0,\n late = 0,\n lateRun = 0;\n\n let first: number | undefined, last: number | undefined;\n let document = 0;\n let captureBoundary = 0;\n let acceptedBoundary = -1;\n let initialUrl: string | null = null;\n let initialUrlQualification: \"NativeCached\" | \"Unread\" | \"Omitted\" = \"Unread\";\n let documentBoundariesTruncated = false;\n const documentBoundaries: Array<CaptureSummary[\"documentBoundaries\"][number]> = [];\n\n /** A URL change is recorded; only a new document advances the frame attribution. */\n const nextDocument = (url: string, sameDocument = false): void => {\n if (ended) return;\n captureBoundary++;\n if (!sameDocument) document++;\n // The latest boundaries are kept: a live consumer needs the address of what it is showing now.\n if (documentBoundaries.length >= MaxDocumentBoundaries) {\n documentBoundaries.shift();\n documentBoundariesTruncated = true;\n }\n\n const boundary = {\n document,\n sameDocument,\n observedMonotonicNanos: clock.monotonicTimeNanosUnsafe(),\n afterSequence: received === 0 ? null : received - 1,\n url: documentUrl(url),\n };\n\n documentBoundaries.push(boundary);\n if (target !== undefined)\n metadata?.({\n _tag: \"CaptureBoundary\",\n captureId,\n target,\n captureBoundary,\n captureDocument: document,\n sameDocument: boundary.sameDocument,\n observedMonotonicNanos: boundary.observedMonotonicNanos,\n afterSequence: boundary.afterSequence,\n url: boundary.url,\n urlQualification: boundary.url === null ? \"Omitted\" : \"NativeCached\",\n });\n };\n\n let geometry:\n | { width: number; height: number; viewportWidth: number; viewportHeight: number }\n | undefined;\n\n let nativeStop: CaptureSummary[\"nativeStop\"] = \"unconfirmed\";\n let lease: CaptureLease | undefined;\n let reservationReleased = false;\n let preStartStopConfirmed = false;\n let postStartStopStarted = false;\n\n const releaseReservation = () => {\n if (reservationReleased) return;\n reservationReleased = true;\n source?.release?.();\n if (\n leaseKey !== undefined &&\n lease !== undefined &&\n parent.captureLeases.get(leaseKey) === lease\n ) {\n parent.captureLeases.delete(leaseKey);\n parent.captureReservedBytes = Math.max(0, parent.captureReservedBytes - lease.reservedBytes);\n }\n };\n\n let confirmPostStartStop = () => {};\n\n const observeStop = (stopping: Promise<void>, afterStart: boolean) => {\n void stopping.then(\n () => {\n if (afterStart) {\n nativeStop = \"confirmed\";\n releaseReservation();\n if (cleanupFinished) publishCapture(\"Stopped\");\n } else {\n preStartStopConfirmed = true;\n confirmPostStartStop();\n }\n },\n () => {},\n );\n };\n\n confirmPostStartStop = () => {\n const stoppingSource = source;\n\n if (\n !preStartStopConfirmed ||\n !startSettled ||\n postStartStopStarted ||\n stoppingSource === undefined ||\n leaseKey === undefined ||\n lease === undefined ||\n parent.captureLeases.get(leaseKey) !== lease\n )\n return;\n\n postStartStopStarted = true;\n observeStop(\n Promise.resolve().then(() => stoppingSource.stop()),\n true,\n );\n };\n\n const finish = (why: CaptureReason, failure?: BrowserError) => {\n if (ended) return;\n ended = true;\n reason = why;\n error = failure;\n publishCapture(\"Ended\");\n Queue.offerUnsafe(wake, undefined);\n Queue.offerUnsafe(finished, undefined);\n };\n\n const snapshot = (): CaptureSummary => {\n if (target === undefined) throw new Error(\"Capture target was not admitted\");\n const status = targetStatus?.();\n const ownerPhase = parent.owner.state.phase;\n const ownerGeneration = parent.owner.state.generation;\n const sessionFenced = [\"uncertain\", \"faulted\", \"closing\", \"closed\"].includes(ownerPhase);\n\n const containment =\n status !== undefined && status.containment._tag !== \"NotRequired\"\n ? { ...status.containment }\n : sessionFenced\n ? { _tag: \"SessionFenced\" as const, generation: ownerGeneration }\n : { _tag: \"NotRequired\" as const };\n\n const qualification: CaptureQualification = {\n authority:\n status?.phase === \"closed\" || terminalAuthority === \"closed\"\n ? \"closed\"\n : target.generation !== ownerGeneration\n ? \"stale\"\n : (status?.phase ?? terminalAuthority ?? \"open\"),\n containment,\n ownerPhase,\n ownerGeneration,\n };\n\n return CaptureSummary.make({\n target,\n qualification,\n reason,\n received,\n delivered,\n discarded: buffer.dropped + rejected + late + duplicates,\n overflow: buffer.dropped,\n duplicates,\n late,\n rejected,\n peakBufferedFrames: buffer.highWaterFrames,\n peakBufferedBytes: buffer.highWaterBytes,\n bufferedFrames: buffer.size,\n bufferedBytes: buffer.bytes,\n sourceFirstMillis: first ?? null,\n sourceLastMillis: last ?? null,\n initialUrl,\n documentBoundaries: documentBoundaries.map((boundary) => ({ ...boundary })),\n documentBoundariesTruncated,\n nativeStop,\n upstreamDrops: \"unknown\",\n ...(error === undefined\n ? {}\n : {\n error: BrowserError.make({\n operation: error.operation,\n reason: { ...error.reason },\n outcome: error.outcome,\n ...(error.containment !== undefined\n ? { containment: { ...error.containment } }\n : containment._tag === \"NotRequired\"\n ? {}\n : { containment }),\n }),\n }),\n });\n };\n\n const publishCapture = (\n phase: Extract<CaptureMetadata, { readonly _tag: \"Capture\" }>[\"phase\"],\n ) => {\n if (metadata === undefined || target === undefined) return;\n const facts = snapshot();\n\n metadata({\n _tag: \"Capture\",\n captureId,\n target,\n phase,\n latePhase: ended && (phase === \"Watching\" || phase === \"Started\"),\n observedMonotonicNanos: clock.monotonicTimeNanosUnsafe(),\n captureBoundary,\n captureDocument: document,\n qualification: facts.qualification,\n initialUrl,\n initialUrlQualification,\n reason: ended ? reason : null,\n nativeStop: phase === \"Stopped\" ? nativeStop : null,\n received,\n delivered,\n discarded: facts.discarded,\n overflow: facts.overflow,\n late,\n duplicates,\n rejected,\n upstreamDrops: \"unknown\",\n });\n };\n\n const performStop = yield* Effect.cached(\n Effect.uninterruptibleMask((restore) =>\n Effect.gen(function* () {\n finish(\"stopped\");\n // Wait for an in-flight start before stop. If it will not settle, quarantine this page lease.\n if (startPromise !== undefined && !startSettled) {\n const starting = startPromise;\n\n yield* restore(\n Effect.tryPromise({\n try: () => starting,\n catch: () =>\n BrowserError.make({\n operation: \"capture-start\",\n reason: Reasons.Provider.make({}),\n outcome: \"unknown\",\n }),\n }).pipe(\n Effect.timeout(2000),\n Trace.span(\"Browser.capture.start-settlement\"),\n Effect.exit,\n ),\n );\n }\n if (source !== undefined) {\n const stopping = source;\n const afterStart = startSettled;\n const stop = Promise.resolve().then(() => stopping.stop());\n\n observeStop(stop, afterStart);\n\n const stopped = yield* restore(\n Effect.tryPromise({\n try: () => stop,\n catch: () =>\n BrowserError.make({\n operation: \"capture-stop\",\n reason: Reasons.Provider.make({}),\n outcome: \"unknown\",\n }),\n }).pipe(Effect.timeout(3000), Trace.span(\"Browser.capture.native-stop\")),\n ).pipe(Effect.exit);\n\n if (Exit.isSuccess(stopped) && afterStart) {\n nativeStop = \"confirmed\";\n releaseReservation();\n }\n } else nativeStop = \"confirmed\";\n if (nativeStop === \"confirmed\") releaseReservation();\n cleanupFinished = true;\n publishCapture(\"Stopped\");\n interval?.end(error === undefined ? Exit.void : Exit.fail(error), {\n \"browser.capture.reason\": reason,\n \"browser.capture.native-stop\": nativeStop,\n \"browser.capture.received\": received,\n \"browser.capture.discarded\": buffer.dropped + rejected + late + duplicates,\n });\n\n return snapshot();\n }).pipe(Trace.span(\"Browser.capture.cleanup\")),\n ).pipe(Effect.provideService(Clock.Clock, clock)),\n );\n\n // Publish completion only after the cached cleanup Exit has settled. Publishing\n // inside it lets the caller close Scope and interrupt the caching fiber first.\n const stopNative = performStop.pipe(Effect.tap(() => Deferred.succeed(completed, undefined)));\n\n const receive = (frame: NativeFrame): void => {\n if (ended) return;\n if (\n target === undefined ||\n parent.owner.state.generation !== target.generation ||\n parent.owner.state.phase !== \"open\"\n ) {\n finish(\n \"parent-unavailable\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Closed.make({}),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n const sequence = received++;\n\n try {\n const decoded = decodeMetadata(frame);\n\n if (Option.isNone(decoded)) {\n rejected++;\n finish(\n \"malformed-frame\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Malformed.make({}),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n const meta = decoded.value;\n\n if (!(frame.data instanceof Uint8Array)) {\n rejected++;\n finish(\n \"malformed-frame\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Malformed.make({ path: \"bytes\" }),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n if (frame.data.length > maxFrameBytes) {\n rejected++;\n finish(\n \"frame-limit\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Limit.make({\n dimension: \"frame-bytes\",\n maximum: maxFrameBytes,\n observed: frame.data.length,\n }),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n if (last !== undefined && meta.timestamp < last) {\n // A newer frame is already accepted, so this one can no longer be presented in order.\n // It is discarded and counted rather than sorted in or given an invented time.\n late++;\n if (++lateRun > MaxConsecutiveLateFrames) {\n finish(\n \"timestamp-discontinuity\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Timestamp.make({}),\n outcome: \"undispatched\",\n }),\n );\n }\n\n return;\n }\n if (last === meta.timestamp) {\n duplicates++;\n\n return;\n }\n const dimensions = jpegGeometry(frame.data);\n\n if (frame.data[frame.data.length - 2] !== 255 || frame.data[frame.data.length - 1] !== 217) {\n rejected++;\n finish(\n \"malformed-frame\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Malformed.make({ path: \"bytes\" }),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n const maximumWidth = Math.min(16384, size?.width ?? 16384);\n const maximumHeight = Math.min(16384, size?.height ?? 16384);\n\n const excessive =\n dimensions.width > maximumWidth\n ? Reasons.Limit.make({\n dimension: \"width\",\n maximum: maximumWidth,\n observed: dimensions.width,\n })\n : dimensions.height > maximumHeight\n ? Reasons.Limit.make({\n dimension: \"height\",\n maximum: maximumHeight,\n observed: dimensions.height,\n })\n : dimensions.width * dimensions.height > 33_554_432\n ? Reasons.Limit.make({\n dimension: \"pixels\",\n maximum: 33_554_432,\n observed: dimensions.width * dimensions.height,\n })\n : undefined;\n\n if (excessive !== undefined) {\n rejected++;\n finish(\n \"frame-limit\",\n BrowserError.make({ operation: \"capture\", reason: excessive, outcome: \"undispatched\" }),\n );\n\n return;\n }\n if (\n geometry !== undefined &&\n (geometry.width !== dimensions.width ||\n geometry.height !== dimensions.height ||\n geometry.viewportWidth !== meta.viewportWidth ||\n geometry.viewportHeight !== meta.viewportHeight)\n ) {\n rejected++;\n finish(\n \"resized\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Resized.make({}),\n outcome: \"undispatched\",\n }),\n );\n\n return;\n }\n geometry ??= {\n ...dimensions,\n viewportWidth: meta.viewportWidth,\n viewportHeight: meta.viewportHeight,\n };\n first ??= meta.timestamp;\n last = meta.timestamp;\n lateRun = 0;\n const receivedMonotonicNanos = clock.monotonicTimeNanosUnsafe();\n\n buffer.offer({\n bytes: new Uint8Array(frame.data),\n mediaType: \"image/jpeg\",\n target,\n sequence,\n document,\n sourceTimeMillis: meta.timestamp,\n sourceClock: \"presentation-unix-millis\",\n receivedMonotonicNanos,\n ...dimensions,\n viewportWidth: meta.viewportWidth,\n viewportHeight: meta.viewportHeight,\n });\n if (captureBoundary !== acceptedBoundary) {\n acceptedBoundary = captureBoundary;\n metadata?.({\n _tag: \"FirstFrame\",\n captureId,\n target,\n captureBoundary,\n captureDocument: document,\n frameSequence: sequence,\n sourceTimeMillis: meta.timestamp,\n sourceClock: \"presentation-unix-millis\",\n receivedMonotonicNanos,\n ...dimensions,\n viewportWidth: meta.viewportWidth,\n viewportHeight: meta.viewportHeight,\n });\n }\n Queue.offerUnsafe(wake, undefined);\n } catch {\n rejected++;\n finish(\n \"malformed-frame\",\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Malformed.make({}),\n outcome: \"undispatched\",\n }),\n );\n }\n };\n\n yield* parent.validate(\"capture-start\");\n\n const requested = parent.page;\n\n const generation = parent.owner.state.generation;\n\n yield* parent.owner\n .guard(\n \"capture-start\",\n (ticket) =>\n Effect.gen(function* () {\n const resolved = yield* parent.resolve(ticket, requested);\n\n // Frames and summaries share this identity with the generation guard. It must not\n // become writable through consumer-owned frame data.\n target = Object.freeze(resolved.target);\n targetStatus = resolved.status;\n metadata = resolved.metadata;\n const resolvedSource = resolved.source;\n\n source = resolvedSource;\n leaseKey = resolved.key;\n if (parent.captureLeases.has(leaseKey)) {\n return yield* BrowserError.make({\n operation: \"capture\",\n reason: Reasons.Busy.make({}),\n outcome: \"undispatched\",\n });\n }\n if (\n parent.captureLeases.size >= MaxParentCaptures ||\n parent.captureReservedBytes + maxBytes > MaxParentBufferedBytes\n ) {\n return yield* BrowserError.make({\n operation: \"capture\",\n reason:\n parent.captureLeases.size >= MaxParentCaptures\n ? Reasons.Limit.make({\n dimension: \"captures\",\n maximum: MaxParentCaptures,\n observed: parent.captureLeases.size + 1,\n })\n : Reasons.Limit.make({\n dimension: \"buffered-bytes\",\n maximum: MaxParentBufferedBytes,\n observed: parent.captureReservedBytes + maxBytes,\n }),\n outcome: \"undispatched\",\n });\n }\n yield* Effect.uninterruptible(\n Trace.start(\"Browser.capture.interval\", {\n attributes: {\n \"browser.operation\": \"capture\",\n \"browser.capture.lifetime\": options.lifetime === \"page\" ? \"page\" : \"document\",\n },\n }).pipe(\n Effect.tap((started) =>\n Effect.sync(() => {\n interval = started;\n }),\n ),\n ),\n );\n lease = {\n pageId: target.pageId,\n reservedBytes: maxBytes,\n stop: stopNative.pipe(Effect.asVoid),\n invalidate: (why) => {\n if (why === \"target-closed\") terminalAuthority = \"closed\";\n else if (why === \"closed\") terminalAuthority ??= \"closing\";\n if (why === \"target-closed\") releaseReservation();\n finish(\n why === \"resized\" ? \"resized\" : \"target-changed\",\n BrowserError.make({\n operation: \"capture\",\n reason:\n why === \"resized\" ? Reasons.Resized.make({}) : Reasons.TargetChanged.make({}),\n outcome: \"undispatched\",\n }),\n );\n },\n };\n parent.captureLeases.set(leaseKey, lease);\n parent.captureReservedBytes += maxBytes;\n // Installed before native acquisition. A cancelled capture cannot escape its caller's scope.\n yield* Effect.addFinalizer(() =>\n stopNative.pipe(\n Effect.andThen(\n Effect.sync(() => {\n rejected += buffer.size;\n buffer.clear();\n }),\n ),\n ),\n );\n publishCapture(\"Reserved\");\n startSettled = false;\n yield* Effect.tryPromise({\n try: () => {\n try {\n startPromise = resolvedSource.start({\n receive,\n quality,\n invalidate: (why) => lease?.invalidate(why),\n opened: (url) => {\n initialUrl = documentUrl(url);\n initialUrlQualification = initialUrl === null ? \"Omitted\" : \"NativeCached\";\n publishCapture(\"Watching\");\n },\n ...(size === undefined ? {} : { size }),\n ...(options.lifetime === \"page\" ? { document: nextDocument } : {}),\n });\n } catch (error) {\n startSettled = true;\n\n throw error;\n }\n\n const cleanupAfterLateStart = () => {\n startSettled = true;\n // A pre-start stop must settle successfully before a post-start stop is sent.\n confirmPostStartStop();\n };\n\n void startPromise.then(cleanupAfterLateStart, cleanupAfterLateStart);\n\n return startPromise;\n },\n catch: () =>\n BrowserError.make({\n operation: \"capture-start\",\n reason: Reasons.Provider.make({}),\n outcome: \"unknown\",\n }),\n }).pipe(Trace.span(\"Browser.capture.native-start\"));\n publishCapture(\"Started\");\n ticket.check();\n }),\n {\n charge: false,\n admission: options.admission,\n targetScope: () => ({ pageId: requested.pageId }),\n preflight: parent.validate(\"capture-start\").pipe(\n Effect.andThen(\n Effect.suspend(() =>\n generation === parent.owner.state.generation\n ? Effect.void\n : Effect.fail(\n BrowserError.make({\n operation: \"capture-start\",\n reason: Reasons.Stale.make({}),\n outcome: \"undispatched\",\n }),\n ),\n ),\n ),\n ),\n },\n )\n .pipe(\n Effect.provideService(Clock.Clock, clock),\n Effect.onExit((exit) =>\n Effect.sync(() => {\n if (Exit.isFailure(exit)) interval?.end(exit);\n }),\n ),\n Effect.onError(() => (lease === undefined ? Effect.void : stopNative.pipe(Effect.asVoid))),\n Effect.onInterrupt(() =>\n lease === undefined ? Effect.void : stopNative.pipe(Effect.asVoid),\n ),\n );\n // One monitor, not a fiber per frame. The finalizer also calls stop directly if this monitor is interrupted.\n // The timeout and explicit-finish branches intentionally carry different\n // values before shared cleanup; preserve the proven first-completion semantics.\n // @effect-diagnostics-next-line raceFirstWithSleepToTimeout:off\n yield* Effect.raceFirst(\n Queue.take(finished).pipe(Effect.as(false)),\n clock.sleep(Duration.millis(duration)).pipe(Effect.as(true)),\n ).pipe(\n Effect.tap((expired) => (expired ? Effect.sync(() => finish(\"duration-limit\")) : Effect.void)),\n Effect.andThen(stopNative),\n Effect.forkScoped,\n );\n\n const next: Effect.Effect<CapturedFrame, BrowserError | Cause.Done> = Effect.suspend(() => {\n const frame = buffer.take();\n\n if (frame !== undefined) {\n delivered++;\n\n return Effect.succeed(frame);\n }\n if (ended) return error === undefined ? Cause.done() : Effect.fail(error);\n\n return Queue.take(wake).pipe(Effect.andThen(next));\n });\n\n const frames = Stream.unwrap(\n Effect.suspend(() => {\n if (subscribed)\n return Effect.fail(\n BrowserError.make({\n operation: \"capture-consume\",\n reason: Reasons.Busy.make({}),\n outcome: \"undispatched\",\n }),\n );\n subscribed = true;\n\n return Effect.succeed(\n Stream.fromEffectRepeat(next).pipe(Stream.ensuring(stopNative.pipe(Effect.asVoid))),\n );\n }),\n ).pipe(Trace.stream(\"Browser.capture.consume\"));\n\n return {\n id: captureId,\n frames,\n snapshot: Effect.sync(() => {\n const { reason, nativeStop, ...metadata } = snapshot();\n\n return CaptureSnapshot.make({\n ...metadata,\n phase: cleanupFinished ? \"stopped\" : ended ? \"stopping\" : \"capturing\",\n observedMonotonicNanos: clock.monotonicTimeNanosUnsafe(),\n currentDocument: document,\n reason: ended ? reason : null,\n nativeStop: cleanupFinished ? nativeStop : null,\n });\n }),\n stop: stopNative,\n completed: Deferred.await(completed).pipe(Effect.map(snapshot)),\n } satisfies CaptureInterval;\n});\n\nexport const startCapture = (parent: PageCaptureParent, options: CaptureOptions = {}) =>\n acquireCapture(parent, options).pipe(\n Trace.span(\"Browser.capture.start\", { attributes: { \"browser.operation\": \"capture-start\" } }),\n );\n","import { Crypto, Effect, type PlatformError, type Scope, Stream } from \"effect\";\n\nimport type { Page } from \"./Browser.ts\";\nimport {\n type CapturedFrame,\n CaptureOptions,\n type CaptureSnapshot,\n type CaptureSummary,\n} from \"./CaptureData.ts\";\nimport { BrowserError, Reasons } from \"./Errors.ts\";\nimport { capturePageParent } from \"./internal/browser/PageRegistry.ts\";\nimport { checked, checkedOperationOptions } from \"./internal/browser/PublicSession.ts\";\nimport { startCapture } from \"./internal/capture/Capture.ts\";\n\nexport {\n CapturedFrame,\n CaptureOptions,\n CaptureQualification,\n CaptureSize,\n CaptureSnapshot,\n CaptureSummary,\n} from \"./CaptureData.ts\";\n\n/** Live stream/Effect capabilities intentionally have no data schema or serialization contract. */\nexport interface CaptureInterval {\n /** Opaque original interval identity; metadata refers to this id and actual frame sequences. */\n readonly id: string;\n /** Single subscription. Ending or interrupting it stops this interval, not its browser. */\n readonly frames: Stream.Stream<CapturedFrame, BrowserError>;\n /**\n * A bounded copy of recorded metadata, available during capture and after cleanup. No native\n * work, budget charge or subscription. Drain frames, then read `completed` for final accounting.\n */\n readonly snapshot: Effect.Effect<CaptureSnapshot>;\n readonly stop: Effect.Effect<CaptureSummary>;\n readonly completed: Effect.Effect<CaptureSummary>;\n}\n\n/**\n * Capture one remote page independently of the session's selected page.\n *\n * Requires an exact issued Page; copying an object or decoding a durable reference cannot\n * copy its capture authority. The private owner is not frame data.\n * `CapturedFrame` and `CaptureOptions` are Schema values as well as structural types. Frame\n * decoding checks binary/metadata fields, not the complete JPEG bitstream or target authority,\n * and does not copy bytes. Options decoding preserves omissions; admission applies defaults.\n * `CaptureInterval` remains a live scoped capability, not a schema or JSON/Tool value.\n */\nexport const start = (\n page: Page,\n options: CaptureOptions = {},\n): Effect.Effect<CaptureInterval, BrowserError, Scope.Scope> =>\n Effect.suspend(() => {\n const parent = capturePageParent(page);\n\n if (parent === undefined)\n return Effect.fail(\n BrowserError.make({\n operation: \"capture\",\n reason: Reasons.UnregisteredSession.make({}),\n outcome: \"undispatched\",\n }),\n );\n\n return checked(CaptureOptions, options, \"capture\").pipe(\n Effect.flatMap(({ admission, ...capture }) =>\n checkedOperationOptions(admission === undefined ? {} : { admission }, \"capture\").pipe(\n Effect.flatMap((operationOptions) =>\n startCapture(parent, {\n ...capture,\n ...(operationOptions.admission === undefined\n ? {}\n : { admission: operationOptions.admission }),\n }),\n ),\n ),\n ),\n );\n });\n\n/**\n * A lazy, scoped frame stream. Each subscription acquires one interval and finalizes it when\n * consumption ends, fails or is interrupted; the browser remains owned by its caller.\n * Concurrent subscriptions on the same page are refused by the existing capture reservation.\n * Unconfirmed native cleanup retains the page reservation. Use start when the host needs\n * explicit stop acknowledgement, interval snapshots and the final capture summary.\n */\nexport const stream = (\n page: Page,\n options: CaptureOptions = {},\n): Stream.Stream<CapturedFrame, BrowserError> =>\n Stream.unwrap(start(page, options).pipe(Effect.map((interval) => interval.frames)));\n\n/** A `multipart/x-mixed-replace` body and the content type that names its boundary. */\nexport interface MultipartBody<E, R> {\n readonly contentType: string;\n readonly body: Stream.Stream<Uint8Array, E, R>;\n}\n\n/**\n * Frames as motion JPEG for an `<img>`: one `multipart/x-mixed-replace` response, as WHATWG HTML\n * defines it for images. Each frame is followed at once by the next part's delimiter and headers,\n * because a browser shows a part only when it has read the headers of the one after it; without\n * that, a still page's last picture would never be shown. Parts carry no metadata, so nothing\n * but the pictures reaches a viewer. The boundary is drawn from `Crypto` for each response, so a\n * page cannot shape its pixels into it. Call it once per viewer.\n */\nexport const multipart = <E, R>(\n frames: Stream.Stream<CapturedFrame, E, R>,\n): Effect.Effect<MultipartBody<E, R>, PlatformError.PlatformError, Crypto.Crypto> =>\n Effect.map(\n Effect.flatMap(Crypto.Crypto, (crypto) => crypto.randomUUIDv4),\n (uuid) => {\n const boundary = `frame-${uuid.replaceAll(\"-\", \"\")}`;\n const encoder = new TextEncoder();\n const opening = encoder.encode(`--${boundary}\\r\\nContent-Type: image/jpeg\\r\\n\\r\\n`);\n const next = encoder.encode(`\\r\\n--${boundary}\\r\\nContent-Type: image/jpeg\\r\\n\\r\\n`);\n\n return {\n contentType: `multipart/x-mixed-replace; boundary=${boundary}`,\n body: Stream.make(opening).pipe(\n Stream.concat(frames.pipe(Stream.flatMap((frame) => Stream.make(frame.bytes, next)))),\n Stream.concat(Stream.make(encoder.encode(`--${boundary}--\\r\\n`))),\n ),\n };\n },\n );\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { BrowserError } from "./Errors.mjs";
2
- import { PageInfo, Target } from "./BrowserData.mjs";
1
+ import { BrowserError, Containment } from "./Errors.mjs";
2
+ import { SessionPhase, Target } from "./BrowserData.mjs";
3
+ import { t as AdmissionOptionsSchema } from "./OperationOptions-DAeRS6O9.mjs";
3
4
  import { Schema } from "effect";
4
5
  //#region src/internal/capture/Options.ts
5
6
  const Dimension = Schema.Int.check(Schema.isBetween({
@@ -80,8 +81,8 @@ const CaptureSize = Schema.Struct({
80
81
  });
81
82
  /** Optional capture data. Defaults are applied at admission, not during schema decoding. */
82
83
  const CaptureOptions = Schema.Struct({
83
- /** Pin to a page from `session.pages`; omission preserves selected-page behavior. */
84
- target: Schema.optionalKey(PageInfo),
84
+ /** Host-only bounded waiting for capture-start admission; stop/finalization retains cleanup ownership. */
85
+ admission: Schema.optionalKey(AdmissionOptionsSchema),
85
86
  /**
86
87
  * Frames held until the consumer takes them (4 by default, at most 1024), oldest dropped first
87
88
  * and counted as `overflow`. A consumer that delays its output leaves frames here, so this and
@@ -104,8 +105,26 @@ const CaptureOptions = Schema.Struct({
104
105
  }).check(FrameBudget);
105
106
  /** An address as the browser reported it. One longer than this is recorded as null, not cut. */
106
107
  const DocumentUrl = Schema.NullOr(Schema.String.check(Schema.isMaxLength(8192)));
108
+ /**
109
+ * Facts about this capture's exact target and owner, independent of its end reason and native
110
+ * screencast stop. Revocation is not positive page closure. Later snapshots may add confirmed
111
+ * closure evidence while the original action outcome and capture end reason stay unchanged.
112
+ */
113
+ const CaptureQualification = Schema.Struct({
114
+ authority: Schema.Literals([
115
+ "open",
116
+ "paused",
117
+ "closing",
118
+ "closed",
119
+ "stale"
120
+ ]),
121
+ containment: Containment,
122
+ ownerPhase: SessionPhase,
123
+ ownerGeneration: Schema.Natural
124
+ });
107
125
  var CaptureSummary = class extends Schema.Class("BrowserCaptureSummary")({
108
126
  target: Target,
127
+ qualification: CaptureQualification,
109
128
  reason: Schema.String.check(Schema.isMaxLength(64)),
110
129
  received: Schema.Natural,
111
130
  delivered: Schema.Natural,
@@ -177,6 +196,6 @@ var CaptureSnapshot = class extends Schema.Class("BrowserCaptureSnapshot")({
177
196
  nativeStop: Schema.NullOr(NativeStop)
178
197
  }) {};
179
198
  //#endregion
180
- export { CapturedFrame as a, CaptureMaxima as c, CaptureSummary as i, CaptureSize as n, CaptureDefaults as o, CaptureSnapshot as r, CaptureLimits as s, CaptureOptions as t };
199
+ export { CaptureSummary as a, CaptureLimits as c, CaptureSnapshot as i, CaptureMaxima as l, CaptureQualification as n, CapturedFrame as o, CaptureSize as r, CaptureDefaults as s, CaptureOptions as t };
181
200
 
182
- //# sourceMappingURL=CaptureData-Dys0Ko9d.mjs.map
201
+ //# sourceMappingURL=CaptureData-CYriZHX1.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CaptureData-CYriZHX1.mjs","names":[],"sources":["../src/internal/capture/Options.ts","../src/CaptureData.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nexport const Dimension = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 16384 }));\nconst BufferedBytes = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 64 * 1024 * 1024 }));\n\n/**\n * Upper bounds of one interval. Frames can be held for as long as a consumer delays them, so the\n * frame bound is set by memory (the byte bound), not by a short hand-off; an interval can last\n * as long as a session may.\n */\nexport const CaptureMaxima = Object.freeze({ frames: 1024, durationMillis: 21_600_000 });\n\n/** Defaults shared by runtime admission and the optional public data schema. */\nexport const CaptureDefaults = Object.freeze({\n maxFrames: 4,\n maxBufferedBytes: 16 * 1024 * 1024,\n maxFrameBytes: 4 * 1024 * 1024,\n maxDurationMillis: 60000,\n quality: 80,\n});\n\nexport const LimitFields = {\n maxFrames: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: CaptureMaxima.frames })),\n maxBufferedBytes: BufferedBytes,\n maxFrameBytes: BufferedBytes,\n maxDurationMillis: Schema.Int.check(\n Schema.isBetween({ minimum: 1, maximum: CaptureMaxima.durationMillis }),\n ),\n quality: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 })),\n};\n\nexport const FrameBudget = Schema.makeFilter(\n (value: { readonly maxFrameBytes?: number; readonly maxBufferedBytes?: number }) =>\n (value.maxFrameBytes ?? CaptureDefaults.maxFrameBytes) <=\n (value.maxBufferedBytes ?? CaptureDefaults.maxBufferedBytes),\n { message: \"A frame must fit within the resolved buffer budget\" },\n);\n\n/** Fully resolved admission values; callers supply the optional public CaptureOptions instead. */\nexport const CaptureLimits = Schema.Struct(LimitFields).check(FrameBudget);\n","import { Schema } from \"effect\";\n\nimport { SessionPhase, Target } from \"./BrowserData.ts\";\nimport { BrowserError, Containment } from \"./Errors.ts\";\nimport { AdmissionOptionsSchema } from \"./internal/browser/OperationOptions.ts\";\nimport { Dimension, FrameBudget, LimitFields } from \"./internal/capture/Options.ts\";\n\n/**\n * Binary frame data, not a live capability or a JSON/thread/Tool value. Decoding validates\n * fields; it does not copy bytes, decode JPEG pixels, prove target authority, or repair clocks.\n * Capture itself owns the byte copy, freezes its shared target identity, and verifies JPEG framing.\n */\nexport const CapturedFrame = Schema.Struct({\n bytes: Schema.Uint8Array.check(Schema.isMinLength(4), Schema.isMaxLength(64 * 1024 * 1024)),\n mediaType: Schema.Literal(\"image/jpeg\"),\n target: Target,\n sequence: Schema.Natural,\n /**\n * Which document of its page this frame was received during: 0 at the start, one more for each\n * main-frame navigation the interval observed. It is attribution by receipt order, not proof\n * of whose pixels these are: a frame received just after a navigation can still show the\n * document before it. Always 0 for an interval that lasts one document.\n */\n document: Schema.Natural,\n sourceTimeMillis: Schema.Finite.check(Schema.isGreaterThan(0)),\n sourceClock: Schema.Literal(\"presentation-unix-millis\"),\n receivedMonotonicNanos: Schema.BigInt,\n width: Dimension,\n height: Dimension,\n viewportWidth: Dimension,\n viewportHeight: Dimension,\n}).check(\n Schema.makeFilter((frame) => frame.width * frame.height <= 33_554_432, {\n message: \"Frame geometry exceeds the capture pixel bound\",\n }),\n);\n\nexport type CapturedFrame = typeof CapturedFrame.Type;\n\n/** Source-fit request in pixels. Actual JPEG bounds are checked before any frame is delivered. */\nexport const CaptureSize = Schema.Struct({ width: Dimension, height: Dimension });\n\nexport type CaptureSize = typeof CaptureSize.Type;\n\n/** Optional capture data. Defaults are applied at admission, not during schema decoding. */\nexport const CaptureOptions = Schema.Struct({\n /** Host-only bounded waiting for capture-start admission; stop/finalization retains cleanup ownership. */\n admission: Schema.optionalKey(AdmissionOptionsSchema),\n /**\n * Frames held until the consumer takes them (4 by default, at most 1024), oldest dropped first\n * and counted as `overflow`. A consumer that delays its output leaves frames here, so this and\n * `maxBufferedBytes` are the delay's memory bound.\n */\n maxFrames: Schema.optionalKey(LimitFields.maxFrames),\n maxBufferedBytes: Schema.optionalKey(LimitFields.maxBufferedBytes),\n maxFrameBytes: Schema.optionalKey(LimitFields.maxFrameBytes),\n /** 60 seconds by default, at most six hours: as long as a session may last. */\n maxDurationMillis: Schema.optionalKey(LimitFields.maxDurationMillis),\n quality: Schema.optionalKey(LimitFields.quality),\n /** Source fit only. Does not resize the viewport or impose an FPS cap. */\n size: Schema.optionalKey(CaptureSize),\n /**\n * `document`, the default, ends the interval when its page navigates. `page` follows the page\n * across documents, so a capture started before a navigation covers the loading in between.\n * It applies to a page's main frame; a capture bound to a child frame still ends with it.\n */\n lifetime: Schema.optionalKey(Schema.Literals([\"document\", \"page\"])),\n}).check(FrameBudget);\n\nexport type CaptureOptions = typeof CaptureOptions.Type;\n\n/** An address as the browser reported it. One longer than this is recorded as null, not cut. */\nconst DocumentUrl = Schema.NullOr(Schema.String.check(Schema.isMaxLength(8192)));\n\n/**\n * Facts about this capture's exact target and owner, independent of its end reason and native\n * screencast stop. Revocation is not positive page closure. Later snapshots may add confirmed\n * closure evidence while the original action outcome and capture end reason stay unchanged.\n */\nexport const CaptureQualification = Schema.Struct({\n authority: Schema.Literals([\"open\", \"paused\", \"closing\", \"closed\", \"stale\"]),\n containment: Containment,\n ownerPhase: SessionPhase,\n ownerGeneration: Schema.Natural,\n});\n\nexport type CaptureQualification = typeof CaptureQualification.Type;\n\nexport class CaptureSummary extends Schema.Class<CaptureSummary>(\"BrowserCaptureSummary\")({\n target: Target,\n qualification: CaptureQualification,\n reason: Schema.String.check(Schema.isMaxLength(64)),\n received: Schema.Natural,\n delivered: Schema.Natural,\n /** All frames this package omitted; the sum of the four disjoint components below. */\n discarded: Schema.Natural,\n /** Evicted by the frame-count or buffered-byte bound. */\n overflow: Schema.Natural,\n duplicates: Schema.Natural,\n /** Arrived after a newer frame was accepted; never reordered in. */\n late: Schema.Natural,\n /** Other refused frames, including malformed data, bounds and undelivered scope cleanup. */\n rejected: Schema.Natural,\n peakBufferedFrames: Schema.Natural,\n peakBufferedBytes: Schema.Natural,\n bufferedFrames: Schema.Natural,\n bufferedBytes: Schema.Natural,\n sourceFirstMillis: Schema.NullOr(Schema.Finite),\n sourceLastMillis: Schema.NullOr(Schema.Finite),\n /**\n * The captured frame's address when this interval began watching it: the URL of document 0.\n * It is read in the same turn the watch is installed, so no navigation can fall between them.\n */\n initialUrl: DocumentUrl,\n /**\n * Each main-frame URL change a `page` interval observed, in order, with the last frame\n * received before it and the address it reached. `sameDocument` is true when the existing\n * document changed its URL; it retains the current document number. The native screencast is\n * never restarted for one, so a boundary is not a gap this package introduced; what Chromium\n * omitted while loading stays `upstreamDrops`. A boundary is the commit. When that navigation\n * started and when its document finished loading are the caller's to stamp, on this same\n * clock, around the operation that caused it. A title is page state, not part of a transition.\n */\n documentBoundaries: Schema.Array(\n Schema.Struct({\n document: Schema.Natural,\n sameDocument: Schema.Boolean,\n observedMonotonicNanos: Schema.BigInt,\n afterSequence: Schema.NullOr(Schema.Natural),\n url: DocumentUrl,\n }),\n ).check(Schema.isMaxLength(64)),\n /**\n * More navigations were observed than are recorded above, so the earliest were let go: the\n * record keeps the latest 64. Frames still count them all.\n */\n documentBoundariesTruncated: Schema.Boolean,\n nativeStop: Schema.Literals([\"confirmed\", \"unconfirmed\"]),\n /** Package accounting cannot measure frames omitted by Chromium, transport, or the provider. */\n upstreamDrops: Schema.Literal(\"unknown\"),\n error: Schema.optionalKey(BrowserError),\n}) {}\n\nconst { reason: StopReason, nativeStop: NativeStop, ...SnapshotFields } = CaptureSummary.fields;\n\n/**\n * Host-side metadata at one instant, without reading or waking the page. The boundary prefix\n * and loss counters are the same facts as the final summary, independent of frame consumption.\n * `stopped` means native cleanup settled; buffered frames may still be drained afterwards.\n */\nexport class CaptureSnapshot extends Schema.Class<CaptureSnapshot>(\"BrowserCaptureSnapshot\")({\n ...SnapshotFields,\n phase: Schema.Literals([\"capturing\", \"stopping\", \"stopped\"]),\n observedMonotonicNanos: Schema.BigInt,\n /** Keeps counting when the bounded boundary prefix is truncated. */\n currentDocument: Schema.Natural,\n /** No reason is reported while the capture still accepts frames. */\n reason: Schema.NullOr(StopReason),\n /** Null until the native cleanup attempt settles; unconfirmed never means stopped remotely. */\n nativeStop: Schema.NullOr(NativeStop),\n}) {}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { BrowserError } from "./Errors.mjs";
2
- import { N as PageInfo, X as Target } from "./BrowserData-DPh3Oaof.mjs";
2
+ import { $ as Target } from "./BrowserData-CPIIIHol.mjs";
3
3
  import { Schema } from "effect";
4
4
  //#region src/CaptureData.d.ts
5
5
  /**
@@ -36,8 +36,19 @@ export declare const CaptureSize: Schema.Struct<{
36
36
  export type CaptureSize = typeof CaptureSize.Type;
37
37
  /** Optional capture data. Defaults are applied at admission, not during schema decoding. */
38
38
  export declare const CaptureOptions: Schema.Struct<{
39
- /** Pin to a page from `session.pages`; omission preserves selected-page behavior. */
40
- readonly target: Schema.optionalKey<typeof PageInfo>;
39
+ /** Host-only bounded waiting for capture-start admission; stop/finalization retains cleanup ownership. */
40
+ readonly admission: Schema.optionalKey<Schema.Struct<{
41
+ readonly queue: Schema.optionalKey<Schema.Union<readonly [Schema.Duration, Schema.Finite, Schema.BigInt, Schema.TemplateLiteral<readonly [Schema.Finite, " ", Schema.Literals<readonly ["nano", "nanos", "micro", "micros", "milli", "millis", "second", "seconds", "minute", "minutes", "hour", "hours", "day", "days", "week", "weeks"]>]>, Schema.Literals<readonly ["Infinity", "-Infinity"]>, Schema.Tuple<readonly [Schema.Finite, Schema.Finite]>, Schema.Struct<{
42
+ readonly weeks: Schema.optionalKey<Schema.Finite>;
43
+ readonly days: Schema.optionalKey<Schema.Finite>;
44
+ readonly hours: Schema.optionalKey<Schema.Finite>;
45
+ readonly minutes: Schema.optionalKey<Schema.Finite>;
46
+ readonly seconds: Schema.optionalKey<Schema.Finite>;
47
+ readonly milliseconds: Schema.optionalKey<Schema.Finite>;
48
+ readonly microseconds: Schema.optionalKey<Schema.Finite>;
49
+ readonly nanoseconds: Schema.optionalKey<Schema.Finite>;
50
+ }>]>>;
51
+ }>>;
41
52
  /**
42
53
  * Frames held until the consumer takes them (4 by default, at most 1024), oldest dropped first
43
54
  * and counted as `overflow`. A consumer that delays its output leaves frames here, so this and
@@ -62,8 +73,42 @@ export declare const CaptureOptions: Schema.Struct<{
62
73
  readonly lifetime: Schema.optionalKey<Schema.Literals<readonly ["document", "page"]>>;
63
74
  }>;
64
75
  export type CaptureOptions = typeof CaptureOptions.Type;
76
+ /**
77
+ * Facts about this capture's exact target and owner, independent of its end reason and native
78
+ * screencast stop. Revocation is not positive page closure. Later snapshots may add confirmed
79
+ * closure evidence while the original action outcome and capture end reason stay unchanged.
80
+ */
81
+ export declare const CaptureQualification: Schema.Struct<{
82
+ readonly authority: Schema.Literals<readonly ["open", "paused", "closing", "closed", "stale"]>;
83
+ readonly containment: Schema.Union<readonly [Schema.TaggedStruct<"NotRequired", {}>, Schema.TaggedStruct<"PageClosed", {
84
+ readonly pageId: Schema.String;
85
+ readonly generation: Schema.Natural;
86
+ }>, Schema.TaggedStruct<"PagePaused", {
87
+ readonly pageId: Schema.String;
88
+ readonly generation: Schema.Natural;
89
+ }>, Schema.TaggedStruct<"SessionFenced", {
90
+ readonly generation: Schema.Natural;
91
+ }>]>;
92
+ readonly ownerPhase: Schema.Literals<readonly ["acquiring", "open", "paused", "detached", "faulted", "uncertain", "closing", "closed"]>;
93
+ readonly ownerGeneration: Schema.Natural;
94
+ }>;
95
+ export type CaptureQualification = typeof CaptureQualification.Type;
65
96
  declare const CaptureSummary_base: Schema.Class<CaptureSummary, Schema.Struct<{
66
97
  readonly target: typeof Target;
98
+ readonly qualification: Schema.Struct<{
99
+ readonly authority: Schema.Literals<readonly ["open", "paused", "closing", "closed", "stale"]>;
100
+ readonly containment: Schema.Union<readonly [Schema.TaggedStruct<"NotRequired", {}>, Schema.TaggedStruct<"PageClosed", {
101
+ readonly pageId: Schema.String;
102
+ readonly generation: Schema.Natural;
103
+ }>, Schema.TaggedStruct<"PagePaused", {
104
+ readonly pageId: Schema.String;
105
+ readonly generation: Schema.Natural;
106
+ }>, Schema.TaggedStruct<"SessionFenced", {
107
+ readonly generation: Schema.Natural;
108
+ }>]>;
109
+ readonly ownerPhase: Schema.Literals<readonly ["acquiring", "open", "paused", "detached", "faulted", "uncertain", "closing", "closed"]>;
110
+ readonly ownerGeneration: Schema.Natural;
111
+ }>;
67
112
  readonly reason: Schema.String;
68
113
  readonly received: Schema.Natural;
69
114
  readonly delivered: Schema.Natural;
@@ -116,6 +161,20 @@ declare const CaptureSummary_base: Schema.Class<CaptureSummary, Schema.Struct<{
116
161
  export declare class CaptureSummary extends CaptureSummary_base {}
117
162
  declare const CaptureSnapshot_base: Schema.Class<CaptureSnapshot, Schema.Struct<{
118
163
  readonly target: typeof Target;
164
+ readonly qualification: Schema.Struct<{
165
+ readonly authority: Schema.Literals<readonly ["open", "paused", "closing", "closed", "stale"]>;
166
+ readonly containment: Schema.Union<readonly [Schema.TaggedStruct<"NotRequired", {}>, Schema.TaggedStruct<"PageClosed", {
167
+ readonly pageId: Schema.String;
168
+ readonly generation: Schema.Natural;
169
+ }>, Schema.TaggedStruct<"PagePaused", {
170
+ readonly pageId: Schema.String;
171
+ readonly generation: Schema.Natural;
172
+ }>, Schema.TaggedStruct<"SessionFenced", {
173
+ readonly generation: Schema.Natural;
174
+ }>]>;
175
+ readonly ownerPhase: Schema.Literals<readonly ["acquiring", "open", "paused", "detached", "faulted", "uncertain", "closing", "closed"]>;
176
+ readonly ownerGeneration: Schema.Natural;
177
+ }>;
119
178
  readonly received: Schema.Natural;
120
179
  readonly delivered: Schema.Natural;
121
180
  readonly discarded: Schema.Natural;
@@ -1,2 +1,2 @@
1
- import { a as CapturedFrame, i as CaptureSummary, n as CaptureSize, r as CaptureSnapshot, t as CaptureOptions } from "./CaptureData-Dys0Ko9d.mjs";
2
- export { CaptureOptions, CaptureSize, CaptureSnapshot, CaptureSummary, CapturedFrame };
1
+ import { a as CaptureSummary, i as CaptureSnapshot, n as CaptureQualification, o as CapturedFrame, r as CaptureSize, t as CaptureOptions } from "./CaptureData-CYriZHX1.mjs";
2
+ export { CaptureOptions, CaptureQualification, CaptureSize, CaptureSnapshot, CaptureSummary, CapturedFrame };
@@ -1,6 +1,6 @@
1
1
  import { BrowserError, InitializationError } from "./Errors.mjs";
2
- import { a as BrowserPolicy, et as Viewport, n as AutomationOptions } from "./BrowserData-DPh3Oaof.mjs";
3
- import { BrowserSession, OpenOptions } from "./Browser.mjs";
2
+ import { it as Viewport, o as BrowserPolicy, r as AutomationOptions } from "./BrowserData-CPIIIHol.mjs";
3
+ import { c as OpenOptions, i as BrowserSession } from "./Browser-n-bKgBNN.mjs";
4
4
  import { Context, Crypto, Effect, Layer, Option, Redacted, Schema, Scope } from "effect";
5
5
  //#region src/internal/chromium/Data.d.ts
6
6
  declare const ChromiumReference_base: Schema.Class<ChromiumReference, Schema.Struct<{
package/dist/Chromium.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BrowserError, Reasons } from "./Errors.mjs";
2
2
  import { Identifier } from "./BrowserData.mjs";
3
- import { a as cleanupStep, c as checked, i as randomUuid, n as make, s as reported } from "./BrowserRuntime-DImn_Oe_.mjs";
3
+ import { n as make } from "./BrowserRuntime-HJ1yYlFS.mjs";
4
+ import { O as span, T as annotate, l as reported, o as randomUuid, s as cleanupStep, t as checked } from "./PublicSession-Bs61Eal8.mjs";
4
5
  import { Clock, Context, Crypto, Duration, Effect, Exit, Layer, Option, Path, Redacted, Schema } from "effect";
5
6
  import { spawn } from "node:child_process";
6
7
  import { mkdtemp, readFile, rm } from "node:fs/promises";
@@ -70,7 +71,7 @@ const ProxyServer = Text.check(Schema.makeFilter((value) => {
70
71
  }
71
72
  }));
72
73
  /** These arguments belong to the launcher; silently overriding them would change ownership. */
73
- const Argument = Text.check(Schema.makeFilter((value) => value.startsWith("--") && !/^--(?:user-data-dir|remote-debugging[^=]*|headless|no-sandbox|disable-setuid-sandbox|single-process|proxy-server|proxy-bypass-list)(?:=|$)/u.test(value)));
74
+ const Argument = Text.check(Schema.makeFilter((value) => value.startsWith("--") && !/^--(?:user-data-dir|remote-debugging[^=]*|headless|no-sandbox|disable-setuid-sandbox|single-process|proxy-server|proxy-bypass-list|no-startup-window)(?:=|$)/u.test(value)));
74
75
  const ChromiumLaunch = Schema.Struct({
75
76
  executablePath: Schema.optionalKey(Text),
76
77
  headless: Schema.optionalKey(Schema.Boolean),
@@ -100,7 +101,7 @@ const launchArguments = (options, directory) => [
100
101
  ...options.chromiumSandbox === false ? ["--no-sandbox"] : [],
101
102
  ...options.proxy === void 0 ? [] : [`--proxy-server=${options.proxy.server}`, `--proxy-bypass-list=${options.proxy.bypass ?? "<-loopback>"}`],
102
103
  ...options.args ?? [],
103
- "about:blank"
104
+ "--no-startup-window"
104
105
  ];
105
106
  const failure = (operation, reason) => BrowserError.make({
106
107
  operation,
@@ -144,7 +145,7 @@ const terminate = Effect.fnUntraced(function* (child, pid, clock) {
144
145
  const forced = clock.monotonicTimeNanosUnsafe() + 1000000000n;
145
146
  while (!(yield* stopped) && clock.monotonicTimeNanosUnsafe() < forced) yield* pause;
146
147
  if (!(yield* stopped)) return yield* failure("close", Reasons.Timeout.make({}));
147
- });
148
+ }, span("Chromium.terminate"));
148
149
  /** Start only Chromium's process. The shared owner later opens its sole CDP connection. */
149
150
  const launch = Effect.fnUntraced(function* (options) {
150
151
  if (process.platform === "win32") return yield* failure("launch", Reasons.Unsupported.make({}));
@@ -218,7 +219,7 @@ const launch = Effect.fnUntraced(function* (options) {
218
219
  yield* clock.sleep(Duration.millis(20));
219
220
  }
220
221
  return yield* failure("connect", Reasons.Timeout.make({}));
221
- }),
222
+ }).pipe(span("Chromium.ready")),
222
223
  terminate: yield* Effect.cached(terminate(launched, pid, clock).pipe(Effect.uninterruptible)),
223
224
  removeProfile
224
225
  };
@@ -230,7 +231,7 @@ const launch = Effect.fnUntraced(function* (options) {
230
231
  const stopped = yield* terminate(child, child.pid, clock).pipe(Effect.exit);
231
232
  if (Exit.isSuccess(stopped)) yield* removeProfile.pipe(Effect.ignore);
232
233
  })));
233
- });
234
+ }, span("Chromium.launch"));
234
235
  //#endregion
235
236
  //#region src/internal/chromium/Session.ts
236
237
  /** Each teardown step runs even when a preceding step fails. Only observed exit permits profile removal. */
@@ -239,7 +240,7 @@ const makeChromiumCleanup = Effect.fnUntraced(function* (reference, local, proce
239
240
  return {
240
241
  close: yield* Effect.cached(Effect.uninterruptible(Effect.gen(function* () {
241
242
  const issues = [];
242
- const step = (name, action) => cleanupStep(action, 3e3).pipe(Effect.tap((result) => Effect.sync(() => {
243
+ const step = (name, action) => cleanupStep(action.pipe(span(`Chromium.cleanup.${name}`)), 3e3).pipe(Effect.tap((result) => Effect.sync(() => {
243
244
  if (result._tag === "Failure") issues.push(ChromiumCleanupIssue.make({
244
245
  step: name,
245
246
  reason: result.reason
@@ -260,8 +261,13 @@ const makeChromiumCleanup = Effect.fnUntraced(function* (reference, local, proce
260
261
  });
261
262
  Object.freeze(result.issues);
262
263
  latest = Object.freeze(result);
264
+ yield* annotate({
265
+ "browser.cleanup.connection": result.connection,
266
+ "browser.cleanup.process": result.process,
267
+ "browser.cleanup.issues": issues.length
268
+ });
263
269
  return latest;
264
- }))),
270
+ }).pipe(span("Chromium.cleanup")))),
265
271
  result: Effect.sync(() => Option.fromNullishOr(latest))
266
272
  };
267
273
  });
@@ -279,7 +285,7 @@ const acquireChromium = (endpoint, options, onCleanup) => (local) => Effect.unin
279
285
  const result = yield* cleanup.close;
280
286
  if (onCleanup !== void 0) yield* reported(Effect.suspend(() => onCleanup(result)));
281
287
  return result;
282
- }).pipe(Effect.uninterruptible));
288
+ }).pipe(span("Chromium.release"), Effect.uninterruptible));
283
289
  yield* Effect.addFinalizer(() => release.pipe(Effect.asVoid));
284
290
  return {
285
291
  reference,
@@ -301,7 +307,7 @@ const acquireChromium = (endpoint, options, onCleanup) => (local) => Effect.unin
301
307
  operation: "close",
302
308
  reason: Reasons.Failed.make({}),
303
309
  outcome: "unknown"
304
- }))),
310
+ })), span("Chromium.close")),
305
311
  cleanupResult: cleanup.result,
306
312
  controlRetired: cleanup.result.pipe(Effect.map((result) => Option.isSome(result) && result.value.ownership === "owned" && result.value.process === "terminated"))
307
313
  };
@@ -341,6 +347,9 @@ var Chromium = class Chromium extends Context.Service()("effect-browser/Chromium
341
347
  implementation: "chromium-playwright-cdp",
342
348
  ...options.viewport === void 0 ? {} : { viewport: options.viewport },
343
349
  automation: {
350
+ ...options.timelineLimits === void 0 ? {} : { timelineLimits: options.timelineLimits },
351
+ ...options.admissionLimits === void 0 ? {} : { admissionLimits: options.admissionLimits },
352
+ ...options.observationLimits === void 0 ? {} : { observationLimits: options.observationLimits },
344
353
  ...options.actionTimeoutMillis === void 0 ? {} : { actionTimeoutMillis: options.actionTimeoutMillis },
345
354
  ...options.maxPages === void 0 ? {} : { maxPages: options.maxPages },
346
355
  ...options.maxHostReads === void 0 ? {} : { maxHostReads: options.maxHostReads },