effect-browser 0.3.0-beta.15 → 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 +18 -6
- package/dist/{Browser-BBSySyjT.mjs → Browser-H63wiekr.mjs} +5 -5
- package/dist/Browser-H63wiekr.mjs.map +1 -0
- package/dist/Browser.d.mts +2 -2
- package/dist/Browser.mjs +1 -1
- package/dist/{BrowserEvent-BRu2juEz.d.mts → BrowserEvent-dq6FRT8w.d.mts} +9 -9
- package/dist/BrowserEvent.d.mts +1 -1
- package/dist/BrowserEvent.mjs +7 -12
- package/dist/BrowserEvent.mjs.map +1 -1
- package/dist/Cdp.mjs +2 -2
- package/dist/{Change-iMlcuzVD.d.mts → Change-DqING3tr.d.mts} +2 -2
- package/dist/Change.d.mts +1 -1
- 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/Motion-DND6I-64.d.mts +40 -0
- package/dist/Motion.d.mts +2 -40
- package/dist/Motion.mjs +1 -2
- package/dist/Motion.mjs.map +1 -1
- package/dist/{Page-B5cjaUp5.mjs → Page-CfB6Zn1p.mjs} +7 -15
- package/dist/Page-CfB6Zn1p.mjs.map +1 -0
- package/dist/{Page-DL9eylp3.d.mts → Page-ku6j5t-v.d.mts} +23 -25
- package/dist/Page.d.mts +1 -1
- package/dist/Page.mjs +1 -1
- package/dist/{Plan-CXA2BW-G.mjs → Plan-C-d5QYS8.mjs} +6 -9
- package/dist/Plan-C-d5QYS8.mjs.map +1 -0
- package/dist/{Plan-6As6vcwT.d.mts → Plan-DJ4hEEna.d.mts} +3 -3
- 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 +2 -2
- package/dist/Presentation.mjs +3 -2
- package/dist/Presentation.mjs.map +1 -1
- package/dist/Stage.d.mts +1 -1
- package/dist/Stage.mjs +8 -7
- package/dist/Stage.mjs.map +1 -1
- package/dist/{Supervisor-DaGlQVjv.mjs → Supervisor-2mPjIYYs.mjs} +44 -19
- package/dist/Supervisor-2mPjIYYs.mjs.map +1 -0
- package/dist/{Supervisor-5tZ47hR5.d.mts → Supervisor-mVPeEUp8.d.mts} +12 -5
- package/dist/Supervisor.d.mts +1 -1
- package/dist/Supervisor.mjs +1 -1
- package/dist/{context-BAjRj7Xo.mjs → context-w3NJPRLo.mjs} +81 -9
- package/dist/context-w3NJPRLo.mjs.map +1 -0
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +4 -4
- package/dist/match.inpage-xOe9LNO0.mjs.map +1 -1
- package/dist/{page-B92QnRfT.mjs → page-BKwfF6z-.mjs} +213 -218
- package/dist/page-BKwfF6z-.mjs.map +1 -0
- package/package.json +1 -1
- package/src/Browser.ts +1 -1
- package/src/BrowserEvent.ts +7 -12
- package/src/Moment.ts +3 -6
- package/src/Motion.ts +1 -2
- package/src/Page.ts +18 -20
- package/src/Plan.ts +1 -2
- package/src/Presentation.ts +2 -1
- package/src/Stage.ts +10 -17
- package/src/Supervisor.ts +9 -9
- package/src/internal/input/actions.ts +53 -97
- package/src/internal/input/dispatch.ts +25 -11
- package/src/internal/input/edit.inpage.ts +26 -11
- package/src/internal/input/evidence.inpage.ts +1 -21
- package/src/internal/input/guard.inpage.ts +9 -29
- package/src/internal/input/guard.ts +15 -10
- 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 +6 -13
- package/src/internal/input/targets.ts +13 -32
- package/src/internal/page/bridge.ts +2 -2
- package/src/internal/page/context.ts +15 -3
- package/src/internal/page/navigation.ts +3 -12
- package/src/internal/pictures/capture.ts +11 -4
- package/src/internal/pictures/clock.ts +8 -3
- package/src/internal/pictures/motion.ts +65 -0
- package/src/internal/pictures/pictures.ts +22 -17
- package/src/internal/pictures/utilsBundle.d.ts +9 -0
- package/src/internal/reading/controls.inpage.ts +8 -1
- package/src/internal/reading/match.inpage.ts +2 -1
- package/src/internal/reading/outline.inpage.ts +7 -4
- package/src/internal/reading/reading.ts +10 -25
- package/src/internal/reading/ready.ts +66 -14
- package/src/internal/supervisor/lifecycle.ts +56 -13
- package/src/internal/timeline/events.ts +5 -8
- package/src/internal/timeline/window.ts +3 -8
- package/dist/Browser-BBSySyjT.mjs.map +0 -1
- package/dist/Page-B5cjaUp5.mjs.map +0 -1
- package/dist/Plan-CXA2BW-G.mjs.map +0 -1
- package/dist/Supervisor-DaGlQVjv.mjs.map +0 -1
- package/dist/context-BAjRj7Xo.mjs.map +0 -1
- package/dist/page-B92QnRfT.mjs.map +0 -1
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { Plan } from "./Motion.mjs";
|
|
2
|
-
import { Action, Box, CursorChanged, KeyChanged, Navigated, PageLoaded, PointerPressed, PointerReleased, Subject,
|
|
1
|
+
import { Plan, Point } from "./Motion.mjs";
|
|
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 Current, i as failWith, l 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
|
|
@@ -333,13 +347,9 @@ const targets = (names, walked, placing) => {
|
|
|
333
347
|
};
|
|
334
348
|
};
|
|
335
349
|
const ResolvedPointSchema = Schema.Struct({
|
|
336
|
-
|
|
337
|
-
|
|
350
|
+
...Point.fields,
|
|
351
|
+
...Subject.fields,
|
|
338
352
|
element: Schema.String,
|
|
339
|
-
tag: Schema.String,
|
|
340
|
-
role: Schema.NullOr(Schema.String),
|
|
341
|
-
name: Schema.String,
|
|
342
|
-
context: SubjectContext,
|
|
343
353
|
box: Schema.optional(Box),
|
|
344
354
|
cursor: Schema.String,
|
|
345
355
|
href: Schema.optional(Schema.String)
|
|
@@ -356,8 +366,7 @@ const PointResultSchema = Schema.Union([ResolvedPointSchema, Schema.Struct({
|
|
|
356
366
|
detail: Schema.String
|
|
357
367
|
})]);
|
|
358
368
|
const ScrollPlanSchema = Schema.NullOr(Schema.Struct({
|
|
359
|
-
|
|
360
|
-
y: Schema.Finite,
|
|
369
|
+
...Point.fields,
|
|
361
370
|
dx: Schema.Finite,
|
|
362
371
|
dy: Schema.Finite
|
|
363
372
|
}));
|
|
@@ -464,6 +473,11 @@ const context = (names, walked) => {
|
|
|
464
473
|
};
|
|
465
474
|
//#endregion
|
|
466
475
|
//#region src/internal/reading/controls.inpage.ts
|
|
476
|
+
/**
|
|
477
|
+
* In the page: a control's states and value as the outline shows them, and as a value; the elements a CSS selector scopes a
|
|
478
|
+
* read to; and a condition `Page.waitFor` waits for. See `names.inpage.ts` for what a page-side part
|
|
479
|
+
* may use.
|
|
480
|
+
*/
|
|
467
481
|
const controls = (names, walked, subjects, texts) => {
|
|
468
482
|
const { clean, isDisabled, isHtml, isInput, isSelect, isTextArea, refFor, textOf } = names;
|
|
469
483
|
const { visible } = walked;
|
|
@@ -553,6 +567,7 @@ const controls = (names, walked, subjects, texts) => {
|
|
|
553
567
|
waitUntil
|
|
554
568
|
};
|
|
555
569
|
};
|
|
570
|
+
const ConditionResultSchema = Schema.Union([Schema.Struct({ met: Schema.Boolean }), Schema.Struct({ invalid: Schema.String })]);
|
|
556
571
|
//#endregion
|
|
557
572
|
//#region src/internal/reading/expect.inpage.ts
|
|
558
573
|
const expectations = (names, subjected) => {
|
|
@@ -942,6 +957,10 @@ const outline = (names, walked, subjects, texts, controlling, url) => {
|
|
|
942
957
|
viewport
|
|
943
958
|
};
|
|
944
959
|
};
|
|
960
|
+
const SnapshotResultSchema = Schema.Union([Schema.Struct({
|
|
961
|
+
snapshot: Snapshot,
|
|
962
|
+
nextRef: Schema.Finite
|
|
963
|
+
}), Schema.Struct({ invalid: Schema.String })]);
|
|
945
964
|
const ViewportResultSchema = Schema.Struct({
|
|
946
965
|
width: Schema.Finite,
|
|
947
966
|
height: Schema.Finite
|
|
@@ -2066,7 +2085,7 @@ const sight = (names, walked, texts, kept) => {
|
|
|
2066
2085
|
*/
|
|
2067
2086
|
const install = (makeNames, makeWalk, makeMatch, makeContext, makeSubjects, makeExpectations, makeText, makeControls, makeFold, makeHistory, makeSight, makeMarks, makeRecord, makeChanges, makeReady, makeOutline, makeTargets, makeEvidence, makeGuard, makeEdit, makeAddresses) => {
|
|
2068
2087
|
const installed = globalThis.__effectBrowser;
|
|
2069
|
-
if (installed !== void 0 && installed.version ===
|
|
2088
|
+
if (installed !== void 0 && installed.version === 20) return installed;
|
|
2070
2089
|
const named = makeNames();
|
|
2071
2090
|
const walked = makeWalk(named);
|
|
2072
2091
|
const placing = makeContext(named, walked);
|
|
@@ -2083,7 +2102,7 @@ const install = (makeNames, makeWalk, makeMatch, makeContext, makeSubjects, make
|
|
|
2083
2102
|
const edited = makeEdit(named, guarded, placing);
|
|
2084
2103
|
const readiness = makeReady(walked, texts, kept, recorder);
|
|
2085
2104
|
const api = {
|
|
2086
|
-
version:
|
|
2105
|
+
version: 20,
|
|
2087
2106
|
snapshot: read.snapshot,
|
|
2088
2107
|
find: subjected.find,
|
|
2089
2108
|
until: makeExpectations(named, subjected).until,
|
|
@@ -2284,74 +2303,26 @@ const make$18 = Effect.fnUntraced(function* (page) {
|
|
|
2284
2303
|
};
|
|
2285
2304
|
});
|
|
2286
2305
|
//#endregion
|
|
2287
|
-
//#region src/internal/pictures/clock.ts
|
|
2288
|
-
/**
|
|
2289
|
-
* The browser's clock read on the owner's: estimates of their offset from timed probes, how an
|
|
2290
|
-
* estimate ages, and the one mapping a browser's pages share. `pictures.ts` takes the probes.
|
|
2291
|
-
*/
|
|
2292
|
-
/** The fastest complete probe limits uncertainty without mistaking transit delay for clock offset. */
|
|
2293
|
-
const estimate = (probes) => {
|
|
2294
|
-
let best;
|
|
2295
|
-
for (const probe of probes) {
|
|
2296
|
-
const roundTripMillis = probe.hostEnd - probe.hostStart;
|
|
2297
|
-
if (!Number.isFinite(probe.hostStart) || !Number.isFinite(probe.hostEnd) || !Number.isFinite(probe.browserTime) || !Number.isFinite(roundTripMillis) || roundTripMillis < 0) continue;
|
|
2298
|
-
const sampledAt = probe.hostStart + roundTripMillis / 2;
|
|
2299
|
-
const offsetMillis = probe.browserTime - sampledAt;
|
|
2300
|
-
if (!Number.isFinite(offsetMillis) || !Number.isFinite(probe.browserTime - probe.hostStart) || !Number.isFinite(probe.browserTime - probe.hostEnd)) continue;
|
|
2301
|
-
if (best === void 0 || roundTripMillis < best.roundTripMillis) best = {
|
|
2302
|
-
offsetMillis,
|
|
2303
|
-
uncertaintyMillis: roundTripMillis / 2,
|
|
2304
|
-
roundTripMillis,
|
|
2305
|
-
sampledAt
|
|
2306
|
-
};
|
|
2307
|
-
}
|
|
2308
|
-
return Option.fromUndefinedOr(best);
|
|
2309
|
-
};
|
|
2310
|
-
const driftPerMillis = 1e-4;
|
|
2311
|
-
/** An estimate's uncertainty at `hostTime`, wider the further that is from when it was sampled. */
|
|
2312
|
-
const uncertaintyAt = (estimate, hostTime) => estimate.uncertaintyMillis + Math.abs(hostTime - estimate.sampledAt) * driftPerMillis;
|
|
2313
|
-
const renewAfter = Duration.seconds(10);
|
|
2314
|
-
/**
|
|
2315
|
-
* Whether a new measurement should replace the current estimate. Each interval contains the true
|
|
2316
|
-
* offset, so overlapping intervals agree and the narrower one is kept, the current one widened by
|
|
2317
|
-
* its age: a probe delayed behind a busy page cannot widen every tab's stamps. A disjoint
|
|
2318
|
-
* measurement means the clocks moved (a wall clock step, or drift between a remote browser and
|
|
2319
|
-
* this host), so the newer evidence wins.
|
|
2320
|
-
*/
|
|
2321
|
-
const supersedes = (next, current) => {
|
|
2322
|
-
const aged = uncertaintyAt(current, next.sampledAt);
|
|
2323
|
-
return next.uncertaintyMillis <= aged || Math.abs(next.offsetMillis - current.offsetMillis) > next.uncertaintyMillis + aged;
|
|
2324
|
-
};
|
|
2325
|
-
/**
|
|
2326
|
-
* Every renderer of a browser reads the same host wall clock, so the offset belongs to the
|
|
2327
|
-
* browser rather than a page. A busy page cannot fail work that an earlier estimate can serve.
|
|
2328
|
-
*/
|
|
2329
|
-
const mapping = (now) => {
|
|
2330
|
-
let latest;
|
|
2331
|
-
let measuredAt = Number.NEGATIVE_INFINITY;
|
|
2332
|
-
const adopt = (measure) => {
|
|
2333
|
-
measuredAt = now();
|
|
2334
|
-
return measure.pipe(Effect.map((estimate) => {
|
|
2335
|
-
if (latest === void 0 || supersedes(estimate, latest)) latest = estimate;
|
|
2336
|
-
return latest;
|
|
2337
|
-
}));
|
|
2338
|
-
};
|
|
2339
|
-
return {
|
|
2340
|
-
latest: () => latest,
|
|
2341
|
-
current: (measure) => Effect.suspend(() => latest === void 0 ? adopt(measure) : Effect.succeed(latest)),
|
|
2342
|
-
renew: (measure) => Effect.suspend(() => latest === void 0 || now() - measuredAt < Duration.toMillis(renewAfter) ? Effect.void : Effect.ignore(adopt(measure)))
|
|
2343
|
-
};
|
|
2344
|
-
};
|
|
2345
|
-
const toHostTime = (calibration, browserEpochMillis) => browserEpochMillis - calibration.offsetMillis;
|
|
2346
|
-
/** CDP input timestamps use seconds, unlike browser frame timestamps and the owner's clock. */
|
|
2347
|
-
const toBrowserSeconds = (calibration, hostMillis) => (hostMillis + calibration.offsetMillis) / 1e3;
|
|
2348
|
-
//#endregion
|
|
2349
2306
|
//#region src/internal/input/dispatch.ts
|
|
2350
2307
|
/**
|
|
2351
2308
|
* Sending input to the browser. Each mouse event, key and inserted text goes out on the page's
|
|
2352
2309
|
* protocol session, stamped with the browser's clock when its run has a mapping, and is published
|
|
2353
2310
|
* as it is submitted.
|
|
2354
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
|
+
});
|
|
2355
2326
|
const make$17 = (page) => {
|
|
2356
2327
|
const { id, pointer, publish, now, noteInput, closedBy } = page;
|
|
2357
2328
|
const { send } = page.protocol;
|
|
@@ -2395,16 +2366,10 @@ const make$17 = (page) => {
|
|
|
2395
2366
|
if (event.type === "mouseReleased") return yield* run.up(held);
|
|
2396
2367
|
if (event.type === "mousePressed") {
|
|
2397
2368
|
yield* run.reserve(2);
|
|
2398
|
-
yield* run.down(held, () => dispatchMouse(event, estimate, submitted), () => dispatchMouse({
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
y: event.y
|
|
2403
|
-
})),
|
|
2404
|
-
button: event.button ?? "left",
|
|
2405
|
-
buttons: 0,
|
|
2406
|
-
clickCount: event.clickCount ?? 1
|
|
2407
|
-
}, 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));
|
|
2408
2373
|
} else {
|
|
2409
2374
|
yield* run.reserve(1);
|
|
2410
2375
|
yield* run.send(() => dispatchMouse(event, estimate, submitted));
|
|
@@ -2453,6 +2418,8 @@ const make$17 = (page) => {
|
|
|
2453
2418
|
* policy decides on, binds an approval to the document and targets it saw, and runs the page
|
|
2454
2419
|
* script's changes in the approved document only.
|
|
2455
2420
|
*/
|
|
2421
|
+
/** Recheck an approval, after any pending input it must see; neither runs without a guard. */
|
|
2422
|
+
const check = (approval, options = {}, before = Effect.void) => approval === void 0 ? Effect.void : before.pipe(Effect.andThen(approval.check(options)));
|
|
2456
2423
|
const inputFailure = (operation, targets, failure) => {
|
|
2457
2424
|
const target = failure.index === void 0 ? void 0 : targets[failure.index];
|
|
2458
2425
|
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 }));
|
|
@@ -2463,8 +2430,8 @@ const make$16 = (page, bridge) => {
|
|
|
2463
2430
|
const { current, evaluateIn, evaluateWithContext } = bridge;
|
|
2464
2431
|
const preparePolicy = (action, info, targets, flags = {}) => Effect.gen(function* () {
|
|
2465
2432
|
for (const target of targets) {
|
|
2466
|
-
if (typeof target === "string" && !/^e\d+$/.test(target)) return yield*
|
|
2467
|
-
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");
|
|
2468
2435
|
}
|
|
2469
2436
|
const input = {
|
|
2470
2437
|
action,
|
|
@@ -2511,9 +2478,12 @@ const make$16 = (page, bridge) => {
|
|
|
2511
2478
|
};
|
|
2512
2479
|
});
|
|
2513
2480
|
const mutate = (operation, call, approval, mayHaveRun = Effect.void) => (approval === void 0 ? current(operation) : Effect.succeed(approval.contextId)).pipe(Effect.flatMap((contextId) => evaluateIn(operation, call, contextId).pipe(Effect.onInterrupt(() => mayHaveRun), Effect.tapError((error) => error.reason._tag === "Failed" && /Cannot find context|__effectBrowser/i.test(error.reason.detail) ? Effect.void : mayHaveRun))), Effect.catchIf(contextGone, () => failWith(operation, new NotActionable({ detail: "the page changed before the approved input could run" }))));
|
|
2481
|
+
/** A read may follow the current document only when no approval binds it to one. */
|
|
2482
|
+
const evaluate = (operation, call, approval) => approval === void 0 ? bridge.evaluate(operation, call) : mutate(operation, call, approval);
|
|
2514
2483
|
return {
|
|
2515
2484
|
preparePolicy,
|
|
2516
|
-
mutate
|
|
2485
|
+
mutate,
|
|
2486
|
+
evaluate
|
|
2517
2487
|
};
|
|
2518
2488
|
};
|
|
2519
2489
|
//#endregion
|
|
@@ -2927,10 +2897,7 @@ const admission = (page, pending, name) => {
|
|
|
2927
2897
|
};
|
|
2928
2898
|
};
|
|
2929
2899
|
/** Close a run on every exit while preserving its native replies for the page's next input. */
|
|
2930
|
-
const useRun = (page, sender, name, run, action) => action.pipe(Effect.
|
|
2931
|
-
onFailure: (error) => run.close.pipe(Effect.andThen(sender.flush(name, run).pipe(Effect.ignore)), Effect.andThen(Effect.fail(error))),
|
|
2932
|
-
onSuccess: (value) => run.close.pipe(Effect.andThen(sender.flush(name, run)), Effect.as(value))
|
|
2933
|
-
}), 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));
|
|
2934
2901
|
const make$14 = (page, sender) => {
|
|
2935
2902
|
const { id, settings, mapping, lane, publish, now, noteInput, span, owned } = page;
|
|
2936
2903
|
const { inputClocks } = sender;
|
|
@@ -2965,7 +2932,7 @@ const make$14 = (page, sender) => {
|
|
|
2965
2932
|
const useInput = (action) => input.begin.pipe(Effect.tap((current) => Effect.sync(() => {
|
|
2966
2933
|
ticket.using(current);
|
|
2967
2934
|
if (estimate !== void 0) inputClocks.set(current, estimate);
|
|
2968
|
-
})), 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))));
|
|
2969
2936
|
let queuedMillis;
|
|
2970
2937
|
const dispatch = (action) => Effect.suspend(() => {
|
|
2971
2938
|
const asked = now();
|
|
@@ -3066,7 +3033,7 @@ const make$13 = (page, dispatch, viewport) => {
|
|
|
3066
3033
|
y: Math.max(0, Math.min(size.height - 1, previous.y))
|
|
3067
3034
|
};
|
|
3068
3035
|
const planned = yield* style.glide(from, to, dragging);
|
|
3069
|
-
const invalid =
|
|
3036
|
+
const invalid = refuse(operation, "motion must be a bounded, ordered schedule ending at the target");
|
|
3070
3037
|
const samples = yield* Schema.decodeEffect(Plan)(planned).pipe(Effect.catch(() => invalid));
|
|
3071
3038
|
if (samples.at(-1)?.x !== to.x || samples.at(-1)?.y !== to.y) return yield* invalid;
|
|
3072
3039
|
yield* Effect.annotateCurrentSpan("samples", samples.length);
|
|
@@ -3163,12 +3130,12 @@ const make$12 = (page, bridge) => {
|
|
|
3163
3130
|
});
|
|
3164
3131
|
/** Wait for the page to settle after input sent since `before`. */
|
|
3165
3132
|
const settle = (operation, before) => Effect.gen(function* () {
|
|
3166
|
-
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));
|
|
3167
3134
|
while (document() > before.document && parsed < document()) yield* Deferred.await(changed);
|
|
3168
3135
|
}).pipe(Effect.timeoutOrElse({
|
|
3169
3136
|
duration: settling,
|
|
3170
3137
|
orElse: () => Effect.fail("unsettled")
|
|
3171
|
-
}), 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"));
|
|
3172
3139
|
return {
|
|
3173
3140
|
mark,
|
|
3174
3141
|
settle
|
|
@@ -3182,29 +3149,22 @@ const make$12 = (page, bridge) => {
|
|
|
3182
3149
|
* viewers watch.
|
|
3183
3150
|
*/
|
|
3184
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 }));
|
|
3185
|
-
const resolvedTarget = (
|
|
3152
|
+
const resolvedTarget = ({ x, y, box, ...target }) => new ResolvedTarget({
|
|
3186
3153
|
point: {
|
|
3187
|
-
x
|
|
3188
|
-
y
|
|
3154
|
+
x,
|
|
3155
|
+
y
|
|
3189
3156
|
},
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
role: result.role,
|
|
3193
|
-
name: result.name,
|
|
3194
|
-
context: result.context,
|
|
3195
|
-
box: result.box,
|
|
3196
|
-
cursor: result.cursor,
|
|
3197
|
-
...result.href === void 0 ? {} : { href: result.href }
|
|
3157
|
+
box,
|
|
3158
|
+
...target
|
|
3198
3159
|
});
|
|
3199
|
-
const make$11 = (
|
|
3200
|
-
const { evaluate } =
|
|
3201
|
-
const { mutate } = guard;
|
|
3160
|
+
const make$11 = (viewport, guard, pointer, dispatch, settling) => {
|
|
3161
|
+
const { evaluate, mutate } = guard;
|
|
3202
3162
|
const { moveTo, wheel } = pointer;
|
|
3203
3163
|
const { flush } = dispatch;
|
|
3204
|
-
const readPoint = (operation, target, approval, scroll) =>
|
|
3164
|
+
const readPoint = (operation, target, approval, scroll) => evaluate(operation, scriptCall("point", target, scroll), approval).pipe(Effect.flatMap(decodeWith(operation, PointResultSchema)));
|
|
3205
3165
|
const resolve = (operation, target, approval, scroll = true) => {
|
|
3206
|
-
if (typeof target === "string" && !/^e\d+$/.test(target)) return
|
|
3207
|
-
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");
|
|
3208
3168
|
return readPoint(operation, target, approval, scroll).pipe(Effect.flatMap((result) => "error" in result ? pointFailure(operation, target, result) : Effect.succeed(resolvedTarget(result))));
|
|
3209
3169
|
};
|
|
3210
3170
|
return {
|
|
@@ -3228,13 +3188,13 @@ const make$11 = (bridge, viewport, guard, pointer, dispatch, settling) => {
|
|
|
3228
3188
|
yield* wheel(operation, marks, point, Math.max(-size.width * .9, Math.min(size.width * .9, plan.dx)), Math.max(-size.height * .9, Math.min(size.height * .9, plan.dy)));
|
|
3229
3189
|
yield* flush(operation, marks.input);
|
|
3230
3190
|
yield* settling.settle(operation, before);
|
|
3231
|
-
|
|
3191
|
+
yield* check(approval);
|
|
3232
3192
|
}
|
|
3233
3193
|
yield* marks.touched;
|
|
3234
3194
|
const before = settling.mark();
|
|
3235
3195
|
yield* resolve(operation, target, approval);
|
|
3236
3196
|
yield* settling.settle(operation, before);
|
|
3237
|
-
|
|
3197
|
+
yield* check(approval);
|
|
3238
3198
|
return yield* resolve(operation, target, approval, false);
|
|
3239
3199
|
})
|
|
3240
3200
|
};
|
|
@@ -3247,12 +3207,6 @@ const make$11 = (bridge, viewport, guard, pointer, dispatch, settling) => {
|
|
|
3247
3207
|
* `perform`, which admits it, puts it to the input guard and records it. A click, a key or a scroll
|
|
3248
3208
|
* then waits for the page to settle: a task and a frame, and a document if the input asked for one.
|
|
3249
3209
|
*/
|
|
3250
|
-
const buttonMask = {
|
|
3251
|
-
none: 0,
|
|
3252
|
-
left: 1,
|
|
3253
|
-
right: 2,
|
|
3254
|
-
middle: 4
|
|
3255
|
-
};
|
|
3256
3210
|
const partsOf = (page, bridge, viewport) => {
|
|
3257
3211
|
const dispatch = make$17(page);
|
|
3258
3212
|
const pointer = make$13(page, dispatch, viewport);
|
|
@@ -3260,12 +3214,11 @@ const partsOf = (page, bridge, viewport) => {
|
|
|
3260
3214
|
const settling = make$12(page, bridge);
|
|
3261
3215
|
return {
|
|
3262
3216
|
page,
|
|
3263
|
-
bridge,
|
|
3264
3217
|
...settling,
|
|
3265
3218
|
viewportFor: viewport.viewportFor,
|
|
3266
3219
|
perform: make$14(page, dispatch),
|
|
3267
3220
|
...guard,
|
|
3268
|
-
...make$11(
|
|
3221
|
+
...make$11(viewport, guard, pointer, dispatch, settling),
|
|
3269
3222
|
...pointer,
|
|
3270
3223
|
...make$15(page, bridge, dispatch),
|
|
3271
3224
|
sendMouse: dispatch.sendMouse,
|
|
@@ -3275,13 +3228,15 @@ const partsOf = (page, bridge, viewport) => {
|
|
|
3275
3228
|
/** Whether every number given is finite; a number left out is. */
|
|
3276
3229
|
const finite = (...values) => values.every((value) => value === void 0 || Number.isFinite(value));
|
|
3277
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;
|
|
3278
3233
|
/** A click's options, once its counts are finite. */
|
|
3279
|
-
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");
|
|
3280
3235
|
/** The keys a press sends, once they and its options are valid. */
|
|
3281
3236
|
const pressed = (keys, options) => {
|
|
3282
3237
|
const parts$1 = parts(keys);
|
|
3283
|
-
if (!finite(options.times, options.holdMillis)) return
|
|
3284
|
-
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`);
|
|
3285
3240
|
return Effect.succeed(parts$1);
|
|
3286
3241
|
};
|
|
3287
3242
|
const click = (input) => {
|
|
@@ -3294,7 +3249,7 @@ const click = (input) => {
|
|
|
3294
3249
|
clickCount: clickOptions.clickCount,
|
|
3295
3250
|
holdMillis: clickOptions.holdMillis
|
|
3296
3251
|
}
|
|
3297
|
-
}, 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* () {
|
|
3298
3253
|
yield* clickable(clickOptions);
|
|
3299
3254
|
const resolved = yield* targetFor("click", target, approval, marks);
|
|
3300
3255
|
const { point } = resolved;
|
|
@@ -3303,37 +3258,22 @@ const click = (input) => {
|
|
|
3303
3258
|
yield* marks.at(point);
|
|
3304
3259
|
yield* marks.on(resolved);
|
|
3305
3260
|
yield* moveTo("click", marks, point, resolved.cursor);
|
|
3306
|
-
|
|
3261
|
+
yield* check(approval, { presses: [{
|
|
3307
3262
|
index: 0,
|
|
3308
3263
|
...point
|
|
3309
3264
|
}] });
|
|
3310
3265
|
const before = mark();
|
|
3311
3266
|
yield* marks.sent;
|
|
3312
3267
|
for (let index = 1; index <= count; index++) {
|
|
3313
|
-
if (
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
}] }).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" }))));
|
|
3319
|
-
}
|
|
3320
|
-
yield* sendMouse("click", marks.input, {
|
|
3321
|
-
type: "mousePressed",
|
|
3322
|
-
...point,
|
|
3323
|
-
button,
|
|
3324
|
-
buttons: buttonMask[button],
|
|
3325
|
-
clickCount: index
|
|
3326
|
-
});
|
|
3268
|
+
if (index > 1) yield* check(approval, { presses: [{
|
|
3269
|
+
index: 0,
|
|
3270
|
+
...point
|
|
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" }))));
|
|
3272
|
+
yield* sendMouse("click", marks.input, buttonAt("mousePressed", point, button, index));
|
|
3327
3273
|
const hold = clickOptions.holdMillis ?? (yield* marks.style.hold);
|
|
3328
3274
|
if (clickOptions.holdMillis === void 0) yield* marks.present(hold);
|
|
3329
3275
|
if (hold > 0) yield* Effect.sleep(Duration.millis(hold));
|
|
3330
|
-
yield* sendMouse("click", marks.input,
|
|
3331
|
-
type: "mouseReleased",
|
|
3332
|
-
...point,
|
|
3333
|
-
button,
|
|
3334
|
-
buttons: 0,
|
|
3335
|
-
clickCount: index
|
|
3336
|
-
});
|
|
3276
|
+
yield* sendMouse("click", marks.input, buttonAt("mouseReleased", point, button, index));
|
|
3337
3277
|
}
|
|
3338
3278
|
yield* flush("click", marks.input);
|
|
3339
3279
|
yield* settle("click", before);
|
|
@@ -3343,7 +3283,7 @@ const click = (input) => {
|
|
|
3343
3283
|
const hover = (input) => {
|
|
3344
3284
|
const { settings } = input.page;
|
|
3345
3285
|
const { perform, preparePolicy, targetFor, moveTo, flush } = input;
|
|
3346
|
-
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* () {
|
|
3347
3287
|
const resolved = yield* targetFor("hover", target, approval, marks);
|
|
3348
3288
|
const { point } = resolved;
|
|
3349
3289
|
yield* marks.at(point);
|
|
@@ -3375,7 +3315,7 @@ const drag = (input) => {
|
|
|
3375
3315
|
yield* marks.at(end.point);
|
|
3376
3316
|
yield* marks.on(start, end);
|
|
3377
3317
|
yield* moveTo("drag", marks, start.point, start.cursor);
|
|
3378
|
-
|
|
3318
|
+
yield* check(approval, { presses: [{
|
|
3379
3319
|
index: 0,
|
|
3380
3320
|
...start.point
|
|
3381
3321
|
}, {
|
|
@@ -3383,27 +3323,15 @@ const drag = (input) => {
|
|
|
3383
3323
|
...end.point
|
|
3384
3324
|
}] });
|
|
3385
3325
|
yield* marks.sent;
|
|
3386
|
-
yield* sendMouse("drag", marks.input,
|
|
3387
|
-
type: "mousePressed",
|
|
3388
|
-
...start.point,
|
|
3389
|
-
button: "left",
|
|
3390
|
-
buttons: 1,
|
|
3391
|
-
clickCount: 1
|
|
3392
|
-
});
|
|
3326
|
+
yield* sendMouse("drag", marks.input, buttonAt("mousePressed", start.point));
|
|
3393
3327
|
yield* moveTo("drag", marks, end.point, end.cursor, "drag");
|
|
3394
|
-
yield* sendMouse("drag", marks.input,
|
|
3395
|
-
type: "mouseReleased",
|
|
3396
|
-
...end.point,
|
|
3397
|
-
button: "left",
|
|
3398
|
-
buttons: 0,
|
|
3399
|
-
clickCount: 1
|
|
3400
|
-
});
|
|
3328
|
+
yield* sendMouse("drag", marks.input, buttonAt("mouseReleased", end.point));
|
|
3401
3329
|
yield* flush("drag", marks.input);
|
|
3402
3330
|
}), style);
|
|
3403
3331
|
};
|
|
3404
3332
|
const typeText = (input) => {
|
|
3405
3333
|
const { settings, now } = input.page;
|
|
3406
|
-
const { perform, preparePolicy, mutate, targetFor, moveTo, sendMouse, flush,
|
|
3334
|
+
const { perform, preparePolicy, mutate, targetFor, moveTo, sendMouse, flush, evaluate } = input;
|
|
3407
3335
|
const { currentDocument, sameDocument, keyStroke, typeEvent, mark, settle } = input;
|
|
3408
3336
|
return (text, typeOptions = {}, style = plain) => perform("type", {
|
|
3409
3337
|
target: typeOptions.into,
|
|
@@ -3419,9 +3347,9 @@ const typeText = (input) => {
|
|
|
3419
3347
|
}, [typeOptions.into ?? null], { submit: typeOptions.submit ?? false }), (marks, approval) => Effect.gen(function* () {
|
|
3420
3348
|
const replace = typeOptions.replace ?? true;
|
|
3421
3349
|
const into = typeOptions.into;
|
|
3422
|
-
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`);
|
|
3423
3351
|
const asked = scriptCall("typeable", into ?? null, typeOptions.secret === true);
|
|
3424
|
-
const typeable = yield*
|
|
3352
|
+
const typeable = yield* evaluate("type", asked, approval).pipe(Effect.flatMap(decodeWith("type", TypeableResultSchema)));
|
|
3425
3353
|
if ("error" in typeable) return yield* failWith("type", typeable.error === "stale" && into !== void 0 ? new StaleRef({ ref: into }) : new NotActionable({ detail: typeable.detail }));
|
|
3426
3354
|
if (typeable.subject !== void 0) yield* marks.on(typeable.subject);
|
|
3427
3355
|
const since = yield* currentDocument("type");
|
|
@@ -3432,29 +3360,24 @@ const typeText = (input) => {
|
|
|
3432
3360
|
yield* marks.on(target);
|
|
3433
3361
|
if (marks.style.shown) {
|
|
3434
3362
|
yield* moveTo("type", marks, target.point, target.cursor);
|
|
3435
|
-
|
|
3363
|
+
yield* check(approval, { presses: [{
|
|
3436
3364
|
index: 0,
|
|
3437
3365
|
...target.point
|
|
3438
3366
|
}] });
|
|
3439
3367
|
yield* marks.sent;
|
|
3440
|
-
for (const type of ["mousePressed", "mouseReleased"]) yield* sendMouse("type", marks.input,
|
|
3441
|
-
type,
|
|
3442
|
-
...target.point,
|
|
3443
|
-
button: "left",
|
|
3444
|
-
buttons: type === "mousePressed" ? 1 : 0,
|
|
3445
|
-
clickCount: 1
|
|
3446
|
-
});
|
|
3368
|
+
for (const type of ["mousePressed", "mouseReleased"]) yield* sendMouse("type", marks.input, buttonAt(type, target.point));
|
|
3447
3369
|
yield* flush("type", marks.input);
|
|
3448
3370
|
}
|
|
3449
3371
|
yield* marks.sent;
|
|
3450
|
-
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)));
|
|
3451
3374
|
if ("error" in focused) return yield* editFailure("type", into, focused);
|
|
3452
3375
|
secret ||= focused.secret;
|
|
3453
3376
|
}
|
|
3454
3377
|
if (!secret) yield* marks.reveal;
|
|
3455
|
-
|
|
3378
|
+
yield* check(approval, { focused: true });
|
|
3456
3379
|
yield* marks.sent;
|
|
3457
|
-
const focusHeld = approval
|
|
3380
|
+
const focusHeld = check(approval, { focused: true }, flush("type", marks.input));
|
|
3458
3381
|
if (text === "" && replace && into !== void 0) {
|
|
3459
3382
|
yield* sameDocument("type", since);
|
|
3460
3383
|
yield* keyStroke("type", marks.input, ["Delete"]);
|
|
@@ -3475,7 +3398,7 @@ const typeText = (input) => {
|
|
|
3475
3398
|
}
|
|
3476
3399
|
yield* flush("type", marks.input);
|
|
3477
3400
|
if (typeOptions.submit === true) {
|
|
3478
|
-
|
|
3401
|
+
yield* check(approval, { focused: true });
|
|
3479
3402
|
yield* sameDocument("type", since);
|
|
3480
3403
|
const before = mark();
|
|
3481
3404
|
yield* keyStroke("type", marks.input, ["Enter"]);
|
|
@@ -3508,16 +3431,13 @@ const press = (input) => {
|
|
|
3508
3431
|
yield* marks.on(yield* targetFor("press", on, approval, marks));
|
|
3509
3432
|
const focused = yield* mutate("press", scriptCall("focusOn", on), approval).pipe(Effect.flatMap(decodeWith("press", EditResultSchema)));
|
|
3510
3433
|
if ("error" in focused) return yield* editFailure("press", on, focused);
|
|
3511
|
-
|
|
3434
|
+
yield* check(approval, { focused: true });
|
|
3512
3435
|
}
|
|
3513
3436
|
const before = mark();
|
|
3514
3437
|
let due = now();
|
|
3515
3438
|
yield* marks.sent;
|
|
3516
3439
|
for (let index = 0; index < times; index++) {
|
|
3517
|
-
if (index > 0 && approval
|
|
3518
|
-
yield* flush("press", marks.input);
|
|
3519
|
-
yield* approval.check({ focused: true });
|
|
3520
|
-
}
|
|
3440
|
+
if (index > 0 && activates) yield* check(approval, { focused: true }, flush("press", marks.input));
|
|
3521
3441
|
yield* sameDocument("press", since);
|
|
3522
3442
|
yield* keyStroke("press", marks.input, parts, hold);
|
|
3523
3443
|
if (index + 1 < times) {
|
|
@@ -3537,14 +3457,14 @@ const scroll = (input) => {
|
|
|
3537
3457
|
const { mark, settle } = input;
|
|
3538
3458
|
return (scrollOptions = {}, style = plain) => {
|
|
3539
3459
|
const target = scrollOptions.at;
|
|
3540
|
-
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");
|
|
3541
3461
|
return perform("scroll", {
|
|
3542
3462
|
target: target === void 0 ? void 0 : named(target),
|
|
3543
3463
|
options: {
|
|
3544
3464
|
dx: scrollOptions.dx,
|
|
3545
3465
|
dy: scrollOptions.dy
|
|
3546
3466
|
}
|
|
3547
|
-
}, 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* () {
|
|
3548
3468
|
yield* valid;
|
|
3549
3469
|
const viewport = yield* viewportFor("scroll");
|
|
3550
3470
|
const middle = {
|
|
@@ -3765,7 +3685,7 @@ const timed = (options, native, timestamp, generation) => {
|
|
|
3765
3685
|
hostTime,
|
|
3766
3686
|
uncertaintyMillis: uncertaintyAt(estimate, hostTime)
|
|
3767
3687
|
}),
|
|
3768
|
-
receivedAt:
|
|
3688
|
+
receivedAt: monotonicMillis(options.clock),
|
|
3769
3689
|
width: size.width,
|
|
3770
3690
|
height: size.height,
|
|
3771
3691
|
...generation.transport.frameTag()
|
|
@@ -3811,7 +3731,7 @@ const sizeFilter = (options, deliver, drop) => Effect.gen(function* () {
|
|
|
3811
3731
|
run = void 0;
|
|
3812
3732
|
Queue.offerUnsafe(wake, void 0);
|
|
3813
3733
|
};
|
|
3814
|
-
const now = () =>
|
|
3734
|
+
const now = () => monotonicMillis(options.clock);
|
|
3815
3735
|
const adopt = (adopted) => {
|
|
3816
3736
|
run = void 0;
|
|
3817
3737
|
expected = adopted.device;
|
|
@@ -3954,7 +3874,7 @@ const make$8 = (options) => Effect.gen(function* () {
|
|
|
3954
3874
|
let latest = Option.none();
|
|
3955
3875
|
let history = [];
|
|
3956
3876
|
const keepMillis = Duration.toMillis(options.frameHistory);
|
|
3957
|
-
const now = () =>
|
|
3877
|
+
const now = () => monotonicMillis(options.clock);
|
|
3958
3878
|
const counts = tally(now);
|
|
3959
3879
|
let delivered = 0;
|
|
3960
3880
|
const current = (frame) => isCurrent(frame, generation, latest);
|
|
@@ -4035,6 +3955,9 @@ const make$8 = (options) => Effect.gen(function* () {
|
|
|
4035
3955
|
return current.phase !== "Stopped" && current.failure === void 0 && !isClosed();
|
|
4036
3956
|
};
|
|
4037
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);
|
|
4038
3961
|
const viewport = yield* readViewport(options);
|
|
4039
3962
|
if (!resumable()) return;
|
|
4040
3963
|
sizes.restart(viewport);
|
|
@@ -4473,7 +4396,7 @@ const millisOf = (input) => Option.match(Duration.fromInput(input), {
|
|
|
4473
4396
|
});
|
|
4474
4397
|
const reuse = (page, bridge, viewport, capture) => (operation, options) => Effect.gen(function* () {
|
|
4475
4398
|
const maxAge = millisOf(options.maxAge ?? defaultMaxAge);
|
|
4476
|
-
if (!(maxAge >= 0)) return yield*
|
|
4399
|
+
if (!(maxAge >= 0)) return yield* refuse(operation, "maxAge must be a duration of zero or more");
|
|
4477
4400
|
const latest = yield* capture.latest;
|
|
4478
4401
|
const known = viewport.knownViewport();
|
|
4479
4402
|
const { activity } = page;
|
|
@@ -4498,6 +4421,11 @@ const make$7 = Effect.fnUntraced(function* (page, bridge, viewport) {
|
|
|
4498
4421
|
watch: bridge.currentDocument("screencast"),
|
|
4499
4422
|
frameHistory: settings.frameHistory,
|
|
4500
4423
|
viewport: Effect.suspend(() => viewport.viewportFor("screencast")),
|
|
4424
|
+
restore: () => page.protocol.send("Page.captureScreenshot", {
|
|
4425
|
+
format: "jpeg",
|
|
4426
|
+
quality: 0,
|
|
4427
|
+
optimizeForSpeed: true
|
|
4428
|
+
}),
|
|
4501
4429
|
imageSize: jpegSize,
|
|
4502
4430
|
error
|
|
4503
4431
|
});
|
|
@@ -4549,7 +4477,7 @@ const make$7 = Effect.fnUntraced(function* (page, bridge, viewport) {
|
|
|
4549
4477
|
const zoom = (requested) => lane.read("zoom")(Effect.gen(function* () {
|
|
4550
4478
|
const region = yield* Schema.decodeEffect(Region)(requested).pipe(Effect.mapError((error) => undispatched("zoom", new InvalidRequest({ detail: error.message }))));
|
|
4551
4479
|
const size = viewport.knownViewport() ?? (yield* viewport.viewportFor("zoom"));
|
|
4552
|
-
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");
|
|
4553
4481
|
const image = yield* picture("zoom", 80, region);
|
|
4554
4482
|
return new Zoom({
|
|
4555
4483
|
page: id,
|
|
@@ -4560,7 +4488,7 @@ const make$7 = Effect.fnUntraced(function* (page, bridge, viewport) {
|
|
|
4560
4488
|
const captureStats = (options = {}) => {
|
|
4561
4489
|
if (options.window === void 0) return capture.stats();
|
|
4562
4490
|
const millis = millisOf(options.window);
|
|
4563
|
-
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");
|
|
4564
4492
|
};
|
|
4565
4493
|
return {
|
|
4566
4494
|
capture,
|
|
@@ -4578,10 +4506,6 @@ const make$7 = Effect.fnUntraced(function* (page, bridge, viewport) {
|
|
|
4578
4506
|
* read takes its turn on the page and shares its work with identical reads, as `lane.ts`
|
|
4579
4507
|
* describes. The viewport's text as it was last read is kept, for `Page.state`.
|
|
4580
4508
|
*/
|
|
4581
|
-
const SnapshotResult = Schema.Union([Schema.Struct({
|
|
4582
|
-
snapshot: Snapshot,
|
|
4583
|
-
nextRef: Schema.Finite
|
|
4584
|
-
}), Schema.Struct({ invalid: Schema.String })]);
|
|
4585
4509
|
const FindResults = Schema.Struct({
|
|
4586
4510
|
found: Schema.Array(Found),
|
|
4587
4511
|
nextRef: Schema.Finite
|
|
@@ -4590,7 +4514,6 @@ const UntilResult = Schema.Struct({
|
|
|
4590
4514
|
met: Schema.Boolean,
|
|
4591
4515
|
mark: Schema.String
|
|
4592
4516
|
});
|
|
4593
|
-
const ConditionResult = Schema.Union([Schema.Struct({ met: Schema.Boolean }), Schema.Struct({ invalid: Schema.String })]);
|
|
4594
4517
|
const wanted = (value) => value === void 0 ? null : typeof value === "string" ? value : {
|
|
4595
4518
|
source: value.source,
|
|
4596
4519
|
flags: value.flags
|
|
@@ -4625,8 +4548,8 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4625
4548
|
...asked,
|
|
4626
4549
|
firstRef: yield* Ref.get(nextRef)
|
|
4627
4550
|
};
|
|
4628
|
-
const result = yield* evaluate("snapshot", scriptCall("snapshot", request)).pipe(Effect.flatMap(decodeWith("snapshot",
|
|
4629
|
-
if ("invalid" in result) return yield*
|
|
4551
|
+
const result = yield* evaluate("snapshot", scriptCall("snapshot", request)).pipe(Effect.flatMap(decodeWith("snapshot", SnapshotResultSchema)));
|
|
4552
|
+
if ("invalid" in result) return yield* refuse("snapshot", result.invalid);
|
|
4630
4553
|
const { text, truncated, url } = result.snapshot;
|
|
4631
4554
|
yield* counted(result.nextRef);
|
|
4632
4555
|
yield* Effect.annotateCurrentSpan({
|
|
@@ -4662,7 +4585,7 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4662
4585
|
maxChars: options.maxChars ?? 12e3,
|
|
4663
4586
|
unmask: options.unmask ?? false
|
|
4664
4587
|
};
|
|
4665
|
-
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* () {
|
|
4666
4589
|
const result = yield* evaluate("text", scriptCall("text", request)).pipe(Effect.flatMap(decodeWith("text", TextResultSchema)));
|
|
4667
4590
|
if (result === null) return yield* failWith("text", new StaleRef({ ref: scope }));
|
|
4668
4591
|
yield* Effect.annotateCurrentSpan({
|
|
@@ -4686,7 +4609,7 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4686
4609
|
};
|
|
4687
4610
|
const millis = Math.min(Duration.toMillis(timeout), Number.MAX_SAFE_INTEGER);
|
|
4688
4611
|
const unmet = () => failWith("waitFor", new Timeout({ millis }));
|
|
4689
|
-
const look = evaluate("waitFor", scriptCall("waitUntil", request, millis)).pipe(Effect.flatMap(decodeWith("waitFor",
|
|
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()));
|
|
4690
4613
|
return lane.read("waitFor")(Effect.void).pipe(Effect.andThen(Effect.retry(look, { while: contextGone })), Effect.timeoutOrElse({
|
|
4691
4614
|
duration: timeout,
|
|
4692
4615
|
orElse: unmet
|
|
@@ -4714,6 +4637,51 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4714
4637
|
};
|
|
4715
4638
|
});
|
|
4716
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
|
|
4717
4685
|
//#region src/internal/reading/ready.ts
|
|
4718
4686
|
/**
|
|
4719
4687
|
* Waiting until a page is ready to be shown. The page's own evidence leads: one page-script call
|
|
@@ -4727,7 +4695,10 @@ const make$6 = Effect.fnUntraced(function* (page, bridge) {
|
|
|
4727
4695
|
* its connection, and a frame that arrives first starts the spell again. Where the page's changes
|
|
4728
4696
|
* are recorded, its evidence includes them: nothing in view may have changed for the spell, which a
|
|
4729
4697
|
* DOM page's changes show better than its paint, and no stall on the way can hide. Content
|
|
4730
|
-
* 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
|
|
4731
4702
|
* new observation, while retries of destroyed script contexts share the caller's deadline.
|
|
4732
4703
|
*/
|
|
4733
4704
|
const make$5 = (page, bridge, capture) => (options = {}) => {
|
|
@@ -4738,30 +4709,54 @@ const make$5 = (page, bridge, capture) => (options = {}) => {
|
|
|
4738
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) }))));
|
|
4739
4710
|
const quiet = (millis, until) => Effect.gen(function* () {
|
|
4740
4711
|
const running = yield* capture.active;
|
|
4741
|
-
|
|
4712
|
+
const foreground = options.still === "foreground";
|
|
4713
|
+
let counts = yield* capture.stats();
|
|
4742
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));
|
|
4743
4725
|
const look = Effect.gen(function* () {
|
|
4744
4726
|
const stats = yield* capture.stats();
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
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
|
+
}
|
|
4748
4743
|
}
|
|
4749
4744
|
return page.now() - stirred;
|
|
4750
4745
|
});
|
|
4751
4746
|
const spell = Effect.repeat(look, {
|
|
4752
|
-
schedule: Schedule.
|
|
4747
|
+
schedule: Schedule.fixed(Duration.millis(foreground ? 100 : 25)),
|
|
4753
4748
|
until: (still) => still >= millis
|
|
4754
4749
|
});
|
|
4755
4750
|
const capturing = running ? Effect.never : capture.stream().pipe(Stream.runDrain, Effect.andThen(Effect.never));
|
|
4756
4751
|
const still = Effect.gen(function* () {
|
|
4757
4752
|
for (;;) {
|
|
4758
4753
|
yield* spell;
|
|
4759
|
-
const before = received;
|
|
4754
|
+
const before = counts.received;
|
|
4760
4755
|
yield* Effect.all([settled(until), capture.sync], {
|
|
4761
4756
|
concurrency: 2,
|
|
4762
4757
|
discard: true
|
|
4763
4758
|
});
|
|
4764
|
-
if ((yield* look) >= millis && received === before) return;
|
|
4759
|
+
if ((yield* look) >= millis && (foreground || counts.received === before)) return;
|
|
4765
4760
|
}
|
|
4766
4761
|
});
|
|
4767
4762
|
return yield* Effect.raceFirst(capturing, still);
|
|
@@ -4860,7 +4855,7 @@ const make$3 = (page, read, frames) => ({ since, until, unmask }) => Effect.gen(
|
|
|
4860
4855
|
since,
|
|
4861
4856
|
until
|
|
4862
4857
|
}, page.now());
|
|
4863
|
-
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");
|
|
4864
4859
|
const bounds = asked.value;
|
|
4865
4860
|
const changes = yield* Effect.result(read({
|
|
4866
4861
|
since: isWindow(since) ? since.changes ?? bounds.since : isFrame(since) ? since : bounds.since,
|
|
@@ -4949,7 +4944,7 @@ const make$2 = (page, perform, preparePolicy) => {
|
|
|
4949
4944
|
"about:",
|
|
4950
4945
|
"data:",
|
|
4951
4946
|
"file:"
|
|
4952
|
-
].includes(parsed.protocol)) return
|
|
4947
|
+
].includes(parsed.protocol)) return refuse("navigate", `"${redact(url)}" is not a URL`);
|
|
4953
4948
|
return navigation("navigate", () => playwright.goto(parsed.href, {
|
|
4954
4949
|
waitUntil: "domcontentloaded",
|
|
4955
4950
|
timeout: 0
|
|
@@ -5099,6 +5094,6 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
5099
5094
|
return Object.assign(new Built(internals), assembled);
|
|
5100
5095
|
});
|
|
5101
5096
|
//#endregion
|
|
5102
|
-
export { performed as a, pause as i, make as n,
|
|
5097
|
+
export { performed as a, pause as i, make as n, viewOf as r, internalsOf as t };
|
|
5103
5098
|
|
|
5104
|
-
//# sourceMappingURL=page-
|
|
5099
|
+
//# sourceMappingURL=page-BKwfF6z-.mjs.map
|