effect-browser 0.2.0-beta.9 → 0.3.0-beta.10
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 +849 -1161
- package/dist/Browser-S4kvpmqa.mjs +605 -0
- package/dist/Browser-S4kvpmqa.mjs.map +1 -0
- package/dist/Browser.d.mts +127 -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-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-B5cjaUp5.mjs +618 -0
- package/dist/Page-B5cjaUp5.mjs.map +1 -0
- package/dist/Page-BlPjfibv.d.mts +595 -0
- package/dist/Page.d.mts +2 -0
- package/dist/Page.mjs +2 -0
- package/dist/Plan-BI8XGvDu.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-B8tUQELg.mjs +5073 -0
- package/dist/page-B8tUQELg.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 +666 -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 +130 -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 +386 -0
- package/src/internal/page/context.ts +312 -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 +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 +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,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A browser's input authority: stop admitting writes, drain admitted operations through their
|
|
3
|
+
* records and native replies, then retain the stop for its scopes. Reads never enter this gate.
|
|
4
|
+
*/
|
|
5
|
+
import { Clock, Deferred, Duration, Effect, Exit, Option, type Scope } from "effect";
|
|
6
|
+
|
|
7
|
+
import { BrowserError, Busy, Closed, InvalidRequest, Suspended } from "../../BrowserError.ts";
|
|
8
|
+
import type { DisconnectCause } from "../../BrowserEvent.ts";
|
|
9
|
+
|
|
10
|
+
interface Stopped {
|
|
11
|
+
readonly since: number;
|
|
12
|
+
readonly at: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type State =
|
|
16
|
+
| { readonly _tag: "Open"; readonly inputs: ReadonlySet<number> }
|
|
17
|
+
| {
|
|
18
|
+
readonly _tag: "Draining";
|
|
19
|
+
readonly inputs: ReadonlySet<number>;
|
|
20
|
+
readonly claims: ReadonlySet<number>;
|
|
21
|
+
readonly startedAt: number;
|
|
22
|
+
readonly deadline: number;
|
|
23
|
+
}
|
|
24
|
+
| { readonly _tag: "Held"; readonly claims: ReadonlySet<number>; readonly stopped: Stopped };
|
|
25
|
+
|
|
26
|
+
type Input =
|
|
27
|
+
| { readonly _tag: "Enter" | "End" | "Leave"; readonly id: number }
|
|
28
|
+
| { readonly _tag: "Suspend"; readonly id: number; readonly drain: number }
|
|
29
|
+
| { readonly _tag: "Expire" };
|
|
30
|
+
|
|
31
|
+
const without = (set: ReadonlySet<number>, id: number) =>
|
|
32
|
+
new Set([...set].filter((each) => each !== id));
|
|
33
|
+
|
|
34
|
+
const step = (state: State, input: Input, stopped: Stopped): State => {
|
|
35
|
+
switch (input._tag) {
|
|
36
|
+
case "Enter":
|
|
37
|
+
return state._tag === "Open"
|
|
38
|
+
? { ...state, inputs: new Set([...state.inputs, input.id]) }
|
|
39
|
+
: state;
|
|
40
|
+
case "End": {
|
|
41
|
+
if (state._tag === "Held") return state;
|
|
42
|
+
const inputs = without(state.inputs, input.id);
|
|
43
|
+
|
|
44
|
+
return state._tag === "Draining" && inputs.size === 0
|
|
45
|
+
? { _tag: "Held", claims: state.claims, stopped }
|
|
46
|
+
: { ...state, inputs };
|
|
47
|
+
}
|
|
48
|
+
case "Suspend":
|
|
49
|
+
if (state._tag !== "Open") return { ...state, claims: new Set([...state.claims, input.id]) };
|
|
50
|
+
|
|
51
|
+
return state.inputs.size === 0
|
|
52
|
+
? { _tag: "Held", claims: new Set([input.id]), stopped }
|
|
53
|
+
: {
|
|
54
|
+
_tag: "Draining",
|
|
55
|
+
inputs: state.inputs,
|
|
56
|
+
claims: new Set([input.id]),
|
|
57
|
+
startedAt: stopped.at,
|
|
58
|
+
deadline: stopped.at + input.drain,
|
|
59
|
+
};
|
|
60
|
+
case "Leave": {
|
|
61
|
+
if (state._tag === "Open" || !state.claims.has(input.id)) return state;
|
|
62
|
+
const claims = without(state.claims, input.id);
|
|
63
|
+
|
|
64
|
+
return claims.size > 0
|
|
65
|
+
? { ...state, claims }
|
|
66
|
+
: { _tag: "Open", inputs: state._tag === "Draining" ? state.inputs : new Set() };
|
|
67
|
+
}
|
|
68
|
+
case "Expire":
|
|
69
|
+
return state._tag === "Draining" && stopped.at >= state.deadline
|
|
70
|
+
? { _tag: "Open", inputs: state.inputs }
|
|
71
|
+
: state;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const make = (options: {
|
|
76
|
+
readonly now: () => number;
|
|
77
|
+
readonly sequence: () => number;
|
|
78
|
+
readonly closedBy: () => DisconnectCause | undefined;
|
|
79
|
+
readonly lost: Effect.Effect<DisconnectCause>;
|
|
80
|
+
readonly clock: Clock.Clock;
|
|
81
|
+
readonly drain: Duration.Duration;
|
|
82
|
+
}) => {
|
|
83
|
+
let state: State = { _tag: "Open", inputs: new Set() };
|
|
84
|
+
let next = 0;
|
|
85
|
+
let refused = Deferred.makeUnsafe<void>();
|
|
86
|
+
let ready = Deferred.makeUnsafe<Stopped, BrowserError>();
|
|
87
|
+
|
|
88
|
+
const error = (operation: string) =>
|
|
89
|
+
new BrowserError({
|
|
90
|
+
operation,
|
|
91
|
+
reason:
|
|
92
|
+
options.closedBy() === undefined
|
|
93
|
+
? new Suspended()
|
|
94
|
+
: new Closed({ cause: options.closedBy() ?? "connection" }),
|
|
95
|
+
dispatched: false,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const stopped = (): Stopped => ({ since: options.sequence(), at: options.now() });
|
|
99
|
+
|
|
100
|
+
// Every change to authority happens here, synchronously with its admission or scope closure.
|
|
101
|
+
const apply = (input: Input): State => {
|
|
102
|
+
if (input._tag !== "Expire" && state._tag === "Draining" && options.now() >= state.deadline)
|
|
103
|
+
apply({ _tag: "Expire" });
|
|
104
|
+
const before = state;
|
|
105
|
+
|
|
106
|
+
state = step(state, input, stopped());
|
|
107
|
+
if (input._tag === "Expire" && before._tag === "Draining" && state._tag === "Open")
|
|
108
|
+
Deferred.doneUnsafe(
|
|
109
|
+
ready,
|
|
110
|
+
Exit.fail(
|
|
111
|
+
new BrowserError({
|
|
112
|
+
operation: "suspend",
|
|
113
|
+
reason: new Busy({
|
|
114
|
+
waitedMillis: Math.round(options.now() - before.startedAt),
|
|
115
|
+
ahead: before.inputs.size,
|
|
116
|
+
}),
|
|
117
|
+
dispatched: false,
|
|
118
|
+
}),
|
|
119
|
+
),
|
|
120
|
+
);
|
|
121
|
+
if (before._tag === "Open" && state._tag !== "Open") Deferred.doneUnsafe(refused, Exit.void);
|
|
122
|
+
if (before._tag === "Draining" && state._tag === "Held")
|
|
123
|
+
Deferred.doneUnsafe(ready, Exit.succeed(state.stopped));
|
|
124
|
+
if (before._tag !== "Open" && state._tag === "Open") {
|
|
125
|
+
refused = Deferred.makeUnsafe();
|
|
126
|
+
ready = Deferred.makeUnsafe();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return state;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const check = (operation: string) =>
|
|
133
|
+
Effect.suspend(() =>
|
|
134
|
+
state._tag === "Open" && options.closedBy() === undefined
|
|
135
|
+
? Effect.void
|
|
136
|
+
: Effect.fail(error(operation)),
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const suspend = (
|
|
140
|
+
drain: Duration.Input = options.drain,
|
|
141
|
+
): Effect.Effect<Stopped, BrowserError, Scope.Scope> =>
|
|
142
|
+
Effect.suspend(() => {
|
|
143
|
+
const duration = Duration.fromInput(drain);
|
|
144
|
+
|
|
145
|
+
if (
|
|
146
|
+
Option.isNone(duration) ||
|
|
147
|
+
!Duration.isFinite(duration.value) ||
|
|
148
|
+
Duration.toMillis(duration.value) < 0
|
|
149
|
+
)
|
|
150
|
+
return Effect.fail(
|
|
151
|
+
new BrowserError({
|
|
152
|
+
operation: "suspend",
|
|
153
|
+
reason: new InvalidRequest({ detail: "drain must be a finite nonnegative duration" }),
|
|
154
|
+
dispatched: false,
|
|
155
|
+
}),
|
|
156
|
+
);
|
|
157
|
+
const id = ++next;
|
|
158
|
+
const leave = Effect.sync(() => apply({ _tag: "Leave", id }));
|
|
159
|
+
|
|
160
|
+
return Effect.acquireRelease(
|
|
161
|
+
Effect.gen(function* () {
|
|
162
|
+
if (options.closedBy() !== undefined) return yield* error("suspend");
|
|
163
|
+
const current = apply({ _tag: "Suspend", id, drain: Duration.toMillis(duration.value) });
|
|
164
|
+
|
|
165
|
+
if (current._tag === "Held") return current.stopped;
|
|
166
|
+
if (current._tag !== "Draining")
|
|
167
|
+
return yield* Effect.die("suspension did not retain authority");
|
|
168
|
+
const pending = ready;
|
|
169
|
+
|
|
170
|
+
// Native completion and timer callbacks both check the same monotonic deadline. A
|
|
171
|
+
// timer may wake a fraction early, so it sleeps the remaining time instead of hanging.
|
|
172
|
+
const expire: Effect.Effect<Stopped, BrowserError> = Effect.suspend(() => {
|
|
173
|
+
const left = current.deadline - options.now();
|
|
174
|
+
|
|
175
|
+
return left > 0
|
|
176
|
+
? Effect.sleep(Duration.millis(left)).pipe(Effect.andThen(expire))
|
|
177
|
+
: Effect.sync(() => apply({ _tag: "Expire" })).pipe(
|
|
178
|
+
Effect.andThen(Deferred.await(pending)),
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const wait = Effect.raceFirst(Deferred.await(pending), expire);
|
|
183
|
+
|
|
184
|
+
return yield* Effect.raceFirst(
|
|
185
|
+
wait,
|
|
186
|
+
options.lost.pipe(Effect.flatMap(() => Effect.fail(error("suspend")))),
|
|
187
|
+
).pipe(
|
|
188
|
+
Effect.interruptible,
|
|
189
|
+
Effect.filterOrFail(
|
|
190
|
+
() => options.closedBy() === undefined,
|
|
191
|
+
() => error("suspend"),
|
|
192
|
+
),
|
|
193
|
+
Effect.onError(() => leave),
|
|
194
|
+
);
|
|
195
|
+
}),
|
|
196
|
+
() => leave,
|
|
197
|
+
);
|
|
198
|
+
}).pipe(Effect.provideService(Clock.Clock, options.clock));
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
check,
|
|
202
|
+
suspend,
|
|
203
|
+
refused: (operation: string): Effect.Effect<never, BrowserError> =>
|
|
204
|
+
Effect.suspend(() =>
|
|
205
|
+
state._tag === "Open"
|
|
206
|
+
? Deferred.await(refused).pipe(Effect.andThen(Effect.fail(error(operation))))
|
|
207
|
+
: Effect.fail(error(operation)),
|
|
208
|
+
),
|
|
209
|
+
enter: (operation: string): Effect.Effect<() => void, BrowserError> =>
|
|
210
|
+
Effect.suspend(() => {
|
|
211
|
+
if (state._tag !== "Open" || options.closedBy() !== undefined)
|
|
212
|
+
return Effect.fail(error(operation));
|
|
213
|
+
const id = ++next;
|
|
214
|
+
|
|
215
|
+
apply({ _tag: "Enter", id });
|
|
216
|
+
|
|
217
|
+
return Effect.succeed(() => {
|
|
218
|
+
apply({ _tag: "End", id });
|
|
219
|
+
});
|
|
220
|
+
}),
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export type Gate = ReturnType<typeof make>;
|