effect-browser 0.2.0-beta.9 → 0.3.0-beta.11
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 +861 -1161
- package/dist/Browser-B4qncxe7.mjs +628 -0
- package/dist/Browser-B4qncxe7.mjs.map +1 -0
- package/dist/Browser.d.mts +129 -3
- package/dist/Browser.mjs +2 -22
- package/dist/BrowserError-Coy7EW1N.d.mts +140 -0
- package/dist/BrowserError.d.mts +2 -0
- package/dist/BrowserError.mjs +211 -0
- package/dist/BrowserError.mjs.map +1 -0
- package/dist/BrowserEvent-BRu2juEz.d.mts +279 -0
- package/dist/BrowserEvent.d.mts +2 -0
- package/dist/BrowserEvent.mjs +297 -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-iMlcuzVD.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-Di2PxyF7.d.mts +119 -0
- package/dist/Frame.d.mts +2 -0
- package/dist/Frame.mjs +125 -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-B5cjaUp5.mjs +618 -0
- package/dist/Page-B5cjaUp5.mjs.map +1 -0
- package/dist/Page-B7X6DQUn.d.mts +595 -0
- package/dist/Page.d.mts +2 -0
- package/dist/Page.mjs +2 -0
- package/dist/Plan-Akcac63g.d.mts +209 -0
- package/dist/Plan-D1wrJVs8.mjs +508 -0
- package/dist/Plan-D1wrJVs8.mjs.map +1 -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 +64 -0
- package/dist/Stage.mjs +237 -0
- package/dist/Stage.mjs.map +1 -0
- package/dist/Supervisor-CYWFK3vM.d.mts +280 -0
- package/dist/Supervisor-TNKNOVzu.mjs +599 -0
- package/dist/Supervisor-TNKNOVzu.mjs.map +1 -0
- package/dist/Supervisor.d.mts +2 -0
- package/dist/Supervisor.mjs +2 -0
- package/dist/context-B6xr8nVi.mjs +261 -0
- package/dist/context-B6xr8nVi.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-BAf__WKX.mjs +5075 -0
- package/dist/page-BAf__WKX.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/url-Cd04Okid.mjs +264 -0
- package/dist/url-Cd04Okid.mjs.map +1 -0
- package/package.json +96 -61
- package/src/Browser.ts +672 -0
- package/src/BrowserError.ts +234 -0
- package/src/BrowserEvent.ts +296 -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 +132 -0
- package/src/Moment.ts +479 -0
- package/src/Motion.ts +166 -0
- package/src/Page.ts +522 -0
- package/src/Plan.ts +663 -0
- package/src/Policy.ts +325 -0
- package/src/Presentation.ts +195 -0
- package/src/Snapshot.ts +89 -0
- package/src/Stage.ts +467 -0
- package/src/Supervisor.ts +599 -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/gate.ts +224 -0
- package/src/internal/input/guard.inpage.ts +605 -0
- package/src/internal/input/guard.ts +184 -0
- package/src/internal/input/keyboard.ts +112 -0
- package/src/internal/input/keys.ts +127 -0
- package/src/internal/input/perform.ts +376 -0
- package/src/internal/input/pointer.ts +153 -0
- package/src/internal/input/replies.ts +195 -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 +391 -0
- package/src/internal/page/context.ts +314 -0
- package/src/internal/page/identity.ts +35 -0
- package/src/internal/page/lane.ts +311 -0
- package/src/internal/page/navigation.ts +183 -0
- package/src/internal/page/openings.ts +87 -0
- package/src/internal/page/page.ts +165 -0
- package/src/internal/page/url.ts +100 -0
- package/src/internal/page/viewport.ts +43 -0
- package/src/internal/pictures/capture.ts +776 -0
- package/src/internal/pictures/clock.ts +141 -0
- package/src/internal/pictures/counts.ts +92 -0
- package/src/internal/pictures/pictures.ts +521 -0
- package/src/internal/pictures/transport.ts +243 -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 +164 -0
- package/src/internal/reading/ready.ts +111 -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 +416 -0
- package/src/internal/timeline/changes.inpage.ts +216 -0
- package/src/internal/timeline/changes.ts +100 -0
- package/src/internal/timeline/events.ts +94 -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,79 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
//#region src/Snapshot.ts
|
|
4
|
+
/**
|
|
5
|
+
* A compact, model-readable outline of what a page shows.
|
|
6
|
+
*
|
|
7
|
+
* Each control gets a ref such as `e12`. A ref stays valid while its element is on the page, and
|
|
8
|
+
* refs are never reused within a page, so a ref from an old snapshot fails as stale rather than
|
|
9
|
+
* naming a different element.
|
|
10
|
+
*
|
|
11
|
+
* @since 0.3.0
|
|
12
|
+
*/
|
|
13
|
+
var Snapshot_exports = /* @__PURE__ */ __exportAll({
|
|
14
|
+
Control: () => Control,
|
|
15
|
+
Snapshot: () => Snapshot
|
|
16
|
+
});
|
|
17
|
+
/** A control the outline shows, as a value: its ref, what it is and what it holds. */
|
|
18
|
+
var Control = class extends Schema.Class("effect-browser/Control")({
|
|
19
|
+
ref: Schema.String,
|
|
20
|
+
/** Its role, such as `button` or `textbox`, or `clickable` for an element without one. */
|
|
21
|
+
kind: Schema.String,
|
|
22
|
+
/** Its accessible name. */
|
|
23
|
+
name: Schema.String,
|
|
24
|
+
/** What it holds: a field's text, `••••` for a secret one, or a select's chosen labels. */
|
|
25
|
+
value: Schema.String,
|
|
26
|
+
/** A select's option labels, at most 64. */
|
|
27
|
+
options: Schema.optional(Schema.Array(Schema.String)),
|
|
28
|
+
/** How many options a select has, when it has options. */
|
|
29
|
+
optionCount: Schema.optional(Schema.Int),
|
|
30
|
+
disabled: Schema.optional(Schema.Boolean),
|
|
31
|
+
/** Whether it is checked, for what can be checked. */
|
|
32
|
+
checked: Schema.optional(Schema.Boolean),
|
|
33
|
+
/** True for a field that takes typed text. */
|
|
34
|
+
editable: Schema.optional(Schema.Boolean)
|
|
35
|
+
}) {};
|
|
36
|
+
var Snapshot = class extends Schema.Class("effect-browser/Snapshot")({
|
|
37
|
+
url: Schema.String,
|
|
38
|
+
title: Schema.String,
|
|
39
|
+
/** One line per control, heading or text block, indented by landmark. */
|
|
40
|
+
text: Schema.String,
|
|
41
|
+
/** True when `text` was cut at `maxChars`. */
|
|
42
|
+
truncated: Schema.Boolean,
|
|
43
|
+
/**
|
|
44
|
+
* Parts of the page left out because they lie above or below the viewport, each an element out
|
|
45
|
+
* of view with all it holds (viewport snapshots only).
|
|
46
|
+
*/
|
|
47
|
+
above: Schema.Finite,
|
|
48
|
+
below: Schema.Finite,
|
|
49
|
+
viewport: Schema.Struct({
|
|
50
|
+
width: Schema.Finite,
|
|
51
|
+
height: Schema.Finite
|
|
52
|
+
}),
|
|
53
|
+
scroll: Schema.Struct({
|
|
54
|
+
y: Schema.Finite,
|
|
55
|
+
height: Schema.Finite
|
|
56
|
+
}),
|
|
57
|
+
/** The controls the outline shows, in its order. */
|
|
58
|
+
controls: Schema.Array(Control)
|
|
59
|
+
}) {
|
|
60
|
+
/** The snapshot as one block of text for a model: header, outline and what was left out. */
|
|
61
|
+
get rendered() {
|
|
62
|
+
const position = this.scroll.height > this.viewport.height ? `, scrolled to ${this.scroll.y} of ${this.scroll.height - this.viewport.height}px` : "";
|
|
63
|
+
const omitted = [];
|
|
64
|
+
if (this.above > 0) omitted.push(`${this.above} parts above`);
|
|
65
|
+
if (this.below > 0) omitted.push(`${this.below} parts below`);
|
|
66
|
+
const footer = [...omitted.length > 0 ? [`(${omitted.join(", ")} the viewport)`] : [], ...this.truncated ? ["(cut short: narrow it with query)"] : []];
|
|
67
|
+
return [
|
|
68
|
+
`Page: ${this.title === "" ? "(untitled)" : this.title}`,
|
|
69
|
+
`URL: ${this.url}`,
|
|
70
|
+
`Viewport: ${this.viewport.width}x${this.viewport.height}${position}`,
|
|
71
|
+
this.text === "" ? "(nothing readable in view)" : this.text,
|
|
72
|
+
...footer
|
|
73
|
+
].join("\n");
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
export { Control, Snapshot, Snapshot_exports as t };
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=Snapshot.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Snapshot.mjs","names":[],"sources":["../src/Snapshot.ts"],"sourcesContent":["/**\n * A compact, model-readable outline of what a page shows.\n *\n * Each control gets a ref such as `e12`. A ref stays valid while its element is on the page, and\n * refs are never reused within a page, so a ref from an old snapshot fails as stale rather than\n * naming a different element.\n *\n * @since 0.3.0\n */\nimport { Schema } from \"effect\";\n\n/** A control the outline shows, as a value: its ref, what it is and what it holds. */\nexport class Control extends Schema.Class<Control>(\"effect-browser/Control\")({\n ref: Schema.String,\n /** Its role, such as `button` or `textbox`, or `clickable` for an element without one. */\n kind: Schema.String,\n /** Its accessible name. */\n name: Schema.String,\n /** What it holds: a field's text, `••••` for a secret one, or a select's chosen labels. */\n value: Schema.String,\n /** A select's option labels, at most 64. */\n options: Schema.optional(Schema.Array(Schema.String)),\n /** How many options a select has, when it has options. */\n optionCount: Schema.optional(Schema.Int),\n disabled: Schema.optional(Schema.Boolean),\n /** Whether it is checked, for what can be checked. */\n checked: Schema.optional(Schema.Boolean),\n /** True for a field that takes typed text. */\n editable: Schema.optional(Schema.Boolean),\n}) {}\n\nexport class Snapshot extends Schema.Class<Snapshot>(\"effect-browser/Snapshot\")({\n url: Schema.String,\n title: Schema.String,\n /** One line per control, heading or text block, indented by landmark. */\n text: Schema.String,\n /** True when `text` was cut at `maxChars`. */\n truncated: Schema.Boolean,\n /**\n * Parts of the page left out because they lie above or below the viewport, each an element out\n * of view with all it holds (viewport snapshots only).\n */\n above: Schema.Finite,\n below: Schema.Finite,\n viewport: Schema.Struct({ width: Schema.Finite, height: Schema.Finite }),\n scroll: Schema.Struct({ y: Schema.Finite, height: Schema.Finite }),\n /** The controls the outline shows, in its order. */\n controls: Schema.Array(Control),\n}) {\n /** The snapshot as one block of text for a model: header, outline and what was left out. */\n get rendered(): string {\n const position =\n this.scroll.height > this.viewport.height\n ? `, scrolled to ${this.scroll.y} of ${this.scroll.height - this.viewport.height}px`\n : \"\";\n\n const omitted: Array<string> = [];\n\n if (this.above > 0) omitted.push(`${this.above} parts above`);\n if (this.below > 0) omitted.push(`${this.below} parts below`);\n\n const footer = [\n ...(omitted.length > 0 ? [`(${omitted.join(\", \")} the viewport)`] : []),\n ...(this.truncated ? [\"(cut short: narrow it with query)\"] : []),\n ];\n\n return [\n `Page: ${this.title === \"\" ? \"(untitled)\" : this.title}`,\n `URL: ${this.url}`,\n `Viewport: ${this.viewport.width}x${this.viewport.height}${position}`,\n this.text === \"\" ? \"(nothing readable in view)\" : this.text,\n ...footer,\n ].join(\"\\n\");\n }\n}\n\nexport interface SnapshotOptions {\n /** Read the whole page instead of the viewport. Defaults to false. */\n readonly full?: boolean | undefined;\n /** Keep only lines containing this text (case-insensitive). */\n readonly query?: string | undefined;\n /**\n * Read only inside the elements this CSS selector matches, such as `form` or `#results`. A\n * selector that matches nothing reads nothing; one that is not CSS is an `InvalidRequest`.\n */\n readonly within?: string | undefined;\n /** Bound on the outline's length. Defaults to 12,000 characters. */\n readonly maxChars?: number | undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAYA,IAAa,UAAb,cAA6B,OAAO,MAAe,wBAAwB,CAAC,CAAC;CAC3E,KAAK,OAAO;;CAEZ,MAAM,OAAO;;CAEb,MAAM,OAAO;;CAEb,OAAO,OAAO;;CAEd,SAAS,OAAO,SAAS,OAAO,MAAM,OAAO,MAAM,CAAC;;CAEpD,aAAa,OAAO,SAAS,OAAO,GAAG;CACvC,UAAU,OAAO,SAAS,OAAO,OAAO;;CAExC,SAAS,OAAO,SAAS,OAAO,OAAO;;CAEvC,UAAU,OAAO,SAAS,OAAO,OAAO;AAC1C,CAAC,CAAC,CAAC,CAAC;AAEJ,IAAa,WAAb,cAA8B,OAAO,MAAgB,yBAAyB,CAAC,CAAC;CAC9E,KAAK,OAAO;CACZ,OAAO,OAAO;;CAEd,MAAM,OAAO;;CAEb,WAAW,OAAO;;;;;CAKlB,OAAO,OAAO;CACd,OAAO,OAAO;CACd,UAAU,OAAO,OAAO;EAAE,OAAO,OAAO;EAAQ,QAAQ,OAAO;CAAO,CAAC;CACvE,QAAQ,OAAO,OAAO;EAAE,GAAG,OAAO;EAAQ,QAAQ,OAAO;CAAO,CAAC;;CAEjE,UAAU,OAAO,MAAM,OAAO;AAChC,CAAC,CAAC,CAAC;;CAED,IAAI,WAAmB;EACrB,MAAM,WACJ,KAAK,OAAO,SAAS,KAAK,SAAS,SAC/B,iBAAiB,KAAK,OAAO,EAAE,MAAM,KAAK,OAAO,SAAS,KAAK,SAAS,OAAO,MAC/E;EAEN,MAAM,UAAyB,CAAC;EAEhC,IAAI,KAAK,QAAQ,GAAG,QAAQ,KAAK,GAAG,KAAK,MAAM,aAAa;EAC5D,IAAI,KAAK,QAAQ,GAAG,QAAQ,KAAK,GAAG,KAAK,MAAM,aAAa;EAE5D,MAAM,SAAS,CACb,GAAI,QAAQ,SAAS,IAAI,CAAC,IAAI,QAAQ,KAAK,IAAI,EAAE,eAAe,IAAI,CAAC,GACrE,GAAI,KAAK,YAAY,CAAC,mCAAmC,IAAI,CAAC,CAChE;EAEA,OAAO;GACL,SAAS,KAAK,UAAU,KAAK,eAAe,KAAK;GACjD,QAAQ,KAAK;GACb,aAAa,KAAK,SAAS,MAAM,GAAG,KAAK,SAAS,SAAS;GAC3D,KAAK,SAAS,KAAK,+BAA+B,KAAK;GACvD,GAAG;EACL,CAAC,CAAC,KAAK,IAAI;CACb;AACF"}
|
package/dist/Stage.d.mts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { t as BrowserError } from "./BrowserError-Coy7EW1N.mjs";
|
|
2
|
+
import { n as CaptureStats, o as ScreencastOptions, r as Frame } from "./Frame-Di2PxyF7.mjs";
|
|
3
|
+
import { u as Page } from "./Page-B7X6DQUn.mjs";
|
|
4
|
+
import { Duration, Effect, Option, Schema, Scope, Stream } from "effect";
|
|
5
|
+
declare namespace Stage_d_exports {
|
|
6
|
+
export { Cue, Options, Presented, Shown, Stage, make };
|
|
7
|
+
}
|
|
8
|
+
export interface Options extends ScreencastOptions {
|
|
9
|
+
/** Bound for each first-frame wait. Defaults to 5 seconds. */
|
|
10
|
+
readonly firstFrame?: Duration.Input | undefined;
|
|
11
|
+
}
|
|
12
|
+
declare const Presented_base: Schema.Class<Presented, Schema.Struct<{
|
|
13
|
+
readonly page: Schema.String;
|
|
14
|
+
readonly at: Schema.Finite;
|
|
15
|
+
readonly latency: Schema.Finite;
|
|
16
|
+
}>, {}>;
|
|
17
|
+
/** A switch that took effect, on the clock shared by browser events and frames. */
|
|
18
|
+
export declare class Presented extends Presented_base {}
|
|
19
|
+
export interface Cue {
|
|
20
|
+
readonly page: Page;
|
|
21
|
+
/** A frame of the current document, or the capture's failure or first-frame timeout. */
|
|
22
|
+
readonly ready: Effect.Effect<void, BrowserError>;
|
|
23
|
+
/** Commit on the event's host time, or now. Interruption before switching leaves the cue usable. */
|
|
24
|
+
readonly commit: (options?: {
|
|
25
|
+
readonly at?: number | undefined;
|
|
26
|
+
}) => Effect.Effect<Presented, BrowserError>;
|
|
27
|
+
}
|
|
28
|
+
/** What the output establishes about its last image; loss ends this page's evidence. */
|
|
29
|
+
export type Shown = {
|
|
30
|
+
readonly _tag: "Painted";
|
|
31
|
+
readonly frame: Frame;
|
|
32
|
+
} | {
|
|
33
|
+
readonly _tag: "Still";
|
|
34
|
+
readonly frame: Frame;
|
|
35
|
+
readonly at: number;
|
|
36
|
+
} | {
|
|
37
|
+
readonly _tag: "Stalled";
|
|
38
|
+
readonly frame: Frame;
|
|
39
|
+
readonly at: number;
|
|
40
|
+
} | {
|
|
41
|
+
readonly _tag: "Gone";
|
|
42
|
+
readonly page: string;
|
|
43
|
+
readonly at: number;
|
|
44
|
+
};
|
|
45
|
+
export interface Stage {
|
|
46
|
+
readonly present: (page: Page, options?: {
|
|
47
|
+
readonly at?: number | undefined;
|
|
48
|
+
}) => Effect.Effect<Presented, BrowserError>;
|
|
49
|
+
readonly cue: (page: Page) => Effect.Effect<Cue, BrowserError, Scope.Scope>;
|
|
50
|
+
/** Paint and, after every finite positive hold without paint, current evidence or loss. */
|
|
51
|
+
readonly shown: (options: {
|
|
52
|
+
readonly hold: Duration.Input;
|
|
53
|
+
}) => Stream.Stream<Shown>;
|
|
54
|
+
/** Current-page paint; a reader more than 16 frames behind loses the oldest. */
|
|
55
|
+
readonly frames: Stream.Stream<Frame>;
|
|
56
|
+
readonly current: Effect.Effect<Option.Option<Page>>;
|
|
57
|
+
readonly stats: (options?: {
|
|
58
|
+
readonly window?: Duration.Input | undefined;
|
|
59
|
+
}) => Effect.Effect<Option.Option<CaptureStats>, BrowserError>;
|
|
60
|
+
}
|
|
61
|
+
export declare const make: (options?: Options | undefined) => Effect.Effect<Stage, BrowserError, Scope.Scope>;
|
|
62
|
+
//#endregion
|
|
63
|
+
export { Stage_d_exports as t };
|
|
64
|
+
//# sourceMappingURL=Stage.d.mts.map
|
package/dist/Stage.mjs
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { Closed, InvalidRequest, Timeout, consequence } from "./BrowserError.mjs";
|
|
3
|
+
import { i as failWith, s as undispatched } from "./context-B6xr8nVi.mjs";
|
|
4
|
+
import { t as internalsOf } from "./page-BAf__WKX.mjs";
|
|
5
|
+
import { Cause, Clock, Deferred, Duration, Effect, Exit, Fiber, Option, PubSub, Result, Schedule, Schema, Scope, Stream } from "effect";
|
|
6
|
+
//#region src/Stage.ts
|
|
7
|
+
/**
|
|
8
|
+
* An output's capture ownership. Cue a page while preparing an event; commit when that event
|
|
9
|
+
* happens. A prepared cue belongs to its caller's scope, and a committed one to the stage.
|
|
10
|
+
* Commits serialize, drain old-page input and refuse stale first frames. `shown` distinguishes
|
|
11
|
+
* confirmed silence, uncertain silence and loss without treating capture silence as evidence.
|
|
12
|
+
* @since 0.3.0
|
|
13
|
+
*/
|
|
14
|
+
var Stage_exports = /* @__PURE__ */ __exportAll({
|
|
15
|
+
Presented: () => Presented,
|
|
16
|
+
make: () => make
|
|
17
|
+
});
|
|
18
|
+
/** A switch that took effect, on the clock shared by browser events and frames. */
|
|
19
|
+
var Presented = class extends Schema.Class("effect-browser/Presented")({
|
|
20
|
+
page: Schema.String,
|
|
21
|
+
at: Schema.Finite,
|
|
22
|
+
latency: Schema.Finite
|
|
23
|
+
}) {};
|
|
24
|
+
const closed = () => undispatched("cue", new Closed({ cause: "released" }));
|
|
25
|
+
/** The sole writer of a cue's capture lifecycle; presentation ownership belongs to the stage. */
|
|
26
|
+
const update = (feed, input) => {
|
|
27
|
+
if (feed.state._tag === "Stopped") return;
|
|
28
|
+
if (input._tag === "Stop") feed.state = { _tag: "Stopped" };
|
|
29
|
+
else if (input._tag === "Paint") feed.state = {
|
|
30
|
+
_tag: "Ready",
|
|
31
|
+
latest: input.frame
|
|
32
|
+
};
|
|
33
|
+
else if (feed.state._tag === "Ready") feed.state = {
|
|
34
|
+
_tag: "Ready",
|
|
35
|
+
latest: void 0
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const restartable = (error) => {
|
|
39
|
+
const { lost, repeat } = consequence(error);
|
|
40
|
+
return lost === "nothing" && repeat !== "pointless";
|
|
41
|
+
};
|
|
42
|
+
const stop = (feed) => Effect.suspend(() => {
|
|
43
|
+
update(feed, { _tag: "Stop" });
|
|
44
|
+
return Scope.close(feed.scope, Exit.void);
|
|
45
|
+
});
|
|
46
|
+
const frameOf = (feed) => {
|
|
47
|
+
const frame = feed.state._tag === "Ready" ? feed.state.latest : void 0;
|
|
48
|
+
const internals = internalsOf(feed.page);
|
|
49
|
+
return frame !== void 0 && (internals === void 0 || internals.current(frame)) ? frame : void 0;
|
|
50
|
+
};
|
|
51
|
+
const ended = (feed) => feed.fiber === void 0 ? Effect.never : Fiber.await(feed.fiber).pipe(Effect.flatMap((exit) => Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause) ? Effect.failCause(exit.cause) : Effect.fail(closed())));
|
|
52
|
+
const firstOf = (feed, wait) => Effect.suspend(() => {
|
|
53
|
+
if (feed.state._tag === "Stopped") return Effect.fail(closed());
|
|
54
|
+
if (feed.page.playwright.isClosed()) return failWith("cue", new Closed({ cause: "page" }));
|
|
55
|
+
if (frameOf(feed) !== void 0) return Effect.void;
|
|
56
|
+
return Effect.raceFirst(Stream.fromPubSub(feed.changed).pipe(Stream.filter(() => frameOf(feed) !== void 0), Stream.runHead, Effect.asVoid), ended(feed)).pipe(Effect.timeoutOrElse({
|
|
57
|
+
duration: wait,
|
|
58
|
+
orElse: () => failWith("cue", new Timeout({ millis: Duration.toMillis(wait) }))
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
61
|
+
const until = (at, now) => Effect.suspend(() => at > now() ? Effect.sleep(Duration.millis(Math.ceil(at - now()))).pipe(Effect.andThen(until(at, now))) : Effect.void);
|
|
62
|
+
/** Reserve the next turn before waking it; a fresh caller cannot overtake a queued commit. */
|
|
63
|
+
const ordered = () => {
|
|
64
|
+
const waiting = [];
|
|
65
|
+
return (effect) => Effect.acquireUseRelease(Effect.sync(() => {
|
|
66
|
+
const turn = Deferred.makeUnsafe();
|
|
67
|
+
waiting.push(turn);
|
|
68
|
+
if (waiting.length === 1) Deferred.doneUnsafe(turn, Exit.void);
|
|
69
|
+
return turn;
|
|
70
|
+
}), (turn) => Deferred.await(turn).pipe(Effect.andThen(effect)), (turn) => Effect.sync(() => {
|
|
71
|
+
const at = waiting.indexOf(turn);
|
|
72
|
+
waiting.splice(at, 1);
|
|
73
|
+
if (at === 0 && waiting[0] !== void 0) Deferred.doneUnsafe(waiting[0], Exit.void);
|
|
74
|
+
}));
|
|
75
|
+
};
|
|
76
|
+
/** A terminal capture can know the connection is gone before the page receives its close event. */
|
|
77
|
+
const confirm = (feed, frame) => {
|
|
78
|
+
const exit = feed.fiber?.pollUnsafe();
|
|
79
|
+
const failure = exit !== void 0 && Exit.isFailure(exit) ? Cause.findErrorOption(exit.cause) : Option.none();
|
|
80
|
+
if (Option.isSome(failure) && consequence(failure.value).lost !== "nothing") return Effect.fail(failure.value);
|
|
81
|
+
return feed.page.playwright.isClosed() ? failWith("shown", new Closed({ cause: "page" })) : internalsOf(feed.page)?.confirm(frame) ?? Effect.succeed(false);
|
|
82
|
+
};
|
|
83
|
+
/** Each subscriber confirms silence; a new frame or commit invalidates a probe. */
|
|
84
|
+
const evidence = (output, current, now, hold) => Stream.unwrap(Effect.sync(() => {
|
|
85
|
+
const parsed = Duration.fromInput(hold);
|
|
86
|
+
if (Option.isNone(parsed) || !Duration.isFinite(parsed.value) || !Duration.isPositive(parsed.value)) throw new RangeError("shown hold must be a finite positive duration");
|
|
87
|
+
const millis = Duration.toMillis(parsed.value);
|
|
88
|
+
let checkedAt = now();
|
|
89
|
+
let gone;
|
|
90
|
+
const probe = Effect.gen(function* () {
|
|
91
|
+
yield* until(Math.max(checkedAt, current()?.changedAt ?? checkedAt) + millis, now);
|
|
92
|
+
checkedAt = now();
|
|
93
|
+
const before = current();
|
|
94
|
+
const frame = before?.frame;
|
|
95
|
+
if (before === void 0 || frame === void 0 || gone === before.feed || checkedAt - before.changedAt < millis) return Option.none();
|
|
96
|
+
const { feed } = before;
|
|
97
|
+
const confirmed = yield* Effect.result(confirm(feed, frame));
|
|
98
|
+
if (current()?.feed !== feed || current()?.frame !== frame) return Option.none();
|
|
99
|
+
const at = now();
|
|
100
|
+
checkedAt = at;
|
|
101
|
+
if (Result.isFailure(confirmed) && consequence(confirmed.failure).lost !== "nothing") {
|
|
102
|
+
gone = feed;
|
|
103
|
+
return Option.some({
|
|
104
|
+
_tag: "Gone",
|
|
105
|
+
page: feed.page.id,
|
|
106
|
+
at
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return Option.some({
|
|
110
|
+
_tag: Result.isSuccess(confirmed) && confirmed.success ? "Still" : "Stalled",
|
|
111
|
+
frame,
|
|
112
|
+
at
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
return Stream.merge(Stream.fromPubSub(output).pipe(Stream.filter(({ feed }) => gone !== feed), Stream.map(({ frame }) => ({
|
|
116
|
+
_tag: "Painted",
|
|
117
|
+
frame
|
|
118
|
+
}))), Stream.fromEffectRepeat(probe).pipe(Stream.filter(Option.isSome), Stream.map(({ value }) => value)));
|
|
119
|
+
}));
|
|
120
|
+
const openFeed = (page, owner, clock, settings, current, publish) => Effect.gen(function* () {
|
|
121
|
+
const scope = yield* Scope.fork(owner);
|
|
122
|
+
const started = yield* Deferred.make();
|
|
123
|
+
const feed = {
|
|
124
|
+
page,
|
|
125
|
+
scope,
|
|
126
|
+
changed: yield* PubSub.sliding({
|
|
127
|
+
capacity: 1,
|
|
128
|
+
replay: 1
|
|
129
|
+
}),
|
|
130
|
+
state: { _tag: "Warming" },
|
|
131
|
+
fiber: void 0
|
|
132
|
+
};
|
|
133
|
+
yield* Scope.addFinalizer(scope, Effect.sync(() => {
|
|
134
|
+
update(feed, { _tag: "Stop" });
|
|
135
|
+
}));
|
|
136
|
+
yield* Effect.addFinalizer(() => current() === feed ? Effect.void : stop(feed));
|
|
137
|
+
const accept = (frame) => Effect.suspend(() => {
|
|
138
|
+
update(feed, {
|
|
139
|
+
_tag: "Paint",
|
|
140
|
+
frame
|
|
141
|
+
});
|
|
142
|
+
return (current() === feed ? publish(feed, frame) : Effect.void).pipe(Effect.andThen(PubSub.publish(feed.changed, frame)));
|
|
143
|
+
});
|
|
144
|
+
feed.fiber = yield* Effect.scoped(Effect.gen(function* () {
|
|
145
|
+
update(feed, { _tag: "Reset" });
|
|
146
|
+
const internals = internalsOf(page);
|
|
147
|
+
const { stream, current: frame } = yield* internals?.capture(settings) ?? Effect.succeed({
|
|
148
|
+
stream: page.screencast(settings),
|
|
149
|
+
current: void 0
|
|
150
|
+
});
|
|
151
|
+
if (frame !== void 0 && internals?.current(frame)) yield* accept(frame);
|
|
152
|
+
yield* Deferred.succeed(started, void 0);
|
|
153
|
+
yield* Stream.runForEach(stream, accept);
|
|
154
|
+
})).pipe(Effect.ensuring(Effect.sync(() => update(feed, { _tag: "Reset" }))), Effect.retry({
|
|
155
|
+
while: (error) => feed.state._tag === "Ready" && restartable(error),
|
|
156
|
+
schedule: Schedule.spaced("500 millis")
|
|
157
|
+
})).pipe(Effect.provideService(Clock.Clock, clock), Effect.forkIn(scope));
|
|
158
|
+
yield* Effect.raceFirst(Deferred.await(started), ended(feed)).pipe(Effect.onError(() => stop(feed)));
|
|
159
|
+
return feed;
|
|
160
|
+
});
|
|
161
|
+
const make = Effect.fn("Stage.make")(function* (options = {}) {
|
|
162
|
+
const clock = yield* Clock.Clock;
|
|
163
|
+
const owner = yield* Effect.scope;
|
|
164
|
+
const now = () => Number(clock.monotonicTimeNanosUnsafe()) / 1e6;
|
|
165
|
+
const waited = Duration.fromInput(options.firstFrame ?? Duration.seconds(5));
|
|
166
|
+
if (Option.isNone(waited) || !Duration.isFinite(waited.value) || !Duration.isPositive(waited.value)) return yield* failWith("stage", new InvalidRequest({ detail: "firstFrame must be a finite positive duration" }));
|
|
167
|
+
const firstFrame = waited.value;
|
|
168
|
+
const settings = {
|
|
169
|
+
quality: options.quality,
|
|
170
|
+
size: options.size
|
|
171
|
+
};
|
|
172
|
+
const output = yield* PubSub.sliding(16);
|
|
173
|
+
const switching = ordered();
|
|
174
|
+
let showing;
|
|
175
|
+
let painted = Number.NEGATIVE_INFINITY;
|
|
176
|
+
yield* Effect.addFinalizer(() => PubSub.shutdown(output));
|
|
177
|
+
const publish = (feed, frame) => Effect.suspend(() => {
|
|
178
|
+
painted = Math.max(painted, frame.hostTime);
|
|
179
|
+
if (showing !== void 0) {
|
|
180
|
+
showing.changedAt = now();
|
|
181
|
+
showing.frame = frame;
|
|
182
|
+
}
|
|
183
|
+
return PubSub.publish(output, {
|
|
184
|
+
feed,
|
|
185
|
+
frame
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
const commit = (feed, options = {}) => Effect.suspend(() => {
|
|
189
|
+
const asked = options.at ?? now();
|
|
190
|
+
return switching(Effect.gen(function* () {
|
|
191
|
+
if (!Number.isFinite(asked)) return yield* failWith("cue", new InvalidRequest({ detail: "at must be finite host milliseconds" }));
|
|
192
|
+
yield* firstOf(feed, firstFrame);
|
|
193
|
+
const old = showing;
|
|
194
|
+
if (old?.feed === feed) return old.presented;
|
|
195
|
+
yield* Effect.raceFirst(until(asked, now), ended(feed));
|
|
196
|
+
const switchTo = Effect.suspend(() => {
|
|
197
|
+
const frame = frameOf(feed);
|
|
198
|
+
if (frame === void 0) return Effect.fail(closed());
|
|
199
|
+
const at = Math.max(now(), asked, frame.hostTime, painted);
|
|
200
|
+
showing = {
|
|
201
|
+
feed,
|
|
202
|
+
frame,
|
|
203
|
+
presented: new Presented({
|
|
204
|
+
page: feed.page.id,
|
|
205
|
+
at,
|
|
206
|
+
latency: at - asked
|
|
207
|
+
}),
|
|
208
|
+
changedAt: at
|
|
209
|
+
};
|
|
210
|
+
return publish(feed, frame).pipe(Effect.andThen(old === void 0 ? Effect.void : stop(old.feed)), Effect.as(showing.presented));
|
|
211
|
+
}).pipe(Effect.uninterruptible);
|
|
212
|
+
const readyToSwitch = firstOf(feed, firstFrame).pipe(Effect.andThen(switchTo), Effect.provideService(Clock.Clock, clock));
|
|
213
|
+
const before = old === void 0 ? void 0 : internalsOf(old.feed.page);
|
|
214
|
+
return yield* before === void 0 ? readyToSwitch : before.afterInput(readyToSwitch);
|
|
215
|
+
}).pipe(Effect.provideService(Clock.Clock, clock)));
|
|
216
|
+
});
|
|
217
|
+
const cue = (page) => Effect.map(openFeed(page, owner, clock, settings, () => showing?.feed, publish), (feed) => ({
|
|
218
|
+
page,
|
|
219
|
+
ready: firstOf(feed, firstFrame).pipe(Effect.provideService(Clock.Clock, clock)),
|
|
220
|
+
commit: (options) => commit(feed, options)
|
|
221
|
+
}));
|
|
222
|
+
return {
|
|
223
|
+
cue,
|
|
224
|
+
present: (page, options) => Effect.suspend(() => {
|
|
225
|
+
const asked = options?.at ?? now();
|
|
226
|
+
return showing?.feed.page === page ? Effect.as(firstOf(showing.feed, firstFrame), showing.presented) : Effect.scoped(Effect.flatMap(cue(page), (prepared) => prepared.commit({ at: asked })));
|
|
227
|
+
}),
|
|
228
|
+
shown: ({ hold }) => evidence(output, () => showing, now, hold).pipe(Stream.provideService(Clock.Clock, clock)),
|
|
229
|
+
frames: Stream.fromPubSub(output).pipe(Stream.map(({ frame }) => frame)),
|
|
230
|
+
current: Effect.sync(() => Option.fromNullishOr(showing?.feed.page)),
|
|
231
|
+
stats: (options = {}) => showing === void 0 ? Effect.succeedNone : Effect.asSome(showing.feed.page.captureStats({ window: options.window ?? "1 second" }))
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
//#endregion
|
|
235
|
+
export { Presented, make, Stage_exports as t };
|
|
236
|
+
|
|
237
|
+
//# sourceMappingURL=Stage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Stage.mjs","names":[],"sources":["../src/Stage.ts"],"sourcesContent":["/**\n * An output's capture ownership. Cue a page while preparing an event; commit when that event\n * happens. A prepared cue belongs to its caller's scope, and a committed one to the stage.\n * Commits serialize, drain old-page input and refuse stale first frames. `shown` distinguishes\n * confirmed silence, uncertain silence and loss without treating capture silence as evidence.\n * @since 0.3.0\n */\nimport {\n Cause,\n Clock,\n Deferred,\n Duration,\n Effect,\n Exit,\n Fiber,\n Option,\n PubSub,\n Result,\n Schedule,\n Schema,\n Scope,\n Stream,\n} from \"effect\";\n\nimport { type BrowserError, Closed, consequence, InvalidRequest, Timeout } from \"./BrowserError.ts\";\nimport type { CaptureStats, Frame, ScreencastOptions } from \"./Frame.ts\";\nimport { failWith, undispatched } from \"./internal/page/context.ts\";\nimport { internalsOf } from \"./internal/page/page.ts\";\nimport type { Page } from \"./Page.ts\";\n\nexport interface Options extends ScreencastOptions {\n /** Bound for each first-frame wait. Defaults to 5 seconds. */\n readonly firstFrame?: Duration.Input | undefined;\n}\n\n/** A switch that took effect, on the clock shared by browser events and frames. */\nexport class Presented extends Schema.Class<Presented>(\"effect-browser/Presented\")({\n page: Schema.String,\n at: Schema.Finite,\n latency: Schema.Finite,\n}) {}\n\nexport interface Cue {\n readonly page: Page;\n /** A frame of the current document, or the capture's failure or first-frame timeout. */\n readonly ready: Effect.Effect<void, BrowserError>;\n /** Commit on the event's host time, or now. Interruption before switching leaves the cue usable. */\n readonly commit: (options?: {\n readonly at?: number | undefined;\n }) => Effect.Effect<Presented, BrowserError>;\n}\n\n/** What the output establishes about its last image; loss ends this page's evidence. */\nexport type Shown =\n | { readonly _tag: \"Painted\"; readonly frame: Frame }\n | { readonly _tag: \"Still\"; readonly frame: Frame; readonly at: number }\n | { readonly _tag: \"Stalled\"; readonly frame: Frame; readonly at: number }\n | { readonly _tag: \"Gone\"; readonly page: string; readonly at: number };\n\nexport interface Stage {\n readonly present: (\n page: Page,\n options?: { readonly at?: number | undefined },\n ) => Effect.Effect<Presented, BrowserError>;\n readonly cue: (page: Page) => Effect.Effect<Cue, BrowserError, Scope.Scope>;\n /** Paint and, after every finite positive hold without paint, current evidence or loss. */\n readonly shown: (options: { readonly hold: Duration.Input }) => Stream.Stream<Shown>;\n /** Current-page paint; a reader more than 16 frames behind loses the oldest. */\n readonly frames: Stream.Stream<Frame>;\n readonly current: Effect.Effect<Option.Option<Page>>;\n readonly stats: (options?: {\n readonly window?: Duration.Input | undefined;\n }) => Effect.Effect<Option.Option<CaptureStats>, BrowserError>;\n}\n\ntype FeedState =\n | { readonly _tag: \"Warming\" }\n | { readonly _tag: \"Ready\"; readonly latest: Frame | undefined }\n | { readonly _tag: \"Stopped\" };\ninterface Feed {\n readonly page: Page;\n readonly scope: Scope.Closeable;\n readonly changed: PubSub.PubSub<Frame>;\n state: FeedState;\n fiber: Fiber.Fiber<void, BrowserError> | undefined;\n}\ninterface Paint {\n readonly feed: Feed;\n readonly frame: Frame;\n}\n\nconst closed = () => undispatched(\"cue\", new Closed({ cause: \"released\" }));\n\n/** The sole writer of a cue's capture lifecycle; presentation ownership belongs to the stage. */\nconst update = (\n feed: Feed,\n input: { readonly _tag: \"Paint\"; readonly frame: Frame } | { readonly _tag: \"Reset\" | \"Stop\" },\n) => {\n if (feed.state._tag === \"Stopped\") return;\n if (input._tag === \"Stop\") feed.state = { _tag: \"Stopped\" };\n else if (input._tag === \"Paint\") feed.state = { _tag: \"Ready\", latest: input.frame };\n else if (feed.state._tag === \"Ready\") feed.state = { _tag: \"Ready\", latest: undefined };\n};\n\nconst restartable = (error: BrowserError) => {\n const { lost, repeat } = consequence(error);\n\n return lost === \"nothing\" && repeat !== \"pointless\";\n};\n\nconst stop = (feed: Feed) =>\n Effect.suspend(() => {\n update(feed, { _tag: \"Stop\" });\n\n return Scope.close(feed.scope, Exit.void);\n });\n\nconst frameOf = (feed: Feed) => {\n const frame = feed.state._tag === \"Ready\" ? feed.state.latest : undefined;\n const internals = internalsOf(feed.page);\n\n return frame !== undefined && (internals === undefined || internals.current(frame))\n ? frame\n : undefined;\n};\n\nconst ended = (feed: Feed): Effect.Effect<never, BrowserError> =>\n feed.fiber === undefined\n ? Effect.never\n : Fiber.await(feed.fiber).pipe(\n Effect.flatMap((exit) =>\n Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause)\n ? Effect.failCause(exit.cause)\n : Effect.fail(closed()),\n ),\n );\n\nconst firstOf = (feed: Feed, wait: Duration.Duration) =>\n Effect.suspend(() => {\n if (feed.state._tag === \"Stopped\") return Effect.fail(closed());\n if (feed.page.playwright.isClosed()) return failWith(\"cue\", new Closed({ cause: \"page\" }));\n if (frameOf(feed) !== undefined) return Effect.void;\n\n return Effect.raceFirst(\n Stream.fromPubSub(feed.changed).pipe(\n Stream.filter(() => frameOf(feed) !== undefined),\n Stream.runHead,\n Effect.asVoid,\n ),\n ended(feed),\n ).pipe(\n Effect.timeoutOrElse({\n duration: wait,\n orElse: () => failWith(\"cue\", new Timeout({ millis: Duration.toMillis(wait) })),\n }),\n );\n });\n\n// A timer can wake a fraction early; a commit never precedes its event.\nconst until = (at: number, now: () => number): Effect.Effect<void> =>\n Effect.suspend(() =>\n at > now()\n ? Effect.sleep(Duration.millis(Math.ceil(at - now()))).pipe(Effect.andThen(until(at, now)))\n : Effect.void,\n );\n\n/** Reserve the next turn before waking it; a fresh caller cannot overtake a queued commit. */\nconst ordered = () => {\n const waiting: Array<Deferred.Deferred<void>> = [];\n\n return <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n Effect.acquireUseRelease(\n Effect.sync(() => {\n const turn = Deferred.makeUnsafe<void>();\n\n waiting.push(turn);\n if (waiting.length === 1) Deferred.doneUnsafe(turn, Exit.void);\n\n return turn;\n }),\n (turn) => Deferred.await(turn).pipe(Effect.andThen(effect)),\n (turn) =>\n Effect.sync(() => {\n const at = waiting.indexOf(turn);\n\n waiting.splice(at, 1);\n if (at === 0 && waiting[0] !== undefined) Deferred.doneUnsafe(waiting[0], Exit.void);\n }),\n );\n};\n\n/** A terminal capture can know the connection is gone before the page receives its close event. */\nconst confirm = (feed: Feed, frame: Frame) => {\n const exit = feed.fiber?.pollUnsafe();\n\n const failure =\n exit !== undefined && Exit.isFailure(exit) ? Cause.findErrorOption(exit.cause) : Option.none();\n\n if (Option.isSome(failure) && consequence(failure.value).lost !== \"nothing\")\n return Effect.fail(failure.value);\n\n return feed.page.playwright.isClosed()\n ? failWith(\"shown\", new Closed({ cause: \"page\" }))\n : (internalsOf(feed.page)?.confirm(frame) ?? Effect.succeed(false));\n};\n\n/** Each subscriber confirms silence; a new frame or commit invalidates a probe. */\nconst evidence = (\n output: PubSub.PubSub<Paint>,\n current: () =>\n | { readonly feed: Feed; readonly frame: Frame; readonly changedAt: number }\n | undefined,\n now: () => number,\n hold: Duration.Input,\n): Stream.Stream<Shown> =>\n Stream.unwrap(\n Effect.sync(() => {\n const parsed = Duration.fromInput(hold);\n\n if (\n Option.isNone(parsed) ||\n !Duration.isFinite(parsed.value) ||\n !Duration.isPositive(parsed.value)\n )\n throw new RangeError(\"shown hold must be a finite positive duration\");\n const millis = Duration.toMillis(parsed.value);\n let checkedAt = now();\n let gone: Feed | undefined;\n\n const probe = Effect.gen(function* () {\n yield* until(Math.max(checkedAt, current()?.changedAt ?? checkedAt) + millis, now);\n checkedAt = now();\n const before = current();\n const frame = before?.frame;\n\n if (\n before === undefined ||\n frame === undefined ||\n gone === before.feed ||\n checkedAt - before.changedAt < millis\n )\n return Option.none<Shown>();\n const { feed } = before;\n\n const confirmed = yield* Effect.result(confirm(feed, frame));\n\n if (current()?.feed !== feed || current()?.frame !== frame) return Option.none<Shown>();\n const at = now();\n\n checkedAt = at;\n if (Result.isFailure(confirmed) && consequence(confirmed.failure).lost !== \"nothing\") {\n gone = feed;\n\n return Option.some<Shown>({ _tag: \"Gone\", page: feed.page.id, at });\n }\n\n return Option.some<Shown>({\n _tag: Result.isSuccess(confirmed) && confirmed.success ? \"Still\" : \"Stalled\",\n frame,\n at,\n });\n });\n\n return Stream.merge(\n Stream.fromPubSub(output).pipe(\n Stream.filter(({ feed }) => gone !== feed),\n Stream.map(({ frame }): Shown => ({ _tag: \"Painted\", frame })),\n ),\n Stream.fromEffectRepeat(probe).pipe(\n Stream.filter(Option.isSome),\n Stream.map(({ value }) => value),\n ),\n );\n }),\n );\n\nconst openFeed = (\n page: Page,\n owner: Scope.Scope,\n clock: Clock.Clock,\n settings: ScreencastOptions,\n current: () => Feed | undefined,\n publish: (feed: Feed, frame: Frame) => Effect.Effect<unknown>,\n) =>\n Effect.gen(function* () {\n const scope = yield* Scope.fork(owner);\n const started = yield* Deferred.make<void>();\n\n const feed: Feed = {\n page,\n scope,\n changed: yield* PubSub.sliding<Frame>({ capacity: 1, replay: 1 }),\n state: { _tag: \"Warming\" },\n fiber: undefined,\n };\n\n yield* Scope.addFinalizer(\n scope,\n Effect.sync(() => {\n update(feed, { _tag: \"Stop\" });\n }),\n );\n yield* Effect.addFinalizer(() => (current() === feed ? Effect.void : stop(feed)));\n\n const accept = (frame: Frame) =>\n Effect.suspend(() => {\n update(feed, { _tag: \"Paint\", frame });\n\n return (current() === feed ? publish(feed, frame) : Effect.void).pipe(\n Effect.andThen(PubSub.publish(feed.changed, frame)),\n );\n });\n\n const capture = Effect.scoped(\n Effect.gen(function* () {\n update(feed, { _tag: \"Reset\" });\n\n const internals = internalsOf(page);\n\n const { stream, current: frame } = yield* (\n internals?.capture(settings) ??\n Effect.succeed({ stream: page.screencast(settings), current: undefined })\n );\n\n if (frame !== undefined && internals?.current(frame)) yield* accept(frame);\n yield* Deferred.succeed(started, undefined);\n yield* Stream.runForEach(stream, accept);\n }),\n ).pipe(\n Effect.ensuring(Effect.sync(() => update(feed, { _tag: \"Reset\" }))),\n Effect.retry({\n while: (error) => feed.state._tag === \"Ready\" && restartable(error),\n schedule: Schedule.spaced(\"500 millis\"),\n }),\n );\n\n feed.fiber = yield* capture.pipe(\n Effect.provideService(Clock.Clock, clock),\n Effect.forkIn(scope),\n );\n yield* Effect.raceFirst(Deferred.await(started), ended(feed)).pipe(\n Effect.onError(() => stop(feed)),\n );\n\n return feed;\n });\n\nexport const make = Effect.fn(\"Stage.make\")(function* (\n options: Options = {},\n): Effect.fn.Return<Stage, BrowserError, Scope.Scope> {\n const clock = yield* Clock.Clock;\n const owner = yield* Effect.scope;\n const now = () => Number(clock.monotonicTimeNanosUnsafe()) / 1e6;\n const waited = Duration.fromInput(options.firstFrame ?? Duration.seconds(5));\n\n if (\n Option.isNone(waited) ||\n !Duration.isFinite(waited.value) ||\n !Duration.isPositive(waited.value)\n )\n return yield* failWith(\n \"stage\",\n new InvalidRequest({ detail: \"firstFrame must be a finite positive duration\" }),\n );\n const firstFrame = waited.value;\n const settings = { quality: options.quality, size: options.size };\n const output = yield* PubSub.sliding<Paint>(16);\n const switching = ordered();\n\n let showing:\n | { readonly feed: Feed; readonly presented: Presented; frame: Frame; changedAt: number }\n | undefined;\n\n let painted = Number.NEGATIVE_INFINITY;\n\n yield* Effect.addFinalizer(() => PubSub.shutdown(output));\n\n const publish = (feed: Feed, frame: Frame) =>\n Effect.suspend(() => {\n painted = Math.max(painted, frame.hostTime);\n if (showing !== undefined) {\n showing.changedAt = now();\n showing.frame = frame;\n }\n\n return PubSub.publish(output, { feed, frame });\n });\n\n const commit = (feed: Feed, options: { readonly at?: number | undefined } = {}) =>\n Effect.suspend(() => {\n const asked = options.at ?? now();\n\n return switching(\n Effect.gen(function* () {\n if (!Number.isFinite(asked))\n return yield* failWith(\n \"cue\",\n new InvalidRequest({ detail: \"at must be finite host milliseconds\" }),\n );\n yield* firstOf(feed, firstFrame);\n const old = showing;\n\n if (old?.feed === feed) return old.presented;\n\n yield* Effect.raceFirst(until(asked, now), ended(feed));\n\n const switchTo = Effect.suspend(() => {\n const frame = frameOf(feed);\n\n if (frame === undefined) return Effect.fail(closed());\n const at = Math.max(now(), asked, frame.hostTime, painted);\n\n showing = {\n feed,\n frame,\n presented: new Presented({ page: feed.page.id, at, latency: at - asked }),\n changedAt: at,\n };\n\n return publish(feed, frame).pipe(\n Effect.andThen(old === undefined ? Effect.void : stop(old.feed)),\n Effect.as(showing.presented),\n );\n }).pipe(Effect.uninterruptible);\n\n const readyToSwitch = firstOf(feed, firstFrame).pipe(\n Effect.andThen(switchTo),\n Effect.provideService(Clock.Clock, clock),\n );\n\n const before = old === undefined ? undefined : internalsOf(old.feed.page);\n\n return yield* before === undefined ? readyToSwitch : before.afterInput(readyToSwitch);\n }).pipe(Effect.provideService(Clock.Clock, clock)),\n );\n });\n\n const cue: Stage[\"cue\"] = (page) =>\n Effect.map(\n openFeed(page, owner, clock, settings, () => showing?.feed, publish),\n (feed) => ({\n page,\n ready: firstOf(feed, firstFrame).pipe(Effect.provideService(Clock.Clock, clock)),\n commit: (options) => commit(feed, options),\n }),\n );\n\n return {\n cue,\n present: (page, options) =>\n Effect.suspend(() => {\n const asked = options?.at ?? now();\n\n return showing?.feed.page === page\n ? Effect.as(firstOf(showing.feed, firstFrame), showing.presented)\n : Effect.scoped(Effect.flatMap(cue(page), (prepared) => prepared.commit({ at: asked })));\n }),\n shown: ({ hold }) =>\n evidence(output, () => showing, now, hold).pipe(Stream.provideService(Clock.Clock, clock)),\n frames: Stream.fromPubSub(output).pipe(Stream.map(({ frame }) => frame)),\n current: Effect.sync(() => Option.fromNullishOr(showing?.feed.page)),\n stats: (options = {}) =>\n showing === undefined\n ? Effect.succeedNone\n : Effect.asSome(showing.feed.page.captureStats({ window: options.window ?? \"1 second\" })),\n } satisfies Stage;\n});\n"],"mappings":"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"}
|