craftdriver 1.3.0 → 1.5.0

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 (132) hide show
  1. package/CHANGELOG.md +17 -3
  2. package/README.md +4 -1
  3. package/dist/cli/dispatcher.js +1 -1
  4. package/dist/cli/dispatcher.js.map +1 -1
  5. package/dist/cli/parseArgs.d.ts +2 -2
  6. package/dist/cli/parseArgs.d.ts.map +1 -1
  7. package/dist/cli/parseArgs.js +1 -1
  8. package/dist/index.d.ts +7 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +5 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/lib/bidi/storage.d.ts +13 -0
  13. package/dist/lib/bidi/storage.d.ts.map +1 -1
  14. package/dist/lib/bidi/storage.js +81 -32
  15. package/dist/lib/bidi/storage.js.map +1 -1
  16. package/dist/lib/browser.d.ts +173 -21
  17. package/dist/lib/browser.d.ts.map +1 -1
  18. package/dist/lib/browser.js +519 -210
  19. package/dist/lib/browser.js.map +1 -1
  20. package/dist/lib/browserContext.d.ts +2 -2
  21. package/dist/lib/browserContext.d.ts.map +1 -1
  22. package/dist/lib/browserContext.js +1 -1
  23. package/dist/lib/builder.d.ts +4 -1
  24. package/dist/lib/builder.d.ts.map +1 -1
  25. package/dist/lib/builder.js +20 -2
  26. package/dist/lib/builder.js.map +1 -1
  27. package/dist/lib/capabilities.d.ts +45 -0
  28. package/dist/lib/capabilities.d.ts.map +1 -0
  29. package/dist/lib/capabilities.js +103 -0
  30. package/dist/lib/capabilities.js.map +1 -0
  31. package/dist/lib/chrome.d.ts +7 -2
  32. package/dist/lib/chrome.d.ts.map +1 -1
  33. package/dist/lib/chrome.js +10 -1
  34. package/dist/lib/chrome.js.map +1 -1
  35. package/dist/lib/driver.d.ts +16 -1
  36. package/dist/lib/driver.d.ts.map +1 -1
  37. package/dist/lib/driver.js +64 -0
  38. package/dist/lib/driver.js.map +1 -1
  39. package/dist/lib/driverManager.d.ts +120 -0
  40. package/dist/lib/driverManager.d.ts.map +1 -1
  41. package/dist/lib/driverManager.js +289 -10
  42. package/dist/lib/driverManager.js.map +1 -1
  43. package/dist/lib/electron.d.ts +60 -0
  44. package/dist/lib/electron.d.ts.map +1 -0
  45. package/dist/lib/electron.js +85 -0
  46. package/dist/lib/electron.js.map +1 -0
  47. package/dist/lib/electronDeeplink.d.ts +22 -0
  48. package/dist/lib/electronDeeplink.d.ts.map +1 -0
  49. package/dist/lib/electronDeeplink.js +118 -0
  50. package/dist/lib/electronDeeplink.js.map +1 -0
  51. package/dist/lib/electronDiagnostics.d.ts +49 -0
  52. package/dist/lib/electronDiagnostics.d.ts.map +1 -0
  53. package/dist/lib/electronDiagnostics.js +195 -0
  54. package/dist/lib/electronDiagnostics.js.map +1 -0
  55. package/dist/lib/electronDialogMock.d.ts +51 -0
  56. package/dist/lib/electronDialogMock.d.ts.map +1 -0
  57. package/dist/lib/electronDialogMock.js +106 -0
  58. package/dist/lib/electronDialogMock.js.map +1 -0
  59. package/dist/lib/electronFuses.d.ts +13 -0
  60. package/dist/lib/electronFuses.d.ts.map +1 -0
  61. package/dist/lib/electronFuses.js +118 -0
  62. package/dist/lib/electronFuses.js.map +1 -0
  63. package/dist/lib/electronMainBridge.d.ts +28 -0
  64. package/dist/lib/electronMainBridge.d.ts.map +1 -0
  65. package/dist/lib/electronMainBridge.js +270 -0
  66. package/dist/lib/electronMainBridge.js.map +1 -0
  67. package/dist/lib/electronMainLogs.d.ts +81 -0
  68. package/dist/lib/electronMainLogs.d.ts.map +1 -0
  69. package/dist/lib/electronMainLogs.js +176 -0
  70. package/dist/lib/electronMainLogs.js.map +1 -0
  71. package/dist/lib/electronMock.d.ts +52 -0
  72. package/dist/lib/electronMock.d.ts.map +1 -0
  73. package/dist/lib/electronMock.js +96 -0
  74. package/dist/lib/electronMock.js.map +1 -0
  75. package/dist/lib/electronRemote.d.ts +106 -0
  76. package/dist/lib/electronRemote.d.ts.map +1 -0
  77. package/dist/lib/electronRemote.js +406 -0
  78. package/dist/lib/electronRemote.js.map +1 -0
  79. package/dist/lib/electronVersions.d.ts +34 -0
  80. package/dist/lib/electronVersions.d.ts.map +1 -0
  81. package/dist/lib/electronVersions.js +90 -0
  82. package/dist/lib/electronVersions.js.map +1 -0
  83. package/dist/lib/errors.d.ts +27 -0
  84. package/dist/lib/errors.d.ts.map +1 -1
  85. package/dist/lib/errors.js +27 -0
  86. package/dist/lib/errors.js.map +1 -1
  87. package/dist/lib/launchTarget.d.ts +30 -0
  88. package/dist/lib/launchTarget.d.ts.map +1 -0
  89. package/dist/lib/launchTarget.js +174 -0
  90. package/dist/lib/launchTarget.js.map +1 -0
  91. package/dist/lib/page.d.ts +1 -0
  92. package/dist/lib/page.d.ts.map +1 -1
  93. package/dist/lib/page.js +1 -1
  94. package/dist/lib/page.js.map +1 -1
  95. package/dist/lib/safari.d.ts +90 -0
  96. package/dist/lib/safari.d.ts.map +1 -0
  97. package/dist/lib/safari.js +136 -0
  98. package/dist/lib/safari.js.map +1 -0
  99. package/dist/lib/service.d.ts +21 -0
  100. package/dist/lib/service.d.ts.map +1 -1
  101. package/dist/lib/service.js +94 -6
  102. package/dist/lib/service.js.map +1 -1
  103. package/dist/lib/tracing.d.ts +1 -1
  104. package/dist/lib/tracing.d.ts.map +1 -1
  105. package/dist/lib/tracing.js.map +1 -1
  106. package/dist/lib/types.d.ts +41 -0
  107. package/dist/lib/types.d.ts.map +1 -1
  108. package/dist/lib/vibiumTrace.d.ts +1 -1
  109. package/dist/lib/vibiumTrace.d.ts.map +1 -1
  110. package/dist/lib/webelement.d.ts.map +1 -1
  111. package/dist/lib/webelement.js +118 -2
  112. package/dist/lib/webelement.js.map +1 -1
  113. package/docs/api-reference.md +39 -2
  114. package/docs/browser-api.md +7 -1
  115. package/docs/driver-configuration.md +54 -0
  116. package/docs/electron.md +419 -0
  117. package/docs/error-codes.md +5 -0
  118. package/docs/getting-started.md +30 -10
  119. package/docs/index.md +5 -1
  120. package/docs/public/examples/displayed.html +86 -0
  121. package/docs/recipes/electron-app-from-another-repo.md +136 -0
  122. package/docs/recipes/electron-deep-link.md +117 -0
  123. package/docs/recipes/electron-mock-apis.md +88 -0
  124. package/docs/recipes/electron-native-dialog.md +105 -0
  125. package/docs/recipes.md +28 -9
  126. package/docs/safari.md +118 -0
  127. package/docs/standards.md +13 -0
  128. package/docs/why-craftdriver.md +1 -1
  129. package/docs/zero-config-drivers.md +12 -0
  130. package/package.json +7 -1
  131. package/skills/craftdriver/SKILL.md +4 -1
  132. package/skills/craftdriver/cheatsheet.md +4 -1
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Validate a deep-link URL: it must parse and use a custom scheme (not
3
+ * http/https/file). Returns the URL unchanged on success.
4
+ */
5
+ export declare function validateDeeplinkUrl(url: string): string;
6
+ /**
7
+ * Append (or overwrite) a `userData` query parameter carrying the running app's
8
+ * user-data dir. On Windows and Linux a fresh `open` would spawn a *second*
9
+ * instance; the app reads this parameter to point the second instance at the same
10
+ * user-data dir so the single-instance lock routes the URL to the test instance.
11
+ */
12
+ export declare function appendUserDataDir(url: string, userDataDir: string): string;
13
+ /** OS launcher command + args for a deep-link URL, per platform. */
14
+ export declare function getPlatformCommand(url: string, platform: NodeJS.Platform, appBinaryPath?: string): {
15
+ command: string;
16
+ args: string[];
17
+ };
18
+ /** Spawn the OS launcher detached (fire-and-forget); rejects only if the spawn itself fails. */
19
+ export declare function executeDeeplinkCommand(command: string, args: string[]): Promise<void>;
20
+ /** Resolve the final URL to hand to the OS launcher for the given platform. */
21
+ export declare function resolveDeeplinkUrl(url: string, platform: NodeJS.Platform, userDataDir?: string): string;
22
+ //# sourceMappingURL=electronDeeplink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electronDeeplink.d.ts","sourceRoot":"","sources":["../../src/lib/electronDeeplink.ts"],"names":[],"mappings":"AAeA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAsBvD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAI1E;AAED,oEAAoE;AACpE,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,aAAa,CAAC,EAAE,MAAM,GACrB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CA2BrC;AAcD,gGAAgG;AAChG,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCrF;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAQR"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Deep-link (custom protocol) triggering for Electron — the pure, testable logic
3
+ * behind `browser.electron.triggerDeeplink(url)`. It opens a `myapp://…` URL the
4
+ * way an external app would (macOS `open`, Linux `gio open`, Windows `rundll32`),
5
+ * so the running app's real `open-url` / `second-instance` handler fires.
6
+ *
7
+ * The OS launcher and platform routing are separated from the transport so they
8
+ * can be unit-tested without a live app (see tests/electron-deeplink.test.ts).
9
+ */
10
+ import { spawn } from 'node:child_process';
11
+ import { CraftdriverError, ErrorCode } from './errors.js';
12
+ /** Protocols that are *not* custom deep links — routing these would hit a browser/FS, not the app. */
13
+ const DISALLOWED_PROTOCOLS = new Set(['http:', 'https:', 'file:']);
14
+ /**
15
+ * Validate a deep-link URL: it must parse and use a custom scheme (not
16
+ * http/https/file). Returns the URL unchanged on success.
17
+ */
18
+ export function validateDeeplinkUrl(url) {
19
+ let parsed;
20
+ try {
21
+ parsed = new URL(url);
22
+ }
23
+ catch {
24
+ throw new CraftdriverError(ErrorCode.INVALID_ARGUMENT, `triggerDeeplink(url): "${url}" is not a valid URL.`, { hint: 'Pass a custom-protocol URL such as myapp://open?file=test.txt.' });
25
+ }
26
+ if (DISALLOWED_PROTOCOLS.has(parsed.protocol)) {
27
+ throw new CraftdriverError(ErrorCode.INVALID_ARGUMENT, `triggerDeeplink(url): "${parsed.protocol.slice(0, -1)}" is not a deep-link protocol.`, {
28
+ hint: 'Use your app’s registered custom protocol (e.g. myapp://), not http/https/file.',
29
+ detail: { protocol: parsed.protocol.slice(0, -1) },
30
+ });
31
+ }
32
+ return url;
33
+ }
34
+ /**
35
+ * Append (or overwrite) a `userData` query parameter carrying the running app's
36
+ * user-data dir. On Windows and Linux a fresh `open` would spawn a *second*
37
+ * instance; the app reads this parameter to point the second instance at the same
38
+ * user-data dir so the single-instance lock routes the URL to the test instance.
39
+ */
40
+ export function appendUserDataDir(url, userDataDir) {
41
+ const parsed = new URL(url);
42
+ parsed.searchParams.set('userData', userDataDir);
43
+ return parsed.toString();
44
+ }
45
+ /** OS launcher command + args for a deep-link URL, per platform. */
46
+ export function getPlatformCommand(url, platform, appBinaryPath) {
47
+ switch (platform) {
48
+ case 'darwin':
49
+ // `open` re-encodes the query when handing off to the protocol handler, so
50
+ // decode our appended query once to avoid double-encoding.
51
+ return { command: 'open', args: [decodeQueryOnce(url)] };
52
+ case 'linux':
53
+ return { command: 'gio', args: ['open', url] };
54
+ case 'win32':
55
+ if (!appBinaryPath) {
56
+ throw new CraftdriverError(ErrorCode.ELECTRON_DEEPLINK_FAILED, 'triggerDeeplink requires the app binary path on Windows to route the deep link.', {
57
+ hint: 'Launch via Browser.launch({ electron: { appBinaryPath } }) so the running instance is targeted.',
58
+ });
59
+ }
60
+ // rundll32's FileProtocolHandler avoids cmd.exe metacharacter interpretation (e.g. &).
61
+ return { command: 'rundll32.exe', args: ['url.dll,FileProtocolHandler', url] };
62
+ default:
63
+ throw new CraftdriverError(ErrorCode.ELECTRON_DEEPLINK_FAILED, `triggerDeeplink does not support platform "${platform}".`, { hint: 'Supported platforms are macOS (darwin), Linux, and Windows (win32).' });
64
+ }
65
+ }
66
+ /** Decode the query component once so `open` re-encodes it exactly once on hand-off. */
67
+ function decodeQueryOnce(url) {
68
+ const q = url.indexOf('?');
69
+ if (q === -1)
70
+ return url;
71
+ const base = url.slice(0, q);
72
+ try {
73
+ return `${base}?${decodeURIComponent(url.slice(q + 1))}`;
74
+ }
75
+ catch {
76
+ return url;
77
+ }
78
+ }
79
+ /** Spawn the OS launcher detached (fire-and-forget); rejects only if the spawn itself fails. */
80
+ export function executeDeeplinkCommand(command, args) {
81
+ return new Promise((resolve, reject) => {
82
+ let settled = false;
83
+ try {
84
+ const child = spawn(command, args, { detached: true, stdio: 'ignore' });
85
+ child.unref();
86
+ child.on('error', (error) => {
87
+ if (settled)
88
+ return;
89
+ settled = true;
90
+ reject(new CraftdriverError(ErrorCode.ELECTRON_DEEPLINK_FAILED, `Failed to run the deep-link launcher "${command}": ${error.message}`, { cause: error, detail: { command } }));
91
+ });
92
+ // The launcher exits quickly; resolve on next tick once no synchronous error fired.
93
+ process.nextTick(() => {
94
+ if (settled)
95
+ return;
96
+ settled = true;
97
+ resolve();
98
+ });
99
+ }
100
+ catch (error) {
101
+ if (settled)
102
+ return;
103
+ settled = true;
104
+ reject(new CraftdriverError(ErrorCode.ELECTRON_DEEPLINK_FAILED, `Failed to run the deep-link launcher "${command}": ${error instanceof Error ? error.message : String(error)}`, { cause: error, detail: { command } }));
105
+ }
106
+ });
107
+ }
108
+ /** Resolve the final URL to hand to the OS launcher for the given platform. */
109
+ export function resolveDeeplinkUrl(url, platform, userDataDir) {
110
+ const validated = validateDeeplinkUrl(url);
111
+ // Only Windows/Linux need the second-instance routing hint; macOS `open-url`
112
+ // reaches the running instance directly.
113
+ if ((platform === 'win32' || platform === 'linux') && userDataDir) {
114
+ return appendUserDataDir(validated, userDataDir);
115
+ }
116
+ return validated;
117
+ }
118
+ //# sourceMappingURL=electronDeeplink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electronDeeplink.js","sourceRoot":"","sources":["../../src/lib/electronDeeplink.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ export type BinaryArch = 'x64' | 'arm64';
2
+ /**
3
+ * Best-effort CPU arch of an executable, read from its Mach-O / ELF header
4
+ * (no child process). Returns `undefined` for a universal/fat binary (no single
5
+ * arch), a Windows PE (not parsed here), or anything unrecognized — callers then
6
+ * skip the arch check rather than guess.
7
+ */
8
+ export declare function readBinaryArch(filePath: string): BinaryArch | undefined;
9
+ /**
10
+ * Fail before spawning when the chromedriver's CPU arch can't match the runtime
11
+ * that has to exec it (e.g. an x64 electron-chromedriver on an arm64 host). A
12
+ * pure header read; skips silently when the arch can't be determined.
13
+ */
14
+ export declare function assertDriverArchCompatible(driverPath: string): void;
15
+ /**
16
+ * Fail before session creation when the resolved chromedriver's major doesn't
17
+ * match the Chromium the app's Electron version bundles — the exact mismatch
18
+ * that otherwise surfaces as an opaque "session not created" deep in startup.
19
+ * Only meaningful when the app's Electron version is known (explicit or detected)
20
+ * AND the driver reports a version; skips otherwise.
21
+ */
22
+ export declare function assertDriverChromiumMajorCompatible(driverPath: string, electronVersion: string): void;
23
+ export type MacSigningState = 'unsigned' | 'adhoc' | 'signed' | 'unknown';
24
+ /**
25
+ * Probe an app binary's code signature via `codesign -dv`. An unsigned or
26
+ * ad-hoc-signed app is what Gatekeeper/AMFI kills on locked-down macOS, which
27
+ * chromedriver reports only as "Chrome instance exited". macOS-only; returns
28
+ * `'unknown'` on any other platform or probe failure.
29
+ */
30
+ export declare function probeMacAppSigning(appBinaryPath: string): MacSigningState;
31
+ /** Heuristic: did session creation fail because the app process exited/crashed? */
32
+ export declare function isElectronInstanceExitedError(error: unknown): boolean;
33
+ export interface ElectronLaunchDiagnosticsInput {
34
+ appBinaryPath: string;
35
+ /** Chromium/app args passed at launch (checked for `--no-sandbox`). */
36
+ args?: string[];
37
+ /** Bounded chromedriver stdout/stderr tail, e.g. `ElectronService#getOutputTail()`. */
38
+ driverOutputTail?: string;
39
+ /** Override the host platform (tests exercise both branches on one host). */
40
+ platform?: NodeJS.Platform;
41
+ }
42
+ /**
43
+ * Enrich a session-creation failure on the Electron path with the diagnosed
44
+ * likely cause and the chromedriver output tail. Returns the original error
45
+ * unchanged when it isn't the app-exited class (so unrelated failures aren't
46
+ * mislabeled).
47
+ */
48
+ export declare function diagnoseElectronLaunchFailure(cause: unknown, input: ElectronLaunchDiagnosticsInput): unknown;
49
+ //# sourceMappingURL=electronDiagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electronDiagnostics.d.ts","sourceRoot":"","sources":["../../src/lib/electronDiagnostics.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,OAAO,CAAC;AAEzC;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAgCvE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAgBnE;AAED;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CACjD,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GACtB,IAAI,CA0BN;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE1E;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe,CAgBzE;AAED,mFAAmF;AACnF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASrE;AAED,MAAM,WAAW,8BAA8B;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAgDT"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Electron launch diagnostics: turn opaque "Chrome instance exited" / mismatched
3
+ * driver failures into actionable {@link CraftdriverError}s, either before the
4
+ * driver spawns (arch / Chromium-major mismatch) or when session creation dies
5
+ * (macOS signing/Gatekeeper, Linux sandbox). See docs/electron.md "Troubleshooting".
6
+ */
7
+ import fs from 'fs';
8
+ import os from 'os';
9
+ import { spawnSync } from 'child_process';
10
+ import { CraftdriverError, ErrorCode } from './errors.js';
11
+ import { chromiumMajorForElectron } from './electronVersions.js';
12
+ import { readChromeDriverVersion } from './driverManager.js';
13
+ import { PATH_PROBE_TIMEOUT_MS } from './timing.js';
14
+ /**
15
+ * Best-effort CPU arch of an executable, read from its Mach-O / ELF header
16
+ * (no child process). Returns `undefined` for a universal/fat binary (no single
17
+ * arch), a Windows PE (not parsed here), or anything unrecognized — callers then
18
+ * skip the arch check rather than guess.
19
+ */
20
+ export function readBinaryArch(filePath) {
21
+ let fd;
22
+ try {
23
+ fd = fs.openSync(filePath, 'r');
24
+ const buf = Buffer.alloc(20);
25
+ const read = fs.readSync(fd, buf, 0, 20, 0);
26
+ if (read < 20)
27
+ return undefined;
28
+ // Mach-O 64-bit, little-endian (MH_MAGIC_64 = 0xFEEDFACF on disk as CF FA ED FE).
29
+ if (buf.readUInt32LE(0) === 0xfeedfacf) {
30
+ const cpuType = buf.readInt32LE(4);
31
+ if (cpuType === 0x01000007)
32
+ return 'x64'; // CPU_TYPE_X86_64
33
+ if (cpuType === 0x0100000c)
34
+ return 'arm64'; // CPU_TYPE_ARM64
35
+ return undefined;
36
+ }
37
+ // Fat/universal (0xCAFEBABE, big-endian): multiple arches, no single answer.
38
+ if (buf.readUInt32BE(0) === 0xcafebabe)
39
+ return undefined;
40
+ // ELF: 0x7F 'E' 'L' 'F'.
41
+ if (buf[0] === 0x7f && buf[1] === 0x45 && buf[2] === 0x4c && buf[3] === 0x46) {
42
+ const littleEndian = buf[5] === 1; // EI_DATA: 1 = LE, 2 = BE
43
+ const machine = littleEndian ? buf.readUInt16LE(18) : buf.readUInt16BE(18);
44
+ if (machine === 0x3e)
45
+ return 'x64'; // EM_X86_64
46
+ if (machine === 0xb7)
47
+ return 'arm64'; // EM_AARCH64
48
+ return undefined;
49
+ }
50
+ return undefined;
51
+ }
52
+ catch {
53
+ return undefined;
54
+ }
55
+ finally {
56
+ if (fd !== undefined)
57
+ fs.closeSync(fd);
58
+ }
59
+ }
60
+ /**
61
+ * Fail before spawning when the chromedriver's CPU arch can't match the runtime
62
+ * that has to exec it (e.g. an x64 electron-chromedriver on an arm64 host). A
63
+ * pure header read; skips silently when the arch can't be determined.
64
+ */
65
+ export function assertDriverArchCompatible(driverPath) {
66
+ const driverArch = readBinaryArch(driverPath);
67
+ const runtimeArch = os.arch();
68
+ if (!driverArch || (runtimeArch !== 'x64' && runtimeArch !== 'arm64'))
69
+ return;
70
+ if (driverArch === runtimeArch)
71
+ return;
72
+ throw new CraftdriverError(ErrorCode.ELECTRON_DRIVER_MISMATCH, `The chromedriver at "${driverPath}" is ${driverArch}, but this process is ${runtimeArch} — ` +
73
+ 'it cannot launch and the Electron session would fail to start.', {
74
+ detail: { kind: 'arch', driverPath, driverArch, runtimeArch },
75
+ hint: `Install/point at a ${runtimeArch} chromedriver (electron-chromedriver for your arch, ` +
76
+ 'or let craftdriver download one via electron.version).',
77
+ });
78
+ }
79
+ /**
80
+ * Fail before session creation when the resolved chromedriver's major doesn't
81
+ * match the Chromium the app's Electron version bundles — the exact mismatch
82
+ * that otherwise surfaces as an opaque "session not created" deep in startup.
83
+ * Only meaningful when the app's Electron version is known (explicit or detected)
84
+ * AND the driver reports a version; skips otherwise.
85
+ */
86
+ export function assertDriverChromiumMajorCompatible(driverPath, electronVersion) {
87
+ const expectedMajor = chromiumMajorForElectron(electronVersion);
88
+ if (expectedMajor === undefined)
89
+ return; // unknown mapping — nothing to assert against
90
+ const driverVersion = readChromeDriverVersion(driverPath);
91
+ if (!driverVersion)
92
+ return; // couldn't read — let the real spawn surface any error
93
+ const driverMajor = Number.parseInt(driverVersion.split('.')[0], 10);
94
+ if (!Number.isFinite(driverMajor) || driverMajor === expectedMajor)
95
+ return;
96
+ throw new CraftdriverError(ErrorCode.ELECTRON_DRIVER_MISMATCH, `chromedriver ${driverVersion} (major ${driverMajor}) does not match Electron ` +
97
+ `${electronVersion}, which bundles Chromium ${expectedMajor} — the session would fail to start.`, {
98
+ detail: {
99
+ kind: 'chromium-major',
100
+ driverPath,
101
+ driverVersion,
102
+ driverMajor,
103
+ electronVersion,
104
+ expectedChromiumMajor: expectedMajor,
105
+ },
106
+ hint: `Use a chromedriver matching Chromium ${expectedMajor} (pin ` +
107
+ `electron-chromedriver@${electronVersion.split('.')[0]}, or set electron.version so ` +
108
+ 'craftdriver downloads the matching Chrome-for-Testing driver).',
109
+ });
110
+ }
111
+ /**
112
+ * Probe an app binary's code signature via `codesign -dv`. An unsigned or
113
+ * ad-hoc-signed app is what Gatekeeper/AMFI kills on locked-down macOS, which
114
+ * chromedriver reports only as "Chrome instance exited". macOS-only; returns
115
+ * `'unknown'` on any other platform or probe failure.
116
+ */
117
+ export function probeMacAppSigning(appBinaryPath) {
118
+ if (os.platform() !== 'darwin')
119
+ return 'unknown';
120
+ const result = spawnSync('codesign', ['-dv', appBinaryPath], {
121
+ encoding: 'utf8',
122
+ timeout: PATH_PROBE_TIMEOUT_MS,
123
+ stdio: ['ignore', 'pipe', 'pipe'],
124
+ });
125
+ if (result.error)
126
+ return 'unknown';
127
+ const output = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
128
+ if (/code object is not signed at all/i.test(output))
129
+ return 'unsigned';
130
+ // Ad-hoc shows up as `flags=0x2(adhoc)` and `Signature=adhoc`; check before the
131
+ // generic signed signal since ad-hoc binaries also carry a CodeDirectory.
132
+ if (/\badhoc\b/i.test(output))
133
+ return 'adhoc';
134
+ if (result.status === 0 && /(CodeDirectory|Signature size=|Authority=)/i.test(output))
135
+ return 'signed';
136
+ return 'unknown';
137
+ }
138
+ /** Heuristic: did session creation fail because the app process exited/crashed? */
139
+ export function isElectronInstanceExitedError(error) {
140
+ const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
141
+ return (message.includes('chrome instance exited') ||
142
+ message.includes('session not created') ||
143
+ message.includes('chrome failed to start') ||
144
+ message.includes('crashed') ||
145
+ message.includes('devtoolsactiveport'));
146
+ }
147
+ /**
148
+ * Enrich a session-creation failure on the Electron path with the diagnosed
149
+ * likely cause and the chromedriver output tail. Returns the original error
150
+ * unchanged when it isn't the app-exited class (so unrelated failures aren't
151
+ * mislabeled).
152
+ */
153
+ export function diagnoseElectronLaunchFailure(cause, input) {
154
+ if (!isElectronInstanceExitedError(cause))
155
+ return cause;
156
+ const platform = input.platform ?? os.platform();
157
+ const causeMessage = cause instanceof Error ? cause.message : String(cause);
158
+ const hints = [];
159
+ const detail = {
160
+ platform: `${platform}-${os.arch()}`,
161
+ appBinaryPath: input.appBinaryPath,
162
+ };
163
+ if (platform === 'darwin') {
164
+ const signing = probeMacAppSigning(input.appBinaryPath);
165
+ detail.macSigning = signing;
166
+ if (signing === 'unsigned' || signing === 'adhoc') {
167
+ hints.push(`The app at "${input.appBinaryPath}" is ${signing === 'adhoc' ? 'only ad-hoc' : 'not'} ` +
168
+ 'code-signed. macOS Gatekeeper/AMFI can kill it before a window opens, which chromedriver ' +
169
+ 'reports as "Chrome instance exited". Sign or notarize the app for a real test target, or ' +
170
+ 'open it once via Finder to clear quarantine for a throwaway.');
171
+ }
172
+ }
173
+ if (platform === 'linux') {
174
+ const hasNoSandbox = (input.args ?? []).includes('--no-sandbox');
175
+ detail.sandboxDisabled = hasNoSandbox;
176
+ if (!hasNoSandbox) {
177
+ hints.push('On Linux CI the unzipped chrome-sandbox helper loses its root-owned SUID bit, so the ' +
178
+ 'sandbox cannot start and the app exits. Pass electron.args: ["--no-sandbox"] for a ' +
179
+ 'throwaway fixture.');
180
+ }
181
+ }
182
+ const tail = input.driverOutputTail?.trim();
183
+ const sections = [causeMessage];
184
+ if (hints.length > 0) {
185
+ sections.push('Electron launch diagnostics:\n' + hints.map((h) => ` • ${h}`).join('\n'));
186
+ }
187
+ if (tail)
188
+ sections.push(`chromedriver output (tail):\n${tail}`);
189
+ return new CraftdriverError(ErrorCode.ELECTRON_LAUNCH_FAILED, sections.join('\n\n'), {
190
+ detail,
191
+ hint: hints[0],
192
+ cause,
193
+ });
194
+ }
195
+ //# sourceMappingURL=electronDiagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electronDiagnostics.js","sourceRoot":"","sources":["../../src/lib/electronDiagnostics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ export type ElectronDialogMethod = 'showOpenDialog' | 'showSaveDialog' | 'showMessageBox';
2
+ /** Scripted result for Electron's asynchronous `dialog.showOpenDialog()`. */
3
+ export interface ElectronOpenDialogResult {
4
+ canceled: boolean;
5
+ filePaths: string[];
6
+ bookmarks?: string[];
7
+ }
8
+ /** Scripted result for Electron's asynchronous `dialog.showSaveDialog()`. */
9
+ export interface ElectronSaveDialogResult {
10
+ canceled: boolean;
11
+ filePath: string;
12
+ bookmark?: string;
13
+ }
14
+ /** Scripted result for Electron's asynchronous `dialog.showMessageBox()`. */
15
+ export interface ElectronMessageBoxResult {
16
+ response: number;
17
+ checkboxChecked: boolean;
18
+ }
19
+ export type ElectronDialogResult = ElectronOpenDialogResult | ElectronSaveDialogResult | ElectronMessageBoxResult;
20
+ /** One native-dialog invocation. `options` excludes the optional parent window. */
21
+ export interface ElectronDialogCall {
22
+ options: unknown;
23
+ }
24
+ interface MainExecutor {
25
+ executeMain<T = unknown>(fn: (electron: unknown, ...args: unknown[]) => T | Promise<T>, ...args: unknown[]): Promise<T>;
26
+ }
27
+ /** A native-dialog replacement returned by `browser.electron.mockDialog()`. */
28
+ export interface ElectronDialogMock {
29
+ readonly method: ElectronDialogMethod;
30
+ getCalls(): Promise<ElectronDialogCall[]>;
31
+ getCallCount(): Promise<number>;
32
+ clearCalls(): Promise<void>;
33
+ restore(): Promise<void>;
34
+ }
35
+ /** Internal implementation; users receive the public interface above. */
36
+ export declare class ElectronDialogMockHandle implements ElectronDialogMock {
37
+ #private;
38
+ readonly method: ElectronDialogMethod;
39
+ constructor(executor: MainExecutor, method: ElectronDialogMethod, id: string, onRestore: () => void);
40
+ /** Return the JSON-safe options received by every call. */
41
+ getCalls(): Promise<ElectronDialogCall[]>;
42
+ /** Return how many times the mocked dialog was called. */
43
+ getCallCount(): Promise<number>;
44
+ /** Clear recorded calls without changing the scripted result. */
45
+ clearCalls(): Promise<void>;
46
+ /** Restore Electron's original dialog function. Safe to call more than once. */
47
+ restore(): Promise<void>;
48
+ }
49
+ export declare function validateDialogResult(method: ElectronDialogMethod, result: ElectronDialogResult): void;
50
+ export {};
51
+ //# sourceMappingURL=electronDialogMock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electronDialogMock.d.ts","sourceRoot":"","sources":["../../src/lib/electronDialogMock.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AAE1F,6EAA6E;AAC7E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,6EAA6E;AAC7E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,6EAA6E;AAC7E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,oBAAoB,GAC5B,wBAAwB,GACxB,wBAAwB,GACxB,wBAAwB,CAAC;AAE7B,mFAAmF;AACnF,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,YAAY;IACpB,WAAW,CAAC,CAAC,GAAG,OAAO,EACrB,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC7D,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,CAAC,CAAC,CAAC;CACf;AAED,+EAA+E;AAC/E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC1C,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,yEAAyE;AACzE,qBAAa,wBAAyB,YAAW,kBAAkB;;IACjE,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;gBAOpC,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,oBAAoB,EAC5B,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,IAAI;IAQvB,2DAA2D;IACrD,QAAQ,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAoB/C,0DAA0D;IACpD,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAIrC,iEAAiE;IAC3D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBjC,gFAAgF;IAC1E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAkC/B;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,oBAAoB,EAC5B,MAAM,EAAE,oBAAoB,GAC3B,IAAI,CAoCN"}
@@ -0,0 +1,106 @@
1
+ import { CraftdriverError, ErrorCode } from './errors.js';
2
+ /** Internal implementation; users receive the public interface above. */
3
+ export class ElectronDialogMockHandle {
4
+ method;
5
+ #id;
6
+ #executor;
7
+ #onRestore;
8
+ #restored = false;
9
+ constructor(executor, method, id, onRestore) {
10
+ this.#executor = executor;
11
+ this.method = method;
12
+ this.#id = id;
13
+ this.#onRestore = onRestore;
14
+ }
15
+ /** Return the JSON-safe options received by every call. */
16
+ async getCalls() {
17
+ this.#assertActive();
18
+ return this.#executor.executeMain((_electron, method, id) => {
19
+ const methodName = method;
20
+ const mockId = id;
21
+ const key = Symbol.for('craftdriver.electron.dialogMocks');
22
+ const registry = globalThis[key];
23
+ const entry = registry?.[methodName];
24
+ if (!entry || entry.id !== mockId)
25
+ throw new Error(`Dialog mock ${methodName} is no longer active.`);
26
+ return entry.calls;
27
+ }, this.method, this.#id);
28
+ }
29
+ /** Return how many times the mocked dialog was called. */
30
+ async getCallCount() {
31
+ return (await this.getCalls()).length;
32
+ }
33
+ /** Clear recorded calls without changing the scripted result. */
34
+ async clearCalls() {
35
+ this.#assertActive();
36
+ await this.#executor.executeMain((_electron, method, id) => {
37
+ const methodName = method;
38
+ const mockId = id;
39
+ const key = Symbol.for('craftdriver.electron.dialogMocks');
40
+ const registry = globalThis[key];
41
+ const entry = registry?.[methodName];
42
+ if (!entry || entry.id !== mockId)
43
+ throw new Error(`Dialog mock ${methodName} is no longer active.`);
44
+ entry.calls.length = 0;
45
+ }, this.method, this.#id);
46
+ }
47
+ /** Restore Electron's original dialog function. Safe to call more than once. */
48
+ async restore() {
49
+ if (this.#restored)
50
+ return;
51
+ await this.#executor.executeMain((electron, method, id) => {
52
+ const methodName = method;
53
+ const mockId = id;
54
+ const key = Symbol.for('craftdriver.electron.dialogMocks');
55
+ const registry = globalThis[key];
56
+ const entry = registry?.[methodName];
57
+ if (!entry || entry.id !== mockId)
58
+ return;
59
+ const dialog = electron.dialog;
60
+ if (dialog[methodName] === entry.replacement)
61
+ dialog[methodName] = entry.original;
62
+ delete registry[methodName];
63
+ }, this.method, this.#id);
64
+ this.#restored = true;
65
+ this.#onRestore();
66
+ }
67
+ #assertActive() {
68
+ if (this.#restored) {
69
+ throw new CraftdriverError(ErrorCode.STATE_INVALID, `The ${this.method} dialog mock has already been restored.`);
70
+ }
71
+ }
72
+ }
73
+ export function validateDialogResult(method, result) {
74
+ if (!result || typeof result !== 'object' || Array.isArray(result)) {
75
+ throw invalidResult(method, 'result must be an object');
76
+ }
77
+ if (method === 'showOpenDialog') {
78
+ const value = result;
79
+ if (typeof value.canceled !== 'boolean' ||
80
+ !Array.isArray(value.filePaths) ||
81
+ !value.filePaths.every((path) => typeof path === 'string') ||
82
+ (value.bookmarks !== undefined &&
83
+ (!Array.isArray(value.bookmarks) ||
84
+ !value.bookmarks.every((bookmark) => typeof bookmark === 'string')))) {
85
+ throw invalidResult(method, 'expected { canceled: boolean, filePaths: string[] }');
86
+ }
87
+ return;
88
+ }
89
+ if (method === 'showSaveDialog') {
90
+ const value = result;
91
+ if (typeof value.canceled !== 'boolean' ||
92
+ typeof value.filePath !== 'string' ||
93
+ (value.bookmark !== undefined && typeof value.bookmark !== 'string')) {
94
+ throw invalidResult(method, 'expected { canceled: boolean, filePath: string }');
95
+ }
96
+ return;
97
+ }
98
+ const value = result;
99
+ if (!Number.isInteger(value.response) || typeof value.checkboxChecked !== 'boolean') {
100
+ throw invalidResult(method, 'expected { response: integer, checkboxChecked: boolean }');
101
+ }
102
+ }
103
+ function invalidResult(method, expected) {
104
+ return new CraftdriverError(ErrorCode.INVALID_ARGUMENT, `Invalid result for electron.mockDialog('${method}', result): ${expected}.`, { detail: { method } });
105
+ }
106
+ //# sourceMappingURL=electronDialogMock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electronDialogMock.js","sourceRoot":"","sources":["../../src/lib/electronDialogMock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export type InspectFuseStatus = 'enabled' | 'disabled' | 'removed' | 'unknown';
2
+ /**
3
+ * The binary that actually carries the fuse wire for a given app executable. On
4
+ * macOS that's the Electron Framework inside the `.app`; elsewhere it's the
5
+ * executable itself.
6
+ */
7
+ export declare function fuseCarrierBinary(appBinaryPath: string): string;
8
+ /**
9
+ * Read the `EnableNodeCliInspectArguments` fuse straight from the packaged binary.
10
+ * Returns `'unknown'` for any older/unfused binary or on any read problem.
11
+ */
12
+ export declare function readInspectArgumentsFuse(appBinaryPath: string | undefined): InspectFuseStatus;
13
+ //# sourceMappingURL=electronFuses.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electronFuses.d.ts","sourceRoot":"","sources":["../../src/lib/electronFuses.ts"],"names":[],"mappings":"AA4BA,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAE/E;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAU/D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,CAqC7F"}