waygraph 0.15.51 → 0.15.53
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 +8 -1
- package/dist/analysis/graph.d.ts +1 -1
- package/dist/analysis/graph.js +10 -15
- package/dist/analysis/map-check.d.ts +3 -2
- package/dist/analysis/practices-check.d.ts +0 -1
- package/dist/analysis/practices-check.js +0 -13
- package/dist/auto-session/session.d.ts +1 -1
- package/dist/auto-session/session.js +13 -8
- package/dist/blocks-select.d.ts +7 -4
- package/dist/blocks-select.js +0 -14
- package/dist/browser.d.ts +27 -0
- package/dist/browser.js +62 -0
- package/dist/cli/flags.js +3 -1
- package/dist/cli/run-chain.js +4 -0
- package/dist/cli/usage.js +17 -1
- package/dist/cli.js +13 -1
- package/dist/commands/agent-dive-scaffold.d.ts +5 -20
- package/dist/commands/agent-dive-scaffold.js +10 -3
- package/dist/commands/extensions.d.ts +1 -0
- package/dist/commands/extensions.js +22 -0
- package/dist/commands/init.js +43 -5
- package/dist/commands/test.js +16 -2
- package/dist/commands/try.js +2 -1
- package/dist/commands/upgrade.d.ts +6 -0
- package/dist/commands/upgrade.js +113 -0
- package/dist/config.d.ts +81 -3
- package/dist/config.js +91 -16
- package/dist/core/block.d.ts +19 -2
- package/dist/core/block.js +43 -3
- package/dist/core/blocks/nav.d.ts +11 -0
- package/dist/core/blocks/nav.js +8 -0
- package/dist/core/config.d.ts +5 -0
- package/dist/core/engine.d.ts +19 -16
- package/dist/core/engine.js +6 -4
- package/dist/core/flow.d.ts +27 -0
- package/dist/core/flow.js +75 -28
- package/dist/core/map-builder.d.ts +30 -4
- package/dist/core/map-builder.js +45 -7
- package/dist/env-file.d.ts +7 -7
- package/dist/env-file.js +29 -16
- package/dist/extensions.d.ts +21 -0
- package/dist/extensions.js +178 -0
- package/dist/highlights/demo-pace.d.ts +0 -1
- package/dist/highlights/demo-pace.js +24 -3
- package/dist/index.d.ts +7 -5
- package/dist/index.js +3 -2
- package/dist/pilot-overlay/action-ring.d.ts +0 -9
- package/dist/pilot-overlay/action-ring.js +1 -1
- package/dist/pilot-overlay/overlay-fixtures.d.ts +0 -7
- package/dist/pilot-overlay/overlay-fixtures.js +0 -45
- package/dist/pilot-overlay/panel.d.ts +2 -1
- package/dist/playwright-config.d.ts +4 -0
- package/dist/playwright-config.js +15 -0
- package/dist/playwright.config.d.ts +2 -0
- package/dist/playwright.config.js +6 -0
- package/dist/runner/demo-log.js +1 -7
- package/dist/runner/inpage/core.d.ts +1 -1
- package/dist/runner/inpage/core.js +8 -7
- package/dist/runner/interaction-patch.js +32 -1
- package/dist/runner/main.js +22 -11
- package/dist/runner/rings.js +0 -49
- package/dist/runner/step-mode.js +10 -4
- package/dist/session/auto-explore-run.js +9 -5
- package/dist/session/auto-explore.d.ts +2 -1
- package/dist/session/auto-explore.js +6 -4
- package/dist/session/auto-session-ipc.d.ts +1 -2
- package/dist/session/auto-session-ipc.js +1 -1
- package/dist/session/block-inject.d.ts +0 -13
- package/dist/session/block-inject.js +3 -3
- package/dist/session/pilot.d.ts +0 -2
- package/dist/session/pilot.js +1 -2
- package/dist/session/step-overlay.js +3 -1
- package/dist/traverse/coverage.d.ts +0 -4
- package/dist/traverse/coverage.js +1 -1
- package/dist/traverse/run.js +3 -1
- package/dist/types.d.ts +1 -1
- package/dist/ui/components/ring.js +1 -0
- package/dist/ui/overlay.css +1 -0
- package/dist/ui/shadow.d.ts +1 -3
- package/dist/ui/shadow.js +0 -4
- package/dist/ui/tokens.d.ts +0 -11
- package/dist/ui/tokens.js +0 -5
- package/dist/video-dir.d.ts +8 -0
- package/dist/video-dir.js +60 -0
- package/dist/webserver.js +5 -1
- package/package.json +11 -5
- package/templates/scaffold/README.md +5 -3
- package/templates/scaffold/STRUCTURE.md +10 -4
- package/templates/scaffold/config/waygraph.config.ts +45 -0
- package/templates/scaffold/package.json +7 -7
- package/templates/scaffold/src/flows/(external)/hoppscotch/auth.flow.ts +36 -0
- package/templates/scaffold/src/flows/(external)/hoppscotch/get.flow.ts +24 -0
- package/templates/scaffold/src/flows/(external)/hoppscotch/post.flow.ts +34 -0
- package/templates/scaffold/src/flows/(user-stories)/email-verification.flow.ts +47 -0
- package/templates/scaffold/src/flows/README.md +35 -14
- package/templates/scaffold/src/flows/home/cart.flow.ts +51 -0
- package/templates/scaffold/src/flows/home/hello.flow.ts +42 -0
- package/templates/scaffold/src/map/(app_base)/docs/_nav.block.ts +0 -9
- package/templates/scaffold/src/map/(app_base)/docs/_page.block.ts +0 -5
- package/templates/scaffold/src/map/(app_base)/docs/_sel.ts +1 -1
- package/templates/scaffold/src/map/(app_base)/home/_methods/add-item.effect.block.ts +3 -19
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-hello.method.block.ts +2 -25
- package/templates/scaffold/src/map/(app_base)/home/_methods/assert-item-added.method.block.ts +2 -19
- package/templates/scaffold/src/map/(app_base)/home/_methods/clear-cart.method.block.ts +1 -17
- package/templates/scaffold/src/map/(app_base)/home/_methods/remove-item.effect.block.ts +1 -10
- package/templates/scaffold/src/map/(app_base)/home/_nav.block.ts +1 -12
- package/templates/scaffold/src/map/(app_base)/home/_page.block.ts +0 -9
- package/templates/scaffold/src/map/(app_base)/home/_sel.ts +3 -1
- package/templates/scaffold/src/map/(app_base)/home/nav-verification-link.block.ts +1 -23
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-body.method.block.ts +21 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-response-header.method.block.ts +19 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/assert-status.method.block.ts +20 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/pick-extension-interceptor.method.block.ts +18 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-body.method.block.ts +21 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/read-response-headers.method.block.ts +21 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/send-request.method.block.ts +15 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-bearer-token.method.block.ts +20 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-headers.method.block.ts +23 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-json-body.method.block.ts +36 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-method.method.block.ts +17 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-query-params.method.block.ts +22 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_methods/set-url.method.block.ts +18 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_nav.block.ts +11 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_page.block.ts +36 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/_sel.ts +27 -0
- package/templates/scaffold/src/map/(external)/hoppscotch/settings/_nav.block.ts +10 -0
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-content.method.block.ts +2 -27
- package/templates/scaffold/src/map/(external)/mailpit/_methods/assert-email-received.method.block.ts +2 -21
- package/templates/scaffold/src/map/(external)/mailpit/_methods/extract-email-link.method.block.ts +1 -19
- package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +1 -11
- package/templates/scaffold/src/map/(external)/mailpit/_nav.block.ts +1 -9
- package/templates/scaffold/src/map/(external)/mailpit/_page.block.ts +0 -11
- package/templates/scaffold/src/states/demo.mem-keys.ts +20 -19
- package/templates/scaffold/src/states/demo.mem-stubs.ts +4 -0
- package/templates/scaffold/src/states/demo.states.ts +5 -1
- package/templates/scaffold/tests/example.spec.ts +6 -7
- package/templates/scaffold/tests/hoppscotch.spec.ts +97 -0
- package/templates/scaffold/tests/mail-verify.spec.ts +8 -17
- package/templates/scaffold/tsconfig.json +1 -1
- package/templates/skills/waygraph-convention.skill.md +40 -3
- package/templates/skills/waygraph-pilot.skill.md +4 -5
- package/dist/browser-path.d.ts +0 -5
- package/dist/browser-path.js +0 -18
- package/dist/runner/overlay-present.d.ts +0 -8
- package/dist/runner/overlay-present.js +0 -57
- package/dist/ui/components/banner.d.ts +0 -2
- package/dist/ui/components/banner.js +0 -10
- package/dist/ui/components/cursor.d.ts +0 -2
- package/dist/ui/components/cursor.js +0 -19
- package/templates/scaffold/playwright.config.ts +0 -12
- package/templates/scaffold/src/flows/example.flow.ts +0 -29
- package/templates/scaffold/src/flows/mail-verify.flow.ts +0 -85
- package/templates/scaffold/src/flows/shop.flow.ts +0 -74
package/dist/commands/try.js
CHANGED
|
@@ -6,6 +6,7 @@ import { packageRoot, runInherited } from "../cli/util.js";
|
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { runChain } from "../cli/run-chain.js";
|
|
8
8
|
import { applyRunFlags, parseRunFlags } from "../cli/flags.js";
|
|
9
|
+
import { resolveVideoDir } from "../video-dir.js";
|
|
9
10
|
/**
|
|
10
11
|
* Runs a throwaway probe script rooted at `projectDir` - the exact same
|
|
11
12
|
* directory the real demo files get copied into, so it resolves "waygraph"
|
|
@@ -196,7 +197,7 @@ async function runTryDemo() {
|
|
|
196
197
|
const videoTo = process.env.WAYGRAPH_VIDEO;
|
|
197
198
|
console.log(videoTo
|
|
198
199
|
? "waygraph try demo: step-through + record (Sign In -> Shop & Checkout -> blocked Viewer login) - click Next; video -> " +
|
|
199
|
-
(videoTo === "1" ?
|
|
200
|
+
(videoTo === "1" ? await resolveVideoDir(destDir) : videoTo)
|
|
200
201
|
: "waygraph try demo: step-through (Sign In -> Shop & Checkout -> blocked Viewer login) - click Next for each step ...");
|
|
201
202
|
await runChain(destDir, TRY_DEMO_CHAIN);
|
|
202
203
|
if (process.exitCode)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `waygraph upgrade [project] [paths...] [--apply] [--overwrite] [--diff] [--skills]`
|
|
3
|
+
* Compares the project with the scaffold shipped in this waygraph. Dry run by default.
|
|
4
|
+
* Only the paths you name are copied, because a real project deliberately drops parts of the demo.
|
|
5
|
+
*/
|
|
6
|
+
export declare function upgradeCase(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { basename, join, relative, resolve, dirname } from "node:path";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { packageRoot } from "../cli/util.js";
|
|
6
|
+
import { agentSkillFiles } from "./agent-dive-scaffold.js";
|
|
7
|
+
// Filled in per project at init, so they never compare equal to the template.
|
|
8
|
+
const SKIP = new Set(["package.json", join("config", "waygraph.config.ts")]);
|
|
9
|
+
function walk(dir, base = dir) {
|
|
10
|
+
return readdirSync(dir).flatMap((name) => {
|
|
11
|
+
const full = join(dir, name);
|
|
12
|
+
return statSync(full).isDirectory() ? walk(full, base) : [relative(base, full)];
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const targetName = (rel) => (rel === "gitignore" ? ".gitignore" : rel);
|
|
16
|
+
const major = (v) => v.replace(/^[^\d]*/, "").split(".").map((n) => parseInt(n, 10) || 0);
|
|
17
|
+
const isOlder = (a, b) => {
|
|
18
|
+
for (let i = 0; i < 3; i++)
|
|
19
|
+
if ((a[i] ?? 0) !== (b[i] ?? 0))
|
|
20
|
+
return (a[i] ?? 0) < (b[i] ?? 0);
|
|
21
|
+
return false;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* `waygraph upgrade [project] [paths...] [--apply] [--overwrite] [--diff] [--skills]`
|
|
25
|
+
* Compares the project with the scaffold shipped in this waygraph. Dry run by default.
|
|
26
|
+
* Only the paths you name are copied, because a real project deliberately drops parts of the demo.
|
|
27
|
+
*/
|
|
28
|
+
export async function upgradeCase(args) {
|
|
29
|
+
const flags = new Set(args.filter((a) => a.startsWith("--")));
|
|
30
|
+
const positional = args.slice(1).filter((a) => !a.startsWith("--"));
|
|
31
|
+
// --skills: the agent skills are waygraph's own text, never edited by a project, so refresh them in place.
|
|
32
|
+
if (flags.has("--skills")) {
|
|
33
|
+
flags.add("--apply");
|
|
34
|
+
flags.add("--overwrite");
|
|
35
|
+
positional.push(".agents/skills");
|
|
36
|
+
}
|
|
37
|
+
const first = positional[0];
|
|
38
|
+
const hasProject = first !== undefined && existsSync(join(resolve(first), "package.json"));
|
|
39
|
+
const proj = resolve(hasProject ? first : process.cwd());
|
|
40
|
+
const paths = hasProject ? positional.slice(1) : positional;
|
|
41
|
+
const templateDir = join(packageRoot(), "templates", "scaffold");
|
|
42
|
+
const ownVersion = JSON.parse(readFileSync(join(packageRoot(), "package.json"), "utf-8")).version;
|
|
43
|
+
const pkgPath = join(proj, "package.json");
|
|
44
|
+
if (!existsSync(pkgPath)) {
|
|
45
|
+
console.error(`waygraph upgrade: no package.json in ${proj}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
const added = [];
|
|
49
|
+
const differing = [];
|
|
50
|
+
// Every shipped file as [path in the project, content]: the scaffold tree plus the agent skills.
|
|
51
|
+
const shipped = new Map();
|
|
52
|
+
for (const rel of walk(templateDir))
|
|
53
|
+
if (!SKIP.has(rel))
|
|
54
|
+
shipped.set(rel, readFileSync(join(templateDir, rel)));
|
|
55
|
+
for (const { rel, text } of agentSkillFiles())
|
|
56
|
+
shipped.set(rel, Buffer.from(text));
|
|
57
|
+
for (const [rel, content] of shipped) {
|
|
58
|
+
const dest = join(proj, targetName(rel));
|
|
59
|
+
if (!existsSync(dest))
|
|
60
|
+
added.push(rel);
|
|
61
|
+
else if (!readFileSync(dest).equals(content))
|
|
62
|
+
differing.push(rel);
|
|
63
|
+
}
|
|
64
|
+
const selected = (rel) => paths.some((p) => rel === p || rel.startsWith(p.replace(/\/?$/, "/")));
|
|
65
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
66
|
+
const current = pkg.dependencies?.waygraph;
|
|
67
|
+
const depStale = current !== undefined && !current.startsWith("file:") && isOlder(major(current), major(ownVersion));
|
|
68
|
+
console.log(`waygraph upgrade: ${proj} (waygraph ${current ?? "not a dependency"} -> ${ownVersion})`);
|
|
69
|
+
if (depStale)
|
|
70
|
+
console.log(` dependency waygraph ${current} -> ^${ownVersion}`);
|
|
71
|
+
for (const rel of added)
|
|
72
|
+
console.log(` new ${rel}`);
|
|
73
|
+
for (const rel of differing)
|
|
74
|
+
console.log(` differs ${rel}`);
|
|
75
|
+
if (!depStale && added.length === 0 && differing.length === 0)
|
|
76
|
+
console.log(" up to date");
|
|
77
|
+
const legacy = ["ts", "mts", "js", "mjs", "cjs"].find((e) => existsSync(join(proj, `playwright.config.${e}`)));
|
|
78
|
+
if (legacy) {
|
|
79
|
+
console.log(` deprecated playwright.config.${legacy} - move its settings into config/waygraph.config.ts (testDir, webServer, playwright: { ... })`);
|
|
80
|
+
}
|
|
81
|
+
if (flags.has("--diff")) {
|
|
82
|
+
for (const rel of differing.filter((r) => paths.length === 0 || selected(r))) {
|
|
83
|
+
const shippedCopy = join(tmpdir(), `waygraph-upgrade-${process.pid}-${basename(rel)}`);
|
|
84
|
+
writeFileSync(shippedCopy, shipped.get(rel));
|
|
85
|
+
spawnSync("diff", ["-u", join(proj, targetName(rel)), shippedCopy], { stdio: "inherit" });
|
|
86
|
+
rmSync(shippedCopy, { force: true });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (!flags.has("--apply")) {
|
|
90
|
+
if (added.length + differing.length > 0) {
|
|
91
|
+
console.log("\nDry run. Copy files with: waygraph upgrade <paths...> --apply (add --overwrite to replace differing files)");
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (depStale) {
|
|
96
|
+
pkg.dependencies.waygraph = `^${ownVersion}`;
|
|
97
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
98
|
+
console.log("updated package.json - run npm install");
|
|
99
|
+
}
|
|
100
|
+
if (paths.length === 0 && added.length + differing.length > 0) {
|
|
101
|
+
console.log("no paths given, so no files were copied (e.g. waygraph upgrade \"src/map/(external)/hoppscotch\" --apply)");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const copy = [...added, ...(flags.has("--overwrite") ? differing : [])].filter(selected);
|
|
105
|
+
for (const rel of copy) {
|
|
106
|
+
const dest = join(proj, targetName(rel));
|
|
107
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
108
|
+
writeFileSync(dest, shipped.get(rel));
|
|
109
|
+
console.log(` wrote ${rel}`);
|
|
110
|
+
}
|
|
111
|
+
if (copy.length === 0 && paths.length > 0)
|
|
112
|
+
console.log("nothing matched those paths");
|
|
113
|
+
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,10 +1,80 @@
|
|
|
1
|
+
import type { PlaywrightTestConfig } from "@playwright/test";
|
|
2
|
+
import type { ExtensionSpec } from "./extensions.js";
|
|
3
|
+
import type { WebServerConfig } from "./webserver.js";
|
|
4
|
+
import type { DemoPace } from "./highlights.js";
|
|
5
|
+
export interface VideoSettings {
|
|
6
|
+
/** Where recordings are saved: absolute, `~/…`, or relative to the project. Default `~/Downloads/waygraph-videos/<project>` (the project's `.waygraph-videos/` where there is no Downloads folder, and on CI). */
|
|
7
|
+
dir?: string;
|
|
8
|
+
/** Recording size, e.g. `"1920x1080"` (demo default) or `"1280x720"` (run default). */
|
|
9
|
+
viewport?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Settings `waygraph run` and `waygraph demo` share. */
|
|
12
|
+
export interface RunSettings {
|
|
13
|
+
/** Show the browser window. */
|
|
14
|
+
headed?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* `run`: Playwright's `slowMo`, ms before every operation. `demo`: waygraph's own pause after each action (default 350),
|
|
17
|
+
* applied once per action rather than per keystroke, and removed by a step's `pace: "blitz"`.
|
|
18
|
+
*/
|
|
19
|
+
slowMo?: number;
|
|
20
|
+
video?: VideoSettings;
|
|
21
|
+
}
|
|
22
|
+
/** Settings for `waygraph demo`. */
|
|
23
|
+
export interface DemoSettings extends RunSettings {
|
|
24
|
+
/** Default pace for flows and steps that set none: `"fast"`, `"slow"`, `"blitz"`, or a multiplier like `0.5` / `2`. Narration gates and dwell scale with it; `"blitz"` also skips typing animation. */
|
|
25
|
+
pace?: DemoPace;
|
|
26
|
+
/**
|
|
27
|
+
* What the named paces mean, as multipliers of normal dwell and gate time (1 = normal): blitz 0.05, fast 0.33, slow 2 by
|
|
28
|
+
* default. Lower is faster. `blitz` also skips the cursor, ring pops and typing animation.
|
|
29
|
+
* @example speeds: { fast: 0.5, blitz: 0.1 }
|
|
30
|
+
*/
|
|
31
|
+
speeds?: {
|
|
32
|
+
blitz?: number;
|
|
33
|
+
fast?: number;
|
|
34
|
+
slow?: number;
|
|
35
|
+
};
|
|
36
|
+
/** Typing animation: ms per character (default 30). `0` types instantly. */
|
|
37
|
+
typingMs?: number;
|
|
38
|
+
/** Advance steps automatically instead of waiting for Next. */
|
|
39
|
+
autoNext?: boolean;
|
|
40
|
+
/** Shorter Next / auto-next gates; keeps the cursor and typing animation. */
|
|
41
|
+
fast?: boolean;
|
|
42
|
+
}
|
|
1
43
|
export interface WaygraphConfig {
|
|
2
44
|
/** Same value `resolveBaseUrl` would otherwise read from package.json's `waygraph.baseUrl`. */
|
|
3
45
|
baseUrl?: string;
|
|
46
|
+
/** Chromium extensions to load in every run: `"hoppscotch"`, a Chrome Web Store id, or `{ path }` to an unpacked one. */
|
|
47
|
+
extensions?: ExtensionSpec[];
|
|
48
|
+
/** Recording with `--video` (`waygraph run` / `demo`); `run` and `demo` below can override it. */
|
|
49
|
+
video?: VideoSettings;
|
|
50
|
+
/** Default for `run` and `demo`: milliseconds to pause around each browser action, so a run is watchable. */
|
|
51
|
+
slowMo?: number;
|
|
52
|
+
/** Default for `run` and `demo`: show the browser window. Without it `demo` and `auto` are headed and `run` is headless. */
|
|
53
|
+
headed?: boolean;
|
|
54
|
+
/** Settings for `waygraph run` only. They override the shared ones above. */
|
|
55
|
+
run?: RunSettings;
|
|
56
|
+
/** Settings for `waygraph demo` only. They override the shared ones above. */
|
|
57
|
+
demo?: DemoSettings;
|
|
58
|
+
/** Folder of test files, relative to the project. Default `"tests"`. */
|
|
59
|
+
testDir?: string;
|
|
60
|
+
/** App to start around `waygraph test`, `run`, `demo` and `auto` (same fields as Playwright's `webServer`). */
|
|
61
|
+
webServer?: WebServerConfig | WebServerConfig[];
|
|
62
|
+
/** Anything else for the test runner, e.g. `workers`, `timeout`, `reporter`, `use: { video: "on" }`. Merged over waygraph's defaults. */
|
|
63
|
+
playwright?: PlaywrightTestConfig;
|
|
64
|
+
}
|
|
65
|
+
/** What a config function receives: the env mode and the environment with `.env` files already loaded. */
|
|
66
|
+
export interface ConfigContext {
|
|
67
|
+
mode: string;
|
|
68
|
+
env: Record<string, string | undefined>;
|
|
4
69
|
}
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
7
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Typed identity helper, like `defineConfig` in `vite.config.ts`. Pass an object, or a function when values come
|
|
72
|
+
* from `.env` files (`.env`, `.env.local`, `.env.<mode>`; pick the mode with `--env <mode>`):
|
|
73
|
+
* @example export default defineConfig(({ env }) => ({ baseUrl: env.BASE_URL }))
|
|
74
|
+
*/
|
|
75
|
+
export declare function defineConfig(config: WaygraphConfig | ((context: ConfigContext) => WaygraphConfig)): WaygraphConfig;
|
|
76
|
+
/** Removes `--config <file>` / `--config=<file>` from argv and records it as `WAYGRAPH_CONFIG`, so every command reads that config. */
|
|
77
|
+
export declare function takeConfigFlag(argv: string[]): string[];
|
|
8
78
|
/**
|
|
9
79
|
* Looks for the first `waygraph.config.*` in `projectDir` and imports it - `.ts` works
|
|
10
80
|
* unmodified because `bin/waygraph` already registers `tsx/esm` before `dist/cli.js` ever runs
|
|
@@ -32,3 +102,11 @@ export declare function loadWaygraphConfig(projectDir: string): Promise<Waygraph
|
|
|
32
102
|
* as a side effect, which resolving a URL string has no business doing).
|
|
33
103
|
*/
|
|
34
104
|
export declare function resolveBaseUrl(projectDir: string): Promise<string | undefined>;
|
|
105
|
+
/** Unpacked extension directories for a run: `WAYGRAPH_EXTENSIONS` if set, else the config file's `extensions` (fetched on first use). */
|
|
106
|
+
export declare function configuredExtensions(projectDir: string): Promise<string[]>;
|
|
107
|
+
/**
|
|
108
|
+
* Applies the config's run settings as the `WAYGRAPH_*` variables the runner reads, for the command being run
|
|
109
|
+
* (`WAYGRAPH_COMMAND`, set by the CLI). The `run` / `demo` section overrides the shared top-level values. A flag, a shell
|
|
110
|
+
* variable or a `.env` value that is already set always wins, so the config only supplies defaults.
|
|
111
|
+
*/
|
|
112
|
+
export declare function applyConfigEnv(config: WaygraphConfig | undefined, command?: string | undefined): void;
|
package/dist/config.js
CHANGED
|
@@ -3,21 +3,52 @@
|
|
|
3
3
|
// setting, for consumers who'd rather have a real typed file than a JSON field. Real ask: "I
|
|
4
4
|
// think its time to add waygraph config now."
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
-
import { join } from "node:path";
|
|
6
|
+
import { isAbsolute, join } from "node:path";
|
|
7
7
|
import { pathToFileURL } from "node:url";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { extensionPathsFromEnv } from "./browser.js";
|
|
9
|
+
import { envMode, loadEnvFiles } from "./env-file.js";
|
|
10
|
+
import { resolveExtensions } from "./extensions.js";
|
|
11
|
+
/**
|
|
12
|
+
* Typed identity helper, like `defineConfig` in `vite.config.ts`. Pass an object, or a function when values come
|
|
13
|
+
* from `.env` files (`.env`, `.env.local`, `.env.<mode>`; pick the mode with `--env <mode>`):
|
|
14
|
+
* @example export default defineConfig(({ env }) => ({ baseUrl: env.BASE_URL }))
|
|
15
|
+
*/
|
|
11
16
|
export function defineConfig(config) {
|
|
12
|
-
|
|
17
|
+
if (typeof config !== "function")
|
|
18
|
+
return config;
|
|
19
|
+
loadEnvFiles(process.cwd());
|
|
20
|
+
return config({ mode: envMode(), env: process.env });
|
|
21
|
+
}
|
|
22
|
+
const CONFIG_NAMES = ["waygraph.config.ts", "waygraph.config.mts", "waygraph.config.mjs", "waygraph.config.js", "waygraph.config.cjs"];
|
|
23
|
+
/** `config/` first, then the project root. */
|
|
24
|
+
const CONFIG_FILENAMES = [...CONFIG_NAMES.map((n) => join("config", n)), ...CONFIG_NAMES];
|
|
25
|
+
/**
|
|
26
|
+
* Which config file(s) to try. `--config <file>` / `WAYGRAPH_CONFIG` picks one: a path (`config/staging.ts`), or a short name
|
|
27
|
+
* (`staging` -> `config/waygraph.staging.config.ts`, also tried in the project root). Without it, `waygraph.config.*`.
|
|
28
|
+
*/
|
|
29
|
+
function configCandidates() {
|
|
30
|
+
const chosen = process.env.WAYGRAPH_CONFIG;
|
|
31
|
+
if (!chosen)
|
|
32
|
+
return CONFIG_FILENAMES;
|
|
33
|
+
if (/[\\/]/.test(chosen) || /\.[cm]?[jt]s$/.test(chosen))
|
|
34
|
+
return [chosen];
|
|
35
|
+
const names = ["ts", "mts", "mjs", "js", "cjs"].map((e) => `waygraph.${chosen}.config.${e}`);
|
|
36
|
+
return [...names.map((n) => join("config", n)), ...names, chosen];
|
|
37
|
+
}
|
|
38
|
+
/** Removes `--config <file>` / `--config=<file>` from argv and records it as `WAYGRAPH_CONFIG`, so every command reads that config. */
|
|
39
|
+
export function takeConfigFlag(argv) {
|
|
40
|
+
const out = [];
|
|
41
|
+
for (let i = 0; i < argv.length; i++) {
|
|
42
|
+
const a = argv[i];
|
|
43
|
+
if (a === "--config" && argv[i + 1] !== undefined)
|
|
44
|
+
process.env.WAYGRAPH_CONFIG = argv[++i];
|
|
45
|
+
else if (a.startsWith("--config="))
|
|
46
|
+
process.env.WAYGRAPH_CONFIG = a.slice("--config=".length);
|
|
47
|
+
else
|
|
48
|
+
out.push(a);
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
13
51
|
}
|
|
14
|
-
const CONFIG_FILENAMES = [
|
|
15
|
-
"waygraph.config.ts",
|
|
16
|
-
"waygraph.config.mts",
|
|
17
|
-
"waygraph.config.mjs",
|
|
18
|
-
"waygraph.config.js",
|
|
19
|
-
"waygraph.config.cjs",
|
|
20
|
-
];
|
|
21
52
|
/**
|
|
22
53
|
* Looks for the first `waygraph.config.*` in `projectDir` and imports it - `.ts` works
|
|
23
54
|
* unmodified because `bin/waygraph` already registers `tsx/esm` before `dist/cli.js` ever runs
|
|
@@ -27,10 +58,15 @@ const CONFIG_FILENAMES = [
|
|
|
27
58
|
* anything" instead of "your config file has a bug."
|
|
28
59
|
*/
|
|
29
60
|
export async function loadWaygraphConfig(projectDir) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
61
|
+
loadEnvFiles(projectDir);
|
|
62
|
+
for (const name of configCandidates()) {
|
|
63
|
+
const p = isAbsolute(name) ? name : join(projectDir, name);
|
|
64
|
+
if (!existsSync(p)) {
|
|
65
|
+
if (process.env.WAYGRAPH_CONFIG && name === process.env.WAYGRAPH_CONFIG) {
|
|
66
|
+
throw new Error(`waygraph: config "${process.env.WAYGRAPH_CONFIG}" not found (looked for ${p})`);
|
|
67
|
+
}
|
|
33
68
|
continue;
|
|
69
|
+
}
|
|
34
70
|
let mod;
|
|
35
71
|
try {
|
|
36
72
|
mod = (await import(pathToFileURL(p).href));
|
|
@@ -38,7 +74,9 @@ export async function loadWaygraphConfig(projectDir) {
|
|
|
38
74
|
catch (err) {
|
|
39
75
|
throw new Error(`waygraph: failed to load ${name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
40
76
|
}
|
|
41
|
-
|
|
77
|
+
const loaded = mod.default ?? mod;
|
|
78
|
+
applyConfigEnv(loaded);
|
|
79
|
+
return loaded;
|
|
42
80
|
}
|
|
43
81
|
return undefined;
|
|
44
82
|
}
|
|
@@ -92,3 +130,40 @@ export async function resolveBaseUrl(projectDir) {
|
|
|
92
130
|
}
|
|
93
131
|
return undefined;
|
|
94
132
|
}
|
|
133
|
+
/** Unpacked extension directories for a run: `WAYGRAPH_EXTENSIONS` if set, else the config file's `extensions` (fetched on first use). */
|
|
134
|
+
export async function configuredExtensions(projectDir) {
|
|
135
|
+
const fromEnv = extensionPathsFromEnv();
|
|
136
|
+
if (fromEnv.length > 0)
|
|
137
|
+
return fromEnv;
|
|
138
|
+
loadEnvFiles(projectDir);
|
|
139
|
+
return resolveExtensions((await loadWaygraphConfig(projectDir))?.extensions, projectDir);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Applies the config's run settings as the `WAYGRAPH_*` variables the runner reads, for the command being run
|
|
143
|
+
* (`WAYGRAPH_COMMAND`, set by the CLI). The `run` / `demo` section overrides the shared top-level values. A flag, a shell
|
|
144
|
+
* variable or a `.env` value that is already set always wins, so the config only supplies defaults.
|
|
145
|
+
*/
|
|
146
|
+
export function applyConfigEnv(config, command = process.env.WAYGRAPH_COMMAND) {
|
|
147
|
+
if (!config)
|
|
148
|
+
return;
|
|
149
|
+
const isDemo = command === "demo" || command === "try";
|
|
150
|
+
const section = isDemo ? config.demo : command === "run" ? config.run : undefined;
|
|
151
|
+
const set = (name, value) => {
|
|
152
|
+
if (value !== undefined && process.env[name] === undefined)
|
|
153
|
+
process.env[name] = value;
|
|
154
|
+
};
|
|
155
|
+
const flag = (b) => (b === undefined ? undefined : b ? "1" : "0");
|
|
156
|
+
const video = { ...config.video, ...section?.video };
|
|
157
|
+
const slowMo = section?.slowMo ?? config.slowMo;
|
|
158
|
+
set("WAYGRAPH_VIDEO_DIR", video.dir);
|
|
159
|
+
set("WAYGRAPH_VIDEO_VIEWPORT", video.viewport);
|
|
160
|
+
set("WAYGRAPH_SLOWMO", slowMo === undefined ? undefined : String(slowMo));
|
|
161
|
+
set("WAYGRAPH_HEADED", flag(section?.headed ?? config.headed));
|
|
162
|
+
if (isDemo) {
|
|
163
|
+
set("WAYGRAPH_AUTOPLAY", flag(config.demo?.autoNext));
|
|
164
|
+
set("WAYGRAPH_DEMO_FAST", config.demo?.fast ? "1" : undefined);
|
|
165
|
+
set("WAYGRAPH_DEMO_PACE", config.demo?.pace === undefined ? undefined : String(config.demo.pace));
|
|
166
|
+
set("WAYGRAPH_PACE_SPEEDS", config.demo?.speeds ? JSON.stringify(config.demo.speeds) : undefined);
|
|
167
|
+
set("WAYGRAPH_TYPING_MS", config.demo?.typingMs === undefined ? undefined : String(config.demo.typingMs));
|
|
168
|
+
}
|
|
169
|
+
}
|
package/dist/core/block.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ActionPage, Block, Checkpoint, DefinedBlock, Instruction } from "../types.js";
|
|
2
2
|
import { MemPage } from "../mem-page.js";
|
|
3
|
+
import type { MemKey } from "../mem-page.js";
|
|
3
4
|
import type { Trait } from "../trait.js";
|
|
4
5
|
export declare function findBlockIndex(middle: readonly Block<any, any>[], block: Block<any, any> | string | number): number;
|
|
5
6
|
/**
|
|
@@ -17,6 +18,8 @@ export declare function findBlockIndex(middle: readonly Block<any, any>[], block
|
|
|
17
18
|
export declare function branch<In extends Checkpoint<string>, Out extends Checkpoint<string>>(block: Block<In, Out>, routes: {
|
|
18
19
|
[K in Out["__state"]]: Block<Extract<Out, Checkpoint<K>>, any> | null;
|
|
19
20
|
}): DefinedBlock<In, any>;
|
|
21
|
+
/** Copy non-enumerable waygraph markers so decorate/withVerify keep map() kind checks. */
|
|
22
|
+
export declare function copyWaygraphRuntime(from: object, to: object): void;
|
|
20
23
|
/**
|
|
21
24
|
* Builds a Block with `withVerify`/`modVerify`/`modVerifyAll` attached as
|
|
22
25
|
* methods - `LoginBlock.withVerify([...])`, discoverable by typing
|
|
@@ -59,12 +62,26 @@ type StubPhaseFn<Out extends Checkpoint<string>> = import("../highlights.js").Hi
|
|
|
59
62
|
* Attach / chain a stubBefore lifecycle on a Block. Prefer
|
|
60
63
|
* `(ctx) => { ctx.ring(...); const x = ctx.mem?.get(Key); }`.
|
|
61
64
|
* @example FillUsernameBlock.stubBefore((ctx) => { ctx.ring("username", { ... }) })
|
|
65
|
+
* @deprecated Use the chained method: `Block.stubBefore((ctx) => …)`.
|
|
62
66
|
*/
|
|
63
67
|
export declare function withStubBefore<B extends Block<any, any>>(block: B, stub: StubPhaseFn<any>): B;
|
|
64
|
-
/** @see {@link withStubBefore}
|
|
68
|
+
/** @see {@link withStubBefore} * @deprecated Use the chained method: `Block.stubAfter((ctx) => …)`.
|
|
69
|
+
*/
|
|
65
70
|
export declare function withStubAfter<B extends Block<any, any>>(block: B, stub: StubPhaseFn<any>): B;
|
|
66
|
-
/** @see {@link withStubBefore}
|
|
71
|
+
/** @see {@link withStubBefore} * @deprecated Use the chained method: `Block.stubOnError((ctx) => …)`.
|
|
72
|
+
*/
|
|
67
73
|
export declare function withStubOnError<B extends Block<any, any>>(block: B, stub: StubPhaseFn<any>): B;
|
|
74
|
+
/**
|
|
75
|
+
* Answers the browser's own dialog (`confirm`, `alert`, `prompt`, `beforeunload`) that this Block's action
|
|
76
|
+
* triggers. A dialog freezes the page until it is answered, so the answer has to be armed before the click -
|
|
77
|
+
* this does that without folding it into the Block's own `act`. The dialog's text can be kept in mem.
|
|
78
|
+
* @example withDialog(CancelBlock, { accept: true, into: LeaveWarning })
|
|
79
|
+
*/
|
|
80
|
+
export declare function withDialog<B extends Block<any, any>>(block: B, options?: {
|
|
81
|
+
accept?: boolean;
|
|
82
|
+
into?: MemKey<string>;
|
|
83
|
+
promptText?: string;
|
|
84
|
+
}): B;
|
|
68
85
|
/**
|
|
69
86
|
* Replaces one Trait inside `block`'s verify list, leaving every other check
|
|
70
87
|
* untouched - the v1/v2/legacy-variant case, where one check needs a different
|
package/dist/core/block.js
CHANGED
|
@@ -75,12 +75,13 @@ function stripMethods(block) {
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
/** Copy non-enumerable waygraph markers so decorate/withVerify keep map() kind checks. */
|
|
78
|
-
function copyWaygraphRuntime(from, to) {
|
|
78
|
+
export function copyWaygraphRuntime(from, to) {
|
|
79
79
|
for (const key of [
|
|
80
80
|
"__waygraphKind",
|
|
81
81
|
"__waygraphSalt",
|
|
82
82
|
"__waygraphNavUrl",
|
|
83
83
|
"__waygraphNavClick",
|
|
84
|
+
"__waygraphNavFrom",
|
|
84
85
|
]) {
|
|
85
86
|
const desc = Object.getOwnPropertyDescriptor(from, key);
|
|
86
87
|
if (!desc)
|
|
@@ -201,18 +202,57 @@ function withStubPhase(block, phase, stub) {
|
|
|
201
202
|
* Attach / chain a stubBefore lifecycle on a Block. Prefer
|
|
202
203
|
* `(ctx) => { ctx.ring(...); const x = ctx.mem?.get(Key); }`.
|
|
203
204
|
* @example FillUsernameBlock.stubBefore((ctx) => { ctx.ring("username", { ... }) })
|
|
205
|
+
* @deprecated Use the chained method: `Block.stubBefore((ctx) => …)`.
|
|
204
206
|
*/
|
|
205
207
|
export function withStubBefore(block, stub) {
|
|
206
208
|
return withStubPhase(block, "stubBefore", stub);
|
|
207
209
|
}
|
|
208
|
-
/** @see {@link withStubBefore}
|
|
210
|
+
/** @see {@link withStubBefore} * @deprecated Use the chained method: `Block.stubAfter((ctx) => …)`.
|
|
211
|
+
*/
|
|
209
212
|
export function withStubAfter(block, stub) {
|
|
210
213
|
return withStubPhase(block, "stubAfter", stub);
|
|
211
214
|
}
|
|
212
|
-
/** @see {@link withStubBefore}
|
|
215
|
+
/** @see {@link withStubBefore} * @deprecated Use the chained method: `Block.stubOnError((ctx) => …)`.
|
|
216
|
+
*/
|
|
213
217
|
export function withStubOnError(block, stub) {
|
|
214
218
|
return withStubPhase(block, "stubOnError", stub);
|
|
215
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Answers the browser's own dialog (`confirm`, `alert`, `prompt`, `beforeunload`) that this Block's action
|
|
222
|
+
* triggers. A dialog freezes the page until it is answered, so the answer has to be armed before the click -
|
|
223
|
+
* this does that without folding it into the Block's own `act`. The dialog's text can be kept in mem.
|
|
224
|
+
* @example withDialog(CancelBlock, { accept: true, into: LeaveWarning })
|
|
225
|
+
*/
|
|
226
|
+
export function withDialog(block, options = {}) {
|
|
227
|
+
const base = stripMethods(block);
|
|
228
|
+
const act = base.instruction.act.bind(base.instruction);
|
|
229
|
+
const next = defineBlock({
|
|
230
|
+
...base,
|
|
231
|
+
instruction: {
|
|
232
|
+
...base.instruction,
|
|
233
|
+
async act(page, input, mem) {
|
|
234
|
+
const answer = async (dialog) => {
|
|
235
|
+
if (options.into)
|
|
236
|
+
mem.set(options.into, dialog.message());
|
|
237
|
+
if (options.accept === false)
|
|
238
|
+
await dialog.dismiss();
|
|
239
|
+
else
|
|
240
|
+
await dialog.accept(options.promptText);
|
|
241
|
+
};
|
|
242
|
+
const raw = page;
|
|
243
|
+
raw.once("dialog", answer);
|
|
244
|
+
try {
|
|
245
|
+
await act(page, input, mem);
|
|
246
|
+
}
|
|
247
|
+
finally {
|
|
248
|
+
raw.off("dialog", answer);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
copyWaygraphRuntime(block, next);
|
|
254
|
+
return next;
|
|
255
|
+
}
|
|
216
256
|
/**
|
|
217
257
|
* Replaces one Trait inside `block`'s verify list, leaving every other check
|
|
218
258
|
* untouched - the v1/v2/legacy-variant case, where one check needs a different
|
|
@@ -39,6 +39,15 @@ export type NavBlockOptions<Out extends Checkpoint<string>> = {
|
|
|
39
39
|
name: string;
|
|
40
40
|
description?: string;
|
|
41
41
|
checkpoint: Out["__state"];
|
|
42
|
+
/**
|
|
43
|
+
* Checkpoint tags this Nav can run from. Omit (the default) = reachable from anywhere. Set it for
|
|
44
|
+
* a page that only exists after something else - e.g. every in-app page after sign-in - so route
|
|
45
|
+
* finding (`auto --blocks`, `pilot reach`, `traverse`) goes through the sign-in steps instead of
|
|
46
|
+
* jumping straight there from the login page.
|
|
47
|
+
* @example const SIGNED_IN = ["Dashboard", "CommandCenter"] as const; // src/states/
|
|
48
|
+
* defineNavBlock({ ..., from: SIGNED_IN })
|
|
49
|
+
*/
|
|
50
|
+
from?: readonly string[];
|
|
42
51
|
requires?: readonly MemKey<any>[];
|
|
43
52
|
verify?: Trait[] | ((out: Out) => Trait[]);
|
|
44
53
|
stubBefore?: import("../../highlights.js").HighlightStubPhaseOrFn<Out>;
|
|
@@ -103,6 +112,8 @@ export type NavClickBlockOptions<Out extends Checkpoint<string>> = {
|
|
|
103
112
|
description?: string;
|
|
104
113
|
checkpoint: Out["__state"];
|
|
105
114
|
click: string | ((mem: MemPage) => string);
|
|
115
|
+
/** See {@link NavBlockOptions.from}. */
|
|
116
|
+
from?: readonly string[];
|
|
106
117
|
requires?: readonly MemKey<any>[];
|
|
107
118
|
verify?: Trait[] | ((out: Out) => Trait[]);
|
|
108
119
|
stubBefore?: import("../../highlights.js").HighlightStubPhaseOrFn<Out>;
|
package/dist/core/blocks/nav.js
CHANGED
|
@@ -54,6 +54,13 @@ export function defineNavBlock(options) {
|
|
|
54
54
|
});
|
|
55
55
|
// Demo/step tooling: remember the click selector (or factory) so
|
|
56
56
|
// overlays can label "nav click" without re-parsing source.
|
|
57
|
+
if (options.from && options.from.length > 0) {
|
|
58
|
+
Object.defineProperty(built, "__waygraphNavFrom", {
|
|
59
|
+
value: [...options.from],
|
|
60
|
+
enumerable: false,
|
|
61
|
+
configurable: false,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
57
64
|
if (options.click !== undefined) {
|
|
58
65
|
Object.defineProperty(built, "__waygraphNavClick", {
|
|
59
66
|
value: options.click,
|
|
@@ -83,6 +90,7 @@ export function defineNavClickBlock(options) {
|
|
|
83
90
|
name: options.name,
|
|
84
91
|
checkpoint: options.checkpoint,
|
|
85
92
|
click: options.click,
|
|
93
|
+
...(options.from ? { from: options.from } : {}),
|
|
86
94
|
...(options.description ? { description: options.description } : {}),
|
|
87
95
|
...(options.requires ? { requires: options.requires } : {}),
|
|
88
96
|
...(options.verify ? { verify: options.verify } : {}),
|
package/dist/core/config.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BrowserType } from "@playwright/test";
|
|
2
2
|
import type { Layout } from "./run-graph.js";
|
|
3
|
+
import type { ExtensionSpec } from "../extensions.js";
|
|
3
4
|
/**
|
|
4
5
|
* Resolves which `BrowserType` actually launches for a `mem`-only run (no
|
|
5
6
|
* caller-supplied context) - `config.browsers[browserName]` if given,
|
|
@@ -52,4 +53,8 @@ export interface EngineConfig {
|
|
|
52
53
|
* @example new Engine({ layouts: [AppShellLayout] })
|
|
53
54
|
*/
|
|
54
55
|
layouts?: readonly Layout[];
|
|
56
|
+
/** Chromium extensions to load: names, store ids or paths (see `extensions` in `waygraph.config.ts`). Default `WAYGRAPH_EXTENSIONS`. */
|
|
57
|
+
extensions?: readonly ExtensionSpec[];
|
|
58
|
+
/** Resolves relative `url`s in Nav Blocks when the Engine launches its own browser. Default `WAYGRAPH_BASE_URL`. */
|
|
59
|
+
baseUrl?: string;
|
|
55
60
|
}
|