walkwright 0.0.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.
- package/LICENSE +21 -0
- package/README.md +276 -0
- package/bin/walkwright.js +3 -0
- package/build/aria.d.ts +92 -0
- package/build/aria.js +215 -0
- package/build/aria.js.map +1 -0
- package/build/browser.d.ts +3 -0
- package/build/browser.js +18 -0
- package/build/browser.js.map +1 -0
- package/build/chunk-5CHKYNP7.js +507 -0
- package/build/chunk-5CHKYNP7.js.map +1 -0
- package/build/chunk-6YRKPGUO.js +1197 -0
- package/build/chunk-6YRKPGUO.js.map +1 -0
- package/build/chunk-A452S7R3.js +35 -0
- package/build/chunk-A452S7R3.js.map +1 -0
- package/build/chunk-BODO6HIH.js +60 -0
- package/build/chunk-BODO6HIH.js.map +1 -0
- package/build/chunk-FJI2CMCE.js +439 -0
- package/build/chunk-FJI2CMCE.js.map +1 -0
- package/build/chunk-JYHZVRB2.js +80 -0
- package/build/chunk-JYHZVRB2.js.map +1 -0
- package/build/chunk-KQN5IYN6.js +97 -0
- package/build/chunk-KQN5IYN6.js.map +1 -0
- package/build/chunk-KTXNERHT.js +72 -0
- package/build/chunk-KTXNERHT.js.map +1 -0
- package/build/chunk-MFTC7XL2.js +141 -0
- package/build/chunk-MFTC7XL2.js.map +1 -0
- package/build/chunk-N4SSLHMP.js +108 -0
- package/build/chunk-N4SSLHMP.js.map +1 -0
- package/build/chunk-RNNW7OW2.js +270 -0
- package/build/chunk-RNNW7OW2.js.map +1 -0
- package/build/chunk-UAWBPTDW.js +51 -0
- package/build/chunk-UAWBPTDW.js.map +1 -0
- package/build/chunk-Z7CW5CAY.js +64 -0
- package/build/chunk-Z7CW5CAY.js.map +1 -0
- package/build/cli.d.ts +1 -0
- package/build/cli.js +253 -0
- package/build/cli.js.map +1 -0
- package/build/config.d.ts +13 -0
- package/build/config.js +15 -0
- package/build/config.js.map +1 -0
- package/build/descriptor.d.ts +96 -0
- package/build/descriptor.js +27 -0
- package/build/descriptor.js.map +1 -0
- package/build/device-auth.d.ts +6 -0
- package/build/device-auth.js +11 -0
- package/build/device-auth.js.map +1 -0
- package/build/locator.d.ts +140 -0
- package/build/locator.js +92 -0
- package/build/locator.js.map +1 -0
- package/build/paths.d.ts +11 -0
- package/build/paths.js +22 -0
- package/build/paths.js.map +1 -0
- package/build/pom-kcSMxwX2.d.ts +349 -0
- package/build/pom.d.ts +6 -0
- package/build/pom.js +37 -0
- package/build/pom.js.map +1 -0
- package/build/project.d.ts +13 -0
- package/build/project.js +19 -0
- package/build/project.js.map +1 -0
- package/build/provisioner.d.ts +34 -0
- package/build/provisioner.js +14 -0
- package/build/provisioner.js.map +1 -0
- package/build/recorder.d.ts +6 -0
- package/build/recorder.js +15 -0
- package/build/recorder.js.map +1 -0
- package/build/reporter.d.ts +16 -0
- package/build/reporter.js +426 -0
- package/build/reporter.js.map +1 -0
- package/build/schema.d.ts +49 -0
- package/build/schema.js +16 -0
- package/build/schema.js.map +1 -0
- package/build/storage-state.d.ts +22 -0
- package/build/storage-state.js +42 -0
- package/build/storage-state.js.map +1 -0
- package/build/store.d.ts +17 -0
- package/build/store.js +9 -0
- package/build/store.js.map +1 -0
- package/build/ui.d.ts +49 -0
- package/build/ui.js +56 -0
- package/build/ui.js.map +1 -0
- package/build/upload.d.ts +10 -0
- package/build/upload.js +8 -0
- package/build/upload.js.map +1 -0
- package/build/wait.d.ts +14 -0
- package/build/wait.js +50 -0
- package/build/wait.js.map +1 -0
- package/package.json +52 -0
- package/src/aria.ts +326 -0
- package/src/browser.ts +15 -0
- package/src/cli.ts +295 -0
- package/src/config.ts +16 -0
- package/src/descriptor.ts +179 -0
- package/src/device-auth.ts +188 -0
- package/src/locator.ts +683 -0
- package/src/paths.ts +70 -0
- package/src/pom.ts +2363 -0
- package/src/project.ts +77 -0
- package/src/provisioner.ts +183 -0
- package/src/recorder.ts +877 -0
- package/src/reporter.ts +561 -0
- package/src/schema.ts +37 -0
- package/src/storage-state.ts +71 -0
- package/src/store.ts +96 -0
- package/src/ui.ts +333 -0
- package/src/upload.ts +116 -0
- package/src/wait.ts +63 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createStore
|
|
3
|
+
} from "./chunk-KTXNERHT.js";
|
|
4
|
+
|
|
5
|
+
// src/provisioner.ts
|
|
6
|
+
function createProvision(name, create, dispose) {
|
|
7
|
+
return {
|
|
8
|
+
name,
|
|
9
|
+
create,
|
|
10
|
+
...dispose === void 0 ? {} : { dispose }
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function createPersistentProvision(name, schema, create, dispose) {
|
|
14
|
+
return {
|
|
15
|
+
name,
|
|
16
|
+
create,
|
|
17
|
+
schema,
|
|
18
|
+
...dispose === void 0 ? {} : { dispose }
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function createProvisioner(page, provisions) {
|
|
22
|
+
const disposals = [];
|
|
23
|
+
const named = /* @__PURE__ */ new Set();
|
|
24
|
+
for (const def of provisions) {
|
|
25
|
+
if (named.has(def.name)) {
|
|
26
|
+
throw new Error(`two provisions are both named "${def.name}"`);
|
|
27
|
+
}
|
|
28
|
+
named.add(def.name);
|
|
29
|
+
}
|
|
30
|
+
const pending = /* @__PURE__ */ new Map();
|
|
31
|
+
const rawUse = async (def, input) => {
|
|
32
|
+
if (def.schema === void 0) {
|
|
33
|
+
const result = await def.create(page, input, use);
|
|
34
|
+
if (def.dispose !== void 0) {
|
|
35
|
+
const dispose = def.dispose;
|
|
36
|
+
disposals.push(async () => {
|
|
37
|
+
await dispose(page, result);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
const schema = def.schema;
|
|
43
|
+
const cached = pending.get(def);
|
|
44
|
+
if (cached !== void 0) {
|
|
45
|
+
return await cached;
|
|
46
|
+
}
|
|
47
|
+
const promise = (async () => {
|
|
48
|
+
const store = createStore(def.name, { schema });
|
|
49
|
+
const cached2 = store.read();
|
|
50
|
+
if (cached2 !== void 0) {
|
|
51
|
+
return cached2;
|
|
52
|
+
}
|
|
53
|
+
const result = await def.create(page, input, use);
|
|
54
|
+
store.persist(result);
|
|
55
|
+
return result;
|
|
56
|
+
})();
|
|
57
|
+
pending.set(def, promise);
|
|
58
|
+
return await promise;
|
|
59
|
+
};
|
|
60
|
+
const use = (async (def, ...input) => await rawUse(def, input[0]));
|
|
61
|
+
const provision = {};
|
|
62
|
+
for (const def of provisions) {
|
|
63
|
+
provision[def.name] = async (...input) => await rawUse(def, input[0]);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
provision,
|
|
67
|
+
[Symbol.asyncDispose]: async () => {
|
|
68
|
+
await disposeAll(disposals);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async function disposeAll(disposals) {
|
|
73
|
+
const failures = [];
|
|
74
|
+
for (const dispose of [...disposals].reverse()) {
|
|
75
|
+
try {
|
|
76
|
+
await dispose();
|
|
77
|
+
} catch (error) {
|
|
78
|
+
failures.push(error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
disposals.length = 0;
|
|
82
|
+
if (failures.length > 0) {
|
|
83
|
+
throw new AggregateError(
|
|
84
|
+
failures,
|
|
85
|
+
`provisioner clean-up failed: ${failures.map(
|
|
86
|
+
(failure) => failure instanceof Error ? failure.message.split("\n")[0] : String(failure)
|
|
87
|
+
).join("; ")}`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export {
|
|
93
|
+
createProvision,
|
|
94
|
+
createPersistentProvision,
|
|
95
|
+
createProvisioner
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=chunk-KQN5IYN6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/provisioner.ts"],"sourcesContent":["import type { Page } from \"@playwright/test\";\nimport type { z } from \"zod\";\n\nimport { createStore } from \"./store.js\";\n\nexport type Use = <D extends AnyProvision>(\n provision: D,\n ...input: ProvisionArgs<InputOf<D>>\n) => Promise<ResultOf<D>>;\n\nexport interface Provision<Name extends string, Input, Result> {\n name: Name;\n create: (page: Page, input: Input, use: Use) => Promise<Result>;\n dispose?: (page: Page, result: Result) => Promise<void>;\n schema?: z.ZodType<Result>;\n}\n\nexport interface AnyProvision {\n name: string;\n create: (page: Page, input: never, use: Use) => Promise<unknown>;\n dispose?: (page: Page, result: never) => Promise<void>;\n schema?: z.ZodType;\n}\n\nexport type InputOf<D extends AnyProvision> = D extends {\n create: (page: Page, input: infer Input, use: Use) => Promise<unknown>;\n}\n ? Input\n : never;\n\nexport type ResultOf<D extends AnyProvision> = D extends {\n create: (page: Page, input: never, use: Use) => Promise<infer Result>;\n}\n ? Result\n : never;\n\nexport function createProvision<Name extends string, Input, Result>(\n name: Name,\n create: (page: Page, input: Input, use: Use) => Promise<Result>,\n dispose?: (page: Page, result: Result) => Promise<void>,\n): Provision<Name, Input, Result> {\n return {\n name,\n create,\n ...(dispose === undefined ? {} : { dispose }),\n };\n}\n\nexport function createPersistentProvision<Name extends string, Input, Result>(\n name: Name,\n schema: z.ZodType<Result>,\n create: (page: Page, input: Input, use: Use) => Promise<Result>,\n dispose?: (page: Page, result: Result) => Promise<void>,\n): Provision<Name, Input, Result> {\n return {\n name,\n create,\n schema,\n ...(dispose === undefined ? {} : { dispose }),\n };\n}\n\nexport type ProvisionMap<Defs extends readonly AnyProvision[]> = {\n [D in Defs[number] as D[\"name\"]]: (\n ...input: ProvisionArgs<InputOf<D>>\n ) => Promise<ResultOf<D>>;\n};\n\nexport interface Provisioner<\n Defs extends readonly AnyProvision[],\n> extends AsyncDisposable {\n provision: ProvisionMap<Defs>;\n}\n\nexport function createProvisioner<Defs extends readonly AnyProvision[]>(\n page: Page,\n provisions: Defs,\n): Provisioner<Defs> {\n const disposals: Disposal[] = [];\n const named = new Set<string>();\n\n for (const def of provisions) {\n if (named.has(def.name)) {\n throw new Error(`two provisions are both named \"${def.name}\"`);\n }\n named.add(def.name);\n }\n\n const pending = new Map<AnyProvision, Promise<unknown>>();\n\n const rawUse = async (\n def: AnyProvision,\n input: unknown,\n ): Promise<unknown> => {\n if (def.schema === undefined) {\n const result = await def.create(page, input as never, use);\n\n if (def.dispose !== undefined) {\n const dispose = def.dispose;\n disposals.push(async (): Promise<void> => {\n await dispose(page, result as never);\n });\n }\n\n return result;\n }\n\n const schema = def.schema;\n const cached = pending.get(def);\n if (cached !== undefined) {\n return await cached;\n }\n\n const promise = (async (): Promise<unknown> => {\n const store = createStore<unknown>(def.name, { schema });\n const cached = store.read();\n\n if (cached !== undefined) {\n return cached;\n }\n\n const result = await def.create(page, input as never, use);\n store.persist(result);\n return result;\n })();\n\n pending.set(def, promise);\n return await promise;\n };\n\n const use = (async (\n def: AnyProvision,\n ...input: unknown[]\n ): Promise<unknown> => await rawUse(def, input[0])) as Use;\n\n const provision: Record<string, (...input: unknown[]) => Promise<unknown>> =\n {};\n\n for (const def of provisions) {\n provision[def.name] = async (...input: unknown[]): Promise<unknown> =>\n await rawUse(def, input[0]);\n }\n\n return {\n provision: provision as unknown as ProvisionMap<Defs>,\n [Symbol.asyncDispose]: async (): Promise<void> => {\n await disposeAll(disposals);\n },\n };\n}\n\ntype ProvisionArgs<Input> = undefined extends Input\n ? [input?: Input]\n : [input: Input];\n\ntype Disposal = () => Promise<void>;\n\nasync function disposeAll(disposals: Disposal[]): Promise<void> {\n const failures: unknown[] = [];\n\n for (const dispose of [...disposals].reverse()) {\n try {\n await dispose();\n } catch (error) {\n failures.push(error);\n }\n }\n\n disposals.length = 0;\n\n if (failures.length > 0) {\n throw new AggregateError(\n failures,\n `provisioner clean-up failed: ${failures\n .map((failure) =>\n failure instanceof Error\n ? failure.message.split(\"\\n\")[0]\n : String(failure),\n )\n .join(\"; \")}`,\n );\n }\n}\n"],"mappings":";;;;;AAoCO,SAAS,gBACd,MACA,QACA,SACgC;AAChC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAI,YAAY,SAAY,CAAC,IAAI,EAAE,QAAQ;AAAA,EAC7C;AACF;AAEO,SAAS,0BACd,MACA,QACA,QACA,SACgC;AAChC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,YAAY,SAAY,CAAC,IAAI,EAAE,QAAQ;AAAA,EAC7C;AACF;AAcO,SAAS,kBACd,MACA,YACmB;AACnB,QAAM,YAAwB,CAAC;AAC/B,QAAM,QAAQ,oBAAI,IAAY;AAE9B,aAAW,OAAO,YAAY;AAC5B,QAAI,MAAM,IAAI,IAAI,IAAI,GAAG;AACvB,YAAM,IAAI,MAAM,kCAAkC,IAAI,IAAI,GAAG;AAAA,IAC/D;AACA,UAAM,IAAI,IAAI,IAAI;AAAA,EACpB;AAEA,QAAM,UAAU,oBAAI,IAAoC;AAExD,QAAM,SAAS,OACb,KACA,UACqB;AACrB,QAAI,IAAI,WAAW,QAAW;AAC5B,YAAM,SAAS,MAAM,IAAI,OAAO,MAAM,OAAgB,GAAG;AAEzD,UAAI,IAAI,YAAY,QAAW;AAC7B,cAAM,UAAU,IAAI;AACpB,kBAAU,KAAK,YAA2B;AACxC,gBAAM,QAAQ,MAAM,MAAe;AAAA,QACrC,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,IAAI;AACnB,UAAM,SAAS,QAAQ,IAAI,GAAG;AAC9B,QAAI,WAAW,QAAW;AACxB,aAAO,MAAM;AAAA,IACf;AAEA,UAAM,WAAW,YAA8B;AAC7C,YAAM,QAAQ,YAAqB,IAAI,MAAM,EAAE,OAAO,CAAC;AACvD,YAAMA,UAAS,MAAM,KAAK;AAE1B,UAAIA,YAAW,QAAW;AACxB,eAAOA;AAAA,MACT;AAEA,YAAM,SAAS,MAAM,IAAI,OAAO,MAAM,OAAgB,GAAG;AACzD,YAAM,QAAQ,MAAM;AACpB,aAAO;AAAA,IACT,GAAG;AAEH,YAAQ,IAAI,KAAK,OAAO;AACxB,WAAO,MAAM;AAAA,EACf;AAEA,QAAM,OAAO,OACX,QACG,UACkB,MAAM,OAAO,KAAK,MAAM,CAAC,CAAC;AAEjD,QAAM,YACJ,CAAC;AAEH,aAAW,OAAO,YAAY;AAC5B,cAAU,IAAI,IAAI,IAAI,UAAU,UAC9B,MAAM,OAAO,KAAK,MAAM,CAAC,CAAC;AAAA,EAC9B;AAEA,SAAO;AAAA,IACL;AAAA,IACA,CAAC,OAAO,YAAY,GAAG,YAA2B;AAChD,YAAM,WAAW,SAAS;AAAA,IAC5B;AAAA,EACF;AACF;AAQA,eAAe,WAAW,WAAsC;AAC9D,QAAM,WAAsB,CAAC;AAE7B,aAAW,WAAW,CAAC,GAAG,SAAS,EAAE,QAAQ,GAAG;AAC9C,QAAI;AACF,YAAM,QAAQ;AAAA,IAChB,SAAS,OAAO;AACd,eAAS,KAAK,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,YAAU,SAAS;AAEnB,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,gCAAgC,SAC7B;AAAA,QAAI,CAAC,YACJ,mBAAmB,QACf,QAAQ,QAAQ,MAAM,IAAI,EAAE,CAAC,IAC7B,OAAO,OAAO;AAAA,MACpB,EACC,KAAK,IAAI,CAAC;AAAA,IACf;AAAA,EACF;AACF;","names":["cached"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ensureWalkwrightDir,
|
|
3
|
+
storeDir
|
|
4
|
+
} from "./chunk-BODO6HIH.js";
|
|
5
|
+
|
|
6
|
+
// src/store.ts
|
|
7
|
+
import {
|
|
8
|
+
existsSync,
|
|
9
|
+
mkdirSync,
|
|
10
|
+
readFileSync,
|
|
11
|
+
renameSync,
|
|
12
|
+
rmSync,
|
|
13
|
+
writeFileSync
|
|
14
|
+
} from "fs";
|
|
15
|
+
import { dirname, join } from "path";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
function createStore(name, { scope = "worker", schema } = {}) {
|
|
18
|
+
const path = () => join(storeDir(scope), `${name}.json`);
|
|
19
|
+
return {
|
|
20
|
+
get path() {
|
|
21
|
+
return path();
|
|
22
|
+
},
|
|
23
|
+
exists: () => existsSync(path()),
|
|
24
|
+
read: () => {
|
|
25
|
+
const file = path();
|
|
26
|
+
if (!existsSync(file)) {
|
|
27
|
+
return void 0;
|
|
28
|
+
}
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
32
|
+
} catch {
|
|
33
|
+
console.log(`${file} is not valid JSON \u2014 ignoring the cached ${name}`);
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
37
|
+
console.log(`${file} is not a ${name} \u2014 ignoring the cached ${name}`);
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
if (schema === void 0) {
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
43
|
+
const decoded = z.safeDecode(schema, parsed);
|
|
44
|
+
if (!decoded.success) {
|
|
45
|
+
console.log(
|
|
46
|
+
`${file} did not decode as a ${name} \u2014 ignoring the cached ${name}`
|
|
47
|
+
);
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
return decoded.data;
|
|
51
|
+
},
|
|
52
|
+
persist: (value) => {
|
|
53
|
+
ensureWalkwrightDir();
|
|
54
|
+
writeJson(path(), schema === void 0 ? value : z.encode(schema, value));
|
|
55
|
+
},
|
|
56
|
+
clear: () => {
|
|
57
|
+
rmSync(path(), { force: true });
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function writeJson(file, value) {
|
|
62
|
+
const temporary = `${file}.${String(process.pid)}.tmp`;
|
|
63
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
64
|
+
writeFileSync(temporary, `${JSON.stringify(value, null, 2)}
|
|
65
|
+
`, "utf8");
|
|
66
|
+
renameSync(temporary, file);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
createStore
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=chunk-KTXNERHT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/store.ts"],"sourcesContent":["import {\n existsSync,\n mkdirSync,\n readFileSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nimport { z } from \"zod\";\n\nimport type { StoreScope } from \"./paths.js\";\nimport { ensureWalkwrightDir, storeDir } from \"./paths.js\";\n\nexport interface StoreOptions<Value> {\n scope?: StoreScope;\n schema?: z.ZodType<Value>;\n}\n\nexport interface Store<Value> {\n readonly path: string;\n exists: () => boolean;\n read: () => Value | undefined;\n persist: (value: Value) => void;\n clear: () => void;\n}\n\nexport function createStore<Value>(\n name: string,\n { scope = \"worker\", schema }: StoreOptions<Value> = {},\n): Store<Value> {\n const path = (): string => join(storeDir(scope), `${name}.json`);\n\n return {\n get path(): string {\n return path();\n },\n\n exists: (): boolean => existsSync(path()),\n\n read: (): Value | undefined => {\n const file = path();\n\n if (!existsSync(file)) {\n return undefined;\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(readFileSync(file, \"utf8\"));\n } catch {\n console.log(`${file} is not valid JSON — ignoring the cached ${name}`);\n return undefined;\n }\n\n if (parsed === null || typeof parsed !== \"object\") {\n console.log(`${file} is not a ${name} — ignoring the cached ${name}`);\n return undefined;\n }\n\n if (schema === undefined) {\n return parsed as Value;\n }\n\n const decoded = z.safeDecode(schema, parsed);\n\n if (!decoded.success) {\n console.log(\n `${file} did not decode as a ${name} — ignoring the cached ${name}`,\n );\n return undefined;\n }\n\n return decoded.data;\n },\n\n persist: (value): void => {\n ensureWalkwrightDir();\n writeJson(path(), schema === undefined ? value : z.encode(schema, value));\n },\n\n clear: (): void => {\n rmSync(path(), { force: true });\n },\n };\n}\n\nfunction writeJson(file: string, value: unknown): void {\n const temporary = `${file}.${String(process.pid)}.tmp`;\n\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n renameSync(temporary, file);\n}\n"],"mappings":";;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS,YAAY;AAE9B,SAAS,SAAS;AAkBX,SAAS,YACd,MACA,EAAE,QAAQ,UAAU,OAAO,IAAyB,CAAC,GACvC;AACd,QAAM,OAAO,MAAc,KAAK,SAAS,KAAK,GAAG,GAAG,IAAI,OAAO;AAE/D,SAAO;AAAA,IACL,IAAI,OAAe;AACjB,aAAO,KAAK;AAAA,IACd;AAAA,IAEA,QAAQ,MAAe,WAAW,KAAK,CAAC;AAAA,IAExC,MAAM,MAAyB;AAC7B,YAAM,OAAO,KAAK;AAElB,UAAI,CAAC,WAAW,IAAI,GAAG;AACrB,eAAO;AAAA,MACT;AAEA,UAAI;AAEJ,UAAI;AACF,iBAAS,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;AAAA,MAChD,QAAQ;AACN,gBAAQ,IAAI,GAAG,IAAI,iDAA4C,IAAI,EAAE;AACrE,eAAO;AAAA,MACT;AAEA,UAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AACjD,gBAAQ,IAAI,GAAG,IAAI,aAAa,IAAI,+BAA0B,IAAI,EAAE;AACpE,eAAO;AAAA,MACT;AAEA,UAAI,WAAW,QAAW;AACxB,eAAO;AAAA,MACT;AAEA,YAAM,UAAU,EAAE,WAAW,QAAQ,MAAM;AAE3C,UAAI,CAAC,QAAQ,SAAS;AACpB,gBAAQ;AAAA,UACN,GAAG,IAAI,wBAAwB,IAAI,+BAA0B,IAAI;AAAA,QACnE;AACA,eAAO;AAAA,MACT;AAEA,aAAO,QAAQ;AAAA,IACjB;AAAA,IAEA,SAAS,CAAC,UAAgB;AACxB,0BAAoB;AACpB,gBAAU,KAAK,GAAG,WAAW,SAAY,QAAQ,EAAE,OAAO,QAAQ,KAAK,CAAC;AAAA,IAC1E;AAAA,IAEA,OAAO,MAAY;AACjB,aAAO,KAAK,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,IAChC;AAAA,EACF;AACF;AAEA,SAAS,UAAU,MAAc,OAAsB;AACrD,QAAM,YAAY,GAAG,IAAI,IAAI,OAAO,QAAQ,GAAG,CAAC;AAEhD,YAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,gBAAc,WAAW,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AACtE,aAAW,WAAW,IAAI;AAC5B;","names":[]}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {
|
|
2
|
+
blank,
|
|
3
|
+
bold,
|
|
4
|
+
glyph,
|
|
5
|
+
line,
|
|
6
|
+
paint,
|
|
7
|
+
prompt,
|
|
8
|
+
pulse
|
|
9
|
+
} from "./chunk-RNNW7OW2.js";
|
|
10
|
+
|
|
11
|
+
// src/device-auth.ts
|
|
12
|
+
import { execFileSync } from "child_process";
|
|
13
|
+
var clientId = "walk-cli";
|
|
14
|
+
async function login(baseUrl) {
|
|
15
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
16
|
+
const code = await postJson(`${base}/api/auth/device/code`, {
|
|
17
|
+
client_id: clientId
|
|
18
|
+
});
|
|
19
|
+
blank();
|
|
20
|
+
line(
|
|
21
|
+
prompt(
|
|
22
|
+
`open ${paint("code", code.verification_uri)} and enter ${bold(paint("accent", code.user_code))}`
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
openBrowser(code.verification_uri_complete);
|
|
26
|
+
const stop = pulse(paint("dim", " waiting for approval"));
|
|
27
|
+
let token;
|
|
28
|
+
try {
|
|
29
|
+
token = await poll(base, code);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
stop();
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
stop();
|
|
35
|
+
line(paint("ok", glyph.ok), ` approved${await approvedAs(base, token)}`);
|
|
36
|
+
return token;
|
|
37
|
+
}
|
|
38
|
+
async function approvedAs(base, token) {
|
|
39
|
+
try {
|
|
40
|
+
const response = await fetch(`${base}/api/auth/get-session`, {
|
|
41
|
+
headers: { authorization: `Bearer ${token}` }
|
|
42
|
+
});
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
const body = await response.json();
|
|
47
|
+
const name = body?.user?.name;
|
|
48
|
+
return name === void 0 || name === "" ? "" : ` as ${bold(name)}`;
|
|
49
|
+
} catch {
|
|
50
|
+
return "";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function poll(base, code) {
|
|
54
|
+
const deadline = Date.now() + code.expires_in * 1e3;
|
|
55
|
+
let intervalMs = Math.max(1, code.interval) * 1e3;
|
|
56
|
+
while (Date.now() < deadline) {
|
|
57
|
+
await sleep(intervalMs);
|
|
58
|
+
const response = await fetch(`${base}/api/auth/device/token`, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: { "content-type": "application/json" },
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
63
|
+
device_code: code.device_code,
|
|
64
|
+
client_id: clientId
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
const body = await response.json();
|
|
68
|
+
if (response.ok) {
|
|
69
|
+
const token = body.session?.token ?? body.access_token;
|
|
70
|
+
if (token === void 0) {
|
|
71
|
+
throw new Error("device login succeeded but returned no session token");
|
|
72
|
+
}
|
|
73
|
+
return token;
|
|
74
|
+
}
|
|
75
|
+
if (body.error === "authorization_pending") {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (body.error === "slow_down") {
|
|
79
|
+
intervalMs += 1e3;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
throw new Error(
|
|
83
|
+
body.error === "expired_token" || body.error === "access_denied" ? "that didn't work \u2014 the code may have expired. run walkwright login again." : `that didn't work \u2014 ${body.error ?? String(response.status)}. run walkwright login again.`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
throw new Error(
|
|
87
|
+
"that didn't work \u2014 the code expired. run walkwright login again."
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
async function ensureProject(baseUrl, sessionToken, name) {
|
|
91
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
92
|
+
const response = await fetch(`${base}/api/projects/ensure`, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: {
|
|
95
|
+
"content-type": "application/json",
|
|
96
|
+
authorization: `Bearer ${sessionToken}`
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify({ name })
|
|
99
|
+
});
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`project setup failed \u2014 ${String(response.status)} from ${base}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
return await response.json();
|
|
106
|
+
}
|
|
107
|
+
async function postJson(url, payload) {
|
|
108
|
+
let response;
|
|
109
|
+
try {
|
|
110
|
+
response = await fetch(url, {
|
|
111
|
+
method: "POST",
|
|
112
|
+
headers: { "content-type": "application/json" },
|
|
113
|
+
body: JSON.stringify(payload)
|
|
114
|
+
});
|
|
115
|
+
} catch {
|
|
116
|
+
throw new Error(`can't reach ${new URL(url).origin}`);
|
|
117
|
+
}
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
throw new Error(`${String(response.status)} from ${url}`);
|
|
120
|
+
}
|
|
121
|
+
return await response.json();
|
|
122
|
+
}
|
|
123
|
+
function openBrowser(url) {
|
|
124
|
+
const [command, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
125
|
+
try {
|
|
126
|
+
execFileSync(command, args, { stdio: "ignore" });
|
|
127
|
+
} catch {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function sleep(ms) {
|
|
132
|
+
await new Promise((resolve) => {
|
|
133
|
+
setTimeout(resolve, ms);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export {
|
|
138
|
+
login,
|
|
139
|
+
ensureProject
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=chunk-MFTC7XL2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/device-auth.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\n\nimport type { WalkwrightConfig } from \"./project.js\";\nimport { blank, bold, glyph, line, paint, prompt, pulse } from \"./ui.js\";\n\nconst clientId = \"walk-cli\";\n\ninterface DeviceCode {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\ninterface DeviceTokenResponse {\n error?: string;\n access_token?: string;\n session?: { token?: string };\n}\n\nexport async function login(baseUrl: string): Promise<string> {\n const base = baseUrl.replace(/\\/$/, \"\");\n\n const code = await postJson<DeviceCode>(`${base}/api/auth/device/code`, {\n client_id: clientId,\n });\n\n blank();\n line(\n prompt(\n `open ${paint(\"code\", code.verification_uri)} and enter ${bold(paint(\"accent\", code.user_code))}`,\n ),\n );\n openBrowser(code.verification_uri_complete);\n\n const stop = pulse(paint(\"dim\", \" waiting for approval\"));\n\n let token: string;\n\n try {\n token = await poll(base, code);\n } catch (error) {\n stop();\n throw error;\n }\n\n stop();\n line(paint(\"ok\", glyph.ok), ` approved${await approvedAs(base, token)}`);\n\n return token;\n}\n\nasync function approvedAs(base: string, token: string): Promise<string> {\n try {\n const response = await fetch(`${base}/api/auth/get-session`, {\n headers: { authorization: `Bearer ${token}` },\n });\n\n if (!response.ok) {\n return \"\";\n }\n\n const body = (await response.json()) as { user?: { name?: string } } | null;\n const name = body?.user?.name;\n\n return name === undefined || name === \"\" ? \"\" : ` as ${bold(name)}`;\n } catch {\n return \"\";\n }\n}\n\nasync function poll(base: string, code: DeviceCode): Promise<string> {\n const deadline = Date.now() + code.expires_in * 1000;\n let intervalMs = Math.max(1, code.interval) * 1000;\n\n while (Date.now() < deadline) {\n await sleep(intervalMs);\n\n const response = await fetch(`${base}/api/auth/device/token`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: code.device_code,\n client_id: clientId,\n }),\n });\n\n const body = (await response.json()) as DeviceTokenResponse;\n\n if (response.ok) {\n const token = body.session?.token ?? body.access_token;\n\n if (token === undefined) {\n throw new Error(\"device login succeeded but returned no session token\");\n }\n\n return token;\n }\n\n if (body.error === \"authorization_pending\") {\n continue;\n }\n\n if (body.error === \"slow_down\") {\n intervalMs += 1000;\n continue;\n }\n\n throw new Error(\n body.error === \"expired_token\" || body.error === \"access_denied\"\n ? \"that didn't work — the code may have expired. run walkwright login again.\"\n : `that didn't work — ${body.error ?? String(response.status)}. run walkwright login again.`,\n );\n }\n\n throw new Error(\n \"that didn't work — the code expired. run walkwright login again.\",\n );\n}\n\nexport async function ensureProject(\n baseUrl: string,\n sessionToken: string,\n name: string,\n): Promise<Pick<WalkwrightConfig, \"project\" | \"token\">> {\n const base = baseUrl.replace(/\\/$/, \"\");\n\n const response = await fetch(`${base}/api/projects/ensure`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${sessionToken}`,\n },\n body: JSON.stringify({ name }),\n });\n\n if (!response.ok) {\n throw new Error(\n `project setup failed — ${String(response.status)} from ${base}`,\n );\n }\n\n return (await response.json()) as Pick<WalkwrightConfig, \"project\" | \"token\">;\n}\n\nasync function postJson<Body>(url: string, payload: unknown): Promise<Body> {\n let response: Response;\n\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(payload),\n });\n } catch {\n throw new Error(`can't reach ${new URL(url).origin}`);\n }\n\n if (!response.ok) {\n throw new Error(`${String(response.status)} from ${url}`);\n }\n\n return (await response.json()) as Body;\n}\n\nfunction openBrowser(url: string): void {\n const [command, args] =\n process.platform === \"darwin\"\n ? [\"open\", [url]]\n : process.platform === \"win32\"\n ? [\"cmd\", [\"/c\", \"start\", \"\", url]]\n : [\"xdg-open\", [url]];\n\n try {\n execFileSync(command, args, { stdio: \"ignore\" });\n } catch {\n return;\n }\n}\n\nasync function sleep(ms: number): Promise<void> {\n await new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
locatorDescriptorSchema,
|
|
3
|
+
textSchema
|
|
4
|
+
} from "./chunk-FJI2CMCE.js";
|
|
5
|
+
|
|
6
|
+
// src/descriptor.ts
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
var paramDeclSchema = z.object({
|
|
9
|
+
name: z.string()
|
|
10
|
+
});
|
|
11
|
+
var opaqueImplSchema = z.object({
|
|
12
|
+
opaque: z.literal(true),
|
|
13
|
+
provenance: z.literal("hand")
|
|
14
|
+
});
|
|
15
|
+
var elementDescriptorSchema = z.lazy(
|
|
16
|
+
() => z.union([
|
|
17
|
+
z.object({
|
|
18
|
+
locator: locatorDescriptorSchema,
|
|
19
|
+
params: z.array(paramDeclSchema).optional()
|
|
20
|
+
}),
|
|
21
|
+
z.object({ surface: nestedSurfaceDescriptorSchema }),
|
|
22
|
+
z.object({
|
|
23
|
+
overlay: overlayDescriptorSchema,
|
|
24
|
+
open: opaqueImplSchema.optional()
|
|
25
|
+
}),
|
|
26
|
+
z.object({ opaque: z.literal(true), provenance: z.literal("hand") })
|
|
27
|
+
])
|
|
28
|
+
);
|
|
29
|
+
var actionDescriptorSchema = z.object({
|
|
30
|
+
name: z.string(),
|
|
31
|
+
impl: opaqueImplSchema
|
|
32
|
+
});
|
|
33
|
+
var regexDescriptorSchema = z.object({
|
|
34
|
+
pattern: z.string(),
|
|
35
|
+
flags: z.string().optional()
|
|
36
|
+
});
|
|
37
|
+
var captureRuleDescriptorSchema = z.union([
|
|
38
|
+
z.object({
|
|
39
|
+
element: z.array(z.string()),
|
|
40
|
+
text: z.string(),
|
|
41
|
+
match: regexDescriptorSchema.optional()
|
|
42
|
+
}),
|
|
43
|
+
z.object({ match: regexDescriptorSchema, text: z.string() })
|
|
44
|
+
]);
|
|
45
|
+
var captureDescriptorSchema = z.object({
|
|
46
|
+
rules: z.array(captureRuleDescriptorSchema)
|
|
47
|
+
});
|
|
48
|
+
var surfaceShape = {
|
|
49
|
+
elements: z.record(
|
|
50
|
+
z.string(),
|
|
51
|
+
z.lazy(() => elementDescriptorSchema)
|
|
52
|
+
),
|
|
53
|
+
actions: z.array(actionDescriptorSchema).optional(),
|
|
54
|
+
capture: captureDescriptorSchema.optional()
|
|
55
|
+
};
|
|
56
|
+
var nestedSurfaceDescriptorSchema = z.lazy(
|
|
57
|
+
() => z.object({
|
|
58
|
+
root: locatorDescriptorSchema.optional(),
|
|
59
|
+
...surfaceShape
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
var overlayDescriptorSchema = z.lazy(
|
|
63
|
+
() => z.object({
|
|
64
|
+
root: locatorDescriptorSchema,
|
|
65
|
+
name: textSchema.optional(),
|
|
66
|
+
recorder: z.object({ label: z.string() }),
|
|
67
|
+
close: z.object({
|
|
68
|
+
esc: z.boolean(),
|
|
69
|
+
button: locatorDescriptorSchema.optional()
|
|
70
|
+
}),
|
|
71
|
+
...surfaceShape
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
var readyDescriptorSchema = z.union([
|
|
75
|
+
z.object({ selector: z.string() }),
|
|
76
|
+
z.object({ opaque: z.literal(true) })
|
|
77
|
+
]);
|
|
78
|
+
var pageDescriptorSchema = z.object({
|
|
79
|
+
path: z.string(),
|
|
80
|
+
name: z.string(),
|
|
81
|
+
recorder: z.object({
|
|
82
|
+
group: z.array(z.string()).optional(),
|
|
83
|
+
label: z.string().optional()
|
|
84
|
+
}).optional(),
|
|
85
|
+
ready: readyDescriptorSchema.optional(),
|
|
86
|
+
header: textSchema.optional(),
|
|
87
|
+
anchor: z.union([locatorDescriptorSchema, z.object({ opaque: z.literal(true) })]).optional(),
|
|
88
|
+
...surfaceShape
|
|
89
|
+
});
|
|
90
|
+
var appDescriptorSchema = z.object({
|
|
91
|
+
ready: readyDescriptorSchema.optional(),
|
|
92
|
+
pages: z.array(pageDescriptorSchema),
|
|
93
|
+
capture: captureDescriptorSchema.optional()
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
paramDeclSchema,
|
|
98
|
+
elementDescriptorSchema,
|
|
99
|
+
actionDescriptorSchema,
|
|
100
|
+
regexDescriptorSchema,
|
|
101
|
+
captureRuleDescriptorSchema,
|
|
102
|
+
captureDescriptorSchema,
|
|
103
|
+
nestedSurfaceDescriptorSchema,
|
|
104
|
+
overlayDescriptorSchema,
|
|
105
|
+
pageDescriptorSchema,
|
|
106
|
+
appDescriptorSchema
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=chunk-N4SSLHMP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/descriptor.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport type { LocatorDescriptor, Text } from \"./locator.js\";\nimport { locatorDescriptorSchema, textSchema } from \"./locator.js\";\n\nexport interface ParamDecl {\n name: string;\n}\n\nexport const paramDeclSchema: z.ZodType<ParamDecl> = z.object({\n name: z.string(),\n});\n\nexport type ElementDescriptor =\n | { locator: LocatorDescriptor; params?: ParamDecl[] }\n | { surface: NestedSurfaceDescriptor }\n | { overlay: OverlayDescriptor; open?: OpaqueImpl }\n | { opaque: true; provenance: \"hand\" };\n\nexport interface OpaqueImpl {\n opaque: true;\n provenance: \"hand\";\n}\n\nconst opaqueImplSchema: z.ZodType<OpaqueImpl> = z.object({\n opaque: z.literal(true),\n provenance: z.literal(\"hand\"),\n});\n\nexport const elementDescriptorSchema: z.ZodType<ElementDescriptor> = z.lazy(\n () =>\n z.union([\n z.object({\n locator: locatorDescriptorSchema,\n params: z.array(paramDeclSchema).optional(),\n }),\n z.object({ surface: nestedSurfaceDescriptorSchema }),\n z.object({\n overlay: overlayDescriptorSchema,\n open: opaqueImplSchema.optional(),\n }),\n z.object({ opaque: z.literal(true), provenance: z.literal(\"hand\") }),\n ]),\n);\n\nexport interface ActionDescriptor {\n name: string;\n impl: OpaqueImpl;\n}\n\nexport const actionDescriptorSchema: z.ZodType<ActionDescriptor> = z.object({\n name: z.string(),\n impl: opaqueImplSchema,\n});\n\nexport interface RegexDescriptor {\n pattern: string;\n flags?: string;\n}\n\nexport const regexDescriptorSchema: z.ZodType<RegexDescriptor> = z.object({\n pattern: z.string(),\n flags: z.string().optional(),\n});\n\nexport type CaptureRuleDescriptor =\n | { element: string[]; text: string; match?: RegexDescriptor }\n | { match: RegexDescriptor; text: string };\n\nexport const captureRuleDescriptorSchema: z.ZodType<CaptureRuleDescriptor> =\n z.union([\n z.object({\n element: z.array(z.string()),\n text: z.string(),\n match: regexDescriptorSchema.optional(),\n }),\n z.object({ match: regexDescriptorSchema, text: z.string() }),\n ]);\n\nexport interface CaptureDescriptor {\n rules: CaptureRuleDescriptor[];\n}\n\nexport const captureDescriptorSchema: z.ZodType<CaptureDescriptor> = z.object({\n rules: z.array(captureRuleDescriptorSchema),\n});\n\nexport interface SurfaceDescriptor {\n elements: Record<string, ElementDescriptor>;\n actions?: ActionDescriptor[];\n capture?: CaptureDescriptor;\n}\n\nconst surfaceShape = {\n elements: z.record(\n z.string(),\n z.lazy((): z.ZodType<ElementDescriptor> => elementDescriptorSchema),\n ),\n actions: z.array(actionDescriptorSchema).optional(),\n capture: captureDescriptorSchema.optional(),\n};\n\nexport interface NestedSurfaceDescriptor extends SurfaceDescriptor {\n root?: LocatorDescriptor;\n}\n\nexport const nestedSurfaceDescriptorSchema: z.ZodType<NestedSurfaceDescriptor> =\n z.lazy(() =>\n z.object({\n root: locatorDescriptorSchema.optional(),\n ...surfaceShape,\n }),\n );\n\nexport interface OverlayDescriptor extends SurfaceDescriptor {\n root: LocatorDescriptor;\n name?: Text;\n recorder: { label: string };\n close: { esc: boolean; button?: LocatorDescriptor };\n}\n\nexport const overlayDescriptorSchema: z.ZodType<OverlayDescriptor> = z.lazy(\n () =>\n z.object({\n root: locatorDescriptorSchema,\n name: textSchema.optional(),\n recorder: z.object({ label: z.string() }),\n close: z.object({\n esc: z.boolean(),\n button: locatorDescriptorSchema.optional(),\n }),\n ...surfaceShape,\n }),\n);\n\nexport type ReadyDescriptor = { selector: string } | { opaque: true };\n\nconst readyDescriptorSchema: z.ZodType<ReadyDescriptor> = z.union([\n z.object({ selector: z.string() }),\n z.object({ opaque: z.literal(true) }),\n]);\n\nexport interface PageDescriptor extends SurfaceDescriptor {\n path: string;\n name: string;\n recorder?: { group?: string[]; label?: string };\n ready?: ReadyDescriptor;\n header?: Text;\n anchor?: LocatorDescriptor | { opaque: true };\n}\n\nexport const pageDescriptorSchema: z.ZodType<PageDescriptor> = z.object({\n path: z.string(),\n name: z.string(),\n recorder: z\n .object({\n group: z.array(z.string()).optional(),\n label: z.string().optional(),\n })\n .optional(),\n ready: readyDescriptorSchema.optional(),\n header: textSchema.optional(),\n anchor: z\n .union([locatorDescriptorSchema, z.object({ opaque: z.literal(true) })])\n .optional(),\n ...surfaceShape,\n});\n\nexport interface AppDescriptor {\n ready?: ReadyDescriptor;\n pages: PageDescriptor[];\n capture?: CaptureDescriptor;\n}\n\nexport const appDescriptorSchema: z.ZodType<AppDescriptor> = z.object({\n ready: readyDescriptorSchema.optional(),\n pages: z.array(pageDescriptorSchema),\n capture: captureDescriptorSchema.optional(),\n});\n"],"mappings":"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","names":[]}
|