effect-browser 0.3.0-beta.16 → 0.3.0-beta.19
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 +12 -4
- package/dist/{Browser-DRPthkNO.mjs → Browser-H63wiekr.mjs} +4 -4
- package/dist/Browser-H63wiekr.mjs.map +1 -0
- package/dist/Browser.d.mts +1 -1
- package/dist/Browser.mjs +1 -1
- package/dist/Cdp.mjs +2 -2
- package/dist/Chromium.mjs +2 -2
- package/dist/Expect.d.mts +1 -1
- package/dist/Expect.mjs +2 -2
- package/dist/Moment.d.mts +1 -1
- package/dist/Moment.mjs +3 -3
- package/dist/Moment.mjs.map +1 -1
- package/dist/{Page-C_VkBVwI.mjs → Page-CfB6Zn1p.mjs} +3 -7
- package/dist/Page-CfB6Zn1p.mjs.map +1 -0
- package/dist/{Page-jHmSJeOS.d.mts → Page-ku6j5t-v.d.mts} +18 -13
- package/dist/Page.d.mts +1 -1
- package/dist/Page.mjs +1 -1
- package/dist/{Plan-X-JkACAB.mjs → Plan-C-d5QYS8.mjs} +3 -3
- package/dist/{Plan-X-JkACAB.mjs.map → Plan-C-d5QYS8.mjs.map} +1 -1
- package/dist/{Plan-DLtRksuu.d.mts → Plan-DJ4hEEna.d.mts} +2 -2
- package/dist/Plan.d.mts +1 -1
- package/dist/Plan.mjs +1 -1
- package/dist/Policy.d.mts +1 -1
- package/dist/Policy.mjs +1 -1
- package/dist/Presentation.d.mts +1 -1
- package/dist/Presentation.mjs +2 -2
- package/dist/Stage.d.mts +1 -1
- package/dist/Stage.mjs +7 -6
- package/dist/Stage.mjs.map +1 -1
- package/dist/{Supervisor-BgWP8o9t.mjs → Supervisor-2mPjIYYs.mjs} +4 -3
- package/dist/{Supervisor-BgWP8o9t.mjs.map → Supervisor-2mPjIYYs.mjs.map} +1 -1
- package/dist/Supervisor.mjs +1 -1
- package/dist/{context-rYTk-3Cv.mjs → context-w3NJPRLo.mjs} +15 -8
- package/dist/context-w3NJPRLo.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +4 -4
- package/dist/{page-ClEMFnBG.mjs → page-BKwfF6z-.mjs} +169 -112
- package/dist/page-BKwfF6z-.mjs.map +1 -0
- package/package.json +1 -1
- package/src/Moment.ts +3 -6
- package/src/Page.ts +13 -11
- package/src/Stage.ts +8 -16
- package/src/Supervisor.ts +6 -7
- package/src/internal/input/actions.ts +28 -64
- package/src/internal/input/dispatch.ts +22 -7
- package/src/internal/input/edit.inpage.ts +23 -2
- package/src/internal/input/evidence.inpage.ts +0 -2
- package/src/internal/input/guard.ts +3 -9
- package/src/internal/input/perform.ts +14 -10
- package/src/internal/input/pointer.ts +3 -6
- package/src/internal/input/replies.ts +19 -8
- package/src/internal/input/settle.ts +3 -2
- package/src/internal/input/targets.inpage.ts +2 -5
- package/src/internal/input/targets.ts +5 -21
- package/src/internal/page/bridge.ts +2 -2
- package/src/internal/page/context.ts +13 -1
- package/src/internal/page/navigation.ts +3 -12
- package/src/internal/pictures/capture.ts +7 -0
- package/src/internal/pictures/motion.ts +65 -0
- package/src/internal/pictures/pictures.ts +20 -16
- package/src/internal/pictures/utilsBundle.d.ts +9 -0
- package/src/internal/reading/reading.ts +5 -9
- package/src/internal/reading/ready.ts +66 -14
- package/src/internal/timeline/events.ts +5 -8
- package/src/internal/timeline/window.ts +3 -8
- package/dist/Browser-DRPthkNO.mjs.map +0 -1
- package/dist/Page-C_VkBVwI.mjs.map +0 -1
- package/dist/context-rYTk-3Cv.mjs.map +0 -1
- package/dist/page-ClEMFnBG.mjs.map +0 -1
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { Plan, Point } from "./Motion.mjs";
|
|
2
|
-
import { Action, Box, CursorChanged, KeyChanged, Navigated, PageLoaded, PointerPressed, PointerReleased, Subject,
|
|
2
|
+
import { Action, Box, CursorChanged, KeyChanged, Navigated, PageLoaded, PointerPressed, PointerReleased, Subject, 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$20, c as
|
|
4
|
+
import { a as make$20, c as undispatched, d as monotonicMillis, f as toBrowserSeconds, g as make$19, h as Current, i as failWith, l as estimate, m as uncertaintyAt, n as contextGone, o as reasonOf, p as toHostTime, r as decodeWith, s as refuse } from "./context-w3NJPRLo.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
|
-
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-
|
|
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-CfB6Zn1p.mjs";
|
|
8
8
|
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
12
|
import { Cause, Clock, Deferred, Duration, Effect, Exit, Fiber, MutableRef, Option, Queue, Random, Ref, Result, Schedule, Schema, Scope, Semaphore, Stream, SynchronizedRef } from "effect";
|
|
13
|
+
import { jpegjs } from "playwright-core/lib/utilsBundle";
|
|
13
14
|
//#region src/internal/input/edit.inpage.ts
|
|
14
15
|
/**
|
|
15
16
|
* In the page: editing a field. It refuses text that a focused control could act on, focuses a
|
|
@@ -17,7 +18,7 @@ import { Cause, Clock, Deferred, Duration, Effect, Exit, Fiber, MutableRef, Opti
|
|
|
17
18
|
* may use.
|
|
18
19
|
*/
|
|
19
20
|
const edit = (names, guard, placing) => {
|
|
20
|
-
const { activeElement, clean, describe, isDisabled, isHtml, isInput, isSecret, isSelect, isTextArea, lookup, nameOf, roleOf } = names;
|
|
21
|
+
const { activeElement, clean, describe, inCurrentDocument, isDisabled, isHtml, isInput, isSecret, isSelect, isTextArea, lookup, nameOf, roleOf } = names;
|
|
21
22
|
const { textEntry, typingRefusal } = guard;
|
|
22
23
|
/** Whether text may be typed into a ref or focus, and, for a `secret`, only into a secret field. */
|
|
23
24
|
const typeable = (ref, secret) => {
|
|
@@ -48,8 +49,21 @@ const edit = (names, guard, placing) => {
|
|
|
48
49
|
}
|
|
49
50
|
};
|
|
50
51
|
};
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* The focused field, when it is a text field named `name`: one a page put in place of a field
|
|
54
|
+
* just pressed and gave focus to, as a typeahead does.
|
|
55
|
+
*/
|
|
56
|
+
const replacement = (name) => {
|
|
57
|
+
const active = activeElement();
|
|
58
|
+
return active !== null && textEntry(active) && inCurrentDocument(active) && nameOf(active, roleOf(active)) === name ? active : void 0;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Focus a field to type into. `follow` is the field's name when the action pressed it first: a
|
|
62
|
+
* page may answer the press with another field of that name in its place, focused, and the keys
|
|
63
|
+
* follow focus there, as a person's would.
|
|
64
|
+
*/
|
|
65
|
+
const focus = (ref, replace, follow) => {
|
|
66
|
+
const element = lookup(ref) ?? (follow === null ? void 0 : replacement(follow));
|
|
53
67
|
if (element === void 0) return {
|
|
54
68
|
error: `${ref} is not on the page any more`,
|
|
55
69
|
stale: true
|
|
@@ -334,11 +348,8 @@ const targets = (names, walked, placing) => {
|
|
|
334
348
|
};
|
|
335
349
|
const ResolvedPointSchema = Schema.Struct({
|
|
336
350
|
...Point.fields,
|
|
351
|
+
...Subject.fields,
|
|
337
352
|
element: Schema.String,
|
|
338
|
-
tag: Schema.String,
|
|
339
|
-
role: Schema.NullOr(Schema.String),
|
|
340
|
-
name: Schema.String,
|
|
341
|
-
context: SubjectContext,
|
|
342
353
|
box: Schema.optional(Box),
|
|
343
354
|
cursor: Schema.String,
|
|
344
355
|
href: Schema.optional(Schema.String)
|
|
@@ -2074,7 +2085,7 @@ const sight = (names, walked, texts, kept) => {
|
|
|
2074
2085
|
*/
|
|
2075
2086
|
const install = (makeNames, makeWalk, makeMatch, makeContext, makeSubjects, makeExpectations, makeText, makeControls, makeFold, makeHistory, makeSight, makeMarks, makeRecord, makeChanges, makeReady, makeOutline, makeTargets, makeEvidence, makeGuard, makeEdit, makeAddresses) => {
|
|
2076
2087
|
const installed = globalThis.__effectBrowser;
|
|
2077
|
-
if (installed !== void 0 && installed.version ===
|
|
2088
|
+
if (installed !== void 0 && installed.version === 20) return installed;
|
|
2078
2089
|
const named = makeNames();
|
|
2079
2090
|
const walked = makeWalk(named);
|
|
2080
2091
|
const placing = makeContext(named, walked);
|
|
@@ -2091,7 +2102,7 @@ const install = (makeNames, makeWalk, makeMatch, makeContext, makeSubjects, make
|
|
|
2091
2102
|
const edited = makeEdit(named, guarded, placing);
|
|
2092
2103
|
const readiness = makeReady(walked, texts, kept, recorder);
|
|
2093
2104
|
const api = {
|
|
2094
|
-
version:
|
|
2105
|
+
version: 20,
|
|
2095
2106
|
snapshot: read.snapshot,
|
|
2096
2107
|
find: subjected.find,
|
|
2097
2108
|
until: makeExpectations(named, subjected).until,
|
|
@@ -2298,6 +2309,20 @@ const make$18 = Effect.fnUntraced(function* (page) {
|
|
|
2298
2309
|
* protocol session, stamped with the browser's clock when its run has a mapping, and is published
|
|
2299
2310
|
* as it is submitted.
|
|
2300
2311
|
*/
|
|
2312
|
+
const buttonMask = {
|
|
2313
|
+
none: 0,
|
|
2314
|
+
left: 1,
|
|
2315
|
+
right: 2,
|
|
2316
|
+
middle: 4
|
|
2317
|
+
};
|
|
2318
|
+
/** A mouse button going down or up at a point, as the `clickCount`th click. */
|
|
2319
|
+
const buttonAt = (type, point, button = "left", clickCount = 1) => ({
|
|
2320
|
+
type,
|
|
2321
|
+
...point,
|
|
2322
|
+
button,
|
|
2323
|
+
buttons: type === "mousePressed" ? buttonMask[button] : 0,
|
|
2324
|
+
clickCount
|
|
2325
|
+
});
|
|
2301
2326
|
const make$17 = (page) => {
|
|
2302
2327
|
const { id, pointer, publish, now, noteInput, closedBy } = page;
|
|
2303
2328
|
const { send } = page.protocol;
|
|
@@ -2341,16 +2366,10 @@ const make$17 = (page) => {
|
|
|
2341
2366
|
if (event.type === "mouseReleased") return yield* run.up(held);
|
|
2342
2367
|
if (event.type === "mousePressed") {
|
|
2343
2368
|
yield* run.reserve(2);
|
|
2344
|
-
yield* run.down(held, () => dispatchMouse(event, estimate, submitted), () => dispatchMouse({
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
y: event.y
|
|
2349
|
-
})),
|
|
2350
|
-
button: event.button ?? "left",
|
|
2351
|
-
buttons: 0,
|
|
2352
|
-
clickCount: event.clickCount ?? 1
|
|
2353
|
-
}, estimate));
|
|
2369
|
+
yield* run.down(held, () => dispatchMouse(event, estimate, submitted), () => dispatchMouse(buttonAt("mouseReleased", Option.getOrElse(MutableRef.get(pointer), () => ({
|
|
2370
|
+
x: event.x,
|
|
2371
|
+
y: event.y
|
|
2372
|
+
})), event.button, event.clickCount), estimate));
|
|
2354
2373
|
} else {
|
|
2355
2374
|
yield* run.reserve(1);
|
|
2356
2375
|
yield* run.send(() => dispatchMouse(event, estimate, submitted));
|
|
@@ -2411,8 +2430,8 @@ const make$16 = (page, bridge) => {
|
|
|
2411
2430
|
const { current, evaluateIn, evaluateWithContext } = bridge;
|
|
2412
2431
|
const preparePolicy = (action, info, targets, flags = {}) => Effect.gen(function* () {
|
|
2413
2432
|
for (const target of targets) {
|
|
2414
|
-
if (typeof target === "string" && !/^e\d+$/.test(target)) return yield*
|
|
2415
|
-
if (target !== null && typeof target !== "string" && (!Number.isFinite(target.x) || !Number.isFinite(target.y))) return yield*
|
|
2433
|
+
if (typeof target === "string" && !/^e\d+$/.test(target)) return yield* refuse(action, `"${target}" is not a ref; refs look like e12`);
|
|
2434
|
+
if (target !== null && typeof target !== "string" && (!Number.isFinite(target.x) || !Number.isFinite(target.y))) return yield* refuse(action, "point coordinates must be finite");
|
|
2416
2435
|
}
|
|
2417
2436
|
const input = {
|
|
2418
2437
|
action,
|
|
@@ -2878,10 +2897,7 @@ const admission = (page, pending, name) => {
|
|
|
2878
2897
|
};
|
|
2879
2898
|
};
|
|
2880
2899
|
/** Close a run on every exit while preserving its native replies for the page's next input. */
|
|
2881
|
-
const useRun = (page, sender, name, run, action) => action.pipe(Effect.
|
|
2882
|
-
onFailure: (error) => run.close.pipe(Effect.andThen(sender.flush(name, run).pipe(Effect.ignore)), Effect.andThen(Effect.fail(error))),
|
|
2883
|
-
onSuccess: (value) => run.close.pipe(Effect.andThen(sender.flush(name, run)), Effect.as(value))
|
|
2884
|
-
}), Effect.ensuring(run.close.pipe(Effect.andThen(page.openings.clear))), Effect.provideService(Current, run));
|
|
2900
|
+
const useRun = (page, sender, name, run, action, canStop) => action.pipe(Effect.tapError(() => run.close.pipe(Effect.andThen(sender.flush(name, run)), Effect.ignore)), Effect.tap(() => run.close.pipe(Effect.andThen(sender.flush(name, run)))), Effect.ensuring(run.close.pipe(Effect.andThen(page.openings.clear))), Effect.onError(() => run.recover(page.stopLoading, page.scope).pipe(Effect.when(canStop))), Effect.provideService(Current, run));
|
|
2885
2901
|
const make$14 = (page, sender) => {
|
|
2886
2902
|
const { id, settings, mapping, lane, publish, now, noteInput, span, owned } = page;
|
|
2887
2903
|
const { inputClocks } = sender;
|
|
@@ -2916,7 +2932,7 @@ const make$14 = (page, sender) => {
|
|
|
2916
2932
|
const useInput = (action) => input.begin.pipe(Effect.tap((current) => Effect.sync(() => {
|
|
2917
2933
|
ticket.using(current);
|
|
2918
2934
|
if (estimate !== void 0) inputClocks.set(current, estimate);
|
|
2919
|
-
})), Effect.flatMap((run) => useRun(page, sender, name, run, action(run))));
|
|
2935
|
+
})), Effect.flatMap((run) => useRun(page, sender, name, run, action(run), info.input === false ? Effect.succeed(false) : Ref.get(sent))));
|
|
2920
2936
|
let queuedMillis;
|
|
2921
2937
|
const dispatch = (action) => Effect.suspend(() => {
|
|
2922
2938
|
const asked = now();
|
|
@@ -3017,7 +3033,7 @@ const make$13 = (page, dispatch, viewport) => {
|
|
|
3017
3033
|
y: Math.max(0, Math.min(size.height - 1, previous.y))
|
|
3018
3034
|
};
|
|
3019
3035
|
const planned = yield* style.glide(from, to, dragging);
|
|
3020
|
-
const invalid =
|
|
3036
|
+
const invalid = refuse(operation, "motion must be a bounded, ordered schedule ending at the target");
|
|
3021
3037
|
const samples = yield* Schema.decodeEffect(Plan)(planned).pipe(Effect.catch(() => invalid));
|
|
3022
3038
|
if (samples.at(-1)?.x !== to.x || samples.at(-1)?.y !== to.y) return yield* invalid;
|
|
3023
3039
|
yield* Effect.annotateCurrentSpan("samples", samples.length);
|
|
@@ -3114,12 +3130,12 @@ const make$12 = (page, bridge) => {
|
|
|
3114
3130
|
});
|
|
3115
3131
|
/** Wait for the page to settle after input sent since `before`. */
|
|
3116
3132
|
const settle = (operation, before) => Effect.gen(function* () {
|
|
3117
|
-
yield* bridge.evaluate(operation, scriptCall("settle")).pipe(Effect.provideService(Current, void 0), Effect.catchIf(contextGone, () => Effect.void)
|
|
3133
|
+
yield* bridge.evaluate(operation, scriptCall("settle")).pipe(Effect.provideService(Current, void 0), Effect.catchIf(contextGone, () => Effect.void));
|
|
3118
3134
|
while (document() > before.document && parsed < document()) yield* Deferred.await(changed);
|
|
3119
3135
|
}).pipe(Effect.timeoutOrElse({
|
|
3120
3136
|
duration: settling,
|
|
3121
3137
|
orElse: () => Effect.fail("unsettled")
|
|
3122
|
-
}), Effect.catch(() => Effect.annotateCurrentSpan("settled", false)), Effect.andThen(page.openings.settle(before.openings)), page.span("Page.settle", {}, "Debug"));
|
|
3138
|
+
}), Effect.catch(() => page.stopLoading.pipe(Effect.andThen(Effect.annotateCurrentSpan("settled", false)))), Effect.andThen(page.openings.settle(before.openings)), page.span("Page.settle", {}, "Debug"));
|
|
3123
3139
|
return {
|
|
3124
3140
|
mark,
|
|
3125
3141
|
settle
|
|
@@ -3133,19 +3149,13 @@ const make$12 = (page, bridge) => {
|
|
|
3133
3149
|
* viewers watch.
|
|
3134
3150
|
*/
|
|
3135
3151
|
const pointFailure = (operation, target, result) => failWith(operation, result.error === "stale" && typeof target === "string" ? new StaleRef({ ref: target }) : result.error === "outside" ? new InvalidRequest({ detail: result.detail }) : new NotActionable({ detail: result.detail }));
|
|
3136
|
-
const resolvedTarget = (
|
|
3152
|
+
const resolvedTarget = ({ x, y, box, ...target }) => new ResolvedTarget({
|
|
3137
3153
|
point: {
|
|
3138
|
-
x
|
|
3139
|
-
y
|
|
3154
|
+
x,
|
|
3155
|
+
y
|
|
3140
3156
|
},
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
role: result.role,
|
|
3144
|
-
name: result.name,
|
|
3145
|
-
context: result.context,
|
|
3146
|
-
box: result.box,
|
|
3147
|
-
cursor: result.cursor,
|
|
3148
|
-
...result.href === void 0 ? {} : { href: result.href }
|
|
3157
|
+
box,
|
|
3158
|
+
...target
|
|
3149
3159
|
});
|
|
3150
3160
|
const make$11 = (viewport, guard, pointer, dispatch, settling) => {
|
|
3151
3161
|
const { evaluate, mutate } = guard;
|
|
@@ -3153,8 +3163,8 @@ const make$11 = (viewport, guard, pointer, dispatch, settling) => {
|
|
|
3153
3163
|
const { flush } = dispatch;
|
|
3154
3164
|
const readPoint = (operation, target, approval, scroll) => evaluate(operation, scriptCall("point", target, scroll), approval).pipe(Effect.flatMap(decodeWith(operation, PointResultSchema)));
|
|
3155
3165
|
const resolve = (operation, target, approval, scroll = true) => {
|
|
3156
|
-
if (typeof target === "string" && !/^e\d+$/.test(target)) return
|
|
3157
|
-
if (typeof target !== "string" && (!Number.isFinite(target.x) || !Number.isFinite(target.y))) return
|
|
3166
|
+
if (typeof target === "string" && !/^e\d+$/.test(target)) return refuse(operation, target + " is not a ref; refs look like e12");
|
|
3167
|
+
if (typeof target !== "string" && (!Number.isFinite(target.x) || !Number.isFinite(target.y))) return refuse(operation, "point coordinates must be finite");
|
|
3158
3168
|
return readPoint(operation, target, approval, scroll).pipe(Effect.flatMap((result) => "error" in result ? pointFailure(operation, target, result) : Effect.succeed(resolvedTarget(result))));
|
|
3159
3169
|
};
|
|
3160
3170
|
return {
|
|
@@ -3197,12 +3207,6 @@ const make$11 = (viewport, guard, pointer, dispatch, settling) => {
|
|
|
3197
3207
|
* `perform`, which admits it, puts it to the input guard and records it. A click, a key or a scroll
|
|
3198
3208
|
* then waits for the page to settle: a task and a frame, and a document if the input asked for one.
|
|
3199
3209
|
*/
|
|
3200
|
-
const buttonMask = {
|
|
3201
|
-
none: 0,
|
|
3202
|
-
left: 1,
|
|
3203
|
-
right: 2,
|
|
3204
|
-
middle: 4
|
|
3205
|
-
};
|
|
3206
3210
|
const partsOf = (page, bridge, viewport) => {
|
|
3207
3211
|
const dispatch = make$17(page);
|
|
3208
3212
|
const pointer = make$13(page, dispatch, viewport);
|
|
@@ -3224,13 +3228,15 @@ const partsOf = (page, bridge, viewport) => {
|
|
|
3224
3228
|
/** Whether every number given is finite; a number left out is. */
|
|
3225
3229
|
const finite = (...values) => values.every((value) => value === void 0 || Number.isFinite(value));
|
|
3226
3230
|
const named = (target) => typeof target === "string" ? target : `${target.x},${target.y}`;
|
|
3231
|
+
/** The ref a target names, if it names one rather than a point. */
|
|
3232
|
+
const refOf = (target) => typeof target === "string" ? target : void 0;
|
|
3227
3233
|
/** A click's options, once its counts are finite. */
|
|
3228
|
-
const clickable = (options) => finite(options.clickCount, options.holdMillis) ? Effect.void :
|
|
3234
|
+
const clickable = (options) => finite(options.clickCount, options.holdMillis) ? Effect.void : refuse("click", "clickCount and holdMillis must be finite");
|
|
3229
3235
|
/** The keys a press sends, once they and its options are valid. */
|
|
3230
3236
|
const pressed = (keys, options) => {
|
|
3231
3237
|
const parts$1 = parts(keys);
|
|
3232
|
-
if (!finite(options.times, options.holdMillis)) return
|
|
3233
|
-
if (parts$1 === void 0) return
|
|
3238
|
+
if (!finite(options.times, options.holdMillis)) return refuse("press", "times and holdMillis must be finite");
|
|
3239
|
+
if (parts$1 === void 0) return refuse("press", `"${keys}" is not a key; try Enter, Space, ArrowLeft or Control+A`);
|
|
3234
3240
|
return Effect.succeed(parts$1);
|
|
3235
3241
|
};
|
|
3236
3242
|
const click = (input) => {
|
|
@@ -3243,7 +3249,7 @@ const click = (input) => {
|
|
|
3243
3249
|
clickCount: clickOptions.clickCount,
|
|
3244
3250
|
holdMillis: clickOptions.holdMillis
|
|
3245
3251
|
}
|
|
3246
|
-
}, settings.actionTimeout, Effect.suspend(() => clickable(clickOptions)).pipe(Effect.andThen(preparePolicy("click", { target:
|
|
3252
|
+
}, settings.actionTimeout, Effect.suspend(() => clickable(clickOptions)).pipe(Effect.andThen(preparePolicy("click", { target: refOf(target) }, [target]))), (marks, approval) => Effect.gen(function* () {
|
|
3247
3253
|
yield* clickable(clickOptions);
|
|
3248
3254
|
const resolved = yield* targetFor("click", target, approval, marks);
|
|
3249
3255
|
const { point } = resolved;
|
|
@@ -3263,23 +3269,11 @@ const click = (input) => {
|
|
|
3263
3269
|
index: 0,
|
|
3264
3270
|
...point
|
|
3265
3271
|
}] }, flush("click", marks.input)).pipe(Effect.catchIf((error) => error.reason._tag === "StaleRef", () => failWith("click", new NotActionable({ detail: "an earlier click removed the approved target, so no further press was sent" }))));
|
|
3266
|
-
yield* sendMouse("click", marks.input,
|
|
3267
|
-
type: "mousePressed",
|
|
3268
|
-
...point,
|
|
3269
|
-
button,
|
|
3270
|
-
buttons: buttonMask[button],
|
|
3271
|
-
clickCount: index
|
|
3272
|
-
});
|
|
3272
|
+
yield* sendMouse("click", marks.input, buttonAt("mousePressed", point, button, index));
|
|
3273
3273
|
const hold = clickOptions.holdMillis ?? (yield* marks.style.hold);
|
|
3274
3274
|
if (clickOptions.holdMillis === void 0) yield* marks.present(hold);
|
|
3275
3275
|
if (hold > 0) yield* Effect.sleep(Duration.millis(hold));
|
|
3276
|
-
yield* sendMouse("click", marks.input,
|
|
3277
|
-
type: "mouseReleased",
|
|
3278
|
-
...point,
|
|
3279
|
-
button,
|
|
3280
|
-
buttons: 0,
|
|
3281
|
-
clickCount: index
|
|
3282
|
-
});
|
|
3276
|
+
yield* sendMouse("click", marks.input, buttonAt("mouseReleased", point, button, index));
|
|
3283
3277
|
}
|
|
3284
3278
|
yield* flush("click", marks.input);
|
|
3285
3279
|
yield* settle("click", before);
|
|
@@ -3289,7 +3283,7 @@ const click = (input) => {
|
|
|
3289
3283
|
const hover = (input) => {
|
|
3290
3284
|
const { settings } = input.page;
|
|
3291
3285
|
const { perform, preparePolicy, targetFor, moveTo, flush } = input;
|
|
3292
|
-
return (target, style = plain) => perform("hover", { target: named(target) }, settings.actionTimeout, preparePolicy("hover", { target:
|
|
3286
|
+
return (target, style = plain) => perform("hover", { target: named(target) }, settings.actionTimeout, preparePolicy("hover", { target: refOf(target) }, [target]), (marks, approval) => Effect.gen(function* () {
|
|
3293
3287
|
const resolved = yield* targetFor("hover", target, approval, marks);
|
|
3294
3288
|
const { point } = resolved;
|
|
3295
3289
|
yield* marks.at(point);
|
|
@@ -3329,21 +3323,9 @@ const drag = (input) => {
|
|
|
3329
3323
|
...end.point
|
|
3330
3324
|
}] });
|
|
3331
3325
|
yield* marks.sent;
|
|
3332
|
-
yield* sendMouse("drag", marks.input,
|
|
3333
|
-
type: "mousePressed",
|
|
3334
|
-
...start.point,
|
|
3335
|
-
button: "left",
|
|
3336
|
-
buttons: 1,
|
|
3337
|
-
clickCount: 1
|
|
3338
|
-
});
|
|
3326
|
+
yield* sendMouse("drag", marks.input, buttonAt("mousePressed", start.point));
|
|
3339
3327
|
yield* moveTo("drag", marks, end.point, end.cursor, "drag");
|
|
3340
|
-
yield* sendMouse("drag", marks.input,
|
|
3341
|
-
type: "mouseReleased",
|
|
3342
|
-
...end.point,
|
|
3343
|
-
button: "left",
|
|
3344
|
-
buttons: 0,
|
|
3345
|
-
clickCount: 1
|
|
3346
|
-
});
|
|
3328
|
+
yield* sendMouse("drag", marks.input, buttonAt("mouseReleased", end.point));
|
|
3347
3329
|
yield* flush("drag", marks.input);
|
|
3348
3330
|
}), style);
|
|
3349
3331
|
};
|
|
@@ -3365,7 +3347,7 @@ const typeText = (input) => {
|
|
|
3365
3347
|
}, [typeOptions.into ?? null], { submit: typeOptions.submit ?? false }), (marks, approval) => Effect.gen(function* () {
|
|
3366
3348
|
const replace = typeOptions.replace ?? true;
|
|
3367
3349
|
const into = typeOptions.into;
|
|
3368
|
-
if (into !== void 0 && !/^e\d+$/.test(into)) return yield*
|
|
3350
|
+
if (into !== void 0 && !/^e\d+$/.test(into)) return yield* refuse("type", `"${into}" is not a ref; refs look like e12`);
|
|
3369
3351
|
const asked = scriptCall("typeable", into ?? null, typeOptions.secret === true);
|
|
3370
3352
|
const typeable = yield* evaluate("type", asked, approval).pipe(Effect.flatMap(decodeWith("type", TypeableResultSchema)));
|
|
3371
3353
|
if ("error" in typeable) return yield* failWith("type", typeable.error === "stale" && into !== void 0 ? new StaleRef({ ref: into }) : new NotActionable({ detail: typeable.detail }));
|
|
@@ -3383,17 +3365,12 @@ const typeText = (input) => {
|
|
|
3383
3365
|
...target.point
|
|
3384
3366
|
}] });
|
|
3385
3367
|
yield* marks.sent;
|
|
3386
|
-
for (const type of ["mousePressed", "mouseReleased"]) yield* sendMouse("type", marks.input,
|
|
3387
|
-
type,
|
|
3388
|
-
...target.point,
|
|
3389
|
-
button: "left",
|
|
3390
|
-
buttons: type === "mousePressed" ? 1 : 0,
|
|
3391
|
-
clickCount: 1
|
|
3392
|
-
});
|
|
3368
|
+
for (const type of ["mousePressed", "mouseReleased"]) yield* sendMouse("type", marks.input, buttonAt(type, target.point));
|
|
3393
3369
|
yield* flush("type", marks.input);
|
|
3394
3370
|
}
|
|
3395
3371
|
yield* marks.sent;
|
|
3396
|
-
const
|
|
3372
|
+
const follow = marks.style.shown && approval === void 0 && !secret && target.name !== "" ? target.name : null;
|
|
3373
|
+
const focused = yield* mutate("type", scriptCall("focus", into, replace, follow), approval).pipe(Effect.flatMap(decodeWith("type", FocusResultSchema)));
|
|
3397
3374
|
if ("error" in focused) return yield* editFailure("type", into, focused);
|
|
3398
3375
|
secret ||= focused.secret;
|
|
3399
3376
|
}
|
|
@@ -3480,14 +3457,14 @@ const scroll = (input) => {
|
|
|
3480
3457
|
const { mark, settle } = input;
|
|
3481
3458
|
return (scrollOptions = {}, style = plain) => {
|
|
3482
3459
|
const target = scrollOptions.at;
|
|
3483
|
-
const valid = Number.isFinite(scrollOptions.dx ?? 0) && Number.isFinite(scrollOptions.dy ?? 0) ? Effect.void :
|
|
3460
|
+
const valid = Number.isFinite(scrollOptions.dx ?? 0) && Number.isFinite(scrollOptions.dy ?? 0) ? Effect.void : refuse("scroll", "scroll deltas must be finite");
|
|
3484
3461
|
return perform("scroll", {
|
|
3485
3462
|
target: target === void 0 ? void 0 : named(target),
|
|
3486
3463
|
options: {
|
|
3487
3464
|
dx: scrollOptions.dx,
|
|
3488
3465
|
dy: scrollOptions.dy
|
|
3489
3466
|
}
|
|
3490
|
-
}, settings.actionTimeout, valid.pipe(Effect.andThen(preparePolicy("scroll", { target:
|
|
3467
|
+
}, settings.actionTimeout, valid.pipe(Effect.andThen(preparePolicy("scroll", { target: refOf(target) }, target === void 0 ? [] : [target]))), (marks, approval) => Effect.gen(function* () {
|
|
3491
3468
|
yield* valid;
|
|
3492
3469
|
const viewport = yield* viewportFor("scroll");
|
|
3493
3470
|
const middle = {
|
|
@@ -3978,6 +3955,9 @@ const make$8 = (options) => Effect.gen(function* () {
|
|
|
3978
3955
|
return current.phase !== "Stopped" && current.failure === void 0 && !isClosed();
|
|
3979
3956
|
};
|
|
3980
3957
|
if (current === void 0 || !resumable()) return;
|
|
3958
|
+
pictures.track("picture restoration", options.restore(), failed(current));
|
|
3959
|
+
yield* pictures.wait("picture restoration");
|
|
3960
|
+
yield* healthy(current);
|
|
3981
3961
|
const viewport = yield* readViewport(options);
|
|
3982
3962
|
if (!resumable()) return;
|
|
3983
3963
|
sizes.restart(viewport);
|
|
@@ -4416,7 +4396,7 @@ const millisOf = (input) => Option.match(Duration.fromInput(input), {
|
|
|
4416
4396
|
});
|
|
4417
4397
|
const reuse = (page, bridge, viewport, capture) => (operation, options) => Effect.gen(function* () {
|
|
4418
4398
|
const maxAge = millisOf(options.maxAge ?? defaultMaxAge);
|
|
4419
|
-
if (!(maxAge >= 0)) return yield*
|
|
4399
|
+
if (!(maxAge >= 0)) return yield* refuse(operation, "maxAge must be a duration of zero or more");
|
|
4420
4400
|
const latest = yield* capture.latest;
|
|
4421
4401
|
const known = viewport.knownViewport();
|
|
4422
4402
|
const { activity } = page;
|
|
@@ -4441,6 +4421,11 @@ const make$7 = Effect.fnUntraced(function* (page, bridge, viewport) {
|
|
|
4441
4421
|
watch: bridge.currentDocument("screencast"),
|
|
4442
4422
|
frameHistory: settings.frameHistory,
|
|
4443
4423
|
viewport: Effect.suspend(() => viewport.viewportFor("screencast")),
|
|
4424
|
+
restore: () => page.protocol.send("Page.captureScreenshot", {
|
|
4425
|
+
format: "jpeg",
|
|
4426
|
+
quality: 0,
|
|
4427
|
+
optimizeForSpeed: true
|
|
4428
|
+
}),
|
|
4444
4429
|
imageSize: jpegSize,
|
|
4445
4430
|
error
|
|
4446
4431
|
});
|
|
@@ -4492,7 +4477,7 @@ const make$7 = Effect.fnUntraced(function* (page, bridge, viewport) {
|
|
|
4492
4477
|
const zoom = (requested) => lane.read("zoom")(Effect.gen(function* () {
|
|
4493
4478
|
const region = yield* Schema.decodeEffect(Region)(requested).pipe(Effect.mapError((error) => undispatched("zoom", new InvalidRequest({ detail: error.message }))));
|
|
4494
4479
|
const size = viewport.knownViewport() ?? (yield* viewport.viewportFor("zoom"));
|
|
4495
|
-
if (region.x + region.width > size.width || region.y + region.height > size.height) return yield*
|
|
4480
|
+
if (region.x + region.width > size.width || region.y + region.height > size.height) return yield* refuse("zoom", "the crop must fit entirely within the viewport");
|
|
4496
4481
|
const image = yield* picture("zoom", 80, region);
|
|
4497
4482
|
return new Zoom({
|
|
4498
4483
|
page: id,
|
|
@@ -4503,7 +4488,7 @@ const make$7 = Effect.fnUntraced(function* (page, bridge, viewport) {
|
|
|
4503
4488
|
const captureStats = (options = {}) => {
|
|
4504
4489
|
if (options.window === void 0) return capture.stats();
|
|
4505
4490
|
const millis = millisOf(options.window);
|
|
4506
|
-
return millis > 0 && millis <= Duration.toMillis(countsKept) ? capture.stats(millis) :
|
|
4491
|
+
return millis > 0 && millis <= Duration.toMillis(countsKept) ? capture.stats(millis) : refuse("captureStats", "window must be over zero and at most a minute");
|
|
4507
4492
|
};
|
|
4508
4493
|
return {
|
|
4509
4494
|
capture,
|
|
@@ -4564,7 +4549,7 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4564
4549
|
firstRef: yield* Ref.get(nextRef)
|
|
4565
4550
|
};
|
|
4566
4551
|
const result = yield* evaluate("snapshot", scriptCall("snapshot", request)).pipe(Effect.flatMap(decodeWith("snapshot", SnapshotResultSchema)));
|
|
4567
|
-
if ("invalid" in result) return yield*
|
|
4552
|
+
if ("invalid" in result) return yield* refuse("snapshot", result.invalid);
|
|
4568
4553
|
const { text, truncated, url } = result.snapshot;
|
|
4569
4554
|
yield* counted(result.nextRef);
|
|
4570
4555
|
yield* Effect.annotateCurrentSpan({
|
|
@@ -4600,7 +4585,7 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4600
4585
|
maxChars: options.maxChars ?? 12e3,
|
|
4601
4586
|
unmask: options.unmask ?? false
|
|
4602
4587
|
};
|
|
4603
|
-
return (scope !== "viewport" && !/^e\d+$/.test(scope) ?
|
|
4588
|
+
return (scope !== "viewport" && !/^e\d+$/.test(scope) ? refuse("text", `${scope} is neither "viewport" nor a ref such as e12`) : texts(JSON.stringify(request), Effect.gen(function* () {
|
|
4604
4589
|
const result = yield* evaluate("text", scriptCall("text", request)).pipe(Effect.flatMap(decodeWith("text", TextResultSchema)));
|
|
4605
4590
|
if (result === null) return yield* failWith("text", new StaleRef({ ref: scope }));
|
|
4606
4591
|
yield* Effect.annotateCurrentSpan({
|
|
@@ -4624,7 +4609,7 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4624
4609
|
};
|
|
4625
4610
|
const millis = Math.min(Duration.toMillis(timeout), Number.MAX_SAFE_INTEGER);
|
|
4626
4611
|
const unmet = () => failWith("waitFor", new Timeout({ millis }));
|
|
4627
|
-
const look = evaluate("waitFor", scriptCall("waitUntil", request, millis)).pipe(Effect.flatMap(decodeWith("waitFor", ConditionResultSchema)), Effect.flatMap((result) => "invalid" in result ?
|
|
4612
|
+
const look = evaluate("waitFor", scriptCall("waitUntil", request, millis)).pipe(Effect.flatMap(decodeWith("waitFor", ConditionResultSchema)), Effect.flatMap((result) => "invalid" in result ? refuse("waitFor", result.invalid) : result.met ? Effect.void : unmet()));
|
|
4628
4613
|
return lane.read("waitFor")(Effect.void).pipe(Effect.andThen(Effect.retry(look, { while: contextGone })), Effect.timeoutOrElse({
|
|
4629
4614
|
duration: timeout,
|
|
4630
4615
|
orElse: unmet
|
|
@@ -4652,6 +4637,51 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4652
4637
|
};
|
|
4653
4638
|
});
|
|
4654
4639
|
//#endregion
|
|
4640
|
+
//#region src/internal/pictures/motion.ts
|
|
4641
|
+
/**
|
|
4642
|
+
* Where a page's screen moves, from its screencast frames: each frame decoded and cut into
|
|
4643
|
+
* 16-pixel blocks, a block moving where a few of its pixels, sampled every other one, changed by
|
|
4644
|
+
* more than JPEG's noise in any color channel.
|
|
4645
|
+
* What moved among the frames before an input is the page's background, such as an idle
|
|
4646
|
+
* animation; foreground stillness ignores it.
|
|
4647
|
+
*
|
|
4648
|
+
* Frames are decoded with the JPEG decoder playwright-core bundles and exports as
|
|
4649
|
+
* `playwright-core/lib/utilsBundle`: effect-browser depends on nothing else, and the runtime has
|
|
4650
|
+
* no image decoder. That entry point has no types, so `utilsBundle.d.ts` declares what is used.
|
|
4651
|
+
*/
|
|
4652
|
+
const picture = (frame) => jpegjs.decode(frame.data, { useTArray: true });
|
|
4653
|
+
/** A sample changed where any color channel moved more than this, beyond JPEG's noise. */
|
|
4654
|
+
const noise = 32;
|
|
4655
|
+
/** The blocks where two pictures differ, by `row * columns + column`; -1 for different sizes. */
|
|
4656
|
+
const moved = (from, to) => {
|
|
4657
|
+
if (from.width !== to.width || from.height !== to.height) return [-1];
|
|
4658
|
+
const columns = Math.ceil(from.width / 16);
|
|
4659
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4660
|
+
const differs = (at) => Math.abs((from.data[at] ?? 0) - (to.data[at] ?? 0)) > noise;
|
|
4661
|
+
for (let y = 0; y < from.height; y += 2) for (let x = 0; x < from.width; x += 2) {
|
|
4662
|
+
const at = (y * from.width + x) * 4;
|
|
4663
|
+
const block = Math.floor(y / 16) * columns + Math.floor(x / 16);
|
|
4664
|
+
if (differs(at) || differs(at + 1) || differs(at + 2)) counts.set(block, (counts.get(block) ?? 0) + 1);
|
|
4665
|
+
}
|
|
4666
|
+
return [...counts].flatMap(([block, count]) => count >= 3 ? [block] : []);
|
|
4667
|
+
};
|
|
4668
|
+
/** The blocks that moved from one picture to the next and their neighbours; none past a resize. */
|
|
4669
|
+
const background = (pictures) => {
|
|
4670
|
+
const columns = Math.ceil((pictures[0]?.width ?? 0) / 16);
|
|
4671
|
+
const around = (block) => [
|
|
4672
|
+
-1,
|
|
4673
|
+
0,
|
|
4674
|
+
1
|
|
4675
|
+
].flatMap((row) => [
|
|
4676
|
+
-1,
|
|
4677
|
+
0,
|
|
4678
|
+
1
|
|
4679
|
+
].filter((step) => block >= 0 && block % columns + step >= 0).filter((step) => block % columns + step < columns).map((step) => block + row * columns + step));
|
|
4680
|
+
return new Set(pictures.flatMap((to, index) => moved(pictures[index - 1] ?? to, to).flatMap(around)));
|
|
4681
|
+
};
|
|
4682
|
+
/** Whether anything moved from one picture to another outside the background. */
|
|
4683
|
+
const stirs = (from, to, mask) => moved(from, to).some((block) => !mask.has(block));
|
|
4684
|
+
//#endregion
|
|
4655
4685
|
//#region src/internal/reading/ready.ts
|
|
4656
4686
|
/**
|
|
4657
4687
|
* Waiting until a page is ready to be shown. The page's own evidence leads: one page-script call
|
|
@@ -4665,7 +4695,10 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4665
4695
|
* its connection, and a frame that arrives first starts the spell again. Where the page's changes
|
|
4666
4696
|
* are recorded, its evidence includes them: nothing in view may have changed for the spell, which a
|
|
4667
4697
|
* DOM page's changes show better than its paint, and no stall on the way can hide. Content
|
|
4668
|
-
* stillness starts that record itself and ignores capture silence.
|
|
4698
|
+
* stillness starts that record itself and ignores capture silence. Foreground stillness lets
|
|
4699
|
+
* frames keep coming but compares them, so that only motion outside what was moving before the
|
|
4700
|
+
* page's latest input counts; it still waits out unanswered acknowledgements while no frame
|
|
4701
|
+
* comes, and its last look follows the round trip too. Each new document starts a
|
|
4669
4702
|
* new observation, while retries of destroyed script contexts share the caller's deadline.
|
|
4670
4703
|
*/
|
|
4671
4704
|
const make$5 = (page, bridge, capture) => (options = {}) => {
|
|
@@ -4676,30 +4709,54 @@ const make$5 = (page, bridge, capture) => (options = {}) => {
|
|
|
4676
4709
|
}), Effect.flatMap(decodeWith("ready", ReadinessSchema)), Effect.tap((waiting) => Effect.annotateCurrentSpan({ waiting: waiting.join(",") })), Effect.filterOrElse((waiting) => waiting.length === 0, () => failWith("ready", new Timeout({ millis: Duration.toMillis(timeout) }))));
|
|
4677
4710
|
const quiet = (millis, until) => Effect.gen(function* () {
|
|
4678
4711
|
const running = yield* capture.active;
|
|
4679
|
-
|
|
4712
|
+
const foreground = options.still === "foreground";
|
|
4713
|
+
let counts = yield* capture.stats();
|
|
4680
4714
|
let stirred = running ? page.now() : Number.POSITIVE_INFINITY;
|
|
4715
|
+
let reference;
|
|
4716
|
+
const decoded = (frame) => Effect.try({
|
|
4717
|
+
try: () => picture(frame),
|
|
4718
|
+
catch: (error) => undispatched("ready", new Failed({ detail: `no picture: ${String(error)}` }))
|
|
4719
|
+
});
|
|
4720
|
+
const { inputAt } = page.activity;
|
|
4721
|
+
const document = Option.getOrUndefined(yield* capture.latest)?.document;
|
|
4722
|
+
const before = (foreground ? yield* capture.recent : []).filter((frame) => frame.hostTime < inputAt && frame.hostTime >= inputAt - 1500 && frame.document === document);
|
|
4723
|
+
const sampled = before.filter((_, index) => index % Math.ceil(before.length / 8) === 0);
|
|
4724
|
+
const mask = background(yield* Effect.forEach(sampled, decoded));
|
|
4681
4725
|
const look = Effect.gen(function* () {
|
|
4682
4726
|
const stats = yield* capture.stats();
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4727
|
+
const latest = Option.getOrUndefined(yield* capture.latest);
|
|
4728
|
+
const arrived = stats.received !== counts.received;
|
|
4729
|
+
const unseen = stats.accepted - counts.accepted;
|
|
4730
|
+
counts = stats;
|
|
4731
|
+
if (latest === void 0 || !capture.current(latest)) stirred = page.now();
|
|
4732
|
+
else if (!foreground ? arrived || stats.ackBacklog > 0 : !arrived && stats.ackBacklog > 0) stirred = page.now();
|
|
4733
|
+
else if (foreground && (unseen > 0 || reference === void 0)) {
|
|
4734
|
+
const frames = (yield* capture.recent).slice(-Math.max(1, Math.min(8, unseen)));
|
|
4735
|
+
if (unseen > frames.length) stirred = page.now();
|
|
4736
|
+
for (const frame of frames) {
|
|
4737
|
+
const seen = yield* decoded(frame);
|
|
4738
|
+
if (reference === void 0 || stirs(reference, seen, mask)) {
|
|
4739
|
+
reference = seen;
|
|
4740
|
+
stirred = page.now();
|
|
4741
|
+
}
|
|
4742
|
+
}
|
|
4686
4743
|
}
|
|
4687
4744
|
return page.now() - stirred;
|
|
4688
4745
|
});
|
|
4689
4746
|
const spell = Effect.repeat(look, {
|
|
4690
|
-
schedule: Schedule.
|
|
4747
|
+
schedule: Schedule.fixed(Duration.millis(foreground ? 100 : 25)),
|
|
4691
4748
|
until: (still) => still >= millis
|
|
4692
4749
|
});
|
|
4693
4750
|
const capturing = running ? Effect.never : capture.stream().pipe(Stream.runDrain, Effect.andThen(Effect.never));
|
|
4694
4751
|
const still = Effect.gen(function* () {
|
|
4695
4752
|
for (;;) {
|
|
4696
4753
|
yield* spell;
|
|
4697
|
-
const before = received;
|
|
4754
|
+
const before = counts.received;
|
|
4698
4755
|
yield* Effect.all([settled(until), capture.sync], {
|
|
4699
4756
|
concurrency: 2,
|
|
4700
4757
|
discard: true
|
|
4701
4758
|
});
|
|
4702
|
-
if ((yield* look) >= millis && received === before) return;
|
|
4759
|
+
if ((yield* look) >= millis && (foreground || counts.received === before)) return;
|
|
4703
4760
|
}
|
|
4704
4761
|
});
|
|
4705
4762
|
return yield* Effect.raceFirst(capturing, still);
|
|
@@ -4798,7 +4855,7 @@ const make$3 = (page, read, frames) => ({ since, until, unmask }) => Effect.gen(
|
|
|
4798
4855
|
since,
|
|
4799
4856
|
until
|
|
4800
4857
|
}, page.now());
|
|
4801
|
-
if (Option.isNone(asked)) return yield*
|
|
4858
|
+
if (Option.isNone(asked)) return yield* refuse("window", "a window's bounds must be finite, its reach not negative");
|
|
4802
4859
|
const bounds = asked.value;
|
|
4803
4860
|
const changes = yield* Effect.result(read({
|
|
4804
4861
|
since: isWindow(since) ? since.changes ?? bounds.since : isFrame(since) ? since : bounds.since,
|
|
@@ -4887,7 +4944,7 @@ const make$2 = (page, perform, preparePolicy) => {
|
|
|
4887
4944
|
"about:",
|
|
4888
4945
|
"data:",
|
|
4889
4946
|
"file:"
|
|
4890
|
-
].includes(parsed.protocol)) return
|
|
4947
|
+
].includes(parsed.protocol)) return refuse("navigate", `"${redact(url)}" is not a URL`);
|
|
4891
4948
|
return navigation("navigate", () => playwright.goto(parsed.href, {
|
|
4892
4949
|
waitUntil: "domcontentloaded",
|
|
4893
4950
|
timeout: 0
|
|
@@ -5039,4 +5096,4 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
5039
5096
|
//#endregion
|
|
5040
5097
|
export { performed as a, pause as i, make as n, viewOf as r, internalsOf as t };
|
|
5041
5098
|
|
|
5042
|
-
//# sourceMappingURL=page-
|
|
5099
|
+
//# sourceMappingURL=page-BKwfF6z-.mjs.map
|