waygraph 0.16.0 → 0.16.1

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 (107) hide show
  1. package/dist/cli/commands/browser.d.ts +2 -0
  2. package/dist/cli/commands/browser.js +109 -0
  3. package/dist/cli/commands/pilot.d.ts +2 -0
  4. package/dist/cli/commands/pilot.js +102 -0
  5. package/dist/cli/commands/session-ops.d.ts +3 -0
  6. package/dist/cli/commands/session-ops.js +257 -0
  7. package/dist/cli/commands/session.js +20 -461
  8. package/dist/cli/usage.d.ts +1 -1
  9. package/dist/demo/narration/demo-pace.d.ts +1 -1
  10. package/dist/demo/narration/device.d.ts +2 -2
  11. package/dist/demo/narration/merge.d.ts +4 -2
  12. package/dist/demo/narration/merge.js +2 -6
  13. package/dist/demo/narration/narration.d.ts +8 -8
  14. package/dist/demo/narration/todo-dock.d.ts +5 -5
  15. package/dist/demo/overlay/cursor.d.ts +9 -2
  16. package/dist/demo/overlay/cursor.js +1 -1
  17. package/dist/demo/overlay/device-stage.d.ts +15 -2
  18. package/dist/demo/overlay/inpage/banner.d.ts +2 -1
  19. package/dist/demo/overlay/inpage/banner.js +3 -3
  20. package/dist/demo/overlay/inpage/caption.d.ts +1 -1
  21. package/dist/demo/overlay/inpage/core.d.ts +2 -1
  22. package/dist/demo/overlay/inpage/core.js +1 -1
  23. package/dist/demo/overlay/inpage/device-chip.d.ts +1 -1
  24. package/dist/demo/overlay/inpage/device-chip.js +6 -6
  25. package/dist/demo/overlay/inpage/network.d.ts +3 -2
  26. package/dist/demo/overlay/inpage/network.js +1 -12
  27. package/dist/demo/overlay/inpage/panel-chrome.d.ts +1 -1
  28. package/dist/demo/overlay/inpage/panel-chrome.js +1 -1
  29. package/dist/demo/overlay/inpage/stamp.d.ts +1 -1
  30. package/dist/demo/overlay/inpage/stamp.js +1 -1
  31. package/dist/demo/overlay/inpage/swipe-zoom.d.ts +1 -1
  32. package/dist/demo/overlay/inpage/swipe-zoom.js +1 -1
  33. package/dist/demo/overlay/inpage/todos.d.ts +2 -1
  34. package/dist/demo/overlay/inpage/todos.js +1 -2
  35. package/dist/demo/overlay/network-capture.d.ts +2 -2
  36. package/dist/demo/overlay/network-capture.js +1 -1
  37. package/dist/demo/overlay/overlay-stage.d.ts +19 -11
  38. package/dist/demo/overlay/overlay.d.ts +2 -2
  39. package/dist/demo/overlay/rings.d.ts +38 -10
  40. package/dist/demo/overlay/rings.js +21 -47
  41. package/dist/demo/stepper/after.js +9 -19
  42. package/dist/demo/stepper/banner-log.d.ts +4 -6
  43. package/dist/demo/stepper/banner-log.js +3 -1
  44. package/dist/demo/stepper/before.js +3 -3
  45. package/dist/demo/stepper/demo-log.d.ts +26 -9
  46. package/dist/demo/stepper/demo-log.js +9 -26
  47. package/dist/demo/stepper/interaction-patch.d.ts +3 -2
  48. package/dist/demo/stepper/interaction-patch.js +19 -19
  49. package/dist/demo/stepper/panel-after.d.ts +17 -0
  50. package/dist/demo/stepper/panel-after.js +166 -0
  51. package/dist/demo/stepper/panel-before.d.ts +12 -0
  52. package/dist/demo/stepper/panel-before.js +241 -0
  53. package/dist/demo/stepper/slides.d.ts +13 -1
  54. package/dist/demo/stepper/slides.js +3 -3
  55. package/dist/demo/stepper/step-panels.d.ts +57 -9
  56. package/dist/demo/stepper/step-panels.js +10 -427
  57. package/dist/demo/stepper/stepper.js +1 -1
  58. package/dist/demo/stepper/teardown.d.ts +4 -5
  59. package/dist/demo/stepper/teardown.js +4 -5
  60. package/dist/demo/stepper/todo-advance.d.ts +3 -2
  61. package/dist/demo/stepper/todo-advance.js +2 -2
  62. package/dist/demo/stepper/view.d.ts +4 -14
  63. package/dist/demo/types.d.ts +69 -1
  64. package/dist/engine/block/action-page.d.ts +53 -0
  65. package/dist/engine/block/action-page.js +1 -0
  66. package/dist/engine/block/block.d.ts +24 -79
  67. package/dist/engine/block/block.js +2 -77
  68. package/dist/engine/block/branch.d.ts +17 -0
  69. package/dist/engine/block/branch.js +40 -0
  70. package/dist/engine/block/dialog.d.ts +13 -0
  71. package/dist/engine/block/dialog.js +37 -0
  72. package/dist/engine/flow/map-branch.d.ts +9 -0
  73. package/dist/engine/flow/map-branch.js +57 -0
  74. package/dist/engine/flow/map-builder.d.ts +7 -22
  75. package/dist/engine/flow/map-builder.js +6 -145
  76. package/dist/engine/flow/map-steps.d.ts +30 -0
  77. package/dist/engine/flow/map-steps.js +87 -0
  78. package/dist/engine/trait/trait.js +1 -1
  79. package/dist/index.d.ts +13 -9
  80. package/dist/index.js +7 -5
  81. package/dist/live/auto/auto.d.ts +3 -15
  82. package/dist/live/auto/auto.js +10 -420
  83. package/dist/live/auto/explore.d.ts +2 -2
  84. package/dist/live/auto/mem.d.ts +11 -0
  85. package/dist/live/auto/mem.js +85 -0
  86. package/dist/live/auto/menu.d.ts +30 -0
  87. package/dist/live/auto/menu.js +335 -0
  88. package/dist/live/auto-session/auto-session.d.ts +23 -103
  89. package/dist/live/auto-session/auto-session.js +100 -370
  90. package/dist/live/auto-session/console.d.ts +4 -0
  91. package/dist/live/auto-session/console.js +41 -0
  92. package/dist/live/auto-session/files.d.ts +44 -0
  93. package/dist/live/auto-session/files.js +145 -0
  94. package/dist/live/auto-session/helpers.d.ts +5 -2
  95. package/dist/live/auto-session/helpers.js +17 -0
  96. package/dist/live/auto-session/inspect.d.ts +4 -0
  97. package/dist/live/auto-session/inspect.js +75 -0
  98. package/dist/live/auto-session/ipc.d.ts +3 -22
  99. package/dist/live/auto-session/ipc.js +7 -147
  100. package/dist/live/auto-session/open-browser.d.ts +6 -0
  101. package/dist/live/auto-session/open-browser.js +47 -0
  102. package/dist/live/pilot/pilot.d.ts +1 -1
  103. package/dist/live/pilot/pilot.js +2 -1
  104. package/dist/live/traverse/traverse.js +6 -200
  105. package/dist/live/traverse/worker.d.ts +37 -0
  106. package/dist/live/traverse/worker.js +200 -0
  107. package/package.json +5 -1
@@ -0,0 +1,57 @@
1
+ import { MSG_MAP_BRANCH_SHARED_SESSION_UNSUPPORTED, WaygraphError } from "../errors.js";
2
+ import { MemPage } from "../mem/mem.js";
3
+ /**
4
+ * Builds the `Flow` object `MapBuilder.branch()` returns: run `before`, then dispatch on the
5
+ * resolved tag into whichever `routes` entry matches (same page/context/mem), or return that
6
+ * Checkpoint as-is when its route is `null`. Factored out so `withBlockVerify`/`modBlockVerify`
7
+ * can patch `before` and rebuild the same branched shape, exactly like a plain Flow's own.
8
+ */
9
+ export function buildBranchedFlow(before, routes) {
10
+ const run = (async (contextOrMem, memOrConfig, options) => {
11
+ if (contextOrMem instanceof MemPage) {
12
+ throw new WaygraphError("WG_MAP_BRANCH_SHARED_SESSION_UNSUPPORTED", MSG_MAP_BRANCH_SHARED_SESSION_UNSUPPORTED);
13
+ }
14
+ const context = contextOrMem;
15
+ const mem = memOrConfig;
16
+ const gotOwnPage = options?.page === undefined;
17
+ const page = options?.page ?? (await context.newPage());
18
+ const closeOnFinish = options?.closeOnFinish ?? gotOwnPage;
19
+ const first = (await before.run(context, mem, { ...options, page, closeOnFinish: false }));
20
+ const branchFlow = routes[first.result.__state];
21
+ if (!branchFlow) {
22
+ if (options?.closeOnFinish === false)
23
+ return { result: first.result, page: first.page };
24
+ if (closeOnFinish)
25
+ await first.page.close();
26
+ return first.result;
27
+ }
28
+ return branchFlow.run(context, mem, { ...options, page: first.page, closeOnFinish });
29
+ });
30
+ return {
31
+ resetSession: before.resetSession,
32
+ config: before.config,
33
+ ...(before.expectedFailureReason !== undefined ? { expectedFailureReason: before.expectedFailureReason } : {}),
34
+ ...(before.demoPace !== undefined ? { demoPace: before.demoPace } : {}),
35
+ ...(before.highlightStyle !== undefined ? { highlightStyle: before.highlightStyle } : {}),
36
+ ...(before.memStub !== undefined ? { memStub: before.memStub } : {}),
37
+ // Read by branchRoutes()/branchInfo() (branch-regression.ts) - real, ORDINARY (enumerable)
38
+ // properties, not hidden ones, specifically so a `{ ...flow, ... }` spread (withSettings) carries them
39
+ // through instead of silently dropping them -
40
+ // the same class of bug branch()'s missing copyWaygraphRuntime call already was.
41
+ __wgBranch: { before, routes },
42
+ // Static introspection (`waygraph graph`/list): the fixed prefix, plus every branch's own
43
+ // Blocks prefixed by the tag that leads to them - can't know at analysis time which one a real
44
+ // run takes, so this shows all of them rather than none.
45
+ blocks: () => [
46
+ ...before.blocks(),
47
+ ...Object.entries(routes).flatMap(([tag, f]) => f ? f.blocks().map((b) => ({ ...b, name: `${tag} -> ${b.name}` })) : []),
48
+ ],
49
+ run,
50
+ withBlockVerify(block, verify) {
51
+ return buildBranchedFlow(before.withBlockVerify(block, verify), routes);
52
+ },
53
+ modBlockVerify(block, nameOrIndex, newCheck) {
54
+ return buildBranchedFlow(before.modBlockVerify(block, nameOrIndex, newCheck), routes);
55
+ },
56
+ };
57
+ }
@@ -1,34 +1,19 @@
1
+ import type { SomeBlock } from "../block/block.js";
2
+ import type { EffectBlock } from "../block/kinds/effect.js";
3
+ import type { AssertBlock, MethodBlock } from "../block/kinds/method.js";
4
+ import type { NavBlock } from "../block/kinds/nav.js";
5
+ import type { PageBlock } from "../block/kinds/page.js";
1
6
  import type { Checkpoint } from "../checkpoint/checkpoint.js";
2
- import type { Flow, FlowSettings } from "./flow.js";
3
7
  import type { DemoPace } from "../stub/pace.js";
4
8
  import type { HighlightStyleDefaults } from "../stub/ring.js";
5
- import type { NavBlock } from "../block/kinds/nav.js";
6
- import type { PageBlock } from "../block/kinds/page.js";
7
- import type { AssertBlock, MethodBlock } from "../block/kinds/method.js";
8
- import type { EffectBlock } from "../block/kinds/effect.js";
9
- import type { SomeBlock } from "../block/block.js";
9
+ import type { Flow, FlowSettings } from "./flow.js";
10
+ import { MapStepOpts } from "./map-steps.js";
10
11
  type S = Checkpoint<"__start__">;
11
12
  /**
12
13
  * The one capability MapBuilder needs from Engine: turn the finished steps into a Flow with the engine's config. A
13
14
  * function, not the Engine class, so engine.ts and map-builder.ts don't import each other.
14
15
  */
15
16
  export type BuildFlowFn = (steps: readonly SomeBlock[], settings: FlowSettings) => Flow<Checkpoint<string>>;
16
- /** Per-step options for the map builder: `ff` fast-forwards the step, `pace` sets its demo pace. */
17
- export interface MapStepOpts {
18
- /**
19
- * Fast-forward just this step, inline - no `.ffStart()/.ffEnd()` bracket needed. Consecutive
20
- * `{ ff: true }` steps merge into ONE fast-forward block, same result as the explicit bracket
21
- * form; a step without the flag closes an auto-opened window first.
22
- * @example map().gotoPage(NavLoginBlock, { ff: true }).method(FillUsernameBlock, { ff: true })
23
- */
24
- ff?: boolean;
25
- /**
26
- * Demo pace for just this step (`"blitz"` skips the typing animation and the pause after the action; `"fast"`, `"slow"`,
27
- * or a number scale the narration gates).
28
- * @example map().method(SetBearerTokenBlock, { pace: "blitz" })
29
- */
30
- pace?: DemoPace;
31
- }
32
17
  /** Flow-level settings for `engine.map({ … })`: `memStub`, `sessionReset`, `expectedFailure`, `demoPace`, `highlightStyle`, `homeOrigin`. */
33
18
  export interface MapBuilderOptions {
34
19
  /**
@@ -1,148 +1,7 @@
1
- import { WaygraphError, MSG_MAP_WRONG_KIND, MSG_MAP_WRONG_SALT, MSG_MAP_WRONG_ORIGIN_INTERNAL, MSG_MAP_WRONG_ORIGIN_EXTERNAL, MSG_MAP_BRANCH_SHARED_SESSION_UNSUPPORTED, MSG_MAP_FF_ALREADY_OPEN, MSG_MAP_FF_NOT_OPEN, MSG_MAP_FF_EMPTY, MSG_MAP_METHOD_GOT_ASSERT, MSG_MAP_BRANCH_NO_PRIOR_STEP, MSG_MAP_FF_NOT_CLOSED, MSG_MAP_EMPTY, } from "../errors.js";
2
- import { MemPage } from "../mem/mem.js";
3
1
  import { fastForwardComposeBlock } from "../block/compose.js";
4
- import { clearSessionState } from "./flow.js";
5
- import { copyWaygraphRuntime } from "../block/block.js";
6
- /** Per-step options every `MapBuilder` step method (`.gotoPage()`/`.method()`/`.assert()`) takes. */
7
- /** The same Block, but it clears cookies and storage before it acts. Keeps the runtime markers. */
8
- function resetBefore(block) {
9
- const act = block.instruction.act.bind(block.instruction);
10
- const next = {
11
- ...block,
12
- instruction: {
13
- ...block.instruction,
14
- async act(page, input, mem) {
15
- await clearSessionState(page.context(), page);
16
- return act(page, input, mem);
17
- },
18
- },
19
- };
20
- copyWaygraphRuntime(block, next);
21
- Object.defineProperty(next, "__waygraphResetBefore", { value: true, enumerable: false, configurable: true });
22
- return next;
23
- }
24
- /** Applies a step's `pace` option, keeping the Block's runtime markers. */
25
- function paced(block, opts) {
26
- if (opts?.pace === undefined)
27
- return block;
28
- const next = { ...block, demoPace: opts.pace };
29
- copyWaygraphRuntime(block, next);
30
- return next;
31
- }
32
- function mapKindOf(block) {
33
- return block?.__waygraphKind;
34
- }
35
- function mapSaltOf(block) {
36
- return block?.__waygraphSalt;
37
- }
38
- function mapNavUrlOf(block) {
39
- const url = block?.__waygraphNavUrl;
40
- return typeof url === "string" ? url : undefined;
41
- }
42
- const MAP_KIND_FACTORY_HINT = {
43
- nav: "defineNavBlock/defineMemNavBlock",
44
- page: "definePageBlock",
45
- assert: "defineAssertBlock",
46
- };
47
- const MAP_SALT_FACTORY_HINT = {
48
- method: "defineMethodBlock",
49
- effect: "defineEffectBlock",
50
- api: "defineApiBlock",
51
- };
52
- function assertMapKind(block, allowed, method) {
53
- const kind = mapKindOf(block);
54
- if (kind !== undefined && allowed.includes(kind))
55
- return;
56
- const wanted = allowed.map((k) => MAP_KIND_FACTORY_HINT[k] ?? k).join(" or ");
57
- const found = kind ? `a Block of kind "${kind}"` : "an object with no waygraph kind marker at all";
58
- throw new WaygraphError("WG_MAP_WRONG_KIND", MSG_MAP_WRONG_KIND(method, block?.name ?? "?", wanted, found));
59
- }
60
- function assertMapSalt(block, allowed, method) {
61
- const salt = mapSaltOf(block);
62
- if (salt !== undefined && allowed.includes(salt))
63
- return;
64
- const wanted = allowed.map((s) => MAP_SALT_FACTORY_HINT[s] ?? s).join(" or ");
65
- const found = salt ? `a Block salted "${salt}"` : "an object with no waygraph salt marker at all";
66
- throw new WaygraphError("WG_MAP_WRONG_SALT", MSG_MAP_WRONG_SALT(method, block?.name ?? "?", wanted, found));
67
- }
68
- function assertMapOrigin(block, homeOrigin, expect, method) {
69
- if (!homeOrigin)
70
- return; // not configured - can't validate, honest no-op
71
- const navUrl = mapNavUrlOf(block);
72
- if (navUrl === undefined)
73
- return; // click-based/dynamic nav - not statically checkable
74
- let targetOrigin;
75
- let wantOrigin;
76
- try {
77
- targetOrigin = new URL(navUrl, homeOrigin).origin;
78
- wantOrigin = new URL(homeOrigin).origin;
79
- }
80
- catch {
81
- return; // malformed URL - not this check's job to validate that
82
- }
83
- const isExternal = targetOrigin !== wantOrigin;
84
- if (expect === "internal" && isExternal) {
85
- throw new WaygraphError("WG_MAP_WRONG_ORIGIN", MSG_MAP_WRONG_ORIGIN_INTERNAL(block.name, targetOrigin, wantOrigin));
86
- }
87
- if (expect === "external" && !isExternal) {
88
- throw new WaygraphError("WG_MAP_WRONG_ORIGIN", MSG_MAP_WRONG_ORIGIN_EXTERNAL(block.name, targetOrigin, wantOrigin));
89
- }
90
- }
91
- /**
92
- * Builds the `Flow` object `MapBuilder.branch()` returns: run `before`, then dispatch on the
93
- * resolved tag into whichever `routes` entry matches (same page/context/mem), or return that
94
- * Checkpoint as-is when its route is `null`. Factored out so `withBlockVerify`/`modBlockVerify`
95
- * can patch `before` and rebuild the same branched shape, exactly like a plain Flow's own.
96
- */
97
- function buildBranchedFlow(before, routes) {
98
- const run = (async (contextOrMem, memOrConfig, options) => {
99
- if (contextOrMem instanceof MemPage) {
100
- throw new WaygraphError("WG_MAP_BRANCH_SHARED_SESSION_UNSUPPORTED", MSG_MAP_BRANCH_SHARED_SESSION_UNSUPPORTED);
101
- }
102
- const context = contextOrMem;
103
- const mem = memOrConfig;
104
- const gotOwnPage = options?.page === undefined;
105
- const page = options?.page ?? (await context.newPage());
106
- const closeOnFinish = options?.closeOnFinish ?? gotOwnPage;
107
- const first = (await before.run(context, mem, { ...options, page, closeOnFinish: false }));
108
- const branchFlow = routes[first.result.__state];
109
- if (!branchFlow) {
110
- if (options?.closeOnFinish === false)
111
- return { result: first.result, page: first.page };
112
- if (closeOnFinish)
113
- await first.page.close();
114
- return first.result;
115
- }
116
- return branchFlow.run(context, mem, { ...options, page: first.page, closeOnFinish });
117
- });
118
- return {
119
- resetSession: before.resetSession,
120
- config: before.config,
121
- ...(before.expectedFailureReason !== undefined ? { expectedFailureReason: before.expectedFailureReason } : {}),
122
- ...(before.demoPace !== undefined ? { demoPace: before.demoPace } : {}),
123
- ...(before.highlightStyle !== undefined ? { highlightStyle: before.highlightStyle } : {}),
124
- ...(before.memStub !== undefined ? { memStub: before.memStub } : {}),
125
- // Read by branchRoutes()/branchInfo() (branch-regression.ts) - real, ORDINARY (enumerable)
126
- // properties, not hidden ones, specifically so a `{ ...flow, ... }` spread (withSettings) carries them
127
- // through instead of silently dropping them -
128
- // the same class of bug branch()'s missing copyWaygraphRuntime call already was.
129
- __wgBranch: { before, routes },
130
- // Static introspection (`waygraph graph`/list): the fixed prefix, plus every branch's own
131
- // Blocks prefixed by the tag that leads to them - can't know at analysis time which one a real
132
- // run takes, so this shows all of them rather than none.
133
- blocks: () => [
134
- ...before.blocks(),
135
- ...Object.entries(routes).flatMap(([tag, f]) => f ? f.blocks().map((b) => ({ ...b, name: `${tag} -> ${b.name}` })) : []),
136
- ],
137
- run,
138
- withBlockVerify(block, verify) {
139
- return buildBranchedFlow(before.withBlockVerify(block, verify), routes);
140
- },
141
- modBlockVerify(block, nameOrIndex, newCheck) {
142
- return buildBranchedFlow(before.modBlockVerify(block, nameOrIndex, newCheck), routes);
143
- },
144
- };
145
- }
2
+ import { MSG_MAP_BRANCH_NO_PRIOR_STEP, MSG_MAP_EMPTY, MSG_MAP_FF_ALREADY_OPEN, MSG_MAP_FF_EMPTY, MSG_MAP_FF_NOT_CLOSED, MSG_MAP_FF_NOT_OPEN, MSG_MAP_METHOD_GOT_ASSERT, WaygraphError, } from "../errors.js";
3
+ import { buildBranchedFlow } from "./map-branch.js";
4
+ import { assertMapKind, assertMapOrigin, assertMapSalt, mapKindOf, paced, resetBefore } from "./map-steps.js";
146
5
  /**
147
6
  * The flow builder behind `engine.map()` - see `map()`'s own doc
148
7
  * comment for why this exists. Each step method is scoped to exactly the
@@ -220,7 +79,9 @@ export class MapBuilder {
220
79
  if (ff.buffer.length === 0) {
221
80
  throw new WaygraphError("WG_MAP_FF_EMPTY", MSG_MAP_FF_EMPTY(ff.name));
222
81
  }
223
- const composed = fastForwardComposeBlock(ff.name, ff.buffer);
82
+ const composed = fastForwardComposeBlock(ff.name,
83
+ // The window's steps were typechecked as they were added; the one-step overload takes them as one Block.
84
+ ff.buffer);
224
85
  return new MapBuilder(this.build, this.settings, [...this.steps, composed], this.homeOrigin, null);
225
86
  }
226
87
  /**
@@ -0,0 +1,30 @@
1
+ import { type SomeBlock, type SomeDefinedBlock } from "../block/block.js";
2
+ import type { DemoPace } from "../stub/pace.js";
3
+ /** The same Block, but it clears cookies and storage before it acts. Keeps the runtime markers. */
4
+ export declare function resetBefore(block: SomeBlock): SomeBlock;
5
+ /** Applies a step's `pace` option, keeping the Block's runtime markers. */
6
+ export declare function paced(block: object, opts: MapStepOpts | undefined): SomeDefinedBlock;
7
+ export declare function mapKindOf(block: unknown): string | undefined;
8
+ export declare function mapSaltOf(block: unknown): string | undefined;
9
+ export declare function mapNavUrlOf(block: unknown): string | undefined;
10
+ export declare function assertMapKind(block: SomeBlock, allowed: readonly string[], method: string): void;
11
+ export declare function assertMapSalt(block: SomeBlock, allowed: readonly string[], method: string): void;
12
+ export declare function assertMapOrigin(block: SomeBlock, homeOrigin: string | undefined, expect: "internal" | "external", method: string): void;
13
+ export declare const MAP_KIND_FACTORY_HINT: Record<string, string>;
14
+ export declare const MAP_SALT_FACTORY_HINT: Record<string, string>;
15
+ /** Per-step options for the map builder: `ff` fast-forwards the step, `pace` sets its demo pace. */
16
+ export interface MapStepOpts {
17
+ /**
18
+ * Fast-forward just this step, inline - no `.ffStart()/.ffEnd()` bracket needed. Consecutive
19
+ * `{ ff: true }` steps merge into ONE fast-forward block, same result as the explicit bracket
20
+ * form; a step without the flag closes an auto-opened window first.
21
+ * @example map().gotoPage(NavLoginBlock, { ff: true }).method(FillUsernameBlock, { ff: true })
22
+ */
23
+ ff?: boolean;
24
+ /**
25
+ * Demo pace for just this step (`"blitz"` skips the typing animation and the pause after the action; `"fast"`, `"slow"`,
26
+ * or a number scale the narration gates).
27
+ * @example map().method(SetBearerTokenBlock, { pace: "blitz" })
28
+ */
29
+ pace?: DemoPace;
30
+ }
@@ -0,0 +1,87 @@
1
+ import { copyWaygraphRuntime } from "../block/block.js";
2
+ import { MSG_MAP_WRONG_KIND, MSG_MAP_WRONG_ORIGIN_EXTERNAL, MSG_MAP_WRONG_ORIGIN_INTERNAL, MSG_MAP_WRONG_SALT, WaygraphError } from "../errors.js";
3
+ import { clearSessionState } from "./flow.js";
4
+ /** The same Block, but it clears cookies and storage before it acts. Keeps the runtime markers. */
5
+ export function resetBefore(block) {
6
+ const act = block.instruction.act.bind(block.instruction);
7
+ const next = {
8
+ ...block,
9
+ instruction: {
10
+ ...block.instruction,
11
+ async act(page, input, mem) {
12
+ await clearSessionState(page.context(), page);
13
+ return act(page, input, mem);
14
+ },
15
+ },
16
+ };
17
+ copyWaygraphRuntime(block, next);
18
+ Object.defineProperty(next, "__waygraphResetBefore", { value: true, enumerable: false, configurable: true });
19
+ return next;
20
+ }
21
+ /** Applies a step's `pace` option, keeping the Block's runtime markers. */
22
+ export function paced(block, opts) {
23
+ if (opts?.pace === undefined)
24
+ return block;
25
+ const next = { ...block, demoPace: opts.pace };
26
+ copyWaygraphRuntime(block, next);
27
+ return next;
28
+ }
29
+ export function mapKindOf(block) {
30
+ return block?.__waygraphKind;
31
+ }
32
+ export function mapSaltOf(block) {
33
+ return block?.__waygraphSalt;
34
+ }
35
+ export function mapNavUrlOf(block) {
36
+ const url = block?.__waygraphNavUrl;
37
+ return typeof url === "string" ? url : undefined;
38
+ }
39
+ export function assertMapKind(block, allowed, method) {
40
+ const kind = mapKindOf(block);
41
+ if (kind !== undefined && allowed.includes(kind))
42
+ return;
43
+ const wanted = allowed.map((k) => MAP_KIND_FACTORY_HINT[k] ?? k).join(" or ");
44
+ const found = kind ? `a Block of kind "${kind}"` : "an object with no waygraph kind marker at all";
45
+ throw new WaygraphError("WG_MAP_WRONG_KIND", MSG_MAP_WRONG_KIND(method, block?.name ?? "?", wanted, found));
46
+ }
47
+ export function assertMapSalt(block, allowed, method) {
48
+ const salt = mapSaltOf(block);
49
+ if (salt !== undefined && allowed.includes(salt))
50
+ return;
51
+ const wanted = allowed.map((s) => MAP_SALT_FACTORY_HINT[s] ?? s).join(" or ");
52
+ const found = salt ? `a Block salted "${salt}"` : "an object with no waygraph salt marker at all";
53
+ throw new WaygraphError("WG_MAP_WRONG_SALT", MSG_MAP_WRONG_SALT(method, block?.name ?? "?", wanted, found));
54
+ }
55
+ export function assertMapOrigin(block, homeOrigin, expect, method) {
56
+ if (!homeOrigin)
57
+ return; // not configured - can't validate, honest no-op
58
+ const navUrl = mapNavUrlOf(block);
59
+ if (navUrl === undefined)
60
+ return; // click-based/dynamic nav - not statically checkable
61
+ let targetOrigin;
62
+ let wantOrigin;
63
+ try {
64
+ targetOrigin = new URL(navUrl, homeOrigin).origin;
65
+ wantOrigin = new URL(homeOrigin).origin;
66
+ }
67
+ catch {
68
+ return; // malformed URL - not this check's job to validate that
69
+ }
70
+ const isExternal = targetOrigin !== wantOrigin;
71
+ if (expect === "internal" && isExternal) {
72
+ throw new WaygraphError("WG_MAP_WRONG_ORIGIN", MSG_MAP_WRONG_ORIGIN_INTERNAL(block.name, targetOrigin, wantOrigin));
73
+ }
74
+ if (expect === "external" && !isExternal) {
75
+ throw new WaygraphError("WG_MAP_WRONG_ORIGIN", MSG_MAP_WRONG_ORIGIN_EXTERNAL(block.name, targetOrigin, wantOrigin));
76
+ }
77
+ }
78
+ export const MAP_KIND_FACTORY_HINT = {
79
+ nav: "defineNavBlock/defineMemNavBlock",
80
+ page: "definePageBlock",
81
+ assert: "defineAssertBlock",
82
+ };
83
+ export const MAP_SALT_FACTORY_HINT = {
84
+ method: "defineMethodBlock",
85
+ effect: "defineEffectBlock",
86
+ api: "defineApiBlock",
87
+ };
@@ -1,5 +1,5 @@
1
1
  // URLPattern is only a Node global from v23.8+ (and even then, Node's own, not a browser's) -
2
- // CI's Node 20/22 matrix has no global at all. Side-effect import only: the polyfill package sets
2
+ // Node 22 (the oldest supported) has no global at all. Side-effect import only: the polyfill package sets
3
3
  // globalThis.URLPattern itself, but only when one doesn't already exist - so below Node 23.8 this
4
4
  // becomes THE global, and from 23.8 up it's a no-op and the native one stays. Playwright's own
5
5
  // waitForURL(pattern) checks `pattern instanceof globalThis.URLPattern` internally, so the instance
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import "./runtime/full-launch.js";
2
2
  import "./runtime/run-log.js";
3
3
  export type { Checkpoint, Start } from "./engine/checkpoint/checkpoint.js";
4
- export type { Instruction, Block, DefinedBlock, SomeBlock, SomeDefinedBlock, WaygraphInstanceOption } from "./engine/block/block.js";
4
+ export type { Instruction, Block, DefinedBlock, SomeBlock, SomeDefinedBlock } from "./engine/block/block.js";
5
+ export type { WaygraphInstanceOption } from "./engine/block/action-page.js";
5
6
  export { connect } from "./engine/run/connect.js";
6
7
  export { checkpoint } from "./engine/checkpoint/checkpoint.js";
7
8
  export { MemKey, MemPage, key, keyGroup } from "./engine/mem/mem.js";
@@ -9,10 +10,12 @@ export { registerMemStub, seedMemStub, getMemStub } from "./engine/mem/mem-stub.
9
10
  export { css, byText, byRole } from "./engine/trait/selector.js";
10
11
  export { WaygraphError, WAYGRAPH_ERRORS } from "./engine/errors.js";
11
12
  export type { WaygraphErrorCode } from "./engine/errors.js";
12
- export { Trait, urlMatches, textEquals, visible, disabled, enabled, frameVisible, frameTextEquals, frameContainsText, } from "./engine/trait/trait.js";
13
+ export { Trait, urlMatches, textEquals, visible, disabled, enabled, frameVisible, frameTextEquals, frameContainsText } from "./engine/trait/trait.js";
13
14
  export { runGraph, spawnTab, narrate, preflight, defineLayout } from "./engine/run/run.js";
14
15
  export { Engine, map } from "./engine/engine.js";
15
- export { branch, withVerify, modVerify, modVerifyAll, defineBlock, withDialog } from "./engine/block/block.js";
16
+ export { branch } from "./engine/block/branch.js";
17
+ export { withVerify, modVerify, modVerifyAll, defineBlock } from "./engine/block/block.js";
18
+ export { withDialog } from "./engine/block/dialog.js";
16
19
  export { defineNavBlock, defineNavClickBlock, defineMemNavBlock } from "./engine/block/kinds/nav.js";
17
20
  export { defineMethodBlock, defineAssertBlock } from "./engine/block/kinds/method.js";
18
21
  export { definePageBlock } from "./engine/block/kinds/page.js";
@@ -24,7 +27,8 @@ export { MapBuilder } from "./engine/flow/map-builder.js";
24
27
  export { branchRoutes, collectBranchFlows, runBranchRegression } from "./engine/flow/branch-regression.js";
25
28
  export type { BranchEntry, BranchRunResult, RunBranchRegressionOptions } from "./engine/flow/branch-regression.js";
26
29
  export type { ApiBlockOptions, ApiCallResult } from "./engine/block/kinds/api.js";
27
- export type { MapStepOpts, MapFlowOpts } from "./engine/flow/map-builder.js";
30
+ export type { MapStepOpts } from "./engine/flow/map-steps.js";
31
+ export type { MapFlowOpts } from "./engine/flow/map-builder.js";
28
32
  export { resolveHighlightSlots, resolveSlides, runStubPhase, hasAuthoredStubAfter, hasAuthoredStubOnError } from "./demo/narration/narration.js";
29
33
  export { resolveFixtureDwellMs, normalizeDemoPace, resolveStepDemoPace, demoPaceScale, demoPaceIsBlitz, demoPaceIsFast, demoPaceIsSlow, demoPaceGateMs, formatDemoPaceBadge, formatDemoPaceLabel, FIXTURE_DURATION_MS_DEFAULT, FIXTURE_DURATION_FAST_MS_DEFAULT, FIXTURE_DURATION_SLOW_MS_DEFAULT } from "./demo/narration/demo-pace.js";
30
34
  export { formatHighlightCaption, applyHighlightStyleDefaults, toneIconPrefix } from "./demo/narration/style.js";
@@ -46,21 +50,21 @@ export type { MethodBlock, AssertBlock, AssertBlockOptions } from "./engine/bloc
46
50
  export type { PageBlock, PageBlockOptions, PageMethodEntry } from "./engine/block/kinds/page.js";
47
51
  export type { EffectBlock } from "./engine/block/kinds/effect.js";
48
52
  export type { MapBuilderOptions } from "./engine/flow/map-builder.js";
49
- export type { ActionPage } from "./engine/block/block.js";
53
+ export type { ActionPage } from "./engine/block/action-page.js";
50
54
  export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./analysis/graph.js";
51
55
  export { buildManifest } from "./manifest/manifest.js";
52
56
  export { onRunEvent } from "./engine/run/events.js";
53
57
  export type { RunEvent } from "./engine/run/events.js";
54
58
  export type { Manifest, ManifestBlock, ManifestFlow } from "./manifest/manifest.js";
55
59
  export type { WaygraphGraph, WaygraphNode, WaygraphEdge, SkippedBlock, OrphanBlock } from "./analysis/graph.js";
56
- export { isFileSelectToken, parseBlocksSelect, matchBlocksSelect, globToRegExp, } from "./manifest/select.js";
60
+ export { isFileSelectToken, parseBlocksSelect, matchBlocksSelect, globToRegExp } from "./manifest/select.js";
57
61
  export type { BlocksSelect, BlocksSelectKind } from "./manifest/select.js";
58
62
  export { EdgeLeaseCoordinator } from "./live/traverse/lease.js";
59
63
  export { runTraverse } from "./live/traverse/traverse.js";
60
- export type { TraverseOptions, TraverseSessionMode, TraverseWorkerResult, } from "./live/traverse/traverse.js";
61
- export { buildCoverageReport, collectGraphEdgeKeys, defaultCoverageOutPath, formatCoverageLine, normalizeHitKey, parseMinEdgeCoverage, writeCoverageReport, } from "./live/traverse/coverage.js";
64
+ export type { TraverseOptions, TraverseSessionMode, TraverseWorkerResult } from "./live/traverse/traverse.js";
65
+ export { buildCoverageReport, collectGraphEdgeKeys, defaultCoverageOutPath, formatCoverageLine, normalizeHitKey, parseMinEdgeCoverage, writeCoverageReport } from "./live/traverse/coverage.js";
62
66
  export type { TraverseCoverageReport } from "./live/traverse/coverage.js";
63
- export { WG_UI_SEL, WG_READY_PANEL_SEL, WG_READY_AUTO_SEL, WG_READY_BANNER_SEL, readWgOverlayBeacon, readWgOverlayBeaconInPage, assertWgOverlayReady, } from "./demo/overlay/beacon.js";
67
+ export { WG_UI_SEL, WG_READY_PANEL_SEL, WG_READY_AUTO_SEL, WG_READY_BANNER_SEL, readWgOverlayBeacon, readWgOverlayBeaconInPage, assertWgOverlayReady } from "./demo/overlay/beacon.js";
64
68
  export type { WgModalKind, WgBeaconRow } from "./demo/overlay/beacon.js";
65
69
  export { AutoSession } from "./live/auto-session/auto-session.js";
66
70
  export { stubFilePath } from "./live/auto-session/helpers.js";
package/dist/index.js CHANGED
@@ -8,10 +8,12 @@ export { MemKey, MemPage, key, keyGroup } from "./engine/mem/mem.js";
8
8
  export { registerMemStub, seedMemStub, getMemStub } from "./engine/mem/mem-stub.js";
9
9
  export { css, byText, byRole } from "./engine/trait/selector.js";
10
10
  export { WaygraphError, WAYGRAPH_ERRORS } from "./engine/errors.js";
11
- export { Trait, urlMatches, textEquals, visible, disabled, enabled, frameVisible, frameTextEquals, frameContainsText, } from "./engine/trait/trait.js";
11
+ export { Trait, urlMatches, textEquals, visible, disabled, enabled, frameVisible, frameTextEquals, frameContainsText } from "./engine/trait/trait.js";
12
12
  export { runGraph, spawnTab, narrate, preflight, defineLayout } from "./engine/run/run.js";
13
13
  export { Engine, map } from "./engine/engine.js";
14
- export { branch, withVerify, modVerify, modVerifyAll, defineBlock, withDialog } from "./engine/block/block.js";
14
+ export { branch } from "./engine/block/branch.js";
15
+ export { withVerify, modVerify, modVerifyAll, defineBlock } from "./engine/block/block.js";
16
+ export { withDialog } from "./engine/block/dialog.js";
15
17
  export { defineNavBlock, defineNavClickBlock, defineMemNavBlock } from "./engine/block/kinds/nav.js";
16
18
  export { defineMethodBlock, defineAssertBlock } from "./engine/block/kinds/method.js";
17
19
  export { definePageBlock } from "./engine/block/kinds/page.js";
@@ -31,11 +33,11 @@ export { WAYGRAPH_RING_CSS } from "./demo/narration/css.js";
31
33
  export { discoverGraph, toMermaid, findOrphanBlocks, findBlockPath } from "./analysis/graph.js";
32
34
  export { buildManifest } from "./manifest/manifest.js";
33
35
  export { onRunEvent } from "./engine/run/events.js";
34
- export { isFileSelectToken, parseBlocksSelect, matchBlocksSelect, globToRegExp, } from "./manifest/select.js";
36
+ export { isFileSelectToken, parseBlocksSelect, matchBlocksSelect, globToRegExp } from "./manifest/select.js";
35
37
  export { EdgeLeaseCoordinator } from "./live/traverse/lease.js";
36
38
  export { runTraverse } from "./live/traverse/traverse.js";
37
- export { buildCoverageReport, collectGraphEdgeKeys, defaultCoverageOutPath, formatCoverageLine, normalizeHitKey, parseMinEdgeCoverage, writeCoverageReport, } from "./live/traverse/coverage.js";
38
- export { WG_UI_SEL, WG_READY_PANEL_SEL, WG_READY_AUTO_SEL, WG_READY_BANNER_SEL, readWgOverlayBeacon, readWgOverlayBeaconInPage, assertWgOverlayReady, } from "./demo/overlay/beacon.js";
39
+ export { buildCoverageReport, collectGraphEdgeKeys, defaultCoverageOutPath, formatCoverageLine, normalizeHitKey, parseMinEdgeCoverage, writeCoverageReport } from "./live/traverse/coverage.js";
40
+ export { WG_UI_SEL, WG_READY_PANEL_SEL, WG_READY_AUTO_SEL, WG_READY_BANNER_SEL, readWgOverlayBeacon, readWgOverlayBeaconInPage, assertWgOverlayReady } from "./demo/overlay/beacon.js";
39
41
  export { AutoSession } from "./live/auto-session/auto-session.js";
40
42
  export { stubFilePath } from "./live/auto-session/helpers.js";
41
43
  export { pilotStart } from "./live/pilot/pilot.js";
@@ -1,9 +1,8 @@
1
- import type { BlockEntry } from "../../manifest/project.js";
2
- import type { Page, BrowserContext } from "@playwright/test";
1
+ import type { BrowserContext, Page } from "@playwright/test";
2
+ import type { Checkpoint } from "../../engine/checkpoint/checkpoint.js";
3
3
  import { Engine } from "../../engine/engine.js";
4
4
  import { MemPage } from "../../engine/mem/mem.js";
5
- import type { MemKey } from "../../engine/mem/mem.js";
6
- import type { Checkpoint } from "../../engine/checkpoint/checkpoint.js";
5
+ import type { BlockEntry } from "../../manifest/project.js";
7
6
  export interface AutoExploreOptions {
8
7
  /** Terminal menu (browser still runs for act()). Default false = headful picker panel. */
9
8
  cli?: boolean;
@@ -16,18 +15,7 @@ export interface AutoExploreOptions {
16
15
  /** Which Checkpoint the page is on, asked of the project's own Nav / Page Blocks (their verify). */
17
16
  export declare function detectHere(page: Page, navBlocks: BlockEntry[]): Promise<string | null>;
18
17
  export declare function ensureLivePage(context: BrowserContext, page: Page, startUrl: string | undefined): Promise<Page>;
19
- /** The project's own default for a key: its `registerMemStub` fake (live sessions load every `*.mem-stubs.ts`). */
20
- export declare function memStubValue(key: MemKey<unknown>): unknown | undefined;
21
- /** Pre-seeds required keys from WAYGRAPH_DATA and the project's mem stubs, so a session does not stop for mem forms. */
22
- export declare function seedDefaultMem(library: Map<string, BlockEntry>, mem: MemPage): void;
23
- export declare function ensureMem(entry: BlockEntry, mem: MemPage, cli: boolean): Promise<void>;
24
18
  export declare function runOneBlock(engine: Engine, entry: BlockEntry, context: BrowserContext, page: Page, mem: MemPage, headful: boolean): Promise<Checkpoint<string>>;
25
- export type PickResult = {
26
- type: "pick";
27
- index: number;
28
- } | {
29
- type: "quit";
30
- };
31
19
  /**
32
20
  * Interactive waygraph auto: locate current Checkpoint, list runnable Blocks, pick one, repeat.
33
21
  */