effect-browserbase 0.1.0-beta.102

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 (136) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +441 -0
  3. package/dist/Account.d.mts +34 -0
  4. package/dist/Account.mjs +41 -0
  5. package/dist/Account.mjs.map +1 -0
  6. package/dist/Acquisition-WBafHwXH.mjs +280 -0
  7. package/dist/Acquisition-WBafHwXH.mjs.map +1 -0
  8. package/dist/Agents.d.mts +156 -0
  9. package/dist/Agents.mjs +307 -0
  10. package/dist/Agents.mjs.map +1 -0
  11. package/dist/Allocation.d.mts +99 -0
  12. package/dist/Allocation.mjs +29 -0
  13. package/dist/Allocation.mjs.map +1 -0
  14. package/dist/Association-CEps4hYP.mjs +10 -0
  15. package/dist/Association-CEps4hYP.mjs.map +1 -0
  16. package/dist/Authorization-Ll5f_XNM.mjs +12 -0
  17. package/dist/Authorization-Ll5f_XNM.mjs.map +1 -0
  18. package/dist/Bootstrap-BXuzZojd.mjs +194 -0
  19. package/dist/Bootstrap-BXuzZojd.mjs.map +1 -0
  20. package/dist/Bootstrap-m7lHgj0D.d.mts +177 -0
  21. package/dist/Bootstrap.d.mts +2 -0
  22. package/dist/Bootstrap.mjs +2 -0
  23. package/dist/Browser-joE4Zgys.mjs +1557 -0
  24. package/dist/Browser-joE4Zgys.mjs.map +1 -0
  25. package/dist/Browser.d.mts +195 -0
  26. package/dist/Browser.mjs +2 -0
  27. package/dist/BrowserBinding-qbQA6JhH.mjs +2452 -0
  28. package/dist/BrowserBinding-qbQA6JhH.mjs.map +1 -0
  29. package/dist/BrowserBinding.d.mts +40 -0
  30. package/dist/BrowserBinding.mjs +2 -0
  31. package/dist/BrowserData-LpcAuAub.d.mts +369 -0
  32. package/dist/BrowserData.d.mts +2 -0
  33. package/dist/BrowserData.mjs +442 -0
  34. package/dist/BrowserData.mjs.map +1 -0
  35. package/dist/Capture-CZJPuD7b.mjs +532 -0
  36. package/dist/Capture-CZJPuD7b.mjs.map +1 -0
  37. package/dist/Capture-Dr5MkIJb.d.mts +125 -0
  38. package/dist/Capture.d.mts +2 -0
  39. package/dist/Capture.mjs +2 -0
  40. package/dist/Certificates.d.mts +35 -0
  41. package/dist/Certificates.mjs +90 -0
  42. package/dist/Certificates.mjs.map +1 -0
  43. package/dist/Cleanup-G2YpTCuU.d.mts +24 -0
  44. package/dist/Cleanup.d.mts +2 -0
  45. package/dist/Cleanup.mjs +48 -0
  46. package/dist/Cleanup.mjs.map +1 -0
  47. package/dist/Client-Ca0zSg1n.d.mts +53 -0
  48. package/dist/Client-D1_xYM9o.mjs +424 -0
  49. package/dist/Client-D1_xYM9o.mjs.map +1 -0
  50. package/dist/Client.d.mts +2 -0
  51. package/dist/Client.mjs +2 -0
  52. package/dist/ContextCoordination.d.mts +16 -0
  53. package/dist/ContextCoordination.mjs +67 -0
  54. package/dist/ContextCoordination.mjs.map +1 -0
  55. package/dist/ContextWriter-BrQmoXRg.mjs +187 -0
  56. package/dist/ContextWriter-BrQmoXRg.mjs.map +1 -0
  57. package/dist/Contexts.d.mts +32 -0
  58. package/dist/Contexts.mjs +103 -0
  59. package/dist/Contexts.mjs.map +1 -0
  60. package/dist/Deadline-CrViaogr.mjs +13 -0
  61. package/dist/Deadline-CrViaogr.mjs.map +1 -0
  62. package/dist/Downloads.d.mts +44 -0
  63. package/dist/Downloads.mjs +142 -0
  64. package/dist/Downloads.mjs.map +1 -0
  65. package/dist/Errors.d.mts +123 -0
  66. package/dist/Errors.mjs +329 -0
  67. package/dist/Errors.mjs.map +1 -0
  68. package/dist/Extensions-ClZbYb1H.mjs +237 -0
  69. package/dist/Extensions-ClZbYb1H.mjs.map +1 -0
  70. package/dist/Extensions.d.mts +44 -0
  71. package/dist/Extensions.mjs +2 -0
  72. package/dist/Functions.d.mts +227 -0
  73. package/dist/Functions.mjs +332 -0
  74. package/dist/Functions.mjs.map +1 -0
  75. package/dist/Images-DgscEfSf.mjs +127 -0
  76. package/dist/Images-DgscEfSf.mjs.map +1 -0
  77. package/dist/Issued-DejqoMYL.mjs +15 -0
  78. package/dist/Issued-DejqoMYL.mjs.map +1 -0
  79. package/dist/Launch-BHcAEq05.mjs +111 -0
  80. package/dist/Launch-BHcAEq05.mjs.map +1 -0
  81. package/dist/Launch-C8CfaYxb.d.mts +132 -0
  82. package/dist/Launch.d.mts +2 -0
  83. package/dist/Launch.mjs +105 -0
  84. package/dist/Launch.mjs.map +1 -0
  85. package/dist/PageControl.d.mts +16 -0
  86. package/dist/PageControl.mjs +36 -0
  87. package/dist/PageControl.mjs.map +1 -0
  88. package/dist/PageControlAssociation-DabEg5AR.mjs +10 -0
  89. package/dist/PageControlAssociation-DabEg5AR.mjs.map +1 -0
  90. package/dist/PageFetch.d.mts +40 -0
  91. package/dist/PageFetch.mjs +64 -0
  92. package/dist/PageFetch.mjs.map +1 -0
  93. package/dist/Projects.d.mts +39 -0
  94. package/dist/Projects.mjs +71 -0
  95. package/dist/Projects.mjs.map +1 -0
  96. package/dist/Recordings.d.mts +28 -0
  97. package/dist/Recordings.mjs +131 -0
  98. package/dist/Recordings.mjs.map +1 -0
  99. package/dist/References-URDAtapt.d.mts +35 -0
  100. package/dist/References.d.mts +2 -0
  101. package/dist/References.mjs +41 -0
  102. package/dist/References.mjs.map +1 -0
  103. package/dist/Replays.d.mts +28 -0
  104. package/dist/Replays.mjs +109 -0
  105. package/dist/Replays.mjs.map +1 -0
  106. package/dist/Resource-DBksC4zB.mjs +50 -0
  107. package/dist/Resource-DBksC4zB.mjs.map +1 -0
  108. package/dist/Search.d.mts +38 -0
  109. package/dist/Search.mjs +53 -0
  110. package/dist/Search.mjs.map +1 -0
  111. package/dist/SessionData-DRKcKCqw.d.mts +39 -0
  112. package/dist/SessionData.d.mts +2 -0
  113. package/dist/SessionData.mjs +55 -0
  114. package/dist/SessionData.mjs.map +1 -0
  115. package/dist/Sessions-B8E4kMxo.d.mts +68 -0
  116. package/dist/Sessions-CtbseWEh.mjs +244 -0
  117. package/dist/Sessions-CtbseWEh.mjs.map +1 -0
  118. package/dist/Sessions.d.mts +3 -0
  119. package/dist/Sessions.mjs +3 -0
  120. package/dist/TransferPolicy-DQ06i7SZ.mjs +25 -0
  121. package/dist/TransferPolicy-DQ06i7SZ.mjs.map +1 -0
  122. package/dist/Transfers-Czv5IZzJ.d.mts +76 -0
  123. package/dist/Transfers.d.mts +2 -0
  124. package/dist/Transfers.mjs +101 -0
  125. package/dist/Transfers.mjs.map +1 -0
  126. package/dist/Uploads.d.mts +29 -0
  127. package/dist/Uploads.mjs +107 -0
  128. package/dist/Uploads.mjs.map +1 -0
  129. package/dist/Webhooks.d.mts +60 -0
  130. package/dist/Webhooks.mjs +143 -0
  131. package/dist/Webhooks.mjs.map +1 -0
  132. package/dist/WriterFacts-osvYAsIx.d.mts +61 -0
  133. package/dist/index.d.mts +30 -0
  134. package/dist/index.mjs +30 -0
  135. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  136. package/package.json +163 -0
@@ -0,0 +1,532 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { BrowserError } from "./Errors.mjs";
3
+ import { PageInfo, Target } from "./BrowserData.mjs";
4
+ import { t as jpegGeometry } from "./Images-DgscEfSf.mjs";
5
+ import { n as captureParent } from "./Association-CEps4hYP.mjs";
6
+ import { Cause, Clock, Deferred, Effect, Exit, Queue, Schema, Stream } from "effect";
7
+ //#region src/internal/capture/CaptureTypes.ts
8
+ const Dimension = Schema.Int.check(Schema.isBetween({
9
+ minimum: 1,
10
+ maximum: 16384
11
+ }));
12
+ const BufferedBytes = Schema.Int.check(Schema.isBetween({
13
+ minimum: 1,
14
+ maximum: 67108864
15
+ }));
16
+ /** Defaults shared by admission and the optional public data schema. */
17
+ const CaptureDefaults = Object.freeze({
18
+ maxFrames: 4,
19
+ maxBufferedBytes: 16777216,
20
+ maxFrameBytes: 4194304,
21
+ maxDurationMillis: 6e4,
22
+ quality: 80
23
+ });
24
+ const LimitFields = {
25
+ maxFrames: Schema.Int.check(Schema.isBetween({
26
+ minimum: 1,
27
+ maximum: 64
28
+ })),
29
+ maxBufferedBytes: BufferedBytes,
30
+ maxFrameBytes: BufferedBytes,
31
+ maxDurationMillis: Schema.Int.check(Schema.isBetween({
32
+ minimum: 1,
33
+ maximum: 6e5
34
+ })),
35
+ quality: Schema.Int.check(Schema.isBetween({
36
+ minimum: 1,
37
+ maximum: 100
38
+ }))
39
+ };
40
+ const FrameBudget = Schema.makeFilter((value) => (value.maxFrameBytes ?? CaptureDefaults.maxFrameBytes) <= (value.maxBufferedBytes ?? CaptureDefaults.maxBufferedBytes), { message: "A frame must fit within the resolved buffer budget" });
41
+ /** Private resolved admission schema. It is not an additional public options API. */
42
+ const CaptureLimits = Schema.Struct(LimitFields).check(FrameBudget);
43
+ /**
44
+ * Binary frame data, not a live capability or a JSON/thread/Tool value. Decoding validates
45
+ * fields; it does not copy bytes, decode JPEG pixels, prove target authority, or repair clocks.
46
+ * Capture itself owns the byte copy, freezes its shared target identity, and verifies JPEG framing.
47
+ */
48
+ const CapturedFrame = Schema.Struct({
49
+ bytes: Schema.Uint8Array.check(Schema.isMinLength(4), Schema.isMaxLength(67108864)),
50
+ mediaType: Schema.Literal("image/jpeg"),
51
+ target: Target,
52
+ sequence: Schema.Natural,
53
+ /**
54
+ * Which document of its page this frame was received during: 0 at the start, one more for each
55
+ * main-frame navigation the interval observed. It is attribution by receipt order, not proof
56
+ * of whose pixels these are: a frame received just after a navigation can still show the
57
+ * document before it. Always 0 for an interval that lasts one document.
58
+ */
59
+ document: Schema.Natural,
60
+ sourceTimeMillis: Schema.Finite.check(Schema.isGreaterThan(0)),
61
+ sourceClock: Schema.Literal("presentation-unix-millis"),
62
+ receivedMonotonicNanos: Schema.BigInt,
63
+ width: Dimension,
64
+ height: Dimension,
65
+ viewportWidth: Dimension,
66
+ viewportHeight: Dimension
67
+ }).check(Schema.makeFilter((frame) => frame.width * frame.height <= 33554432, { message: "Frame geometry exceeds the capture pixel bound" }));
68
+ /** Source-fit request in pixels. Actual JPEG bounds are checked before any frame is delivered. */
69
+ const CaptureSize = Schema.Struct({
70
+ width: Dimension,
71
+ height: Dimension
72
+ });
73
+ /** Optional capture data. Defaults are applied at admission, not during schema decoding. */
74
+ const CaptureOptions = Schema.Struct({
75
+ /** Pin to a page from `session.pages`; omission preserves selected-page behavior. */
76
+ target: Schema.optionalKey(PageInfo),
77
+ maxFrames: Schema.optionalKey(LimitFields.maxFrames),
78
+ maxBufferedBytes: Schema.optionalKey(LimitFields.maxBufferedBytes),
79
+ maxFrameBytes: Schema.optionalKey(LimitFields.maxFrameBytes),
80
+ maxDurationMillis: Schema.optionalKey(LimitFields.maxDurationMillis),
81
+ quality: Schema.optionalKey(LimitFields.quality),
82
+ /** Source fit only. Does not resize the viewport or impose an FPS cap. */
83
+ size: Schema.optionalKey(CaptureSize),
84
+ /**
85
+ * `document`, the default, ends the interval when its page navigates. `page` follows the page
86
+ * across documents, so a capture started before a navigation covers the loading in between.
87
+ * It applies to a page's main frame; a capture bound to a child frame still ends with it.
88
+ */
89
+ lifetime: Schema.optionalKey(Schema.Literals(["document", "page"]))
90
+ }).check(FrameBudget);
91
+ /** An address as the browser reported it. One longer than this is recorded as null, not cut. */
92
+ const DocumentUrl = Schema.NullOr(Schema.String.check(Schema.isMaxLength(8192)));
93
+ var CaptureSummary = class extends Schema.Class("BrowserbaseCaptureSummary")({
94
+ target: Target,
95
+ reason: Schema.String.check(Schema.isMaxLength(64)),
96
+ received: Schema.Natural,
97
+ delivered: Schema.Natural,
98
+ dropped: Schema.Natural,
99
+ duplicates: Schema.Natural,
100
+ /** Arrived after a newer frame was accepted; counted within `dropped`, never reordered in. */
101
+ late: Schema.Natural,
102
+ peakBufferedFrames: Schema.Natural,
103
+ peakBufferedBytes: Schema.Natural,
104
+ bufferedFrames: Schema.Natural,
105
+ bufferedBytes: Schema.Natural,
106
+ sourceFirstMillis: Schema.NullOr(Schema.Finite),
107
+ sourceLastMillis: Schema.NullOr(Schema.Finite),
108
+ /**
109
+ * The captured frame's address when this interval began watching it: the URL of document 0.
110
+ * It is read in the same turn the watch is installed, so no navigation can fall between them.
111
+ */
112
+ initialUrl: DocumentUrl,
113
+ /**
114
+ * Each main-frame navigation a `page` interval observed, in order, with the last frame
115
+ * received before it and the address the new document committed. The native screencast is
116
+ * never restarted for one, so a boundary is not a gap this package introduced; what Chromium
117
+ * omitted while loading stays `upstreamDrops`. A boundary is the commit. When that navigation
118
+ * started and when its document finished loading are the caller's to stamp, on this same
119
+ * clock, around the operation that caused it. A title is page state, not part of a transition.
120
+ */
121
+ documentBoundaries: Schema.Array(Schema.Struct({
122
+ document: Schema.Natural,
123
+ observedMonotonicNanos: Schema.BigInt,
124
+ afterSequence: Schema.NullOr(Schema.Natural),
125
+ url: DocumentUrl
126
+ })).check(Schema.isMaxLength(64)),
127
+ /** More navigations were observed than are recorded above. Frames still count them all. */
128
+ documentBoundariesTruncated: Schema.Boolean,
129
+ nativeStop: Schema.Literals(["confirmed", "unconfirmed"]),
130
+ /** Package accounting cannot measure frames omitted by Chromium, transport, or the provider. */
131
+ upstreamDrops: Schema.Literal("unknown"),
132
+ error: Schema.optionalKey(BrowserError)
133
+ }) {};
134
+ //#endregion
135
+ //#region src/internal/capture/FrameBuffer.ts
136
+ /** Callback-side bounded retention. No Promise, Effect, blocked producer, or per-frame fiber. */
137
+ var FrameBuffer = class {
138
+ maximumFrames;
139
+ maximumBytes;
140
+ items = [];
141
+ retained = 0;
142
+ dropped = 0;
143
+ received = 0;
144
+ highWaterBytes = 0;
145
+ highWaterFrames = 0;
146
+ constructor(maximumFrames, maximumBytes) {
147
+ if (!Number.isSafeInteger(maximumFrames) || maximumFrames < 1 || maximumFrames > 64 || !Number.isSafeInteger(maximumBytes) || maximumBytes < 1 || maximumBytes > 67108864) throw new RangeError("Invalid capture retention limits");
148
+ this.maximumFrames = maximumFrames;
149
+ this.maximumBytes = maximumBytes;
150
+ }
151
+ offer(frame) {
152
+ this.received++;
153
+ if (frame.bytes.byteLength > this.maximumBytes) {
154
+ this.dropped++;
155
+ return false;
156
+ }
157
+ while (this.items.length >= this.maximumFrames || this.retained + frame.bytes.byteLength > this.maximumBytes) {
158
+ const removed = this.items.shift();
159
+ if (removed === void 0) break;
160
+ this.retained -= removed.bytes.byteLength;
161
+ this.dropped++;
162
+ }
163
+ this.items.push(frame);
164
+ this.retained += frame.bytes.byteLength;
165
+ this.highWaterBytes = Math.max(this.highWaterBytes, this.retained);
166
+ this.highWaterFrames = Math.max(this.highWaterFrames, this.items.length);
167
+ return true;
168
+ }
169
+ take() {
170
+ const frame = this.items.shift();
171
+ if (frame !== void 0) this.retained -= frame.bytes.byteLength;
172
+ return frame;
173
+ }
174
+ clear() {
175
+ this.items.length = 0;
176
+ this.retained = 0;
177
+ }
178
+ get size() {
179
+ return this.items.length;
180
+ }
181
+ get bytes() {
182
+ return this.retained;
183
+ }
184
+ };
185
+ //#endregion
186
+ //#region src/internal/capture/Capture.ts
187
+ const MaxParentCaptures = 4;
188
+ const MaxParentBufferedBytes = 67108864;
189
+ const MaxDocumentBoundaries = 64;
190
+ const MaxDocumentUrlLength = 8192;
191
+ /** An over-long address is recorded as null rather than cut into one that was never shown. */
192
+ const documentUrl = (url) => typeof url === "string" && url.length <= MaxDocumentUrlLength ? url : null;
193
+ /**
194
+ * Chromium stamps a screencast frame on its UI thread, encodes it on an unsequenced thread
195
+ * pool, and emits it when that encode completes. It admits a new frame while at most two are
196
+ * unacknowledged (`kMaxScreencastFramesInFlight`), so up to three encode at once and two
197
+ * frames stamped close together can complete in either order. Every frame stamped before an
198
+ * accepted one was already in flight when that one was stamped, so at most two late frames
199
+ * can arrive in a row. A longer run is source time that really went backwards.
200
+ */
201
+ const MaxConsecutiveLateFrames = 2;
202
+ const Metadata = Schema.Struct({
203
+ timestamp: Schema.Finite.check(Schema.isGreaterThan(0)),
204
+ viewportWidth: Schema.Int.check(Schema.isBetween({
205
+ minimum: 1,
206
+ maximum: 16384
207
+ })),
208
+ viewportHeight: Schema.Int.check(Schema.isBetween({
209
+ minimum: 1,
210
+ maximum: 16384
211
+ }))
212
+ });
213
+ const parseMetadata = Schema.decodeUnknownSync(Metadata);
214
+ /** Private seam for deterministic callback/lifetime tests. The public start accepts a real live session. */
215
+ const startCapture = Effect.fnUntraced(function* (parent, options = {}) {
216
+ const maxFrames = options.maxFrames ?? CaptureDefaults.maxFrames;
217
+ const maxBytes = options.maxBufferedBytes ?? CaptureDefaults.maxBufferedBytes;
218
+ const maxFrameBytes = options.maxFrameBytes ?? CaptureDefaults.maxFrameBytes;
219
+ const duration = options.maxDurationMillis ?? CaptureDefaults.maxDurationMillis;
220
+ const quality = options.quality ?? CaptureDefaults.quality;
221
+ const size = options.size === void 0 ? void 0 : yield* Schema.decodeEffect(CaptureSize)(options.size, { onExcessProperty: "error" }).pipe(Effect.map(({ width, height }) => Object.freeze({
222
+ width,
223
+ height
224
+ })), Effect.mapError(() => BrowserError.make({
225
+ operation: "capture",
226
+ reason: "configuration",
227
+ outcome: "undispatched"
228
+ })));
229
+ yield* Schema.decodeEffect(CaptureLimits)({
230
+ maxFrames,
231
+ maxBufferedBytes: maxBytes,
232
+ maxFrameBytes,
233
+ maxDurationMillis: duration,
234
+ quality
235
+ }).pipe(Effect.mapError(() => BrowserError.make({
236
+ operation: "capture",
237
+ reason: "configuration",
238
+ outcome: "undispatched"
239
+ })));
240
+ const clock = yield* Clock.Clock;
241
+ const wake = yield* Queue.dropping(1);
242
+ const finished = yield* Queue.dropping(1);
243
+ const completed = yield* Deferred.make();
244
+ yield* Effect.addFinalizer(() => Queue.shutdown(wake).pipe(Effect.andThen(Queue.shutdown(finished)), Effect.asVoid));
245
+ const buffer = new FrameBuffer(maxFrames, maxBytes);
246
+ let source;
247
+ let startPromise;
248
+ let startSettled = true;
249
+ let target;
250
+ let leaseKey;
251
+ let ended = false, subscribed = false, cleanupFinished = false;
252
+ let reason = "stopped";
253
+ let error;
254
+ let received = 0, delivered = 0, rejected = 0, duplicates = 0, late = 0, lateRun = 0;
255
+ let first, last;
256
+ let document = 0;
257
+ let initialUrl = null;
258
+ let documentBoundariesTruncated = false;
259
+ const documentBoundaries = [];
260
+ /** The page navigated and its screencast kept running: later frames belong to a new document. */
261
+ const nextDocument = (url) => {
262
+ if (ended) return;
263
+ document++;
264
+ if (documentBoundaries.length >= MaxDocumentBoundaries) documentBoundariesTruncated = true;
265
+ else documentBoundaries.push({
266
+ document,
267
+ observedMonotonicNanos: clock.monotonicTimeNanosUnsafe(),
268
+ afterSequence: received === 0 ? null : received - 1,
269
+ url: documentUrl(url)
270
+ });
271
+ };
272
+ let geometry;
273
+ let nativeStop = "unconfirmed";
274
+ let lease;
275
+ const finish = (why, failure) => {
276
+ if (ended) return;
277
+ ended = true;
278
+ reason = why;
279
+ error = failure;
280
+ Queue.offerUnsafe(wake, void 0);
281
+ Queue.offerUnsafe(finished, void 0);
282
+ };
283
+ const snapshot = () => {
284
+ if (target === void 0) throw new Error("Capture target was not admitted");
285
+ return CaptureSummary.make({
286
+ target,
287
+ reason,
288
+ received,
289
+ delivered,
290
+ dropped: buffer.dropped + rejected,
291
+ duplicates,
292
+ late,
293
+ peakBufferedFrames: buffer.highWaterFrames,
294
+ peakBufferedBytes: buffer.highWaterBytes,
295
+ bufferedFrames: buffer.size,
296
+ bufferedBytes: buffer.bytes,
297
+ sourceFirstMillis: first ?? null,
298
+ sourceLastMillis: last ?? null,
299
+ initialUrl,
300
+ documentBoundaries: [...documentBoundaries],
301
+ documentBoundariesTruncated,
302
+ nativeStop,
303
+ upstreamDrops: "unknown",
304
+ ...error === void 0 ? {} : { error }
305
+ });
306
+ };
307
+ const stopNative = (yield* Effect.cached(Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
308
+ finish("stopped");
309
+ if (startPromise !== void 0 && !startSettled) yield* restore(Effect.tryPromise({
310
+ try: () => startPromise,
311
+ catch: () => BrowserError.make({
312
+ operation: "capture-start",
313
+ reason: "provider"
314
+ })
315
+ }).pipe(Effect.timeout(2e3), Effect.exit));
316
+ if (source !== void 0) {
317
+ const stopped = yield* restore(Effect.tryPromise({
318
+ try: () => source.stop(),
319
+ catch: () => BrowserError.make({
320
+ operation: "capture-stop",
321
+ reason: "provider"
322
+ })
323
+ }).pipe(Effect.timeout(3e3))).pipe(Effect.exit);
324
+ if (Exit.isSuccess(stopped) && startSettled) nativeStop = "confirmed";
325
+ } else nativeStop = "confirmed";
326
+ if (nativeStop === "confirmed" && leaseKey !== void 0 && lease !== void 0 && parent.captureLeases.get(leaseKey) === lease) {
327
+ parent.captureLeases.delete(leaseKey);
328
+ parent.captureReservedBytes = Math.max(0, parent.captureReservedBytes - lease.reservedBytes);
329
+ }
330
+ cleanupFinished = true;
331
+ return snapshot();
332
+ })))).pipe(Effect.tap(() => Deferred.succeed(completed, void 0)));
333
+ const receive = (frame) => {
334
+ if (ended) return;
335
+ if (target === void 0 || parent.owner.state.generation !== target.generation || parent.owner.state.phase !== "open") {
336
+ finish("parent-unavailable", BrowserError.make({
337
+ operation: "capture",
338
+ reason: "closed"
339
+ }));
340
+ return;
341
+ }
342
+ const sequence = received++;
343
+ try {
344
+ const meta = parseMetadata(frame);
345
+ if (!(frame.data instanceof Uint8Array) || frame.data.length > maxFrameBytes) {
346
+ rejected++;
347
+ finish("frame-limit", BrowserError.make({
348
+ operation: "capture",
349
+ reason: "limit"
350
+ }));
351
+ return;
352
+ }
353
+ if (last !== void 0 && meta.timestamp < last) {
354
+ rejected++;
355
+ late++;
356
+ if (++lateRun > MaxConsecutiveLateFrames) finish("timestamp-discontinuity", BrowserError.make({
357
+ operation: "capture",
358
+ reason: "timestamp"
359
+ }));
360
+ return;
361
+ }
362
+ if (last === meta.timestamp) {
363
+ duplicates++;
364
+ rejected++;
365
+ return;
366
+ }
367
+ const dimensions = jpegGeometry(frame.data);
368
+ if (dimensions.width > 16384 || dimensions.height > 16384 || size !== void 0 && (dimensions.width > size.width || dimensions.height > size.height) || dimensions.width * dimensions.height > 33554432 || frame.data[frame.data.length - 2] !== 255 || frame.data[frame.data.length - 1] !== 217) {
369
+ rejected++;
370
+ finish("frame-limit", BrowserError.make({
371
+ operation: "capture",
372
+ reason: "limit"
373
+ }));
374
+ return;
375
+ }
376
+ if (geometry !== void 0 && (geometry.width !== dimensions.width || geometry.height !== dimensions.height || geometry.viewportWidth !== meta.viewportWidth || geometry.viewportHeight !== meta.viewportHeight)) {
377
+ rejected++;
378
+ finish("resized", BrowserError.make({
379
+ operation: "capture",
380
+ reason: "resized"
381
+ }));
382
+ return;
383
+ }
384
+ geometry ??= {
385
+ ...dimensions,
386
+ viewportWidth: meta.viewportWidth,
387
+ viewportHeight: meta.viewportHeight
388
+ };
389
+ first ??= meta.timestamp;
390
+ last = meta.timestamp;
391
+ lateRun = 0;
392
+ buffer.offer({
393
+ bytes: new Uint8Array(frame.data),
394
+ mediaType: "image/jpeg",
395
+ target,
396
+ sequence,
397
+ document,
398
+ sourceTimeMillis: meta.timestamp,
399
+ sourceClock: "presentation-unix-millis",
400
+ receivedMonotonicNanos: clock.monotonicTimeNanosUnsafe(),
401
+ ...dimensions,
402
+ viewportWidth: meta.viewportWidth,
403
+ viewportHeight: meta.viewportHeight
404
+ });
405
+ Queue.offerUnsafe(wake, void 0);
406
+ } catch {
407
+ rejected++;
408
+ finish("malformed-frame", BrowserError.make({
409
+ operation: "capture",
410
+ reason: "malformed"
411
+ }));
412
+ }
413
+ };
414
+ yield* parent.owner.guard("capture-start", (ticket) => Effect.gen(function* () {
415
+ const resolved = yield* parent.resolve(ticket, options.target);
416
+ target = Object.freeze(resolved.target);
417
+ source = resolved.source;
418
+ leaseKey = resolved.key;
419
+ if (parent.captureLeases.has(leaseKey)) return yield* BrowserError.make({
420
+ operation: "capture",
421
+ reason: "busy",
422
+ outcome: "undispatched"
423
+ });
424
+ if (parent.captureLeases.size >= MaxParentCaptures || parent.captureReservedBytes + maxBytes > MaxParentBufferedBytes) return yield* BrowserError.make({
425
+ operation: "capture",
426
+ reason: "limit",
427
+ outcome: "undispatched"
428
+ });
429
+ lease = {
430
+ reservedBytes: maxBytes,
431
+ stop: stopNative.pipe(Effect.asVoid),
432
+ invalidate: (why) => finish(why, BrowserError.make({
433
+ operation: "capture",
434
+ reason: why === "resized" ? "resized" : "target-changed"
435
+ }))
436
+ };
437
+ parent.captureLeases.set(leaseKey, lease);
438
+ parent.captureReservedBytes += maxBytes;
439
+ yield* Effect.addFinalizer(() => stopNative.pipe(Effect.andThen(Effect.sync(() => {
440
+ rejected += buffer.size;
441
+ buffer.clear();
442
+ }))));
443
+ startSettled = false;
444
+ yield* Effect.tryPromise({
445
+ try: () => {
446
+ startPromise = source.start({
447
+ receive,
448
+ quality,
449
+ invalidate: (why) => lease?.invalidate(why),
450
+ opened: (url) => {
451
+ initialUrl = documentUrl(url);
452
+ },
453
+ ...size === void 0 ? {} : { size },
454
+ ...options.lifetime === "page" ? { document: nextDocument } : {}
455
+ });
456
+ startPromise.then(() => {
457
+ startSettled = true;
458
+ if (cleanupFinished && nativeStop === "unconfirmed" && leaseKey !== void 0 && parent.captureLeases.get(leaseKey) === lease) source.stop().catch(() => {});
459
+ }, () => {
460
+ startSettled = true;
461
+ });
462
+ return startPromise;
463
+ },
464
+ catch: () => BrowserError.make({
465
+ operation: "capture-start",
466
+ reason: "provider"
467
+ })
468
+ });
469
+ ticket.check();
470
+ }), { charge: false }).pipe(Effect.onError(() => lease === void 0 ? Effect.void : stopNative.pipe(Effect.asVoid)), Effect.onInterrupt(() => lease === void 0 ? Effect.void : stopNative.pipe(Effect.asVoid)));
471
+ yield* Effect.raceFirst(Queue.take(finished).pipe(Effect.as(false)), Effect.sleep(duration).pipe(Effect.as(true))).pipe(Effect.tap((expired) => expired ? Effect.sync(() => finish("duration-limit")) : Effect.void), Effect.andThen(stopNative), Effect.forkScoped);
472
+ const next = Effect.suspend(() => {
473
+ const frame = buffer.take();
474
+ if (frame !== void 0) {
475
+ delivered++;
476
+ return Effect.succeed(frame);
477
+ }
478
+ if (ended) return error === void 0 ? Cause.done() : Effect.fail(error);
479
+ return Queue.take(wake).pipe(Effect.andThen(next));
480
+ });
481
+ return {
482
+ frames: Stream.unwrap(Effect.suspend(() => {
483
+ if (subscribed) return Effect.fail(BrowserError.make({
484
+ operation: "capture-consume",
485
+ reason: "busy"
486
+ }));
487
+ subscribed = true;
488
+ return Effect.succeed(Stream.fromEffectRepeat(next).pipe(Stream.ensuring(stopNative.pipe(Effect.asVoid))));
489
+ })),
490
+ stop: stopNative,
491
+ completed: Deferred.await(completed).pipe(Effect.map(snapshot))
492
+ };
493
+ });
494
+ //#endregion
495
+ //#region src/Capture.ts
496
+ var Capture_exports = /* @__PURE__ */ __exportAll({
497
+ CaptureOptions: () => CaptureOptions,
498
+ CaptureSize: () => CaptureSize,
499
+ CaptureSummary: () => CaptureSummary,
500
+ CapturedFrame: () => CapturedFrame,
501
+ start: () => start
502
+ });
503
+ /**
504
+ * Capture one remote page independently of the session's selected page.
505
+ *
506
+ * Requires the exact live session returned by the host; copying a session object or decoding
507
+ * a durable reference cannot copy its capture authority. The private owner is not frame data.
508
+ * `CapturedFrame` and `CaptureOptions` are Schema values as well as structural types. Frame
509
+ * decoding checks binary/metadata fields, not the complete JPEG bitstream or target authority,
510
+ * and does not copy bytes. Options decoding preserves omissions; admission applies defaults.
511
+ * `CaptureInterval` remains a live scoped capability, not a schema or JSON/Tool value.
512
+ */
513
+ const start = (session, options = {}) => Effect.suspend(() => {
514
+ const parent = captureParent(session);
515
+ if (parent === void 0) return Effect.fail(BrowserError.make({
516
+ operation: "capture",
517
+ reason: "closed"
518
+ }));
519
+ if (options.target === void 0) return startCapture(parent, options);
520
+ return Schema.decodeEffect(PageInfo)(options.target, { onExcessProperty: "error" }).pipe(Effect.mapError(() => BrowserError.make({
521
+ operation: "capture",
522
+ reason: "configuration",
523
+ outcome: "undispatched"
524
+ })), Effect.flatMap((target) => startCapture(parent, {
525
+ ...options,
526
+ target
527
+ })));
528
+ });
529
+ //#endregion
530
+ export { CaptureSummary as a, CaptureSize as i, start as n, CapturedFrame as o, CaptureOptions as r, Capture_exports as t };
531
+
532
+ //# sourceMappingURL=Capture-CZJPuD7b.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Capture-CZJPuD7b.mjs","names":[],"sources":["../src/internal/capture/CaptureTypes.ts","../src/internal/capture/FrameBuffer.ts","../src/internal/capture/Capture.ts","../src/Capture.ts"],"sourcesContent":["import { Schema, type Effect, type Stream } from \"effect\";\n\nimport { PageInfo, Target } from \"../../BrowserData.ts\";\nimport { BrowserError } from \"../../Errors.ts\";\nconst 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/** Defaults shared by 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\nconst LimitFields = {\n maxFrames: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 64 })),\n maxBufferedBytes: BufferedBytes,\n maxFrameBytes: BufferedBytes,\n maxDurationMillis: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 600000 })),\n quality: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 })),\n};\n\nconst 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/** Private resolved admission schema. It is not an additional public options API. */\nexport const CaptureLimits = Schema.Struct(LimitFields).check(FrameBudget);\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 /** Pin to a page from `session.pages`; omission preserves selected-page behavior. */\n target: Schema.optionalKey(PageInfo),\n maxFrames: Schema.optionalKey(LimitFields.maxFrames),\n maxBufferedBytes: Schema.optionalKey(LimitFields.maxBufferedBytes),\n maxFrameBytes: Schema.optionalKey(LimitFields.maxFrameBytes),\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\nexport class CaptureSummary extends Schema.Class<CaptureSummary>(\"BrowserbaseCaptureSummary\")({\n target: Target,\n reason: Schema.String.check(Schema.isMaxLength(64)),\n received: Schema.Natural,\n delivered: Schema.Natural,\n dropped: Schema.Natural,\n duplicates: Schema.Natural,\n /** Arrived after a newer frame was accepted; counted within `dropped`, never reordered in. */\n late: 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 navigation a `page` interval observed, in order, with the last frame\n * received before it and the address the new document committed. 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 observedMonotonicNanos: Schema.BigInt,\n afterSequence: Schema.NullOr(Schema.Natural),\n url: DocumentUrl,\n }),\n ).check(Schema.isMaxLength(64)),\n /** More navigations were observed than are recorded above. Frames still count them all. */\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\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 readonly stop: Effect.Effect<CaptureSummary>;\n readonly completed: Effect.Effect<CaptureSummary>;\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 > 64 ||\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, Queue, Schema, Stream } from \"effect\";\n\nimport type { Target } from \"../../BrowserData.ts\";\nimport { BrowserError } from \"../../Errors.ts\";\nimport { type CaptureLease, type CaptureParent } from \"../browser/Association.ts\";\nimport type { CaptureSource, NativeFrame } from \"../browser/Driver.ts\";\nimport {\n CaptureDefaults,\n CaptureLimits,\n CaptureSize,\n CaptureSummary,\n type CaptureInterval,\n type CaptureOptions,\n type CapturedFrame,\n} from \"./CaptureTypes.ts\";\nimport { FrameBuffer } from \"./FrameBuffer.ts\";\nimport { jpegGeometry } from \"./Images.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 parseMetadata = Schema.decodeUnknownSync(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: \"configuration\",\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: \"configuration\",\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 /** The page navigated and its screencast kept running: later frames belong to a new document. */\n const nextDocument = (url: string): void => {\n if (ended) return;\n document++;\n if (documentBoundaries.length >= MaxDocumentBoundaries) documentBoundariesTruncated = true;\n else\n documentBoundaries.push({\n document,\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\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 dropped: buffer.dropped + rejected,\n duplicates,\n late,\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],\n documentBoundariesTruncated,\n nativeStop,\n upstreamDrops: \"unknown\",\n ...(error === undefined ? {} : { error }),\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 yield* restore(\n Effect.tryPromise({\n try: () => startPromise!,\n catch: () => BrowserError.make({ operation: \"capture-start\", reason: \"provider\" }),\n }).pipe(Effect.timeout(2000), Effect.exit),\n );\n }\n if (source !== undefined) {\n const stopped = yield* restore(\n Effect.tryPromise({\n try: () => source!.stop(),\n catch: () => BrowserError.make({ operation: \"capture-stop\", reason: \"provider\" }),\n }).pipe(Effect.timeout(3000)),\n ).pipe(Effect.exit);\n\n if (Exit.isSuccess(stopped) && startSettled) nativeStop = \"confirmed\";\n } else nativeStop = \"confirmed\";\n // No older attachment may clear a replacement. Unconfirmed native cleanup quarantines only this page.\n if (\n nativeStop === \"confirmed\" &&\n leaseKey !== undefined &&\n lease !== undefined &&\n parent.captureLeases.get(leaseKey) === lease\n ) {\n parent.captureLeases.delete(leaseKey);\n parent.captureReservedBytes = Math.max(\n 0,\n parent.captureReservedBytes - lease.reservedBytes,\n );\n }\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(\"parent-unavailable\", BrowserError.make({ operation: \"capture\", reason: \"closed\" }));\n\n return;\n }\n const sequence = received++;\n\n try {\n const meta = parseMetadata(frame);\n\n if (!(frame.data instanceof Uint8Array) || frame.data.length > maxFrameBytes) {\n rejected++;\n finish(\"frame-limit\", BrowserError.make({ operation: \"capture\", reason: \"limit\" }));\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 rejected++;\n late++;\n if (++lateRun > MaxConsecutiveLateFrames) {\n finish(\n \"timestamp-discontinuity\",\n BrowserError.make({ operation: \"capture\", reason: \"timestamp\" }),\n );\n }\n\n return;\n }\n if (last === meta.timestamp) {\n duplicates++;\n rejected++;\n\n return;\n }\n const dimensions = jpegGeometry(frame.data);\n\n if (\n dimensions.width > 16384 ||\n dimensions.height > 16384 ||\n (size !== undefined &&\n (dimensions.width > size.width || dimensions.height > size.height)) ||\n dimensions.width * dimensions.height > 33_554_432 ||\n frame.data[frame.data.length - 2] !== 255 ||\n frame.data[frame.data.length - 1] !== 217\n ) {\n rejected++;\n finish(\"frame-limit\", BrowserError.make({ operation: \"capture\", reason: \"limit\" }));\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(\"resized\", BrowserError.make({ operation: \"capture\", reason: \"resized\" }));\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(\"malformed-frame\", BrowserError.make({ operation: \"capture\", reason: \"malformed\" }));\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 source = resolved.source;\n leaseKey = resolved.key;\n if (parent.captureLeases.has(leaseKey)) {\n return yield* BrowserError.make({\n operation: \"capture\",\n reason: \"busy\",\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: \"limit\",\n outcome: \"undispatched\",\n });\n }\n lease = {\n reservedBytes: maxBytes,\n stop: stopNative.pipe(Effect.asVoid),\n invalidate: (why) =>\n finish(\n why,\n BrowserError.make({\n operation: \"capture\",\n reason: why === \"resized\" ? \"resized\" : \"target-changed\",\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 startPromise = source!.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 void startPromise.then(\n () => {\n startSettled = true;\n if (\n cleanupFinished &&\n nativeStop === \"unconfirmed\" &&\n leaseKey !== undefined &&\n parent.captureLeases.get(leaseKey) === lease\n ) {\n // One late acquisition cleanup, not a callback-side worker. Keep the page quarantined.\n void source!.stop().catch(() => {});\n }\n },\n () => {\n startSettled = true;\n },\n );\n\n return startPromise;\n },\n catch: () => BrowserError.make({ operation: \"capture-start\", reason: \"provider\" }),\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(BrowserError.make({ operation: \"capture-consume\", reason: \"busy\" }));\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 stop: stopNative,\n completed: Deferred.await(completed).pipe(Effect.map(snapshot)),\n } satisfies CaptureInterval;\n});\n","import { Effect, Schema, type Scope } from \"effect\";\n\nimport type { BrowserbaseSession } from \"./Browser.ts\";\nimport { PageInfo } from \"./BrowserData.ts\";\nimport { BrowserError } from \"./Errors.ts\";\nimport { captureParent } from \"./internal/browser/Association.ts\";\nimport { startCapture } from \"./internal/capture/Capture.ts\";\nimport type { CaptureInterval, CaptureOptions } from \"./internal/capture/CaptureTypes.ts\";\n\nexport {\n CapturedFrame,\n CaptureOptions,\n CaptureSize,\n CaptureSummary,\n} from \"./internal/capture/CaptureTypes.ts\";\n\nexport type { CaptureInterval } from \"./internal/capture/CaptureTypes.ts\";\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: BrowserbaseSession<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(BrowserError.make({ operation: \"capture\", reason: \"closed\" }));\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: \"configuration\",\n outcome: \"undispatched\",\n }),\n ),\n Effect.flatMap((target) => startCapture(parent, { ...options, target })),\n );\n });\n"],"mappings":"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"}