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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Browser-DRPthkNO.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* crypto.randomUUIDv4.pipe(\n Effect.mapError(() =>\n undispatched(\"make\", new Failed({ detail: \"Could not name connection\" })),\n ),\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, InvalidRequest } from \"../../BrowserError.ts\";\nimport { type BrowserEvent, RecordedEvent } from \"../../BrowserEvent.ts\";\nimport { 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.fail(\n undispatched(\n \"events\",\n new InvalidRequest({\n detail:\n \"the event cursor must be a nonnegative integer no greater than the latest sequence\",\n }),\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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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Page-C_VkBVwI.mjs","names":["Fact","Motion.Point","Guard.Fact","Url.withheld"],"sources":["../src/internal/input/evidence.inpage.ts","../src/internal/input/guard.inpage.ts","../src/Page.ts"],"sourcesContent":["/**\n * In the page: what the page says about an input's first target, for a judge, and which fields a\n * form would send. It never reads what a field holds. See `reading/names.inpage.ts` for what a page-side part may use.\n */\nimport { Schema } from \"effect\";\n\nimport type { ContextReader } from \"../reading/context.inpage.ts\";\nimport type { Names } from \"../reading/names.inpage.ts\";\n\nexport type FormField = typeof FormFieldSchema.Encoded;\n\n/** Page text about the first target. It never includes what a field holds. */\nexport type Evidence = typeof EvidenceSchema.Encoded;\n\ntype Field = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n\nexport const evidence = (names: Names, placing: ContextReader) => {\n const { clean, isDocument, isInput, isSelect, isTextArea, nameOf, parentOf, roleOf, textOf } =\n names;\n\n const { groups, headingBefore, textBeside, treeOf } = placing;\n\n /** A field a submission would send. */\n const isField = (element: Element): element is Field =>\n ((isInput(element) && ![\"button\", \"submit\", \"reset\", \"image\"].includes(element.type)) ||\n isSelect(element) ||\n isTextArea(element)) &&\n !element.matches(\":disabled\");\n\n const isFilled = (field: Field): boolean =>\n isInput(field) && (field.type === \"checkbox\" || field.type === \"radio\")\n ? field.checked\n : isInput(field) && field.type === \"file\"\n ? (field.files?.length ?? 0) > 0\n : field.value !== \"\";\n\n const dialogOf = (element: Element): Element | undefined => {\n for (let node: Element | null = element; node !== null; node = parentOf(node))\n if (node.tagName === \"DIALOG\" || /^(?:alert)?dialog$/.test(node.getAttribute(\"role\") ?? \"\"))\n return node;\n\n return undefined;\n };\n\n /** What the page says about an input's first target, for a judge. Never a field's value. */\n const evidenceOf = (\n element: Element,\n form: HTMLFormElement | null,\n method: string | undefined,\n action: string | undefined,\n ): Evidence => {\n const name = nameOf(element, roleOf(element));\n const ids = element.getAttribute(\"aria-describedby\");\n\n const description = clean(\n ids === null\n ? (element.getAttribute(\"aria-description\") ?? element.getAttribute(\"title\"))\n : ids\n .split(/\\s+/)\n .map((id) => element.ownerDocument.getElementById(id)?.textContent ?? \"\")\n .join(\" \"),\n 120,\n );\n\n const dialog = dialogOf(element);\n\n const title = dialog?.querySelector(\"h1,h2,h3,h4,h5,h6,[role=heading]\");\n\n const dialogName =\n dialog === undefined\n ? \"\"\n : clean(nameOf(dialog, \"dialog\"), 120) ||\n (title === null || title === undefined ? \"\" : clean(textOf(title), 120));\n\n // Each scope stays in the target's own tree: a walker cannot leave a shadow root.\n const root = element.getRootNode();\n const top = isDocument(root) ? (root.body ?? root) : root;\n const inTree = element.closest(\"dialog,[role=dialog],[role=alertdialog]\");\n let nearby = \"\";\n\n for (const scope of new Set([element.closest(groups), inTree, top]))\n if (scope !== null && nearby === \"\")\n nearby = textBeside(element, scope, true) || textBeside(element, scope, false);\n\n const heading = headingBefore(element, treeOf(element));\n\n const fields =\n form === null\n ? []\n : Array.from(form.elements)\n .filter(isField)\n .slice(0, 16)\n .map((field) => {\n const autocomplete = clean(field.getAttribute(\"autocomplete\"), 40);\n\n return {\n type: isInput(field) ? field.type : field.tagName.toLowerCase(),\n name: clean(\n isInput(field) && field.type === \"hidden\"\n ? field.getAttribute(\"name\")\n : nameOf(field, roleOf(field)),\n 40,\n ),\n ...(autocomplete === \"\" ? {} : { autocomplete }),\n filled: isFilled(field),\n };\n });\n\n return {\n title: clean(document.title, 120),\n ...(description === \"\" || description === name ? {} : { description }),\n ...(dialogName === \"\" ? {} : { dialog: dialogName }),\n ...(heading === undefined ? {} : { heading }),\n ...(nearby === \"\" ? {} : { nearby }),\n ...(form === null\n ? {}\n : { form: { method: method ?? form.method, action: action ?? form.action, fields } }),\n };\n };\n\n return { evidenceOf, isField, isFilled };\n};\n\nexport type EvidenceReader = ReturnType<typeof evidence>;\n\nexport const FormFieldSchema = Schema.Struct({\n type: Schema.String,\n name: Schema.String,\n autocomplete: Schema.optional(Schema.String),\n filled: Schema.Boolean,\n});\n\nexport const EvidenceSchema = Schema.Struct({\n title: Schema.String,\n description: Schema.optional(Schema.String),\n dialog: Schema.optional(Schema.String),\n heading: Schema.optional(Schema.String),\n nearby: Schema.optional(Schema.String),\n form: Schema.optional(\n Schema.Struct({\n method: Schema.String,\n action: Schema.String,\n fields: Schema.Array(FormFieldSchema),\n }),\n ),\n});\n","/**\n * In the page: what the input guard decides on. It inspects an input's targets for the facts a\n * policy weighs, such as a form submission or a secret field, binds an approval to them, and\n * checks before each press that the approved target would still receive it. See `reading/names.inpage.ts` for what a page-side part may use.\n */\nimport { Schema } from \"effect\";\n\nimport type { Point } from \"../../Motion.ts\";\nimport type { Names } from \"../reading/names.inpage.ts\";\nimport { type Evidence, type EvidenceReader, EvidenceSchema } from \"./evidence.inpage.ts\";\nimport type { Targets } from \"./targets.inpage.ts\";\n\nexport const Fact = Schema.Literals([\n \"form-submit\",\n \"cross-origin\",\n \"download\",\n \"upload\",\n \"secret\",\n \"scripted\",\n \"opaque\",\n]);\n\nexport type Fact = typeof Fact.Type;\n\nexport interface InputPlan {\n readonly action: string;\n readonly targets: ReadonlyArray<string | Point | null>;\n readonly submit: boolean;\n readonly keys: string | null;\n readonly destination: string | null;\n}\n\nexport type InspectedTarget = NonNullable<PreparedInput[\"targets\"][number]>;\n\nexport type PreparedInput = Exclude<PreparedInputResult, InputFailure>;\n\n/** A refusal; a stale target is named by its index in the plan. */\nexport type InputFailure = typeof InputPreparationError.Encoded;\n\nexport type PreparedInputResult = typeof PreparedInputResultSchema.Encoded;\n\nexport type ValidatedInputResult = typeof ValidatedInputResultSchema.Encoded;\n\n/** A point where a target, by its index in the plan, is about to receive a press. */\nexport interface Press extends Point {\n readonly index: number;\n}\n\nexport interface ValidationOptions {\n /** Require focus on the first target. */\n readonly focused?: boolean;\n /** After the pointer's own events have run, each target must still receive its press. */\n readonly presses?: ReadonlyArray<Press>;\n}\n\nexport const guard = (names: Names, targets: Targets, evidence: EvidenceReader) => {\n const {\n activeElement,\n clean,\n describe,\n inCurrentDocument,\n interactiveRoles,\n isButton,\n isDisabled,\n isHtml,\n isInput,\n isLabel,\n isRoot,\n isSecret,\n isSelect,\n isTextArea,\n lookup,\n parentOf,\n refFor,\n roleOf,\n } = names;\n\n const { controlOf, details, hitAt, hrefAttribute, linkOf, receives, within } = targets;\n const { evidenceOf, isField, isFilled } = evidence;\n\n /**\n * The element whose activation behaviour a click or key on `element` runs, as the browser\n * resolves it along the composed path: a link, button, input, summary or a label's control.\n */\n const activationTarget = (element: Element): Element | undefined => {\n for (let node: Element | null = element; node !== null; node = parentOf(node)) {\n if (\n hrefAttribute(node) !== null ||\n node.tagName === \"BUTTON\" ||\n node.tagName === \"SUMMARY\" ||\n (isInput(node) && node.type !== \"hidden\")\n )\n return node;\n if (isLabel(node) && node.control !== null) return node.control;\n }\n\n return undefined;\n };\n\n /**\n * A control between a press's hit and the approved target that is not the target's own\n * activation, such as a link or button a hover handler nested into it. The approval inspected\n * the target, so that control would act unapproved.\n */\n const nestedControl = (element: Element, hit: Element): Element | undefined => {\n // A container of the target is covered by the target's own facts.\n if (!within(element, hit)) return undefined;\n const own = activationTarget(element);\n\n for (\n let node: Element | null = hit;\n node !== null && node !== element;\n node = parentOf(node) ?? node.ownerDocument.defaultView?.frameElement ?? null\n )\n if (\n node !== own &&\n (hrefAttribute(node) !== null ||\n node.tagName === \"BUTTON\" ||\n node.tagName === \"SUMMARY\" ||\n (isInput(node) && node.type !== \"hidden\") ||\n isSelect(node) ||\n isTextArea(node) ||\n (isLabel(node) && node.control !== null && node.control !== own) ||\n activatingRoles.has(roleOf(node) ?? \"\"))\n )\n return node;\n\n return undefined;\n };\n\n const textEntry = (element: Element): boolean =>\n (isInput(element) &&\n ![\n \"button\",\n \"reset\",\n \"submit\",\n \"image\",\n \"checkbox\",\n \"radio\",\n \"file\",\n \"range\",\n \"color\",\n \"hidden\",\n ].includes(element.type)) ||\n isTextArea(element) ||\n (isHtml(element) && element.isContentEditable);\n\n const activatingRoles = new Set([\n \"button\",\n \"link\",\n \"checkbox\",\n \"radio\",\n \"switch\",\n \"tab\",\n \"menuitem\",\n \"menuitemcheckbox\",\n \"menuitemradio\",\n \"option\",\n \"treeitem\",\n ]);\n\n // Typed text goes wherever focus is, and a typed space or letter can press a focused button,\n // toggle a box, follow a link or change a select. Only fields, or elements that are none of\n // these (a page or a canvas game), may receive text.\n const typingRefusal = (element: Element, explicit: boolean): string | undefined =>\n textEntry(element)\n ? undefined\n : explicit\n ? `${describe(element)} is not a text field`\n : activationTarget(element) !== undefined ||\n isSelect(element) ||\n activatingRoles.has(roleOf(element) ?? \"\")\n ? `focus is on ${describe(element)}, which typed text could activate or change; type into a text field by ref, or use press for keys`\n : undefined;\n\n const isSubmitter = (element: Element): element is HTMLButtonElement | HTMLInputElement =>\n (isButton(element) && element.type === \"submit\") ||\n (isInput(element) && (element.type === \"submit\" || element.type === \"image\"));\n\n // form.elements omits image submitters. Walk the whole root in tree order so an Enter\n // submission uses the real default button, including controls associated from outside the form.\n const defaultSubmitter = (form: HTMLFormElement) => {\n const root = form.getRootNode();\n\n return isRoot(root)\n ? Array.from(root.querySelectorAll(\"button,input\")).find(\n (candidate): candidate is HTMLButtonElement | HTMLInputElement =>\n isSubmitter(candidate) && candidate.form === form,\n )\n : undefined;\n };\n\n // Attributes that say what a field is for. They bind an approval.\n const purpose = (control: Element, form: HTMLFormElement | null) => [\n control.getAttribute(\"id\"),\n control.getAttribute(\"name\"),\n control.getAttribute(\"inputmode\"),\n control.getAttribute(\"autocomplete\"),\n control.getAttribute(\"aria-label\"),\n form?.getAttribute(\"id\"),\n form?.getAttribute(\"name\"),\n form?.getAttribute(\"aria-label\"),\n ];\n\n // What an approval binds of a URL. A fragment that names a place on the page, which scroll-spy\n // and feed pages rewrite as they scroll, is left out. A hash route (#/… or #!…) stays: it\n // selects what the page's controls act on.\n const boundUrl = (url: string): string => {\n const hash = url.indexOf(\"#\");\n\n return hash === -1 || /^#[/!]/.test(url.slice(hash)) ? url : url.slice(0, hash);\n };\n\n const inspectInput = (element: Element, plan: InputPlan) => {\n const metadata = details(element, element, 0, 0);\n // Facts are about what the input activates, such as the submit button around a painted label.\n const control = activationTarget(element) ?? element;\n\n const form =\n isInput(control) || isButton(control) || isTextArea(control) || isSelect(control)\n ? control.form\n : null;\n\n // The chord's last key, which may be the plus key itself: Control++.\n const key = plan.keys === null ? undefined : /(?:^|\\+)(\\+|[^+]+)$/.exec(plan.keys)?.[1];\n const enter = key === \"Enter\";\n\n const activation =\n plan.action === \"click\" || (plan.action === \"press\" && (enter || key === \"Space\"));\n\n // Enter submits a form from any input but buttons, file and color pickers, including\n // checkboxes, radios and ranges.\n const fieldEnter =\n isInput(control) &&\n ![\"button\", \"reset\", \"submit\", \"image\", \"file\", \"color\", \"hidden\"].includes(control.type) &&\n ((plan.action === \"press\" && enter) || (plan.action === \"type\" && plan.submit));\n\n const submits = form !== null && ((activation && isSubmitter(control)) || fieldEnter);\n\n const submitter = isSubmitter(control)\n ? control\n : form === null\n ? undefined\n : defaultSubmitter(form);\n\n const formDestination =\n form === null\n ? undefined\n : submitter?.hasAttribute(\"formaction\") === true\n ? submitter.formAction\n : form.action;\n\n const formMethod =\n form === null\n ? undefined\n : submitter?.hasAttribute(\"formmethod\") === true\n ? submitter.formMethod\n : form.method;\n\n const formTarget =\n form === null\n ? undefined\n : submitter?.hasAttribute(\"formtarget\") === true\n ? submitter.formTarget\n : form.target;\n\n const link = linkOf(element);\n const href = link === undefined ? null : hrefAttribute(link);\n // A dialog form only closes its dialog; the page's script decides what that means.\n const sends = submits && formMethod !== \"dialog\";\n // Only activation follows a link or opens a file chooser; hovering or scrolling over a\n // control does neither.\n const destination = sends ? formDestination : activation ? metadata.href : undefined;\n const acts = plan.action !== \"hover\" && plan.action !== \"scroll\";\n\n // What the browser itself does on activation: follow a link, submit or reset a form, choose\n // a file or a value, toggle a box or a disclosure, or focus a field. Anything else is the\n // page's script.\n const builtIn =\n sends ||\n (href !== null && !/^\\s*(?:#\\s*|javascript:[^]*)$/i.test(href)) ||\n (isInput(control) && ![\"button\", \"submit\", \"image\", \"reset\"].includes(control.type)) ||\n ((isInput(control) || isButton(control)) && control.type === \"reset\" && form !== null) ||\n control.tagName === \"SUMMARY\" ||\n control.closest(\"select\") !== null ||\n textEntry(control);\n\n const facts: Array<Fact> = [];\n\n // Facts come from structure only. What a name or the text around it says is evidence for a\n // judge, never a fact: words change meaning with context and language.\n if (sends) facts.push(\"form-submit\");\n if (activation && link?.hasAttribute(\"download\") === true) facts.push(\"download\");\n if (activation && isInput(control) && control.type === \"file\") facts.push(\"upload\");\n if (\n (plan.action === \"type\" && isSecret(control)) ||\n (sends &&\n form !== null &&\n Array.from(form.elements).some(\n (field) => isField(field) && isSecret(field) && isFilled(field),\n ))\n )\n facts.push(\"secret\");\n if (activation && !builtIn) facts.push(\"scripted\");\n if (acts && (metadata.role === \"canvas\" || metadata.role === \"iframe\" || metadata.name === \"\"))\n facts.push(\"opaque\");\n\n // Bind what decides the consequence and the control's identity. Names bind interactive\n // controls only: other text, such as a live price or a page's own text, may change freely.\n const role = metadata.role;\n\n const boundName =\n role !== null &&\n (interactiveRoles.has(role) || role === \"canvas\" || role === \"iframe\") &&\n !(isHtml(element) && element.isContentEditable)\n ? metadata.name\n : null;\n\n // A focus or scroll handler changing these attributes must not leave an old permission behind.\n const fingerprint = JSON.stringify([\n purpose(control, form),\n element.tagName,\n element.id,\n role,\n boundName,\n metadata.href,\n control === element ? null : refFor(control),\n isInput(control) || isButton(control) ? control.type : control.tagName,\n control.matches(\":disabled\") || isDisabled(control),\n control.getAttribute(\"readonly\"),\n control.getAttribute(\"aria-readonly\"),\n isHtml(control) && control.isContentEditable,\n control.getAttribute(\"name\"),\n control.getAttribute(\"accept\"),\n control.hasAttribute(\"multiple\"),\n link?.getAttribute(\"download\"),\n form === null ? null : refFor(form),\n form === null ? null : boundUrl(form.action),\n form?.method,\n form?.target,\n submitter === undefined ? null : refFor(submitter),\n formDestination === undefined ? undefined : boundUrl(formDestination),\n formMethod,\n formTarget,\n submitter?.formNoValidate,\n form?.noValidate,\n ]);\n\n const inspected: InspectedTarget = {\n ref: refFor(element),\n element: metadata.element,\n role: metadata.role,\n name: metadata.name,\n cursor: metadata.cursor,\n ...(metadata.href === undefined ? {} : { href: metadata.href }),\n secret: isSecret(control),\n fingerprint,\n };\n\n return {\n inspected,\n facts,\n destination,\n explain: () => evidenceOf(element, form, formMethod, formDestination),\n };\n };\n\n // Approval preparation only reads the DOM. In particular, an offscreen ref must not scroll\n // before the policy has had a chance to deny it.\n const inspect = (\n plan: InputPlan,\n ): (Omit<PreparedInput, \"evidence\"> & { readonly explain: () => Evidence }) | InputFailure => {\n const targets: Array<InspectedTarget | null> = [];\n const facts = new Set<Fact>();\n let destination = plan.destination ?? undefined;\n let explain = (): Evidence => ({ title: clean(document.title, 120) });\n\n for (const [index, target] of plan.targets.entries()) {\n let element: Element | null | undefined;\n\n if (target === null) {\n element = activeElement();\n } else if (typeof target === \"string\") {\n element = lookup(target);\n if (element === undefined)\n return { error: \"stale\", detail: target + \" is not on the page any more\", index };\n } else {\n if (\n !Number.isFinite(target.x) ||\n !Number.isFinite(target.y) ||\n target.x < 0 ||\n target.y < 0 ||\n target.x >= window.innerWidth ||\n target.y >= window.innerHeight\n )\n return { error: \"outside\", detail: \"the point is outside the viewport\" };\n const hit = hitAt(document, target.x, target.y);\n\n element = hit === null ? null : controlOf(hit);\n if (element === null)\n return { error: \"offscreen\", detail: \"nothing is painted at the point\" };\n }\n\n if (element === null) {\n targets.push(null);\n continue;\n }\n if (!inCurrentDocument(element))\n return { error: \"stale\", detail: \"the input target belongs to a replaced document\", index };\n const refusal = plan.action === \"type\" ? typingRefusal(element, target !== null) : undefined;\n\n if (refusal !== undefined) return { error: \"untypeable\", detail: refusal };\n const inspected = inspectInput(element, plan);\n\n if (index === 0) explain = inspected.explain;\n targets.push(inspected.inspected);\n for (const fact of inspected.facts) facts.add(fact);\n destination ??= inspected.destination;\n if (inspected.destination !== undefined) {\n try {\n if (new URL(inspected.destination, location.href).origin !== location.origin)\n facts.add(\"cross-origin\");\n } catch {\n return { error: \"outside\", detail: \"the input destination is not a valid URL\" };\n }\n }\n }\n\n if (destination !== undefined) {\n try {\n destination = new URL(destination, location.href).href;\n if (new URL(destination).origin !== location.origin) facts.add(\"cross-origin\");\n } catch {\n return { error: \"outside\", detail: \"the input destination is not a valid URL\" };\n }\n }\n\n return {\n url: boundUrl(location.href),\n targets,\n facts: [...facts],\n ...(destination === undefined ? {} : { destination }),\n explain,\n };\n };\n\n // Evidence is read once, for the policy. Validation binds the facts and the targets, not the\n // text around them, which live pages change freely.\n const prepareInput = (plan: InputPlan): PreparedInputResult => {\n const inspected = inspect(plan);\n\n if (\"error\" in inspected) return inspected;\n const { explain, ...prepared } = inspected;\n\n return { ...prepared, evidence: explain() };\n };\n\n const validate = (\n plan: InputPlan,\n prepared: PreparedInput,\n options: ValidationOptions,\n ): ValidatedInputResult => {\n const current = inspect(plan);\n\n if (\"error\" in current)\n return current.error === \"stale\" ? current : { error: \"changed\", detail: current.detail };\n if (\n current.url !== prepared.url ||\n (current.destination === undefined || prepared.destination === undefined\n ? current.destination !== prepared.destination\n : boundUrl(current.destination) !== boundUrl(prepared.destination)) ||\n JSON.stringify(current.facts) !== JSON.stringify(prepared.facts) ||\n current.targets.length !== prepared.targets.length ||\n current.targets.some((target, index) => {\n const previous = prepared.targets[index];\n\n return target === null\n ? previous !== null\n : previous === null ||\n previous === undefined ||\n target.ref !== previous.ref ||\n target.fingerprint !== previous.fingerprint;\n })\n )\n return {\n error: \"changed\",\n detail: \"the page or input target changed while the policy was deciding\",\n };\n\n if (options.focused === true) {\n const active = activeElement();\n const expected = prepared.targets[0];\n\n if (\n active === null ||\n expected === null ||\n expected === undefined ||\n refFor(active) !== expected.ref\n )\n return { error: \"changed\", detail: \"focus moved away from the approved element\" };\n }\n\n for (const press of options.presses ?? []) {\n const expected = prepared.targets[press.index];\n\n const element =\n expected === null || expected === undefined ? undefined : lookup(expected.ref);\n\n const hit = hitAt(document, press.x, press.y);\n\n if (element === undefined || hit === null || !receives(element, hit))\n return {\n error: \"changed\",\n detail: `the approved target is no longer under the pointer at (${press.x}, ${press.y})`,\n };\n\n const nested = nestedControl(element, hit);\n\n if (nested !== undefined)\n return {\n error: \"changed\",\n detail: `${describe(nested)} inside the approved target would receive the press at (${press.x}, ${press.y})`,\n };\n }\n\n return { ok: true };\n };\n\n // Chromium delivers pointer moves with the next frame. A press check waits until the frame\n // after it, so it sees what the page did when the pointer arrived, such as a menu opened over\n // the target. A hidden document draws no frames, and its moves wait for the press instead.\n const validateInput = (\n plan: InputPlan,\n prepared: PreparedInput,\n options: ValidationOptions = {},\n ): ValidatedInputResult | Promise<ValidatedInputResult> => {\n if ((options.presses ?? []).length === 0) return validate(plan, prepared, options);\n const { promise, resolve } = Promise.withResolvers<void>();\n\n if (document.visibilityState === \"hidden\") resolve();\n else requestAnimationFrame(() => requestAnimationFrame(() => resolve()));\n\n return promise.then(() => validate(plan, prepared, options));\n };\n\n return { prepareInput, textEntry, typingRefusal, validateInput };\n};\n\nexport type Guard = ReturnType<typeof guard>;\n\nconst InputPreparationError = Schema.Struct({\n error: Schema.String,\n detail: Schema.String,\n index: Schema.optional(Schema.Finite),\n});\n\nexport const PreparedInputResultSchema = Schema.Union([\n Schema.Struct({\n url: Schema.String,\n targets: Schema.Array(\n Schema.NullOr(\n Schema.Struct({\n ref: Schema.String,\n element: Schema.String,\n role: Schema.NullOr(Schema.String),\n name: Schema.String,\n cursor: Schema.String,\n href: Schema.optional(Schema.String),\n /** A field the DOM marks as holding a password, a one-time code or a card's details. */\n secret: Schema.Boolean,\n fingerprint: Schema.String,\n }),\n ),\n ),\n facts: Schema.Array(Fact),\n destination: Schema.optional(Schema.String),\n evidence: EvidenceSchema,\n }),\n InputPreparationError,\n]);\n\nexport const ValidatedInputResultSchema = Schema.Union([\n Schema.Struct({ ok: Schema.Literal(true) }),\n InputPreparationError,\n]);\n","/**\n * One browser tab: navigation, snapshots, pictures and input.\n *\n * A page waits only for itself: its operations take turns in one lane of its own. An action, which\n * sends input or navigates, has the page to itself, in the order actions were asked; reads share\n * it, after the action in flight and every action asked before them, so a read describes the page\n * an action left. A wait for a turn ends at the operation's deadline as `Busy`, never `Timeout`,\n * and a full deadline then bounds the operation itself; `failFast` fails it at once instead.\n * Identical reads asked between the same actions share one call to the page, and one whose\n * callers gave up finishes for the next caller to ask it. A policy holds outside the lane while\n * other operations continue; its target is revalidated before dispatch. Element targets are refs\n * from a snapshot; point targets are viewport coordinates in CSS pixels, the same coordinates as a\n * screenshot's pixels. Mouse and keyboard input share a bounded pipeline, so pacing does not wait\n * for each protocol reply. Target lookup happens before the input is sent.\n *\n * @since 0.3.0\n */\nimport { type Duration, Effect, Schema, type Stream } from \"effect\";\nimport type { Page as PlaywrightPage } from \"playwright-core\";\n\nimport { type BrowserError, type PolicyDenied } from \"./BrowserError.ts\";\nimport { Box, type BrowserEvent, PageLoaded, Subject, SubjectContext } from \"./BrowserEvent.ts\";\nimport type { Changes } from \"./Change.ts\";\nimport { type CaptureStats, Frame, Image, type ScreencastOptions } from \"./Frame.ts\";\nimport { FormFieldSchema } from \"./internal/input/evidence.inpage.ts\";\nimport * as Guard from \"./internal/input/guard.inpage.ts\";\nimport { Correlation, FailFast } from \"./internal/page/lane.ts\";\nimport * as Url from \"./internal/page/url.ts\";\nimport type { Window } from \"./Moment.ts\";\nimport * as Motion from \"./Motion.ts\";\nimport { type Snapshot, type SnapshotOptions } from \"./Snapshot.ts\";\n\nexport type Point = Motion.Point;\n\n/** A ref from a snapshot, such as `\"e12\"`, or a viewport point. */\nexport type Target = string | Point;\n\n/** An integer rectangle in viewport CSS pixels. */\nexport class Region extends Schema.Class<Region>(\"effect-browser/Region\")({\n x: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n y: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n width: Schema.Int.check(Schema.isGreaterThan(0)),\n height: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\n/** A crop and its viewport origin: add that origin to a point read from the crop. */\nexport class Zoom extends Schema.Class<Zoom>(\"effect-browser/Zoom\")({\n page: Schema.String,\n region: Region,\n image: Image,\n}) {}\n\n/** The target as it read before input. Point coordinates are never snapped to another position. */\nexport class ResolvedTarget extends Schema.Class<ResolvedTarget>(\"effect-browser/ResolvedTarget\")({\n point: Motion.Point,\n element: Schema.String,\n /** The element's lowercase tag name. */\n tag: Schema.String,\n role: Schema.NullOr(Schema.String),\n name: Schema.String,\n context: SubjectContext,\n /** For a point target, the box of what it found there. */\n box: Schema.optional(Box),\n cursor: Schema.String,\n href: Schema.optional(Schema.String),\n}) {}\n\nexport interface ClickOptions {\n readonly button?: \"left\" | \"right\" | \"middle\" | undefined;\n /** 2 for a double click. */\n readonly clickCount?: number | undefined;\n /** Hold the button down this long before releasing it. */\n readonly holdMillis?: number | undefined;\n}\n\nexport interface TypeOptions {\n /** Type into this text field: it is focused first, and its content replaced unless `replace` is false. */\n readonly into?: string | undefined;\n readonly replace?: boolean | undefined;\n /** Press Enter afterwards. */\n readonly submit?: boolean | undefined;\n /**\n * The text is a secret: type it only into a field the page marks secret, such as a password,\n * and otherwise refuse with `NotActionable` before any input. A replayed password asks this.\n */\n readonly secret?: boolean | undefined;\n}\n\nexport interface PressOptions {\n /**\n * Focus this element, by ref, before the first press: a link, a button or a field. The keys go to\n * whatever has focus otherwise.\n */\n readonly on?: string | undefined;\n /** Press the keys this many times. */\n readonly times?: number | undefined;\n /** Hold the keys down this long before releasing them, as a game control might need. */\n readonly holdMillis?: number | undefined;\n}\n\nexport interface ScrollOptions {\n readonly dx?: number | undefined;\n /** Pixels to scroll down; negative scrolls up. Defaults to most of a viewport. */\n readonly dy?: number | undefined;\n /** Scroll whatever is under this point or element. Defaults to the middle of the viewport. */\n readonly at?: Target | undefined;\n}\n\n/**\n * How current a picture must be. The newest screencast frame serves when it qualifies, at no cost;\n * otherwise a new screenshot is taken.\n */\nexport interface FrameOptions {\n /**\n * The oldest a reused frame may be, from its paint, at the earliest its timing allows, to now.\n * Defaults to 250 milliseconds; 0 always takes a new screenshot.\n */\n readonly maxAge?: Duration.Input | undefined;\n /**\n * `\"input\"`: reuse only a frame painted after this page's latest input, including input of an\n * interrupted action, and never while an action is changing the page. For a caller that has\n * just acted on the page.\n */\n readonly after?: \"input\" | undefined;\n}\n\n/** A screenshot reuses only a frame painted after the page's latest input, as `after: \"input\"`. */\nexport interface ScreenshotOptions {\n /** The oldest a reused frame may be, as for `frame`. Defaults to 250 milliseconds. */\n readonly maxAge?: Duration.Input | undefined;\n /** A region of the viewport, captured in CSS pixels at the viewport's own scale; always new. */\n readonly clip?: Box | undefined;\n /** JPEG quality, 0 to 100. Defaults to 80. */\n readonly quality?: number | undefined;\n /** `\"jpeg\"`, the default, or `\"png\"`, which is always a new picture. */\n readonly format?: \"jpeg\" | \"png\" | undefined;\n}\n\n/**\n * What `find` looks for. Every rule given must hold; with none, it finds every element in scope\n * that has a role or is a control.\n */\nexport interface FindQuery {\n /** An ARIA role, such as `\"button\"` or `\"heading\"`, ignoring case. */\n readonly role?: string | undefined;\n /**\n * The accessible name: a string that reads the same once spaces are collapsed and case folded,\n * or a pattern found in it.\n */\n readonly name?: string | RegExp | undefined;\n /**\n * Text it shows, ignoring case and spacing, or a pattern. Text inside a control or a heading is\n * that control's or heading's, and only the smallest element showing it matches, not every\n * element around it.\n */\n readonly text?: string | RegExp | undefined;\n /** Whole words in its context (row, column, label or heading), ignoring case and spacing. */\n readonly near?: string | undefined;\n /** Only what a point action at this viewport point would reach: the control there, or else what is painted there. */\n readonly at?: Point | undefined;\n /** The viewport (the default), or the whole document. */\n readonly scope?: \"viewport\" | \"document\" | undefined;\n}\n\n/**\n * An element's state as its markup gives it: `checked` for what can be checked, `expanded`,\n * `selected` and `pressed` where the page says either way, and `level` for headings.\n */\nexport const ElementState = Schema.Struct({\n disabled: Schema.Boolean,\n focused: Schema.Boolean,\n checked: Schema.optional(Schema.Boolean),\n expanded: Schema.optional(Schema.Boolean),\n selected: Schema.optional(Schema.Boolean),\n pressed: Schema.optional(Schema.Boolean),\n level: Schema.optional(Schema.Int),\n});\n\nexport type ElementState = typeof ElementState.Type;\n\n/** An element `find` found: a ref for the actions, what it is, where it is and its state. */\nexport class Found extends Schema.Class<Found>(\"effect-browser/Found\")({\n ref: Schema.String,\n subject: Subject,\n /** Its box, rounded. Reading the document, it may be out of view. */\n box: Box,\n inViewport: Schema.Boolean,\n state: ElementState,\n}) {}\n\nexport interface TextOptions {\n /** `\"viewport\"` (the default) reads what the viewport shows; a ref reads that element whole. */\n readonly scope?: string | undefined;\n /** Bound on the text's length, cut at a line. Defaults to 12,000 characters. */\n readonly maxChars?: number | undefined;\n /** Show what fields hold; a secret field still reads `••••`. Defaults to false. */\n readonly unmask?: boolean | undefined;\n}\n\n/** What a page showed as text: a line per block, with table cells apart by tabs. */\nexport class Text extends Schema.Class<Text>(\"effect-browser/Text\")({\n url: Schema.String,\n title: Schema.String,\n text: Schema.String,\n /** True when `text` was cut at `maxChars`. */\n truncated: Schema.Boolean,\n /** Host monotonic milliseconds from the browser's captured Effect Clock. */\n at: Schema.Finite,\n}) {}\n\n/** What `waitFor` waits for. */\nexport interface WaitCondition {\n /** A CSS selector for what to watch; the document's body without one. */\n readonly selector?: string | undefined;\n /**\n * `\"visible\"` (the default): something it matches shows; `\"hidden\"`: nothing it matches shows;\n * `\"enabled\"`: something it matches shows and is not disabled.\n */\n readonly state?: \"visible\" | \"hidden\" | \"enabled\" | undefined;\n /** Only what shows this text counts, case and all, with runs of spaces read as one. */\n readonly text?: string | undefined;\n}\n\nexport interface ReadyOptions {\n /** What must stay still during quietMillis: screen paint (default), or recorded content. */\n readonly still?: \"screen\" | \"content\" | undefined;\n /** How long the selected evidence must stay still; screen paint by default. */\n readonly quietMillis?: number | undefined;\n readonly timeout?: Duration.Input | undefined;\n}\n\n/** The window `changes` reads, and whether to show what fields hold. */\nexport interface ChangesOptions {\n /**\n * Where the window starts: the changes a previous read returned, to continue exactly where they\n * ended; a frame, at its paint; or host monotonic milliseconds, which mapped to the page's clock\n * may miss or repeat changes near the start if the browser's clock mapping changed since. Defaults\n * to the start of the record.\n */\n readonly since?: Changes | Frame | number | undefined;\n /**\n * Where it ends: a frame, at its paint, so a delayed frame's window holds nothing it does not\n * show; or host monotonic milliseconds. Defaults to now, and is never later.\n */\n readonly until?: Frame | number | undefined;\n /** Show what fields hold; a secret field still reads `••••`. Defaults to false. */\n readonly unmask?: boolean | undefined;\n}\n\n/** The window `window` reads, and whether to show what fields hold. */\nexport interface WindowOptions {\n /**\n * Where the window starts: a previous window, to continue exactly where it ended; a frame, at its\n * paint; host monotonic milliseconds; or a `Duration` back from `until`. A start after `until`\n * leaves the window empty there.\n */\n readonly since: Window | Frame | Duration.Duration | number;\n /**\n * Where it ends: a frame, at its paint, such as one a delayed consumer airs now; or host\n * monotonic milliseconds. Defaults to now, and is never later.\n */\n readonly until?: Frame | number | undefined;\n /** Show what fields hold in its changes; a secret field still reads `••••`. Defaults to false. */\n readonly unmask?: boolean | undefined;\n}\n\n/**\n * What the library knows of a page now, without asking it, each part with when it learned it, in\n * host monotonic milliseconds: a part's age is `at` less its time. Text read before the current\n * document began is left out, since it tells of a document that has gone.\n */\nexport class State extends Schema.Class<State>(\"effect-browser/PageState\")({\n page: Schema.String,\n /** When this was taken. */\n at: Schema.Finite,\n /** Where the main frame last committed or moved, without userinfo or known secret parameters. */\n url: Schema.String,\n /** The page's document, as `Navigated` counts them. */\n document: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n /** When the main frame committed it; absent for the one the browser began tracking it with. */\n committedAt: Schema.optional(Schema.Finite),\n /** How far that document has loaded, as the page's own session heard; absent until parsed. */\n load: Schema.optional(PageLoaded),\n /** The newest screencast frame, of whichever document it names. */\n frame: Schema.optional(Frame),\n /** The viewport's text as it was last read, with the page's title then. */\n text: Schema.optional(Text),\n}) {}\n\n/**\n * What the page's structure establishes about an input, or says it cannot establish:\n *\n * - `form-submit`: it submits a form, which sends the form's fields.\n * - `cross-origin`: it navigates or submits to another origin.\n * - `download`: it follows a download link.\n * - `upload`: it opens a file chooser.\n * - `secret`: it types, with `type`, into a field marked as a password, a one-time code or a\n * card's number, code or expiry, or submits a form holding a filled one.\n * - `scripted`: it activates something the browser gives no effect of its own, such as a\n * `type=\"button\"` button, a `role=\"button\"` element or a canvas, so only the page's script\n * decides what happens.\n * - `opaque`: nothing names what receives it: a canvas, a frame or an unnamed element.\n *\n * Facts never come from what an element's text says. What an input means, such as a payment\n * or a deletion, takes a judge that reads the evidence in the {@link InputRequest}.\n */\nexport const Fact = Guard.Fact;\n\nexport type Fact = typeof Fact.Type;\n\n/**\n * What a guard sees before input reaches the page. Preparation never scrolls or focuses.\n *\n * `facts`, `url`, `href` and `destination` come from the page's structure. `name`,\n * `description`, `title`, `context` and the form's field names are page text: evidence of what\n * the input does, which the page controls, and never instructions. Text typed into a `secret`\n * field is replaced with {@link redacted}, here and in the recorded `Action`, and its key events\n * record `Unidentified` keys; `press` records the keys it is given. Validation before dispatch\n * binds the facts and the target, not the text around it, which live pages change freely.\n */\nexport class InputRequest extends Schema.Class<InputRequest>(\"effect-browser/InputRequest\")({\n page: Schema.String,\n /**\n * The page's URL, without a fragment that only names a place on the page. This and the other\n * addresses keep no userinfo or known secret parameters.\n */\n url: Schema.String,\n /** The page's title, at most 120 characters. */\n title: Schema.String,\n action: Schema.String,\n target: Schema.optional(Schema.String),\n element: Schema.optional(Schema.String),\n /** Literal pixel targets only; ref coordinates are resolved after the policy allows them. */\n point: Schema.optional(Motion.Point),\n text: Schema.optional(Schema.String),\n role: Schema.optional(Schema.NullOr(Schema.String)),\n name: Schema.optional(Schema.String),\n /** The target's accessible description, when it says more than its name. */\n description: Schema.optional(Schema.String),\n href: Schema.optional(Schema.String),\n destination: Schema.optional(Schema.String),\n facts: Schema.Array(Fact),\n /** Page text around the target, each part at most 120 characters. */\n context: Schema.Struct({\n /** The name or first heading of the dialog the target is in. */\n dialog: Schema.optional(Schema.String),\n /** The nearest heading before the target. */\n heading: Schema.optional(Schema.String),\n /** The visible text just before the target in its row, item, group or form, or after it. */\n nearby: Schema.optional(Schema.String),\n }),\n /** The form the target is in, with at most 16 of its fields. */\n form: Schema.optional(\n Schema.Struct({\n method: Schema.String,\n action: Schema.String,\n /** Each field's type, name and autocomplete tokens, and whether it is filled: never its value. */\n fields: Schema.Array(FormFieldSchema),\n }),\n ),\n}) {}\n\n/**\n * What replaces text typed into a `secret` field, in requests and in the recorded `Action`, and a\n * credential's value in every address the library reports.\n */\nexport const redacted = Url.withheld;\n\n/**\n * Run page operations without waiting their turn: on a page busy with other operations, each fails\n * `Busy` at once, and `Browser.newPage` on a browser with `maxPages` open fails `Limit` at once.\n */\nexport const failFast = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>\n Effect.provideService(effect, FailFast, true);\n\n/**\n * Give every action `effect` performs a caller's id, such as a model's tool call id, which its\n * recorded `Action` carries as `correlation`.\n */\nexport const correlate =\n (id: string) =>\n <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>\n Effect.provideService(effect, Correlation, id);\n\n/** Succeed to allow, fail to deny, or await an external signal to hold the input. */\nexport type InputGuard = (request: InputRequest) => Effect.Effect<void, PolicyDenied>;\n\nexport interface Page {\n /** The page's CDP target id: the same page has it again after a reconnect to its browser. */\n readonly id: string;\n /** The Playwright page, for anything this API does not cover. Never give it to a model. */\n readonly playwright: PlaywrightPage;\n /** The page's address, without its userinfo or known secret parameters. */\n readonly url: Effect.Effect<string>;\n /**\n * The document's title as the page last set it, empty for an untitled page. The browser answers\n * it, in one call, so a page busy with a script cannot hold it up.\n */\n readonly title: Effect.Effect<string, BrowserError>;\n\n readonly goto: (url: string) => Effect.Effect<void, BrowserError>;\n /** The previous history entry, including one only a frame created; `NotFound` when none. */\n readonly back: Effect.Effect<void, BrowserError>;\n readonly reload: Effect.Effect<void, BrowserError>;\n /** Make this the visible tab. Background tabs paint rarely and send few screencast frames. */\n readonly bringToFront: Effect.Effect<void, BrowserError>;\n /** Close the tab, succeeding once it has closed, or at once when it already had. */\n readonly close: Effect.Effect<void, BrowserError>;\n\n readonly snapshot: (options?: SnapshotOptions) => Effect.Effect<Snapshot, BrowserError>;\n /**\n * A picture of the viewport, in CSS pixels: a screencast frame painted since the page's latest\n * input, if one qualifies, or a new one. A caller that has just acted sees what its action did.\n */\n readonly screenshot: (options?: ScreenshotOptions) => Effect.Effect<Image, BrowserError>;\n /**\n * The viewport with its timing: the newest screencast frame if it qualifies, else a new\n * screenshot timed by the host interval in which it was taken.\n */\n readonly frame: (options?: FrameOptions) => Effect.Effect<Frame, BrowserError>;\n /** A crop in CSS pixels, unmagnified, with the origin that keeps later input in viewport pixels. */\n readonly zoom: (region: Region) => Effect.Effect<Zoom, BrowserError>;\n /**\n * The viewport's size in CSS pixels, the space of points, crops and page scrolls. Over CDP the\n * page reports it, within the action timeout.\n */\n readonly viewport: Effect.Effect<\n { readonly width: number; readonly height: number },\n BrowserError\n >;\n /**\n * The elements that match a query, in tree order, with refs the actions take, in one call to the\n * page. All that match are returned, so a caller tells them apart by their context; none is an\n * empty result, not a failure.\n */\n readonly find: (query?: FindQuery) => Effect.Effect<ReadonlyArray<Found>, BrowserError>;\n /**\n * The text the viewport shows, or one element whole, in one call to the page. Field values read\n * `••••` unless `unmask`, and a secret field's always do, as does one that was secret when the\n * library saw it.\n */\n readonly text: (options?: TextOptions) => Effect.Effect<Text, BrowserError>;\n /**\n * What visibly changed over a window, in one call to the page. The first read starts the page's\n * record, so it finds none; from then the page records, and from the start of each later\n * document, until nobody has read it for two minutes. See `Change`.\n */\n readonly changes: (options?: ChangesOptions) => Effect.Effect<Changes, BrowserError>;\n /**\n * The page's events, changes and frames over a window: the frames and events it keeps, at no\n * call, and its changes, in one call, the first starting its record as `changes` does. A part\n * that cannot be read is missing, with why; the window fails only for bounds that are not finite.\n */\n readonly window: (options: WindowOptions) => Effect.Effect<Window, BrowserError>;\n /**\n * What the library knows of the page now, at no call and with no wait for its turn: where it is,\n * its document and how far it has loaded, its newest frame, and its text and title as last read.\n */\n readonly state: Effect.Effect<State>;\n\n readonly click: (\n target: Target,\n options?: ClickOptions,\n ) => Effect.Effect<ResolvedTarget, BrowserError>;\n readonly hover: (target: Target) => Effect.Effect<void, BrowserError>;\n readonly drag: (from: Target, to: Target) => Effect.Effect<void, BrowserError>;\n /** Type into a text field, or to whatever has focus unless a typed key could activate it. */\n readonly type: (text: string, options?: TypeOptions) => Effect.Effect<void, BrowserError>;\n /** Keys such as `\"Enter\"`, `\"Space\"`, `\"ArrowLeft\"` or `\"Control+A\"`. */\n readonly press: (keys: string, options?: PressOptions) => Effect.Effect<void, BrowserError>;\n readonly scroll: (options?: ScrollOptions) => Effect.Effect<void, BrowserError>;\n /**\n * Choose options of a `<select>` by value or label; returns the chosen labels. A refusal, such\n * as no matching option, is undispatched.\n */\n readonly select: (\n ref: string,\n values: ReadonlyArray<string>,\n ) => Effect.Effect<string, BrowserError>;\n\n /**\n * Wait until a condition holds, in one call that the page answers as it comes, looking every\n * 100 ms, or `Timeout` after `timeout`, 10 seconds by default. A selector that is not CSS is an\n * `InvalidRequest`.\n */\n readonly waitFor: (\n condition: WaitCondition,\n timeout?: Duration.Input,\n ) => Effect.Effect<void, BrowserError>;\n /**\n * Wait until the page is ready to be shown, asking the page every 100 ms: its document is parsed\n * and has painted since, nothing that ends is animating in view, its fonts and the images in\n * view have loaded, and the viewport shows something. With `quietMillis`, the screen must then\n * also stay still that long: nothing in view changed, where the page's changes are recorded, and\n * no frame comes, counted from the first frame of a capture the wait starts itself. A canvas\n * that keeps drawing, such as a live chart, is never still, and a page\n * is never ready without a painted frame, as a hidden tab may be. `Timeout` after `timeout`,\n * 15 seconds by default.\n */\n readonly ready: (options?: ReadyOptions) => Effect.Effect<void, BrowserError>;\n\n /**\n * Screencast frames for as long as the stream runs. Concurrent streams share one screencast and\n * its settings; explicit options that differ from a running screencast's fail with InvalidRequest.\n */\n readonly screencast: (options?: ScreencastOptions) => Stream.Stream<Frame, BrowserError>;\n /**\n * What this page's captures received, delivered and dropped, over its life or the latest\n * `window`, which reaches back at most a minute; a longer one is an `InvalidRequest`.\n */\n readonly captureStats: (options?: {\n readonly window?: Duration.Input | undefined;\n }) => Effect.Effect<CaptureStats, BrowserError>;\n /** Screencast frames painted within `frameHistory` of the newest, oldest first. */\n readonly recentFrames: Effect.Effect<ReadonlyArray<Frame>>;\n /** This page's events among the browser's latest `eventHistory`, oldest first. */\n readonly recentEvents: Effect.Effect<ReadonlyArray<BrowserEvent>>;\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context-rYTk-3Cv.mjs","names":["make","Url.redactWithin","BrowserClock.monotonicMillis","Lane.make"],"sources":["../src/internal/input/replies.ts","../src/internal/pictures/clock.ts","../src/internal/page/context.ts"],"sourcesContent":["/**\n * Bounded input replies owned by the page, including after an action is interrupted.\n * Canceling a caller cannot cancel a protocol command already sent. The next action waits for\n * those replies, while a stopped run releases only held keys or buttons whose release was never submitted.\n */\nimport { Context, Data, Effect } from \"effect\";\n\nimport { maximumSamples } from \"../../Motion.ts\";\n\nexport const capacity = 64;\n\nexport class InputFailure extends Data.TaggedError(\"InputFailure\")<{\n readonly cause: unknown;\n}> {}\n\nexport interface Run {\n /** A native call made by this operation: cancellation cannot cancel its actual reply. */\n readonly track: <A>(reply: Promise<A>) => Promise<A>;\n /** End ownership after the record and all this operation's native replies have settled. */\n readonly afterIdle: (ended: () => void) => void;\n /** Reserve a complete stroke, including its releases, before sending its first event. */\n readonly reserve: (commands: number) => Effect.Effect<void, InputFailure>;\n /** Admit every sample before a motion starts its published clock; ordinary input stays bounded separately. */\n readonly reserveMotion: (commands: number) => Effect.Effect<void, InputFailure>;\n readonly send: (command: () => Promise<unknown>) => Effect.Effect<void, InputFailure>;\n readonly down: (\n key: string,\n press: () => Promise<unknown>,\n release: () => Promise<unknown>,\n ) => Effect.Effect<void, InputFailure>;\n readonly up: (key: string) => Effect.Effect<void, InputFailure>;\n readonly drain: Effect.Effect<void, InputFailure>;\n /** Stop future input and submit missing releases without waiting indefinitely for replies. */\n readonly close: Effect.Effect<void>;\n}\n\n/** Native page calls join their operation's reply ownership, including script mutations. */\nexport const Current = Context.Reference<Run | undefined>(\"effect-browser/internal/input/Current\", {\n defaultValue: () => undefined,\n});\n\nexport const make = () => {\n const outstanding = new Set<Promise<void>>();\n\n // A timed-out action keeps capacity until its real replies arrive. Waiting for them sends\n // nothing, so cancellation here cannot leave a detached continuation that later types.\n const idle = Effect.gen(function* () {\n while (outstanding.size > 0) yield* Effect.promise(() => Promise.all(outstanding));\n });\n\n const begin = Effect.gen(function* () {\n yield* idle;\n const pending = new Set<Promise<void>>();\n const held: Array<{ readonly key: string; readonly release: () => Promise<unknown> }> = [];\n let failure: InputFailure | undefined;\n let reserved = 0;\n let closed = false;\n const observed = new WeakMap<Promise<unknown>, { input: boolean }>();\n const endings = new Set<() => void>();\n\n const track = <A>(response: Promise<A>, input = false): Promise<A> => {\n const existing = observed.get(response);\n\n if (existing !== undefined) {\n existing.input ||= input;\n\n return response;\n }\n const entry = { input };\n\n observed.set(response, entry);\n\n const reply = response\n .then(\n () => undefined,\n (cause: unknown) => {\n if (entry.input) failure ??= new InputFailure({ cause });\n },\n )\n .then(() => {\n pending.delete(reply);\n outstanding.delete(reply);\n if (pending.size === 0) {\n for (const end of endings) end();\n endings.clear();\n }\n });\n\n pending.add(reply);\n outstanding.add(reply);\n\n return response;\n };\n\n const requireOpen = Effect.suspend(() =>\n closed\n ? Effect.fail(new InputFailure({ cause: new Error(\"the input run has stopped\") }))\n : Effect.void,\n );\n\n const requireSuccess = Effect.suspend(() =>\n failure === undefined ? Effect.void : Effect.fail(failure),\n );\n\n const submit = (command: () => Promise<unknown>) => {\n if (reserved < 1) throw new Error(\"input must reserve capacity before dispatch\");\n reserved--;\n let response: Promise<unknown>;\n\n try {\n response = command();\n } catch (cause) {\n failure ??= new InputFailure({ cause });\n\n return;\n }\n\n void track(response, true);\n };\n\n const reserve = (commands: number, maximum: number, limit: number) =>\n Effect.gen(function* () {\n yield* requireOpen;\n yield* requireSuccess;\n if (!Number.isInteger(commands) || commands < 1 || commands > maximum)\n return yield* Effect.die(new Error(\"invalid input reservation\"));\n while (outstanding.size + reserved + commands > limit) {\n yield* Effect.promise(() => Promise.race(outstanding));\n yield* requireOpen;\n yield* requireSuccess;\n }\n reserved += commands;\n });\n\n const run: Run = {\n track,\n afterIdle: (end) => {\n if (pending.size === 0) end();\n else endings.add(end);\n },\n reserve: (commands) => reserve(commands, capacity, capacity),\n // A dense stroke cannot wait for replies midway without changing its published timing.\n // Its finite reservation also leaves room for the ordinary pool's already-owned releases.\n reserveMotion: (commands) => reserve(commands, maximumSamples, capacity + maximumSamples),\n send: (command) =>\n Effect.gen(function* () {\n yield* requireOpen;\n yield* requireSuccess;\n yield* Effect.sync(() => submit(command));\n yield* requireSuccess;\n }),\n down: (key, press, release) =>\n Effect.gen(function* () {\n yield* requireOpen;\n yield* requireSuccess;\n yield* Effect.sync(() => {\n held.push({ key, release });\n submit(press);\n });\n yield* requireSuccess;\n }),\n up: (key) =>\n Effect.gen(function* () {\n yield* requireOpen;\n yield* Effect.sync(() => {\n const index = held.findLastIndex((entry) => entry.key === key);\n const entry = held[index];\n\n if (entry === undefined) return;\n // Submission owns the release, even if its reply fails. Retrying an uncertain\n // release could run page handlers twice, so cleanup never sends it again.\n held.splice(index, 1);\n submit(entry.release);\n });\n yield* requireSuccess;\n }),\n drain: Effect.gen(function* () {\n while (pending.size > 0) yield* Effect.promise(() => Promise.all(pending));\n yield* requireSuccess;\n }),\n close: Effect.sync(() => {\n if (closed) return;\n closed = true;\n for (const entry of held.toReversed()) submit(entry.release);\n held.length = 0;\n reserved = 0;\n }),\n };\n\n return run;\n });\n\n /** `idle` lets an action wait, in its page's turn, for the page's earlier replies. */\n return { idle, begin };\n};\n","/**\n * Host monotonic milliseconds and the browser's clock read on the owner's: estimates of their\n * offset from timed probes, how an estimate ages, and the mapping a browser's pages share.\n * `pictures.ts` takes the probes.\n */\nimport { type Clock, Duration, Effect, Option } from \"effect\";\n\n/** Read the captured owner's clock, including from native callbacks, without changing its origin. */\nexport const monotonicMillis = (clock: Clock.Clock): number =>\n Number(clock.monotonicTimeNanosUnsafe()) / 1e6;\n\nexport interface Probe {\n readonly hostStart: number;\n readonly hostEnd: number;\n readonly browserTime: number;\n}\n\nexport interface Estimate {\n /** Browser epoch milliseconds minus the owner's host monotonic milliseconds. */\n readonly offsetMillis: number;\n /** Either transport direction can own the entire round trip; symmetry is not assumed. */\n readonly uncertaintyMillis: number;\n readonly roundTripMillis: number;\n readonly sampledAt: number;\n}\n\n/** The fastest complete probe limits uncertainty without mistaking transit delay for clock offset. */\nexport const estimate = (probes: ReadonlyArray<Probe>): Option.Option<Estimate> => {\n let best: Estimate | undefined;\n\n for (const probe of probes) {\n const roundTripMillis = probe.hostEnd - probe.hostStart;\n\n if (\n !Number.isFinite(probe.hostStart) ||\n !Number.isFinite(probe.hostEnd) ||\n !Number.isFinite(probe.browserTime) ||\n !Number.isFinite(roundTripMillis) ||\n roundTripMillis < 0\n )\n continue;\n const sampledAt = probe.hostStart + roundTripMillis / 2;\n const offsetMillis = probe.browserTime - sampledAt;\n\n if (\n !Number.isFinite(offsetMillis) ||\n !Number.isFinite(probe.browserTime - probe.hostStart) ||\n !Number.isFinite(probe.browserTime - probe.hostEnd)\n )\n continue;\n if (best === undefined || roundTripMillis < best.roundTripMillis)\n best = {\n offsetMillis,\n uncertaintyMillis: roundTripMillis / 2,\n roundTripMillis,\n sampledAt,\n };\n }\n\n return Option.fromUndefinedOr(best);\n};\n\n// Two machines' clocks drift apart by up to about 100 parts per million, so an estimate says this\n// much less about the offset for each millisecond of its age.\nconst driftPerMillis = 1e-4;\n\n/** An estimate's uncertainty at `hostTime`, wider the further that is from when it was sampled. */\nexport const uncertaintyAt = (estimate: Estimate, hostTime: number): number =>\n estimate.uncertaintyMillis + Math.abs(hostTime - estimate.sampledAt) * driftPerMillis;\n\n// Ten seconds widen an estimate by a millisecond, far less than a remote round trip, so it is\n// measured again no more often than this.\nconst renewAfter = Duration.seconds(10);\n\n/**\n * The browser's one epoch mapping, shared by its pages, input runs and capture generations. It is\n * measured on first need, by the first capture, never ahead of it.\n */\nexport interface Mapping {\n /** The latest estimate, without measuring: input uses it, and never waits for one. */\n readonly latest: () => Estimate | undefined;\n /** The latest estimate, measured through `measure` only while the browser has none. */\n readonly current: <E>(measure: Effect.Effect<Estimate, E>) => Effect.Effect<Estimate, E>;\n /**\n * Measure again once ten seconds have passed since the latest measurement began. A failed\n * measurement keeps the estimate, which keeps widening with its age.\n */\n readonly renew: <E>(measure: Effect.Effect<Estimate, E>) => Effect.Effect<void>;\n}\n\n/**\n * Whether a new measurement should replace the current estimate. Each interval contains the true\n * offset, so overlapping intervals agree and the narrower one is kept, the current one widened by\n * its age: a probe delayed behind a busy page cannot widen every tab's stamps. A disjoint\n * measurement means the clocks moved (a wall clock step, or drift between a remote browser and\n * this host), so the newer evidence wins.\n */\nexport const supersedes = (next: Estimate, current: Estimate): boolean => {\n const aged = uncertaintyAt(current, next.sampledAt);\n\n return (\n next.uncertaintyMillis <= aged ||\n Math.abs(next.offsetMillis - current.offsetMillis) > next.uncertaintyMillis + aged\n );\n};\n\n/**\n * Every renderer of a browser reads the same host wall clock, so the offset belongs to the\n * browser rather than a page. A busy page cannot fail work that an earlier estimate can serve.\n */\nexport const mapping = (now: () => number): Mapping => {\n let latest: Estimate | undefined;\n let measuredAt = Number.NEGATIVE_INFINITY;\n\n // Called where a measurement is decided, so no other can be decided before this one begins.\n const adopt = <E>(measure: Effect.Effect<Estimate, E>) => {\n measuredAt = now();\n\n return measure.pipe(\n Effect.map((estimate) => {\n if (latest === undefined || supersedes(estimate, latest)) latest = estimate;\n\n return latest;\n }),\n );\n };\n\n return {\n latest: () => latest,\n current: (measure) =>\n Effect.suspend(() => (latest === undefined ? adopt(measure) : Effect.succeed(latest))),\n renew: (measure) =>\n Effect.suspend(() =>\n latest === undefined || now() - measuredAt < Duration.toMillis(renewAfter)\n ? Effect.void\n : Effect.ignore(adopt(measure)),\n ),\n };\n};\n\nexport const toHostTime = (calibration: Estimate, browserEpochMillis: number): number =>\n browserEpochMillis - calibration.offsetMillis;\n\n/** CDP input timestamps use seconds, unlike browser frame timestamps and the owner's clock. */\nexport const toBrowserSeconds = (calibration: Estimate, hostMillis: number): number =>\n (hostMillis + calibration.offsetMillis) / 1000;\n","/**\n * What a page's parts share: the browser state they act on, the page's own lane, pointer and\n * clock, and how they call the browser and report its failures. The assembly in `page.ts` builds\n * one context per page.\n */\nimport {\n Clock,\n Context,\n Duration,\n Effect,\n Fiber,\n MutableRef,\n Option,\n Schema,\n type Scope,\n} from \"effect\";\nimport type { CDPSession, Page as PlaywrightPage } from \"playwright-core\";\n\nimport type { CaptureSource } from \"../../Browser.ts\";\nimport { BrowserError, Closed, Failed, type Reason, Timeout } from \"../../BrowserError.ts\";\nimport type { BrowserEvent } from \"../../BrowserEvent.ts\";\nimport type { InputGuard, Point } from \"../../Page.ts\";\nimport type { Gate } from \"../input/gate.ts\";\nimport { Current } from \"../input/replies.ts\";\nimport * as BrowserClock from \"../pictures/clock.ts\";\nimport * as Lane from \"./lane.ts\";\nimport type { Openings } from \"./openings.ts\";\nimport * as Url from \"./url.ts\";\n\n/** Why a page is gone. */\nexport type ClosedCause = Closed[\"cause\"];\n\n/** What every page of a browser shares, from its options. */\nexport interface Settings {\n readonly actionTimeout: Duration.Duration;\n readonly policyTimeout: Duration.Duration;\n readonly navigationTimeout: Duration.Duration;\n /** How long screencast frames stay in `recentFrames`, measured back from the newest. */\n readonly frameHistory: Duration.Duration;\n readonly guard: InputGuard | undefined;\n}\n\nexport interface MakeOptions {\n /** The page's CDP target id, which is also its main frame's id. */\n readonly id: string;\n /** The id of the browser's session, which its frames carry. */\n readonly session: string;\n /** This tracking connection, distinct from the provider session and capture socket. */\n readonly connection: string;\n /** The page's address when the browser began tracking it. */\n readonly url: string;\n readonly playwright: PlaywrightPage;\n readonly cdp: CDPSession;\n /** A call's reply, or a failure as for a closed page once the browser is lost first. */\n readonly untilLost: <A>(reply: Promise<A>) => Promise<A>;\n readonly settings: Settings;\n readonly clock: Clock.Clock;\n /** Browser-wide input authority; direct internal page fixtures need not provide one. */\n readonly inputGate?: Gate | undefined;\n /** The browser's epoch mapping: its first capture measures it, and later ones renew it. */\n readonly mapping: BrowserClock.Mapping;\n readonly publish: (event: BrowserEvent) => number;\n /** This page's retained events, oldest first. */\n readonly recentEvents: Effect.Effect<ReadonlyArray<BrowserEvent>>;\n /** Registration of the actual popups this page's current input opened. */\n readonly openings: Openings;\n /** Succeeds once the page's own session holds focus emulation, which keeps it painting behind. */\n readonly focused: Effect.Effect<void, BrowserError>;\n /** Succeeds once the page's own session has the Page domain on, so it sees every later commit. */\n readonly paging: (operation: string) => Effect.Effect<void, BrowserError>;\n /** Why the page is gone, once it is: its browser's loss, else its own close or crash. */\n readonly closedBy: () => ClosedCause;\n /** Where the page's screencast runs, if not on its own session. */\n readonly capture?: CaptureSource | undefined;\n}\n\nconst messageOf = (cause: unknown): string =>\n cause instanceof Error ? cause.message : typeof cause === \"string\" ? cause : \"unknown error\";\n\nconst closedPattern =\n /has been closed|Target closed|Session closed|browser has disconnected|Target page, context or browser/i;\n\n/**\n * Map a Playwright or protocol failure to a reason, `Closed` with `closed` as its cause for a page\n * or browser that is gone. A call that gives Playwright a timeout passes the same bound, so its\n * `Timeout` reports it; without one, Playwright's own message stays.\n */\nexport const reasonOf = (\n cause: unknown,\n timeoutMillis?: number,\n closed: ClosedCause = \"connection\",\n): Reason => {\n const message = messageOf(cause);\n\n if (closedPattern.test(message)) return new Closed({ cause: closed });\n if (cause instanceof Error && cause.name === \"TimeoutError\" && timeoutMillis !== undefined)\n return new Timeout({ millis: timeoutMillis });\n const line = message.split(\"\\n\")[0] ?? message;\n\n return new Failed({ detail: Url.redactWithin(line.replace(/^[\\w.]+: /, \"\")) });\n};\n\n/**\n * One Playwright or protocol call, failing undispatched. A closed page says why it is gone as the\n * browser knows then: the library's own calls fail with the browser's loss, and Playwright fails\n * its calls on a dropped connection after reporting the context closed.\n */\nexport const call = <A>(\n operation: string,\n run: () => Promise<A>,\n closedBy: () => ClosedCause,\n timeoutMillis?: number,\n) =>\n Effect.tryPromise({\n try: run,\n catch: (cause) => undispatched(operation, reasonOf(cause, timeoutMillis, closedBy())),\n });\n\nexport const contextGone = (error: BrowserError) =>\n error.reason._tag === \"Failed\" &&\n /Cannot find context|Execution context was destroyed|__effectBrowser|Inspected target navigated/i.test(\n error.reason.detail,\n );\n\n/**\n * What a page operation spent on the page's own protocol session: its calls, the bytes of their\n * parameters and results, and how long at least one of them awaited its reply. An operation inside\n * another counts toward both.\n */\ninterface Cost {\n readonly enclosing: Cost | undefined;\n calls: number;\n bytesOut: number;\n bytesIn: number;\n waitedMillis: number;\n awaiting: number;\n awaitingSince: number;\n}\n\n/** The cost of the page operation the current fiber runs, if any. */\nconst CurrentCost = Context.Reference<Cost | undefined>(\n \"effect-browser/internal/page/CurrentCost\",\n {\n defaultValue: () => undefined,\n },\n);\n\n/** Track the promise returned to the action, after tracing wraps it, so input counts once. */\nconst track = <A>(reply: Promise<A>) => Fiber.getCurrent()?.getRef(Current)?.track(reply) ?? reply;\n\n// A message's size on the wire, give or take its envelope.\nconst sizeOf = (value: unknown) =>\n value === undefined ? 0 : Buffer.byteLength(JSON.stringify(value));\n\n/** A failure of `operation` before any of its input reached the browser. */\nexport const undispatched = (operation: string, reason: Reason) =>\n new BrowserError({ operation, reason, dispatched: false });\n\nexport const failWith = (operation: string, reason: Reason) =>\n Effect.fail(undispatched(operation, reason));\n\nexport const decodeWith =\n <A>(operation: string, schema: Schema.Codec<A, unknown>) =>\n (value: unknown) =>\n Schema.decodeUnknownEffect(schema)(value).pipe(\n Effect.mapError((error) => undispatched(operation, new Failed({ detail: error.message }))),\n );\n\nexport const make = (options: MakeOptions, scope: Scope.Scope) => {\n const { id, clock } = options;\n const now = () => BrowserClock.monotonicMillis(clock);\n // Deadlines and pacing guard the page's lane, so page operations run on the owner's clock; a\n // caller's clock, such as a TestClock, cannot stall or stretch them.\n const owned = Effect.provideService(Clock.Clock, clock);\n\n // This page's spans name it and report what the operation cost on the protocol. Fine-grained\n // ones carry a level below the default Info, so an application keeps only the coarse ones by\n // raising `Tracer.MinimumTraceLevel`.\n const span =\n (name: string, attributes: Record<string, unknown> = {}, level?: \"Debug\" | \"Trace\") =>\n <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n Effect.gen(function* () {\n const cost: Cost = {\n enclosing: yield* CurrentCost,\n calls: 0,\n bytesOut: 0,\n bytesIn: 0,\n waitedMillis: 0,\n awaiting: 0,\n awaitingSince: 0,\n };\n\n return yield* effect.pipe(\n Effect.provideService(CurrentCost, cost),\n Effect.ensuring(\n Effect.suspend(() =>\n Effect.annotateCurrentSpan({\n calls: cost.calls,\n bytesOut: cost.bytesOut,\n bytesIn: cost.bytesIn,\n waitedMillis: Math.round(cost.waitedMillis * 10) / 10,\n }),\n ),\n ),\n );\n }).pipe(\n Effect.withSpan(\n name,\n { attributes: { page: id, ...attributes }, ...(level === undefined ? {} : { level }) },\n { captureStackTrace: false },\n ),\n );\n\n // Every call on the page's own protocol session, counted into the operation that sends it and\n // the operations around that one. It is looked up when the call is sent, so input pipelined\n // from inside an operation counts toward it too.\n const send: CDPSession[\"send\"] = (method, params) => {\n const cost = Fiber.getCurrent()?.getRef(CurrentCost);\n const sentAt = now();\n const bytesOut = sizeOf(params);\n\n for (let each = cost; each !== undefined; each = each.enclosing) {\n each.calls++;\n each.bytesOut += bytesOut;\n if (each.awaiting++ === 0) each.awaitingSince = sentAt;\n }\n const reply = options.untilLost(options.cdp.send(method, params));\n\n if (cost === undefined) return track(reply);\n\n const settle = (bytesIn: number) => {\n const at = now();\n\n for (let each: Cost | undefined = cost; each !== undefined; each = each.enclosing) {\n each.bytesIn += bytesIn;\n if (--each.awaiting === 0) each.waitedMillis += at - each.awaitingSince;\n }\n };\n\n return track(\n reply.then(\n (result) => {\n settle(sizeOf(result));\n\n return result;\n },\n (cause: unknown) => {\n settle(0);\n\n return Promise.reject(cause);\n },\n ),\n );\n };\n\n // Every protocol or Playwright call. Errors are undispatched here; `perform` marks them\n // dispatched once input has gone out.\n const native = <A>(operation: string, run: () => Promise<A>, timeoutMillis?: number) =>\n call(operation, () => track(run()), options.closedBy, timeoutMillis);\n\n /** Fail with `Timeout` once `duration` has passed, the action timeout unless another is given. */\n const within =\n (operation: string, duration: Duration.Input = options.settings.actionTimeout) =>\n <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n Effect.timeoutOrElse(effect, {\n duration,\n orElse: () => failWith(operation, new Timeout({ millis: Duration.toMillis(duration) })),\n });\n\n // Stop a navigation whose bounded wait failed. The stop and original mutation keep their\n // actual replies owned; this cleanup does not turn an unanswered acknowledgement into success.\n const stopLoading = native(\"stopLoading\", () => send(\"Page.stopLoading\")).pipe(\n within(\"stopLoading\", options.settings.navigationTimeout),\n Effect.ignore,\n );\n\n // The latest submitted input or page change. A read that must follow it waits for the action in\n // flight, so only paint from after its latest input is current. An action ends after its input\n // was handled, so if that input changed the page, newer paint follows; a lost final paint is\n // bounded by recency instead. Paint from before the current document began, when the page's own\n // session saw the main frame commit it, shows a page the tab has left, so no read reuses it,\n // whatever it asks.\n const activity = { inputAt: 0, documentAt: Number.NEGATIVE_INFINITY };\n\n const noteInput = () => {\n activity.inputAt = Math.max(activity.inputAt, now());\n };\n\n const lane = Lane.make({\n now,\n actionTimeout: options.settings.actionTimeout,\n documentAt: () => activity.documentAt,\n gone: (operation) => undispatched(operation, new Closed({ cause: options.closedBy() })),\n scope,\n inputGate: options.inputGate,\n });\n\n // Where this page's latest move left its pointer, which is where its next plain glide starts and\n // where a held button is released. Its lane orders the page's input, and Chromium keeps a\n // pointer per page too.\n const pointer = MutableRef.make(Option.none<Point>());\n\n // Named, so that the declarations of what holds it need not spell out Playwright's protocol types.\n const protocol: Pick<CDPSession, \"send\"> = { send };\n\n return {\n ...options,\n lane,\n pointer,\n now,\n owned,\n span,\n protocol,\n native,\n within,\n stopLoading,\n activity,\n noteInput,\n };\n};\n\nexport type PageContext = ReturnType<typeof make>;\n"],"mappings":"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"}
|