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,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll as t };
@@ -0,0 +1,264 @@
1
+ import { BrowserError, Busy } from "./BrowserError.mjs";
2
+ import { Context, Deferred, Duration, Effect, Exit } from "effect";
3
+ //#region src/internal/page/lane.ts
4
+ /**
5
+ * A page's admission: the one lane every operation on the page takes its turn in, so a page waits
6
+ * only for itself. A write, an action that sends input or navigates, holds the lane alone, in the
7
+ * order writes asked; reads share it, after the write in flight and every write asked before them,
8
+ * so a read describes the page an action left, never one an action is still changing. Each write
9
+ * starts a new epoch as it asks. A turn not given in time fails `Busy`, never `Timeout`, and a
10
+ * caller under `FailFast` gets it at once.
11
+ *
12
+ * Reads keep their work. An identical read asked in the same epoch and document joins the one in
13
+ * flight, which runs in the page's scope under the action timeout whoever gives up; one that ends
14
+ * after all its callers gave up serves the next to ask the same, within an action timeout. A write
15
+ * stops the reads nobody awaits, since no caller after it could use them.
16
+ *
17
+ * Effect's `Semaphore` is not fair to a writer that needs every permit, so the rule is this
18
+ * module's own: one state, changed by `step` alone, which the model test drives.
19
+ */
20
+ const initial = {
21
+ turn: { _tag: "Free" },
22
+ queue: [],
23
+ epoch: 0
24
+ };
25
+ const holders = (turn) => turn._tag === "Reading" ? turn.count : turn._tag === "Writing" ? 1 : 0;
26
+ /** Whether a ticket of `kind` asking now would hold the lane at once. */
27
+ const admitsNow = ({ turn, queue }, kind) => queue.length === 0 && (kind === "read" ? turn._tag !== "Writing" : turn._tag === "Free");
28
+ /**
29
+ * The operations ahead of a waiting ticket: those holding the lane and those asked before it, or
30
+ * all that are queued for a ticket not in the queue.
31
+ */
32
+ const ahead = ({ turn, queue }, id) => {
33
+ const at = queue.findIndex((ticket) => ticket.id === id);
34
+ return holders(turn) + (at === -1 ? queue.length : at);
35
+ };
36
+ /**
37
+ * The lane after `input`, and the tickets it lets in. Tickets go in from the head of the queue
38
+ * only: a write once the lane is free, reads while no write holds it, so reads asked before a
39
+ * write go before it, and reads asked after it wait for it.
40
+ */
41
+ const step = (state, input) => {
42
+ let { turn, queue, epoch } = state;
43
+ if (input._tag === "Ask") {
44
+ queue = [...queue, input.ticket];
45
+ if (input.ticket.kind === "write") epoch += 1;
46
+ } else {
47
+ const at = queue.findIndex((ticket) => ticket.id === input.ticket.id);
48
+ if (at !== -1) queue = queue.toSpliced(at, 1);
49
+ else turn = turn._tag === "Reading" && turn.count > 1 ? {
50
+ _tag: "Reading",
51
+ count: turn.count - 1
52
+ } : { _tag: "Free" };
53
+ }
54
+ const admitted = [];
55
+ for (const ticket of queue) {
56
+ if (ticket.kind === "write" ? turn._tag !== "Free" : turn._tag === "Writing") break;
57
+ admitted.push(ticket);
58
+ turn = ticket.kind === "write" ? { _tag: "Writing" } : {
59
+ _tag: "Reading",
60
+ count: holders(turn) + 1
61
+ };
62
+ }
63
+ return {
64
+ state: {
65
+ turn,
66
+ queue: queue.slice(admitted.length),
67
+ epoch
68
+ },
69
+ admitted
70
+ };
71
+ };
72
+ /** Whether operations on a busy page fail `Busy` at once rather than wait their turn. */
73
+ const FailFast = Context.Reference("effect-browser/internal/page/FailFast", { defaultValue: () => false });
74
+ /** The id a caller gives the actions it asks for, which each records as its `correlation`. */
75
+ const Correlation = Context.Reference("effect-browser/internal/page/Correlation", { defaultValue: () => void 0 });
76
+ const make = (options) => {
77
+ const { now, actionTimeout } = options;
78
+ let state = initial;
79
+ let tickets = 0;
80
+ const admissions = /* @__PURE__ */ new Map();
81
+ const sweeps = [];
82
+ const apply = (input) => {
83
+ const next = step(state, input);
84
+ state = next.state;
85
+ if (input._tag === "Leave") admissions.delete(input.ticket.id);
86
+ for (const ticket of next.admitted) {
87
+ const admitted = admissions.get(ticket.id);
88
+ admissions.delete(ticket.id);
89
+ if (admitted !== void 0) Deferred.doneUnsafe(admitted, Exit.void);
90
+ }
91
+ if (input._tag === "Ask" && input.ticket.kind === "write") for (const sweep of sweeps) sweep();
92
+ };
93
+ const busy = (operation, askedAt, id) => new BrowserError({
94
+ operation,
95
+ reason: new Busy({
96
+ waitedMillis: Math.round(now() - askedAt),
97
+ ahead: ahead(state, id)
98
+ }),
99
+ dispatched: false
100
+ });
101
+ /**
102
+ * Run `effect` in a turn of `kind`, waiting at most `wait` for it, or failing `Busy`. The turn
103
+ * ends with `effect`, however it ends.
104
+ */
105
+ const turn = (kind, operation, wait) => (effect) => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
106
+ const ticket = {
107
+ id: ++tickets,
108
+ kind
109
+ };
110
+ const askedAt = now();
111
+ if (kind === "write" && options.inputGate !== void 0) yield* options.inputGate.check(operation);
112
+ if ((yield* FailFast) && !admitsNow(state, kind)) return yield* busy(operation, askedAt);
113
+ const admitted = Deferred.makeUnsafe();
114
+ admissions.set(ticket.id, admitted);
115
+ apply({
116
+ _tag: "Ask",
117
+ ticket
118
+ });
119
+ const waiting = Deferred.await(admitted).pipe(Effect.timeoutOrElse({
120
+ duration: wait,
121
+ orElse: () => Deferred.isDoneUnsafe(admitted) ? Effect.void : Effect.fail(busy(operation, askedAt, ticket.id))
122
+ }));
123
+ const given = yield* Effect.exit(restore(kind === "write" && options.inputGate !== void 0 ? Effect.raceFirst(waiting, options.inputGate.refused(operation)) : waiting));
124
+ if (Exit.isFailure(given)) {
125
+ apply({
126
+ _tag: "Leave",
127
+ ticket
128
+ });
129
+ return yield* Effect.failCause(given.cause);
130
+ }
131
+ return yield* restore(effect).pipe(Effect.ensuring(Effect.sync(() => apply({
132
+ _tag: "Leave",
133
+ ticket
134
+ }))));
135
+ }));
136
+ /**
137
+ * A read whose identical calls share their work: `work` runs once per epoch and document while
138
+ * calls await it, and with `keep` its result serves the next call after all of them gave up,
139
+ * within an action timeout of its end. Pictures, whose callers say how old they may be, only
140
+ * join.
141
+ */
142
+ const shared = (operation, keep) => {
143
+ const flights = /* @__PURE__ */ new Map();
144
+ const kept = /* @__PURE__ */ new Map();
145
+ sweeps.push(() => {
146
+ kept.clear();
147
+ for (const flight of flights.values()) if (flight.waiting === 0) flight.fiber?.interruptUnsafe();
148
+ });
149
+ const start = (id, work) => Effect.gen(function* () {
150
+ const flight = {
151
+ epoch: state.epoch,
152
+ result: Deferred.makeUnsafe(),
153
+ waiting: 1,
154
+ fiber: void 0
155
+ };
156
+ flights.set(id, flight);
157
+ flight.fiber = yield* turn("read", operation, actionTimeout)(work).pipe(Effect.provideService(FailFast, false), Effect.forkIn(options.scope));
158
+ flight.fiber.addObserver((exit) => {
159
+ flights.delete(id);
160
+ if (keep && Exit.isSuccess(exit) && flight.waiting === 0 && flight.epoch === state.epoch) kept.set(id, {
161
+ value: exit.value,
162
+ until: now() + Duration.toMillis(actionTimeout)
163
+ });
164
+ Deferred.doneUnsafe(flight.result, Exit.hasInterrupts(exit) ? Effect.fail(options.gone(operation)) : exit);
165
+ });
166
+ return flight;
167
+ });
168
+ const join = (id, work) => Effect.acquireUseRelease(Effect.suspend(() => {
169
+ const flying = flights.get(id);
170
+ if (flying === void 0) return start(id, work);
171
+ flying.waiting += 1;
172
+ return Effect.as(Effect.annotateCurrentSpan("shared", "joined"), flying);
173
+ }), (flight) => Deferred.await(flight.result), (flight) => Effect.sync(() => {
174
+ flight.waiting -= 1;
175
+ if (flight.waiting === 0 && flight.epoch < state.epoch) flight.fiber?.interruptUnsafe();
176
+ }));
177
+ return (key, work) => Effect.gen(function* () {
178
+ const id = `${state.epoch} ${options.documentAt()} ${key}`;
179
+ const at = now();
180
+ for (const [old, { until }] of kept) if (until < at) kept.delete(old);
181
+ const hit = kept.get(id);
182
+ if (hit !== void 0) {
183
+ kept.delete(id);
184
+ yield* Effect.annotateCurrentSpan("shared", "kept");
185
+ return hit.value;
186
+ }
187
+ if ((yield* FailFast) && !admitsNow(state, "read")) return yield* busy(operation, at);
188
+ return yield* join(id, work);
189
+ });
190
+ };
191
+ return {
192
+ /** A turn alone, for an action: `wait` bounds the wait for it. */
193
+ write: (operation, wait) => turn("write", operation, wait),
194
+ /** A turn beside other reads, waited for within the action timeout. */
195
+ read: (operation, wait = actionTimeout) => turn("read", operation, wait),
196
+ shared
197
+ };
198
+ };
199
+ //#endregion
200
+ //#region src/internal/page/url.ts
201
+ /**
202
+ * Addresses: reading one the way a person types it, for `Page.goto` and the browser tools alike,
203
+ * and reporting one without the values that are credentials, by one rule that the page script runs
204
+ * too, for the outline's links.
205
+ */
206
+ const scheme = /^[a-z][a-z0-9+.-]*:/i;
207
+ const hostAndPort = /^[^\s/?#@:]+:\d+(?:[/?#]|$)/;
208
+ const loopback = /^(?:localhost|127(?:\.\d+){3}|\[::1\])(?:[:/?#]|$)/i;
209
+ /** The URL `input` names. Without a scheme it is a web address: HTTPS, or HTTP on loopback. */
210
+ const parse = (input) => {
211
+ const text = input.trim();
212
+ if (scheme.test(text) && !hostAndPort.test(text)) return URL.parse(text);
213
+ return URL.parse(`${loopback.test(text) ? "http" : "https"}://${text}`);
214
+ };
215
+ /**
216
+ * The rule that reports an address without its credentials. The page script runs it too, so it
217
+ * stays self-contained, as `names.inpage.ts` says a page-side part must.
218
+ */
219
+ const addresses = () => {
220
+ const withheld = "••••••••";
221
+ const credential = /token|secret|passw|passcode|passphrase|signature|credential|assertion|verifier|bearer|jwt|hmac|apikey|accesskey|privatekey|sess(?:ion)?id|saml(?:response|art)|(?:sig|otp)$|(?:auth|api|access|private|secret|signing|client|encryption|licen[cs]e|session|master|app|device|verification|verify|confirmation|confirm|activation|activate|reset|recovery|login|security|magic|onetime|mfa|2fa|sms|email|otp|oob)(?:code|key)$|^(?:auth|authorization|pwd|pass)$/;
222
+ const ambiguous = /^(?:code|key|session|sid|ticket)$/;
223
+ const secret = (name, value) => {
224
+ const bare = name.toLowerCase().replace(/[^a-z0-9]/g, "");
225
+ return value !== "" && (credential.test(bare) || ambiguous.test(bare) && value.length >= 16 && /\d/.test(value) && /[a-z]/i.test(value));
226
+ };
227
+ const masked = (parameters, separator) => parameters.split(separator).map((parameter) => {
228
+ const [name = "", value = ""] = [...new URLSearchParams(parameter)][0] ?? [];
229
+ return secret(name, value) ? `${parameter.slice(0, parameter.indexOf("=") + 1)}${withheld}` : parameter;
230
+ }).join(separator);
231
+ /**
232
+ * `url` as the library reports it: without userinfo, and with each credential's value withheld,
233
+ * so the rest keeps its identity, such as a chart's `?ticker=ETH`. An address without a host,
234
+ * such as `data:` or `about:blank`, is content or a fixed name, and stays as it is.
235
+ */
236
+ const redact = (url) => {
237
+ const parsed = URL.parse(url);
238
+ if (parsed === null || parsed.host === "") return url;
239
+ parsed.username = "";
240
+ parsed.password = "";
241
+ parsed.pathname = masked(parsed.pathname, ";");
242
+ parsed.search = masked(parsed.search.slice(1), "&");
243
+ if (parsed.hash.includes("=")) {
244
+ const fragment = parsed.hash.slice(1);
245
+ const question = fragment.indexOf("?");
246
+ const start = question >= 0 && question < fragment.indexOf("=") ? question + 1 : 0;
247
+ parsed.hash = fragment.slice(0, start) + masked(fragment.slice(start), "&");
248
+ }
249
+ return parsed.href.replaceAll(encodeURIComponent(withheld), withheld);
250
+ };
251
+ return {
252
+ withheld,
253
+ redact
254
+ };
255
+ };
256
+ const { withheld, redact } = addresses();
257
+ /** An address inside text, as a failure's message quotes one. */
258
+ const quoted = /[a-z][a-z\d+.-]*:\/\/[^\s"'<>]+/gi;
259
+ /** `text` with each address in it redacted. */
260
+ const redactWithin = (text) => text.replace(quoted, (url) => redact(url));
261
+ //#endregion
262
+ export { redactWithin as a, FailFast as c, redact as i, make as l, parse as n, withheld as o, quoted as r, Correlation as s, addresses as t };
263
+
264
+ //# sourceMappingURL=url-Cd04Okid.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-Cd04Okid.mjs","names":[],"sources":["../src/internal/page/lane.ts","../src/internal/page/url.ts"],"sourcesContent":["/**\n * A page's admission: the one lane every operation on the page takes its turn in, so a page waits\n * only for itself. A write, an action that sends input or navigates, holds the lane alone, in the\n * order writes asked; reads share it, after the write in flight and every write asked before them,\n * so a read describes the page an action left, never one an action is still changing. Each write\n * starts a new epoch as it asks. A turn not given in time fails `Busy`, never `Timeout`, and a\n * caller under `FailFast` gets it at once.\n *\n * Reads keep their work. An identical read asked in the same epoch and document joins the one in\n * flight, which runs in the page's scope under the action timeout whoever gives up; one that ends\n * after all its callers gave up serves the next to ask the same, within an action timeout. A write\n * stops the reads nobody awaits, since no caller after it could use them.\n *\n * Effect's `Semaphore` is not fair to a writer that needs every permit, so the rule is this\n * module's own: one state, changed by `step` alone, which the model test drives.\n */\nimport { Context, Deferred, Duration, Effect, Exit, type Fiber, type Scope } from \"effect\";\n\nimport { BrowserError, Busy } from \"../../BrowserError.ts\";\nimport type { Gate } from \"../input/gate.ts\";\n\nexport type Kind = \"read\" | \"write\";\n\nexport interface Ticket {\n readonly id: number;\n readonly kind: Kind;\n}\n\n/** Who holds the lane: no one, reads together, or one write. */\nexport type Turn =\n | { readonly _tag: \"Free\" }\n | { readonly _tag: \"Reading\"; readonly count: number }\n | { readonly _tag: \"Writing\" };\n\nexport interface State {\n readonly turn: Turn;\n /** The tickets waiting, in the order they asked. */\n readonly queue: ReadonlyArray<Ticket>;\n /** The writes asked so far: two reads in one epoch follow the same writes. */\n readonly epoch: number;\n}\n\nexport type Input =\n | { readonly _tag: \"Ask\"; readonly ticket: Ticket }\n /** The ticket gave up waiting, or ended its turn. */\n | { readonly _tag: \"Leave\"; readonly ticket: Ticket };\n\nexport const initial: State = { turn: { _tag: \"Free\" }, queue: [], epoch: 0 };\n\nconst holders = (turn: Turn) =>\n turn._tag === \"Reading\" ? turn.count : turn._tag === \"Writing\" ? 1 : 0;\n\n/** Whether a ticket of `kind` asking now would hold the lane at once. */\nexport const admitsNow = ({ turn, queue }: State, kind: Kind) =>\n queue.length === 0 && (kind === \"read\" ? turn._tag !== \"Writing\" : turn._tag === \"Free\");\n\n/**\n * The operations ahead of a waiting ticket: those holding the lane and those asked before it, or\n * all that are queued for a ticket not in the queue.\n */\nexport const ahead = ({ turn, queue }: State, id?: number) => {\n const at = queue.findIndex((ticket) => ticket.id === id);\n\n return holders(turn) + (at === -1 ? queue.length : at);\n};\n\n/**\n * The lane after `input`, and the tickets it lets in. Tickets go in from the head of the queue\n * only: a write once the lane is free, reads while no write holds it, so reads asked before a\n * write go before it, and reads asked after it wait for it.\n */\nexport const step = (\n state: State,\n input: Input,\n): { readonly state: State; readonly admitted: ReadonlyArray<Ticket> } => {\n let { turn, queue, epoch } = state;\n\n if (input._tag === \"Ask\") {\n queue = [...queue, input.ticket];\n if (input.ticket.kind === \"write\") epoch += 1;\n } else {\n const at = queue.findIndex((ticket) => ticket.id === input.ticket.id);\n\n if (at !== -1) queue = queue.toSpliced(at, 1);\n else\n turn =\n turn._tag === \"Reading\" && turn.count > 1\n ? { _tag: \"Reading\", count: turn.count - 1 }\n : { _tag: \"Free\" };\n }\n\n const admitted: Array<Ticket> = [];\n\n for (const ticket of queue) {\n if (ticket.kind === \"write\" ? turn._tag !== \"Free\" : turn._tag === \"Writing\") break;\n admitted.push(ticket);\n turn =\n ticket.kind === \"write\" ? { _tag: \"Writing\" } : { _tag: \"Reading\", count: holders(turn) + 1 };\n }\n\n return { state: { turn, queue: queue.slice(admitted.length), epoch }, admitted };\n};\n\n/** Whether operations on a busy page fail `Busy` at once rather than wait their turn. */\nexport const FailFast = Context.Reference<boolean>(\"effect-browser/internal/page/FailFast\", {\n defaultValue: () => false,\n});\n\n/** The id a caller gives the actions it asks for, which each records as its `correlation`. */\nexport const Correlation = Context.Reference<string | undefined>(\n \"effect-browser/internal/page/Correlation\",\n { defaultValue: () => undefined },\n);\n\n/** A shared read in flight: its epoch, its result once it ends, and how many callers await it. */\ninterface Flight<A> {\n readonly epoch: number;\n readonly result: Deferred.Deferred<A, BrowserError>;\n waiting: number;\n fiber: Fiber.Fiber<A, BrowserError> | undefined;\n}\n\nexport const make = (options: {\n readonly now: () => number;\n readonly actionTimeout: Duration.Duration;\n /** When the page's current document began: a read is shared only within one. */\n readonly documentAt: () => number;\n /** The failure of a read still awaited as the page closes. */\n readonly gone: (operation: string) => BrowserError;\n /** The page's scope, which shared reads run in. */\n readonly scope: Scope.Scope;\n readonly inputGate?: Gate | undefined;\n}) => {\n const { now, actionTimeout } = options;\n let state = initial;\n let tickets = 0;\n const admissions = new Map<number, Deferred.Deferred<void>>();\n // Each shared read's sweep, which a write runs as it asks.\n const sweeps: Array<() => void> = [];\n\n const apply = (input: Input) => {\n const next = step(state, input);\n\n state = next.state;\n if (input._tag === \"Leave\") admissions.delete(input.ticket.id);\n for (const ticket of next.admitted) {\n const admitted = admissions.get(ticket.id);\n\n admissions.delete(ticket.id);\n if (admitted !== undefined) Deferred.doneUnsafe(admitted, Exit.void);\n }\n if (input._tag === \"Ask\" && input.ticket.kind === \"write\") for (const sweep of sweeps) sweep();\n };\n\n const busy = (operation: string, askedAt: number, id?: number) =>\n new BrowserError({\n operation,\n reason: new Busy({ waitedMillis: Math.round(now() - askedAt), ahead: ahead(state, id) }),\n dispatched: false,\n });\n\n /**\n * Run `effect` in a turn of `kind`, waiting at most `wait` for it, or failing `Busy`. The turn\n * ends with `effect`, however it ends.\n */\n const turn =\n (kind: Kind, operation: string, wait: Duration.Duration) =>\n <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | BrowserError, R> =>\n Effect.uninterruptibleMask((restore) =>\n Effect.gen(function* () {\n const ticket: Ticket = { id: ++tickets, kind };\n const askedAt = now();\n\n if (kind === \"write\" && options.inputGate !== undefined)\n yield* options.inputGate.check(operation);\n\n if ((yield* FailFast) && !admitsNow(state, kind)) return yield* busy(operation, askedAt);\n const admitted = Deferred.makeUnsafe<void>();\n\n admissions.set(ticket.id, admitted);\n apply({ _tag: \"Ask\", ticket });\n\n const waiting = Deferred.await(admitted).pipe(\n Effect.timeoutOrElse({\n duration: wait,\n orElse: () =>\n Deferred.isDoneUnsafe(admitted)\n ? Effect.void\n : Effect.fail(busy(operation, askedAt, ticket.id)),\n }),\n );\n\n const given = yield* Effect.exit(\n restore(\n kind === \"write\" && options.inputGate !== undefined\n ? Effect.raceFirst(waiting, options.inputGate.refused(operation))\n : waiting,\n ),\n );\n\n if (Exit.isFailure(given)) {\n apply({ _tag: \"Leave\", ticket });\n\n return yield* Effect.failCause(given.cause);\n }\n\n return yield* restore(effect).pipe(\n Effect.ensuring(Effect.sync(() => apply({ _tag: \"Leave\", ticket }))),\n );\n }),\n );\n\n /**\n * A read whose identical calls share their work: `work` runs once per epoch and document while\n * calls await it, and with `keep` its result serves the next call after all of them gave up,\n * within an action timeout of its end. Pictures, whose callers say how old they may be, only\n * join.\n */\n const shared = <A>(operation: string, keep: boolean) => {\n const flights = new Map<string, Flight<A>>();\n const kept = new Map<string, { readonly value: A; readonly until: number }>();\n\n sweeps.push(() => {\n kept.clear();\n for (const flight of flights.values())\n if (flight.waiting === 0) flight.fiber?.interruptUnsafe();\n });\n\n // A read in flight, its first caller waiting. However its fiber ends, even before it began,\n // as when the page closes, its callers hear.\n const start = (id: string, work: Effect.Effect<A, BrowserError>) =>\n Effect.gen(function* () {\n const flight: Flight<A> = {\n epoch: state.epoch,\n result: Deferred.makeUnsafe(),\n waiting: 1,\n fiber: undefined,\n };\n\n flights.set(id, flight);\n flight.fiber = yield* turn(\n \"read\",\n operation,\n actionTimeout,\n )(work).pipe(\n // The caller chose whether to wait; the work it started serves others too.\n Effect.provideService(FailFast, false),\n Effect.forkIn(options.scope),\n );\n flight.fiber.addObserver((exit) => {\n flights.delete(id);\n if (keep && Exit.isSuccess(exit) && flight.waiting === 0 && flight.epoch === state.epoch)\n kept.set(id, { value: exit.value, until: now() + Duration.toMillis(actionTimeout) });\n Deferred.doneUnsafe(\n flight.result,\n Exit.hasInterrupts(exit) ? Effect.fail(options.gone(operation)) : exit,\n );\n });\n\n return flight;\n });\n\n const join = (id: string, work: Effect.Effect<A, BrowserError>) =>\n Effect.acquireUseRelease(\n Effect.suspend(() => {\n const flying = flights.get(id);\n\n if (flying === undefined) return start(id, work);\n flying.waiting += 1;\n\n return Effect.as(Effect.annotateCurrentSpan(\"shared\", \"joined\"), flying);\n }),\n (flight) => Deferred.await(flight.result),\n (flight) =>\n Effect.sync(() => {\n flight.waiting -= 1;\n if (flight.waiting === 0 && flight.epoch < state.epoch) flight.fiber?.interruptUnsafe();\n }),\n );\n\n return (key: string, work: Effect.Effect<A, BrowserError>): Effect.Effect<A, BrowserError> =>\n Effect.gen(function* () {\n const id = `${state.epoch} ${options.documentAt()} ${key}`;\n const at = now();\n\n for (const [old, { until }] of kept) if (until < at) kept.delete(old);\n const hit = kept.get(id);\n\n if (hit !== undefined) {\n kept.delete(id);\n yield* Effect.annotateCurrentSpan(\"shared\", \"kept\");\n\n return hit.value;\n }\n if ((yield* FailFast) && !admitsNow(state, \"read\")) return yield* busy(operation, at);\n\n return yield* join(id, work);\n });\n };\n\n return {\n /** A turn alone, for an action: `wait` bounds the wait for it. */\n write: (operation: string, wait: Duration.Duration) => turn(\"write\", operation, wait),\n /** A turn beside other reads, waited for within the action timeout. */\n read: (operation: string, wait: Duration.Duration = actionTimeout) =>\n turn(\"read\", operation, wait),\n shared,\n };\n};\n\nexport type Lane = ReturnType<typeof make>;\n","/**\n * Addresses: reading one the way a person types it, for `Page.goto` and the browser tools alike,\n * and reporting one without the values that are credentials, by one rule that the page script runs\n * too, for the outline's links.\n */\n\nconst scheme = /^[a-z][a-z0-9+.-]*:/i;\n\n// `localhost:3000` and `example.com:8080/a` look like a scheme to the URL parser; a port decides.\nconst hostAndPort = /^[^\\s/?#@:]+:\\d+(?:[/?#]|$)/;\n\nconst loopback = /^(?:localhost|127(?:\\.\\d+){3}|\\[::1\\])(?:[:/?#]|$)/i;\n\n/** The URL `input` names. Without a scheme it is a web address: HTTPS, or HTTP on loopback. */\nexport const parse = (input: string): URL | null => {\n const text = input.trim();\n\n if (scheme.test(text) && !hostAndPort.test(text)) return URL.parse(text);\n\n return URL.parse(`${loopback.test(text) ? \"http\" : \"https\"}://${text}`);\n};\n\n/**\n * The rule that reports an address without its credentials. The page script runs it too, so it\n * stays self-contained, as `names.inpage.ts` says a page-side part must.\n */\nexport const addresses = () => {\n // What a credential's value reads as, as a secret field's text does (`Page.redacted`).\n const withheld = \"••••••••\" as const;\n\n // A parameter's name, compared in lowercase without separators, says it is a credential: a token,\n // secret, password, signature, assertion, session id or one-time code, or a code or key of a kind\n // that signs someone in or signs a request, such as `verification_code` or `api_key`.\n const credential =\n /token|secret|passw|passcode|passphrase|signature|credential|assertion|verifier|bearer|jwt|hmac|apikey|accesskey|privatekey|sess(?:ion)?id|saml(?:response|art)|(?:sig|otp)$|(?:auth|api|access|private|secret|signing|client|encryption|licen[cs]e|session|master|app|device|verification|verify|confirmation|confirm|activation|activate|reset|recovery|login|security|magic|onetime|mfa|2fa|sms|email|otp|oob)(?:code|key)$|^(?:auth|authorization|pwd|pass)$/;\n\n // These names as often say what an address is about, such as a stock code, a support ticket or a\n // conference session. Under them a value is a credential when it looks generated, at least 16\n // characters with letters and digits, as tokens, session ids and authorization codes do.\n const ambiguous = /^(?:code|key|session|sid|ticket)$/;\n\n const secret = (name: string, value: string) => {\n const bare = name.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n\n return (\n value !== \"\" &&\n (credential.test(bare) ||\n (ambiguous.test(bare) && value.length >= 16 && /\\d/.test(value) && /[a-z]/i.test(value)))\n );\n };\n\n // Parameters as written, each credential's value withheld: a query's, a fragment's written as a\n // query, or a path's segments', as a Java session id is.\n const masked = (parameters: string, separator: string) =>\n parameters\n .split(separator)\n .map((parameter) => {\n const [name = \"\", value = \"\"] = [...new URLSearchParams(parameter)][0] ?? [];\n\n return secret(name, value)\n ? `${parameter.slice(0, parameter.indexOf(\"=\") + 1)}${withheld}`\n : parameter;\n })\n .join(separator);\n\n /**\n * `url` as the library reports it: without userinfo, and with each credential's value withheld,\n * so the rest keeps its identity, such as a chart's `?ticker=ETH`. An address without a host,\n * such as `data:` or `about:blank`, is content or a fixed name, and stays as it is.\n */\n const redact = (url: string): string => {\n const parsed = URL.parse(url);\n\n if (parsed === null || parsed.host === \"\") return url;\n parsed.username = \"\";\n parsed.password = \"\";\n parsed.pathname = masked(parsed.pathname, \";\");\n parsed.search = masked(parsed.search.slice(1), \"&\");\n if (parsed.hash.includes(\"=\")) {\n const fragment = parsed.hash.slice(1);\n const question = fragment.indexOf(\"?\");\n // A route before the parameters, as in `#/inbox?token=…`, stays.\n const start = question >= 0 && question < fragment.indexOf(\"=\") ? question + 1 : 0;\n\n parsed.hash = fragment.slice(0, start) + masked(fragment.slice(start), \"&\");\n }\n\n return parsed.href.replaceAll(encodeURIComponent(withheld), withheld);\n };\n\n return { withheld, redact };\n};\n\nexport const { withheld, redact } = addresses();\n\n/** An address inside text, as a failure's message quotes one. */\nexport const quoted = /[a-z][a-z\\d+.-]*:\\/\\/[^\\s\"'<>]+/gi;\n\n/** `text` with each address in it redacted. */\nexport const redactWithin = (text: string) => text.replace(quoted, (url) => redact(url));\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,99 +1,134 @@
1
1
  {
2
2
  "name": "effect-browser",
3
- "version": "0.2.0-beta.9",
4
- "description": "Shared Effect browser sessions, modeled control and capture with an isolated Chromium launcher.",
3
+ "version": "0.3.0-beta.10",
4
+ "description": "Effect browser sessions, page control, screencast and moments over Playwright and CDP.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/mannyc2/effect-agent-browserbase.git",
9
9
  "directory": "packages/browser"
10
10
  },
11
- "type": "module",
12
- "sideEffects": [],
13
- "engines": {
14
- "node": "^22.18.0 || >=24.11.0"
15
- },
16
- "peerDependencies": {
17
- "effect": "4.0.0-rc.117",
18
- "playwright-core": "1.63.0"
19
- },
20
- "peerDependenciesMeta": {
21
- "playwright-core": {
22
- "optional": true
23
- }
24
- },
25
- "homepage": "https://github.com/mannyc2/effect-agent-browserbase#readme",
26
- "bugs": {
27
- "url": "https://github.com/mannyc2/effect-agent-browserbase/issues"
28
- },
29
11
  "files": [
30
- "dist"
12
+ "dist",
13
+ "src"
31
14
  ],
15
+ "type": "module",
16
+ "sideEffects": [],
32
17
  "exports": {
33
18
  ".": {
19
+ "@effect-browser/source": "./src/index.ts",
34
20
  "types": "./dist/index.d.mts",
35
21
  "default": "./dist/index.mjs"
36
22
  },
37
- "./bootstrap": {
38
- "types": "./dist/Bootstrap.d.mts",
39
- "default": "./dist/Bootstrap.mjs"
40
- },
41
- "./browser": {
23
+ "./Browser": {
24
+ "@effect-browser/source": "./src/Browser.ts",
42
25
  "types": "./dist/Browser.d.mts",
43
26
  "default": "./dist/Browser.mjs"
44
27
  },
45
- "./browser-data": {
46
- "types": "./dist/BrowserData.d.mts",
47
- "default": "./dist/BrowserData.mjs"
28
+ "./BrowserError": {
29
+ "@effect-browser/source": "./src/BrowserError.ts",
30
+ "types": "./dist/BrowserError.d.mts",
31
+ "default": "./dist/BrowserError.mjs"
48
32
  },
49
- "./browser-runtime": {
50
- "types": "./dist/BrowserRuntime.d.mts",
51
- "default": "./dist/BrowserRuntime.mjs"
33
+ "./BrowserEvent": {
34
+ "@effect-browser/source": "./src/BrowserEvent.ts",
35
+ "types": "./dist/BrowserEvent.d.mts",
36
+ "default": "./dist/BrowserEvent.mjs"
52
37
  },
53
- "./capture": {
54
- "types": "./dist/Capture.d.mts",
55
- "default": "./dist/Capture.mjs"
38
+ "./Change": {
39
+ "@effect-browser/source": "./src/Change.ts",
40
+ "types": "./dist/Change.d.mts",
41
+ "default": "./dist/Change.mjs"
56
42
  },
57
- "./capture-data": {
58
- "types": "./dist/CaptureData.d.mts",
59
- "default": "./dist/CaptureData.mjs"
43
+ "./Cdp": {
44
+ "@effect-browser/source": "./src/Cdp.ts",
45
+ "types": "./dist/Cdp.d.mts",
46
+ "default": "./dist/Cdp.mjs"
60
47
  },
61
- "./chromium": {
48
+ "./Chromium": {
49
+ "@effect-browser/source": "./src/Chromium.ts",
62
50
  "types": "./dist/Chromium.d.mts",
63
51
  "default": "./dist/Chromium.mjs"
64
52
  },
65
- "./errors": {
66
- "types": "./dist/Errors.d.mts",
67
- "default": "./dist/Errors.mjs"
53
+ "./Expect": {
54
+ "@effect-browser/source": "./src/Expect.ts",
55
+ "types": "./dist/Expect.d.mts",
56
+ "default": "./dist/Expect.mjs"
57
+ },
58
+ "./Frame": {
59
+ "@effect-browser/source": "./src/Frame.ts",
60
+ "types": "./dist/Frame.d.mts",
61
+ "default": "./dist/Frame.mjs"
62
+ },
63
+ "./Moment": {
64
+ "@effect-browser/source": "./src/Moment.ts",
65
+ "types": "./dist/Moment.d.mts",
66
+ "default": "./dist/Moment.mjs"
68
67
  },
69
- "./page-control": {
70
- "types": "./dist/PageControl.d.mts",
71
- "default": "./dist/PageControl.mjs"
68
+ "./Motion": {
69
+ "@effect-browser/source": "./src/Motion.ts",
70
+ "types": "./dist/Motion.d.mts",
71
+ "default": "./dist/Motion.mjs"
72
72
  },
73
- "./plan": {
73
+ "./Page": {
74
+ "@effect-browser/source": "./src/Page.ts",
75
+ "types": "./dist/Page.d.mts",
76
+ "default": "./dist/Page.mjs"
77
+ },
78
+ "./Plan": {
79
+ "@effect-browser/source": "./src/Plan.ts",
74
80
  "types": "./dist/Plan.d.mts",
75
81
  "default": "./dist/Plan.mjs"
76
82
  },
77
- "./plan-data": {
78
- "types": "./dist/PlanData.d.mts",
79
- "default": "./dist/PlanData.mjs"
83
+ "./Policy": {
84
+ "@effect-browser/source": "./src/Policy.ts",
85
+ "types": "./dist/Policy.d.mts",
86
+ "default": "./dist/Policy.mjs"
87
+ },
88
+ "./Presentation": {
89
+ "@effect-browser/source": "./src/Presentation.ts",
90
+ "types": "./dist/Presentation.d.mts",
91
+ "default": "./dist/Presentation.mjs"
80
92
  },
81
- "./testing": {
82
- "types": "./dist/Testing.d.mts",
83
- "default": "./dist/Testing.mjs"
93
+ "./Snapshot": {
94
+ "@effect-browser/source": "./src/Snapshot.ts",
95
+ "types": "./dist/Snapshot.d.mts",
96
+ "default": "./dist/Snapshot.mjs"
84
97
  },
85
- "./timeline": {
86
- "types": "./dist/Timeline.d.mts",
87
- "default": "./dist/Timeline.mjs"
98
+ "./Stage": {
99
+ "@effect-browser/source": "./src/Stage.ts",
100
+ "types": "./dist/Stage.d.mts",
101
+ "default": "./dist/Stage.mjs"
88
102
  },
89
- "./timeline-data": {
90
- "types": "./dist/TimelineData.d.mts",
91
- "default": "./dist/TimelineData.mjs"
103
+ "./Supervisor": {
104
+ "@effect-browser/source": "./src/Supervisor.ts",
105
+ "types": "./dist/Supervisor.d.mts",
106
+ "default": "./dist/Supervisor.mjs"
92
107
  }
93
108
  },
94
109
  "publishConfig": {
95
- "access": "public",
96
- "registry": "https://registry.npmjs.org/",
97
- "tag": "beta"
110
+ "access": "public"
111
+ },
112
+ "scripts": {
113
+ "build": "vp pack",
114
+ "check": "tsc --noEmit -p tsconfig.json",
115
+ "test": "vp test --run"
116
+ },
117
+ "devDependencies": {
118
+ "@effect/vitest": "4.0.0",
119
+ "@types/node": "26.1.2",
120
+ "effect": "4.0.0",
121
+ "playwright-core": "1.63.0",
122
+ "typescript": "7.0.2",
123
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.1.0",
124
+ "vite-plus": "1.1.0",
125
+ "vitest": "5.0.3"
126
+ },
127
+ "peerDependencies": {
128
+ "effect": "~4.0.0",
129
+ "playwright-core": "^1.63.0"
130
+ },
131
+ "engines": {
132
+ "node": "^22.18.0 || >=24.11.0"
98
133
  }
99
134
  }