effect-browser 0.3.0-beta.13 → 0.3.0-beta.15
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.
- package/README.md +59 -19
- package/dist/{Browser-QiT6Cdn_.mjs → Browser-BBSySyjT.mjs} +2 -2
- package/dist/{Browser-QiT6Cdn_.mjs.map → Browser-BBSySyjT.mjs.map} +1 -1
- package/dist/Browser.d.mts +1 -1
- package/dist/Browser.mjs +1 -1
- package/dist/Cdp.mjs +1 -1
- package/dist/Chromium.mjs +1 -1
- package/dist/Expect.d.mts +1 -1
- package/dist/Expect.mjs +1 -1
- package/dist/{Frame-Di2PxyF7.d.mts → Frame-DkNdjjjr.d.mts} +3 -5
- package/dist/Frame.d.mts +1 -1
- package/dist/Frame.mjs +2 -4
- package/dist/Frame.mjs.map +1 -1
- package/dist/Moment.d.mts +1 -1
- package/dist/Moment.mjs +7 -3
- package/dist/Moment.mjs.map +1 -1
- package/dist/{Page-B7X6DQUn.d.mts → Page-DL9eylp3.d.mts} +2 -2
- package/dist/Page.d.mts +1 -1
- package/dist/{Plan-BS0jpENY.d.mts → Plan-6As6vcwT.d.mts} +3 -3
- package/dist/{Plan-Bl2NM1D5.mjs → Plan-CXA2BW-G.mjs} +4 -6
- package/dist/Plan-CXA2BW-G.mjs.map +1 -0
- package/dist/Plan.d.mts +1 -1
- package/dist/Plan.mjs +1 -1
- package/dist/Policy.d.mts +1 -1
- package/dist/Presentation.d.mts +1 -1
- package/dist/Presentation.mjs +1 -1
- package/dist/Stage.d.mts +5 -4
- package/dist/Stage.mjs +53 -20
- package/dist/Stage.mjs.map +1 -1
- package/dist/{Supervisor-CYWFK3vM.d.mts → Supervisor-5tZ47hR5.d.mts} +40 -10
- package/dist/{Supervisor-TNKNOVzu.mjs → Supervisor-DaGlQVjv.mjs} +120 -68
- package/dist/Supervisor-DaGlQVjv.mjs.map +1 -0
- package/dist/Supervisor.d.mts +2 -2
- package/dist/Supervisor.mjs +2 -2
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +3 -3
- package/dist/{page-ZxMhw16l.mjs → page-B92QnRfT.mjs} +196 -166
- package/dist/page-B92QnRfT.mjs.map +1 -0
- package/package.json +1 -1
- package/src/Frame.ts +2 -4
- package/src/Moment.ts +14 -3
- package/src/Plan.ts +7 -6
- package/src/Stage.ts +61 -21
- package/src/Supervisor.ts +205 -172
- package/src/internal/pictures/capture.ts +172 -188
- package/src/internal/pictures/pictures.ts +50 -73
- package/src/internal/pictures/quiescence.ts +94 -0
- package/src/internal/reading/ready.ts +9 -3
- package/src/internal/supervisor/lifecycle.ts +40 -15
- package/dist/Plan-Bl2NM1D5.mjs.map +0 -1
- package/dist/Supervisor-TNKNOVzu.mjs.map +0 -1
- package/dist/page-ZxMhw16l.mjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Plan } from "./Motion.mjs";
|
|
2
2
|
import { Action, Box, CursorChanged, KeyChanged, Navigated, PageLoaded, PointerPressed, PointerReleased, Subject, SubjectContext, TextInserted, TrackEvent, TrackPerformed, TrackPlanned, WheelScrolled } from "./BrowserEvent.mjs";
|
|
3
3
|
import { BrowserError, Failed, InvalidRequest, NavigationFailed, NotActionable, NotFound, PolicyTimeout, StaleRef, Timeout } from "./BrowserError.mjs";
|
|
4
|
-
import { a as make$
|
|
4
|
+
import { a as make$20, c as Current, i as failWith, l as make$19, n as contextGone, o as reasonOf, r as decodeWith, s as undispatched } from "./context-BAjRj7Xo.mjs";
|
|
5
5
|
import { i as redact, n as parse, s as Correlation, t as addresses } from "./url-Cd04Okid.mjs";
|
|
6
6
|
import { BrowserPaint, CaptureStats, Frame, Image, Screenshot } from "./Frame.mjs";
|
|
7
7
|
import { _ as evidence, c as State, g as guard, h as ValidatedInputResultSchema, i as InputRequest, l as Text, m as PreparedInputResultSchema, o as Region, p as redacted, r as Found, s as ResolvedTarget, u as Zoom } from "./Page-B5cjaUp5.mjs";
|
|
@@ -9,7 +9,7 @@ import { Snapshot } from "./Snapshot.mjs";
|
|
|
9
9
|
import { t as match } from "./match.inpage-xOe9LNO0.mjs";
|
|
10
10
|
import { r as Changes, t as Change } from "./Change-DNvztNLu.mjs";
|
|
11
11
|
import { Window } from "./Moment.mjs";
|
|
12
|
-
import { Clock, Deferred, Duration, Effect, Exit, MutableRef, Option, Queue, Random, Ref, Result, Schedule, Schema, Scope, Semaphore, Stream, SynchronizedRef } from "effect";
|
|
12
|
+
import { Cause, Clock, Deferred, Duration, Effect, Exit, Fiber, MutableRef, Option, Queue, Random, Ref, Result, Schedule, Schema, Scope, Semaphore, Stream, SynchronizedRef } from "effect";
|
|
13
13
|
//#region src/internal/input/edit.inpage.ts
|
|
14
14
|
/**
|
|
15
15
|
* In the page: editing a field. It refuses text that a focused control could act on, focuses a
|
|
@@ -2166,7 +2166,7 @@ const mainFrame = (page, event) => "frame" in event ? event.frame.parentId === v
|
|
|
2166
2166
|
} : void 0;
|
|
2167
2167
|
/** A call to the page script, its arguments quoted as JavaScript literals. */
|
|
2168
2168
|
const scriptCall = (name, ...args) => `${name}(${args.map((arg) => JSON.stringify(arg)).join(", ")})`;
|
|
2169
|
-
const make$
|
|
2169
|
+
const make$18 = Effect.fnUntraced(function* (page) {
|
|
2170
2170
|
const { id, cdp, native, span, publish, now } = page;
|
|
2171
2171
|
const { send } = page.protocol;
|
|
2172
2172
|
const registration = yield* SynchronizedRef.make("none");
|
|
@@ -2352,7 +2352,7 @@ const toBrowserSeconds = (calibration, hostMillis) => (hostMillis + calibration.
|
|
|
2352
2352
|
* protocol session, stamped with the browser's clock when its run has a mapping, and is published
|
|
2353
2353
|
* as it is submitted.
|
|
2354
2354
|
*/
|
|
2355
|
-
const make$
|
|
2355
|
+
const make$17 = (page) => {
|
|
2356
2356
|
const { id, pointer, publish, now, noteInput, closedBy } = page;
|
|
2357
2357
|
const { send } = page.protocol;
|
|
2358
2358
|
const inputClocks = /* @__PURE__ */ new WeakMap();
|
|
@@ -2458,7 +2458,7 @@ const inputFailure = (operation, targets, failure) => {
|
|
|
2458
2458
|
return failWith(operation, failure.error === "outside" ? new InvalidRequest({ detail: failure.detail }) : failure.error === "stale" && typeof target === "string" ? new StaleRef({ ref: target }) : new NotActionable({ detail: failure.detail }));
|
|
2459
2459
|
};
|
|
2460
2460
|
const editFailure = (operation, ref, failure) => failWith(operation, failure.stale === true ? new StaleRef({ ref }) : new NotActionable({ detail: failure.error }));
|
|
2461
|
-
const make$
|
|
2461
|
+
const make$16 = (page, bridge) => {
|
|
2462
2462
|
const { id } = page;
|
|
2463
2463
|
const { current, evaluateIn, evaluateWithContext } = bridge;
|
|
2464
2464
|
const preparePolicy = (action, info, targets, flags = {}) => Effect.gen(function* () {
|
|
@@ -2686,7 +2686,7 @@ const description = (character) => {
|
|
|
2686
2686
|
* Keys and typing: a key chord held and released, each typed event, and the document a run of
|
|
2687
2687
|
* keys must stay in.
|
|
2688
2688
|
*/
|
|
2689
|
-
const make$
|
|
2689
|
+
const make$15 = (page, bridge, dispatch) => {
|
|
2690
2690
|
const { playwright } = page;
|
|
2691
2691
|
const { send } = page.protocol;
|
|
2692
2692
|
const { currentDocument } = bridge;
|
|
@@ -2893,7 +2893,7 @@ const timedOut = (operation, timeout) => failWith(operation, new Timeout({ milli
|
|
|
2893
2893
|
* Fail `effect` with `Timeout` once `timeout` has passed, and as much later again as `presented`
|
|
2894
2894
|
* says presentation has planned meanwhile.
|
|
2895
2895
|
*/
|
|
2896
|
-
const deadline$
|
|
2896
|
+
const deadline$2 = (operation, timeout, now, presented) => (effect) => Effect.suspend(() => {
|
|
2897
2897
|
const due = now() + Duration.toMillis(timeout);
|
|
2898
2898
|
const expiry = Effect.suspend(() => {
|
|
2899
2899
|
const left = due + presented() - now();
|
|
@@ -2931,10 +2931,10 @@ const useRun = (page, sender, name, run, action) => action.pipe(Effect.matchEffe
|
|
|
2931
2931
|
onFailure: (error) => run.close.pipe(Effect.andThen(sender.flush(name, run).pipe(Effect.ignore)), Effect.andThen(Effect.fail(error))),
|
|
2932
2932
|
onSuccess: (value) => run.close.pipe(Effect.andThen(sender.flush(name, run)), Effect.as(value))
|
|
2933
2933
|
}), Effect.ensuring(run.close.pipe(Effect.andThen(page.openings.clear))), Effect.provideService(Current, run));
|
|
2934
|
-
const make$
|
|
2934
|
+
const make$14 = (page, sender) => {
|
|
2935
2935
|
const { id, settings, mapping, lane, publish, now, noteInput, span, owned } = page;
|
|
2936
2936
|
const { inputClocks } = sender;
|
|
2937
|
-
const input = make$
|
|
2937
|
+
const input = make$19();
|
|
2938
2938
|
const admitted = /* @__PURE__ */ new Set();
|
|
2939
2939
|
const perform = (name, info, timeout, prepare, body, style = plain) => Effect.gen(function* () {
|
|
2940
2940
|
const startedAt = now();
|
|
@@ -2974,14 +2974,14 @@ const make$13 = (page, sender) => {
|
|
|
2974
2974
|
orElse: () => timedOut(name, timeout)
|
|
2975
2975
|
})))), Effect.tap(() => Effect.sync(() => {
|
|
2976
2976
|
queuedMillis = Math.round(now() - asked);
|
|
2977
|
-
})), Effect.andThen(deadline$
|
|
2977
|
+
})), Effect.andThen(deadline$2(name, timeout, now, () => presented)(action))));
|
|
2978
2978
|
});
|
|
2979
2979
|
const guard = settings.guard;
|
|
2980
2980
|
const action = guard === void 0 ? dispatch(useInput((run) => body({
|
|
2981
2981
|
...marks,
|
|
2982
2982
|
input: run
|
|
2983
2983
|
}, void 0))) : Effect.gen(function* () {
|
|
2984
|
-
const plan = yield* lane.read(name)(deadline$
|
|
2984
|
+
const plan = yield* lane.read(name)(deadline$2(name, settings.actionTimeout, now, () => 0)(prepare)).pipe(span("Page.prepare", {}, "Debug"));
|
|
2985
2985
|
yield* guard(plan.request).pipe(Effect.mapError((reason) => undispatched(name, reason)), Effect.timeoutOrElse({
|
|
2986
2986
|
duration: settings.policyTimeout,
|
|
2987
2987
|
orElse: () => failWith(name, new PolicyTimeout({ millis: Duration.toMillis(settings.policyTimeout) }))
|
|
@@ -3049,7 +3049,7 @@ const make$13 = (page, sender) => {
|
|
|
3049
3049
|
* plan, published before its first move, from where viewers last saw the pointer when it is
|
|
3050
3050
|
* shown, and a wheel scroll goes in the style's steps.
|
|
3051
3051
|
*/
|
|
3052
|
-
const make$
|
|
3052
|
+
const make$13 = (page, dispatch, viewport) => {
|
|
3053
3053
|
const { id, pointer, publish, now, span } = page;
|
|
3054
3054
|
const { inputClocks, inputCall, dispatchMouse, sendMouse } = dispatch;
|
|
3055
3055
|
const moveTo = (operation, marks, to, cursor, travel = "approach") => Effect.gen(function* () {
|
|
@@ -3146,8 +3146,8 @@ const make$12 = (page, dispatch, viewport) => {
|
|
|
3146
3146
|
* `pushState` asks for no document, and a navigation a handler starts after a fetch answers is the
|
|
3147
3147
|
* next look's to see. A tab the input opened waits for the browser's registration too.
|
|
3148
3148
|
*/
|
|
3149
|
-
const settling
|
|
3150
|
-
const make$
|
|
3149
|
+
const settling = Duration.seconds(5);
|
|
3150
|
+
const make$12 = (page, bridge) => {
|
|
3151
3151
|
const document = () => bridge.frameTag().document;
|
|
3152
3152
|
let parsed = -1;
|
|
3153
3153
|
let changed = Deferred.makeUnsafe();
|
|
@@ -3166,7 +3166,7 @@ const make$11 = (page, bridge) => {
|
|
|
3166
3166
|
yield* bridge.evaluate(operation, scriptCall("settle")).pipe(Effect.provideService(Current, void 0), Effect.catchIf(contextGone, () => Effect.void), Effect.onError(() => page.stopLoading));
|
|
3167
3167
|
while (document() > before.document && parsed < document()) yield* Deferred.await(changed);
|
|
3168
3168
|
}).pipe(Effect.timeoutOrElse({
|
|
3169
|
-
duration: settling
|
|
3169
|
+
duration: settling,
|
|
3170
3170
|
orElse: () => Effect.fail("unsettled")
|
|
3171
3171
|
}), Effect.catch(() => Effect.annotateCurrentSpan("settled", false)), Effect.andThen(page.openings.settle(before.openings)), page.span("Page.settle", {}, "Debug"));
|
|
3172
3172
|
return {
|
|
@@ -3196,7 +3196,7 @@ const resolvedTarget = (result) => new ResolvedTarget({
|
|
|
3196
3196
|
cursor: result.cursor,
|
|
3197
3197
|
...result.href === void 0 ? {} : { href: result.href }
|
|
3198
3198
|
});
|
|
3199
|
-
const make$
|
|
3199
|
+
const make$11 = (bridge, viewport, guard, pointer, dispatch, settling) => {
|
|
3200
3200
|
const { evaluate } = bridge;
|
|
3201
3201
|
const { mutate } = guard;
|
|
3202
3202
|
const { moveTo, wheel } = pointer;
|
|
@@ -3254,20 +3254,20 @@ const buttonMask = {
|
|
|
3254
3254
|
middle: 4
|
|
3255
3255
|
};
|
|
3256
3256
|
const partsOf = (page, bridge, viewport) => {
|
|
3257
|
-
const dispatch = make$
|
|
3258
|
-
const pointer = make$
|
|
3259
|
-
const guard = make$
|
|
3260
|
-
const settling = make$
|
|
3257
|
+
const dispatch = make$17(page);
|
|
3258
|
+
const pointer = make$13(page, dispatch, viewport);
|
|
3259
|
+
const guard = make$16(page, bridge);
|
|
3260
|
+
const settling = make$12(page, bridge);
|
|
3261
3261
|
return {
|
|
3262
3262
|
page,
|
|
3263
3263
|
bridge,
|
|
3264
3264
|
...settling,
|
|
3265
3265
|
viewportFor: viewport.viewportFor,
|
|
3266
|
-
perform: make$
|
|
3266
|
+
perform: make$14(page, dispatch),
|
|
3267
3267
|
...guard,
|
|
3268
|
-
...make$
|
|
3268
|
+
...make$11(bridge, viewport, guard, pointer, dispatch, settling),
|
|
3269
3269
|
...pointer,
|
|
3270
|
-
...make$
|
|
3270
|
+
...make$15(page, bridge, dispatch),
|
|
3271
3271
|
sendMouse: dispatch.sendMouse,
|
|
3272
3272
|
flush: dispatch.flush
|
|
3273
3273
|
};
|
|
@@ -3584,7 +3584,7 @@ const select = (input) => {
|
|
|
3584
3584
|
return result.detail;
|
|
3585
3585
|
}));
|
|
3586
3586
|
};
|
|
3587
|
-
const make$
|
|
3587
|
+
const make$10 = (page, bridge, viewport) => {
|
|
3588
3588
|
const parts = partsOf(page, bridge, viewport);
|
|
3589
3589
|
return {
|
|
3590
3590
|
perform: parts.perform,
|
|
@@ -3689,6 +3689,47 @@ const tally = (now) => {
|
|
|
3689
3689
|
};
|
|
3690
3690
|
};
|
|
3691
3691
|
//#endregion
|
|
3692
|
+
//#region src/internal/pictures/quiescence.ts
|
|
3693
|
+
/** Actual native replies outlive callers; bounded transactions retain them without holding teardown. */
|
|
3694
|
+
const deadline$1 = Duration.seconds(2);
|
|
3695
|
+
const make$9 = (options) => {
|
|
3696
|
+
const replies = make$19();
|
|
3697
|
+
const pending = /* @__PURE__ */ new Map();
|
|
3698
|
+
const late = (kind) => options.error(/* @__PURE__ */ new Error(`${kind} exceeded its deadline`));
|
|
3699
|
+
const track = (operation, actual, failed) => {
|
|
3700
|
+
const reply = actual.then(() => void 0, failed);
|
|
3701
|
+
pending.set(operation, reply);
|
|
3702
|
+
return reply.finally(() => {
|
|
3703
|
+
if (pending.get(operation) === reply) pending.delete(operation);
|
|
3704
|
+
});
|
|
3705
|
+
};
|
|
3706
|
+
const wait = (operation) => (operation === void 0 ? replies.idle.pipe(Effect.andThen(Effect.promise(() => Promise.all(pending.values())))) : Effect.promise(() => pending.get(operation) ?? Promise.resolve())).pipe(Effect.asVoid, Effect.interruptible, Effect.timeoutOrElse({
|
|
3707
|
+
duration: deadline$1,
|
|
3708
|
+
orElse: () => Effect.fail(late(operation ?? pending.keys().next().value ?? "picture restoration"))
|
|
3709
|
+
}), Effect.provideService(Clock.Clock, options.clock));
|
|
3710
|
+
const excluding = (picture) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
|
|
3711
|
+
yield* restore(wait());
|
|
3712
|
+
if (options.closed()) return yield* options.error(/* @__PURE__ */ new Error("Target page has been closed"));
|
|
3713
|
+
const current = options.current();
|
|
3714
|
+
const run = yield* replies.begin;
|
|
3715
|
+
const result = yield* restore(options.pause(current).pipe(Effect.andThen(picture), Effect.provideService(Current, run))).pipe(Effect.exit);
|
|
3716
|
+
const cleaned = yield* wait().pipe(Effect.andThen(options.resume(current)), Effect.timeoutOrElse({
|
|
3717
|
+
duration: deadline$1,
|
|
3718
|
+
orElse: () => Effect.fail(late("picture restoration"))
|
|
3719
|
+
}), Effect.provideService(Clock.Clock, options.clock), Effect.exit, Effect.forkChild, Effect.flatMap(Fiber.join));
|
|
3720
|
+
if (Exit.isFailure(cleaned)) options.fail(current, options.error(Cause.squash(cleaned.cause)));
|
|
3721
|
+
if (Exit.isFailure(result)) return yield* Effect.failCause(result.cause);
|
|
3722
|
+
if (Exit.isFailure(cleaned)) return yield* Effect.failCause(cleaned.cause);
|
|
3723
|
+
return result.value;
|
|
3724
|
+
}));
|
|
3725
|
+
return {
|
|
3726
|
+
excluding,
|
|
3727
|
+
idle: wait(),
|
|
3728
|
+
wait,
|
|
3729
|
+
track
|
|
3730
|
+
};
|
|
3731
|
+
};
|
|
3732
|
+
//#endregion
|
|
3692
3733
|
//#region src/internal/pictures/capture.ts
|
|
3693
3734
|
/**
|
|
3694
3735
|
* One CDP screencast per page, with bounded transport replies and per-reader loss accounting.
|
|
@@ -3700,36 +3741,6 @@ const deadline = Duration.seconds(2);
|
|
|
3700
3741
|
const sameSize = (left, right) => Math.abs(left.width - right.width) < 1 && Math.abs(left.height - right.height) < 1;
|
|
3701
3742
|
const sameShape = (image, device) => Math.abs(image.width * device.height - image.height * device.width) < device.width + device.height;
|
|
3702
3743
|
const outlasting = Duration.seconds(1);
|
|
3703
|
-
const excludedFor = Duration.seconds(10);
|
|
3704
|
-
const settling = Duration.millis(50);
|
|
3705
|
-
/**
|
|
3706
|
-
* Chromium draws the library's own clipped pictures into the running screencast. Where Playwright
|
|
3707
|
-
* emulates the viewport they keep the page's device size, and its shape when the crop has the
|
|
3708
|
-
* viewport's proportions, so nothing in a frame tells them apart: a frame painted, or arriving,
|
|
3709
|
-
* while one is taken is left out, the page's own included. A crop on the page's own session is
|
|
3710
|
-
* drawn at the crop's size, so there only a frame of another size than the page's is left out.
|
|
3711
|
-
*/
|
|
3712
|
-
const pictureWindows = (now) => {
|
|
3713
|
-
let windows = [];
|
|
3714
|
-
return {
|
|
3715
|
-
drawn: ({ hostTime, timing, receivedAt }, foreign) => windows.some((window) => {
|
|
3716
|
-
const until = window.until + Duration.toMillis(settling);
|
|
3717
|
-
return (foreign || !window.resized) && (hostTime + timing.uncertaintyMillis >= window.from && hostTime - timing.uncertaintyMillis <= until || receivedAt >= window.from && receivedAt <= until);
|
|
3718
|
-
}),
|
|
3719
|
-
excluding: (picture, resized = false) => Effect.acquireUseRelease(Effect.sync(() => {
|
|
3720
|
-
const window = {
|
|
3721
|
-
from: now(),
|
|
3722
|
-
until: Number.POSITIVE_INFINITY,
|
|
3723
|
-
resized
|
|
3724
|
-
};
|
|
3725
|
-
const since = window.from - Duration.toMillis(excludedFor);
|
|
3726
|
-
windows = [...windows.filter((kept) => kept.until > since), window];
|
|
3727
|
-
return window;
|
|
3728
|
-
}), () => picture, (window) => Effect.sync(() => {
|
|
3729
|
-
window.until = now();
|
|
3730
|
-
}))
|
|
3731
|
-
};
|
|
3732
|
-
};
|
|
3733
3744
|
/**
|
|
3734
3745
|
* A native frame as readers get it: its picture's size, else the capture's or its device's, and
|
|
3735
3746
|
* its paint mapped by the browser's newest estimate, which may be older than the frame and says
|
|
@@ -3831,7 +3842,6 @@ const sizeFilter = (options, deliver, drop) => Effect.gen(function* () {
|
|
|
3831
3842
|
expected = viewport;
|
|
3832
3843
|
},
|
|
3833
3844
|
/** Whether a frame of this device size shows the page, as far as the capture knows. */
|
|
3834
|
-
expects: (device) => expected !== null && sameSize(device, expected),
|
|
3835
3845
|
offer: (frame, timestamp, image, device) => {
|
|
3836
3846
|
if (image !== void 0 && !sameShape(image, device)) {
|
|
3837
3847
|
drop(1);
|
|
@@ -3895,7 +3905,7 @@ const confirmation = (read, current, why, error) => (frame) => Effect.suspend(()
|
|
|
3895
3905
|
return after.generation === generation && after.replies === 0 && current(frame);
|
|
3896
3906
|
}));
|
|
3897
3907
|
});
|
|
3898
|
-
const isCurrent = (frame, generation, latest) => generation !== void 0 && generation.
|
|
3908
|
+
const isCurrent = (frame, generation, latest) => generation !== void 0 && generation.phase === "Capturing" && generation.failure === void 0 && Option.getOrUndefined(latest) === frame && generation.transport.frameTag().document === frame.document;
|
|
3899
3909
|
const currentFrame = (generation, latest) => Option.getOrUndefined(Option.filter(latest, (frame) => isCurrent(frame, generation, latest)));
|
|
3900
3910
|
/** One reader counts its own missed envelopes without hiding gaps inside stream chunks. */
|
|
3901
3911
|
const frames = (subscription, baseline, why, missed) => {
|
|
@@ -3909,19 +3919,44 @@ const frames = (subscription, baseline, why, missed) => {
|
|
|
3909
3919
|
});
|
|
3910
3920
|
})));
|
|
3911
3921
|
};
|
|
3922
|
+
const renewals = Effect.fnUntraced(function* (options) {
|
|
3923
|
+
const renewing = yield* Queue.sliding(1);
|
|
3924
|
+
yield* Queue.take(renewing).pipe(Effect.andThen(options.renew), Effect.andThen(Effect.sleep(Duration.seconds(1))), Effect.provideService(Clock.Clock, options.clock), Effect.forever, Effect.forkScoped);
|
|
3925
|
+
return renewing;
|
|
3926
|
+
});
|
|
3927
|
+
const receive = (options, current, replies, counts, sizes, renewing, fail) => (native) => {
|
|
3928
|
+
if (current.phase === "Stopped") return;
|
|
3929
|
+
counts.count("received");
|
|
3930
|
+
if (replies.size >= replyCapacity) {
|
|
3931
|
+
fail(current, options.error(/* @__PURE__ */ new Error("screencast acknowledgement capacity exceeded")));
|
|
3932
|
+
return;
|
|
3933
|
+
}
|
|
3934
|
+
const reply = current.transport.acknowledge(native.sessionId).then(() => void 0, (cause) => {
|
|
3935
|
+
if (current.phase !== "Stopped") fail(current, options.error(cause));
|
|
3936
|
+
}).then(() => void replies.delete(reply));
|
|
3937
|
+
replies.add(reply);
|
|
3938
|
+
const browserSeconds = native.metadata.timestamp;
|
|
3939
|
+
const timestamp = browserSeconds === void 0 ? NaN : browserSeconds * 1e3;
|
|
3940
|
+
if (!Number.isFinite(timestamp)) return counts.count("missingTimestamp");
|
|
3941
|
+
if (current.predecessor !== void 0 && timestamp <= current.predecessor) return counts.count("late");
|
|
3942
|
+
Queue.offerUnsafe(renewing, void 0);
|
|
3943
|
+
const { frame, image, device } = timed(options, native, timestamp, current);
|
|
3944
|
+
if (current.phase === "Paused") return counts.count("duringPictures");
|
|
3945
|
+
sizes.offer(frame, timestamp, image, device);
|
|
3946
|
+
};
|
|
3912
3947
|
const make$8 = (options) => Effect.gen(function* () {
|
|
3913
3948
|
const lock = yield* Semaphore.make(1);
|
|
3914
3949
|
const replies = /* @__PURE__ */ new Set();
|
|
3915
3950
|
let generation;
|
|
3916
3951
|
const closed = yield* Deferred.make();
|
|
3917
|
-
|
|
3952
|
+
const pageScope = yield* Effect.scope;
|
|
3953
|
+
const isClosed = () => pageScope.state._tag === "Closed" || Deferred.isDoneUnsafe(closed);
|
|
3918
3954
|
let latest = Option.none();
|
|
3919
3955
|
let history = [];
|
|
3920
3956
|
const keepMillis = Duration.toMillis(options.frameHistory);
|
|
3921
3957
|
const now = () => Number(options.clock.monotonicTimeNanosUnsafe()) / 1e6;
|
|
3922
3958
|
const counts = tally(now);
|
|
3923
3959
|
let delivered = 0;
|
|
3924
|
-
const pictures = pictureWindows(now);
|
|
3925
3960
|
const current = (frame) => isCurrent(frame, generation, latest);
|
|
3926
3961
|
const deliver = (frame, timestamp) => {
|
|
3927
3962
|
const current = generation;
|
|
@@ -3940,8 +3975,7 @@ const make$8 = (options) => Effect.gen(function* () {
|
|
|
3940
3975
|
});
|
|
3941
3976
|
};
|
|
3942
3977
|
const sizes = yield* sizeFilter(options, deliver, (frames) => counts.count("foreignSize", frames));
|
|
3943
|
-
const renewing = yield*
|
|
3944
|
-
yield* Queue.take(renewing).pipe(Effect.andThen(options.renew), Effect.andThen(Effect.sleep(Duration.seconds(1))), Effect.provideService(Clock.Clock, options.clock), Effect.forever, Effect.forkScoped);
|
|
3978
|
+
const renewing = yield* renewals(options);
|
|
3945
3979
|
const notifyFailure = (current, failure) => {
|
|
3946
3980
|
if (current.failure !== void 0) return;
|
|
3947
3981
|
current.failure = failure;
|
|
@@ -3949,37 +3983,67 @@ const make$8 = (options) => Effect.gen(function* () {
|
|
|
3949
3983
|
_tag: "Failure",
|
|
3950
3984
|
error: failure
|
|
3951
3985
|
});
|
|
3986
|
+
stop(current);
|
|
3952
3987
|
};
|
|
3988
|
+
const failed = (current) => (cause) => notifyFailure(current, options.error(cause));
|
|
3989
|
+
const stopNative = (current) => pictures.track("screencast stop", current.transport.stop(), failed(current));
|
|
3990
|
+
const startNative = (current) => pictures.track("screencast start", current.transport.start({
|
|
3991
|
+
format: "jpeg",
|
|
3992
|
+
quality: current.quality,
|
|
3993
|
+
...current.size === null ? {} : {
|
|
3994
|
+
maxWidth: current.size.width,
|
|
3995
|
+
maxHeight: current.size.height
|
|
3996
|
+
}
|
|
3997
|
+
}), failed(current));
|
|
3953
3998
|
const stop = (current) => {
|
|
3954
|
-
if (
|
|
3955
|
-
current.
|
|
3999
|
+
if (current.phase === "Stopped") return;
|
|
4000
|
+
const paused = current.phase === "Paused";
|
|
4001
|
+
current.phase = "Stopped";
|
|
3956
4002
|
sizes.end();
|
|
3957
4003
|
current.unlisten();
|
|
3958
|
-
|
|
3959
|
-
notifyFailure(current, options.error(cause));
|
|
3960
|
-
});
|
|
3961
|
-
current.stopReply = reply;
|
|
3962
|
-
unsettledStop = reply;
|
|
3963
|
-
reply.then(() => {
|
|
3964
|
-
if (unsettledStop === reply) unsettledStop = void 0;
|
|
3965
|
-
});
|
|
3966
|
-
};
|
|
3967
|
-
const fail = (current, failure) => {
|
|
3968
|
-
notifyFailure(current, failure);
|
|
3969
|
-
stop(current);
|
|
4004
|
+
if (!paused) stopNative(current);
|
|
3970
4005
|
};
|
|
3971
4006
|
const gone = () => options.error(/* @__PURE__ */ new Error("Target page has been closed"));
|
|
3972
|
-
const stopDeadline = () => options.error(/* @__PURE__ */ new Error("screencast stop exceeded its deadline"));
|
|
3973
4007
|
const why = told(closed, gone, options.clock);
|
|
3974
|
-
const
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
4008
|
+
const awaitStop = (current) => pictures.wait("screencast stop").pipe(Effect.catch((error) => Effect.sync(() => notifyFailure(current, error))));
|
|
4009
|
+
const healthy = (current) => Effect.suspend(() => current.failure === void 0 ? Effect.void : Effect.fail(current.failure));
|
|
4010
|
+
const pictures = make$9({
|
|
4011
|
+
clock: options.clock,
|
|
4012
|
+
error: options.error,
|
|
4013
|
+
closed: isClosed,
|
|
4014
|
+
current: () => generation,
|
|
4015
|
+
fail: (current, error) => {
|
|
4016
|
+
if (current !== void 0) notifyFailure(current, error);
|
|
4017
|
+
},
|
|
4018
|
+
pause: (current) => Effect.gen(function* () {
|
|
4019
|
+
if (current?.phase !== "Capturing" || current.failure !== void 0) return;
|
|
4020
|
+
current.phase = "Paused";
|
|
4021
|
+
latest = Option.none();
|
|
4022
|
+
sizes.end();
|
|
4023
|
+
stopNative(current);
|
|
4024
|
+
yield* pictures.wait("screencast stop").pipe(Effect.tapError((error) => Effect.sync(() => notifyFailure(current, error))));
|
|
4025
|
+
yield* healthy(current);
|
|
4026
|
+
}),
|
|
4027
|
+
resume: (current) => Effect.gen(function* () {
|
|
4028
|
+
const resumable = () => {
|
|
4029
|
+
if (current === void 0 || generation !== current) return false;
|
|
4030
|
+
if (current.subscribers.size === 0) {
|
|
4031
|
+
stop(current);
|
|
4032
|
+
generation = void 0;
|
|
4033
|
+
return false;
|
|
4034
|
+
}
|
|
4035
|
+
return current.phase !== "Stopped" && current.failure === void 0 && !isClosed();
|
|
4036
|
+
};
|
|
4037
|
+
if (current === void 0 || !resumable()) return;
|
|
4038
|
+
const viewport = yield* readViewport(options);
|
|
4039
|
+
if (!resumable()) return;
|
|
4040
|
+
sizes.restart(viewport);
|
|
4041
|
+
current.phase = "Capturing";
|
|
4042
|
+
startNative(current);
|
|
4043
|
+
yield* pictures.wait("screencast start");
|
|
4044
|
+
yield* healthy(current);
|
|
4045
|
+
})
|
|
4046
|
+
});
|
|
3983
4047
|
const leave = (current, subscription) => Effect.gen(function* () {
|
|
3984
4048
|
current.subscribers.delete(subscription);
|
|
3985
4049
|
yield* Queue.shutdown(subscription);
|
|
@@ -3989,50 +4053,25 @@ const make$8 = (options) => Effect.gen(function* () {
|
|
|
3989
4053
|
if (generation === current) generation = void 0;
|
|
3990
4054
|
});
|
|
3991
4055
|
const acquire = (screencast) => lock.withPermits(1)(Effect.gen(function* () {
|
|
3992
|
-
if (
|
|
4056
|
+
if (isClosed()) return yield* gone();
|
|
3993
4057
|
let current = generation;
|
|
3994
4058
|
const starting = current === void 0;
|
|
3995
4059
|
if (current === void 0) {
|
|
3996
|
-
yield*
|
|
4060
|
+
yield* pictures.idle;
|
|
3997
4061
|
const [transport, { calibration, viewport }] = yield* prepare(options, screencast);
|
|
3998
4062
|
const size = screencast.size ?? viewport;
|
|
3999
|
-
if (
|
|
4000
|
-
|
|
4063
|
+
if (isClosed()) return yield* gone();
|
|
4064
|
+
current = {
|
|
4001
4065
|
subscribers: /* @__PURE__ */ new Set(),
|
|
4002
4066
|
transport,
|
|
4003
4067
|
unlisten: () => void 0,
|
|
4004
4068
|
calibration,
|
|
4005
4069
|
quality: screencast.quality ?? 80,
|
|
4006
4070
|
size,
|
|
4007
|
-
|
|
4071
|
+
phase: "Capturing",
|
|
4008
4072
|
predecessor: void 0,
|
|
4009
|
-
failure: void 0
|
|
4010
|
-
stopReply: void 0,
|
|
4011
|
-
onFrame: (native) => {
|
|
4012
|
-
if (!created.accepting) return;
|
|
4013
|
-
counts.count("received");
|
|
4014
|
-
if (replies.size >= replyCapacity) {
|
|
4015
|
-
fail(created, options.error(/* @__PURE__ */ new Error("screencast acknowledgement capacity exceeded")));
|
|
4016
|
-
return;
|
|
4017
|
-
}
|
|
4018
|
-
const reply = created.transport.acknowledge(native.sessionId).then(() => {
|
|
4019
|
-
replies.delete(reply);
|
|
4020
|
-
}, (cause) => {
|
|
4021
|
-
replies.delete(reply);
|
|
4022
|
-
if (created.accepting) fail(created, options.error(cause));
|
|
4023
|
-
});
|
|
4024
|
-
replies.add(reply);
|
|
4025
|
-
const browserSeconds = native.metadata.timestamp;
|
|
4026
|
-
const timestamp = browserSeconds === void 0 ? NaN : browserSeconds * 1e3;
|
|
4027
|
-
if (!Number.isFinite(timestamp)) return counts.count("missingTimestamp");
|
|
4028
|
-
if (created.predecessor !== void 0 && timestamp <= created.predecessor) return counts.count("late");
|
|
4029
|
-
Queue.offerUnsafe(renewing, void 0);
|
|
4030
|
-
const { frame, image, device } = timed(options, native, timestamp, created);
|
|
4031
|
-
if (pictures.drawn(frame, !sizes.expects(device))) return counts.count("duringPictures");
|
|
4032
|
-
sizes.offer(frame, timestamp, image, device);
|
|
4033
|
-
}
|
|
4073
|
+
failure: void 0
|
|
4034
4074
|
};
|
|
4035
|
-
current = created;
|
|
4036
4075
|
generation = current;
|
|
4037
4076
|
latest = Option.none();
|
|
4038
4077
|
sizes.restart(viewport);
|
|
@@ -4046,24 +4085,13 @@ const make$8 = (options) => Effect.gen(function* () {
|
|
|
4046
4085
|
const baseline = delivered;
|
|
4047
4086
|
const frame = currentFrame(current, latest);
|
|
4048
4087
|
if (starting) {
|
|
4049
|
-
const { transport, quality, size } = current;
|
|
4050
4088
|
const listening = current;
|
|
4051
|
-
current.unlisten = transport.listen({
|
|
4052
|
-
frame: current
|
|
4053
|
-
lost: (error) =>
|
|
4054
|
-
});
|
|
4055
|
-
const screencast = Effect.tryPromise({
|
|
4056
|
-
try: () => transport.start({
|
|
4057
|
-
format: "jpeg",
|
|
4058
|
-
quality,
|
|
4059
|
-
...size === null ? {} : {
|
|
4060
|
-
maxWidth: size.width,
|
|
4061
|
-
maxHeight: size.height
|
|
4062
|
-
}
|
|
4063
|
-
}),
|
|
4064
|
-
catch: options.error
|
|
4089
|
+
current.unlisten = listening.transport.listen({
|
|
4090
|
+
frame: receive(options, current, replies, counts, sizes, renewing, notifyFailure),
|
|
4091
|
+
lost: (error) => notifyFailure(listening, error)
|
|
4065
4092
|
});
|
|
4066
|
-
const
|
|
4093
|
+
const screencast = Effect.promise(() => startNative(listening)).pipe(Effect.andThen(healthy(listening)));
|
|
4094
|
+
const started = yield* options.watch.pipe(Effect.zip(screencast, { concurrent: true }), Effect.interruptible, Effect.timeoutOrElse({
|
|
4067
4095
|
duration: deadline,
|
|
4068
4096
|
orElse: () => Effect.fail(options.error(/* @__PURE__ */ new Error("screencast start exceeded its deadline")))
|
|
4069
4097
|
}), Effect.provideService(Clock.Clock, options.clock), Effect.exit);
|
|
@@ -4079,30 +4107,29 @@ const make$8 = (options) => Effect.gen(function* () {
|
|
|
4079
4107
|
frame
|
|
4080
4108
|
};
|
|
4081
4109
|
}));
|
|
4082
|
-
const open = (screencast = {}) => Effect.acquireRelease(acquire(screencast), ({ current, subscription }) => lock.withPermits(1)(leave(current, subscription))).pipe(Effect.map((lease) => ({
|
|
4110
|
+
const open = (screencast = {}) => Effect.acquireRelease(acquire(screencast), ({ current, subscription }) => Effect.sync(() => current.subscribers.delete(subscription)).pipe(Effect.andThen(lock.withPermits(1)(leave(current, subscription))))).pipe(Effect.map((lease) => ({
|
|
4083
4111
|
current: lease.frame,
|
|
4084
4112
|
stream: frames(lease.subscription, lease.baseline, why, (count) => counts.count("lost", count))
|
|
4085
4113
|
})));
|
|
4086
|
-
yield* Effect.addFinalizer(() => lock.withPermits(1)(Effect.suspend(() => {
|
|
4114
|
+
yield* Effect.addFinalizer(() => Effect.sync(() => Deferred.doneUnsafe(closed, Exit.void)).pipe(Effect.andThen(lock.withPermits(1)(Effect.suspend(() => {
|
|
4087
4115
|
const current = generation;
|
|
4088
|
-
Deferred.doneUnsafe(closed, Exit.void);
|
|
4089
4116
|
if (current === void 0) return Effect.void;
|
|
4090
|
-
|
|
4117
|
+
notifyFailure(current, gone());
|
|
4091
4118
|
return awaitStop(current);
|
|
4092
|
-
})));
|
|
4119
|
+
})))));
|
|
4093
4120
|
return {
|
|
4094
4121
|
open,
|
|
4095
4122
|
stream: (options) => Stream.unwrap(Effect.map(open(options), ({ stream }) => stream)),
|
|
4096
4123
|
latest: Effect.sync(() => latest),
|
|
4097
4124
|
recent: Effect.sync(() => history),
|
|
4098
|
-
active: Effect.sync(() => generation
|
|
4125
|
+
active: Effect.sync(() => generation !== void 0 && generation.phase !== "Stopped"),
|
|
4099
4126
|
sync: Effect.suspend(() => synced(generation, why, options.error)),
|
|
4100
4127
|
current,
|
|
4101
4128
|
confirm: confirmation(() => ({
|
|
4102
4129
|
generation,
|
|
4103
4130
|
replies: replies.size
|
|
4104
4131
|
}), current, why, options.error),
|
|
4105
|
-
excluding: pictures.excluding,
|
|
4132
|
+
excluding: (picture) => lock.withPermits(1)(pictures.excluding(picture)),
|
|
4106
4133
|
stats: (windowMillis) => Effect.sync(() => new CaptureStats({
|
|
4107
4134
|
...counts.read(windowMillis),
|
|
4108
4135
|
ackBacklog: replies.size
|
|
@@ -4366,22 +4393,23 @@ const ScreenSize = Schema.Struct({
|
|
|
4366
4393
|
height: Schema.Int
|
|
4367
4394
|
});
|
|
4368
4395
|
const camera = (page, bridge, viewport, capture) => {
|
|
4369
|
-
const { playwright,
|
|
4396
|
+
const { playwright, native, within } = page;
|
|
4370
4397
|
const { send } = page.protocol;
|
|
4371
|
-
const actionMillis = Duration.toMillis(settings.actionTimeout);
|
|
4372
4398
|
let ratio = 1;
|
|
4373
|
-
const alone = Semaphore.makeUnsafe(1).withPermits(1);
|
|
4374
4399
|
let screenHeld = false;
|
|
4375
|
-
const holdScreen =
|
|
4376
|
-
|
|
4377
|
-
height
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4400
|
+
const holdScreen = Effect.fnUntraced(function* (operation) {
|
|
4401
|
+
if (screenHeld) return;
|
|
4402
|
+
const { width, height } = yield* bridge.evaluate(operation, scriptCall("screenSize")).pipe(Effect.flatMap(decodeWith(operation, ScreenSize)));
|
|
4403
|
+
yield* native(operation, () => send("Emulation.setDeviceMetricsOverride", {
|
|
4404
|
+
width: 0,
|
|
4405
|
+
height: 0,
|
|
4406
|
+
deviceScaleFactor: 0,
|
|
4407
|
+
mobile: false,
|
|
4408
|
+
screenWidth: width,
|
|
4409
|
+
screenHeight: height
|
|
4410
|
+
}));
|
|
4383
4411
|
screenHeld = true;
|
|
4384
|
-
})
|
|
4412
|
+
});
|
|
4385
4413
|
const decoded = (operation, data, format) => {
|
|
4386
4414
|
const size = format === "png" ? pngSize(data) : jpegSize(data);
|
|
4387
4415
|
return size === void 0 ? failWith(operation, new Failed({ detail: `the browser's picture is not a ${format.toUpperCase()}` })) : Effect.succeed(new Image({
|
|
@@ -4390,18 +4418,19 @@ const camera = (page, bridge, viewport, capture) => {
|
|
|
4390
4418
|
...size
|
|
4391
4419
|
}));
|
|
4392
4420
|
};
|
|
4393
|
-
const
|
|
4421
|
+
const take = (operation, format, run) => native(operation, run).pipe(untilPainted, Effect.flatMap((data) => decoded(operation, data, format)));
|
|
4422
|
+
const shot = (operation, format, quality, clip) => take(operation, format, () => send("Page.captureScreenshot", {
|
|
4394
4423
|
format,
|
|
4395
4424
|
...format === "jpeg" ? { quality } : {},
|
|
4396
4425
|
...clip === void 0 ? {} : { clip }
|
|
4397
|
-
})
|
|
4398
|
-
const emulatedShot = (operation, format, quality, crop) =>
|
|
4426
|
+
}).then(({ data }) => Buffer.from(data, "base64")));
|
|
4427
|
+
const emulatedShot = (operation, format, quality, crop) => take(operation, format, () => playwright.screenshot({
|
|
4399
4428
|
type: format,
|
|
4400
4429
|
...format === "jpeg" ? { quality } : {},
|
|
4401
4430
|
scale: "css",
|
|
4402
|
-
timeout:
|
|
4431
|
+
timeout: 0,
|
|
4403
4432
|
...crop === void 0 ? {} : { clip: crop }
|
|
4404
|
-
})
|
|
4433
|
+
}));
|
|
4405
4434
|
return (operation, quality, crop, format = "jpeg") => Effect.gen(function* () {
|
|
4406
4435
|
const known = viewport.knownViewport();
|
|
4407
4436
|
let whole;
|
|
@@ -4412,9 +4441,9 @@ const camera = (page, bridge, viewport, capture) => {
|
|
|
4412
4441
|
const emulated = playwright.viewportSize();
|
|
4413
4442
|
if (emulated !== null) {
|
|
4414
4443
|
if (whole !== void 0) ratio = whole.width / emulated.width;
|
|
4415
|
-
return yield*
|
|
4444
|
+
return yield* emulatedShot(operation, format, quality, crop);
|
|
4416
4445
|
}
|
|
4417
|
-
const [metrics] = yield*
|
|
4446
|
+
const [metrics] = yield* native(operation, () => send("Page.getLayoutMetrics")).pipe(Effect.flatMap(decodeWith(operation, LayoutMetrics)), Effect.zip(crop === void 0 ? Effect.void : holdScreen(operation), { concurrent: true }));
|
|
4418
4447
|
const measured = metrics.contentSize.width / metrics.cssContentSize.width;
|
|
4419
4448
|
ratio = Number.isFinite(measured) && measured > 0 ? measured : 1;
|
|
4420
4449
|
if (crop === void 0 && ratio === 1) {
|
|
@@ -4429,14 +4458,14 @@ const camera = (page, bridge, viewport, capture) => {
|
|
|
4429
4458
|
};
|
|
4430
4459
|
const { pageX, pageY, scale } = metrics.cssVisualViewport;
|
|
4431
4460
|
yield* holdScreen(operation);
|
|
4432
|
-
return yield*
|
|
4461
|
+
return yield* shot(operation, format, quality, {
|
|
4433
4462
|
x: pageX + rect.x,
|
|
4434
4463
|
y: pageY + rect.y,
|
|
4435
4464
|
width: Math.floor(rect.width / scale + .001),
|
|
4436
4465
|
height: Math.floor(rect.height / scale + .001),
|
|
4437
4466
|
scale: scale / ratio
|
|
4438
|
-
})
|
|
4439
|
-
}).pipe(within(operation));
|
|
4467
|
+
});
|
|
4468
|
+
}).pipe(capture.excluding, within(operation));
|
|
4440
4469
|
};
|
|
4441
4470
|
const millisOf = (input) => Option.match(Duration.fromInput(input), {
|
|
4442
4471
|
onNone: () => NaN,
|
|
@@ -4711,8 +4740,9 @@ const make$5 = (page, bridge, capture) => (options = {}) => {
|
|
|
4711
4740
|
const running = yield* capture.active;
|
|
4712
4741
|
let { received } = yield* capture.stats();
|
|
4713
4742
|
let stirred = running ? page.now() : Number.POSITIVE_INFINITY;
|
|
4714
|
-
const look = Effect.
|
|
4715
|
-
|
|
4743
|
+
const look = Effect.gen(function* () {
|
|
4744
|
+
const stats = yield* capture.stats();
|
|
4745
|
+
if (!Option.exists(yield* capture.latest, capture.current) || stats.received !== received || stats.ackBacklog > 0) {
|
|
4716
4746
|
received = stats.received;
|
|
4717
4747
|
stirred = page.now();
|
|
4718
4748
|
}
|
|
@@ -4996,11 +5026,11 @@ const viewOf = (page, view) => {
|
|
|
4996
5026
|
return internals === void 0 ? view : Object.assign(new Built(internals), view);
|
|
4997
5027
|
};
|
|
4998
5028
|
const make = Effect.fnUntraced(function* (options) {
|
|
4999
|
-
const page = make$
|
|
5029
|
+
const page = make$20(options, yield* Effect.scope);
|
|
5000
5030
|
const { id, playwright, native, owned, within, lane, span } = page;
|
|
5001
|
-
const bridge = yield* make$
|
|
5031
|
+
const bridge = yield* make$18(page);
|
|
5002
5032
|
const viewport = make$1(page, bridge);
|
|
5003
|
-
const input = make$
|
|
5033
|
+
const input = make$10(page, bridge, viewport);
|
|
5004
5034
|
const pictures = yield* make$7(page, bridge, viewport);
|
|
5005
5035
|
const reading = yield* make$6(page, bridge);
|
|
5006
5036
|
const navigation = make$2(page, input.perform, input.preparePolicy);
|
|
@@ -5071,4 +5101,4 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
5071
5101
|
//#endregion
|
|
5072
5102
|
export { performed as a, pause as i, make as n, mapping as o, viewOf as r, internalsOf as t };
|
|
5073
5103
|
|
|
5074
|
-
//# sourceMappingURL=page-
|
|
5104
|
+
//# sourceMappingURL=page-B92QnRfT.mjs.map
|