effect-browser 0.3.0-beta.6 → 0.3.0-beta.7
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 +37 -2
- package/dist/{Browser-B5AV7zPS.mjs → Browser-CNwK0r0q.mjs} +2 -2
- package/dist/{Browser-B5AV7zPS.mjs.map → Browser-CNwK0r0q.mjs.map} +1 -1
- package/dist/Browser.d.mts +2 -2
- package/dist/Browser.mjs +1 -1
- package/dist/{BrowserEvent-DzdNdvoh.d.mts → BrowserEvent-BRu2juEz.d.mts} +3 -1
- package/dist/BrowserEvent.d.mts +1 -1
- package/dist/BrowserEvent.mjs +2 -0
- package/dist/BrowserEvent.mjs.map +1 -1
- package/dist/Cdp.mjs +1 -1
- package/dist/{Change-DVP2IJWm.d.mts → Change-iMlcuzVD.d.mts} +2 -2
- package/dist/Change.d.mts +1 -1
- package/dist/Chromium.mjs +1 -1
- package/dist/Expect.d.mts +1 -1
- package/dist/Expect.mjs +1 -1
- package/dist/Moment.d.mts +1 -1
- package/dist/{Page-DYTdVhYa.d.mts → Page-C30aG2RQ.d.mts} +6 -4
- package/dist/Page-D4281dIi.mjs.map +1 -1
- package/dist/Page.d.mts +1 -1
- package/dist/Plan-BvCS9qAf.d.mts +209 -0
- package/dist/{Plan-5MdsRzE5.mjs → Plan-CyQNv49C.mjs} +232 -38
- package/dist/Plan-CyQNv49C.mjs.map +1 -0
- package/dist/Plan.d.mts +2 -2
- package/dist/Plan.mjs +2 -2
- package/dist/Policy.d.mts +1 -1
- package/dist/Presentation.d.mts +1 -1
- package/dist/Presentation.mjs +1 -1
- package/dist/Stage.d.mts +1 -1
- package/dist/Stage.mjs +1 -1
- package/dist/{Supervisor-Im6-wbg5.d.mts → Supervisor-CLJaT7rG.d.mts} +2 -2
- package/dist/Supervisor.d.mts +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +2 -2
- package/dist/{page-BkRcLCWZ.mjs → page-DHeYWEs-.mjs} +27 -14
- package/dist/page-DHeYWEs-.mjs.map +1 -0
- package/package.json +1 -1
- package/src/BrowserEvent.ts +2 -0
- package/src/Page.ts +3 -1
- package/src/Plan.ts +365 -56
- package/src/internal/input/perform.ts +2 -0
- package/src/internal/page/bridge.ts +3 -3
- package/src/internal/reading/ready.inpage.ts +17 -7
- package/src/internal/reading/ready.ts +9 -3
- package/dist/Plan-5MdsRzE5.mjs.map +0 -1
- package/dist/Plan-CNNOU1Tx.d.mts +0 -112
- package/dist/page-BkRcLCWZ.mjs.map +0 -1
|
@@ -4,7 +4,7 @@ import { BrowserError, InvalidRequest } from "./BrowserError.mjs";
|
|
|
4
4
|
import { s as undispatched } from "./context-DAYjATgC.mjs";
|
|
5
5
|
import { p as redacted } from "./Page-D4281dIi.mjs";
|
|
6
6
|
import { t as match } from "./match.inpage-xOe9LNO0.mjs";
|
|
7
|
-
import { Duration, Effect, Schedule, Schema } from "effect";
|
|
7
|
+
import { Duration, Effect, Exit, Option, Schedule, Schema } from "effect";
|
|
8
8
|
//#region src/internal/reading/choose.ts
|
|
9
9
|
/**
|
|
10
10
|
* Choosing the one element a recorded subject names, among those `find` gives for its role and
|
|
@@ -93,23 +93,32 @@ const choose = (subject, found) => {
|
|
|
93
93
|
* it. Text typed into focus was typed into the focused field, which replay finds the same way, and
|
|
94
94
|
* text typed into a secret field goes into nothing else. An element step never falls back to
|
|
95
95
|
* coordinates, and a step recorded at a point acts there only while the element found for it still
|
|
96
|
-
* covers that point.
|
|
97
|
-
*
|
|
98
|
-
*
|
|
96
|
+
* covers that point. `take` and `replay` return receipts; failure preserves a stopping point and
|
|
97
|
+
* earlier receipts. Unknown consequential input is never resent. Only a positive durable read-back
|
|
98
|
+
* can reconcile it; restoration follows the same rule. The consumer journals begun steps before
|
|
99
|
+
* calling, treating interruption or a missing receipt as unknown. Plain recordings use version 1;
|
|
100
|
+
* authored expected effects use version 2. Old 0.2 plans and unknown versions do not decode.
|
|
99
101
|
*
|
|
100
102
|
* @since 0.3.0
|
|
101
103
|
*/
|
|
102
104
|
var Plan_exports = /* @__PURE__ */ __exportAll({
|
|
103
105
|
Ambiguous: () => Ambiguous,
|
|
104
106
|
Drifted: () => Drifted,
|
|
107
|
+
Expected: () => Expected,
|
|
105
108
|
Missing: () => Missing,
|
|
106
109
|
Plan: () => Plan,
|
|
110
|
+
Receipt: () => Receipt,
|
|
107
111
|
ReplayError: () => ReplayError,
|
|
108
112
|
Step: () => Step,
|
|
109
113
|
StepAction: () => StepAction,
|
|
114
|
+
Stopped: () => Stopped,
|
|
115
|
+
Uncertain: () => Uncertain,
|
|
110
116
|
fromEvents: () => fromEvents,
|
|
111
117
|
locate: () => locate,
|
|
112
|
-
|
|
118
|
+
repeatable: () => repeatable,
|
|
119
|
+
replay: () => replay,
|
|
120
|
+
restore: () => restore,
|
|
121
|
+
take: () => take
|
|
113
122
|
});
|
|
114
123
|
const ViewportPoint = Schema.Struct({
|
|
115
124
|
x: Schema.Finite,
|
|
@@ -127,10 +136,38 @@ const StepAction = Schema.Literals([
|
|
|
127
136
|
"scroll",
|
|
128
137
|
"select"
|
|
129
138
|
]);
|
|
139
|
+
const Query = Schema.Struct({
|
|
140
|
+
role: Schema.optional(Schema.String),
|
|
141
|
+
name: Schema.optional(Schema.String),
|
|
142
|
+
text: Schema.optional(Schema.String)
|
|
143
|
+
});
|
|
144
|
+
/**
|
|
145
|
+
* What a step leaves. `durable` asserts an author-chosen, lasting read-back of this operation,
|
|
146
|
+
* such as its uniquely named saved receipt. A toast or an intermediate address is not durable.
|
|
147
|
+
* Even a durable check's absence never authorizes repeating unknown consequential input.
|
|
148
|
+
*/
|
|
149
|
+
const Expected = Schema.Union([
|
|
150
|
+
Schema.TaggedStruct("Checked", { checked: Schema.Boolean }),
|
|
151
|
+
Schema.TaggedStruct("Appeared", {
|
|
152
|
+
query: Query,
|
|
153
|
+
durable: Schema.optional(Schema.Literal(true))
|
|
154
|
+
}),
|
|
155
|
+
Schema.TaggedStruct("Gone", {
|
|
156
|
+
query: Query,
|
|
157
|
+
durable: Schema.optional(Schema.Literal(true))
|
|
158
|
+
}),
|
|
159
|
+
Schema.TaggedStruct("Navigated", {
|
|
160
|
+
url: Schema.optional(Schema.String),
|
|
161
|
+
durable: Schema.optional(Schema.Literal(true))
|
|
162
|
+
})
|
|
163
|
+
]);
|
|
130
164
|
/** One recorded step: the action, what it acted on, and what else it was asked. */
|
|
131
165
|
var Step = class extends Schema.Class("effect-browser/Plan/Step")({
|
|
132
166
|
action: StepAction,
|
|
133
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* The ending address, or a later recorded navigation before the next action began. Empty when
|
|
169
|
+
* unknown; a delayed navigation can be stronger arrival evidence than the action's ending URL.
|
|
170
|
+
*/
|
|
134
171
|
url: Schema.String,
|
|
135
172
|
/** A navigation's requested address, or the keys a press pressed. */
|
|
136
173
|
target: Schema.optional(Schema.String),
|
|
@@ -149,27 +186,67 @@ var Step = class extends Schema.Class("effect-browser/Plan/Step")({
|
|
|
149
186
|
input: Schema.optional(Schema.String),
|
|
150
187
|
/** The slot's text went into a secret field, so replay types it into nothing else. */
|
|
151
188
|
secret: Schema.optional(Schema.Literal(true)),
|
|
152
|
-
options: Schema.optional(ActionOptions)
|
|
189
|
+
options: Schema.optional(ActionOptions),
|
|
190
|
+
expect: Schema.optional(Expected)
|
|
153
191
|
}) {};
|
|
154
|
-
|
|
155
|
-
version: Schema.
|
|
192
|
+
const PlanData = Schema.Struct({
|
|
193
|
+
version: Schema.Literals([1, 2]),
|
|
156
194
|
steps: Schema.Array(Step)
|
|
157
|
-
})
|
|
195
|
+
}).check(Schema.makeFilter((plan) => plan.version === (plan.steps.some((step) => step.expect !== void 0) ? 2 : 1) ? void 0 : "only plans with expected effects use version 2"));
|
|
196
|
+
var Plan = class Plan extends Schema.Class("effect-browser/Plan")(PlanData) {
|
|
197
|
+
/** Choose the encoding version from the steps; simple recordings remain version 1. */
|
|
198
|
+
static new(steps) {
|
|
199
|
+
return new Plan({
|
|
200
|
+
version: steps.some((step) => step.expect !== void 0) ? 2 : 1,
|
|
201
|
+
steps
|
|
202
|
+
});
|
|
203
|
+
}
|
|
158
204
|
/** The input slots its steps type, in order; replay needs text for each. */
|
|
159
205
|
get inputs() {
|
|
160
206
|
return this.steps.flatMap((step) => step.input === void 0 ? [] : [step.input]);
|
|
161
207
|
}
|
|
162
208
|
};
|
|
163
|
-
/**
|
|
209
|
+
/** One completed step, on the page's host clock. `verified` means its expected effect was seen. */
|
|
210
|
+
var Receipt = class extends Schema.Class("effect-browser/Plan/Receipt")({
|
|
211
|
+
step: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
212
|
+
outcome: Schema.Literals([
|
|
213
|
+
"taken",
|
|
214
|
+
"verified",
|
|
215
|
+
"skipped"
|
|
216
|
+
]),
|
|
217
|
+
startedAt: Schema.Finite,
|
|
218
|
+
at: Schema.Finite
|
|
219
|
+
}) {};
|
|
220
|
+
/** Durable stopping data. A begun step without a receipt must be restored as `unknown`. */
|
|
221
|
+
var Stopped = class extends Schema.Class("effect-browser/Plan/Stopped")({
|
|
222
|
+
step: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
223
|
+
input: Schema.Literals(["unsent", "unknown"])
|
|
224
|
+
}) {};
|
|
225
|
+
/** Repeating this step could repeat an unresolved effect; the consumer must reconcile it. */
|
|
226
|
+
var Uncertain = class extends Schema.TaggedError()("Uncertain", { detail: Schema.String }) {
|
|
227
|
+
get message() {
|
|
228
|
+
return this.detail;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
/** Where replay stopped, counting steps from 0, why, and the steps that completed before it. */
|
|
164
232
|
var ReplayError = class extends Schema.TaggedError()("ReplayError", {
|
|
165
233
|
step: Schema.Int,
|
|
166
234
|
reason: Schema.Union([
|
|
167
235
|
Missing,
|
|
168
236
|
Ambiguous,
|
|
169
237
|
Drifted,
|
|
170
|
-
BrowserError
|
|
171
|
-
|
|
238
|
+
BrowserError,
|
|
239
|
+
Uncertain
|
|
240
|
+
]),
|
|
241
|
+
input: Schema.Literals(["unsent", "unknown"]),
|
|
242
|
+
receipts: Schema.Array(Receipt)
|
|
172
243
|
}) {
|
|
244
|
+
get stopped() {
|
|
245
|
+
return new Stopped({
|
|
246
|
+
step: this.step,
|
|
247
|
+
input: this.input
|
|
248
|
+
});
|
|
249
|
+
}
|
|
173
250
|
get message() {
|
|
174
251
|
return `step ${this.step} failed: ${this.reason.message}`;
|
|
175
252
|
}
|
|
@@ -208,9 +285,11 @@ const fromEvents = (events) => {
|
|
|
208
285
|
steps: steps.map((action, index) => {
|
|
209
286
|
const drag = action.name === "drag" ? (action.target ?? "").split(" -> ") : void 0;
|
|
210
287
|
const point = pointIn(drag === void 0 ? action.target : drag[0]);
|
|
288
|
+
const until = steps[index + 1]?.startedAt ?? Number.POSITIVE_INFINITY;
|
|
289
|
+
const arrival = moves.findLast((move) => move.at > action.at && move.at <= until);
|
|
211
290
|
return new Step({
|
|
212
291
|
action: action.name,
|
|
213
|
-
url:
|
|
292
|
+
url: arrival?.url ?? action.url ?? before(until),
|
|
214
293
|
target: action.name === "navigate" || action.name === "press" ? action.target : void 0,
|
|
215
294
|
subject: action.subject,
|
|
216
295
|
to: action.to,
|
|
@@ -256,7 +335,7 @@ const aim = (page, subject, point, recorded) => {
|
|
|
256
335
|
const missed = new Drifted({ detail: "a press at the subject's point reaches another element" });
|
|
257
336
|
return locate(page, subject).pipe(Effect.flatMap((found) => Effect.flatMap(reach(found), (at) => at !== void 0 ? Effect.succeed(at) : page.hover(found.ref).pipe(Effect.andThen(locate(page, subject)), Effect.flatMap(reach), Effect.flatMap((again) => again === void 0 ? Effect.fail(missed) : Effect.succeed(again))))));
|
|
258
337
|
};
|
|
259
|
-
const
|
|
338
|
+
const dispatch = (page, step, text) => {
|
|
260
339
|
const options = step.options ?? {};
|
|
261
340
|
switch (step.action) {
|
|
262
341
|
case "navigate": return page.goto(step.input === void 0 ? step.target ?? step.url : text);
|
|
@@ -284,31 +363,146 @@ const take = (page, step, text) => {
|
|
|
284
363
|
}));
|
|
285
364
|
}
|
|
286
365
|
};
|
|
287
|
-
/**
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
366
|
+
/**
|
|
367
|
+
* Input that can be repeated without repeating a commitment. `take` also validates a Checked
|
|
368
|
+
* target's boolean state before input. Back/reload can resubmit a form.
|
|
369
|
+
*/
|
|
370
|
+
const repeatable = (step) => [
|
|
371
|
+
"navigate",
|
|
372
|
+
"hover",
|
|
373
|
+
"scroll",
|
|
374
|
+
"select"
|
|
375
|
+
].includes(step.action) || step.action === "type" && step.subject !== void 0 && step.options?.replace !== false && step.options?.submit !== true || step.action === "click" && step.expect?._tag === "Checked";
|
|
376
|
+
const within = (check, millis) => millis === 0 ? check : check.pipe(Effect.repeat({
|
|
377
|
+
until: (held) => held,
|
|
378
|
+
schedule: Schedule.spaced(Duration.millis(25))
|
|
379
|
+
}), Effect.timeoutOrElse({
|
|
380
|
+
duration: Duration.millis(millis),
|
|
381
|
+
orElse: () => Effect.succeed(false)
|
|
382
|
+
}));
|
|
383
|
+
const sameSite = (url, recorded) => {
|
|
384
|
+
const origin = URL.parse(recorded)?.origin;
|
|
385
|
+
return recorded === "" || (origin === void 0 || origin === "null" ? url === recorded : URL.parse(url)?.origin === origin);
|
|
386
|
+
};
|
|
387
|
+
const arrived = (page, urls, millis) => within(Effect.map(page.url, (url) => urls.some((recorded) => sameSite(url, recorded))), millis).pipe(Effect.filterOrFail((held) => held, () => new Drifted({ detail: "the page did not reach the recorded site within the arrival wait" })), Effect.asVoid);
|
|
388
|
+
const checkEffect = (page, step, first) => {
|
|
389
|
+
const expected = step.expect;
|
|
390
|
+
if (expected === void 0) return Effect.succeed(false);
|
|
391
|
+
switch (expected._tag) {
|
|
392
|
+
case "Checked": return step.subject === void 0 ? Effect.fail(invalid("a checked effect needs a subject")) : Effect.flatMap(locate(page, step.subject), (found) => found.state.checked === void 0 ? Effect.fail(invalid("a checked effect needs a checkable subject")) : Effect.succeed(found.state.checked === expected.checked));
|
|
393
|
+
case "Navigated": return Effect.map(page.state, (now) => expected.url === void 0 ? now.url !== first.url || now.document !== first.document : now.url === expected.url);
|
|
394
|
+
case "Appeared":
|
|
395
|
+
case "Gone": return Effect.map(page.find({
|
|
396
|
+
...expected.query,
|
|
397
|
+
scope: "document"
|
|
398
|
+
}), (found) => expected._tag === "Appeared" ? found.length > 0 : found.length === 0);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
/**
|
|
402
|
+
* Take one step. Unknown non-repeatable input is never resent: only positive durable read-back
|
|
403
|
+
* can skip it. An interrupted call remains interrupted; persist begun-before-call in the consumer
|
|
404
|
+
* and treat a missing receipt as Stopped{input: "unknown"}, including after process restart.
|
|
405
|
+
*/
|
|
406
|
+
const take = Effect.fn("Plan.take")(function* (page, plan, at, options = {}) {
|
|
407
|
+
const index = typeof at === "number" ? at : at.step;
|
|
408
|
+
let input = typeof at === "number" ? "unsent" : at.input;
|
|
409
|
+
return yield* Effect.gen(function* () {
|
|
410
|
+
const step = plan.steps[index];
|
|
411
|
+
if (!Number.isInteger(index) || index < 0 || step === void 0) return yield* invalid("the step index is outside the plan");
|
|
412
|
+
const duration = Duration.fromInput(options.arrival ?? Duration.seconds(5));
|
|
413
|
+
if (Option.isNone(duration) || Duration.isNegative(duration.value) || !Duration.isFinite(duration.value)) return yield* invalid("arrival must be a finite nonnegative duration");
|
|
414
|
+
const millis = Duration.toMillis(duration.value);
|
|
415
|
+
const first = yield* page.state;
|
|
416
|
+
const uncertain = new Uncertain({ detail: "the step may have been sent; reconcile its durable effect before continuing" });
|
|
417
|
+
const unresolved = input === "unknown" && !repeatable(step);
|
|
418
|
+
const expected = step.expect;
|
|
419
|
+
if (unresolved && (expected === void 0 || expected._tag === "Checked" || expected.durable !== true)) return yield* uncertain;
|
|
420
|
+
const settle = options.settle === false ? Effect.void : page.ready(options.settle);
|
|
421
|
+
if (![
|
|
422
|
+
"navigate",
|
|
423
|
+
"back",
|
|
424
|
+
"reload"
|
|
425
|
+
].includes(step.action)) yield* settle;
|
|
426
|
+
const before = plan.steps[index - 1]?.url;
|
|
427
|
+
if (before !== void 0) yield* arrived(page, unresolved ? [before, step.url] : [before], millis);
|
|
428
|
+
const check = checkEffect(page, step, first);
|
|
429
|
+
const held = yield* (millis === 0 ? check : check.pipe(Effect.timeoutOrElse({
|
|
430
|
+
duration: Duration.millis(millis),
|
|
431
|
+
orElse: () => Effect.fail(new Drifted({ detail: "the expected-effect read timed out" }))
|
|
432
|
+
}))).pipe(Effect.mapError((error) => unresolved ? uncertain : error));
|
|
433
|
+
const receipt = (outcome) => Effect.gen(function* () {
|
|
434
|
+
if (index === plan.steps.length - 1) yield* settle;
|
|
435
|
+
yield* arrived(page, [step.url], millis);
|
|
436
|
+
const now = yield* page.state;
|
|
437
|
+
return new Receipt({
|
|
438
|
+
step: index,
|
|
439
|
+
outcome,
|
|
440
|
+
startedAt: first.at,
|
|
441
|
+
at: now.at
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
if (held) return yield* receipt("skipped");
|
|
445
|
+
if (unresolved) return yield* uncertain;
|
|
446
|
+
const text = step.input === void 0 ? "" : options.inputs?.[step.input];
|
|
447
|
+
if (text === void 0) return yield* invalid(`no text for the input "${step.input ?? ""}"`);
|
|
448
|
+
const acted = yield* Effect.exit(dispatch(page, step, text));
|
|
449
|
+
if (Exit.isFailure(acted)) {
|
|
450
|
+
const error = Exit.findErrorOption(acted);
|
|
451
|
+
if (Option.isSome(error) && error.value._tag === "BrowserError" && error.value.dispatched) {
|
|
452
|
+
input = "unknown";
|
|
453
|
+
if (expected !== void 0 && (repeatable(step) || expected._tag !== "Checked" && expected.durable === true)) {
|
|
454
|
+
const observed = yield* Effect.exit(within(check, millis));
|
|
455
|
+
if (Exit.isSuccess(observed) && observed.value) return yield* receipt("verified");
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return yield* Effect.failCause(acted.cause);
|
|
459
|
+
}
|
|
460
|
+
input = "unknown";
|
|
461
|
+
if (expected !== void 0 && !(yield* within(check, millis))) return yield* new Drifted({ detail: "the step's expected effect did not arrive" });
|
|
462
|
+
return yield* receipt(expected === void 0 ? "taken" : "verified");
|
|
463
|
+
}).pipe(Effect.mapError((reason) => new ReplayError({
|
|
464
|
+
step: index,
|
|
465
|
+
reason,
|
|
466
|
+
input,
|
|
467
|
+
receipts: []
|
|
294
468
|
})));
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
469
|
+
});
|
|
470
|
+
const run = Effect.fnUntraced(function* (page, plan, options, from, until, restoring) {
|
|
471
|
+
const receipts = [];
|
|
472
|
+
const start = typeof from === "number" ? from : from.step;
|
|
473
|
+
if (!Number.isInteger(start) || start < 0 || start > plan.steps.length || !Number.isInteger(until) || until < start || until > plan.steps.length) return yield* new ReplayError({
|
|
474
|
+
step: start,
|
|
475
|
+
input: "unsent",
|
|
476
|
+
receipts,
|
|
477
|
+
reason: invalid("the run bounds are outside the plan")
|
|
478
|
+
});
|
|
479
|
+
if (!restoring && typeof from === "number") {
|
|
480
|
+
const unfilled = plan.steps.findIndex((step, index) => index >= start && step.input !== void 0 && options.inputs?.[step.input] === void 0);
|
|
481
|
+
if (unfilled !== -1) return yield* new ReplayError({
|
|
482
|
+
step: start,
|
|
483
|
+
input: "unsent",
|
|
484
|
+
receipts,
|
|
485
|
+
reason: invalid(`no text for the input "${plan.steps[unfilled]?.input ?? ""}"`)
|
|
486
|
+
});
|
|
305
487
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
488
|
+
for (let index = start; index < until; index++) {
|
|
489
|
+
const at = restoring ? new Stopped({
|
|
490
|
+
step: index,
|
|
491
|
+
input: "unknown"
|
|
492
|
+
}) : index === start ? from : index;
|
|
493
|
+
const receipt = yield* take(page, plan, at, options).pipe(Effect.mapError((error) => new ReplayError({
|
|
494
|
+
...error,
|
|
495
|
+
receipts: [...receipts]
|
|
496
|
+
})));
|
|
497
|
+
receipts.push(receipt);
|
|
309
498
|
}
|
|
310
|
-
|
|
499
|
+
return receipts;
|
|
500
|
+
});
|
|
501
|
+
/** Take a plan's steps from a fresh index or durable stopping point, returning completed receipts. */
|
|
502
|
+
const replay = (page, plan, options = {}) => run(page, plan, options, options.from ?? 0, plan.steps.length, false).pipe(Effect.withSpan("Plan.replay"));
|
|
503
|
+
/** Restore prior steps on a fresh page; unresolved commitments require positive durable evidence. */
|
|
504
|
+
const restore = (page, plan, options = {}) => run(page, plan, options, 0, options.upTo ?? plan.steps.length, true).pipe(Effect.withSpan("Plan.restore"));
|
|
311
505
|
//#endregion
|
|
312
|
-
export {
|
|
506
|
+
export { Drifted as _, ReplayError as a, Stopped as c, locate as d, repeatable as f, Ambiguous as g, take as h, Receipt as i, Uncertain as l, restore as m, Plan as n, Step as o, replay as p, Plan_exports as r, StepAction as s, Expected as t, fromEvents as u, Missing as v };
|
|
313
507
|
|
|
314
|
-
//# sourceMappingURL=Plan-
|
|
508
|
+
//# sourceMappingURL=Plan-CyQNv49C.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Plan-CyQNv49C.mjs","names":[],"sources":["../src/internal/reading/choose.ts","../src/Plan.ts"],"sourcesContent":["/**\n * Choosing the one element a recorded subject names, among those `find` gives for its role and\n * name. Context tells them apart, and an element that does not repeat every part of the recorded\n * context is another subject, so a sole element left once its own has gone, such as Alice's\n * \"Remove\" after Bob has left, drifts rather than stands in:\n *\n * - a row is read whole: a row named \"Wrapped BTC\" is not the row \"BTC\". Laid out again without\n * rows, as cards, one of the element's fields must start with the row's words;\n * - a column counts where the element is under one;\n * - a label or heading must read the same, or its words appear, whole and in order, in one of the\n * element's fields, as `near` reads them.\n *\n * The rest are ranked by how much of the recorded context they read the same. There is no\n * ordinal, so a tie stays a tie.\n */\nimport { Effect, Schema } from \"effect\";\n\nimport type { Subject, SubjectContext } from \"../../BrowserEvent.ts\";\nimport type { Found } from \"../../Page.ts\";\nimport { match } from \"./match.inpage.ts\";\n\n/** Nothing on the page has the step's role and name. */\nexport class Missing extends Schema.TaggedError<Missing>()(\"Missing\", {}) {\n override get message() {\n return \"nothing on the page has the recorded role and name\";\n }\n}\n\n/** Several elements match the step's subject equally well, and nothing tells them apart. */\nexport class Ambiguous extends Schema.TaggedError<Ambiguous>()(\"Ambiguous\", {\n count: Schema.Int,\n}) {\n override get message() {\n return `${this.count} elements match the recorded subject equally well`;\n }\n}\n\n/** The page is not where the recording was: another site, or no element with its context. */\nexport class Drifted extends Schema.TaggedError<Drifted>()(\"Drifted\", {\n detail: Schema.String,\n}) {\n override get message() {\n return this.detail;\n }\n}\n\nconst { holds, normalize } = match();\nconst fields = [\"row\", \"column\", \"label\", \"heading\"] as const;\n\nconst said = (context: SubjectContext) =>\n Object.values(context).filter((value) => typeof value === \"string\");\n\n/** How an element repeats one recorded field: 2 read the same, 1 found as words, 0 not at all. */\nconst repeats = (field: (typeof fields)[number], value: string, context: SubjectContext) => {\n const own = context[field];\n\n if (own !== undefined && normalize(own) === normalize(value)) return 2;\n if (field === \"column\") return own === undefined ? 1 : 0;\n if (field === \"row\")\n return own === undefined &&\n said(context).some((other) => `${normalize(other)} `.startsWith(`${normalize(value)} `))\n ? 1\n : 0;\n\n return said(context).some((other) => holds(other, value)) ? 1 : 0;\n};\n\nexport const choose = (\n subject: Subject,\n found: ReadonlyArray<Found>,\n): Effect.Effect<Found, Missing | Ambiguous | Drifted> => {\n // `find` matched the role; a subject without one only matches elements without one.\n const named = found.filter((one) => subject.role !== null || one.subject.role === null);\n\n const kept = named.flatMap((one) => {\n let score = 0;\n\n for (const field of fields) {\n const value = subject.context[field];\n const repeated = value === undefined ? 0 : repeats(field, value, one.subject.context);\n\n if (value !== undefined && repeated === 0) return [];\n score += repeated;\n }\n\n return [{ one, score }];\n });\n\n const best = Math.max(...kept.map(({ score }) => score));\n const top = kept.filter(({ score }) => score === best);\n const [only] = top;\n\n if (named.length === 0) return Effect.fail(new Missing());\n if (kept.length === 0)\n return Effect.fail(new Drifted({ detail: \"no element named so repeats the recorded context\" }));\n\n return top.length === 1 && only !== undefined\n ? Effect.succeed(only.one)\n : Effect.fail(new Ambiguous({ count: top.length }));\n};\n","/**\n * A walk recorded once from a page's events and replayed later, on a fresh page, with no model\n * call.\n *\n * `fromEvents` keeps one page's completed actions with their subjects and the options they were\n * given, its navigations with both the address asked for and the one reached, and what was typed\n * as a named input slot, never the text itself. A navigation to an address whose credentials the\n * events withheld is an input slot too, so replay goes where the caller says, or nowhere, and\n * never to the address without them. `replay` takes the steps in turn. Before a step\n * that acts on the page, it waits for `Page.ready`; then it finds the one element the step's\n * subject names, by role and name among those that repeat all its recorded context, and acts on\n * it. Text typed into focus was typed into the focused field, which replay finds the same way, and\n * text typed into a secret field goes into nothing else. An element step never falls back to\n * coordinates, and a step recorded at a point acts there only while the element found for it still\n * covers that point. `take` and `replay` return receipts; failure preserves a stopping point and\n * earlier receipts. Unknown consequential input is never resent. Only a positive durable read-back\n * can reconcile it; restoration follows the same rule. The consumer journals begun steps before\n * calling, treating interruption or a missing receipt as unknown. Plain recordings use version 1;\n * authored expected effects use version 2. Old 0.2 plans and unknown versions do not decode.\n *\n * @since 0.3.0\n */\nimport { Duration, Effect, Exit, Option, Schedule, Schema } from \"effect\";\n\nimport { BrowserError, InvalidRequest } from \"./BrowserError.ts\";\nimport {\n type Action,\n ActionOptions,\n Box,\n type BrowserEvent,\n type Navigated,\n Subject,\n} from \"./BrowserEvent.ts\";\nimport { undispatched } from \"./internal/page/context.ts\";\nimport { Ambiguous, choose, Drifted, Missing } from \"./internal/reading/choose.ts\";\nimport {\n type Found,\n type Page,\n type Point,\n type ReadyOptions,\n redacted,\n type Target,\n} from \"./Page.ts\";\n\nexport { Ambiguous, Drifted, Missing } from \"./internal/reading/choose.ts\";\n\nconst ViewportPoint = Schema.Struct({ x: Schema.Finite, y: Schema.Finite });\n\nexport const StepAction = Schema.Literals([\n \"navigate\",\n \"back\",\n \"reload\",\n \"click\",\n \"hover\",\n \"drag\",\n \"type\",\n \"press\",\n \"scroll\",\n \"select\",\n]);\n\nexport type StepAction = typeof StepAction.Type;\n\nconst Query = Schema.Struct({\n role: Schema.optional(Schema.String),\n name: Schema.optional(Schema.String),\n text: Schema.optional(Schema.String),\n});\n\n/**\n * What a step leaves. `durable` asserts an author-chosen, lasting read-back of this operation,\n * such as its uniquely named saved receipt. A toast or an intermediate address is not durable.\n * Even a durable check's absence never authorizes repeating unknown consequential input.\n */\nexport const Expected = Schema.Union([\n Schema.TaggedStruct(\"Checked\", { checked: Schema.Boolean }),\n Schema.TaggedStruct(\"Appeared\", {\n query: Query,\n durable: Schema.optional(Schema.Literal(true)),\n }),\n Schema.TaggedStruct(\"Gone\", {\n query: Query,\n durable: Schema.optional(Schema.Literal(true)),\n }),\n Schema.TaggedStruct(\"Navigated\", {\n url: Schema.optional(Schema.String),\n durable: Schema.optional(Schema.Literal(true)),\n }),\n]);\n\nexport type Expected = typeof Expected.Type;\n\n/** One recorded step: the action, what it acted on, and what else it was asked. */\nexport class Step extends Schema.Class<Step>(\"effect-browser/Plan/Step\")({\n action: StepAction,\n /**\n * The ending address, or a later recorded navigation before the next action began. Empty when\n * unknown; a delayed navigation can be stronger arrival evidence than the action's ending URL.\n */\n url: Schema.String,\n /** A navigation's requested address, or the keys a press pressed. */\n target: Schema.optional(Schema.String),\n subject: Schema.optional(Subject),\n /** Where a drag ended. */\n to: Schema.optional(Subject),\n /** The viewport point a step aimed at, when it aimed at a point, and a drag's end point. */\n point: Schema.optional(ViewportPoint),\n toPoint: Schema.optional(ViewportPoint),\n /** The box of what a step aimed at by point found there, so replay aims at the same place in it. */\n box: Schema.optional(Box),\n /**\n * The input slot whose text a `type` step types, or whose address a `navigate` step goes to, as\n * its recorded address had a credential withheld.\n */\n input: Schema.optional(Schema.String),\n /** The slot's text went into a secret field, so replay types it into nothing else. */\n secret: Schema.optional(Schema.Literal(true)),\n options: Schema.optional(ActionOptions),\n expect: Schema.optional(Expected),\n}) {}\n\nconst PlanData = Schema.Struct({\n version: Schema.Literals([1, 2]),\n steps: Schema.Array(Step),\n}).check(\n Schema.makeFilter((plan) =>\n plan.version === (plan.steps.some((step) => step.expect !== undefined) ? 2 : 1)\n ? undefined\n : \"only plans with expected effects use version 2\",\n ),\n);\n\nexport class Plan extends Schema.Class<Plan>(\"effect-browser/Plan\")(PlanData) {\n /** Choose the encoding version from the steps; simple recordings remain version 1. */\n static new(steps: ReadonlyArray<Step>): Plan {\n return new Plan({ version: steps.some((step) => step.expect !== undefined) ? 2 : 1, steps });\n }\n\n /** The input slots its steps type, in order; replay needs text for each. */\n get inputs(): ReadonlyArray<string> {\n return this.steps.flatMap((step) => (step.input === undefined ? [] : [step.input]));\n }\n}\n\n/** One completed step, on the page's host clock. `verified` means its expected effect was seen. */\nexport class Receipt extends Schema.Class<Receipt>(\"effect-browser/Plan/Receipt\")({\n step: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n outcome: Schema.Literals([\"taken\", \"verified\", \"skipped\"]),\n startedAt: Schema.Finite,\n at: Schema.Finite,\n}) {}\n\n/** Durable stopping data. A begun step without a receipt must be restored as `unknown`. */\nexport class Stopped extends Schema.Class<Stopped>(\"effect-browser/Plan/Stopped\")({\n step: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n input: Schema.Literals([\"unsent\", \"unknown\"]),\n}) {}\n\n/** Repeating this step could repeat an unresolved effect; the consumer must reconcile it. */\nexport class Uncertain extends Schema.TaggedError<Uncertain>()(\"Uncertain\", {\n detail: Schema.String,\n}) {\n override get message() {\n return this.detail;\n }\n}\n\n/** Where replay stopped, counting steps from 0, why, and the steps that completed before it. */\nexport class ReplayError extends Schema.TaggedError<ReplayError>()(\"ReplayError\", {\n step: Schema.Int,\n reason: Schema.Union([Missing, Ambiguous, Drifted, BrowserError, Uncertain]),\n input: Schema.Literals([\"unsent\", \"unknown\"]),\n receipts: Schema.Array(Receipt),\n}) {\n get stopped(): Stopped {\n return new Stopped({ step: this.step, input: this.input });\n }\n\n override get message() {\n return `step ${this.step} failed: ${this.reason.message}`;\n }\n}\n\nconst isStep = (event: BrowserEvent): event is Action & { readonly name: StepAction } =>\n event._tag === \"Action\" &&\n event.ok &&\n (StepAction.literals as ReadonlyArray<string>).includes(event.name);\n\n// A point target reads `x,y`, as `{\"x\":…,\"y\":…}` inside a drag's; a ref reads like e12.\nconst pointIn = (target: string | undefined): Point | undefined => {\n const parsed = /^\\{?(?:\"x\":)?(-?[\\d.]+),(?:\"y\":)?(-?[\\d.]+)\\}?$/.exec(target ?? \"\");\n\n return parsed === null ? undefined : { x: Number(parsed[1]), y: Number(parsed[2]) };\n};\n\n/** A slot named for the field it fills, such as `email`, unique within the plan. */\nconst slotFor = (taken: Set<string>, field: string | undefined) => {\n const base =\n field\n ?.toLowerCase()\n .match(/[\\p{L}\\p{N}]+/gu)\n ?.join(\"-\") ?? \"input\";\n\n let slot = base;\n\n for (let count = 2; taken.has(slot); count++) slot = `${base}-${count}`;\n taken.add(slot);\n\n return slot;\n};\n\n/**\n * The walk one page's events record: the completed actions of the page that acted first, in\n * order. `page.recentEvents` gives them, or `browser.events()` read until the walk ends.\n */\nexport const fromEvents = (events: Iterable<BrowserEvent>): Plan => {\n const all = Array.from(events);\n const page = all.find((event) => event._tag === \"Action\")?.page;\n const mine = all.filter((event) => \"page\" in event && event.page === page);\n const steps = mine.filter(isStep);\n const opened = mine.find((event) => event._tag === \"PageOpened\")?.url ?? \"\";\n const moves = mine.filter((event): event is Navigated => event._tag === \"Navigated\");\n const taken = new Set<string>();\n\n // Where the page was just before a time: the last address it reached by then.\n const before = (time: number) => moves.findLast((move) => move.at <= time)?.url ?? opened;\n\n return new Plan({\n version: 1,\n steps: steps.map((action, index) => {\n const drag = action.name === \"drag\" ? (action.target ?? \"\").split(\" -> \") : undefined;\n const point = pointIn(drag === undefined ? action.target : drag[0]);\n const until = steps[index + 1]?.startedAt ?? Number.POSITIVE_INFINITY;\n const arrival = moves.findLast((move) => move.at > action.at && move.at <= until);\n\n // Only a navigation and a press keep their target: an address, or keys.\n return new Step({\n action: action.name,\n url: arrival?.url ?? action.url ?? before(until),\n target: action.name === \"navigate\" || action.name === \"press\" ? action.target : undefined,\n subject: action.subject,\n to: action.to,\n point,\n toPoint: pointIn(drag?.[1]),\n box: point === undefined ? undefined : action.box,\n input:\n action.name === \"type\"\n ? slotFor(taken, action.subject?.name)\n : action.name === \"navigate\" && action.target?.includes(redacted) === true\n ? slotFor(taken, \"address\")\n : undefined,\n secret: action.name === \"type\" && action.text === redacted ? true : undefined,\n options: action.options,\n });\n }),\n });\n};\n\n/**\n * The one element on the page that a subject names, by role, name and context (see `Plan`),\n * looking again for two seconds while the page may still be drawing it.\n */\nexport const locate = (page: Page, subject: Subject) =>\n page\n .find({\n name: subject.name,\n scope: \"document\",\n ...(subject.role === null ? {} : { role: subject.role }),\n })\n .pipe(\n Effect.flatMap((found) => choose(subject, found)),\n Effect.retry({\n schedule: Schedule.spaced(Duration.millis(250)),\n times: 8,\n while: (error) => error._tag !== \"BrowserError\",\n }),\n Effect.withSpan(\"Plan.locate\", { attributes: { role: subject.role ?? \"\" } }),\n );\n\nconst invalid = (detail: string) => undispatched(\"replay\", new InvalidRequest({ detail }));\n\n/**\n * Where the step acts: the element its subject names, or, for a step recorded at a point, the same\n * place within that element, as long as a press there reaches that element and not one over it.\n * An element out of view is first brought into it, by hovering it, as a press by ref would be.\n */\nconst aim = (page: Page, subject: Subject | undefined, point?: Point, recorded?: Box) => {\n if (subject === undefined) return Effect.fail(invalid(\"the step names no element\"));\n if (point === undefined) return Effect.map(locate(page, subject), ({ ref }): Target => ref);\n\n const reach = ({ ref, box }: Found) => {\n const at =\n recorded === undefined || recorded.width <= 0 || recorded.height <= 0\n ? point\n : {\n x: box.x + ((point.x - recorded.x) / recorded.width) * box.width,\n y: box.y + ((point.y - recorded.y) / recorded.height) * box.height,\n };\n\n return Effect.map(page.find({ at }), ([reached]) => (reached?.ref === ref ? at : undefined));\n };\n\n const missed = new Drifted({ detail: \"a press at the subject's point reaches another element\" });\n\n return locate(page, subject).pipe(\n Effect.flatMap((found) =>\n Effect.flatMap(reach(found), (at) =>\n at !== undefined\n ? Effect.succeed<Target>(at)\n : page.hover(found.ref).pipe(\n Effect.andThen(locate(page, subject)),\n Effect.flatMap(reach),\n Effect.flatMap((again) =>\n again === undefined ? Effect.fail(missed) : Effect.succeed<Target>(again),\n ),\n ),\n ),\n ),\n );\n};\n\nconst dispatch = (\n page: Page,\n step: Step,\n text: string,\n): Effect.Effect<void, Missing | Ambiguous | Drifted | BrowserError> => {\n const options = step.options ?? {};\n\n switch (step.action) {\n case \"navigate\":\n return page.goto(step.input === undefined ? (step.target ?? step.url) : text);\n case \"back\":\n return page.back;\n case \"reload\":\n return page.reload;\n case \"press\":\n return step.subject === undefined\n ? page.press(step.target ?? \"\", options)\n : Effect.flatMap(locate(page, step.subject), ({ ref }) =>\n page.press(step.target ?? \"\", { ...options, on: ref }),\n );\n case \"click\":\n return aim(page, step.subject, step.point, step.box).pipe(\n Effect.flatMap((at) => page.click(at, options)),\n Effect.asVoid,\n );\n case \"hover\":\n return Effect.flatMap(aim(page, step.subject, step.point, step.box), page.hover);\n case \"drag\":\n return Effect.all([\n aim(page, step.subject, step.point),\n aim(page, step.to, step.toPoint),\n ]).pipe(Effect.flatMap(([from, to]) => page.drag(from, to)));\n case \"select\":\n return aim(page, step.subject).pipe(\n Effect.flatMap((at) => page.select(typeof at === \"string\" ? at : \"\", options.values ?? [])),\n Effect.asVoid,\n );\n // A scroll or a typing step may name no element: the page, or whatever has focus.\n case \"scroll\":\n return step.subject === undefined\n ? page.scroll(options)\n : Effect.flatMap(aim(page, step.subject, step.point, step.box), (at) =>\n page.scroll({ ...options, at }),\n );\n case \"type\":\n return step.subject === undefined\n ? page.type(text, { ...options, secret: step.secret })\n : Effect.flatMap(aim(page, step.subject), (into) =>\n page.type(text, {\n ...options,\n into: typeof into === \"string\" ? into : undefined,\n secret: step.secret,\n }),\n );\n }\n};\n\nexport interface TakeOptions {\n /** How each step waits for the page first, or false not to wait. */\n readonly settle?: ReadyOptions | false | undefined;\n readonly inputs?: Readonly<Record<string, string>> | undefined;\n /**\n * Bound for recorded arrival and expected effect, each. Defaults to 5 seconds. Zero makes one\n * read without polling; that read retains the page operation's timeout.\n */\n readonly arrival?: Duration.Input | undefined;\n}\n\nexport interface ReplayOptions extends TakeOptions {\n readonly from?: number | Stopped | undefined;\n}\n\n/**\n * Input that can be repeated without repeating a commitment. `take` also validates a Checked\n * target's boolean state before input. Back/reload can resubmit a form.\n */\nexport const repeatable = (step: Step): boolean =>\n [\"navigate\", \"hover\", \"scroll\", \"select\"].includes(step.action) ||\n (step.action === \"type\" &&\n step.subject !== undefined &&\n step.options?.replace !== false &&\n step.options?.submit !== true) ||\n (step.action === \"click\" && step.expect?._tag === \"Checked\");\n\ntype StepError = Missing | Ambiguous | Drifted | BrowserError | Uncertain;\n\n// Zero waits make one read; positive waits bound all reads and never repeat input.\nconst within = (check: Effect.Effect<boolean, StepError>, millis: number) =>\n millis === 0\n ? check\n : check.pipe(\n Effect.repeat({ until: (held) => held, schedule: Schedule.spaced(Duration.millis(25)) }),\n Effect.timeoutOrElse({\n duration: Duration.millis(millis),\n orElse: () => Effect.succeed(false),\n }),\n );\n\nconst sameSite = (url: string, recorded: string) => {\n const origin = URL.parse(recorded)?.origin;\n\n return (\n recorded === \"\" ||\n (origin === undefined || origin === \"null\"\n ? url === recorded\n : URL.parse(url)?.origin === origin)\n );\n};\n\nconst arrived = (page: Page, urls: ReadonlyArray<string>, millis: number) =>\n within(\n Effect.map(page.url, (url) => urls.some((recorded) => sameSite(url, recorded))),\n millis,\n ).pipe(\n Effect.filterOrFail(\n (held) => held,\n () =>\n new Drifted({ detail: \"the page did not reach the recorded site within the arrival wait\" }),\n ),\n Effect.asVoid,\n );\n\nconst checkEffect = (\n page: Page,\n step: Step,\n first: { readonly url: string; readonly document: number },\n) => {\n const expected = step.expect;\n\n if (expected === undefined) return Effect.succeed(false);\n switch (expected._tag) {\n case \"Checked\":\n return step.subject === undefined\n ? Effect.fail(invalid(\"a checked effect needs a subject\"))\n : Effect.flatMap(locate(page, step.subject), (found) =>\n found.state.checked === undefined\n ? Effect.fail(invalid(\"a checked effect needs a checkable subject\"))\n : Effect.succeed(found.state.checked === expected.checked),\n );\n case \"Navigated\":\n return Effect.map(page.state, (now) =>\n expected.url === undefined\n ? now.url !== first.url || now.document !== first.document\n : now.url === expected.url,\n );\n case \"Appeared\":\n case \"Gone\":\n return Effect.map(page.find({ ...expected.query, scope: \"document\" }), (found) =>\n expected._tag === \"Appeared\" ? found.length > 0 : found.length === 0,\n );\n }\n};\n\n/**\n * Take one step. Unknown non-repeatable input is never resent: only positive durable read-back\n * can skip it. An interrupted call remains interrupted; persist begun-before-call in the consumer\n * and treat a missing receipt as Stopped{input: \"unknown\"}, including after process restart.\n */\nexport const take = Effect.fn(\"Plan.take\")(function* (\n page: Page,\n plan: Plan,\n at: number | Stopped,\n options: TakeOptions = {},\n): Effect.fn.Return<Receipt, ReplayError> {\n const index = typeof at === \"number\" ? at : at.step;\n let input: Stopped[\"input\"] = typeof at === \"number\" ? \"unsent\" : at.input;\n\n const work = Effect.gen(function* (): Effect.fn.Return<Receipt, StepError> {\n const step = plan.steps[index];\n\n if (!Number.isInteger(index) || index < 0 || step === undefined)\n return yield* invalid(\"the step index is outside the plan\");\n const duration = Duration.fromInput(options.arrival ?? Duration.seconds(5));\n\n if (\n Option.isNone(duration) ||\n Duration.isNegative(duration.value) ||\n !Duration.isFinite(duration.value)\n )\n return yield* invalid(\"arrival must be a finite nonnegative duration\");\n const millis = Duration.toMillis(duration.value);\n const first = yield* page.state;\n\n const uncertain = new Uncertain({\n detail: \"the step may have been sent; reconcile its durable effect before continuing\",\n });\n\n const unresolved = input === \"unknown\" && !repeatable(step);\n const expected = step.expect;\n\n if (\n unresolved &&\n (expected === undefined || expected._tag === \"Checked\" || expected.durable !== true)\n )\n return yield* uncertain;\n const settle = options.settle === false ? Effect.void : page.ready(options.settle);\n\n if (![\"navigate\", \"back\", \"reload\"].includes(step.action)) yield* settle;\n const before = plan.steps[index - 1]?.url;\n\n if (before !== undefined)\n yield* arrived(page, unresolved ? [before, step.url] : [before], millis);\n const check = checkEffect(page, step, first);\n\n const read =\n millis === 0\n ? check\n : check.pipe(\n Effect.timeoutOrElse({\n duration: Duration.millis(millis),\n orElse: () =>\n Effect.fail(new Drifted({ detail: \"the expected-effect read timed out\" })),\n }),\n );\n\n const held = yield* read.pipe(Effect.mapError((error) => (unresolved ? uncertain : error)));\n\n const receipt = (outcome: Receipt[\"outcome\"]) =>\n Effect.gen(function* () {\n if (index === plan.steps.length - 1) yield* settle;\n yield* arrived(page, [step.url], millis);\n const now = yield* page.state;\n\n return new Receipt({ step: index, outcome, startedAt: first.at, at: now.at });\n });\n\n if (held) return yield* receipt(\"skipped\");\n if (unresolved) return yield* uncertain;\n const text = step.input === undefined ? \"\" : options.inputs?.[step.input];\n\n if (text === undefined) return yield* invalid(`no text for the input \"${step.input ?? \"\"}\"`);\n const acted = yield* Effect.exit(dispatch(page, step, text));\n\n if (Exit.isFailure(acted)) {\n const error = Exit.findErrorOption(acted);\n\n if (Option.isSome(error) && error.value._tag === \"BrowserError\" && error.value.dispatched) {\n input = \"unknown\";\n if (\n expected !== undefined &&\n (repeatable(step) || (expected._tag !== \"Checked\" && expected.durable === true))\n ) {\n const observed = yield* Effect.exit(within(check, millis));\n\n if (Exit.isSuccess(observed) && observed.value) return yield* receipt(\"verified\");\n }\n }\n\n return yield* Effect.failCause(acted.cause);\n }\n input = \"unknown\";\n if (expected !== undefined && !(yield* within(check, millis)))\n return yield* new Drifted({ detail: \"the step's expected effect did not arrive\" });\n\n return yield* receipt(expected === undefined ? \"taken\" : \"verified\");\n });\n\n return yield* work.pipe(\n Effect.mapError(\n (reason) =>\n new ReplayError({\n step: index,\n reason,\n input,\n receipts: [],\n }),\n ),\n );\n});\n\nconst run = Effect.fnUntraced(function* (\n page: Page,\n plan: Plan,\n options: TakeOptions,\n from: number | Stopped,\n until: number,\n restoring: boolean,\n) {\n const receipts: Array<Receipt> = [];\n const start = typeof from === \"number\" ? from : from.step;\n\n if (\n !Number.isInteger(start) ||\n start < 0 ||\n start > plan.steps.length ||\n !Number.isInteger(until) ||\n until < start ||\n until > plan.steps.length\n )\n return yield* new ReplayError({\n step: start,\n input: \"unsent\",\n receipts,\n reason: invalid(\"the run bounds are outside the plan\"),\n });\n // Fresh runs still ask for all input slots before changing the page. Restoration checks first.\n if (!restoring && typeof from === \"number\") {\n const unfilled = plan.steps.findIndex(\n (step, index) =>\n index >= start && step.input !== undefined && options.inputs?.[step.input] === undefined,\n );\n\n if (unfilled !== -1)\n return yield* new ReplayError({\n step: start,\n input: \"unsent\",\n receipts,\n reason: invalid(`no text for the input \"${plan.steps[unfilled]?.input ?? \"\"}\"`),\n });\n }\n for (let index = start; index < until; index++) {\n const at = restoring\n ? new Stopped({ step: index, input: \"unknown\" })\n : index === start\n ? from\n : index;\n\n const receipt = yield* take(page, plan, at, options).pipe(\n Effect.mapError((error) => new ReplayError({ ...error, receipts: [...receipts] })),\n );\n\n receipts.push(receipt);\n }\n\n return receipts;\n});\n\n/** Take a plan's steps from a fresh index or durable stopping point, returning completed receipts. */\nexport const replay = (page: Page, plan: Plan, options: ReplayOptions = {}) =>\n run(page, plan, options, options.from ?? 0, plan.steps.length, false).pipe(\n Effect.withSpan(\"Plan.replay\"),\n );\n\n/** Restore prior steps on a fresh page; unresolved commitments require positive durable evidence. */\nexport const restore = (\n page: Page,\n plan: Plan,\n options: TakeOptions & { readonly upTo?: number | undefined } = {},\n) =>\n run(page, plan, options, 0, options.upTo ?? plan.steps.length, true).pipe(\n Effect.withSpan(\"Plan.restore\"),\n );\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,UAAb,cAA6B,OAAO,YAAqB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CACxE,IAAa,UAAU;EACrB,OAAO;CACT;AACF;;AAGA,IAAa,YAAb,cAA+B,OAAO,YAAuB,CAAC,CAAC,aAAa,EAC1E,OAAO,OAAO,IAChB,CAAC,CAAC,CAAC;CACD,IAAa,UAAU;EACrB,OAAO,GAAG,KAAK,MAAM;CACvB;AACF;;AAGA,IAAa,UAAb,cAA6B,OAAO,YAAqB,CAAC,CAAC,WAAW,EACpE,QAAQ,OAAO,OACjB,CAAC,CAAC,CAAC;CACD,IAAa,UAAU;EACrB,OAAO,KAAK;CACd;AACF;AAEA,MAAM,EAAE,OAAO,cAAc,MAAM;AACnC,MAAM,SAAS;CAAC;CAAO;CAAU;CAAS;AAAS;AAEnD,MAAM,QAAQ,YACZ,OAAO,OAAO,OAAO,CAAC,CAAC,QAAQ,UAAU,OAAO,UAAU,QAAQ;;AAGpE,MAAM,WAAW,OAAgC,OAAe,YAA4B;CAC1F,MAAM,MAAM,QAAQ;CAEpB,IAAI,QAAQ,KAAA,KAAa,UAAU,GAAG,MAAM,UAAU,KAAK,GAAG,OAAO;CACrE,IAAI,UAAU,UAAU,OAAO,QAAQ,KAAA,IAAY,IAAI;CACvD,IAAI,UAAU,OACZ,OAAO,QAAQ,KAAA,KACb,KAAK,OAAO,CAAC,CAAC,MAAM,UAAU,GAAG,UAAU,KAAK,EAAE,GAAG,WAAW,GAAG,UAAU,KAAK,EAAE,EAAE,CAAC,IACrF,IACA;CAEN,OAAO,KAAK,OAAO,CAAC,CAAC,MAAM,UAAU,MAAM,OAAO,KAAK,CAAC,IAAI,IAAI;AAClE;AAEA,MAAa,UACX,SACA,UACwD;CAExD,MAAM,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,IAAI,QAAQ,SAAS,IAAI;CAEtF,MAAM,OAAO,MAAM,SAAS,QAAQ;EAClC,IAAI,QAAQ;EAEZ,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,QAAQ,QAAQ,QAAQ;GAC9B,MAAM,WAAW,UAAU,KAAA,IAAY,IAAI,QAAQ,OAAO,OAAO,IAAI,QAAQ,OAAO;GAEpF,IAAI,UAAU,KAAA,KAAa,aAAa,GAAG,OAAO,CAAC;GACnD,SAAS;EACX;EAEA,OAAO,CAAC;GAAE;GAAK;EAAM,CAAC;CACxB,CAAC;CAED,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,EAAE,YAAY,KAAK,CAAC;CACvD,MAAM,MAAM,KAAK,QAAQ,EAAE,YAAY,UAAU,IAAI;CACrD,MAAM,CAAC,QAAQ;CAEf,IAAI,MAAM,WAAW,GAAG,OAAO,OAAO,KAAK,IAAI,QAAQ,CAAC;CACxD,IAAI,KAAK,WAAW,GAClB,OAAO,OAAO,KAAK,IAAI,QAAQ,EAAE,QAAQ,mDAAmD,CAAC,CAAC;CAEhG,OAAO,IAAI,WAAW,KAAK,SAAS,KAAA,IAChC,OAAO,QAAQ,KAAK,GAAG,IACvB,OAAO,KAAK,IAAI,UAAU,EAAE,OAAO,IAAI,OAAO,CAAC,CAAC;AACtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrDA,MAAM,gBAAgB,OAAO,OAAO;CAAE,GAAG,OAAO;CAAQ,GAAG,OAAO;AAAO,CAAC;AAE1E,MAAa,aAAa,OAAO,SAAS;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAID,MAAM,QAAQ,OAAO,OAAO;CAC1B,MAAM,OAAO,SAAS,OAAO,MAAM;CACnC,MAAM,OAAO,SAAS,OAAO,MAAM;CACnC,MAAM,OAAO,SAAS,OAAO,MAAM;AACrC,CAAC;;;;;;AAOD,MAAa,WAAW,OAAO,MAAM;CACnC,OAAO,aAAa,WAAW,EAAE,SAAS,OAAO,QAAQ,CAAC;CAC1D,OAAO,aAAa,YAAY;EAC9B,OAAO;EACP,SAAS,OAAO,SAAS,OAAO,QAAQ,IAAI,CAAC;CAC/C,CAAC;CACD,OAAO,aAAa,QAAQ;EAC1B,OAAO;EACP,SAAS,OAAO,SAAS,OAAO,QAAQ,IAAI,CAAC;CAC/C,CAAC;CACD,OAAO,aAAa,aAAa;EAC/B,KAAK,OAAO,SAAS,OAAO,MAAM;EAClC,SAAS,OAAO,SAAS,OAAO,QAAQ,IAAI,CAAC;CAC/C,CAAC;AACH,CAAC;;AAKD,IAAa,OAAb,cAA0B,OAAO,MAAY,0BAA0B,CAAC,CAAC;CACvE,QAAQ;;;;;CAKR,KAAK,OAAO;;CAEZ,QAAQ,OAAO,SAAS,OAAO,MAAM;CACrC,SAAS,OAAO,SAAS,OAAO;;CAEhC,IAAI,OAAO,SAAS,OAAO;;CAE3B,OAAO,OAAO,SAAS,aAAa;CACpC,SAAS,OAAO,SAAS,aAAa;;CAEtC,KAAK,OAAO,SAAS,GAAG;;;;;CAKxB,OAAO,OAAO,SAAS,OAAO,MAAM;;CAEpC,QAAQ,OAAO,SAAS,OAAO,QAAQ,IAAI,CAAC;CAC5C,SAAS,OAAO,SAAS,aAAa;CACtC,QAAQ,OAAO,SAAS,QAAQ;AAClC,CAAC,CAAC,CAAC,CAAC;AAEJ,MAAM,WAAW,OAAO,OAAO;CAC7B,SAAS,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC;CAC/B,OAAO,OAAO,MAAM,IAAI;AAC1B,CAAC,CAAC,CAAC,MACD,OAAO,YAAY,SACjB,KAAK,aAAa,KAAK,MAAM,MAAM,SAAS,KAAK,WAAW,KAAA,CAAS,IAAI,IAAI,KACzE,KAAA,IACA,gDACN,CACF;AAEA,IAAa,OAAb,MAAa,aAAa,OAAO,MAAY,qBAAqB,CAAC,CAAC,QAAQ,CAAC,CAAC;;CAE5E,OAAO,IAAI,OAAkC;EAC3C,OAAO,IAAI,KAAK;GAAE,SAAS,MAAM,MAAM,SAAS,KAAK,WAAW,KAAA,CAAS,IAAI,IAAI;GAAG;EAAM,CAAC;CAC7F;;CAGA,IAAI,SAAgC;EAClC,OAAO,KAAK,MAAM,SAAS,SAAU,KAAK,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,KAAK,KAAK,CAAE;CACpF;AACF;;AAGA,IAAa,UAAb,cAA6B,OAAO,MAAe,6BAA6B,CAAC,CAAC;CAChF,MAAM,OAAO,IAAI,MAAM,OAAO,uBAAuB,CAAC,CAAC;CACvD,SAAS,OAAO,SAAS;EAAC;EAAS;EAAY;CAAS,CAAC;CACzD,WAAW,OAAO;CAClB,IAAI,OAAO;AACb,CAAC,CAAC,CAAC,CAAC;;AAGJ,IAAa,UAAb,cAA6B,OAAO,MAAe,6BAA6B,CAAC,CAAC;CAChF,MAAM,OAAO,IAAI,MAAM,OAAO,uBAAuB,CAAC,CAAC;CACvD,OAAO,OAAO,SAAS,CAAC,UAAU,SAAS,CAAC;AAC9C,CAAC,CAAC,CAAC,CAAC;;AAGJ,IAAa,YAAb,cAA+B,OAAO,YAAuB,CAAC,CAAC,aAAa,EAC1E,QAAQ,OAAO,OACjB,CAAC,CAAC,CAAC;CACD,IAAa,UAAU;EACrB,OAAO,KAAK;CACd;AACF;;AAGA,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,eAAe;CAChF,MAAM,OAAO;CACb,QAAQ,OAAO,MAAM;EAAC;EAAS;EAAW;EAAS;EAAc;CAAS,CAAC;CAC3E,OAAO,OAAO,SAAS,CAAC,UAAU,SAAS,CAAC;CAC5C,UAAU,OAAO,MAAM,OAAO;AAChC,CAAC,CAAC,CAAC;CACD,IAAI,UAAmB;EACrB,OAAO,IAAI,QAAQ;GAAE,MAAM,KAAK;GAAM,OAAO,KAAK;EAAM,CAAC;CAC3D;CAEA,IAAa,UAAU;EACrB,OAAO,QAAQ,KAAK,KAAK,WAAW,KAAK,OAAO;CAClD;AACF;AAEA,MAAM,UAAU,UACd,MAAM,SAAS,YACf,MAAM,MACL,WAAW,SAAmC,SAAS,MAAM,IAAI;AAGpE,MAAM,WAAW,WAAkD;CACjE,MAAM,SAAS,kDAAkD,KAAK,UAAU,EAAE;CAElF,OAAO,WAAW,OAAO,KAAA,IAAY;EAAE,GAAG,OAAO,OAAO,EAAE;EAAG,GAAG,OAAO,OAAO,EAAE;CAAE;AACpF;;AAGA,MAAM,WAAW,OAAoB,UAA8B;CACjE,MAAM,OACJ,OACI,YAAY,CAAC,CACd,MAAM,iBAAiB,CAAC,EACvB,KAAK,GAAG,KAAK;CAEnB,IAAI,OAAO;CAEX,KAAK,IAAI,QAAQ,GAAG,MAAM,IAAI,IAAI,GAAG,SAAS,OAAO,GAAG,KAAK,GAAG;CAChE,MAAM,IAAI,IAAI;CAEd,OAAO;AACT;;;;;AAMA,MAAa,cAAc,WAAyC;CAClE,MAAM,MAAM,MAAM,KAAK,MAAM;CAC7B,MAAM,OAAO,IAAI,MAAM,UAAU,MAAM,SAAS,QAAQ,CAAC,EAAE;CAC3D,MAAM,OAAO,IAAI,QAAQ,UAAU,UAAU,SAAS,MAAM,SAAS,IAAI;CACzE,MAAM,QAAQ,KAAK,OAAO,MAAM;CAChC,MAAM,SAAS,KAAK,MAAM,UAAU,MAAM,SAAS,YAAY,CAAC,EAAE,OAAO;CACzE,MAAM,QAAQ,KAAK,QAAQ,UAA8B,MAAM,SAAS,WAAW;CACnF,MAAM,wBAAQ,IAAI,IAAY;CAG9B,MAAM,UAAU,SAAiB,MAAM,UAAU,SAAS,KAAK,MAAM,IAAI,CAAC,EAAE,OAAO;CAEnF,OAAO,IAAI,KAAK;EACd,SAAS;EACT,OAAO,MAAM,KAAK,QAAQ,UAAU;GAClC,MAAM,OAAO,OAAO,SAAS,UAAU,OAAO,UAAU,GAAA,CAAI,MAAM,MAAM,IAAI,KAAA;GAC5E,MAAM,QAAQ,QAAQ,SAAS,KAAA,IAAY,OAAO,SAAS,KAAK,EAAE;GAClE,MAAM,QAAQ,MAAM,QAAQ,EAAE,EAAE,aAAa,OAAO;GACpD,MAAM,UAAU,MAAM,UAAU,SAAS,KAAK,KAAK,OAAO,MAAM,KAAK,MAAM,KAAK;GAGhF,OAAO,IAAI,KAAK;IACd,QAAQ,OAAO;IACf,KAAK,SAAS,OAAO,OAAO,OAAO,OAAO,KAAK;IAC/C,QAAQ,OAAO,SAAS,cAAc,OAAO,SAAS,UAAU,OAAO,SAAS,KAAA;IAChF,SAAS,OAAO;IAChB,IAAI,OAAO;IACX;IACA,SAAS,QAAQ,OAAO,EAAE;IAC1B,KAAK,UAAU,KAAA,IAAY,KAAA,IAAY,OAAO;IAC9C,OACE,OAAO,SAAS,SACZ,QAAQ,OAAO,OAAO,SAAS,IAAI,IACnC,OAAO,SAAS,cAAc,OAAO,QAAQ,SAAS,QAAQ,MAAM,OAClE,QAAQ,OAAO,SAAS,IACxB,KAAA;IACR,QAAQ,OAAO,SAAS,UAAU,OAAO,SAAS,WAAW,OAAO,KAAA;IACpE,SAAS,OAAO;GAClB,CAAC;EACH,CAAC;CACH,CAAC;AACH;;;;;AAMA,MAAa,UAAU,MAAY,YACjC,KACG,KAAK;CACJ,MAAM,QAAQ;CACd,OAAO;CACP,GAAI,QAAQ,SAAS,OAAO,CAAC,IAAI,EAAE,MAAM,QAAQ,KAAK;AACxD,CAAC,CAAC,CACD,KACC,OAAO,SAAS,UAAU,OAAO,SAAS,KAAK,CAAC,GAChD,OAAO,MAAM;CACX,UAAU,SAAS,OAAO,SAAS,OAAO,GAAG,CAAC;CAC9C,OAAO;CACP,QAAQ,UAAU,MAAM,SAAS;AACnC,CAAC,GACD,OAAO,SAAS,eAAe,EAAE,YAAY,EAAE,MAAM,QAAQ,QAAQ,GAAG,EAAE,CAAC,CAC7E;AAEJ,MAAM,WAAW,WAAmB,aAAa,UAAU,IAAI,eAAe,EAAE,OAAO,CAAC,CAAC;;;;;;AAOzF,MAAM,OAAO,MAAY,SAA8B,OAAe,aAAmB;CACvF,IAAI,YAAY,KAAA,GAAW,OAAO,OAAO,KAAK,QAAQ,2BAA2B,CAAC;CAClF,IAAI,UAAU,KAAA,GAAW,OAAO,OAAO,IAAI,OAAO,MAAM,OAAO,IAAI,EAAE,UAAkB,GAAG;CAE1F,MAAM,SAAS,EAAE,KAAK,UAAiB;EACrC,MAAM,KACJ,aAAa,KAAA,KAAa,SAAS,SAAS,KAAK,SAAS,UAAU,IAChE,QACA;GACE,GAAG,IAAI,KAAM,MAAM,IAAI,SAAS,KAAK,SAAS,QAAS,IAAI;GAC3D,GAAG,IAAI,KAAM,MAAM,IAAI,SAAS,KAAK,SAAS,SAAU,IAAI;EAC9D;EAEN,OAAO,OAAO,IAAI,KAAK,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,aAAc,SAAS,QAAQ,MAAM,KAAK,KAAA,CAAU;CAC7F;CAEA,MAAM,SAAS,IAAI,QAAQ,EAAE,QAAQ,yDAAyD,CAAC;CAE/F,OAAO,OAAO,MAAM,OAAO,CAAC,CAAC,KAC3B,OAAO,SAAS,UACd,OAAO,QAAQ,MAAM,KAAK,IAAI,OAC5B,OAAO,KAAA,IACH,OAAO,QAAgB,EAAE,IACzB,KAAK,MAAM,MAAM,GAAG,CAAC,CAAC,KACpB,OAAO,QAAQ,OAAO,MAAM,OAAO,CAAC,GACpC,OAAO,QAAQ,KAAK,GACpB,OAAO,SAAS,UACd,UAAU,KAAA,IAAY,OAAO,KAAK,MAAM,IAAI,OAAO,QAAgB,KAAK,CAC1E,CACF,CACN,CACF,CACF;AACF;AAEA,MAAM,YACJ,MACA,MACA,SACsE;CACtE,MAAM,UAAU,KAAK,WAAW,CAAC;CAEjC,QAAQ,KAAK,QAAb;EACE,KAAK,YACH,OAAO,KAAK,KAAK,KAAK,UAAU,KAAA,IAAa,KAAK,UAAU,KAAK,MAAO,IAAI;EAC9E,KAAK,QACH,OAAO,KAAK;EACd,KAAK,UACH,OAAO,KAAK;EACd,KAAK,SACH,OAAO,KAAK,YAAY,KAAA,IACpB,KAAK,MAAM,KAAK,UAAU,IAAI,OAAO,IACrC,OAAO,QAAQ,OAAO,MAAM,KAAK,OAAO,IAAI,EAAE,UAC5C,KAAK,MAAM,KAAK,UAAU,IAAI;GAAE,GAAG;GAAS,IAAI;EAAI,CAAC,CACvD;EACN,KAAK,SACH,OAAO,IAAI,MAAM,KAAK,SAAS,KAAK,OAAO,KAAK,GAAG,CAAC,CAAC,KACnD,OAAO,SAAS,OAAO,KAAK,MAAM,IAAI,OAAO,CAAC,GAC9C,OAAO,MACT;EACF,KAAK,SACH,OAAO,OAAO,QAAQ,IAAI,MAAM,KAAK,SAAS,KAAK,OAAO,KAAK,GAAG,GAAG,KAAK,KAAK;EACjF,KAAK,QACH,OAAO,OAAO,IAAI,CAChB,IAAI,MAAM,KAAK,SAAS,KAAK,KAAK,GAClC,IAAI,MAAM,KAAK,IAAI,KAAK,OAAO,CACjC,CAAC,CAAC,CAAC,KAAK,OAAO,SAAS,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,EAAE,CAAC,CAAC;EAC7D,KAAK,UACH,OAAO,IAAI,MAAM,KAAK,OAAO,CAAC,CAAC,KAC7B,OAAO,SAAS,OAAO,KAAK,OAAO,OAAO,OAAO,WAAW,KAAK,IAAI,QAAQ,UAAU,CAAC,CAAC,CAAC,GAC1F,OAAO,MACT;EAEF,KAAK,UACH,OAAO,KAAK,YAAY,KAAA,IACpB,KAAK,OAAO,OAAO,IACnB,OAAO,QAAQ,IAAI,MAAM,KAAK,SAAS,KAAK,OAAO,KAAK,GAAG,IAAI,OAC7D,KAAK,OAAO;GAAE,GAAG;GAAS;EAAG,CAAC,CAChC;EACN,KAAK,QACH,OAAO,KAAK,YAAY,KAAA,IACpB,KAAK,KAAK,MAAM;GAAE,GAAG;GAAS,QAAQ,KAAK;EAAO,CAAC,IACnD,OAAO,QAAQ,IAAI,MAAM,KAAK,OAAO,IAAI,SACvC,KAAK,KAAK,MAAM;GACd,GAAG;GACH,MAAM,OAAO,SAAS,WAAW,OAAO,KAAA;GACxC,QAAQ,KAAK;EACf,CAAC,CACH;CACR;AACF;;;;;AAqBA,MAAa,cAAc,SACzB;CAAC;CAAY;CAAS;CAAU;AAAQ,CAAC,CAAC,SAAS,KAAK,MAAM,KAC7D,KAAK,WAAW,UACf,KAAK,YAAY,KAAA,KACjB,KAAK,SAAS,YAAY,SAC1B,KAAK,SAAS,WAAW,QAC1B,KAAK,WAAW,WAAW,KAAK,QAAQ,SAAS;AAKpD,MAAM,UAAU,OAA0C,WACxD,WAAW,IACP,QACA,MAAM,KACJ,OAAO,OAAO;CAAE,QAAQ,SAAS;CAAM,UAAU,SAAS,OAAO,SAAS,OAAO,EAAE,CAAC;AAAE,CAAC,GACvF,OAAO,cAAc;CACnB,UAAU,SAAS,OAAO,MAAM;CAChC,cAAc,OAAO,QAAQ,KAAK;AACpC,CAAC,CACH;AAEN,MAAM,YAAY,KAAa,aAAqB;CAClD,MAAM,SAAS,IAAI,MAAM,QAAQ,CAAC,EAAE;CAEpC,OACE,aAAa,OACZ,WAAW,KAAA,KAAa,WAAW,SAChC,QAAQ,WACR,IAAI,MAAM,GAAG,CAAC,EAAE,WAAW;AAEnC;AAEA,MAAM,WAAW,MAAY,MAA6B,WACxD,OACE,OAAO,IAAI,KAAK,MAAM,QAAQ,KAAK,MAAM,aAAa,SAAS,KAAK,QAAQ,CAAC,CAAC,GAC9E,MACF,CAAC,CAAC,KACA,OAAO,cACJ,SAAS,YAER,IAAI,QAAQ,EAAE,QAAQ,mEAAmE,CAAC,CAC9F,GACA,OAAO,MACT;AAEF,MAAM,eACJ,MACA,MACA,UACG;CACH,MAAM,WAAW,KAAK;CAEtB,IAAI,aAAa,KAAA,GAAW,OAAO,OAAO,QAAQ,KAAK;CACvD,QAAQ,SAAS,MAAjB;EACE,KAAK,WACH,OAAO,KAAK,YAAY,KAAA,IACpB,OAAO,KAAK,QAAQ,kCAAkC,CAAC,IACvD,OAAO,QAAQ,OAAO,MAAM,KAAK,OAAO,IAAI,UAC1C,MAAM,MAAM,YAAY,KAAA,IACpB,OAAO,KAAK,QAAQ,4CAA4C,CAAC,IACjE,OAAO,QAAQ,MAAM,MAAM,YAAY,SAAS,OAAO,CAC7D;EACN,KAAK,aACH,OAAO,OAAO,IAAI,KAAK,QAAQ,QAC7B,SAAS,QAAQ,KAAA,IACb,IAAI,QAAQ,MAAM,OAAO,IAAI,aAAa,MAAM,WAChD,IAAI,QAAQ,SAAS,GAC3B;EACF,KAAK;EACL,KAAK,QACH,OAAO,OAAO,IAAI,KAAK,KAAK;GAAE,GAAG,SAAS;GAAO,OAAO;EAAW,CAAC,IAAI,UACtE,SAAS,SAAS,aAAa,MAAM,SAAS,IAAI,MAAM,WAAW,CACrE;CACJ;AACF;;;;;;AAOA,MAAa,OAAO,OAAO,GAAG,WAAW,CAAC,CAAC,WACzC,MACA,MACA,IACA,UAAuB,CAAC,GACgB;CACxC,MAAM,QAAQ,OAAO,OAAO,WAAW,KAAK,GAAG;CAC/C,IAAI,QAA0B,OAAO,OAAO,WAAW,WAAW,GAAG;CA4FrE,OAAO,OA1FM,OAAO,IAAI,aAAmD;EACzE,MAAM,OAAO,KAAK,MAAM;EAExB,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,SAAS,KAAA,GACpD,OAAO,OAAO,QAAQ,oCAAoC;EAC5D,MAAM,WAAW,SAAS,UAAU,QAAQ,WAAW,SAAS,QAAQ,CAAC,CAAC;EAE1E,IACE,OAAO,OAAO,QAAQ,KACtB,SAAS,WAAW,SAAS,KAAK,KAClC,CAAC,SAAS,SAAS,SAAS,KAAK,GAEjC,OAAO,OAAO,QAAQ,+CAA+C;EACvE,MAAM,SAAS,SAAS,SAAS,SAAS,KAAK;EAC/C,MAAM,QAAQ,OAAO,KAAK;EAE1B,MAAM,YAAY,IAAI,UAAU,EAC9B,QAAQ,8EACV,CAAC;EAED,MAAM,aAAa,UAAU,aAAa,CAAC,WAAW,IAAI;EAC1D,MAAM,WAAW,KAAK;EAEtB,IACE,eACC,aAAa,KAAA,KAAa,SAAS,SAAS,aAAa,SAAS,YAAY,OAE/E,OAAO,OAAO;EAChB,MAAM,SAAS,QAAQ,WAAW,QAAQ,OAAO,OAAO,KAAK,MAAM,QAAQ,MAAM;EAEjF,IAAI,CAAC;GAAC;GAAY;GAAQ;EAAQ,CAAC,CAAC,SAAS,KAAK,MAAM,GAAG,OAAO;EAClE,MAAM,SAAS,KAAK,MAAM,QAAQ,EAAE,EAAE;EAEtC,IAAI,WAAW,KAAA,GACb,OAAO,QAAQ,MAAM,aAAa,CAAC,QAAQ,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,MAAM;EACzE,MAAM,QAAQ,YAAY,MAAM,MAAM,KAAK;EAa3C,MAAM,OAAO,QAVX,WAAW,IACP,QACA,MAAM,KACJ,OAAO,cAAc;GACnB,UAAU,SAAS,OAAO,MAAM;GAChC,cACE,OAAO,KAAK,IAAI,QAAQ,EAAE,QAAQ,qCAAqC,CAAC,CAAC;EAC7E,CAAC,CACH,EAAA,CAEmB,KAAK,OAAO,UAAU,UAAW,aAAa,YAAY,KAAM,CAAC;EAE1F,MAAM,WAAW,YACf,OAAO,IAAI,aAAa;GACtB,IAAI,UAAU,KAAK,MAAM,SAAS,GAAG,OAAO;GAC5C,OAAO,QAAQ,MAAM,CAAC,KAAK,GAAG,GAAG,MAAM;GACvC,MAAM,MAAM,OAAO,KAAK;GAExB,OAAO,IAAI,QAAQ;IAAE,MAAM;IAAO;IAAS,WAAW,MAAM;IAAI,IAAI,IAAI;GAAG,CAAC;EAC9E,CAAC;EAEH,IAAI,MAAM,OAAO,OAAO,QAAQ,SAAS;EACzC,IAAI,YAAY,OAAO,OAAO;EAC9B,MAAM,OAAO,KAAK,UAAU,KAAA,IAAY,KAAK,QAAQ,SAAS,KAAK;EAEnE,IAAI,SAAS,KAAA,GAAW,OAAO,OAAO,QAAQ,0BAA0B,KAAK,SAAS,GAAG,EAAE;EAC3F,MAAM,QAAQ,OAAO,OAAO,KAAK,SAAS,MAAM,MAAM,IAAI,CAAC;EAE3D,IAAI,KAAK,UAAU,KAAK,GAAG;GACzB,MAAM,QAAQ,KAAK,gBAAgB,KAAK;GAExC,IAAI,OAAO,OAAO,KAAK,KAAK,MAAM,MAAM,SAAS,kBAAkB,MAAM,MAAM,YAAY;IACzF,QAAQ;IACR,IACE,aAAa,KAAA,MACZ,WAAW,IAAI,KAAM,SAAS,SAAS,aAAa,SAAS,YAAY,OAC1E;KACA,MAAM,WAAW,OAAO,OAAO,KAAK,OAAO,OAAO,MAAM,CAAC;KAEzD,IAAI,KAAK,UAAU,QAAQ,KAAK,SAAS,OAAO,OAAO,OAAO,QAAQ,UAAU;IAClF;GACF;GAEA,OAAO,OAAO,OAAO,UAAU,MAAM,KAAK;EAC5C;EACA,QAAQ;EACR,IAAI,aAAa,KAAA,KAAa,EAAE,OAAO,OAAO,OAAO,MAAM,IACzD,OAAO,OAAO,IAAI,QAAQ,EAAE,QAAQ,4CAA4C,CAAC;EAEnF,OAAO,OAAO,QAAQ,aAAa,KAAA,IAAY,UAAU,UAAU;CACrE,CAEiB,CAAC,CAAC,KACjB,OAAO,UACJ,WACC,IAAI,YAAY;EACd,MAAM;EACN;EACA;EACA,UAAU,CAAC;CACb,CAAC,CACL,CACF;AACF,CAAC;AAED,MAAM,MAAM,OAAO,WAAW,WAC5B,MACA,MACA,SACA,MACA,OACA,WACA;CACA,MAAM,WAA2B,CAAC;CAClC,MAAM,QAAQ,OAAO,SAAS,WAAW,OAAO,KAAK;CAErD,IACE,CAAC,OAAO,UAAU,KAAK,KACvB,QAAQ,KACR,QAAQ,KAAK,MAAM,UACnB,CAAC,OAAO,UAAU,KAAK,KACvB,QAAQ,SACR,QAAQ,KAAK,MAAM,QAEnB,OAAO,OAAO,IAAI,YAAY;EAC5B,MAAM;EACN,OAAO;EACP;EACA,QAAQ,QAAQ,qCAAqC;CACvD,CAAC;CAEH,IAAI,CAAC,aAAa,OAAO,SAAS,UAAU;EAC1C,MAAM,WAAW,KAAK,MAAM,WACzB,MAAM,UACL,SAAS,SAAS,KAAK,UAAU,KAAA,KAAa,QAAQ,SAAS,KAAK,WAAW,KAAA,CACnF;EAEA,IAAI,aAAa,IACf,OAAO,OAAO,IAAI,YAAY;GAC5B,MAAM;GACN,OAAO;GACP;GACA,QAAQ,QAAQ,0BAA0B,KAAK,MAAM,SAAS,EAAE,SAAS,GAAG,EAAE;EAChF,CAAC;CACL;CACA,KAAK,IAAI,QAAQ,OAAO,QAAQ,OAAO,SAAS;EAC9C,MAAM,KAAK,YACP,IAAI,QAAQ;GAAE,MAAM;GAAO,OAAO;EAAU,CAAC,IAC7C,UAAU,QACR,OACA;EAEN,MAAM,UAAU,OAAO,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,CAAC,KACnD,OAAO,UAAU,UAAU,IAAI,YAAY;GAAE,GAAG;GAAO,UAAU,CAAC,GAAG,QAAQ;EAAE,CAAC,CAAC,CACnF;EAEA,SAAS,KAAK,OAAO;CACvB;CAEA,OAAO;AACT,CAAC;;AAGD,MAAa,UAAU,MAAY,MAAY,UAAyB,CAAC,MACvE,IAAI,MAAM,MAAM,SAAS,QAAQ,QAAQ,GAAG,KAAK,MAAM,QAAQ,KAAK,CAAC,CAAC,KACpE,OAAO,SAAS,aAAa,CAC/B;;AAGF,MAAa,WACX,MACA,MACA,UAAgE,CAAC,MAEjE,IAAI,MAAM,MAAM,SAAS,GAAG,QAAQ,QAAQ,KAAK,MAAM,QAAQ,IAAI,CAAC,CAAC,KACnE,OAAO,SAAS,cAAc,CAChC"}
|
package/dist/Plan.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { Ambiguous, Drifted, Missing, Plan, ReplayError, ReplayOptions, Step, StepAction, fromEvents, locate, replay };
|
|
1
|
+
import { _ as take, a as ReplayError, b as Missing, c as StepAction, d as Uncertain, f as fromEvents, g as restore, h as replay, i as Receipt, l as Stopped, m as repeatable, n as Plan, o as ReplayOptions, p as locate, s as Step, t as Expected, u as TakeOptions, v as Ambiguous, y as Drifted } from "./Plan-BvCS9qAf.mjs";
|
|
2
|
+
export { Ambiguous, Drifted, Expected, Missing, Plan, Receipt, ReplayError, ReplayOptions, Step, StepAction, Stopped, TakeOptions, Uncertain, fromEvents, locate, repeatable, replay, restore, take };
|
package/dist/Plan.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { Ambiguous, Drifted, Missing, Plan, ReplayError, Step, StepAction, fromEvents, locate, replay };
|
|
1
|
+
import { _ as Drifted, a as ReplayError, c as Stopped, d as locate, f as repeatable, g as Ambiguous, h as take, i as Receipt, l as Uncertain, m as restore, n as Plan, o as Step, p as replay, s as StepAction, t as Expected, u as fromEvents, v as Missing } from "./Plan-CyQNv49C.mjs";
|
|
2
|
+
export { Ambiguous, Drifted, Expected, Missing, Plan, Receipt, ReplayError, Step, StepAction, Stopped, Uncertain, fromEvents, locate, repeatable, replay, restore, take };
|
package/dist/Policy.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as InputGuard, i as Fact, l as InputRequest } from "./Page-
|
|
1
|
+
import { c as InputGuard, i as Fact, l as InputRequest } from "./Page-C30aG2RQ.mjs";
|
|
2
2
|
import { Context, Duration, Effect, Schema } from "effect";
|
|
3
3
|
import { AiError, DecisionModel, LanguageModel } from "effect/ai";
|
|
4
4
|
declare namespace Policy_d_exports {
|
package/dist/Presentation.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as Target, u as Page } from "./Page-
|
|
1
|
+
import { b as Target, u as Page } from "./Page-C30aG2RQ.mjs";
|
|
2
2
|
import { Service, t as Motion_d_exports } from "./Motion.mjs";
|
|
3
3
|
import { Duration, Effect } from "effect";
|
|
4
4
|
declare namespace Presentation_d_exports {
|
package/dist/Presentation.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { lognormal } from "./Motion.mjs";
|
|
3
|
-
import { a as performed, i as pause, r as viewOf, t as internalsOf } from "./page-
|
|
3
|
+
import { a as performed, i as pause, r as viewOf, t as internalsOf } from "./page-DHeYWEs-.mjs";
|
|
4
4
|
import { Clock, Duration, Effect, Fiber, MutableRef, Option, Semaphore } from "effect";
|
|
5
5
|
//#region src/Presentation.ts
|
|
6
6
|
/**
|
package/dist/Stage.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as BrowserError } from "./BrowserError-DXXIA6Rk.mjs";
|
|
2
2
|
import { n as CaptureStats, o as ScreencastOptions, r as Frame } from "./Frame-BERmf_gM.mjs";
|
|
3
|
-
import { u as Page } from "./Page-
|
|
3
|
+
import { u as Page } from "./Page-C30aG2RQ.mjs";
|
|
4
4
|
import { Duration, Effect, Option, Schema, Stream } from "effect";
|
|
5
5
|
declare namespace Stage_d_exports {
|
|
6
6
|
export { Options, Presented, Stage, make };
|
package/dist/Stage.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { InvalidRequest, Timeout, consequence } from "./BrowserError.mjs";
|
|
3
3
|
import { i as failWith } from "./context-DAYjATgC.mjs";
|
|
4
|
-
import { t as internalsOf } from "./page-
|
|
4
|
+
import { t as internalsOf } from "./page-DHeYWEs-.mjs";
|
|
5
5
|
import { Clock, Deferred, Duration, Effect, Exit, Fiber, Option, PubSub, Schedule, Schema, Semaphore, Stream } from "effect";
|
|
6
6
|
//#region src/Stage.ts
|
|
7
7
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as DisconnectCause } from "./BrowserEvent-
|
|
1
|
+
import { c as DisconnectCause } from "./BrowserEvent-BRu2juEz.mjs";
|
|
2
2
|
import { Service, t as Browser_d_exports } from "./Browser.mjs";
|
|
3
3
|
import { Cause, Duration, Effect, Schedule, Schema, Scope, Stream } from "effect";
|
|
4
4
|
declare namespace lifecycle_d_exports {
|
|
@@ -227,4 +227,4 @@ interface Supervisor {
|
|
|
227
227
|
declare const make: <E, R>(options: Options<E, R>) => Effect.Effect<Supervisor, never, Scope.Scope | Exclude<R, Scope.Scope>>;
|
|
228
228
|
//#endregion
|
|
229
229
|
export { Settled as _, Supervisor_d_exports as a, Closed as c, Kept as d, Lost as f, Reopening as g, Released as h, Supervisor as i, Down as l, Opening as m, Opened as n, Unavailable as o, Open as p, Options as r, make as s, Generation as t, GenerationState as u, Unconfirmed as v };
|
|
230
|
-
//# sourceMappingURL=Supervisor-
|
|
230
|
+
//# sourceMappingURL=Supervisor-CLJaT7rG.d.mts.map
|
package/dist/Supervisor.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as Settled, c as Closed, d as Kept, f as Lost, g as Reopening, h as Released, i as Supervisor, l as Down, m as Opening, n as Opened, o as Unavailable, p as Open, r as Options, s as make, t as Generation, u as GenerationState, v as Unconfirmed } from "./Supervisor-
|
|
1
|
+
import { _ as Settled, c as Closed, d as Kept, f as Lost, g as Reopening, h as Released, i as Supervisor, l as Down, m as Opening, n as Opened, o as Unavailable, p as Open, r as Options, s as make, t as Generation, u as GenerationState, v as Unconfirmed } from "./Supervisor-CLJaT7rG.mjs";
|
|
2
2
|
export { Closed, Down, Generation, GenerationState, Kept, Lost, Open, Opened, Opening, Options, Released, Reopening, Settled, Supervisor, Unavailable, Unconfirmed, make };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { n as BrowserError_d_exports } from "./BrowserError-DXXIA6Rk.mjs";
|
|
2
|
-
import { a as BrowserEvent_d_exports } from "./BrowserEvent-
|
|
3
|
-
import { n as Change_d_exports } from "./Change-
|
|
2
|
+
import { a as BrowserEvent_d_exports } from "./BrowserEvent-BRu2juEz.mjs";
|
|
3
|
+
import { n as Change_d_exports } from "./Change-iMlcuzVD.mjs";
|
|
4
4
|
import { i as Frame_d_exports } from "./Frame-BERmf_gM.mjs";
|
|
5
5
|
import { i as Snapshot_d_exports } from "./Snapshot-B34hZ4Jl.mjs";
|
|
6
|
-
import { N as Moment_d_exports, d as Page_d_exports } from "./Page-
|
|
6
|
+
import { N as Moment_d_exports, d as Page_d_exports } from "./Page-C30aG2RQ.mjs";
|
|
7
7
|
import { t as Browser_d_exports } from "./Browser.mjs";
|
|
8
8
|
import { t as Cdp_d_exports } from "./Cdp.mjs";
|
|
9
9
|
import { t as Chromium_d_exports } from "./Chromium.mjs";
|
|
10
10
|
import { t as Expect_d_exports } from "./Expect.mjs";
|
|
11
11
|
import { t as Motion_d_exports } from "./Motion.mjs";
|
|
12
|
-
import {
|
|
12
|
+
import { r as Plan_d_exports } from "./Plan-BvCS9qAf.mjs";
|
|
13
13
|
import { t as Policy_d_exports } from "./Policy.mjs";
|
|
14
14
|
import { t as Presentation_d_exports } from "./Presentation.mjs";
|
|
15
15
|
import { t as Stage_d_exports } from "./Stage.mjs";
|
|
16
|
-
import { a as Supervisor_d_exports } from "./Supervisor-
|
|
16
|
+
import { a as Supervisor_d_exports } from "./Supervisor-CLJaT7rG.mjs";
|
|
17
17
|
export { Browser_d_exports as Browser, BrowserError_d_exports as BrowserError, BrowserEvent_d_exports as BrowserEvent, Cdp_d_exports as Cdp, Change_d_exports as Change, Chromium_d_exports as Chromium, Expect_d_exports as Expect, Frame_d_exports as Frame, Moment_d_exports as Moment, Motion_d_exports as Motion, Page_d_exports as Page, Plan_d_exports as Plan, Policy_d_exports as Policy, Presentation_d_exports as Presentation, Snapshot_d_exports as Snapshot, Stage_d_exports as Stage, Supervisor_d_exports as Supervisor };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as Motion_exports } from "./Motion.mjs";
|
|
2
2
|
import { t as BrowserEvent_exports } from "./BrowserEvent.mjs";
|
|
3
3
|
import { t as BrowserError_exports } from "./BrowserError.mjs";
|
|
4
|
-
import { n as Browser_exports } from "./Browser-
|
|
4
|
+
import { n as Browser_exports } from "./Browser-CNwK0r0q.mjs";
|
|
5
5
|
import { t as Frame_exports } from "./Frame.mjs";
|
|
6
6
|
import { a as Page_exports } from "./Page-D4281dIi.mjs";
|
|
7
7
|
import { t as Snapshot_exports } from "./Snapshot.mjs";
|
|
@@ -10,7 +10,7 @@ import { t as Moment_exports } from "./Moment.mjs";
|
|
|
10
10
|
import { t as Cdp_exports } from "./Cdp.mjs";
|
|
11
11
|
import { t as Chromium_exports } from "./Chromium.mjs";
|
|
12
12
|
import { t as Expect_exports } from "./Expect.mjs";
|
|
13
|
-
import {
|
|
13
|
+
import { r as Plan_exports } from "./Plan-CyQNv49C.mjs";
|
|
14
14
|
import { t as Policy_exports } from "./Policy.mjs";
|
|
15
15
|
import { t as Presentation_exports } from "./Presentation.mjs";
|
|
16
16
|
import { t as Stage_exports } from "./Stage.mjs";
|