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.
Files changed (204) hide show
  1. package/README.md +849 -1161
  2. package/dist/Browser-S4kvpmqa.mjs +605 -0
  3. package/dist/Browser-S4kvpmqa.mjs.map +1 -0
  4. package/dist/Browser.d.mts +127 -3
  5. package/dist/Browser.mjs +2 -22
  6. package/dist/BrowserError-Coy7EW1N.d.mts +140 -0
  7. package/dist/BrowserError.d.mts +2 -0
  8. package/dist/BrowserError.mjs +211 -0
  9. package/dist/BrowserError.mjs.map +1 -0
  10. package/dist/BrowserEvent-BRu2juEz.d.mts +279 -0
  11. package/dist/BrowserEvent.d.mts +2 -0
  12. package/dist/BrowserEvent.mjs +297 -0
  13. package/dist/BrowserEvent.mjs.map +1 -0
  14. package/dist/Cdp.d.mts +32 -0
  15. package/dist/Cdp.mjs +61 -0
  16. package/dist/Cdp.mjs.map +1 -0
  17. package/dist/Change-DNvztNLu.mjs +138 -0
  18. package/dist/Change-DNvztNLu.mjs.map +1 -0
  19. package/dist/Change-iMlcuzVD.d.mts +71 -0
  20. package/dist/Change.d.mts +2 -0
  21. package/dist/Change.mjs +2 -0
  22. package/dist/Chromium.d.mts +29 -81
  23. package/dist/Chromium.mjs +57 -392
  24. package/dist/Chromium.mjs.map +1 -1
  25. package/dist/Expect.d.mts +62 -0
  26. package/dist/Expect.mjs +114 -0
  27. package/dist/Expect.mjs.map +1 -0
  28. package/dist/Frame-BERmf_gM.d.mts +117 -0
  29. package/dist/Frame.d.mts +2 -0
  30. package/dist/Frame.mjs +123 -0
  31. package/dist/Frame.mjs.map +1 -0
  32. package/dist/Moment.d.mts +2 -0
  33. package/dist/Moment.mjs +288 -0
  34. package/dist/Moment.mjs.map +1 -0
  35. package/dist/Motion.d.mts +40 -0
  36. package/dist/Motion.mjs +122 -0
  37. package/dist/Motion.mjs.map +1 -0
  38. package/dist/Page-B5cjaUp5.mjs +618 -0
  39. package/dist/Page-B5cjaUp5.mjs.map +1 -0
  40. package/dist/Page-BlPjfibv.d.mts +595 -0
  41. package/dist/Page.d.mts +2 -0
  42. package/dist/Page.mjs +2 -0
  43. package/dist/Plan-BI8XGvDu.d.mts +209 -0
  44. package/dist/Plan-D1wrJVs8.mjs +508 -0
  45. package/dist/Plan-D1wrJVs8.mjs.map +1 -0
  46. package/dist/Plan.d.mts +2 -3
  47. package/dist/Plan.mjs +2 -2
  48. package/dist/Policy.d.mts +76 -0
  49. package/dist/Policy.mjs +237 -0
  50. package/dist/Policy.mjs.map +1 -0
  51. package/dist/Presentation.d.mts +48 -0
  52. package/dist/Presentation.mjs +117 -0
  53. package/dist/Presentation.mjs.map +1 -0
  54. package/dist/Snapshot-B34hZ4Jl.d.mts +68 -0
  55. package/dist/Snapshot.d.mts +2 -0
  56. package/dist/Snapshot.mjs +79 -0
  57. package/dist/Snapshot.mjs.map +1 -0
  58. package/dist/Stage.d.mts +64 -0
  59. package/dist/Stage.mjs +237 -0
  60. package/dist/Stage.mjs.map +1 -0
  61. package/dist/Supervisor-CYWFK3vM.d.mts +280 -0
  62. package/dist/Supervisor-TNKNOVzu.mjs +599 -0
  63. package/dist/Supervisor-TNKNOVzu.mjs.map +1 -0
  64. package/dist/Supervisor.d.mts +2 -0
  65. package/dist/Supervisor.mjs +2 -0
  66. package/dist/context-B6xr8nVi.mjs +261 -0
  67. package/dist/context-B6xr8nVi.mjs.map +1 -0
  68. package/dist/index.d.mts +17 -14
  69. package/dist/index.mjs +18 -13
  70. package/dist/match.inpage-xOe9LNO0.mjs +48 -0
  71. package/dist/match.inpage-xOe9LNO0.mjs.map +1 -0
  72. package/dist/page-B8tUQELg.mjs +5073 -0
  73. package/dist/page-B8tUQELg.mjs.map +1 -0
  74. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  75. package/dist/url-Cd04Okid.mjs +264 -0
  76. package/dist/url-Cd04Okid.mjs.map +1 -0
  77. package/package.json +96 -61
  78. package/src/Browser.ts +666 -0
  79. package/src/BrowserError.ts +234 -0
  80. package/src/BrowserEvent.ts +296 -0
  81. package/src/Cdp.ts +101 -0
  82. package/src/Change.ts +88 -0
  83. package/src/Chromium.ts +102 -0
  84. package/src/Expect.ts +180 -0
  85. package/src/Frame.ts +130 -0
  86. package/src/Moment.ts +479 -0
  87. package/src/Motion.ts +166 -0
  88. package/src/Page.ts +522 -0
  89. package/src/Plan.ts +663 -0
  90. package/src/Policy.ts +325 -0
  91. package/src/Presentation.ts +195 -0
  92. package/src/Snapshot.ts +89 -0
  93. package/src/Stage.ts +467 -0
  94. package/src/Supervisor.ts +599 -0
  95. package/src/index.ts +20 -0
  96. package/src/internal/input/actions.ts +610 -0
  97. package/src/internal/input/dispatch.ts +161 -0
  98. package/src/internal/input/edit.inpage.ts +162 -0
  99. package/src/internal/input/evidence.inpage.ts +164 -0
  100. package/src/internal/input/gate.ts +224 -0
  101. package/src/internal/input/guard.inpage.ts +605 -0
  102. package/src/internal/input/guard.ts +184 -0
  103. package/src/internal/input/keyboard.ts +112 -0
  104. package/src/internal/input/keys.ts +127 -0
  105. package/src/internal/input/perform.ts +376 -0
  106. package/src/internal/input/pointer.ts +153 -0
  107. package/src/internal/input/replies.ts +195 -0
  108. package/src/internal/input/settle.ts +50 -0
  109. package/src/internal/input/style.ts +186 -0
  110. package/src/internal/input/targets.inpage.ts +293 -0
  111. package/src/internal/input/targets.ts +148 -0
  112. package/src/internal/page/bridge.ts +386 -0
  113. package/src/internal/page/context.ts +312 -0
  114. package/src/internal/page/lane.ts +311 -0
  115. package/src/internal/page/navigation.ts +183 -0
  116. package/src/internal/page/openings.ts +87 -0
  117. package/src/internal/page/page.ts +165 -0
  118. package/src/internal/page/url.ts +100 -0
  119. package/src/internal/page/viewport.ts +43 -0
  120. package/src/internal/pictures/capture.ts +776 -0
  121. package/src/internal/pictures/clock.ts +141 -0
  122. package/src/internal/pictures/counts.ts +92 -0
  123. package/src/internal/pictures/pictures.ts +520 -0
  124. package/src/internal/pictures/transport.ts +242 -0
  125. package/src/internal/reading/choose.ts +100 -0
  126. package/src/internal/reading/context.inpage.ts +201 -0
  127. package/src/internal/reading/controls.inpage.ts +158 -0
  128. package/src/internal/reading/expect.inpage.ts +70 -0
  129. package/src/internal/reading/match.inpage.ts +92 -0
  130. package/src/internal/reading/names.inpage.ts +306 -0
  131. package/src/internal/reading/outline.inpage.ts +260 -0
  132. package/src/internal/reading/reading.ts +223 -0
  133. package/src/internal/reading/ready.inpage.ts +164 -0
  134. package/src/internal/reading/ready.ts +111 -0
  135. package/src/internal/reading/subjects.inpage.ts +188 -0
  136. package/src/internal/reading/text.inpage.ts +135 -0
  137. package/src/internal/reading/walk.inpage.ts +220 -0
  138. package/src/internal/supervisor/lifecycle.ts +416 -0
  139. package/src/internal/timeline/changes.inpage.ts +216 -0
  140. package/src/internal/timeline/changes.ts +100 -0
  141. package/src/internal/timeline/events.ts +94 -0
  142. package/src/internal/timeline/fold.inpage.ts +123 -0
  143. package/src/internal/timeline/history.inpage.ts +229 -0
  144. package/src/internal/timeline/marks.inpage.ts +207 -0
  145. package/src/internal/timeline/record.inpage.ts +133 -0
  146. package/src/internal/timeline/sight.inpage.ts +122 -0
  147. package/src/internal/timeline/window.ts +96 -0
  148. package/src/internal/timeline/words.ts +65 -0
  149. package/dist/Bootstrap-B9UUXsvF.d.mts +0 -183
  150. package/dist/Bootstrap-CeQOWBy6.mjs +0 -189
  151. package/dist/Bootstrap-CeQOWBy6.mjs.map +0 -1
  152. package/dist/Bootstrap.d.mts +0 -3
  153. package/dist/Bootstrap.mjs +0 -2
  154. package/dist/Browser-BF9_sORP.d.mts +0 -388
  155. package/dist/Browser.mjs.map +0 -1
  156. package/dist/BrowserData-CPIIIHol.d.mts +0 -585
  157. package/dist/BrowserData.d.mts +0 -3
  158. package/dist/BrowserData.mjs +0 -695
  159. package/dist/BrowserData.mjs.map +0 -1
  160. package/dist/BrowserRuntime-B6nT1G4X.d.mts +0 -148
  161. package/dist/BrowserRuntime-C1r2aSRK.mjs +0 -6820
  162. package/dist/BrowserRuntime-C1r2aSRK.mjs.map +0 -1
  163. package/dist/BrowserRuntime.d.mts +0 -3
  164. package/dist/BrowserRuntime.mjs +0 -3
  165. package/dist/Capture.d.mts +0 -56
  166. package/dist/Capture.mjs +0 -678
  167. package/dist/Capture.mjs.map +0 -1
  168. package/dist/CaptureData-CYriZHX1.mjs +0 -201
  169. package/dist/CaptureData-CYriZHX1.mjs.map +0 -1
  170. package/dist/CaptureData.d.mts +0 -219
  171. package/dist/CaptureData.mjs +0 -2
  172. package/dist/Errors.d.mts +0 -158
  173. package/dist/Errors.mjs +0 -207
  174. package/dist/Errors.mjs.map +0 -1
  175. package/dist/Images-yCG9BmRU.mjs +0 -76
  176. package/dist/Images-yCG9BmRU.mjs.map +0 -1
  177. package/dist/OperationOptions-DAeRS6O9.mjs +0 -55
  178. package/dist/OperationOptions-DAeRS6O9.mjs.map +0 -1
  179. package/dist/PageControl.d.mts +0 -15
  180. package/dist/PageControl.mjs +0 -34
  181. package/dist/PageControl.mjs.map +0 -1
  182. package/dist/PageRegistry-B3q9DS3g.mjs +0 -164
  183. package/dist/PageRegistry-B3q9DS3g.mjs.map +0 -1
  184. package/dist/Plan-Dyxu2q8C.mjs +0 -543
  185. package/dist/Plan-Dyxu2q8C.mjs.map +0 -1
  186. package/dist/PlanData-B668RxbQ.d.mts +0 -4831
  187. package/dist/PlanData.d.mts +0 -3
  188. package/dist/PlanData.mjs +0 -268
  189. package/dist/PlanData.mjs.map +0 -1
  190. package/dist/PlanInput-BJcPPncs.mjs +0 -75
  191. package/dist/PlanInput-BJcPPncs.mjs.map +0 -1
  192. package/dist/PublicSession-DCSMMqOj.mjs +0 -5602
  193. package/dist/PublicSession-DCSMMqOj.mjs.map +0 -1
  194. package/dist/Testing.d.mts +0 -479
  195. package/dist/Testing.mjs +0 -2147
  196. package/dist/Testing.mjs.map +0 -1
  197. package/dist/Timeline-fV22Xk-S.d.mts +0 -29
  198. package/dist/Timeline.d.mts +0 -4
  199. package/dist/Timeline.mjs +0 -20
  200. package/dist/Timeline.mjs.map +0 -1
  201. package/dist/TimelineData-BsOn-YGZ.d.mts +0 -3818
  202. package/dist/TimelineData.d.mts +0 -3
  203. package/dist/TimelineData.mjs +0 -482
  204. 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>;