effect-browser 0.3.0-beta.16 → 0.3.0-beta.20
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 +14 -7
- package/dist/{Browser-DRPthkNO.mjs → Browser-BwCldIff.mjs} +6 -5
- package/dist/Browser-BwCldIff.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 +4 -4
- 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/identity.ts +2 -4
- 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
package/README.md
CHANGED
|
@@ -122,6 +122,12 @@ longer than `quietMillis` between phases reads as still. On the slot machine fix
|
|
|
122
122
|
connection stalled for 450 to 900 ms toward either end while the reels spun, none of 132 waits
|
|
123
123
|
ended early, where all 36 did before.
|
|
124
124
|
|
|
125
|
+
`Page.ready({ still: "foreground", quietMillis })` allows motion already seen in the 1.5 seconds
|
|
126
|
+
before the page's latest input, such as idle decoration. Motion elsewhere restarts the quiet
|
|
127
|
+
interval. It compares newly accepted frames, including brief motion between polls and frames
|
|
128
|
+
accepted after a viewport-size check; missing history or more than eight new frames in one poll
|
|
129
|
+
restarts the interval conservatively. Without pre-input frame history, all motion counts.
|
|
130
|
+
|
|
125
131
|
`Page.ready({ still: "content", quietMillis })` instead observes a full interval without visible
|
|
126
132
|
recorded DOM changes. It starts the recorder itself and starts the interval again in each new
|
|
127
133
|
document; navigation retries share the original timeout. Canvas animation can continue while DOM
|
|
@@ -341,9 +347,8 @@ text and the facts as trusted, and the page's text only as evidence. It never se
|
|
|
341
347
|
words. A judgement only adds to structure: a `secret` fact counts whatever the judge reads. A judge
|
|
342
348
|
that fails or exceeds `timeout` (30 seconds) leaves the input unjudged. `make` then denies the input
|
|
343
349
|
if it has any fact, with the judge's failure as the `PolicyDenied` cause, and lets an input without
|
|
344
|
-
facts, such as a same-origin link, go ahead.
|
|
345
|
-
`strictJsonSchema: true` in the model's config
|
|
346
|
-
review fails to decode.
|
|
350
|
+
facts, such as a same-origin link, go ahead. With `@effect/ai-openrouter`, set
|
|
351
|
+
`strictJsonSchema: true` in the model's config for structured judge outputs.
|
|
347
352
|
|
|
348
353
|
Holds use `policyTimeout`, a finite positive duration defaulting to five minutes, separately from
|
|
349
354
|
the action timeout. They do not keep the page locked. After approval, the library verifies the same
|
|
@@ -619,11 +624,13 @@ under browser zoom, is never stalled. `foreignSize` therefore also counts some o
|
|
|
619
624
|
frames: those of a new size still unconfirmed when another size replaced it, when the capture
|
|
620
625
|
stopped, or beyond the 16 held. Before taking any new library picture, including an uncropped
|
|
621
626
|
forced screenshot, the running native capture stops. It restarts with the same readers and settings
|
|
622
|
-
only after the actual screenshot promise and viewport restoration settle
|
|
623
|
-
|
|
627
|
+
only after the actual screenshot promise and viewport restoration settle. Before restarting, it
|
|
628
|
+
takes an uncropped surface snapshot and discards its pixels, then reads the current viewport:
|
|
629
|
+
Chromium can answer a crop before the compositor paints the restored page, even with the viewport's
|
|
630
|
+
own proportions. A frame received during the pause is acknowledged and discarded as
|
|
624
631
|
`duringPictures`; the pause can produce no callbacks, leaving the count at zero. Cached-frame reuse
|
|
625
|
-
still costs no call. A forced picture with capture running adds stop,
|
|
626
|
-
calls to its usual cost. Caller cancellation retains the actual native replies: the next picture or
|
|
632
|
+
still costs no call. A forced picture with capture running adds stop, a restoration snapshot,
|
|
633
|
+
viewport refresh and restart calls to its usual cost. Caller cancellation retains the actual native replies: the next picture or
|
|
627
634
|
capture waits for them, cleanup is bounded to two seconds, and unconfirmed restoration fails the
|
|
628
635
|
capture rather than resuming it early. Readiness requires current post-resume frame evidence, so
|
|
629
636
|
paused capture cannot certify that a still-painting page is quiet.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { DialogShown, Disconnected, PageClosed, PageOpened, PageUntracked, RecordedEvent, SessionEnding } from "./BrowserEvent.mjs";
|
|
3
3
|
import { BrowserError, Busy, Closed, EventHistoryExpired, Failed, InvalidRequest, Limit, Suspended } from "./BrowserError.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { c as undispatched, d as monotonicMillis, i as failWith, s as refuse, t as call, u as mapping } from "./context-w3NJPRLo.mjs";
|
|
5
5
|
import { c as FailFast, i as redact } from "./url-Cd04Okid.mjs";
|
|
6
|
-
import { n as make$5 } from "./page-
|
|
6
|
+
import { n as make$5 } from "./page-BKwfF6z-.mjs";
|
|
7
7
|
import { Cause, Clock, Context, Crypto, DateTime, Deferred, Duration, Effect, Exit, Option, PlatformError, Queue, Schema, Scope, Semaphore, Stream } from "effect";
|
|
8
8
|
//#region src/internal/input/gate.ts
|
|
9
9
|
/**
|
|
@@ -168,7 +168,8 @@ const native = () => Crypto.make({
|
|
|
168
168
|
});
|
|
169
169
|
const make$3 = Effect.gen(function* () {
|
|
170
170
|
const supplied = yield* Effect.serviceOption(Crypto.Crypto);
|
|
171
|
-
|
|
171
|
+
const crypto = Option.getOrElse(supplied, native);
|
|
172
|
+
return yield* Effect.mapError(crypto.randomUUIDv4(), () => undispatched("make", new Failed({ detail: "Could not name connection" })));
|
|
172
173
|
});
|
|
173
174
|
//#endregion
|
|
174
175
|
//#region src/internal/page/openings.ts
|
|
@@ -250,7 +251,7 @@ const make$1 = (capacity) => {
|
|
|
250
251
|
};
|
|
251
252
|
const stream = (after) => Stream.unwrap(Effect.sync(() => {
|
|
252
253
|
let cursor = after ?? sequence;
|
|
253
|
-
if (!Number.isSafeInteger(cursor) || cursor < 0 || cursor > sequence) return Stream.
|
|
254
|
+
if (!Number.isSafeInteger(cursor) || cursor < 0 || cursor > sequence) return Stream.fromEffect(refuse("events", "the event cursor must be a nonnegative integer no greater than the latest sequence"));
|
|
254
255
|
return Stream.fromEffectRepeat(Effect.gen(function* () {
|
|
255
256
|
while (true) {
|
|
256
257
|
const oldest = records[0]?.sequence ?? sequence + 1;
|
|
@@ -625,4 +626,4 @@ const make = Effect.fn("Browser.make")(function* (context, info, options = {}) {
|
|
|
625
626
|
//#endregion
|
|
626
627
|
export { make as i, Browser_exports as n, Suspension as r, Browser as t };
|
|
627
628
|
|
|
628
|
-
//# sourceMappingURL=Browser-
|
|
629
|
+
//# sourceMappingURL=Browser-BwCldIff.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Browser-BwCldIff.mjs","names":["make","make","make","make","Url.redact","Identity.make","BrowserClock.monotonicMillis","mapping","BrowserClock.mapping","Timeline.make","Gate.make","PageImpl.make","Openings.make"],"sources":["../src/internal/input/gate.ts","../src/internal/page/identity.ts","../src/internal/page/openings.ts","../src/internal/timeline/events.ts","../src/Browser.ts"],"sourcesContent":["/**\n * A browser's input authority: stop admitting writes, drain admitted operations through their\n * records and native replies, then retain the stop for its scopes. Reads never enter this gate.\n */\nimport { Clock, Deferred, Duration, Effect, Exit, Option, type Scope } from \"effect\";\n\nimport { BrowserError, Busy, Closed, InvalidRequest, Suspended } from \"../../BrowserError.ts\";\nimport type { DisconnectCause } from \"../../BrowserEvent.ts\";\n\ninterface Stopped {\n readonly since: number;\n readonly at: number;\n}\n\ntype State =\n | { readonly _tag: \"Open\"; readonly inputs: ReadonlySet<number> }\n | {\n readonly _tag: \"Draining\";\n readonly inputs: ReadonlySet<number>;\n readonly claims: ReadonlySet<number>;\n readonly startedAt: number;\n readonly deadline: number;\n }\n | { readonly _tag: \"Held\"; readonly claims: ReadonlySet<number>; readonly stopped: Stopped };\n\ntype Input =\n | { readonly _tag: \"Enter\" | \"End\" | \"Leave\"; readonly id: number }\n | { readonly _tag: \"Suspend\"; readonly id: number; readonly drain: number }\n | { readonly _tag: \"Expire\" };\n\nconst without = (set: ReadonlySet<number>, id: number) =>\n new Set([...set].filter((each) => each !== id));\n\nconst step = (state: State, input: Input, stopped: Stopped): State => {\n switch (input._tag) {\n case \"Enter\":\n return state._tag === \"Open\"\n ? { ...state, inputs: new Set([...state.inputs, input.id]) }\n : state;\n case \"End\": {\n if (state._tag === \"Held\") return state;\n const inputs = without(state.inputs, input.id);\n\n return state._tag === \"Draining\" && inputs.size === 0\n ? { _tag: \"Held\", claims: state.claims, stopped }\n : { ...state, inputs };\n }\n case \"Suspend\":\n if (state._tag !== \"Open\") return { ...state, claims: new Set([...state.claims, input.id]) };\n\n return state.inputs.size === 0\n ? { _tag: \"Held\", claims: new Set([input.id]), stopped }\n : {\n _tag: \"Draining\",\n inputs: state.inputs,\n claims: new Set([input.id]),\n startedAt: stopped.at,\n deadline: stopped.at + input.drain,\n };\n case \"Leave\": {\n if (state._tag === \"Open\" || !state.claims.has(input.id)) return state;\n const claims = without(state.claims, input.id);\n\n return claims.size > 0\n ? { ...state, claims }\n : { _tag: \"Open\", inputs: state._tag === \"Draining\" ? state.inputs : new Set() };\n }\n case \"Expire\":\n return state._tag === \"Draining\" && stopped.at >= state.deadline\n ? { _tag: \"Open\", inputs: state.inputs }\n : state;\n }\n};\n\nexport const make = (options: {\n readonly now: () => number;\n readonly sequence: () => number;\n readonly closedBy: () => DisconnectCause | undefined;\n readonly lost: Effect.Effect<DisconnectCause>;\n readonly clock: Clock.Clock;\n readonly drain: Duration.Duration;\n}) => {\n let state: State = { _tag: \"Open\", inputs: new Set() };\n let next = 0;\n let refused = Deferred.makeUnsafe<void>();\n let ready = Deferred.makeUnsafe<Stopped, BrowserError>();\n\n const error = (operation: string) =>\n new BrowserError({\n operation,\n reason:\n options.closedBy() === undefined\n ? new Suspended()\n : new Closed({ cause: options.closedBy() ?? \"connection\" }),\n dispatched: false,\n });\n\n const stopped = (): Stopped => ({ since: options.sequence(), at: options.now() });\n\n // Every change to authority happens here, synchronously with its admission or scope closure.\n const apply = (input: Input): State => {\n if (input._tag !== \"Expire\" && state._tag === \"Draining\" && options.now() >= state.deadline)\n apply({ _tag: \"Expire\" });\n const before = state;\n\n state = step(state, input, stopped());\n if (input._tag === \"Expire\" && before._tag === \"Draining\" && state._tag === \"Open\")\n Deferred.doneUnsafe(\n ready,\n Exit.fail(\n new BrowserError({\n operation: \"suspend\",\n reason: new Busy({\n waitedMillis: Math.round(options.now() - before.startedAt),\n ahead: before.inputs.size,\n }),\n dispatched: false,\n }),\n ),\n );\n if (before._tag === \"Open\" && state._tag !== \"Open\") Deferred.doneUnsafe(refused, Exit.void);\n if (before._tag === \"Draining\" && state._tag === \"Held\")\n Deferred.doneUnsafe(ready, Exit.succeed(state.stopped));\n if (before._tag !== \"Open\" && state._tag === \"Open\") {\n refused = Deferred.makeUnsafe();\n ready = Deferred.makeUnsafe();\n }\n\n return state;\n };\n\n const check = (operation: string) =>\n Effect.suspend(() =>\n state._tag === \"Open\" && options.closedBy() === undefined\n ? Effect.void\n : Effect.fail(error(operation)),\n );\n\n const suspend = (\n drain: Duration.Input = options.drain,\n ): Effect.Effect<Stopped, BrowserError, Scope.Scope> =>\n Effect.suspend(() => {\n const duration = Duration.fromInput(drain);\n\n if (\n Option.isNone(duration) ||\n !Duration.isFinite(duration.value) ||\n Duration.toMillis(duration.value) < 0\n )\n return Effect.fail(\n new BrowserError({\n operation: \"suspend\",\n reason: new InvalidRequest({ detail: \"drain must be a finite nonnegative duration\" }),\n dispatched: false,\n }),\n );\n const id = ++next;\n const leave = Effect.sync(() => apply({ _tag: \"Leave\", id }));\n\n return Effect.acquireRelease(\n Effect.gen(function* () {\n if (options.closedBy() !== undefined) return yield* error(\"suspend\");\n const current = apply({ _tag: \"Suspend\", id, drain: Duration.toMillis(duration.value) });\n\n if (current._tag === \"Held\") return current.stopped;\n if (current._tag !== \"Draining\")\n return yield* Effect.die(\"suspension did not retain authority\");\n const pending = ready;\n\n // Native completion and timer callbacks both check the same monotonic deadline. A\n // timer may wake a fraction early, so it sleeps the remaining time instead of hanging.\n const expire: Effect.Effect<Stopped, BrowserError> = Effect.suspend(() => {\n const left = current.deadline - options.now();\n\n return left > 0\n ? Effect.sleep(Duration.millis(left)).pipe(Effect.andThen(expire))\n : Effect.sync(() => apply({ _tag: \"Expire\" })).pipe(\n Effect.andThen(Deferred.await(pending)),\n );\n });\n\n const wait = Effect.raceFirst(Deferred.await(pending), expire);\n\n return yield* Effect.raceFirst(\n wait,\n options.lost.pipe(Effect.flatMap(() => Effect.fail(error(\"suspend\")))),\n ).pipe(\n Effect.interruptible,\n Effect.filterOrFail(\n () => options.closedBy() === undefined,\n () => error(\"suspend\"),\n ),\n Effect.onError(() => leave),\n );\n }),\n () => leave,\n );\n }).pipe(Effect.provideService(Clock.Clock, options.clock));\n\n return {\n check,\n suspend,\n refused: (operation: string): Effect.Effect<never, BrowserError> =>\n Effect.suspend(() =>\n state._tag === \"Open\"\n ? Deferred.await(refused).pipe(Effect.andThen(Effect.fail(error(operation))))\n : Effect.fail(error(operation)),\n ),\n enter: (operation: string): Effect.Effect<() => void, BrowserError> =>\n Effect.suspend(() => {\n if (state._tag !== \"Open\" || options.closedBy() !== undefined)\n return Effect.fail(error(operation));\n const id = ++next;\n\n apply({ _tag: \"Enter\", id });\n\n return Effect.succeed(() => {\n apply({ _tag: \"End\", id });\n });\n }),\n };\n};\n\nexport type Gate = ReturnType<typeof make>;\n","/** Connection identity uses the supplied Crypto service, or the host's Web Crypto on Node/Bun. */\nimport { Crypto, Effect, Option, PlatformError } from \"effect\";\n\nimport { Failed } from \"../../BrowserError.ts\";\nimport { undispatched } from \"./context.ts\";\n\n// The core owns this tiny platform adapter to keep Chromium/CDP usable without another package\n// or a new required service. Browser construction captures it once; there is no global counter.\nconst native = () =>\n Crypto.make({\n randomBytes: (size) => globalThis.crypto.getRandomValues(new Uint8Array(size)),\n digest: (algorithm, data) =>\n Effect.tryPromise({\n try: () => globalThis.crypto.subtle.digest(algorithm, new Uint8Array(data)),\n catch: (cause) =>\n PlatformError.systemError({\n module: \"Crypto\",\n method: \"digest\",\n _tag: \"Unknown\",\n description: \"Could not compute digest\",\n cause,\n }),\n }).pipe(Effect.map((bytes) => new Uint8Array(bytes))),\n });\n\nexport const make = Effect.gen(function* () {\n const supplied = yield* Effect.serviceOption(Crypto.Crypto);\n const crypto = Option.getOrElse(supplied, native);\n\n return yield* Effect.mapError(crypto.randomUUIDv4(), () =>\n undispatched(\"make\", new Failed({ detail: \"Could not name connection\" })),\n );\n});\n","/** A page's input waits for the actual tabs it opened to finish the browser's registration. */\nimport { Deferred, Effect, Exit } from \"effect\";\nimport type { CDPSession, Page as PlaywrightPage } from \"playwright-core\";\n\nimport { BrowserError, Closed, Failed, type Reason } from \"../../BrowserError.ts\";\n\n/** How the browser's registration of each tab it was told of ended, once it has. */\nexport type Registrations = WeakMap<PlaywrightPage, Deferred.Deferred<void, BrowserError>>;\n\nexport interface Mark {\n windows: number;\n readonly registrations: Array<Effect.Effect<void, BrowserError>>;\n changed: Deferred.Deferred<void>;\n}\n\nexport const make = Effect.fnUntraced(function* (\n playwright: PlaywrightPage,\n cdp: CDPSession,\n registrations: Registrations,\n closedBy: () => Closed[\"cause\"],\n) {\n const failed = (reason: Reason) =>\n Exit.fail(new BrowserError({ operation: \"newPage\", reason, dispatched: false }));\n\n let active: Mark | undefined;\n const gone = Deferred.makeUnsafe<never, BrowserError>();\n\n const windowOpened = () => {\n if (active !== undefined) active.windows += 1;\n };\n\n const popup = (opened: PlaywrightPage) => {\n if (active === undefined) return;\n // Playwright emits the context's page event first, so its owner already has this exact\n // popup's registration. A window notification alone has no target id and cannot name it.\n const registered = registrations.get(opened);\n\n active.registrations.push(\n registered === undefined\n ? failed(new Failed({ detail: \"the popup has no registration\" }))\n : Deferred.await(registered),\n );\n Deferred.doneUnsafe(active.changed, Exit.void);\n active.changed = Deferred.makeUnsafe<void>();\n };\n\n const clear = Effect.sync(() => {\n active = undefined;\n });\n\n yield* Effect.acquireRelease(\n Effect.sync(() => {\n cdp.on(\"Page.windowOpen\", windowOpened);\n playwright.on(\"popup\", popup);\n }),\n () =>\n Effect.sync(() => {\n active = undefined;\n cdp.off(\"Page.windowOpen\", windowOpened);\n playwright.off(\"popup\", popup);\n Deferred.doneUnsafe(gone, failed(new Closed({ cause: closedBy() })));\n }),\n );\n\n return {\n mark: () => {\n const mark: Mark = { windows: 0, registrations: [], changed: Deferred.makeUnsafe<void>() };\n\n active = mark;\n\n return mark;\n },\n clear,\n settle: (mark: Mark) =>\n Effect.gen(function* () {\n // A blocked window or a tab that closes as it opens may never become a Playwright popup.\n // Discovery and registration both share the input's deadline, so an unresolved opening\n // fails with potentially dispatched input rather than claiming the tab has been tracked.\n while (mark.registrations.length < mark.windows) yield* Deferred.await(mark.changed);\n // A real popup has a known registration; its failure stays a failure, and its wait shares\n // the input's deadline rather than quietly returning before the browser tracks it.\n yield* Effect.forEach(mark.registrations, (registration) => registration);\n }).pipe(Effect.raceFirst(Deferred.await(gone)), Effect.ensuring(clear)),\n };\n});\n\nexport type Openings = Effect.Success<ReturnType<typeof make>>;\n","/**\n * The browser's bounded event history and replay cursors. Readers share the same records and\n * wakeup generation, so a delayed reader cannot block input or retain an unbounded private queue.\n */\nimport { Cause, Deferred, Effect, Stream } from \"effect\";\n\nimport { type BrowserError, EventHistoryExpired } from \"../../BrowserError.ts\";\nimport { type BrowserEvent, RecordedEvent } from \"../../BrowserEvent.ts\";\nimport { refuse, undispatched } from \"../page/context.ts\";\n\n/** The owning Browser validates capacity and closes this timeline with its scope. */\nexport const make = (capacity: number) => {\n let records: ReadonlyArray<RecordedEvent> = [];\n let sequence = 0;\n let closed = false;\n let changed = Deferred.makeUnsafe<void>();\n\n const wake = () => {\n const previous = changed;\n\n changed = Deferred.makeUnsafe<void>();\n Deferred.doneUnsafe(previous, Effect.void);\n };\n\n const publish = (event: BrowserEvent): number => {\n // Native callbacks may finish after their owning scope. They must not revive closed readers.\n if (closed) return sequence;\n sequence += 1;\n const recorded = new RecordedEvent({ sequence, event });\n\n records = records.length < capacity ? [...records, recorded] : [...records.slice(1), recorded];\n wake();\n\n return sequence;\n };\n\n const stream = (after?: number): Stream.Stream<RecordedEvent, BrowserError> =>\n Stream.unwrap(\n Effect.sync(() => {\n // This runs for each subscription, rather than when the reusable stream is constructed.\n let cursor = after ?? sequence;\n\n if (!Number.isSafeInteger(cursor) || cursor < 0 || cursor > sequence)\n return Stream.fromEffect(\n refuse(\n \"events\",\n \"the event cursor must be a nonnegative integer no greater than the latest sequence\",\n ),\n );\n\n return Stream.fromEffectRepeat(\n Effect.gen(function* () {\n while (true) {\n const oldest = records[0]?.sequence ?? sequence + 1;\n\n if (cursor < oldest - 1)\n return yield* undispatched(\n \"events\",\n new EventHistoryExpired({ after: cursor, oldest, latest: sequence }),\n );\n const next = records[cursor - oldest + 1];\n\n if (next !== undefined) {\n cursor = next.sequence;\n\n return next;\n }\n if (closed) return yield* Cause.done();\n // Capture the generation in the same synchronous read as the empty history check.\n // A publish before await completes this exact Deferred, so no wakeup can be missed.\n const waiting = changed;\n\n yield* Deferred.await(waiting);\n }\n }),\n );\n }),\n );\n\n return {\n publish,\n sequence: () => sequence,\n recent: Effect.sync(() => records),\n stream,\n close: Effect.sync(() => {\n if (closed) return;\n closed = true;\n wake();\n }),\n };\n};\n","/**\n * A live browser: its pages and what happens in it.\n *\n * `Browser` is a service with one implementation, built by a provider over a Playwright browser\n * context: `Chromium` launches one locally, `Cdp` connects to any DevTools endpoint and\n * `effect-browserbase` allocates a hosted one. Code written against `Browser` runs on all three.\n * A page is named by its CDP target id, so a new connection to the same browser finds it again.\n *\n * @since 0.3.0\n */\nimport {\n Clock,\n Context,\n DateTime,\n Deferred,\n Duration,\n Effect,\n Exit,\n Option,\n Queue,\n Schema,\n Scope,\n Semaphore,\n type Stream,\n} from \"effect\";\nimport type { BrowserContext, Dialog, Page as PlaywrightPage } from \"playwright-core\";\n\nimport { type BrowserError, Failed, InvalidRequest, Limit } from \"./BrowserError.ts\";\nimport {\n type BrowserEvent,\n DialogShown,\n Disconnected,\n type DisconnectCause,\n PageClosed,\n PageOpened,\n PageUntracked,\n type RecordedEvent,\n SessionEnding,\n} from \"./BrowserEvent.ts\";\nimport * as Gate from \"./internal/input/gate.ts\";\nimport { call, failWith, type Settings, undispatched } from \"./internal/page/context.ts\";\nimport * as Identity from \"./internal/page/identity.ts\";\nimport { FailFast } from \"./internal/page/lane.ts\";\nimport * as Openings from \"./internal/page/openings.ts\";\nimport * as PageImpl from \"./internal/page/page.ts\";\nimport * as Url from \"./internal/page/url.ts\";\nimport * as BrowserClock from \"./internal/pictures/clock.ts\";\nimport * as Timeline from \"./internal/timeline/events.ts\";\nimport type * as Page from \"./Page.ts\";\n\n/** A script that documents run before their own, such as a consent-banner remover. */\nexport interface InitScript {\n /**\n * The documents that run it, by a pattern their address (`location.href`) matches; every\n * document and frame when left out. Under a `match`, the source runs as a block, so its own\n * top-level `let`, `const` and classes stay its own.\n */\n readonly match?: RegExp | undefined;\n readonly source: string;\n}\n\nexport interface Options {\n /**\n * Bound on each action; finite and positive. Defaults to 10 seconds. What a presenter's view\n * takes to show an action, such as its glides and typing at a person's pace, does not count\n * against it.\n */\n readonly actionTimeout?: Duration.Input | undefined;\n /** Bound on each navigation; finite and positive. Defaults to 30 seconds. */\n readonly navigationTimeout?: Duration.Input | undefined;\n /**\n * How long each page keeps screencast frames for `recentFrames`, measured back from the newest;\n * finite and positive. Defaults to 5 seconds, a moment's default window.\n */\n readonly frameHistory?: Duration.Input | undefined;\n /** Events retained for replay and `recentEvents`. A positive safe integer, defaulting to 4,096. */\n readonly eventHistory?: number | undefined;\n /** Allow, deny or hold each input or navigation before it reaches the page. Defaults to allow. */\n readonly guard?: Page.InputGuard | undefined;\n /** A separate bound for policy holds, outside action timeouts. Defaults to 5 minutes. */\n readonly policyTimeout?: Duration.Input | undefined;\n /** Scripts that new documents run before their own, each where its `match` allows. */\n readonly initScripts?: ReadonlyArray<InitScript> | undefined;\n /**\n * The most pages the browser keeps open, those a site opens included, which are never refused. At\n * it, `newPage` waits for one to close, within the action timeout, then fails `Limit`; under\n * `Page.failFast` it fails at once. A positive safe integer; no limit when left out.\n */\n readonly maxPages?: number | undefined;\n}\n\nexport interface EventOptions {\n /** Resume after this sequence; 0 replays from the beginning if it is still retained. */\n readonly after?: number | undefined;\n}\n\nexport interface SuspendOptions {\n /** Finite, nonnegative drain bound; defaults to the browser's navigationTimeout. */\n readonly drain?: Duration.Input | undefined;\n}\n\n/** When admitted input finished; events after `since` describe the handoff interval. */\nexport class Suspension extends Schema.Class<Suspension>(\"effect-browser/Suspension\")({\n since: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n at: Schema.Finite,\n}) {}\n\n/**\n * A connection to the browser apart from the one that drives its pages, for their screencasts,\n * as a provider that reaches the browser over a network supplies it: a frame and its\n * acknowledgement then never wait behind a large message, such as an upload or a read's answer,\n * on the connection that drives the page. It is read-only. A page's session on it sends the\n * capture's commands alone, and the page's own session keeps its focus emulation, which keeps a\n * tab behind painting.\n */\nexport interface CaptureSource {\n /**\n * A session on the page's target, for the scope. `event` gets the session's events in the order\n * the browser sent them, its target's detach among them, until the scope closes; `lost` gets\n * the connection's failure, once, if it fails first. Its calls never throw: a failure rejects.\n */\n readonly attach: (\n target: string,\n listener: {\n readonly event: (method: string, params: unknown) => void;\n readonly lost: (error: BrowserError) => void;\n },\n ) => Effect.Effect<\n (\n method:\n | \"Page.enable\"\n | \"Page.getFrameTree\"\n | \"Page.startScreencast\"\n | \"Page.screencastFrameAck\"\n | \"Page.stopScreencast\",\n params?: Record<string, unknown>,\n ) => Promise<unknown>,\n BrowserError,\n Scope.Scope\n >;\n}\n\nexport interface Service {\n /** The provider's session id, or a local id. */\n readonly id: string;\n /** Fresh for this connection, even when reattaching the same provider session and page. */\n readonly connection: string;\n readonly provider: string;\n /** When the provider ends the session on its own, as a hosted session's timeout does. */\n readonly expiresAt: DateTime.Utc | undefined;\n /** Host monotonic milliseconds on the clock shared by this browser’s events and frames. */\n readonly now: Effect.Effect<number>;\n /** Drain admitted input and withhold new input for this scope; reads and capture continue. */\n readonly suspend: (\n options?: SuspendOptions,\n ) => Effect.Effect<Suspension, BrowserError, Scope.Scope>;\n /** The Playwright context, for anything this API does not cover. Never give it to a model. */\n readonly context: BrowserContext;\n /** Open pages in the order this browser began tracking them. */\n readonly pages: Effect.Effect<ReadonlyArray<Page.Page>>;\n /** The open page with this id, its CDP target id, as stored before a reconnect. */\n readonly page: (id: string) => Effect.Effect<Option.Option<Page.Page>>;\n /** The first open page, opening one when there is none. */\n readonly firstPage: Effect.Effect<Page.Page, BrowserError>;\n readonly newPage: (url?: string) => Effect.Effect<Page.Page, BrowserError>;\n /**\n * Completes once the browser is lost to its owner, with why: its connection dropped, its\n * provider ended its session, or its owner's scope released it.\n */\n readonly disconnected: Effect.Effect<DisconnectCause>;\n /** Live events, or replay after a cursor. A reader that falls behind fails with EventHistoryExpired. */\n readonly events: (options?: EventOptions) => Stream.Stream<RecordedEvent, BrowserError>;\n /** The latest `eventHistory` events, oldest first. */\n readonly recentEvents: Effect.Effect<ReadonlyArray<BrowserEvent>>;\n}\n\nexport class Browser extends Context.Service<Browser, Service>()(\"effect-browser/Browser\") {}\n\n/** The settings every page shares, and how many events the browser keeps, from its options. */\nconst settingsOf = Effect.fnUntraced(function* (options: Options) {\n const invalid = (detail: string) => undispatched(\"make\", new InvalidRequest({ detail }));\n\n // Every bound guards a lock or a held key, so each must be a real, finite deadline.\n const bound = (name: string, input: Duration.Input | undefined, fallback: Duration.Duration) => {\n const decoded = Duration.fromInput(input ?? fallback);\n\n return Option.isSome(decoded) &&\n Number.isFinite(Duration.toMillis(decoded.value)) &&\n Duration.isPositive(decoded.value)\n ? Effect.succeed(decoded.value)\n : Effect.fail(invalid(`${name} must be finite and greater than zero`));\n };\n\n const settings: Settings = {\n actionTimeout: yield* bound(\"actionTimeout\", options.actionTimeout, Duration.seconds(10)),\n navigationTimeout: yield* bound(\n \"navigationTimeout\",\n options.navigationTimeout,\n Duration.seconds(30),\n ),\n frameHistory: yield* bound(\"frameHistory\", options.frameHistory, Duration.seconds(5)),\n guard: options.guard,\n policyTimeout: yield* bound(\"policyTimeout\", options.policyTimeout, Duration.minutes(5)),\n };\n\n const eventHistory = options.eventHistory ?? 4096;\n const { maxPages } = options;\n\n if (!Number.isSafeInteger(eventHistory) || eventHistory < 1)\n return yield* invalid(\"eventHistory must be a positive safe integer\");\n if (maxPages !== undefined && (!Number.isSafeInteger(maxPages) || maxPages < 1))\n return yield* invalid(\"maxPages must be a positive safe integer\");\n\n return { settings, eventHistory, maxPages };\n});\n\n/**\n * A provider that ends a session at `expiresAt` by its own clock can cut the connection a little\n * before this host's clock gets there.\n */\nconst endMargin = Duration.seconds(5);\n\n/**\n * The browser's loss, once: its context closing from the other side, at or after the session's\n * end or before it, or `lose`, as the owner's scope releases it. Playwright leaves the calls in\n * flight on the library's own sessions unanswered when the connection drops, so `untilLost` fails\n * each with the browser, as a closed page's call fails.\n */\nconst watchLoss = Effect.fnUntraced(function* (\n context: BrowserContext,\n expiresAt: DateTime.Utc | undefined,\n clock: Clock.Clock,\n disconnected: (cause: DisconnectCause) => void,\n) {\n let lostBy: DisconnectCause | undefined;\n const lost = yield* Deferred.make<DisconnectCause>();\n const inFlight = new Set<(cause: Error) => void>();\n const gone = () => new Error(\"Target page, context or browser has been closed\");\n\n const lose = (cause: DisconnectCause) => {\n if (lostBy !== undefined) return;\n lostBy = cause;\n for (const reject of inFlight) reject(gone());\n disconnected(cause);\n Deferred.doneUnsafe(lost, Exit.succeed(cause));\n };\n\n const untilLost = <A>(reply: Promise<A>): Promise<A> => {\n if (lostBy !== undefined) {\n void reply.catch(() => undefined);\n\n return Promise.reject(gone());\n }\n\n return new Promise<A>((resolve, reject) => {\n inFlight.add(reject);\n void reply.then(resolve, reject).finally(() => inFlight.delete(reject));\n });\n };\n\n const ended = () =>\n expiresAt !== undefined &&\n clock.currentTimeMillisUnsafe() >=\n DateTime.toEpochMillis(expiresAt) - Duration.toMillis(endMargin);\n\n const onClose = () => lose(ended() ? \"session\" : \"connection\");\n\n context.on(\"close\", onClose);\n yield* Effect.addFinalizer(() => Effect.sync(() => context.off(\"close\", onClose)));\n if (context.browser()?.isConnected() === false) onClose();\n\n const native = <A>(operation: string, run: () => Promise<A>) =>\n call(operation, run, () => lostBy ?? \"page\");\n\n return { lostBy: () => lostBy, lost: Deferred.await(lost), lose, untilLost, native };\n});\n\n/**\n * What a page's own Playwright events publish, its close and crash aside, while its scope is\n * open. Dialogs are answered: alerts accepted, others dismissed. The page's own session tells its\n * documents' commits and loads.\n */\nconst listen = (\n playwright: PlaywrightPage,\n page: string,\n publish: (event: BrowserEvent) => number,\n now: () => number,\n on: { readonly close: () => void; readonly crash: () => void },\n) => {\n const dialog = (shown: Dialog) => {\n const kind = shown.type();\n const answer = kind === \"alert\" || kind === \"beforeunload\" ? \"accepted\" : \"dismissed\";\n const message = shown.message().slice(0, 500);\n\n publish(new DialogShown({ at: now(), page, kind, message, answer }));\n (answer === \"accepted\" ? shown.accept() : shown.dismiss()).catch(() => undefined);\n };\n\n return Effect.acquireRelease(\n Effect.sync(() => {\n playwright.on(\"close\", on.close);\n playwright.on(\"crash\", on.crash);\n playwright.on(\"dialog\", dialog);\n }),\n () =>\n Effect.sync(() => {\n playwright.off(\"close\", on.close);\n playwright.off(\"crash\", on.crash);\n playwright.off(\"dialog\", dialog);\n }),\n );\n};\n\n/**\n * Register each page the site opens, such as a popup, as Playwright reports it, for as long as the\n * scope is open. One that could not be tracked is published, unless it closed as it opened.\n */\nconst followOpened = Effect.fnUntraced(function* (\n context: BrowserContext,\n register: (playwright: PlaywrightPage) => Effect.Effect<Page.Page, BrowserError>,\n publish: (event: BrowserEvent) => number,\n now: () => number,\n registrations: Openings.Registrations,\n) {\n const opened = yield* Queue.unbounded<PlaywrightPage>();\n\n const onPage = (playwright: PlaywrightPage) => {\n registrations.set(playwright, Deferred.makeUnsafe<void, BrowserError>());\n Queue.offerUnsafe(opened, playwright);\n };\n\n const untracked = (playwright: PlaywrightPage) => (error: BrowserError) =>\n Effect.sync(() => {\n const url = Url.redact(playwright.url());\n\n if (!playwright.isClosed())\n publish(new PageUntracked({ at: now(), url, detail: error.message }));\n });\n\n context.on(\"page\", onPage);\n yield* Effect.addFinalizer(() => Effect.sync(() => context.off(\"page\", onPage)));\n yield* Queue.take(opened).pipe(\n Effect.flatMap((playwright) =>\n register(playwright).pipe(\n Effect.asVoid,\n Effect.onExit((exit) =>\n Effect.sync(() => {\n const done = registrations.get(playwright);\n\n if (done !== undefined) Deferred.doneUnsafe(done, exit);\n }),\n ),\n Effect.catch(untracked(playwright)),\n ),\n ),\n Effect.forever,\n Effect.forkScoped,\n );\n});\n\n/** Release something native, on the owner's clock, giving up after a second: cleanup only. */\nconst releaseNative = (clock: Clock.Clock) => (run: () => Promise<unknown>) =>\n Effect.tryPromise(run).pipe(\n Effect.interruptible,\n Effect.timeoutOrElse({ duration: Duration.seconds(1), orElse: () => Effect.void }),\n Effect.provideService(Clock.Clock, clock),\n Effect.ignore,\n );\n\n/** A page's own events among the browser's retained ones, and the openings of tabs it opened. */\nconst eventsOf = (recent: Effect.Effect<ReadonlyArray<RecordedEvent>>, page: string) =>\n Effect.map(recent, (records) =>\n records.flatMap(({ event }) =>\n (\"page\" in event && event.page === page) ||\n (event._tag === \"PageOpened\" && event.opener === page)\n ? [event]\n : [],\n ),\n );\n\n/** A script as its documents run it: everywhere, or as a block where its `match` allows. */\nconst scoped = ({ match, source }: InitScript) =>\n match === undefined ? source : `if (${String(match)}.test(location.href)) {\\n${source}\\n}`;\n\n/**\n * At most `maxPages` open pages, those a site opened included, which are never refused: an open\n * past it waits for one to close, within `wait` on the owner's clock, then fails `Limit`, or fails\n * at once under `FailFast`. An open counts until its page is tracked.\n */\nconst pageBudget = (\n maxPages: number | undefined,\n tracked: () => number,\n wait: Duration.Duration,\n clock: Clock.Clock,\n) => {\n let opening = 0;\n // Completed as a page closes or an open ends, so the opens waiting look again.\n let roomMade = Deferred.makeUnsafe<void>();\n\n const makeRoom = () => {\n Deferred.doneUnsafe(roomMade, Exit.void);\n roomMade = Deferred.makeUnsafe<void>();\n };\n\n const full = (limit: number) => tracked() + opening >= limit;\n\n const room = (limit: number) =>\n Effect.gen(function* () {\n const refused = undispatched(\"newPage\", new Limit({ maxPages: limit }));\n\n if ((yield* FailFast) && full(limit)) return yield* refused;\n yield* Effect.gen(function* () {\n while (full(limit)) yield* Deferred.await(roomMade);\n opening += 1;\n }).pipe(\n Effect.timeoutOrElse({ duration: wait, orElse: () => Effect.fail(refused) }),\n Effect.provideService(Clock.Clock, clock),\n );\n });\n\n const open = <A, E, R>(opened: Effect.Effect<A, E, R>) =>\n maxPages === undefined\n ? opened\n : Effect.uninterruptibleMask((restore) =>\n restore(room(maxPages)).pipe(\n Effect.andThen(\n restore(opened).pipe(\n Effect.ensuring(\n Effect.sync(() => {\n opening -= 1;\n makeRoom();\n }),\n ),\n ),\n ),\n ),\n );\n\n return { makeRoom, open };\n};\n\n/** A call sent now and awaited later, by whatever needs its answer. */\nconst sentNow = <A>(sent: Promise<A>) => {\n void sent.catch(() => undefined);\n\n return sent;\n};\n\n/** Close tab resources after publishing their close; a browser loss speaks for all its tabs. */\nconst closures = (\n lostBy: () => DisconnectCause | undefined,\n publish: (event: BrowserEvent) => number,\n now: () => number,\n) =>\n Effect.gen(function* () {\n const closing = yield* Queue.unbounded<{\n readonly scope: Scope.Closeable;\n readonly page: string;\n readonly cause: PageClosed[\"cause\"];\n }>();\n\n yield* Queue.take(closing).pipe(\n Effect.tap(({ page, cause }) =>\n Effect.sync(() => {\n if (lostBy() === undefined) publish(new PageClosed({ at: now(), page, cause }));\n }),\n ),\n Effect.flatMap(({ scope }) => Scope.close(scope, Exit.void)),\n Effect.forever,\n Effect.forkScoped,\n );\n\n return closing;\n });\n\n/**\n * Build the service over a context the provider owns. The provider closes the context; this only\n * tracks its pages and events, for as long as the surrounding scope is open. Each page's protocol\n * session, capture and listeners end when that page closes or when the scope does, so a closed\n * tab retains nothing and the context keeps none of them afterwards.\n */\nexport const make = Effect.fn(\"Browser.make\")(function* (\n context: BrowserContext,\n info: {\n readonly id: string;\n readonly provider: string;\n readonly expiresAt?: DateTime.Utc | undefined;\n /** Where pages' screencasts run, if not on each page's own session. */\n readonly capture?: CaptureSource | undefined;\n },\n options: Options = {},\n) {\n const clock = yield* Clock.Clock;\n const connection = yield* Identity.make;\n const now = () => BrowserClock.monotonicMillis(clock);\n const { settings, eventHistory, maxPages } = yield* settingsOf(options);\n // Measured on first need: the first capture of any page measures it, and input never waits.\n const mapping = BrowserClock.mapping(now);\n\n const timeline = Timeline.make(eventHistory);\n\n yield* Effect.addFinalizer(() => timeline.close);\n const publish = timeline.publish;\n\n if (info.expiresAt !== undefined)\n publish(new SessionEnding({ at: now(), expiresAt: info.expiresAt }));\n\n const { lostBy, lost, lose, untilLost, native } = yield* watchLoss(\n context,\n info.expiresAt,\n clock,\n (cause) => publish(new Disconnected({ at: now(), cause })),\n );\n\n const inputGate = Gate.make({\n now,\n sequence: timeline.sequence,\n closedBy: lostBy,\n lost,\n clock,\n drain: settings.navigationTimeout,\n });\n\n const registry = new Map<PlaywrightPage, Page.Page>();\n const registrations: Openings.Registrations = new WeakMap();\n const registering = yield* Semaphore.make(1);\n // The pages' scopes close after the browser is marked released, so what fails as they close\n // says why.\n const pagesScope = yield* Scope.fork(yield* Scope.Scope);\n\n const release = releaseNative(clock);\n const budget = pageBudget(maxPages, () => registry.size, settings.actionTimeout, clock);\n\n // Each tab's scope closes with the tab or the browser. A dropped connection closes every page,\n // then the context, and `Disconnected` stands for all of them: the queue hands a close to its\n // fiber in a later turn, once Playwright has reported the context's.\n const closing = yield* closures(lostBy, publish, now);\n\n const register = (playwright: PlaywrightPage) =>\n registering.withPermits(1)(\n Effect.gen(function* () {\n const known = registry.get(playwright);\n\n if (known !== undefined) return known;\n if (playwright.isClosed())\n return yield* failWith(\"newPage\", new Failed({ detail: \"the page closed as it opened\" }));\n const scope = yield* Scope.fork(pagesScope);\n\n return yield* Effect.gen(function* () {\n let crashed = false;\n const closedBy = () => lostBy() ?? (crashed ? \"crashed\" : \"page\");\n const cdp = yield* native(\"newPage\", () => context.newCDPSession(playwright));\n\n yield* Effect.addFinalizer(() => release(() => cdp.detach()));\n // The page's name, its target id, costs one round trip, which the calls that keep it\n // painting behind other tabs and report its documents share. A renderer busy with its\n // first script answers those two late, so what needs them waits, and registering does not.\n const send: typeof cdp.send = (method, params) => untilLost(cdp.send(method, params));\n const focusing = sentNow(send(\"Emulation.setFocusEmulationEnabled\", { enabled: true }));\n const paging = sentNow(send(\"Page.enable\"));\n const { targetInfo } = yield* native(\"newPage\", () => send(\"Target.getTargetInfo\"));\n const id = targetInfo.targetId;\n\n const page = yield* PageImpl.make({\n id,\n session: info.id,\n connection,\n url: targetInfo.url,\n playwright,\n cdp,\n untilLost,\n settings,\n inputGate,\n clock,\n mapping,\n publish,\n recentEvents: eventsOf(timeline.recent, id),\n openings: yield* Openings.make(playwright, cdp, registrations, closedBy),\n focused: call(\"focus\", () => focusing, closedBy).pipe(Effect.asVoid),\n paging: (operation) => call(operation, () => paging, closedBy).pipe(Effect.asVoid),\n closedBy,\n capture: info.capture,\n });\n\n const close = () => {\n if (registry.get(playwright) !== page) return;\n registry.delete(playwright);\n budget.makeRoom();\n Queue.offerUnsafe(closing, { scope, page: id, cause: crashed ? \"crashed\" : \"page\" });\n };\n\n // Playwright drives a crashed page no more and its calls never return, so it is closed:\n // they fail at once, `Closed` because it crashed.\n const crash = () => {\n crashed = true;\n void playwright.close().catch(() => undefined);\n };\n\n registry.set(playwright, page);\n publish(\n new PageOpened({\n at: now(),\n page: id,\n url: Url.redact(targetInfo.url),\n opener: targetInfo.openerId,\n }),\n );\n yield* listen(playwright, id, publish, now, { close, crash });\n if (playwright.isClosed()) close();\n\n return page;\n }).pipe(\n Scope.provide(scope),\n Effect.onError(() => Scope.close(scope, Exit.void)),\n );\n }),\n );\n\n // Playwright registers its init scripts as it sets up each page, before a popup's first document\n // runs, and they cost no call per document.\n for (const script of options.initScripts ?? [])\n yield* native(\"initScripts\", () => context.addInitScript({ content: scoped(script) }));\n yield* followOpened(context, register, publish, now, registrations);\n for (const existing of context.pages()) yield* register(existing);\n\n const pages = Effect.sync(() => [...registry.values()]);\n\n const newPage = Effect.fn(\"Browser.newPage\")(function* (url?: string) {\n const page = yield* budget.open(\n native(\"newPage\", () => context.newPage()).pipe(\n Effect.flatMap((playwright) =>\n register(playwright).pipe(Effect.onError(() => release(() => playwright.close()))),\n ),\n ),\n );\n\n // A rejected or interrupted navigation must not leave the newly allocated blank tab behind.\n if (url !== undefined)\n yield* page.goto(url).pipe(Effect.onError(() => page.close.pipe(Effect.ignore)));\n\n return page;\n });\n\n // Added last, so it runs first as the owner's scope closes.\n yield* Effect.addFinalizer(() => Effect.sync(() => lose(\"released\")));\n\n const service: Service = {\n id: info.id,\n connection,\n provider: info.provider,\n expiresAt: info.expiresAt,\n now: Effect.sync(now),\n suspend: (options = {}) =>\n Effect.map(inputGate.suspend(options.drain), (held) => new Suspension(held)),\n context,\n pages,\n page: (id) =>\n Effect.map(pages, (open) => Option.fromNullishOr(open.find((page) => page.id === id))),\n firstPage: pages.pipe(\n Effect.map((open) => Option.fromNullishOr(open[0])),\n Effect.flatMap(Option.match({ onNone: () => newPage(), onSome: Effect.succeed })),\n ),\n newPage,\n disconnected: lost,\n events: (eventOptions = {}) => timeline.stream(eventOptions.after),\n recentEvents: timeline.recent.pipe(\n Effect.map((records) => records.map((record) => record.event)),\n ),\n };\n\n return Browser.of(service);\n});\n"],"mappings":"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"}
|
package/dist/Browser.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as BrowserError } from "./BrowserError-Coy7EW1N.mjs";
|
|
2
2
|
import { c as DisconnectCause, i as BrowserEvent, v as RecordedEvent } from "./BrowserEvent-dq6FRT8w.mjs";
|
|
3
|
-
import { c as InputGuard, d as Page_d_exports, u as Page$1 } from "./Page-
|
|
3
|
+
import { c as InputGuard, d as Page_d_exports, u as Page$1 } from "./Page-ku6j5t-v.mjs";
|
|
4
4
|
import { Context, DateTime, Duration, Effect, Option, Schema, Scope, Stream } from "effect";
|
|
5
5
|
import { BrowserContext } from "playwright-core";
|
|
6
6
|
declare namespace Browser_d_exports {
|
package/dist/Browser.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as make, r as Suspension, t as Browser } from "./Browser-
|
|
1
|
+
import { i as make, r as Suspension, t as Browser } from "./Browser-BwCldIff.mjs";
|
|
2
2
|
export { Browser, Suspension, make };
|
package/dist/Cdp.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { Failed } from "./BrowserError.mjs";
|
|
3
|
-
import { i as make, t as Browser } from "./Browser-
|
|
4
|
-
import {
|
|
3
|
+
import { i as make, t as Browser } from "./Browser-BwCldIff.mjs";
|
|
4
|
+
import { c as undispatched, o as reasonOf } from "./context-w3NJPRLo.mjs";
|
|
5
5
|
import { r as quoted } from "./url-Cd04Okid.mjs";
|
|
6
6
|
import { Effect, Layer, Redacted } from "effect";
|
|
7
7
|
import { chromium } from "playwright-core";
|
package/dist/Chromium.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { Failed } from "./BrowserError.mjs";
|
|
3
|
-
import { i as make, t as Browser } from "./Browser-
|
|
4
|
-
import {
|
|
3
|
+
import { i as make, t as Browser } from "./Browser-BwCldIff.mjs";
|
|
4
|
+
import { c as undispatched, o as reasonOf } from "./context-w3NJPRLo.mjs";
|
|
5
5
|
import { Effect, Layer } from "effect";
|
|
6
6
|
import { chromium } from "playwright-core";
|
|
7
7
|
//#region src/Chromium.ts
|
package/dist/Expect.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as BrowserError } from "./BrowserError-Coy7EW1N.mjs";
|
|
2
|
-
import { a as FindQuery, u as Page } from "./Page-
|
|
2
|
+
import { a as FindQuery, u as Page } from "./Page-ku6j5t-v.mjs";
|
|
3
3
|
import { Duration, Effect } from "effect";
|
|
4
4
|
declare namespace Expect_d_exports {
|
|
5
5
|
export { Attempt, Expectation, Options, Outcome, appeared, attempt, changed, gone, navigated };
|
package/dist/Expect.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { InvalidRequest } from "./BrowserError.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { t as internalsOf } from "./page-
|
|
3
|
+
import { c as undispatched } from "./context-w3NJPRLo.mjs";
|
|
4
|
+
import { t as internalsOf } from "./page-BKwfF6z-.mjs";
|
|
5
5
|
import { Cause, Duration, Effect, Exit, Option, Schedule } from "effect";
|
|
6
6
|
//#region src/Expect.ts
|
|
7
7
|
/**
|
package/dist/Moment.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as Account, F as account, I as capture, L as toPrompt, M as Moment, P as Window, j as CaptureOptions } from "./Page-
|
|
1
|
+
import { A as Account, F as account, I as capture, L as toPrompt, M as Moment, P as Window, j as CaptureOptions } from "./Page-ku6j5t-v.mjs";
|
|
2
2
|
export { Account, CaptureOptions, Moment, Window, account, capture, toPrompt };
|
package/dist/Moment.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { BrowserEvent } from "./BrowserEvent.mjs";
|
|
3
|
-
import { BrowserError
|
|
4
|
-
import { s as
|
|
3
|
+
import { BrowserError } from "./BrowserError.mjs";
|
|
4
|
+
import { s as refuse } from "./context-w3NJPRLo.mjs";
|
|
5
5
|
import { Frame } from "./Frame.mjs";
|
|
6
6
|
import { Snapshot } from "./Snapshot.mjs";
|
|
7
7
|
import { c as quoted, l as where, o as describe, r as Changes, s as named } from "./Change-DNvztNLu.mjs";
|
|
@@ -83,7 +83,7 @@ const pictureOf = Effect.fnUntraced(function* (page) {
|
|
|
83
83
|
});
|
|
84
84
|
const capture = Effect.fn("Moment.capture")(function* (page, options = {}) {
|
|
85
85
|
const count = options.frames ?? 2;
|
|
86
|
-
if (!Number.isSafeInteger(count) || count < 1) return yield*
|
|
86
|
+
if (!Number.isSafeInteger(count) || count < 1) return yield* refuse("moment", "frames must be a positive safe integer");
|
|
87
87
|
const outline = options.snapshot ?? false;
|
|
88
88
|
const { pictured, outlined } = yield* Effect.all({
|
|
89
89
|
pictured: Effect.result(pictureOf(page)).pipe(Effect.flatMap((picture) => Effect.map(page.window({
|
package/dist/Moment.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Moment.mjs","names":[],"sources":["../src/Moment.ts"],"sourcesContent":["/**\n * What a page showed, and what changed on it, over a window of time.\n *\n * A page's timeline has three tracks on its browser's host clock: its events, what visibly changed\n * on it (`Change`), and its screencast frames. A `Window` holds the three from `since` to `until`,\n * and says why a part it could not read is missing rather than fail. `Page.window` takes one, which\n * can end in the past, at a frame a delayed consumer airs late, so that a line written now tells\n * what its viewers will see. Its `account` says what was so at its end: how long the page had been\n * still, which of its changes were still under way, and which had settled.\n *\n * A `Moment` is a window that ends at a picture of the page now: `capture` takes the picture, then\n * the window up to it, and on request the page's outline. `toPrompt` turns a moment into one user\n * message for any `effect/ai` call: a structured answer from `LanguageModel.generateObject`, a\n * caption from `generateText`, or one turn of a `Chat` that follows moment after moment. It leads\n * with what changed, news and what settled before what was still changing, as its account tells\n * them apart, and names an action as what a change followed; as a step where changes followed it\n * but none names it, or where its effect is drawn rather than written, as on a canvas, which only\n * the screenshots show; and claims nothing of what changed where the record did not see, or of a\n * part it could not read, which it names with why.\n *\n * Frames come from a running screencast, as far back as the browser's `frameHistory` keeps them.\n * A moment's picture is the newest frame if it was painted after the page's latest input and\n * completed action, at most 250 ms ago, else a new screenshot timed by its capture.\n *\n * @since 0.3.0\n */\nimport { Duration, Effect, Option, Result, Schema } from \"effect\";\nimport { Prompt } from \"effect/ai\";\n\nimport { BrowserError, InvalidRequest } from \"./BrowserError.ts\";\nimport { type Action, BrowserEvent } from \"./BrowserEvent.ts\";\nimport { type Change, Changes } from \"./Change.ts\";\nimport { Frame } from \"./Frame.ts\";\nimport { undispatched } from \"./internal/page/context.ts\";\nimport { describe, named, quoted, where } from \"./internal/timeline/words.ts\";\nimport type * as Page from \"./Page.ts\";\nimport { Snapshot, type SnapshotOptions } from \"./Snapshot.ts\";\n\n/** A page's events, changes and frames over one window of its browser's host clock. */\nexport class Window extends Schema.Class<Window>(\"effect-browser/Window\")({\n page: Schema.String,\n /** Where the window starts, in host monotonic milliseconds on the owning browser’s clock. */\n since: Schema.Finite,\n /** Where it ends, never after it was taken. */\n until: Schema.Finite,\n /** The page's events after `since`, up to `until`, oldest first, without the input presentation track. */\n events: Schema.Array(BrowserEvent),\n /**\n * What visibly changed after `since`, up to `until`; absent where `missing` says why. A page's\n * first window starts its record, so the record sees none of it.\n */\n changes: Schema.optional(Changes),\n /** Screencast frames painted from `since` to `until`, oldest first, as far back as kept. */\n frames: Schema.Array(Frame),\n /**\n * Why each part that could not be read is missing: the read of its changes, by whatever\n * operation failed there, or a moment's picture (`frame`) or outline (`snapshot`).\n */\n missing: Schema.Array(BrowserError),\n}) {}\n\n/**\n * A window that ends at a picture of the page, its last frame, unless `missing` says why it has\n * none. Its frames are a few, spread over the window, so that it still begins where it starts.\n */\nexport class Moment extends Window.extend<Moment>(\"effect-browser/Moment\")({\n /** The page's outline at the end of the window, when the capture asked for it. */\n snapshot: Schema.optional(Snapshot),\n}) {}\n\nexport interface CaptureOptions {\n /**\n * Where the window starts, as for `Page.window`: a previous window or moment, so that consecutive\n * ones neither repeat nor miss an event or a change, or a `Duration` back from the picture.\n * Defaults to 5 seconds.\n */\n readonly since?: Page.WindowOptions[\"since\"] | undefined;\n /** Frames to keep, at least 1, spread over the window and ending with the picture. Defaults to 2. */\n readonly frames?: number | undefined;\n /**\n * Whether to take the page's outline at the end, or its options; `true` means 4,000 characters.\n * Defaults to `false`: the frames and the timeline carry most moments, while an outline costs a\n * round trip to the page and can double a moment's tokens.\n */\n readonly snapshot?: SnapshotOptions | boolean | undefined;\n /** Show what fields hold in the moment's changes; a secret field still reads `••••`. */\n readonly unmask?: boolean | undefined;\n}\n\n/** Pick `count` frames spread evenly over `frames`, always including the last. */\nconst spread = (frames: ReadonlyArray<Frame>, count: number): ReadonlyArray<Frame> => {\n if (frames.length <= count) return frames;\n if (count <= 1) return frames.slice(-1);\n const step = (frames.length - 1) / (count - 1);\n\n return Array.from({ length: count }, (_, index) => frames[Math.round(index * step)]).filter(\n (frame): frame is Frame => frame !== undefined,\n );\n};\n\n// An action ends after its navigation settles, which can follow the last paint. A fresh picture\n// keeps that completed action inside the moment without moving events between adjacent windows.\nconst pictureOf = Effect.fnUntraced(function* (page: Page.Page) {\n const frame = yield* page.frame({ after: \"input\" });\n const events = yield* page.recentEvents;\n\n return events.some((event) => event._tag === \"Action\" && event.at > frame.hostTime)\n ? yield* page.frame({ maxAge: 0 })\n : frame;\n});\n\nexport const capture = Effect.fn(\"Moment.capture\")(function* (\n page: Page.Page,\n options: CaptureOptions = {},\n) {\n const count = options.frames ?? 2;\n\n if (!Number.isSafeInteger(count) || count < 1)\n return yield* undispatched(\n \"moment\",\n new InvalidRequest({ detail: \"frames must be a positive safe integer\" }),\n );\n const outline = options.snapshot ?? false;\n\n // The picture comes first, at no call with a running screencast, and the window ends at its\n // paint, so its changes hold nothing it does not show; without one, the window ends now. The\n // outline is taken alongside. What cannot be read is missing from the moment, not its end.\n const { pictured, outlined } = yield* Effect.all(\n {\n pictured: Effect.result(pictureOf(page)).pipe(\n Effect.flatMap((picture) =>\n Effect.map(\n page.window({\n since: options.since ?? Duration.seconds(5),\n until: Result.getOrUndefined(picture),\n unmask: options.unmask,\n }),\n (window) => ({ window, picture }),\n ),\n ),\n ),\n outlined: Effect.result(\n outline === false\n ? Effect.void\n : page.snapshot({ maxChars: 4000, ...(outline === true ? {} : outline) }),\n ),\n },\n { concurrency: 2 },\n );\n\n const { window, picture } = pictured;\n const shown = Result.getOrUndefined(picture);\n\n return new Moment({\n ...window,\n frames: spread(\n shown === undefined\n ? window.frames\n : [...window.frames.filter((frame) => frame !== shown), shown],\n count,\n ),\n snapshot: Result.getOrUndefined(outlined) ?? undefined,\n missing: [\n ...window.missing,\n ...Option.toArray(Result.getFailure(picture)),\n ...Option.toArray(Result.getFailure(outlined)),\n ],\n });\n});\n\n/** A window's record of changes, if it saw any of the window: a page's first has none. */\nconst recordOf = ({ changes }: Window) =>\n changes !== undefined && changes.from < changes.until ? changes : undefined;\n\n/** What a window says of its page at its end: what was still in flux, and what had settled. */\nexport interface Account {\n /**\n * How long, in milliseconds, the page had been still at the end: since the last change in view\n * its record shows, or the last paint its screencast frames show, or else since the window, or\n * its record, began. Undefined where neither could tell, with no record of the window and no\n * painted frame: a screenshot shows the page, not when it last changed. Frames show paint only\n * while a capture runs, and the record does not see a canvas, so a canvas that keeps drawing\n * with no capture running reads as still.\n */\n readonly stillFor: number | undefined;\n /**\n * The changes still under way at the end: what kept changing, more than once in the window or\n * already before it, and changed again within twice its own pace before the end.\n */\n readonly changing: ReadonlyArray<Change>;\n /** Every other change, which shows what it settled at. */\n readonly settled: ReadonlyArray<Change>;\n}\n\n/** Whether a change was still under way at `until`, by its own pace. */\nconst underWay = (change: Change, until: number) => {\n const pace =\n change.count > 1\n ? (change.at - change.startedAt) / (change.count - 1)\n : change.earlier === undefined\n ? undefined\n : change.startedAt - change.earlier;\n\n return pace !== undefined && until - change.at < 2 * pace;\n};\n\n/**\n * An account of the window's page at its end: how long it had been still, and which of its\n * changes were still under way and which had settled. A window whose record saw none of it has\n * neither.\n */\nexport const account = (window: Window): Account => {\n const record = recordOf(window);\n const changes = record?.changes ?? [];\n\n const stirred = [\n ...changes.flatMap((change) => (change.kind === \"title\" ? [] : [change.at])),\n ...window.frames.flatMap((frame) =>\n frame.timing._tag === \"BrowserPaint\" ? [frame.hostTime] : [],\n ),\n ];\n\n return {\n stillFor:\n record === undefined && stirred.length === 0\n ? undefined\n : window.until - Math.max(window.since, record?.from ?? window.since, ...stirred),\n changing: changes.filter((change) => underWay(change, window.until)),\n settled: changes.filter((change) => !underWay(change, window.until)),\n };\n};\n\nconst seconds = (moment: Moment, at: number) => `${((at - moment.until) / 1000).toFixed(1)}s`;\n\nconst pointOf = (x: number | undefined, y: number | undefined) =>\n x === undefined || y === undefined ? undefined : `(${Math.round(x)}, ${Math.round(y)})`;\n\n/**\n * What an action acted on. Without a subject the action failed before finding it, and a ref it was\n * given is left out: refs are reused, so the page's outline may give it to something else by now.\n */\nconst acted = (event: Action): string => {\n const point = pointOf(event.x, event.y);\n\n if (event.subject === undefined)\n return event.target === undefined || /^e\\d+$|\"e\\d+\"/.test(event.target)\n ? (point ?? \"\")\n : event.target;\n // A drag's point is where it ended.\n if (event.to !== undefined)\n return `${named(event.subject, undefined)} to ${named(event.to, point)}`;\n\n return named(event.subject, point);\n};\n\n/**\n * An action as a step: `click button \"Pay\"`. A failed one says only that: its error is advice for\n * the caller that acted, which may name a ref, not a fact about the page.\n */\nconst step = (event: Action): string => {\n const target = acted(event);\n const text = event.text === undefined ? \"\" : JSON.stringify(event.text);\n\n const what =\n event.name === \"type\" && target !== \"\"\n ? `${text} into ${target}`\n : event.name === \"select\" && target !== \"\"\n ? `${text} in ${target}`\n : `${target} ${text}`;\n\n return `${event.name} ${what}${event.ok ? \"\" : \" (failed)\"}`.replace(/\\s+/g, \" \").trim();\n};\n\n/** What is drawn rather than written, whose changes only the screenshots show. */\nconst drawn = new Set([\"canvas\", \"iframe\", \"video\", \"embed\", \"object\", \"svg\"]);\n\nconst onDrawn = (event: Action) =>\n event.ok && event.subject !== undefined && drawn.has(event.subject.role ?? event.subject.tag);\n\ninterface Line {\n readonly at: number;\n readonly rank: number;\n readonly text: string;\n}\n\n/** At most this many lines of what happened; the least notable are counted, not listed. */\nconst maxLines = 24;\n\n/**\n * The changes as lines, news first, and the actions they name; cells of one column that changed\n * together as one line. What kept changing says whether it still was at the moment, by its account.\n */\nconst changed = (moment: Moment, record: Changes) => {\n const actions = moment.events.filter((event): event is Action => event._tag === \"Action\");\n const named = new Set<Action>();\n const changing = new Set(account(moment).changing);\n\n const state = (change: Change) =>\n changing.has(change)\n ? \", still changing at the moment\"\n : change.count > 1 || change.earlier !== undefined\n ? `, settled since ${seconds(moment, change.at)}`\n : \"\";\n\n // The action whose input a change followed: one that ran while the input arrived, give or take\n // the clock's mapping, so input the library did not send names no action.\n const cause = (change: Change) => {\n const input = change.cause;\n\n const action =\n input === undefined\n ? undefined\n : actions.findLast((event) => event.startedAt <= input + 100 && event.at >= input - 100);\n\n if (action === undefined) return \"\";\n named.add(action);\n\n return `, after ${step(action)}`;\n };\n\n const columns = Map.groupBy(\n record.changes.filter(\n (change) => change.kind === \"text\" && change.subject.context.column !== undefined,\n ),\n ({ subject: { context } }) => JSON.stringify([context.heading, context.column]),\n );\n\n const lines: Array<Line> = [];\n const collapsed = new Set<Change>();\n\n for (const [first, ...cells] of columns.values())\n if (first !== undefined && cells.length >= 2) {\n const still = [first, ...cells].filter((cell) => changing.has(cell)).length;\n\n for (const cell of [first, ...cells]) collapsed.add(cell);\n lines.push({\n at: first.startedAt,\n rank: still > 0 ? 3 : 2,\n text: `${cells.length + 1} cells in column ${quoted(first.subject.context.column)}${where({ heading: first.subject.context.heading })} changed, such as ${describe(first, true)}${still > 0 ? `, ${still} still changing at the moment` : \"\"}`,\n });\n }\n for (const change of record.changes)\n if (!collapsed.has(change))\n lines.push({\n at: change.startedAt,\n rank: changing.has(change) ? 3 : 2,\n text: describe(change) + cause(change) + state(change),\n });\n\n return { lines, named };\n};\n\n/** What a part a moment could not read was, by the operation that failed: a window's one read is its changes. */\nconst parts = new Map([\n [\"frame\", \"A picture of the moment\"],\n [\"snapshot\", \"The page's outline\"],\n]);\n\n/** The moment's changes and events as lines, most notable first when its changes are recorded. */\nconst happened = (moment: Moment): ReadonlyArray<string> => {\n const record = recordOf(moment);\n\n const { lines, named } =\n record === undefined\n ? { lines: new Array<Line>(), named: new Set<Action>() }\n : changed(moment, record);\n\n // Whether anything but a field's own edit changed after an action began.\n const followed = (event: Action) =>\n record?.changes.some((change) => change.kind !== \"value\" && change.at > event.startedAt) ===\n true;\n\n // With a record, an action is told as a step where changes followed it and none names it, so a\n // click whose effect a busy page leaves uncredited is not lost; where its effect is drawn; or\n // where it started before the record began, as on the document a click opened. An attempt that\n // nothing followed, a failed one, a hover and a scroll are left out.\n const told = (event: Action) =>\n !(event.ok && [\"navigate\", \"back\", \"reload\"].includes(event.name)) &&\n (record === undefined ||\n event.startedAt <= record.from ||\n (event.ok &&\n event.name !== \"scroll\" &&\n (onDrawn(event) || (event.name !== \"hover\" && !named.has(event) && followed(event)))));\n\n for (const event of moment.events)\n if (event._tag === \"Action\" && event.page === moment.page && told(event))\n lines.push({ at: event.at, rank: 4, text: step(event) });\n else if (event._tag === \"Navigated\")\n lines.push({\n at: event.at,\n rank: 0,\n text: `${event.sameDocument ? \"moved within the page\" : \"navigated\"} to ${event.url}`,\n });\n else if (event._tag === \"PageOpened\")\n lines.push({ at: event.at, rank: 0, text: `a tab opened at ${event.url}` });\n else if (event._tag === \"PageClosed\")\n lines.push({\n at: event.at,\n rank: 0,\n text: `the tab ${event.cause === \"crashed\" ? \"crashed\" : \"closed\"}`,\n });\n else if (event._tag === \"DialogShown\")\n lines.push({\n at: event.at,\n rank: 1,\n text: `a dialog (${event.kind}) said ${JSON.stringify(event.message)}`,\n });\n\n const ordered = lines.toSorted((left, right) =>\n record === undefined ? left.at - right.at : left.rank - right.rank || left.at - right.at,\n );\n\n const kept = ordered.slice(0, maxLines);\n const drawing = moment.events.some((event) => event._tag === \"Action\" && onDrawn(event));\n const begins = record === undefined ? moment.since : Math.max(moment.since, record.from);\n const unread = moment.missing.some((error) => !parts.has(error.operation));\n\n return [\n ...kept.map((line) => `${seconds(moment, line.at)} ${line.text}`),\n ...(ordered.length > maxLines ? [`…and ${ordered.length - maxLines} less notable`] : []),\n ...(record === undefined\n ? unread\n ? []\n : [\"What changed on the page was not recorded.\"]\n : record.changes.length > 0\n ? []\n : [\n `No text in view changed${begins > moment.since ? ` after ${seconds(moment, begins)}` : \"\"}${drawing ? \"; what is drawn, such as a canvas, shows only in the screenshots\" : \"\"}.`,\n ]),\n ...(record !== undefined && record.dropped > 0\n ? [\n `The page changed too much to tell it all: at least ${record.dropped} changes are not told.`,\n ]\n : []),\n ...(begins > moment.since\n ? [`Changes before ${seconds(moment, begins)} are not all known.`]\n : []),\n ...moment.missing.map(\n (error) =>\n `${parts.get(error.operation) ?? \"What changed on the page\"} could not be read: ${error.reason.message}.`,\n ),\n ];\n};\n\n/**\n * The moment as one user message: the page's outline when the moment has one, what changed, most\n * notable first, what kept changing told as still changing at the moment or settled since when, by\n * its account, with the actions that the changes followed, that changes followed though none\n * names them, or that drew what only the screenshots show, what could not be read and why, and its\n * frames captioned with their times, the last one \"the moment\" where it is the picture at its end.\n * Give a model its task with `Prompt.setSystem`, and add what the caller knows about the page as\n * more text.\n */\nexport const toPrompt = (moment: Moment): Prompt.Prompt => {\n const count = moment.frames.length;\n const last = count - 1;\n const pictured = moment.frames.at(-1)?.hostTime === moment.until;\n\n const following =\n count === 1 ? \"One screenshot follows\" : `${count} screenshots follow, oldest first`;\n\n return Prompt.fromMessages([\n Prompt.makeMessage(\"user\", {\n content: [\n Prompt.makePart(\"text\", {\n text: [\n \"One moment of a browser session. Rely only on what this material shows, and prefer concrete details: numbers, names, colours, positions and motion.\",\n \"\",\n ...(moment.snapshot === undefined ? [] : [moment.snapshot.rendered, \"\"]),\n `${recordOf(moment) === undefined ? \"What happened\" : \"What changed, most notable first\"} (seconds before the moment, over ${((moment.until - moment.since) / 1000).toFixed(1)}s):`,\n ...happened(moment),\n ...(count === 0\n ? []\n : [\n \"\",\n `${following}${pictured ? (count === 1 ? \": the moment itself.\" : \"; the last one is the moment itself.\") : \".\"}`,\n ]),\n ].join(\"\\n\"),\n }),\n ...moment.frames.flatMap((frame, index) => [\n Prompt.makePart(\"text\", {\n text:\n index === last && pictured ? \"The moment:\" : `${seconds(moment, frame.hostTime)}:`,\n }),\n Prompt.makePart(\"file\", { mediaType: \"image/jpeg\", data: frame.data }),\n ]),\n ],\n }),\n ]);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Moment.mjs","names":[],"sources":["../src/Moment.ts"],"sourcesContent":["/**\n * What a page showed, and what changed on it, over a window of time.\n *\n * A page's timeline has three tracks on its browser's host clock: its events, what visibly changed\n * on it (`Change`), and its screencast frames. A `Window` holds the three from `since` to `until`,\n * and says why a part it could not read is missing rather than fail. `Page.window` takes one, which\n * can end in the past, at a frame a delayed consumer airs late, so that a line written now tells\n * what its viewers will see. Its `account` says what was so at its end: how long the page had been\n * still, which of its changes were still under way, and which had settled.\n *\n * A `Moment` is a window that ends at a picture of the page now: `capture` takes the picture, then\n * the window up to it, and on request the page's outline. `toPrompt` turns a moment into one user\n * message for any `effect/ai` call: a structured answer from `LanguageModel.generateObject`, a\n * caption from `generateText`, or one turn of a `Chat` that follows moment after moment. It leads\n * with what changed, news and what settled before what was still changing, as its account tells\n * them apart, and names an action as what a change followed; as a step where changes followed it\n * but none names it, or where its effect is drawn rather than written, as on a canvas, which only\n * the screenshots show; and claims nothing of what changed where the record did not see, or of a\n * part it could not read, which it names with why.\n *\n * Frames come from a running screencast, as far back as the browser's `frameHistory` keeps them.\n * A moment's picture is the newest frame if it was painted after the page's latest input and\n * completed action, at most 250 ms ago, else a new screenshot timed by its capture.\n *\n * @since 0.3.0\n */\nimport { Duration, Effect, Option, Result, Schema } from \"effect\";\nimport { Prompt } from \"effect/ai\";\n\nimport { BrowserError } from \"./BrowserError.ts\";\nimport { type Action, BrowserEvent } from \"./BrowserEvent.ts\";\nimport { type Change, Changes } from \"./Change.ts\";\nimport { Frame } from \"./Frame.ts\";\nimport { refuse } from \"./internal/page/context.ts\";\nimport { describe, named, quoted, where } from \"./internal/timeline/words.ts\";\nimport type * as Page from \"./Page.ts\";\nimport { Snapshot, type SnapshotOptions } from \"./Snapshot.ts\";\n\n/** A page's events, changes and frames over one window of its browser's host clock. */\nexport class Window extends Schema.Class<Window>(\"effect-browser/Window\")({\n page: Schema.String,\n /** Where the window starts, in host monotonic milliseconds on the owning browser’s clock. */\n since: Schema.Finite,\n /** Where it ends, never after it was taken. */\n until: Schema.Finite,\n /** The page's events after `since`, up to `until`, oldest first, without the input presentation track. */\n events: Schema.Array(BrowserEvent),\n /**\n * What visibly changed after `since`, up to `until`; absent where `missing` says why. A page's\n * first window starts its record, so the record sees none of it.\n */\n changes: Schema.optional(Changes),\n /** Screencast frames painted from `since` to `until`, oldest first, as far back as kept. */\n frames: Schema.Array(Frame),\n /**\n * Why each part that could not be read is missing: the read of its changes, by whatever\n * operation failed there, or a moment's picture (`frame`) or outline (`snapshot`).\n */\n missing: Schema.Array(BrowserError),\n}) {}\n\n/**\n * A window that ends at a picture of the page, its last frame, unless `missing` says why it has\n * none. Its frames are a few, spread over the window, so that it still begins where it starts.\n */\nexport class Moment extends Window.extend<Moment>(\"effect-browser/Moment\")({\n /** The page's outline at the end of the window, when the capture asked for it. */\n snapshot: Schema.optional(Snapshot),\n}) {}\n\nexport interface CaptureOptions {\n /**\n * Where the window starts, as for `Page.window`: a previous window or moment, so that consecutive\n * ones neither repeat nor miss an event or a change, or a `Duration` back from the picture.\n * Defaults to 5 seconds.\n */\n readonly since?: Page.WindowOptions[\"since\"] | undefined;\n /** Frames to keep, at least 1, spread over the window and ending with the picture. Defaults to 2. */\n readonly frames?: number | undefined;\n /**\n * Whether to take the page's outline at the end, or its options; `true` means 4,000 characters.\n * Defaults to `false`: the frames and the timeline carry most moments, while an outline costs a\n * round trip to the page and can double a moment's tokens.\n */\n readonly snapshot?: SnapshotOptions | boolean | undefined;\n /** Show what fields hold in the moment's changes; a secret field still reads `••••`. */\n readonly unmask?: boolean | undefined;\n}\n\n/** Pick `count` frames spread evenly over `frames`, always including the last. */\nconst spread = (frames: ReadonlyArray<Frame>, count: number): ReadonlyArray<Frame> => {\n if (frames.length <= count) return frames;\n if (count <= 1) return frames.slice(-1);\n const step = (frames.length - 1) / (count - 1);\n\n return Array.from({ length: count }, (_, index) => frames[Math.round(index * step)]).filter(\n (frame): frame is Frame => frame !== undefined,\n );\n};\n\n// An action ends after its navigation settles, which can follow the last paint. A fresh picture\n// keeps that completed action inside the moment without moving events between adjacent windows.\nconst pictureOf = Effect.fnUntraced(function* (page: Page.Page) {\n const frame = yield* page.frame({ after: \"input\" });\n const events = yield* page.recentEvents;\n\n return events.some((event) => event._tag === \"Action\" && event.at > frame.hostTime)\n ? yield* page.frame({ maxAge: 0 })\n : frame;\n});\n\nexport const capture = Effect.fn(\"Moment.capture\")(function* (\n page: Page.Page,\n options: CaptureOptions = {},\n) {\n const count = options.frames ?? 2;\n\n if (!Number.isSafeInteger(count) || count < 1)\n return yield* refuse(\"moment\", \"frames must be a positive safe integer\");\n const outline = options.snapshot ?? false;\n\n // The picture comes first, at no call with a running screencast, and the window ends at its\n // paint, so its changes hold nothing it does not show; without one, the window ends now. The\n // outline is taken alongside. What cannot be read is missing from the moment, not its end.\n const { pictured, outlined } = yield* Effect.all(\n {\n pictured: Effect.result(pictureOf(page)).pipe(\n Effect.flatMap((picture) =>\n Effect.map(\n page.window({\n since: options.since ?? Duration.seconds(5),\n until: Result.getOrUndefined(picture),\n unmask: options.unmask,\n }),\n (window) => ({ window, picture }),\n ),\n ),\n ),\n outlined: Effect.result(\n outline === false\n ? Effect.void\n : page.snapshot({ maxChars: 4000, ...(outline === true ? {} : outline) }),\n ),\n },\n { concurrency: 2 },\n );\n\n const { window, picture } = pictured;\n const shown = Result.getOrUndefined(picture);\n\n return new Moment({\n ...window,\n frames: spread(\n shown === undefined\n ? window.frames\n : [...window.frames.filter((frame) => frame !== shown), shown],\n count,\n ),\n snapshot: Result.getOrUndefined(outlined) ?? undefined,\n missing: [\n ...window.missing,\n ...Option.toArray(Result.getFailure(picture)),\n ...Option.toArray(Result.getFailure(outlined)),\n ],\n });\n});\n\n/** A window's record of changes, if it saw any of the window: a page's first has none. */\nconst recordOf = ({ changes }: Window) =>\n changes !== undefined && changes.from < changes.until ? changes : undefined;\n\n/** What a window says of its page at its end: what was still in flux, and what had settled. */\nexport interface Account {\n /**\n * How long, in milliseconds, the page had been still at the end: since the last change in view\n * its record shows, or the last paint its screencast frames show, or else since the window, or\n * its record, began. Undefined where neither could tell, with no record of the window and no\n * painted frame: a screenshot shows the page, not when it last changed. Frames show paint only\n * while a capture runs, and the record does not see a canvas, so a canvas that keeps drawing\n * with no capture running reads as still.\n */\n readonly stillFor: number | undefined;\n /**\n * The changes still under way at the end: what kept changing, more than once in the window or\n * already before it, and changed again within twice its own pace before the end.\n */\n readonly changing: ReadonlyArray<Change>;\n /** Every other change, which shows what it settled at. */\n readonly settled: ReadonlyArray<Change>;\n}\n\n/** Whether a change was still under way at `until`, by its own pace. */\nconst underWay = (change: Change, until: number) => {\n const pace =\n change.count > 1\n ? (change.at - change.startedAt) / (change.count - 1)\n : change.earlier === undefined\n ? undefined\n : change.startedAt - change.earlier;\n\n return pace !== undefined && until - change.at < 2 * pace;\n};\n\n/**\n * An account of the window's page at its end: how long it had been still, and which of its\n * changes were still under way and which had settled. A window whose record saw none of it has\n * neither.\n */\nexport const account = (window: Window): Account => {\n const record = recordOf(window);\n const changes = record?.changes ?? [];\n\n const stirred = [\n ...changes.flatMap((change) => (change.kind === \"title\" ? [] : [change.at])),\n ...window.frames.flatMap((frame) =>\n frame.timing._tag === \"BrowserPaint\" ? [frame.hostTime] : [],\n ),\n ];\n\n return {\n stillFor:\n record === undefined && stirred.length === 0\n ? undefined\n : window.until - Math.max(window.since, record?.from ?? window.since, ...stirred),\n changing: changes.filter((change) => underWay(change, window.until)),\n settled: changes.filter((change) => !underWay(change, window.until)),\n };\n};\n\nconst seconds = (moment: Moment, at: number) => `${((at - moment.until) / 1000).toFixed(1)}s`;\n\nconst pointOf = (x: number | undefined, y: number | undefined) =>\n x === undefined || y === undefined ? undefined : `(${Math.round(x)}, ${Math.round(y)})`;\n\n/**\n * What an action acted on. Without a subject the action failed before finding it, and a ref it was\n * given is left out: refs are reused, so the page's outline may give it to something else by now.\n */\nconst acted = (event: Action): string => {\n const point = pointOf(event.x, event.y);\n\n if (event.subject === undefined)\n return event.target === undefined || /^e\\d+$|\"e\\d+\"/.test(event.target)\n ? (point ?? \"\")\n : event.target;\n // A drag's point is where it ended.\n if (event.to !== undefined)\n return `${named(event.subject, undefined)} to ${named(event.to, point)}`;\n\n return named(event.subject, point);\n};\n\n/**\n * An action as a step: `click button \"Pay\"`. A failed one says only that: its error is advice for\n * the caller that acted, which may name a ref, not a fact about the page.\n */\nconst step = (event: Action): string => {\n const target = acted(event);\n const text = event.text === undefined ? \"\" : JSON.stringify(event.text);\n\n const what =\n event.name === \"type\" && target !== \"\"\n ? `${text} into ${target}`\n : event.name === \"select\" && target !== \"\"\n ? `${text} in ${target}`\n : `${target} ${text}`;\n\n return `${event.name} ${what}${event.ok ? \"\" : \" (failed)\"}`.replace(/\\s+/g, \" \").trim();\n};\n\n/** What is drawn rather than written, whose changes only the screenshots show. */\nconst drawn = new Set([\"canvas\", \"iframe\", \"video\", \"embed\", \"object\", \"svg\"]);\n\nconst onDrawn = (event: Action) =>\n event.ok && event.subject !== undefined && drawn.has(event.subject.role ?? event.subject.tag);\n\ninterface Line {\n readonly at: number;\n readonly rank: number;\n readonly text: string;\n}\n\n/** At most this many lines of what happened; the least notable are counted, not listed. */\nconst maxLines = 24;\n\n/**\n * The changes as lines, news first, and the actions they name; cells of one column that changed\n * together as one line. What kept changing says whether it still was at the moment, by its account.\n */\nconst changed = (moment: Moment, record: Changes) => {\n const actions = moment.events.filter((event): event is Action => event._tag === \"Action\");\n const named = new Set<Action>();\n const changing = new Set(account(moment).changing);\n\n const state = (change: Change) =>\n changing.has(change)\n ? \", still changing at the moment\"\n : change.count > 1 || change.earlier !== undefined\n ? `, settled since ${seconds(moment, change.at)}`\n : \"\";\n\n // The action whose input a change followed: one that ran while the input arrived, give or take\n // the clock's mapping, so input the library did not send names no action.\n const cause = (change: Change) => {\n const input = change.cause;\n\n const action =\n input === undefined\n ? undefined\n : actions.findLast((event) => event.startedAt <= input + 100 && event.at >= input - 100);\n\n if (action === undefined) return \"\";\n named.add(action);\n\n return `, after ${step(action)}`;\n };\n\n const columns = Map.groupBy(\n record.changes.filter(\n (change) => change.kind === \"text\" && change.subject.context.column !== undefined,\n ),\n ({ subject: { context } }) => JSON.stringify([context.heading, context.column]),\n );\n\n const lines: Array<Line> = [];\n const collapsed = new Set<Change>();\n\n for (const [first, ...cells] of columns.values())\n if (first !== undefined && cells.length >= 2) {\n const still = [first, ...cells].filter((cell) => changing.has(cell)).length;\n\n for (const cell of [first, ...cells]) collapsed.add(cell);\n lines.push({\n at: first.startedAt,\n rank: still > 0 ? 3 : 2,\n text: `${cells.length + 1} cells in column ${quoted(first.subject.context.column)}${where({ heading: first.subject.context.heading })} changed, such as ${describe(first, true)}${still > 0 ? `, ${still} still changing at the moment` : \"\"}`,\n });\n }\n for (const change of record.changes)\n if (!collapsed.has(change))\n lines.push({\n at: change.startedAt,\n rank: changing.has(change) ? 3 : 2,\n text: describe(change) + cause(change) + state(change),\n });\n\n return { lines, named };\n};\n\n/** What a part a moment could not read was, by the operation that failed: a window's one read is its changes. */\nconst parts = new Map([\n [\"frame\", \"A picture of the moment\"],\n [\"snapshot\", \"The page's outline\"],\n]);\n\n/** The moment's changes and events as lines, most notable first when its changes are recorded. */\nconst happened = (moment: Moment): ReadonlyArray<string> => {\n const record = recordOf(moment);\n\n const { lines, named } =\n record === undefined\n ? { lines: new Array<Line>(), named: new Set<Action>() }\n : changed(moment, record);\n\n // Whether anything but a field's own edit changed after an action began.\n const followed = (event: Action) =>\n record?.changes.some((change) => change.kind !== \"value\" && change.at > event.startedAt) ===\n true;\n\n // With a record, an action is told as a step where changes followed it and none names it, so a\n // click whose effect a busy page leaves uncredited is not lost; where its effect is drawn; or\n // where it started before the record began, as on the document a click opened. An attempt that\n // nothing followed, a failed one, a hover and a scroll are left out.\n const told = (event: Action) =>\n !(event.ok && [\"navigate\", \"back\", \"reload\"].includes(event.name)) &&\n (record === undefined ||\n event.startedAt <= record.from ||\n (event.ok &&\n event.name !== \"scroll\" &&\n (onDrawn(event) || (event.name !== \"hover\" && !named.has(event) && followed(event)))));\n\n for (const event of moment.events)\n if (event._tag === \"Action\" && event.page === moment.page && told(event))\n lines.push({ at: event.at, rank: 4, text: step(event) });\n else if (event._tag === \"Navigated\")\n lines.push({\n at: event.at,\n rank: 0,\n text: `${event.sameDocument ? \"moved within the page\" : \"navigated\"} to ${event.url}`,\n });\n else if (event._tag === \"PageOpened\")\n lines.push({ at: event.at, rank: 0, text: `a tab opened at ${event.url}` });\n else if (event._tag === \"PageClosed\")\n lines.push({\n at: event.at,\n rank: 0,\n text: `the tab ${event.cause === \"crashed\" ? \"crashed\" : \"closed\"}`,\n });\n else if (event._tag === \"DialogShown\")\n lines.push({\n at: event.at,\n rank: 1,\n text: `a dialog (${event.kind}) said ${JSON.stringify(event.message)}`,\n });\n\n const ordered = lines.toSorted((left, right) =>\n record === undefined ? left.at - right.at : left.rank - right.rank || left.at - right.at,\n );\n\n const kept = ordered.slice(0, maxLines);\n const drawing = moment.events.some((event) => event._tag === \"Action\" && onDrawn(event));\n const begins = record === undefined ? moment.since : Math.max(moment.since, record.from);\n const unread = moment.missing.some((error) => !parts.has(error.operation));\n\n return [\n ...kept.map((line) => `${seconds(moment, line.at)} ${line.text}`),\n ...(ordered.length > maxLines ? [`…and ${ordered.length - maxLines} less notable`] : []),\n ...(record === undefined\n ? unread\n ? []\n : [\"What changed on the page was not recorded.\"]\n : record.changes.length > 0\n ? []\n : [\n `No text in view changed${begins > moment.since ? ` after ${seconds(moment, begins)}` : \"\"}${drawing ? \"; what is drawn, such as a canvas, shows only in the screenshots\" : \"\"}.`,\n ]),\n ...(record !== undefined && record.dropped > 0\n ? [\n `The page changed too much to tell it all: at least ${record.dropped} changes are not told.`,\n ]\n : []),\n ...(begins > moment.since\n ? [`Changes before ${seconds(moment, begins)} are not all known.`]\n : []),\n ...moment.missing.map(\n (error) =>\n `${parts.get(error.operation) ?? \"What changed on the page\"} could not be read: ${error.reason.message}.`,\n ),\n ];\n};\n\n/**\n * The moment as one user message: the page's outline when the moment has one, what changed, most\n * notable first, what kept changing told as still changing at the moment or settled since when, by\n * its account, with the actions that the changes followed, that changes followed though none\n * names them, or that drew what only the screenshots show, what could not be read and why, and its\n * frames captioned with their times, the last one \"the moment\" where it is the picture at its end.\n * Give a model its task with `Prompt.setSystem`, and add what the caller knows about the page as\n * more text.\n */\nexport const toPrompt = (moment: Moment): Prompt.Prompt => {\n const count = moment.frames.length;\n const last = count - 1;\n const pictured = moment.frames.at(-1)?.hostTime === moment.until;\n\n const following =\n count === 1 ? \"One screenshot follows\" : `${count} screenshots follow, oldest first`;\n\n return Prompt.fromMessages([\n Prompt.makeMessage(\"user\", {\n content: [\n Prompt.makePart(\"text\", {\n text: [\n \"One moment of a browser session. Rely only on what this material shows, and prefer concrete details: numbers, names, colours, positions and motion.\",\n \"\",\n ...(moment.snapshot === undefined ? [] : [moment.snapshot.rendered, \"\"]),\n `${recordOf(moment) === undefined ? \"What happened\" : \"What changed, most notable first\"} (seconds before the moment, over ${((moment.until - moment.since) / 1000).toFixed(1)}s):`,\n ...happened(moment),\n ...(count === 0\n ? []\n : [\n \"\",\n `${following}${pictured ? (count === 1 ? \": the moment itself.\" : \"; the last one is the moment itself.\") : \".\"}`,\n ]),\n ].join(\"\\n\"),\n }),\n ...moment.frames.flatMap((frame, index) => [\n Prompt.makePart(\"text\", {\n text:\n index === last && pictured ? \"The moment:\" : `${seconds(moment, frame.hostTime)}:`,\n }),\n Prompt.makePart(\"file\", { mediaType: \"image/jpeg\", data: frame.data }),\n ]),\n ],\n }),\n ]);\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { Point } from "./Motion.mjs";
|
|
3
|
-
import { Box, PageLoaded, Subject
|
|
3
|
+
import { Box, PageLoaded, Subject } from "./BrowserEvent.mjs";
|
|
4
4
|
import { c as FailFast, o as withheld, s as Correlation } from "./url-Cd04Okid.mjs";
|
|
5
5
|
import { Frame, Image } from "./Frame.mjs";
|
|
6
6
|
import { Effect, Schema } from "effect";
|
|
@@ -461,12 +461,8 @@ var Zoom = class extends Schema.Class("effect-browser/Zoom")({
|
|
|
461
461
|
/** The target as it read before input. Point coordinates are never snapped to another position. */
|
|
462
462
|
var ResolvedTarget = class extends Schema.Class("effect-browser/ResolvedTarget")({
|
|
463
463
|
point: Point,
|
|
464
|
+
...Subject.fields,
|
|
464
465
|
element: Schema.String,
|
|
465
|
-
/** The element's lowercase tag name. */
|
|
466
|
-
tag: Schema.String,
|
|
467
|
-
role: Schema.NullOr(Schema.String),
|
|
468
|
-
name: Schema.String,
|
|
469
|
-
context: SubjectContext,
|
|
470
466
|
/** For a point target, the box of what it found there. */
|
|
471
467
|
box: Schema.optional(Box),
|
|
472
468
|
cursor: Schema.String,
|
|
@@ -611,4 +607,4 @@ const correlate = (id) => (effect) => Effect.provideService(effect, Correlation,
|
|
|
611
607
|
//#endregion
|
|
612
608
|
export { evidence as _, Page_exports as a, State as c, correlate as d, failFast as f, guard as g, ValidatedInputResultSchema as h, InputRequest as i, Text as l, PreparedInputResultSchema as m, Fact as n, Region as o, redacted as p, Found as r, ResolvedTarget as s, ElementState as t, Zoom as u };
|
|
613
609
|
|
|
614
|
-
//# sourceMappingURL=Page-
|
|
610
|
+
//# sourceMappingURL=Page-CfB6Zn1p.mjs.map
|