effect-browser 0.2.0-beta.9 → 0.3.0-beta.6
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 +707 -1184
- package/dist/Browser-B5AV7zPS.mjs +437 -0
- package/dist/Browser-B5AV7zPS.mjs.map +1 -0
- package/dist/Browser.d.mts +115 -3
- package/dist/Browser.mjs +2 -22
- package/dist/BrowserError-DXXIA6Rk.d.mts +135 -0
- package/dist/BrowserError.d.mts +2 -0
- package/dist/BrowserError.mjs +202 -0
- package/dist/BrowserError.mjs.map +1 -0
- package/dist/BrowserEvent-DzdNdvoh.d.mts +277 -0
- package/dist/BrowserEvent.d.mts +2 -0
- package/dist/BrowserEvent.mjs +295 -0
- package/dist/BrowserEvent.mjs.map +1 -0
- package/dist/Cdp.d.mts +32 -0
- package/dist/Cdp.mjs +61 -0
- package/dist/Cdp.mjs.map +1 -0
- package/dist/Change-DNvztNLu.mjs +138 -0
- package/dist/Change-DNvztNLu.mjs.map +1 -0
- package/dist/Change-DVP2IJWm.d.mts +71 -0
- package/dist/Change.d.mts +2 -0
- package/dist/Change.mjs +2 -0
- package/dist/Chromium.d.mts +29 -81
- package/dist/Chromium.mjs +57 -392
- package/dist/Chromium.mjs.map +1 -1
- package/dist/Expect.d.mts +62 -0
- package/dist/Expect.mjs +114 -0
- package/dist/Expect.mjs.map +1 -0
- package/dist/Frame-BERmf_gM.d.mts +117 -0
- package/dist/Frame.d.mts +2 -0
- package/dist/Frame.mjs +123 -0
- package/dist/Frame.mjs.map +1 -0
- package/dist/Moment.d.mts +2 -0
- package/dist/Moment.mjs +288 -0
- package/dist/Moment.mjs.map +1 -0
- package/dist/Motion.d.mts +40 -0
- package/dist/Motion.mjs +122 -0
- package/dist/Motion.mjs.map +1 -0
- package/dist/Page-D4281dIi.mjs +618 -0
- package/dist/Page-D4281dIi.mjs.map +1 -0
- package/dist/Page-DYTdVhYa.d.mts +593 -0
- package/dist/Page.d.mts +2 -0
- package/dist/Page.mjs +2 -0
- package/dist/Plan-5MdsRzE5.mjs +314 -0
- package/dist/Plan-5MdsRzE5.mjs.map +1 -0
- package/dist/Plan-CNNOU1Tx.d.mts +112 -0
- package/dist/Plan.d.mts +2 -3
- package/dist/Plan.mjs +2 -2
- package/dist/Policy.d.mts +76 -0
- package/dist/Policy.mjs +237 -0
- package/dist/Policy.mjs.map +1 -0
- package/dist/Presentation.d.mts +48 -0
- package/dist/Presentation.mjs +117 -0
- package/dist/Presentation.mjs.map +1 -0
- package/dist/Snapshot-B34hZ4Jl.d.mts +68 -0
- package/dist/Snapshot.d.mts +2 -0
- package/dist/Snapshot.mjs +79 -0
- package/dist/Snapshot.mjs.map +1 -0
- package/dist/Stage.d.mts +54 -0
- package/dist/Stage.mjs +133 -0
- package/dist/Stage.mjs.map +1 -0
- package/dist/Supervisor-BtEG93gR.mjs +420 -0
- package/dist/Supervisor-BtEG93gR.mjs.map +1 -0
- package/dist/Supervisor-Im6-wbg5.d.mts +230 -0
- package/dist/Supervisor.d.mts +2 -0
- package/dist/Supervisor.mjs +2 -0
- package/dist/context-DAYjATgC.mjs +137 -0
- package/dist/context-DAYjATgC.mjs.map +1 -0
- package/dist/index.d.mts +17 -14
- package/dist/index.mjs +18 -13
- package/dist/match.inpage-xOe9LNO0.mjs +48 -0
- package/dist/match.inpage-xOe9LNO0.mjs.map +1 -0
- package/dist/page-BkRcLCWZ.mjs +5097 -0
- package/dist/page-BkRcLCWZ.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/url-CcL0K7S0.mjs +262 -0
- package/dist/url-CcL0K7S0.mjs.map +1 -0
- package/package.json +96 -61
- package/src/Browser.ts +625 -0
- package/src/BrowserError.ts +225 -0
- package/src/BrowserEvent.ts +294 -0
- package/src/Cdp.ts +101 -0
- package/src/Change.ts +88 -0
- package/src/Chromium.ts +102 -0
- package/src/Expect.ts +180 -0
- package/src/Frame.ts +130 -0
- package/src/Moment.ts +479 -0
- package/src/Motion.ts +166 -0
- package/src/Page.ts +520 -0
- package/src/Plan.ts +354 -0
- package/src/Policy.ts +325 -0
- package/src/Presentation.ts +195 -0
- package/src/Snapshot.ts +89 -0
- package/src/Stage.ts +223 -0
- package/src/Supervisor.ts +353 -0
- package/src/index.ts +20 -0
- package/src/internal/input/actions.ts +610 -0
- package/src/internal/input/dispatch.ts +161 -0
- package/src/internal/input/edit.inpage.ts +162 -0
- package/src/internal/input/evidence.inpage.ts +164 -0
- package/src/internal/input/guard.inpage.ts +605 -0
- package/src/internal/input/guard.ts +183 -0
- package/src/internal/input/keyboard.ts +112 -0
- package/src/internal/input/keys.ts +127 -0
- package/src/internal/input/perform.ts +322 -0
- package/src/internal/input/pointer.ts +153 -0
- package/src/internal/input/replies.ts +159 -0
- package/src/internal/input/settle.ts +50 -0
- package/src/internal/input/style.ts +186 -0
- package/src/internal/input/targets.inpage.ts +293 -0
- package/src/internal/input/targets.ts +148 -0
- package/src/internal/page/bridge.ts +386 -0
- package/src/internal/page/context.ts +302 -0
- package/src/internal/page/lane.ts +301 -0
- package/src/internal/page/navigation.ts +183 -0
- package/src/internal/page/openings.ts +87 -0
- package/src/internal/page/page.ts +137 -0
- package/src/internal/page/url.ts +100 -0
- package/src/internal/page/viewport.ts +43 -0
- package/src/internal/pictures/capture.ts +778 -0
- package/src/internal/pictures/clock.ts +141 -0
- package/src/internal/pictures/pictures.ts +520 -0
- package/src/internal/pictures/transport.ts +242 -0
- package/src/internal/reading/choose.ts +100 -0
- package/src/internal/reading/context.inpage.ts +201 -0
- package/src/internal/reading/controls.inpage.ts +158 -0
- package/src/internal/reading/expect.inpage.ts +70 -0
- package/src/internal/reading/match.inpage.ts +92 -0
- package/src/internal/reading/names.inpage.ts +306 -0
- package/src/internal/reading/outline.inpage.ts +260 -0
- package/src/internal/reading/reading.ts +223 -0
- package/src/internal/reading/ready.inpage.ts +154 -0
- package/src/internal/reading/ready.ts +105 -0
- package/src/internal/reading/subjects.inpage.ts +188 -0
- package/src/internal/reading/text.inpage.ts +135 -0
- package/src/internal/reading/walk.inpage.ts +220 -0
- package/src/internal/supervisor/lifecycle.ts +265 -0
- package/src/internal/timeline/changes.inpage.ts +216 -0
- package/src/internal/timeline/changes.ts +100 -0
- package/src/internal/timeline/events.ts +93 -0
- package/src/internal/timeline/fold.inpage.ts +123 -0
- package/src/internal/timeline/history.inpage.ts +229 -0
- package/src/internal/timeline/marks.inpage.ts +207 -0
- package/src/internal/timeline/record.inpage.ts +133 -0
- package/src/internal/timeline/sight.inpage.ts +122 -0
- package/src/internal/timeline/window.ts +96 -0
- package/src/internal/timeline/words.ts +65 -0
- package/dist/Bootstrap-B9UUXsvF.d.mts +0 -183
- package/dist/Bootstrap-CeQOWBy6.mjs +0 -189
- package/dist/Bootstrap-CeQOWBy6.mjs.map +0 -1
- package/dist/Bootstrap.d.mts +0 -3
- package/dist/Bootstrap.mjs +0 -2
- package/dist/Browser-BF9_sORP.d.mts +0 -388
- package/dist/Browser.mjs.map +0 -1
- package/dist/BrowserData-CPIIIHol.d.mts +0 -585
- package/dist/BrowserData.d.mts +0 -3
- package/dist/BrowserData.mjs +0 -695
- package/dist/BrowserData.mjs.map +0 -1
- package/dist/BrowserRuntime-B6nT1G4X.d.mts +0 -148
- package/dist/BrowserRuntime-C1r2aSRK.mjs +0 -6820
- package/dist/BrowserRuntime-C1r2aSRK.mjs.map +0 -1
- package/dist/BrowserRuntime.d.mts +0 -3
- package/dist/BrowserRuntime.mjs +0 -3
- package/dist/Capture.d.mts +0 -56
- package/dist/Capture.mjs +0 -678
- package/dist/Capture.mjs.map +0 -1
- package/dist/CaptureData-CYriZHX1.mjs +0 -201
- package/dist/CaptureData-CYriZHX1.mjs.map +0 -1
- package/dist/CaptureData.d.mts +0 -219
- package/dist/CaptureData.mjs +0 -2
- package/dist/Errors.d.mts +0 -158
- package/dist/Errors.mjs +0 -207
- package/dist/Errors.mjs.map +0 -1
- package/dist/Images-yCG9BmRU.mjs +0 -76
- package/dist/Images-yCG9BmRU.mjs.map +0 -1
- package/dist/OperationOptions-DAeRS6O9.mjs +0 -55
- package/dist/OperationOptions-DAeRS6O9.mjs.map +0 -1
- package/dist/PageControl.d.mts +0 -15
- package/dist/PageControl.mjs +0 -34
- package/dist/PageControl.mjs.map +0 -1
- package/dist/PageRegistry-B3q9DS3g.mjs +0 -164
- package/dist/PageRegistry-B3q9DS3g.mjs.map +0 -1
- package/dist/Plan-Dyxu2q8C.mjs +0 -543
- package/dist/Plan-Dyxu2q8C.mjs.map +0 -1
- package/dist/PlanData-B668RxbQ.d.mts +0 -4831
- package/dist/PlanData.d.mts +0 -3
- package/dist/PlanData.mjs +0 -268
- package/dist/PlanData.mjs.map +0 -1
- package/dist/PlanInput-BJcPPncs.mjs +0 -75
- package/dist/PlanInput-BJcPPncs.mjs.map +0 -1
- package/dist/PublicSession-DCSMMqOj.mjs +0 -5602
- package/dist/PublicSession-DCSMMqOj.mjs.map +0 -1
- package/dist/Testing.d.mts +0 -479
- package/dist/Testing.mjs +0 -2147
- package/dist/Testing.mjs.map +0 -1
- package/dist/Timeline-fV22Xk-S.d.mts +0 -29
- package/dist/Timeline.d.mts +0 -4
- package/dist/Timeline.mjs +0 -20
- package/dist/Timeline.mjs.map +0 -1
- package/dist/TimelineData-BsOn-YGZ.d.mts +0 -3818
- package/dist/TimelineData.d.mts +0 -3
- package/dist/TimelineData.mjs +0 -482
- package/dist/TimelineData.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Supervisor-BtEG93gR.mjs","names":["Lifecycle.GenerationState","Lifecycle.resolve","Lifecycle.start","Lifecycle.transition","Lifecycle.Settled","Lifecycle.Unconfirmed"],"sources":["../src/internal/supervisor/lifecycle.ts","../src/Supervisor.ts"],"sourcesContent":["/**\n * A supervisor's life as one state and one transition function, and the generation states it\n * publishes. The transition has no effects: `Supervisor.make` applies each input under one lock,\n * publishes the events in order and runs the commands, so the rules here are tested alone.\n */\nimport { Schema } from \"effect\";\n\nimport { DisconnectCause } from \"../../BrowserEvent.ts\";\n\n/** The provider confirmed that the generation's browser ended. */\nexport class Settled extends Schema.TaggedClass<Settled>()(\"Settled\", {}) {}\n\n/** The provider could not confirm the end by its deadline, so the browser may still run, and bill. */\nexport class Unconfirmed extends Schema.TaggedClass<Unconfirmed>()(\"Unconfirmed\", {\n detail: Schema.String,\n}) {}\n\nexport const Released = Schema.Union([Settled, Unconfirmed]);\n\nexport type Released = typeof Released.Type;\n\n/** Opening, but not after a loss: the first generation, a rotation, or the one after `Down`. */\nexport class Opening extends Schema.TaggedClass<Opening>()(\"Opening\", {}) {}\n\n/** Opening after the generation before it was lost. */\nexport class Reopening extends Schema.TaggedClass<Reopening>()(\"Reopening\", {}) {}\n\n/** Open: `browser` gives this generation until the next one opens. */\nexport class Open extends Schema.TaggedClass<Open>()(\"Open\", {}) {}\n\n/** Lost: its connection dropped, or its provider ended its session, as `cause` says. */\nexport class Lost extends Schema.TaggedClass<Lost>()(\"Lost\", {\n cause: DisconnectCause,\n}) {}\n\n/**\n * It never opened: its last try failed with `cause`, which the provider deems definite, or after\n * which the reopen schedule gave up.\n */\nexport class Down extends Schema.TaggedClass<Down>()(\"Down\", {\n detail: Schema.String,\n cause: Schema.Defect(),\n}) {}\n\n/** It ended. `released` says how its release went; one retired while opening has none. */\nexport class Closed extends Schema.TaggedClass<Closed>()(\"Closed\", {\n released: Schema.optional(Released),\n}) {}\n\n/**\n * It was serving as the supervisor's scope closed, and was left running, not released: its scope\n * closed, and its provider runs it on, and bills, until something adopts and releases it.\n */\nexport class Kept extends Schema.TaggedClass<Kept>()(\"Kept\", {}) {}\n\nexport const GenerationState = Schema.Union([Opening, Reopening, Open, Lost, Down, Closed, Kept]);\n\nexport type GenerationState = typeof GenerationState.Type;\n\n/** A generation that opened: its number, and what the runtime keeps to serve and end it. */\nexport interface Live<A> {\n readonly number: number;\n readonly value: A;\n}\n\n/**\n * At most one generation opens and at most one serves. Both do while a rotation makes the next\n * before it breaks the current, and `Down` keeps serving one that a rotation failed to replace.\n */\nexport type State<A> =\n | { readonly _tag: \"Opening\"; readonly number: number; readonly serving: Live<A> | undefined }\n | { readonly _tag: \"Open\"; readonly serving: Live<A> }\n | {\n readonly _tag: \"Down\";\n readonly number: number;\n readonly detail: string;\n readonly cause: unknown;\n readonly serving: Live<A> | undefined;\n }\n | { readonly _tag: \"Retired\" };\n\nexport type Input<A> =\n | { readonly _tag: \"Opened\"; readonly live: Live<A> }\n /** The open of `number` failed for good. */\n | {\n readonly _tag: \"Failed\";\n readonly number: number;\n readonly detail: string;\n readonly cause: unknown;\n }\n /** The open of `number` was stopped, as on retiring, before it opened. */\n | { readonly _tag: \"Abandoned\"; readonly number: number }\n | { readonly _tag: \"Lost\"; readonly number: number; readonly cause: DisconnectCause }\n /** A caller asks for the next generation, or the rotation time of `due` came. */\n | { readonly _tag: \"Rotate\"; readonly due?: number | undefined }\n | { readonly _tag: \"Retire\" }\n /** Stop as `Retire` does, but leave the serving generation running. */\n | { readonly _tag: \"Keep\" }\n | { readonly _tag: \"Released\"; readonly number: number; readonly released: Released };\n\nexport type Command<A> =\n /** Open `number`, after the release of `after` has finished. */\n | { readonly _tag: \"Open\"; readonly number: number; readonly after: number | undefined }\n /** Watch a generation that opened for its loss and its rotation time. */\n | { readonly _tag: \"Watch\"; readonly live: Live<A> }\n | { readonly _tag: \"Release\"; readonly live: Live<A> }\n /** Close its scope without asking its provider to release it. */\n | { readonly _tag: \"Leave\"; readonly live: Live<A> };\n\nexport interface Step<A> {\n readonly state: State<A>;\n /** Generation numbers and their new states, to publish in this order. */\n readonly events: ReadonlyArray<readonly [number, GenerationState]>;\n readonly commands: ReadonlyArray<Command<A>>;\n /** For `Rotate`, the generation to wait for, unless retired. */\n readonly reply?: number | undefined;\n}\n\nexport const start = <A>(): Step<A> => ({\n state: { _tag: \"Opening\", number: 1, serving: undefined },\n events: [[1, new Opening()]],\n commands: [{ _tag: \"Open\", number: 1, after: undefined }],\n});\n\nconst servingOf = <A>(state: State<A>) => (state._tag === \"Retired\" ? undefined : state.serving);\n\n/** The state after `input`, with the events to publish and the commands to run. */\nexport const transition = <A>(state: State<A>, input: Input<A>, exclusive: boolean): Step<A> => {\n const release = (live: Live<A>): Command<A> => ({ _tag: \"Release\", live });\n const stay: Step<A> = { state, events: [], commands: [] };\n\n /**\n * Open `number`, ending `current` now if it `ends`; exclusive generations open only once its\n * release has finished. Otherwise `current` serves until the next one opens.\n */\n const next = (\n number: number,\n reopen: boolean,\n current: Live<A> | undefined,\n ends: boolean,\n ): Step<A> => ({\n state: { _tag: \"Opening\", number, serving: ends ? undefined : current },\n events: [[number, reopen ? new Reopening() : new Opening()]],\n commands: [\n ...(ends && current !== undefined ? [release(current)] : []),\n { _tag: \"Open\", number, after: ends && exclusive ? current?.number : undefined },\n ],\n });\n\n switch (input._tag) {\n case \"Opened\": {\n const { live } = input;\n\n // A generation nobody waits for any more, as after `Retire`, is released at once.\n if (state._tag !== \"Opening\" || state.number !== live.number)\n return { ...stay, commands: [release(live)] };\n\n return {\n state: { _tag: \"Open\", serving: live },\n events: [[live.number, new Open()]],\n commands: [\n { _tag: \"Watch\", live },\n ...(state.serving === undefined ? [] : [release(state.serving)]),\n ],\n };\n }\n case \"Failed\": {\n const { number, detail, cause } = input;\n const events = [[number, new Down({ detail, cause })] as const];\n\n if (state._tag !== \"Opening\" || state.number !== input.number) return { ...stay, events };\n\n return {\n state: { _tag: \"Down\", number, detail, cause, serving: state.serving },\n events,\n commands: [],\n };\n }\n case \"Abandoned\":\n return { ...stay, events: [[input.number, new Closed({})]] };\n case \"Released\":\n return { ...stay, events: [[input.number, new Closed({ released: input.released })]] };\n case \"Lost\": {\n const lost = servingOf(state);\n\n if (state._tag === \"Retired\" || lost?.number !== input.number) return stay;\n const events = [[lost.number, new Lost({ cause: input.cause })] as const];\n\n // A rotation already opening the next generation carries on without the lost one.\n if (state._tag === \"Opening\")\n return { state: { ...state, serving: undefined }, events, commands: [release(lost)] };\n\n const reopened = next(\n (state._tag === \"Open\" ? lost.number : state.number) + 1,\n true,\n lost,\n true,\n );\n\n return { ...reopened, events: [...events, ...reopened.events] };\n }\n case \"Rotate\": {\n if (state._tag === \"Retired\") return stay;\n // A rotation time comes only for the generation still serving with nothing opening.\n if (input.due !== undefined && (state._tag !== \"Open\" || state.serving.number !== input.due))\n return stay;\n if (state._tag === \"Opening\") return { ...stay, reply: state.number };\n const number = (state._tag === \"Open\" ? state.serving.number : state.number) + 1;\n\n return { ...next(number, false, state.serving, exclusive), reply: number };\n }\n case \"Retire\":\n case \"Keep\": {\n const current = servingOf(state);\n\n if (state._tag === \"Retired\") return stay;\n if (current === undefined) return { state: { _tag: \"Retired\" }, events: [], commands: [] };\n\n return input._tag === \"Retire\"\n ? { state: { _tag: \"Retired\" }, events: [], commands: [release(current)] }\n : {\n state: { _tag: \"Retired\" },\n events: [[current.number, new Kept()]],\n commands: [{ _tag: \"Leave\", live: current }],\n };\n }\n }\n};\n\nexport type Resolution<A> =\n | { readonly _tag: \"Serve\"; readonly live: Live<A> }\n | {\n readonly _tag: \"Unavailable\";\n readonly reason: \"down\" | \"retired\";\n readonly detail: string;\n readonly cause?: unknown;\n };\n\n/**\n * What a caller waiting for generation `target`, or for any when it is undefined, gets in\n * `state`; undefined while it should go on waiting.\n */\nexport const resolve = <A>(\n state: State<A>,\n target: number | undefined,\n): Resolution<A> | undefined => {\n const serve = (live: Live<A>) => ({ _tag: \"Serve\" as const, live });\n\n switch (state._tag) {\n case \"Retired\":\n return { _tag: \"Unavailable\", reason: \"retired\", detail: \"the supervisor was retired\" };\n case \"Open\":\n return target === undefined || state.serving.number >= target\n ? serve(state.serving)\n : undefined;\n case \"Opening\":\n return target === undefined && state.serving !== undefined ? serve(state.serving) : undefined;\n case \"Down\":\n if (target === undefined && state.serving !== undefined) return serve(state.serving);\n\n return target === undefined || state.number >= target\n ? { _tag: \"Unavailable\", reason: \"down\", detail: state.detail, cause: state.cause }\n : undefined;\n }\n};\n","/**\n * A browser kept open across losses and session ends, as a series of generations, each a new\n * browser from the same provider. Pages don't carry over from one generation to the next.\n *\n * `make` opens the first generation at once with the provider's `open`, in a scope of its own, so\n * a caller that stops waiting never interrupts a half-open browser. `browser` gives the current\n * generation; callers wait, bounded, and share one open. A loss is published at once and the next\n * generation opens on the `reopen` schedule, which also retries a failed open, unless the provider\n * deems its failure `definite`: that goes `Down` at once, with its cause. `rotate` opens the\n * next generation now, and so does the time `rotateBefore` ahead of a generation's `expiresAt`. A\n * rotation makes the next generation before it breaks the current one, unless generations are\n * `exclusive`, as sessions saving to one stored context must be: then the current one is released\n * first. `retire` stops reopening at once and releases what is open; the scope's close retires\n * too, unless the supervisor `keep`s: then it leaves the serving generation running, `Kept`. `states`\n * publishes each generation's changes, with the provider's release outcome last.\n *\n * Providers supply the specifics: `Browserbase.supervise` opens hosted sessions this way.\n *\n * @since 0.3.0\n */\nimport {\n Cause,\n Clock,\n DateTime,\n Duration,\n Effect,\n Exit,\n Fiber,\n FiberHandle,\n FiberMap,\n Option,\n Predicate,\n PubSub,\n Schedule,\n Schema,\n Scope,\n Stream,\n SubscriptionRef,\n type Take,\n} from \"effect\";\n\nimport type * as Browser from \"./Browser.ts\";\nimport * as Lifecycle from \"./internal/supervisor/lifecycle.ts\";\n\nexport {\n Closed,\n Down,\n GenerationState,\n Kept,\n Lost,\n Open,\n Opening,\n Released,\n Reopening,\n Settled,\n Unconfirmed,\n} from \"./internal/supervisor/lifecycle.ts\";\n\n/** One change in a generation's life. `at` is wall-clock epoch milliseconds from the Effect `Clock`. */\nexport class Generation extends Schema.Class<Generation>(\"effect-browser/Generation\")({\n number: Schema.Int.check(Schema.isGreaterThan(0)),\n at: Schema.Finite,\n state: Lifecycle.GenerationState,\n}) {}\n\n/**\n * No browser to give: none opened within `waitTimeout` (`opening`), the latest generation failed\n * to open (`down`, with what it failed with as `cause`), or the supervisor was retired.\n */\nexport class Unavailable extends Schema.TaggedError<Unavailable>()(\"Unavailable\", {\n reason: Schema.Literals([\"opening\", \"down\", \"retired\"]),\n detail: Schema.String,\n cause: Schema.optional(Schema.Defect()),\n}) {\n override get message() {\n return `no browser: ${this.detail}`;\n }\n}\n\n/** One generation, as a provider opened it in the scope the supervisor gave it. */\nexport interface Opened {\n readonly browser: Browser.Service;\n /**\n * End the generation, and say whether the provider confirmed its end. The supervisor asks it\n * before it closes the generation's scope; without it, closing the scope ends the generation,\n * which counts as `Settled`.\n */\n readonly release?: Effect.Effect<Lifecycle.Released> | undefined;\n}\n\nexport interface Options<E, R> {\n /** Opens one generation in the scope it is given. */\n readonly open: Effect.Effect<Opened, E, R>;\n /** When to try a failed open again. Defaults to exponential from 1 second, for 5 minutes. */\n readonly reopen?: Schedule.Schedule<unknown, E> | undefined;\n /**\n * Failures no new try mends, such as a refused key: an open that fails so is `Down` at once.\n * Defaults to none.\n */\n readonly definite?: ((error: E) => boolean) | undefined;\n /**\n * Rotate this long ahead of a generation's `expiresAt`, but no sooner than halfway through its\n * life. Without it, a generation's end is a loss.\n */\n readonly rotateBefore?: Duration.Input | undefined;\n /** Generations must not overlap: a rotation releases the current one before it opens the next. */\n readonly exclusive?: boolean | undefined;\n /**\n * Closing the scope leaves the serving generation running, `Kept`: it closes the generation's\n * scope but never asks `release`. For providers whose scope only disconnects, such as\n * `Browserbase.supervise` with `keep`. `retire` still releases it.\n */\n readonly keep?: boolean | undefined;\n /** How long `browser` and `rotate` wait for a generation to open. Defaults to 2 minutes. */\n readonly waitTimeout?: Duration.Input | undefined;\n}\n\nexport interface Supervisor {\n /** The current generation's browser, waiting up to `waitTimeout` while none is open. */\n readonly browser: Effect.Effect<Browser.Service, Unavailable>;\n /** Each generation's changes, in order. A new reader first gets the latest 64; ends on retiring. */\n readonly states: Stream.Stream<Generation>;\n /** Open the next generation now, or join the one opening, and wait for it. */\n readonly rotate: Effect.Effect<Browser.Service, Unavailable>;\n /** Stop opening at once, release every generation, and wait until each release has finished. */\n readonly retire: Effect.Effect<void>;\n}\n\ninterface Held {\n readonly opened: Opened;\n readonly scope: Scope.Closeable;\n}\n\nconst retired = () => new Unavailable({ reason: \"retired\", detail: \"the supervisor was retired\" });\n\nconst describe = (cause: Cause.Cause<unknown>) => {\n const error = Cause.squash(cause);\n\n return Predicate.isError(error) ? error.message : String(error);\n};\n\n/**\n * Wait up to `waitTimeout` for generation `target`, or for any when it is undefined, as `state`\n * changes.\n */\nconst waitFor = <A extends { readonly opened: Opened }>(\n state: SubscriptionRef.SubscriptionRef<Lifecycle.State<A>>,\n waitTimeout: Duration.Duration,\n target: number | undefined,\n) =>\n SubscriptionRef.changes(state).pipe(\n Stream.map((current) => Lifecycle.resolve(current, target)),\n Stream.filter(Predicate.isNotUndefined),\n Stream.runHead,\n // The state's changes never end, so the first resolution always comes.\n Effect.flatMap(\n Option.match({\n onNone: () => Effect.fail(retired()),\n onSome: (resolution) =>\n resolution._tag === \"Serve\"\n ? Effect.succeed(resolution.live.value.opened.browser)\n : Effect.fail(\n new Unavailable({\n reason: resolution.reason,\n detail: resolution.detail,\n cause: resolution.cause,\n }),\n ),\n }),\n ),\n Effect.timeoutOrElse({\n duration: waitTimeout,\n orElse: () =>\n Effect.fail(\n new Unavailable({\n reason: \"opening\",\n detail: `no generation opened within ${Duration.format(waitTimeout)}`,\n }),\n ),\n }),\n );\n\n/** Sleep until `before` ahead of `expiresAt`, but no sooner than halfway there from now. */\nconst untilRotation = (expiresAt: DateTime.Utc, before: Duration.Duration) =>\n Clock.currentTimeMillis.pipe(\n Effect.flatMap((now) => {\n const left = DateTime.toEpochMillis(expiresAt) - now;\n\n return Effect.sleep(Duration.millis(Math.max(left - Duration.toMillis(before), left / 2, 0)));\n }),\n );\n\n/** Supervise generations of a provider's browser for as long as the scope is open. */\nexport const make = Effect.fn(\"Supervisor.make\")(function* <E, R>(\n options: Options<E, R>,\n): Effect.fn.Return<Supervisor, never, Scope.Scope | Exclude<R, Scope.Scope>> {\n const clock = yield* Clock.Clock;\n const context = yield* Effect.context<Exclude<R, Scope.Scope>>();\n const own = yield* Scope.fork(yield* Effect.scope);\n const exclusive = options.exclusive ?? false;\n const definite = options.definite ?? (() => false);\n\n const reopen: Schedule.Schedule<unknown, E> =\n options.reopen ??\n Schedule.exponential(\"1 second\").pipe(Schedule.upTo({ duration: Duration.minutes(5) }));\n\n const rotateBefore =\n options.rotateBefore === undefined ? undefined : Duration.fromInputUnsafe(options.rotateBefore);\n\n const waitTimeout = Duration.fromInputUnsafe(options.waitTimeout ?? Duration.minutes(2));\n const started = Lifecycle.start<Held>();\n const state = yield* SubscriptionRef.make(started.state);\n const events = yield* PubSub.unbounded<Take.Take<Generation>>({ replay: 64 });\n const opening = yield* FiberHandle.make<unknown, never>();\n const releases = yield* FiberMap.make<number, unknown, never>();\n const runOpen = yield* FiberHandle.runtime(opening)();\n const runRelease = yield* FiberMap.runtime(releases)();\n\n // Each input changes the state under one lock, which also publishes its events and starts its\n // work, so neither can be reordered against another input's.\n const apply = (input: Lifecycle.Input<Held>): Effect.Effect<number | undefined> =>\n SubscriptionRef.modifyEffect(state, (current) => {\n const step = Lifecycle.transition(current, input, exclusive);\n\n return Effect.as(perform(step), [step.reply, step.state] as const);\n }).pipe(Effect.uninterruptible);\n\n const perform = (step: Lifecycle.Step<Held>) =>\n Effect.gen(function* () {\n for (const [number, generation] of step.events)\n PubSub.publishUnsafe(events, [\n new Generation({ number, at: clock.currentTimeMillisUnsafe(), state: generation }),\n ]);\n for (const command of step.commands)\n switch (command._tag) {\n case \"Open\":\n runOpen(openGeneration(command.number, command.after));\n break;\n case \"Watch\":\n yield* Effect.forkIn(\n Effect.provideContext(watch(command.live), context),\n command.live.value.scope,\n );\n break;\n case \"Release\":\n runRelease(command.live.number, release(command.live));\n break;\n case \"Leave\":\n runRelease(command.live.number, Scope.close(command.live.value.scope, Exit.void));\n }\n });\n\n const openOnce = Effect.uninterruptibleMask((restore) =>\n Effect.flatMap(Scope.fork(own), (scope) =>\n restore(options.open.pipe(Scope.provide(scope), Effect.provideContext(context))).pipe(\n Effect.onError((cause) => Scope.close(scope, Exit.failCause(cause))),\n Effect.map((opened): Held => ({ opened, scope })),\n ),\n ),\n );\n\n // Retiring interrupts the open between tries or during one; the provider releases what an\n // interrupted try had made, as its scope closes.\n const openGeneration = (number: number, after: number | undefined) =>\n Effect.uninterruptibleMask((restore) => {\n const previous =\n after === undefined\n ? Effect.void\n : FiberMap.get(releases, after).pipe(\n Effect.flatMap(Option.match({ onNone: () => Effect.void, onSome: Fiber.await })),\n );\n\n const tries = Effect.retry(openOnce, {\n schedule: reopen,\n while: (error) => !definite(error),\n });\n\n return restore(previous.pipe(Effect.andThen(tries))).pipe(\n Effect.exit,\n Effect.flatMap((exit) => {\n if (Exit.isSuccess(exit))\n return apply({ _tag: \"Opened\", live: { number, value: exit.value } });\n\n return Cause.hasInterruptsOnly(exit.cause)\n ? apply({ _tag: \"Abandoned\", number })\n : apply({\n _tag: \"Failed\",\n number,\n detail: describe(exit.cause),\n cause: Cause.squash(exit.cause),\n });\n }),\n );\n });\n\n // A generation's own release loses its browser too, which the transition ignores.\n const watch = (live: Lifecycle.Live<Held>) => {\n const { browser } = live.value.opened;\n\n const loss = browser.disconnected.pipe(\n Effect.flatMap((cause) => apply({ _tag: \"Lost\", number: live.number, cause })),\n );\n\n const rotation =\n browser.expiresAt === undefined || rotateBefore === undefined\n ? Effect.void\n : untilRotation(browser.expiresAt, rotateBefore).pipe(\n Effect.andThen(apply({ _tag: \"Rotate\", due: live.number })),\n );\n\n return Effect.all([loss, rotation], { concurrency: 2, discard: true });\n };\n\n // The provider releases before the scope closes, so what the scope holds, such as a stored\n // context's lease, goes only once the release has reported.\n const release = (live: Lifecycle.Live<Held>) =>\n (live.value.opened.release ?? Effect.succeed(new Lifecycle.Settled())).pipe(\n Effect.catchCause((cause) =>\n Effect.succeed(\n new Lifecycle.Unconfirmed({ detail: `the release failed: ${describe(cause)}` }),\n ),\n ),\n Effect.ensuring(Scope.close(live.value.scope, Exit.void)),\n Effect.flatMap((released) => apply({ _tag: \"Released\", number: live.number, released })),\n );\n\n const end = yield* Effect.cached(PubSub.publish(events, Exit.void));\n\n // Stop at once, end or leave what is open, and wait for every release.\n const stop = (input: Lifecycle.Input<Held>) =>\n apply(input).pipe(\n Effect.andThen(FiberHandle.clear(opening)),\n Effect.andThen(FiberMap.awaitEmpty(releases)),\n Effect.andThen(end),\n Effect.asVoid,\n );\n\n const retire = yield* Effect.cached(stop({ _tag: \"Retire\" }));\n\n yield* Effect.addFinalizer(() => (options.keep === true ? stop({ _tag: \"Keep\" }) : retire));\n yield* perform(started);\n\n return {\n browser: waitFor(state, waitTimeout, undefined),\n states: Stream.fromPubSubTake(events),\n rotate: apply({ _tag: \"Rotate\" }).pipe(\n Effect.flatMap((target) =>\n target === undefined ? Effect.fail(retired()) : waitFor(state, waitTimeout, target),\n ),\n ),\n retire,\n } satisfies Supervisor;\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { c as DisconnectCause } from "./BrowserEvent-DzdNdvoh.mjs";
|
|
2
|
+
import { Service, t as Browser_d_exports } from "./Browser.mjs";
|
|
3
|
+
import { Cause, Duration, Effect, Schedule, Schema, Scope, Stream } from "effect";
|
|
4
|
+
declare namespace lifecycle_d_exports {
|
|
5
|
+
export { Closed, Command, Down, GenerationState, Input, Kept, Live, Lost, Open, Opening, Released, Reopening, Resolution, Settled, State, Step, Unconfirmed, resolve, start, transition };
|
|
6
|
+
}
|
|
7
|
+
declare const Settled_base: Schema.Class<Settled, Schema.TaggedStruct<"Settled", {}>, {}>;
|
|
8
|
+
/** The provider confirmed that the generation's browser ended. */
|
|
9
|
+
declare class Settled extends Settled_base {}
|
|
10
|
+
declare const Unconfirmed_base: Schema.Class<Unconfirmed, Schema.TaggedStruct<"Unconfirmed", {
|
|
11
|
+
readonly detail: Schema.String;
|
|
12
|
+
}>, {}>;
|
|
13
|
+
/** The provider could not confirm the end by its deadline, so the browser may still run, and bill. */
|
|
14
|
+
declare class Unconfirmed extends Unconfirmed_base {}
|
|
15
|
+
declare const Released: Schema.Union<readonly [typeof Settled, typeof Unconfirmed]>;
|
|
16
|
+
type Released = typeof Released.Type;
|
|
17
|
+
declare const Opening_base: Schema.Class<Opening, Schema.TaggedStruct<"Opening", {}>, {}>;
|
|
18
|
+
/** Opening, but not after a loss: the first generation, a rotation, or the one after `Down`. */
|
|
19
|
+
declare class Opening extends Opening_base {}
|
|
20
|
+
declare const Reopening_base: Schema.Class<Reopening, Schema.TaggedStruct<"Reopening", {}>, {}>;
|
|
21
|
+
/** Opening after the generation before it was lost. */
|
|
22
|
+
declare class Reopening extends Reopening_base {}
|
|
23
|
+
declare const Open_base: Schema.Class<Open, Schema.TaggedStruct<"Open", {}>, {}>;
|
|
24
|
+
/** Open: `browser` gives this generation until the next one opens. */
|
|
25
|
+
declare class Open extends Open_base {}
|
|
26
|
+
declare const Lost_base: Schema.Class<Lost, Schema.TaggedStruct<"Lost", {
|
|
27
|
+
readonly cause: Schema.Literals<readonly ["connection", "session", "released"]>;
|
|
28
|
+
}>, {}>;
|
|
29
|
+
/** Lost: its connection dropped, or its provider ended its session, as `cause` says. */
|
|
30
|
+
declare class Lost extends Lost_base {}
|
|
31
|
+
declare const Down_base: Schema.Class<Down, Schema.TaggedStruct<"Down", {
|
|
32
|
+
readonly detail: Schema.String;
|
|
33
|
+
readonly cause: Schema.Defect;
|
|
34
|
+
}>, {}>;
|
|
35
|
+
/**
|
|
36
|
+
* It never opened: its last try failed with `cause`, which the provider deems definite, or after
|
|
37
|
+
* which the reopen schedule gave up.
|
|
38
|
+
*/
|
|
39
|
+
declare class Down extends Down_base {}
|
|
40
|
+
declare const Closed_base: Schema.Class<Closed, Schema.TaggedStruct<"Closed", {
|
|
41
|
+
readonly released: Schema.optional<Schema.Union<readonly [typeof Settled, typeof Unconfirmed]>>;
|
|
42
|
+
}>, {}>;
|
|
43
|
+
/** It ended. `released` says how its release went; one retired while opening has none. */
|
|
44
|
+
declare class Closed extends Closed_base {}
|
|
45
|
+
declare const Kept_base: Schema.Class<Kept, Schema.TaggedStruct<"Kept", {}>, {}>;
|
|
46
|
+
/**
|
|
47
|
+
* It was serving as the supervisor's scope closed, and was left running, not released: its scope
|
|
48
|
+
* closed, and its provider runs it on, and bills, until something adopts and releases it.
|
|
49
|
+
*/
|
|
50
|
+
declare class Kept extends Kept_base {}
|
|
51
|
+
declare const GenerationState: Schema.Union<readonly [typeof Opening, typeof Reopening, typeof Open, typeof Lost, typeof Down, typeof Closed, typeof Kept]>;
|
|
52
|
+
type GenerationState = typeof GenerationState.Type;
|
|
53
|
+
/** A generation that opened: its number, and what the runtime keeps to serve and end it. */
|
|
54
|
+
interface Live<A> {
|
|
55
|
+
readonly number: number;
|
|
56
|
+
readonly value: A;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* At most one generation opens and at most one serves. Both do while a rotation makes the next
|
|
60
|
+
* before it breaks the current, and `Down` keeps serving one that a rotation failed to replace.
|
|
61
|
+
*/
|
|
62
|
+
type State<A> = {
|
|
63
|
+
readonly _tag: "Opening";
|
|
64
|
+
readonly number: number;
|
|
65
|
+
readonly serving: Live<A> | undefined;
|
|
66
|
+
} | {
|
|
67
|
+
readonly _tag: "Open";
|
|
68
|
+
readonly serving: Live<A>;
|
|
69
|
+
} | {
|
|
70
|
+
readonly _tag: "Down";
|
|
71
|
+
readonly number: number;
|
|
72
|
+
readonly detail: string;
|
|
73
|
+
readonly cause: unknown;
|
|
74
|
+
readonly serving: Live<A> | undefined;
|
|
75
|
+
} | {
|
|
76
|
+
readonly _tag: "Retired";
|
|
77
|
+
};
|
|
78
|
+
type Input<A> = {
|
|
79
|
+
readonly _tag: "Opened";
|
|
80
|
+
readonly live: Live<A>;
|
|
81
|
+
} |
|
|
82
|
+
/** The open of `number` failed for good. */
|
|
83
|
+
{
|
|
84
|
+
readonly _tag: "Failed";
|
|
85
|
+
readonly number: number;
|
|
86
|
+
readonly detail: string;
|
|
87
|
+
readonly cause: unknown;
|
|
88
|
+
} |
|
|
89
|
+
/** The open of `number` was stopped, as on retiring, before it opened. */
|
|
90
|
+
{
|
|
91
|
+
readonly _tag: "Abandoned";
|
|
92
|
+
readonly number: number;
|
|
93
|
+
} | {
|
|
94
|
+
readonly _tag: "Lost";
|
|
95
|
+
readonly number: number;
|
|
96
|
+
readonly cause: DisconnectCause;
|
|
97
|
+
} |
|
|
98
|
+
/** A caller asks for the next generation, or the rotation time of `due` came. */
|
|
99
|
+
{
|
|
100
|
+
readonly _tag: "Rotate";
|
|
101
|
+
readonly due?: number | undefined;
|
|
102
|
+
} | {
|
|
103
|
+
readonly _tag: "Retire";
|
|
104
|
+
} |
|
|
105
|
+
/** Stop as `Retire` does, but leave the serving generation running. */
|
|
106
|
+
{
|
|
107
|
+
readonly _tag: "Keep";
|
|
108
|
+
} | {
|
|
109
|
+
readonly _tag: "Released";
|
|
110
|
+
readonly number: number;
|
|
111
|
+
readonly released: Released;
|
|
112
|
+
};
|
|
113
|
+
type Command<A> =
|
|
114
|
+
/** Open `number`, after the release of `after` has finished. */
|
|
115
|
+
{
|
|
116
|
+
readonly _tag: "Open";
|
|
117
|
+
readonly number: number;
|
|
118
|
+
readonly after: number | undefined;
|
|
119
|
+
} |
|
|
120
|
+
/** Watch a generation that opened for its loss and its rotation time. */
|
|
121
|
+
{
|
|
122
|
+
readonly _tag: "Watch";
|
|
123
|
+
readonly live: Live<A>;
|
|
124
|
+
} | {
|
|
125
|
+
readonly _tag: "Release";
|
|
126
|
+
readonly live: Live<A>;
|
|
127
|
+
} |
|
|
128
|
+
/** Close its scope without asking its provider to release it. */
|
|
129
|
+
{
|
|
130
|
+
readonly _tag: "Leave";
|
|
131
|
+
readonly live: Live<A>;
|
|
132
|
+
};
|
|
133
|
+
interface Step<A> {
|
|
134
|
+
readonly state: State<A>;
|
|
135
|
+
/** Generation numbers and their new states, to publish in this order. */
|
|
136
|
+
readonly events: ReadonlyArray<readonly [number, GenerationState]>;
|
|
137
|
+
readonly commands: ReadonlyArray<Command<A>>;
|
|
138
|
+
/** For `Rotate`, the generation to wait for, unless retired. */
|
|
139
|
+
readonly reply?: number | undefined;
|
|
140
|
+
}
|
|
141
|
+
declare const start: <A>() => Step<A>;
|
|
142
|
+
/** The state after `input`, with the events to publish and the commands to run. */
|
|
143
|
+
declare const transition: <A>(state: State<A>, input: Input<A>, exclusive: boolean) => Step<A>;
|
|
144
|
+
type Resolution<A> = {
|
|
145
|
+
readonly _tag: "Serve";
|
|
146
|
+
readonly live: Live<A>;
|
|
147
|
+
} | {
|
|
148
|
+
readonly _tag: "Unavailable";
|
|
149
|
+
readonly reason: "down" | "retired";
|
|
150
|
+
readonly detail: string;
|
|
151
|
+
readonly cause?: unknown;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* What a caller waiting for generation `target`, or for any when it is undefined, gets in
|
|
155
|
+
* `state`; undefined while it should go on waiting.
|
|
156
|
+
*/
|
|
157
|
+
declare const resolve: <A>(state: State<A>, target: number | undefined) => Resolution<A> | undefined;
|
|
158
|
+
declare namespace Supervisor_d_exports {
|
|
159
|
+
export { Closed, Down, Generation, GenerationState, Kept, Lost, Open, Opened, Opening, Options, Released, Reopening, Settled, Supervisor, Unavailable, Unconfirmed, make };
|
|
160
|
+
}
|
|
161
|
+
declare const Generation_base: Schema.Class<Generation, Schema.Struct<{
|
|
162
|
+
readonly number: Schema.Int;
|
|
163
|
+
readonly at: Schema.Finite;
|
|
164
|
+
readonly state: Schema.Union<readonly [typeof Opening, typeof Reopening, typeof Open, typeof Lost, typeof Down, typeof Closed, typeof Kept]>;
|
|
165
|
+
}>, {}>;
|
|
166
|
+
/** One change in a generation's life. `at` is wall-clock epoch milliseconds from the Effect `Clock`. */
|
|
167
|
+
declare class Generation extends Generation_base {}
|
|
168
|
+
declare const Unavailable_base: Schema.Class<Unavailable, Schema.TaggedStruct<"Unavailable", {
|
|
169
|
+
readonly reason: Schema.Literals<readonly ["opening", "down", "retired"]>;
|
|
170
|
+
readonly detail: Schema.String;
|
|
171
|
+
readonly cause: Schema.optional<Schema.Defect>;
|
|
172
|
+
}>, Cause.YieldableError>;
|
|
173
|
+
/**
|
|
174
|
+
* No browser to give: none opened within `waitTimeout` (`opening`), the latest generation failed
|
|
175
|
+
* to open (`down`, with what it failed with as `cause`), or the supervisor was retired.
|
|
176
|
+
*/
|
|
177
|
+
declare class Unavailable extends Unavailable_base {
|
|
178
|
+
get message(): string;
|
|
179
|
+
}
|
|
180
|
+
/** One generation, as a provider opened it in the scope the supervisor gave it. */
|
|
181
|
+
interface Opened {
|
|
182
|
+
readonly browser: Service;
|
|
183
|
+
/**
|
|
184
|
+
* End the generation, and say whether the provider confirmed its end. The supervisor asks it
|
|
185
|
+
* before it closes the generation's scope; without it, closing the scope ends the generation,
|
|
186
|
+
* which counts as `Settled`.
|
|
187
|
+
*/
|
|
188
|
+
readonly release?: Effect.Effect<Released> | undefined;
|
|
189
|
+
}
|
|
190
|
+
interface Options<E, R> {
|
|
191
|
+
/** Opens one generation in the scope it is given. */
|
|
192
|
+
readonly open: Effect.Effect<Opened, E, R>;
|
|
193
|
+
/** When to try a failed open again. Defaults to exponential from 1 second, for 5 minutes. */
|
|
194
|
+
readonly reopen?: Schedule.Schedule<unknown, E> | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* Failures no new try mends, such as a refused key: an open that fails so is `Down` at once.
|
|
197
|
+
* Defaults to none.
|
|
198
|
+
*/
|
|
199
|
+
readonly definite?: ((error: E) => boolean) | undefined;
|
|
200
|
+
/**
|
|
201
|
+
* Rotate this long ahead of a generation's `expiresAt`, but no sooner than halfway through its
|
|
202
|
+
* life. Without it, a generation's end is a loss.
|
|
203
|
+
*/
|
|
204
|
+
readonly rotateBefore?: Duration.Input | undefined;
|
|
205
|
+
/** Generations must not overlap: a rotation releases the current one before it opens the next. */
|
|
206
|
+
readonly exclusive?: boolean | undefined;
|
|
207
|
+
/**
|
|
208
|
+
* Closing the scope leaves the serving generation running, `Kept`: it closes the generation's
|
|
209
|
+
* scope but never asks `release`. For providers whose scope only disconnects, such as
|
|
210
|
+
* `Browserbase.supervise` with `keep`. `retire` still releases it.
|
|
211
|
+
*/
|
|
212
|
+
readonly keep?: boolean | undefined;
|
|
213
|
+
/** How long `browser` and `rotate` wait for a generation to open. Defaults to 2 minutes. */
|
|
214
|
+
readonly waitTimeout?: Duration.Input | undefined;
|
|
215
|
+
}
|
|
216
|
+
interface Supervisor {
|
|
217
|
+
/** The current generation's browser, waiting up to `waitTimeout` while none is open. */
|
|
218
|
+
readonly browser: Effect.Effect<Service, Unavailable>;
|
|
219
|
+
/** Each generation's changes, in order. A new reader first gets the latest 64; ends on retiring. */
|
|
220
|
+
readonly states: Stream.Stream<Generation>;
|
|
221
|
+
/** Open the next generation now, or join the one opening, and wait for it. */
|
|
222
|
+
readonly rotate: Effect.Effect<Service, Unavailable>;
|
|
223
|
+
/** Stop opening at once, release every generation, and wait until each release has finished. */
|
|
224
|
+
readonly retire: Effect.Effect<void>;
|
|
225
|
+
}
|
|
226
|
+
/** Supervise generations of a provider's browser for as long as the scope is open. */
|
|
227
|
+
declare const make: <E, R>(options: Options<E, R>) => Effect.Effect<Supervisor, never, Scope.Scope | Exclude<R, Scope.Scope>>;
|
|
228
|
+
//#endregion
|
|
229
|
+
export { Settled as _, Supervisor_d_exports as a, Closed as c, Kept as d, Lost as f, Reopening as g, Released as h, Supervisor as i, Down as l, Opening as m, Opened as n, Unavailable as o, Open as p, Options as r, make as s, Generation as t, GenerationState as u, Unconfirmed as v };
|
|
230
|
+
//# sourceMappingURL=Supervisor-Im6-wbg5.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { _ as Settled, c as Closed, d as Kept, f as Lost, g as Reopening, h as Released, i as Supervisor, l as Down, m as Opening, n as Opened, o as Unavailable, p as Open, r as Options, s as make, t as Generation, u as GenerationState, v as Unconfirmed } from "./Supervisor-Im6-wbg5.mjs";
|
|
2
|
+
export { Closed, Down, Generation, GenerationState, Kept, Lost, Open, Opened, Opening, Options, Released, Reopening, Settled, Supervisor, Unavailable, Unconfirmed, make };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as Closed, c as Kept, d as Opening, f as Released, h as Unconfirmed, i as make, l as Lost, m as Settled, o as Down, p as Reopening, r as Unavailable, s as GenerationState, t as Generation, u as Open } from "./Supervisor-BtEG93gR.mjs";
|
|
2
|
+
export { Closed, Down, Generation, GenerationState, Kept, Lost, Open, Opening, Released, Reopening, Settled, Unavailable, Unconfirmed, make };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { BrowserError, Closed, Failed, Timeout } from "./BrowserError.mjs";
|
|
2
|
+
import { a as redactWithin, l as make$1 } from "./url-CcL0K7S0.mjs";
|
|
3
|
+
import { Clock, Context, Duration, Effect, Fiber, MutableRef, Option, Schema } from "effect";
|
|
4
|
+
//#region src/internal/page/context.ts
|
|
5
|
+
/**
|
|
6
|
+
* What a page's parts share: the browser state they act on, the page's own lane, pointer and
|
|
7
|
+
* clock, and how they call the browser and report its failures. The assembly in `page.ts` builds
|
|
8
|
+
* one context per page.
|
|
9
|
+
*/
|
|
10
|
+
const messageOf = (cause) => cause instanceof Error ? cause.message : typeof cause === "string" ? cause : "unknown error";
|
|
11
|
+
const closedPattern = /has been closed|Target closed|Session closed|browser has disconnected|Target page, context or browser/i;
|
|
12
|
+
/**
|
|
13
|
+
* Map a Playwright or protocol failure to a reason, `Closed` with `closed` as its cause for a page
|
|
14
|
+
* or browser that is gone. A call that gives Playwright a timeout passes the same bound, so its
|
|
15
|
+
* `Timeout` reports it; without one, Playwright's own message stays.
|
|
16
|
+
*/
|
|
17
|
+
const reasonOf = (cause, timeoutMillis, closed = "connection") => {
|
|
18
|
+
const message = messageOf(cause);
|
|
19
|
+
if (closedPattern.test(message)) return new Closed({ cause: closed });
|
|
20
|
+
if (cause instanceof Error && cause.name === "TimeoutError" && timeoutMillis !== void 0) return new Timeout({ millis: timeoutMillis });
|
|
21
|
+
const line = message.split("\n")[0] ?? message;
|
|
22
|
+
return new Failed({ detail: redactWithin(line.replace(/^[\w.]+: /, "")) });
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* One Playwright or protocol call, failing undispatched. A closed page says why it is gone as the
|
|
26
|
+
* browser knows then: the library's own calls fail with the browser's loss, and Playwright fails
|
|
27
|
+
* its calls on a dropped connection after reporting the context closed.
|
|
28
|
+
*/
|
|
29
|
+
const call = (operation, run, closedBy, timeoutMillis) => Effect.tryPromise({
|
|
30
|
+
try: run,
|
|
31
|
+
catch: (cause) => undispatched(operation, reasonOf(cause, timeoutMillis, closedBy()))
|
|
32
|
+
});
|
|
33
|
+
const contextGone = (error) => error.reason._tag === "Failed" && /Cannot find context|Execution context was destroyed|__effectBrowser|Inspected target navigated/i.test(error.reason.detail);
|
|
34
|
+
/** The cost of the page operation the current fiber runs, if any. */
|
|
35
|
+
const CurrentCost = Context.Reference("effect-browser/internal/page/CurrentCost", { defaultValue: () => void 0 });
|
|
36
|
+
const sizeOf = (value) => value === void 0 ? 0 : Buffer.byteLength(JSON.stringify(value));
|
|
37
|
+
/** A failure of `operation` before any of its input reached the browser. */
|
|
38
|
+
const undispatched = (operation, reason) => new BrowserError({
|
|
39
|
+
operation,
|
|
40
|
+
reason,
|
|
41
|
+
dispatched: false
|
|
42
|
+
});
|
|
43
|
+
const failWith = (operation, reason) => Effect.fail(undispatched(operation, reason));
|
|
44
|
+
const decodeWith = (operation, schema) => (value) => Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((error) => undispatched(operation, new Failed({ detail: error.message }))));
|
|
45
|
+
const make = (options, scope) => {
|
|
46
|
+
const { id, clock } = options;
|
|
47
|
+
const now = () => Number(clock.monotonicTimeNanosUnsafe()) / 1e6;
|
|
48
|
+
const owned = Effect.provideService(Clock.Clock, clock);
|
|
49
|
+
const span = (name, attributes = {}, level) => (effect) => Effect.gen(function* () {
|
|
50
|
+
const cost = {
|
|
51
|
+
enclosing: yield* CurrentCost,
|
|
52
|
+
calls: 0,
|
|
53
|
+
bytesOut: 0,
|
|
54
|
+
bytesIn: 0,
|
|
55
|
+
waitedMillis: 0,
|
|
56
|
+
awaiting: 0,
|
|
57
|
+
awaitingSince: 0
|
|
58
|
+
};
|
|
59
|
+
return yield* effect.pipe(Effect.provideService(CurrentCost, cost), Effect.ensuring(Effect.suspend(() => Effect.annotateCurrentSpan({
|
|
60
|
+
calls: cost.calls,
|
|
61
|
+
bytesOut: cost.bytesOut,
|
|
62
|
+
bytesIn: cost.bytesIn,
|
|
63
|
+
waitedMillis: Math.round(cost.waitedMillis * 10) / 10
|
|
64
|
+
}))));
|
|
65
|
+
}).pipe(Effect.withSpan(name, {
|
|
66
|
+
attributes: {
|
|
67
|
+
page: id,
|
|
68
|
+
...attributes
|
|
69
|
+
},
|
|
70
|
+
...level === void 0 ? {} : { level }
|
|
71
|
+
}, { captureStackTrace: false }));
|
|
72
|
+
const send = (method, params) => {
|
|
73
|
+
const cost = Fiber.getCurrent()?.getRef(CurrentCost);
|
|
74
|
+
const sentAt = now();
|
|
75
|
+
const bytesOut = sizeOf(params);
|
|
76
|
+
for (let each = cost; each !== void 0; each = each.enclosing) {
|
|
77
|
+
each.calls++;
|
|
78
|
+
each.bytesOut += bytesOut;
|
|
79
|
+
if (each.awaiting++ === 0) each.awaitingSince = sentAt;
|
|
80
|
+
}
|
|
81
|
+
const reply = options.untilLost(options.cdp.send(method, params));
|
|
82
|
+
if (cost === void 0) return reply;
|
|
83
|
+
const settle = (bytesIn) => {
|
|
84
|
+
const at = now();
|
|
85
|
+
for (let each = cost; each !== void 0; each = each.enclosing) {
|
|
86
|
+
each.bytesIn += bytesIn;
|
|
87
|
+
if (--each.awaiting === 0) each.waitedMillis += at - each.awaitingSince;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
return reply.then((result) => {
|
|
91
|
+
settle(sizeOf(result));
|
|
92
|
+
return result;
|
|
93
|
+
}, (cause) => {
|
|
94
|
+
settle(0);
|
|
95
|
+
return Promise.reject(cause);
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
const native = (operation, run, timeoutMillis) => call(operation, run, options.closedBy, timeoutMillis);
|
|
99
|
+
/** Fail with `Timeout` once `duration` has passed, the action timeout unless another is given. */
|
|
100
|
+
const within = (operation, duration = options.settings.actionTimeout) => (effect) => Effect.timeoutOrElse(effect, {
|
|
101
|
+
duration,
|
|
102
|
+
orElse: () => failWith(operation, new Timeout({ millis: Duration.toMillis(duration) }))
|
|
103
|
+
});
|
|
104
|
+
const activity = {
|
|
105
|
+
inputAt: 0,
|
|
106
|
+
documentAt: Number.NEGATIVE_INFINITY
|
|
107
|
+
};
|
|
108
|
+
const noteInput = () => {
|
|
109
|
+
activity.inputAt = Math.max(activity.inputAt, now());
|
|
110
|
+
};
|
|
111
|
+
const lane = make$1({
|
|
112
|
+
now,
|
|
113
|
+
actionTimeout: options.settings.actionTimeout,
|
|
114
|
+
documentAt: () => activity.documentAt,
|
|
115
|
+
gone: (operation) => undispatched(operation, new Closed({ cause: options.closedBy() })),
|
|
116
|
+
scope
|
|
117
|
+
});
|
|
118
|
+
const pointer = MutableRef.make(Option.none());
|
|
119
|
+
const protocol = { send };
|
|
120
|
+
return {
|
|
121
|
+
...options,
|
|
122
|
+
lane,
|
|
123
|
+
pointer,
|
|
124
|
+
now,
|
|
125
|
+
owned,
|
|
126
|
+
span,
|
|
127
|
+
protocol,
|
|
128
|
+
native,
|
|
129
|
+
within,
|
|
130
|
+
activity,
|
|
131
|
+
noteInput
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
//#endregion
|
|
135
|
+
export { make as a, failWith as i, contextGone as n, reasonOf as o, decodeWith as r, undispatched as s, call as t };
|
|
136
|
+
|
|
137
|
+
//# sourceMappingURL=context-DAYjATgC.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-DAYjATgC.mjs","names":["Url.redactWithin","Lane.make"],"sources":["../src/internal/page/context.ts"],"sourcesContent":["/**\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 * 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 /** 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 /** 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// 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 = () => Number(clock.monotonicTimeNanosUnsafe()) / 1e6;\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 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 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 // 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, 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 // 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 });\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 activity,\n noteInput,\n };\n};\n\nexport type PageContext = ReturnType<typeof make>;\n"],"mappings":";;;;;;;;;AAsEA,MAAM,aAAa,UACjB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,UAAU,WAAW,QAAQ;AAE/E,MAAM,gBACJ;;;;;;AAOF,MAAa,YACX,OACA,eACA,SAAsB,iBACX;CACX,MAAM,UAAU,UAAU,KAAK;CAE/B,IAAI,cAAc,KAAK,OAAO,GAAG,OAAO,IAAI,OAAO,EAAE,OAAO,OAAO,CAAC;CACpE,IAAI,iBAAiB,SAAS,MAAM,SAAS,kBAAkB,kBAAkB,KAAA,GAC/E,OAAO,IAAI,QAAQ,EAAE,QAAQ,cAAc,CAAC;CAC9C,MAAM,OAAO,QAAQ,MAAM,IAAI,CAAC,CAAC,MAAM;CAEvC,OAAO,IAAI,OAAO,EAAE,QAAQA,aAAiB,KAAK,QAAQ,aAAa,EAAE,CAAC,EAAE,CAAC;AAC/E;;;;;;AAOA,MAAa,QACX,WACA,KACA,UACA,kBAEA,OAAO,WAAW;CAChB,KAAK;CACL,QAAQ,UAAU,aAAa,WAAW,SAAS,OAAO,eAAe,SAAS,CAAC,CAAC;AACtF,CAAC;AAEH,MAAa,eAAe,UAC1B,MAAM,OAAO,SAAS,YACtB,kGAAkG,KAChG,MAAM,OAAO,MACf;;AAkBF,MAAM,cAAc,QAAQ,UAC1B,4CACA,EACE,oBAAoB,KAAA,EACtB,CACF;AAGA,MAAM,UAAU,UACd,UAAU,KAAA,IAAY,IAAI,OAAO,WAAW,KAAK,UAAU,KAAK,CAAC;;AAGnE,MAAa,gBAAgB,WAAmB,WAC9C,IAAI,aAAa;CAAE;CAAW;CAAQ,YAAY;AAAM,CAAC;AAE3D,MAAa,YAAY,WAAmB,WAC1C,OAAO,KAAK,aAAa,WAAW,MAAM,CAAC;AAE7C,MAAa,cACP,WAAmB,YACtB,UACC,OAAO,oBAAoB,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KACxC,OAAO,UAAU,UAAU,aAAa,WAAW,IAAI,OAAO,EAAE,QAAQ,MAAM,QAAQ,CAAC,CAAC,CAAC,CAC3F;AAEJ,MAAa,QAAQ,SAAsB,UAAuB;CAChE,MAAM,EAAE,IAAI,UAAU;CACtB,MAAM,YAAY,OAAO,MAAM,yBAAyB,CAAC,IAAI;CAG7D,MAAM,QAAQ,OAAO,eAAe,MAAM,OAAO,KAAK;CAKtD,MAAM,QACH,MAAc,aAAsC,CAAC,GAAG,WAC/C,WACR,OAAO,IAAI,aAAa;EACtB,MAAM,OAAa;GACjB,WAAW,OAAO;GAClB,OAAO;GACP,UAAU;GACV,SAAS;GACT,cAAc;GACd,UAAU;GACV,eAAe;EACjB;EAEA,OAAO,OAAO,OAAO,KACnB,OAAO,eAAe,aAAa,IAAI,GACvC,OAAO,SACL,OAAO,cACL,OAAO,oBAAoB;GACzB,OAAO,KAAK;GACZ,UAAU,KAAK;GACf,SAAS,KAAK;GACd,cAAc,KAAK,MAAM,KAAK,eAAe,EAAE,IAAI;EACrD,CAAC,CACH,CACF,CACF;CACF,CAAC,CAAC,CAAC,KACD,OAAO,SACL,MACA;EAAE,YAAY;GAAE,MAAM;GAAI,GAAG;EAAW;EAAG,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;CAAG,GACrF,EAAE,mBAAmB,MAAM,CAC7B,CACF;CAKJ,MAAM,QAA4B,QAAQ,WAAW;EACnD,MAAM,OAAO,MAAM,WAAW,CAAC,EAAE,OAAO,WAAW;EACnD,MAAM,SAAS,IAAI;EACnB,MAAM,WAAW,OAAO,MAAM;EAE9B,KAAK,IAAI,OAAO,MAAM,SAAS,KAAA,GAAW,OAAO,KAAK,WAAW;GAC/D,KAAK;GACL,KAAK,YAAY;GACjB,IAAI,KAAK,eAAe,GAAG,KAAK,gBAAgB;EAClD;EACA,MAAM,QAAQ,QAAQ,UAAU,QAAQ,IAAI,KAAK,QAAQ,MAAM,CAAC;EAEhE,IAAI,SAAS,KAAA,GAAW,OAAO;EAE/B,MAAM,UAAU,YAAoB;GAClC,MAAM,KAAK,IAAI;GAEf,KAAK,IAAI,OAAyB,MAAM,SAAS,KAAA,GAAW,OAAO,KAAK,WAAW;IACjF,KAAK,WAAW;IAChB,IAAI,EAAE,KAAK,aAAa,GAAG,KAAK,gBAAgB,KAAK,KAAK;GAC5D;EACF;EAEA,OAAO,MAAM,MACV,WAAW;GACV,OAAO,OAAO,MAAM,CAAC;GAErB,OAAO;EACT,IACC,UAAmB;GAClB,OAAO,CAAC;GAER,OAAO,QAAQ,OAAO,KAAK;EAC7B,CACF;CACF;CAIA,MAAM,UAAa,WAAmB,KAAuB,kBAC3D,KAAK,WAAW,KAAK,QAAQ,UAAU,aAAa;;CAGtD,MAAM,UACH,WAAmB,WAA2B,QAAQ,SAAS,mBACtD,WACR,OAAO,cAAc,QAAQ;EAC3B;EACA,cAAc,SAAS,WAAW,IAAI,QAAQ,EAAE,QAAQ,SAAS,SAAS,QAAQ,EAAE,CAAC,CAAC;CACxF,CAAC;CAQL,MAAM,WAAW;EAAE,SAAS;EAAG,YAAY,OAAO;CAAkB;CAEpE,MAAM,kBAAkB;EACtB,SAAS,UAAU,KAAK,IAAI,SAAS,SAAS,IAAI,CAAC;CACrD;CAEA,MAAM,OAAOC,OAAU;EACrB;EACA,eAAe,QAAQ,SAAS;EAChC,kBAAkB,SAAS;EAC3B,OAAO,cAAc,aAAa,WAAW,IAAI,OAAO,EAAE,OAAO,QAAQ,SAAS,EAAE,CAAC,CAAC;EACtF;CACF,CAAC;CAKD,MAAM,UAAU,WAAW,KAAK,OAAO,KAAY,CAAC;CAGpD,MAAM,WAAqC,EAAE,KAAK;CAElD,OAAO;EACL,GAAG;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import { n as BrowserError_d_exports } from "./BrowserError-DXXIA6Rk.mjs";
|
|
2
|
+
import { a as BrowserEvent_d_exports } from "./BrowserEvent-DzdNdvoh.mjs";
|
|
3
|
+
import { n as Change_d_exports } from "./Change-DVP2IJWm.mjs";
|
|
4
|
+
import { i as Frame_d_exports } from "./Frame-BERmf_gM.mjs";
|
|
5
|
+
import { i as Snapshot_d_exports } from "./Snapshot-B34hZ4Jl.mjs";
|
|
6
|
+
import { N as Moment_d_exports, d as Page_d_exports } from "./Page-DYTdVhYa.mjs";
|
|
7
|
+
import { t as Browser_d_exports } from "./Browser.mjs";
|
|
8
|
+
import { t as Cdp_d_exports } from "./Cdp.mjs";
|
|
9
|
+
import { t as Chromium_d_exports } from "./Chromium.mjs";
|
|
10
|
+
import { t as Expect_d_exports } from "./Expect.mjs";
|
|
11
|
+
import { t as Motion_d_exports } from "./Motion.mjs";
|
|
12
|
+
import { n as Plan_d_exports } from "./Plan-CNNOU1Tx.mjs";
|
|
13
|
+
import { t as Policy_d_exports } from "./Policy.mjs";
|
|
14
|
+
import { t as Presentation_d_exports } from "./Presentation.mjs";
|
|
15
|
+
import { t as Stage_d_exports } from "./Stage.mjs";
|
|
16
|
+
import { a as Supervisor_d_exports } from "./Supervisor-Im6-wbg5.mjs";
|
|
17
|
+
export { Browser_d_exports as Browser, BrowserError_d_exports as BrowserError, BrowserEvent_d_exports as BrowserEvent, Cdp_d_exports as Cdp, Change_d_exports as Change, Chromium_d_exports as Chromium, Expect_d_exports as Expect, Frame_d_exports as Frame, Moment_d_exports as Moment, Motion_d_exports as Motion, Page_d_exports as Page, Plan_d_exports as Plan, Policy_d_exports as Policy, Presentation_d_exports as Presentation, Snapshot_d_exports as Snapshot, Stage_d_exports as Stage, Supervisor_d_exports as Supervisor };
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
|
|
1
|
+
import { t as Motion_exports } from "./Motion.mjs";
|
|
2
|
+
import { t as BrowserEvent_exports } from "./BrowserEvent.mjs";
|
|
3
|
+
import { t as BrowserError_exports } from "./BrowserError.mjs";
|
|
4
|
+
import { n as Browser_exports } from "./Browser-B5AV7zPS.mjs";
|
|
5
|
+
import { t as Frame_exports } from "./Frame.mjs";
|
|
6
|
+
import { a as Page_exports } from "./Page-D4281dIi.mjs";
|
|
7
|
+
import { t as Snapshot_exports } from "./Snapshot.mjs";
|
|
8
|
+
import { n as Change_exports } from "./Change-DNvztNLu.mjs";
|
|
9
|
+
import { t as Moment_exports } from "./Moment.mjs";
|
|
10
|
+
import { t as Cdp_exports } from "./Cdp.mjs";
|
|
11
|
+
import { t as Chromium_exports } from "./Chromium.mjs";
|
|
12
|
+
import { t as Expect_exports } from "./Expect.mjs";
|
|
13
|
+
import { n as Plan_exports } from "./Plan-5MdsRzE5.mjs";
|
|
14
|
+
import { t as Policy_exports } from "./Policy.mjs";
|
|
15
|
+
import { t as Presentation_exports } from "./Presentation.mjs";
|
|
16
|
+
import { t as Stage_exports } from "./Stage.mjs";
|
|
17
|
+
import { n as Supervisor_exports } from "./Supervisor-BtEG93gR.mjs";
|
|
18
|
+
export { Browser_exports as Browser, BrowserError_exports as BrowserError, BrowserEvent_exports as BrowserEvent, Cdp_exports as Cdp, Change_exports as Change, Chromium_exports as Chromium, Expect_exports as Expect, Frame_exports as Frame, Moment_exports as Moment, Motion_exports as Motion, Page_exports as Page, Plan_exports as Plan, Policy_exports as Policy, Presentation_exports as Presentation, Snapshot_exports as Snapshot, Stage_exports as Stage, Supervisor_exports as Supervisor };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region src/internal/reading/match.inpage.ts
|
|
2
|
+
const match = () => {
|
|
3
|
+
/**
|
|
4
|
+
* How names, text and context compare: one Unicode form, without invisible format characters,
|
|
5
|
+
* spaces collapsed, and case folded upper first, so that "ß" and "SS" read the same.
|
|
6
|
+
*/
|
|
7
|
+
const normalize = (value) => value.normalize("NFKC").replace(/\p{Cf}/gu, "").replace(/\s+/g, " ").trim().toUpperCase().toLowerCase();
|
|
8
|
+
/** A string that reads the same, or, unless `whole`, appears within; or a pattern found within. */
|
|
9
|
+
const rule = (wanted, whole) => {
|
|
10
|
+
if (typeof wanted !== "string") {
|
|
11
|
+
const found = new RegExp(wanted.source, wanted.flags.replace(/[gy]/g, ""));
|
|
12
|
+
return (value) => found.test(value.replace(/\s+/g, " ").trim());
|
|
13
|
+
}
|
|
14
|
+
const target = normalize(wanted);
|
|
15
|
+
return whole ? (value) => normalize(value) === target : (value) => normalize(value).includes(target);
|
|
16
|
+
};
|
|
17
|
+
/** Whether a value's words appear, whole and in order, among a text's: "BTC" not in "WBTC". */
|
|
18
|
+
const holds = (text, value) => ` ${normalize(text)} `.includes(` ${normalize(value)} `);
|
|
19
|
+
/** Whether a candidate meets every rule a query gives; a rule left out always holds. */
|
|
20
|
+
const compile = (request) => {
|
|
21
|
+
const role = request.role === null ? null : normalize(request.role);
|
|
22
|
+
const name = request.name === null ? null : rule(request.name, true);
|
|
23
|
+
const text = request.text === null ? null : rule(request.text, false);
|
|
24
|
+
const { near } = request;
|
|
25
|
+
return (candidate) => {
|
|
26
|
+
if (role !== null && normalize(candidate.role ?? "") !== role) return false;
|
|
27
|
+
if (text !== null && !text(candidate.text())) return false;
|
|
28
|
+
if (name !== null && !name(candidate.name())) return false;
|
|
29
|
+
if (near === null) return true;
|
|
30
|
+
const { row, column, label, heading } = candidate.context();
|
|
31
|
+
return [
|
|
32
|
+
row,
|
|
33
|
+
column,
|
|
34
|
+
label,
|
|
35
|
+
heading
|
|
36
|
+
].some((value) => value !== void 0 && holds(value, near));
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
compile,
|
|
41
|
+
holds,
|
|
42
|
+
normalize
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { match as t };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=match.inpage-xOe9LNO0.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.inpage-xOe9LNO0.mjs","names":[],"sources":["../src/internal/reading/match.inpage.ts"],"sourcesContent":["/**\n * In the page: the rules `find` matches by. It touches no DOM, so it also runs outside a page.\n *\n * - A role matches when it is the same token, ignoring case and the space around it.\n * - A name given as a string matches when the two read the same once their spaces are collapsed,\n * their case folded and their characters given one Unicode form; a pattern matches when it\n * finds itself in the name.\n * - Text matches when it appears, read the same way, in the element's text.\n * - `near` matches when its words appear, whole and in order, in any of the element's context:\n * its row, column, label or heading. Replay chooses among candidates by the same rule.\n */\nimport type { SubjectContext } from \"../../BrowserEvent.ts\";\n\n/** A string, or a pattern sent to the page as its source and flags. */\nexport type Wanted = string | { readonly source: string; readonly flags: string };\n\nexport interface FindRequest {\n readonly role: string | null;\n readonly name: Wanted | null;\n readonly text: Wanted | null;\n readonly near: string | null;\n readonly at: { readonly x: number; readonly y: number } | null;\n readonly scope: \"viewport\" | \"document\";\n readonly firstRef: number;\n}\n\n/** What a query is matched against, read only when a rule needs it. */\nexport interface Candidate {\n readonly role: string | null;\n readonly name: () => string;\n readonly text: () => string;\n readonly context: () => SubjectContext;\n}\n\nexport const match = () => {\n /**\n * How names, text and context compare: one Unicode form, without invisible format characters,\n * spaces collapsed, and case folded upper first, so that \"ß\" and \"SS\" read the same.\n */\n const normalize = (value: string): string =>\n value\n .normalize(\"NFKC\")\n .replace(/\\p{Cf}/gu, \"\")\n .replace(/\\s+/g, \" \")\n .trim()\n .toUpperCase()\n .toLowerCase();\n\n /** A string that reads the same, or, unless `whole`, appears within; or a pattern found within. */\n const rule = (wanted: Wanted, whole: boolean) => {\n if (typeof wanted !== \"string\") {\n // `g` and `y` keep a position from one test to the next, so one pattern would answer\n // differently for each element. A pattern is tried on the text as the page shows it.\n const found = new RegExp(wanted.source, wanted.flags.replace(/[gy]/g, \"\"));\n\n return (value: string) => found.test(value.replace(/\\s+/g, \" \").trim());\n }\n const target = normalize(wanted);\n\n return whole\n ? (value: string) => normalize(value) === target\n : (value: string) => normalize(value).includes(target);\n };\n\n /** Whether a value's words appear, whole and in order, among a text's: \"BTC\" not in \"WBTC\". */\n const holds = (text: string, value: string) =>\n ` ${normalize(text)} `.includes(` ${normalize(value)} `);\n\n /** Whether a candidate meets every rule a query gives; a rule left out always holds. */\n const compile = (request: Pick<FindRequest, \"role\" | \"name\" | \"text\" | \"near\">) => {\n const role = request.role === null ? null : normalize(request.role);\n const name = request.name === null ? null : rule(request.name, true);\n const text = request.text === null ? null : rule(request.text, false);\n const { near } = request;\n\n return (candidate: Candidate): boolean => {\n if (role !== null && normalize(candidate.role ?? \"\") !== role) return false;\n if (text !== null && !text(candidate.text())) return false;\n if (name !== null && !name(candidate.name())) return false;\n if (near === null) return true;\n const { row, column, label, heading } = candidate.context();\n\n return [row, column, label, heading].some(\n (value) => value !== undefined && holds(value, near),\n );\n };\n };\n\n return { compile, holds, normalize };\n};\n\nexport type Match = ReturnType<typeof match>;\n"],"mappings":";AAkCA,MAAa,cAAc;;;;;CAKzB,MAAM,aAAa,UACjB,MACG,UAAU,MAAM,CAAC,CACjB,QAAQ,YAAY,EAAE,CAAC,CACvB,QAAQ,QAAQ,GAAG,CAAC,CACpB,KAAK,CAAC,CACN,YAAY,CAAC,CACb,YAAY;;CAGjB,MAAM,QAAQ,QAAgB,UAAmB;EAC/C,IAAI,OAAO,WAAW,UAAU;GAG9B,MAAM,QAAQ,IAAI,OAAO,OAAO,QAAQ,OAAO,MAAM,QAAQ,SAAS,EAAE,CAAC;GAEzE,QAAQ,UAAkB,MAAM,KAAK,MAAM,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC;EACxE;EACA,MAAM,SAAS,UAAU,MAAM;EAE/B,OAAO,SACF,UAAkB,UAAU,KAAK,MAAM,UACvC,UAAkB,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM;CACzD;;CAGA,MAAM,SAAS,MAAc,UAC3B,IAAI,UAAU,IAAI,EAAE,GAAG,SAAS,IAAI,UAAU,KAAK,EAAE,EAAE;;CAGzD,MAAM,WAAW,YAAkE;EACjF,MAAM,OAAO,QAAQ,SAAS,OAAO,OAAO,UAAU,QAAQ,IAAI;EAClE,MAAM,OAAO,QAAQ,SAAS,OAAO,OAAO,KAAK,QAAQ,MAAM,IAAI;EACnE,MAAM,OAAO,QAAQ,SAAS,OAAO,OAAO,KAAK,QAAQ,MAAM,KAAK;EACpE,MAAM,EAAE,SAAS;EAEjB,QAAQ,cAAkC;GACxC,IAAI,SAAS,QAAQ,UAAU,UAAU,QAAQ,EAAE,MAAM,MAAM,OAAO;GACtE,IAAI,SAAS,QAAQ,CAAC,KAAK,UAAU,KAAK,CAAC,GAAG,OAAO;GACrD,IAAI,SAAS,QAAQ,CAAC,KAAK,UAAU,KAAK,CAAC,GAAG,OAAO;GACrD,IAAI,SAAS,MAAM,OAAO;GAC1B,MAAM,EAAE,KAAK,QAAQ,OAAO,YAAY,UAAU,QAAQ;GAE1D,OAAO;IAAC;IAAK;IAAQ;IAAO;GAAO,CAAC,CAAC,MAClC,UAAU,UAAU,KAAA,KAAa,MAAM,OAAO,IAAI,CACrD;EACF;CACF;CAEA,OAAO;EAAE;EAAS;EAAO;CAAU;AACrC"}
|