browser-debugger-cli 0.14.0 → 0.16.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 (167) hide show
  1. package/.claude/skills/bdg/SKILL.md +3 -2
  2. package/dist/cdp/methodTarget.d.ts +92 -0
  3. package/dist/cdp/methodTarget.js +159 -0
  4. package/dist/cdp/protocol.d.ts +16 -1
  5. package/dist/cdp/protocol.js +21 -0
  6. package/dist/cdp/schema.d.ts +55 -1
  7. package/dist/cdp/schema.js +134 -25
  8. package/dist/cdp/types.d.ts +3 -1
  9. package/dist/commands/cdp.d.ts +38 -1
  10. package/dist/commands/cdp.js +201 -133
  11. package/dist/commands/cleanup.js +21 -4
  12. package/dist/commands/dom/eval.d.ts +2 -1
  13. package/dist/commands/dom/eval.js +6 -21
  14. package/dist/commands/dom/formInteraction.js +8 -4
  15. package/dist/commands/dom/helpers/evalResult.d.ts +36 -0
  16. package/dist/commands/dom/helpers/evalResult.js +59 -0
  17. package/dist/commands/dom/helpers/index.d.ts +4 -4
  18. package/dist/commands/dom/helpers/index.js +3 -3
  19. package/dist/commands/dom/helpers/query.d.ts +2 -2
  20. package/dist/commands/dom/helpers/query.js +2 -2
  21. package/dist/commands/dom/helpers/screenshot.d.ts +21 -26
  22. package/dist/commands/dom/helpers/screenshot.js +50 -668
  23. package/dist/commands/dom/screenshot.js +56 -36
  24. package/dist/commands/helpJson.d.ts +1 -1
  25. package/dist/commands/helpJson.js +3 -3
  26. package/dist/commands/helpTopic.js +10 -4
  27. package/dist/commands/network/har.js +18 -14
  28. package/dist/commands/optionBehaviors.js +24 -9
  29. package/dist/commands/shared/CommandRunner.d.ts +5 -0
  30. package/dist/commands/shared/CommandRunner.js +18 -3
  31. package/dist/commands/shared/interrupt.d.ts +40 -0
  32. package/dist/commands/shared/interrupt.js +73 -0
  33. package/dist/commands/shared/optionTypes.d.ts +3 -0
  34. package/dist/commands/shared/outputFile.d.ts +2 -1
  35. package/dist/commands/shared/outputFile.js +7 -4
  36. package/dist/commands/shared/startHelpers.d.ts +26 -3
  37. package/dist/commands/shared/startHelpers.js +145 -23
  38. package/dist/commands/status.js +3 -1
  39. package/dist/commands/stop.js +2 -1
  40. package/dist/commands/types.d.ts +5 -0
  41. package/dist/connection/cdp.js +1 -16
  42. package/dist/connection/chromeIdentity.d.ts +24 -5
  43. package/dist/connection/chromeIdentity.js +53 -22
  44. package/dist/connection/launcher/flagsBuilder.d.ts +46 -0
  45. package/dist/connection/launcher/flagsBuilder.js +107 -23
  46. package/dist/connection/launcher.d.ts +35 -2
  47. package/dist/connection/launcher.js +99 -12
  48. package/dist/connection/typed-cdp.d.ts +3 -2
  49. package/dist/constants.d.ts +3 -5
  50. package/dist/constants.js +3 -5
  51. package/dist/daemon/SessionController.d.ts +10 -5
  52. package/dist/daemon/SessionController.js +15 -8
  53. package/dist/daemon/ipcServer.js +1 -1
  54. package/dist/daemon/launcher.d.ts +22 -3
  55. package/dist/daemon/launcher.js +45 -8
  56. package/dist/daemon/session/Session.d.ts +5 -1
  57. package/dist/daemon/session/Session.js +9 -8
  58. package/dist/daemon/session/TelemetryStore.d.ts +5 -0
  59. package/dist/daemon/session/TelemetryStore.js +4 -0
  60. package/dist/daemon/session/captureGate.d.ts +59 -0
  61. package/dist/daemon/session/captureGate.js +96 -0
  62. package/dist/daemon/session/chromeConnection.d.ts +16 -1
  63. package/dist/daemon/session/chromeConnection.js +34 -4
  64. package/dist/daemon/session/collectors.d.ts +15 -0
  65. package/dist/daemon/session/collectors.js +39 -2
  66. package/dist/daemon/session/commandRegistry.d.ts +14 -1
  67. package/dist/daemon/session/commandRegistry.js +48 -13
  68. package/dist/daemon/session/downloads.d.ts +32 -0
  69. package/dist/daemon/session/downloads.js +96 -0
  70. package/dist/daemon/session/interactions.d.ts +3 -2
  71. package/dist/daemon/session/interactions.js +7 -2
  72. package/dist/daemon/session/plugins.js +6 -0
  73. package/dist/daemon.js +18520 -17014
  74. package/dist/errors/CommandError.d.ts +2 -0
  75. package/dist/errors/issues.d.ts +1 -1
  76. package/dist/errors/messages.d.ts +81 -0
  77. package/dist/errors/messages.js +198 -6
  78. package/dist/index.js +1446 -1078
  79. package/dist/ipc/client.d.ts +20 -2
  80. package/dist/ipc/client.js +32 -6
  81. package/dist/ipc/protocol/commands.d.ts +36 -2
  82. package/dist/ipc/protocol/commands.js +1 -0
  83. package/dist/ipc/protocol/domTypes.d.ts +24 -1
  84. package/dist/ipc/session/queries.d.ts +3 -0
  85. package/dist/ipc/session/types.d.ts +5 -0
  86. package/dist/ipc/transport/IPCError.d.ts +9 -0
  87. package/dist/ipc/transport/IPCError.js +12 -0
  88. package/dist/ipc/transport/errors.d.ts +2 -1
  89. package/dist/ipc/transport/errors.js +4 -1
  90. package/dist/ipc/transport/index.d.ts +10 -2
  91. package/dist/ipc/transport/index.js +29 -4
  92. package/dist/runtime/dom/actionEffects.d.ts +48 -9
  93. package/dist/runtime/dom/actionEffects.js +269 -34
  94. package/dist/runtime/dom/actionEffectsScripts.d.ts +45 -0
  95. package/dist/runtime/dom/actionEffectsScripts.js +101 -2
  96. package/dist/runtime/dom/captureArea.d.ts +35 -0
  97. package/dist/runtime/dom/captureArea.js +203 -0
  98. package/dist/runtime/dom/elementInfo.d.ts +13 -4
  99. package/dist/runtime/dom/elementInfo.js +12 -3
  100. package/dist/runtime/dom/evalHelpers.d.ts +24 -4
  101. package/dist/runtime/dom/evalHelpers.js +40 -12
  102. package/dist/runtime/dom/formDiscovery.d.ts +1 -1
  103. package/dist/runtime/dom/frames.d.ts +2 -1
  104. package/dist/runtime/dom/frames.js +3 -1
  105. package/dist/runtime/page/bdgWorld.d.ts +9 -0
  106. package/dist/runtime/page/bdgWorld.js +11 -0
  107. package/dist/runtime/page/captureEmulation.d.ts +119 -0
  108. package/dist/runtime/page/captureEmulation.js +189 -0
  109. package/dist/runtime/page/captureScroll.d.ts +24 -0
  110. package/dist/runtime/page/captureScroll.js +124 -0
  111. package/dist/runtime/page/emulation.js +6 -5
  112. package/dist/runtime/page/screenshot.d.ts +41 -0
  113. package/dist/runtime/page/screenshot.js +394 -0
  114. package/dist/runtime/page/userAgent.d.ts +86 -2
  115. package/dist/runtime/page/userAgent.js +154 -33
  116. package/dist/session/paths.d.ts +52 -3
  117. package/dist/session/paths.js +179 -7
  118. package/dist/session/portClaims.d.ts +0 -8
  119. package/dist/session/portClaims.js +1 -22
  120. package/dist/session/sessionList.d.ts +5 -1
  121. package/dist/session/sessionList.js +5 -1
  122. package/dist/telemetry/downloads.d.ts +127 -0
  123. package/dist/telemetry/downloads.js +265 -0
  124. package/dist/telemetry/har/builder.d.ts +12 -1
  125. package/dist/telemetry/har/builder.js +32 -9
  126. package/dist/telemetry/har/sanitize.d.ts +28 -0
  127. package/dist/telemetry/har/sanitize.js +184 -0
  128. package/dist/telemetry/har/sanitizeBody.d.ts +78 -0
  129. package/dist/telemetry/har/sanitizeBody.js +541 -0
  130. package/dist/telemetry/har/types.d.ts +2 -0
  131. package/dist/telemetry/network.d.ts +4 -4
  132. package/dist/telemetry/network.js +38 -4
  133. package/dist/telemetry/networkRetention.d.ts +35 -14
  134. package/dist/telemetry/networkRetention.js +62 -26
  135. package/dist/types.d.ts +9 -14
  136. package/dist/ui/OutputBuilder.d.ts +3 -2
  137. package/dist/ui/OutputBuilder.js +4 -3
  138. package/dist/ui/formatters/cdp.d.ts +32 -9
  139. package/dist/ui/formatters/cdp.js +77 -6
  140. package/dist/ui/formatters/details.js +7 -15
  141. package/dist/ui/formatters/preview.d.ts +2 -0
  142. package/dist/ui/formatters/preview.js +7 -1
  143. package/dist/ui/formatters/sessions.d.ts +3 -2
  144. package/dist/ui/formatters/sessions.js +10 -3
  145. package/dist/ui/formatters/status.js +6 -1
  146. package/dist/ui/formatting.d.ts +7 -0
  147. package/dist/ui/formatting.js +13 -0
  148. package/dist/ui/logging/logger.d.ts +1 -1
  149. package/dist/ui/messages/chrome.d.ts +27 -6
  150. package/dist/ui/messages/chrome.js +78 -12
  151. package/dist/ui/messages/commands.d.ts +71 -3
  152. package/dist/ui/messages/commands.js +98 -3
  153. package/dist/ui/messages/networkMessages.d.ts +50 -5
  154. package/dist/ui/messages/networkMessages.js +50 -6
  155. package/dist/ui/messages/session.d.ts +8 -0
  156. package/dist/ui/messages/session.js +10 -0
  157. package/dist/utils/async.d.ts +3 -2
  158. package/dist/utils/async.js +16 -3
  159. package/dist/utils/atomicFile.d.ts +2 -1
  160. package/dist/utils/atomicFile.js +5 -2
  161. package/dist/utils/directories.d.ts +41 -0
  162. package/dist/utils/directories.js +48 -0
  163. package/dist/utils/http.d.ts +11 -4
  164. package/dist/utils/http.js +5 -3
  165. package/package.json +18 -4
  166. /package/dist/{commands/dom → runtime/page}/screenshotResize.d.ts +0 -0
  167. /package/dist/{commands/dom → runtime/page}/screenshotResize.js +0 -0
@@ -18,6 +18,8 @@ export interface ErrorMetadata {
18
18
  fallback?: string;
19
19
  /** CDP alternative for advanced use cases */
20
20
  cdpAlternative?: string;
21
+ /** How the command ran despite failing (e.g. a CDP method sent though bdg's protocol lacks it) */
22
+ warning?: string;
21
23
  }
22
24
  /**
23
25
  * Custom error class for CLI commands with structured metadata.
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Add new codes here as vertical slices migrate away from raw string messages.
9
9
  */
10
- export type IssueCode = 'PORT_IN_USE' | 'INVALID_PORT' | 'USER_DATA_DIR_CREATE_FAILED' | 'CHROME_LAUNCH_FAILED' | 'CHROME_DIED_AFTER_LAUNCH' | 'CHROME_EXITED_DURING_STARTUP' | 'NO_PAGE_TARGET_FOUND' | 'CHROME_BINARY_NOT_FOUND' | 'CHROME_BINARY_NOT_EXECUTABLE' | 'CHROME_BINARY_IS_DIRECTORY' | 'PREFS_FILE_NOT_FOUND' | 'PREFS_INVALID_FORMAT' | 'PREFS_LOAD_FAILED' | 'PREFS_NOT_JSON_SERIALIZABLE';
10
+ export type IssueCode = 'PORT_IN_USE' | 'INVALID_PORT' | 'USER_DATA_DIR_CREATE_FAILED' | 'CHROME_LAUNCH_FAILED' | 'CHROME_DIED_AFTER_LAUNCH' | 'CHROME_PORT_NOT_OPENED' | 'CHROME_EXITED_DURING_STARTUP' | 'NO_PAGE_TARGET_FOUND' | 'CHROME_BINARY_NOT_FOUND' | 'CHROME_BINARY_NOT_EXECUTABLE' | 'CHROME_BINARY_IS_DIRECTORY' | 'PREFS_FILE_NOT_FOUND' | 'PREFS_INVALID_FORMAT' | 'PREFS_LOAD_FAILED' | 'PREFS_NOT_JSON_SERIALIZABLE';
11
11
  export interface IssueDetails {
12
12
  code: IssueCode;
13
13
  context?: Record<string, unknown>;
@@ -3,8 +3,10 @@
3
3
  *
4
4
  * Centralized location for reusable error messages with consistent formatting.
5
5
  */
6
+ import type { MissingMethodCause } from '../cdp/methodTarget.js';
6
7
  import type { DomFrame, PendingRequestInfo } from '../ipc/protocol/commands.js';
7
8
  import { type WaitCondition, type WaitSnapshot } from '../runtime/dom/waitCondition.js';
9
+ import { type UntrustedSessionDir } from '../session/paths.js';
8
10
  import type { DocumentRequestState, IndexSource } from '../types.js';
9
11
  /**
10
12
  * Generate "session already running" error message (commands carry
@@ -82,6 +84,15 @@ export declare function sessionNotRespondingError(seconds: number): ErrorWithSug
82
84
  * @param seconds - Timeout in seconds
83
85
  */
84
86
  export declare function commandTimedOutError(seconds: number): ErrorWithSuggestion;
87
+ /**
88
+ * A screenshot interrupted by Ctrl-C or SIGTERM: the daemon skips the
89
+ * capture if it has not started and puts the page's emulation back before
90
+ * any later page command runs.
91
+ *
92
+ * @param signal - The signal that stopped it
93
+ * @returns Message and suggestion
94
+ */
95
+ export declare function screenshotInterruptedError(signal: 'SIGINT' | 'SIGTERM'): ErrorWithSuggestion;
85
96
  /**
86
97
  * What to do when a command finds no session to work with.
87
98
  *
@@ -258,6 +269,13 @@ export declare function invalidSelectorFilterError(selector: string, filter: str
258
269
  * @param closest - Most similar existing command path, if any
259
270
  */
260
271
  export declare function unknownHelpTopicError(topic: string, closest?: string): ErrorWithSuggestion;
272
+ /**
273
+ * "Did you mean" for one or more close candidates, joined as a sentence.
274
+ *
275
+ * @param candidates - Close matches, e.g. ["form", "frames"]
276
+ * @returns e.g. "Did you mean: form or frames?" or "Did you mean: a, b or c?"
277
+ */
278
+ export declare function didYouMeanSuggestion(candidates: string[]): string;
261
279
  /**
262
280
  * Suggestion for a command-line usage error (missing argument, invalid value,
263
281
  * unknown option without a close match).
@@ -360,6 +378,21 @@ export declare function sessionDirIsFileError(dir: string): ErrorWithSuggestion;
360
378
  * @param reason - File-system error
361
379
  */
362
380
  export declare function sessionDirNotWritableError(dir: string, reason: string): ErrorWithSuggestion;
381
+ /**
382
+ * The session directory, or one above it, is not safe to use: another user
383
+ * could replace the daemon socket or plant files there.
384
+ *
385
+ * @param untrusted - Untrusted directory and why
386
+ */
387
+ export declare function untrustedSessionDirError(untrusted: UntrustedSessionDir): ErrorWithSuggestion;
388
+ /**
389
+ * The daemon log cannot be opened for writing (a symlink there is refused,
390
+ * not followed).
391
+ *
392
+ * @param logPath - Daemon log path
393
+ * @param code - File-system error code
394
+ */
395
+ export declare function daemonLogNotOpenedError(logPath: string, code: string): ErrorWithSuggestion;
363
396
  /**
364
397
  * The daemon socket path exceeds the OS limit for Unix sockets.
365
398
  *
@@ -1037,6 +1070,54 @@ export declare function formInIframeError(iframeUrl: string, crossOrigin: boolea
1037
1070
  export declare function cdpCallError(method: string, message: string): ErrorWithSuggestion & {
1038
1071
  notFound: boolean;
1039
1072
  };
1073
+ /**
1074
+ * `bdg cdp` when Chrome answered -32601: it has no such method (for the
1075
+ * page target). What it says depends on why, as far as the bundled protocol
1076
+ * tells: an unknown domain, a redirect to a method the protocol lacks, a
1077
+ * Chrome older than the protocol, or a method only Chrome could know (typed
1078
+ * in one case, it gets a reminder that such names are case-sensitive).
1079
+ *
1080
+ * @param method - CDP method
1081
+ * @param chromeMessage - Chrome's error, e.g. "'Foo.bar' wasn't found"
1082
+ * @param cause - Why Chrome may lack it
1083
+ * @returns Message and suggestion
1084
+ */
1085
+ export declare function cdpMethodNotImplementedError(method: string, chromeMessage: string, cause: MissingMethodCause): ErrorWithSuggestion;
1086
+ /**
1087
+ * `bdg cdp <Domain.Type>` without `--describe`: a type cannot be called.
1088
+ *
1089
+ * @param name - Full type name, e.g. Network.CookieSameSite
1090
+ * @returns Message and suggestion
1091
+ */
1092
+ export declare function cdpTypeNotMethodError(name: string): ErrorWithSuggestion;
1093
+ /**
1094
+ * `bdg cdp <name>` for a close typo of bundled methods, or a name that is
1095
+ * not `Domain.method`.
1096
+ *
1097
+ * @param input - Name as typed
1098
+ * @param similar - Methods to suggest
1099
+ * @param listHint - First suggestion line (how to find methods)
1100
+ * @returns Message and suggestion
1101
+ */
1102
+ export declare function cdpMethodNotFoundError(input: string, similar: string[], listHint: string): ErrorWithSuggestion;
1103
+ /**
1104
+ * `bdg cdp <name>` for a close typo of bundled methods or domains: did you
1105
+ * mean, or how to send it as typed (a method newer than the bundled protocol).
1106
+ *
1107
+ * @param input - Name as typed
1108
+ * @param similar - Methods to suggest
1109
+ * @param listHint - First suggestion line (how to find methods)
1110
+ * @returns Message and suggestion
1111
+ */
1112
+ export declare function cdpMethodTypoError(input: string, similar: string[], listHint: string): ErrorWithSuggestion;
1113
+ /**
1114
+ * `bdg cdp <Domain.method> --describe` for a method the bundled protocol lacks.
1115
+ *
1116
+ * @param method - Method as typed
1117
+ * @param protocolVersion - Bundled devtools-protocol version
1118
+ * @returns Message and suggestion
1119
+ */
1120
+ export declare function cdpMethodNotInBundledProtocolError(method: string, protocolVersion: string): ErrorWithSuggestion;
1040
1121
  /**
1041
1122
  * The skill file is not where the package should have it (a broken or
1042
1123
  * partial install).
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Centralized location for reusable error messages with consistent formatting.
5
5
  */
6
+ import * as os from 'os';
6
7
  import * as path from 'path';
7
8
  import { countedMatches, } from '../runtime/dom/waitCondition.js';
8
9
  import { getSessionBaseDir, getSessionName } from '../session/paths.js';
@@ -108,6 +109,20 @@ export function commandTimedOutError(seconds) {
108
109
  suggestion: `Check the session with: ${sessionCommand('bdg status')}; if the page stays frozen, end it with: ${sessionCommand('bdg cleanup --force')}`,
109
110
  };
110
111
  }
112
+ /**
113
+ * A screenshot interrupted by Ctrl-C or SIGTERM: the daemon skips the
114
+ * capture if it has not started and puts the page's emulation back before
115
+ * any later page command runs.
116
+ *
117
+ * @param signal - The signal that stopped it
118
+ * @returns Message and suggestion
119
+ */
120
+ export function screenshotInterruptedError(signal) {
121
+ return {
122
+ message: `Screenshot cancelled (${signal === 'SIGINT' ? 'interrupted' : 'terminated'})`,
123
+ suggestion: "No file was written; run it again to capture (the next command sees the page's own emulation)",
124
+ };
125
+ }
111
126
  /**
112
127
  * What to do when a command finds no session to work with.
113
128
  *
@@ -370,6 +385,17 @@ export function unknownHelpTopicError(topic, closest) {
370
385
  : `Run "bdg ${parent ? `${parent} ` : ''}--help" for commands`,
371
386
  };
372
387
  }
388
+ /**
389
+ * "Did you mean" for one or more close candidates, joined as a sentence.
390
+ *
391
+ * @param candidates - Close matches, e.g. ["form", "frames"]
392
+ * @returns e.g. "Did you mean: form or frames?" or "Did you mean: a, b or c?"
393
+ */
394
+ export function didYouMeanSuggestion(candidates) {
395
+ const last = candidates.at(-1) ?? '';
396
+ const rest = candidates.slice(0, -1);
397
+ return `Did you mean: ${rest.length > 0 ? `${rest.join(', ')} or ${last}` : last}?`;
398
+ }
373
399
  /**
374
400
  * Suggestion for a command-line usage error (missing argument, invalid value,
375
401
  * unknown option without a close match).
@@ -498,7 +524,7 @@ export function invalidSessionNameError(name, maxLength) {
498
524
  export function sessionNameSocketTooLongError(name, socketPath, max) {
499
525
  return {
500
526
  message: `Session name "${name}" makes the daemon socket path too long (${Buffer.byteLength(socketPath)} bytes, at most ${max}): ${socketPath}`,
501
- suggestion: 'Use a shorter session name, or a shorter BDG_SESSION_DIR (e.g. /tmp/bdg)',
527
+ suggestion: `Use a shorter session name, or a shorter BDG_SESSION_DIR (e.g. ${privateSessionDirExample()})`,
502
528
  };
503
529
  }
504
530
  /**
@@ -524,15 +550,36 @@ export function purgeRefusedError(dir, reason) {
524
550
  suggestion: `End the session first (${sessionCommand('bdg cleanup --force')}), then retry: ${sessionCommand('bdg cleanup --purge')}`,
525
551
  };
526
552
  }
527
- /** Fix for an unusable session directory */
528
- const SESSION_DIR_SUGGESTION = 'Set BDG_SESSION_DIR to a short, writable directory, e.g. BDG_SESSION_DIR=/tmp/bdg';
553
+ /**
554
+ * A short session directory only the user can use, for suggestions: in
555
+ * `$XDG_RUNTIME_DIR` (Linux, private to the user) when set, else a per-user
556
+ * name in the OS temp directory (per-user on macOS). Never the shared
557
+ * `/tmp/bdg`, which another user can create first.
558
+ *
559
+ * @returns Absolute directory path
560
+ */
561
+ function privateSessionDirExample() {
562
+ const runtimeDir = process.env['XDG_RUNTIME_DIR']?.trim();
563
+ if (runtimeDir)
564
+ return path.join(runtimeDir, 'bdg');
565
+ const uid = process.getuid?.();
566
+ return path.join(os.tmpdir(), uid === undefined ? 'bdg' : `bdg-${uid}`);
567
+ }
568
+ /**
569
+ * Fix for an unusable session directory.
570
+ *
571
+ * @returns Suggestion naming a private, short directory
572
+ */
573
+ function sessionDirSuggestion() {
574
+ return `Set BDG_SESSION_DIR to a short directory only you can write to, e.g. BDG_SESSION_DIR=${privateSessionDirExample()}`;
575
+ }
529
576
  /**
530
577
  * The session directory exists but is not a directory.
531
578
  *
532
579
  * @param dir - Session directory
533
580
  */
534
581
  export function sessionDirIsFileError(dir) {
535
- return { message: `Session directory ${dir} is a file`, suggestion: SESSION_DIR_SUGGESTION };
582
+ return { message: `Session directory ${dir} is a file`, suggestion: sessionDirSuggestion() };
536
583
  }
537
584
  /**
538
585
  * The session directory cannot be created or written.
@@ -543,7 +590,54 @@ export function sessionDirIsFileError(dir) {
543
590
  export function sessionDirNotWritableError(dir, reason) {
544
591
  return {
545
592
  message: `Session directory ${dir} is not writable (${reason})`,
546
- suggestion: SESSION_DIR_SUGGESTION,
593
+ suggestion: sessionDirSuggestion(),
594
+ };
595
+ }
596
+ /**
597
+ * The session directory, or one above it, is not safe to use: another user
598
+ * could replace the daemon socket or plant files there.
599
+ *
600
+ * @param untrusted - Untrusted directory and why
601
+ */
602
+ export function untrustedSessionDirError(untrusted) {
603
+ return {
604
+ message: `Session directory ${untrusted.dir} is not safe to use: ${untrusted.reason}`,
605
+ suggestion: untrustedSessionDirSuggestion(untrusted),
606
+ };
607
+ }
608
+ /**
609
+ * Fix for an untrusted session directory: remove a symlink, use a
610
+ * subdirectory of a shared sticky directory (`BDG_SESSION_DIR=/tmp`), chmod
611
+ * a directory bdg owns (`~/.bdg`, `sessions/`, `sessions/<name>`), else
612
+ * choose another `BDG_SESSION_DIR`.
613
+ *
614
+ * @param untrusted - Untrusted directory and why
615
+ * @returns Suggestion
616
+ */
617
+ function untrustedSessionDirSuggestion(untrusted) {
618
+ const { dir, kind, bdgOwned } = untrusted;
619
+ const example = `BDG_SESSION_DIR=${privateSessionDirExample()}`;
620
+ if (kind === 'symlink') {
621
+ return `Remove the link (rm ${dir}) or point BDG_SESSION_DIR at the real directory`;
622
+ }
623
+ if (kind === 'shared') {
624
+ return `${dir} is shared by all users; use a subdirectory only you can write to, e.g. ${example}`;
625
+ }
626
+ if (bdgOwned)
627
+ return `Run chmod 700 ${dir} (or remove it if it is not yours), then retry`;
628
+ return `Use a directory you own that others cannot write to, e.g. ${example} (or chmod 700 ${dir} if it is yours)`;
629
+ }
630
+ /**
631
+ * The daemon log cannot be opened for writing (a symlink there is refused,
632
+ * not followed).
633
+ *
634
+ * @param logPath - Daemon log path
635
+ * @param code - File-system error code
636
+ */
637
+ export function daemonLogNotOpenedError(logPath, code) {
638
+ return {
639
+ message: `Cannot open the daemon log ${logPath} (${code === 'ELOOP' ? 'it is a symbolic link' : code})`,
640
+ suggestion: `Remove ${logPath} if you did not create it, then retry`,
547
641
  };
548
642
  }
549
643
  /**
@@ -555,7 +649,7 @@ export function sessionDirNotWritableError(dir, reason) {
555
649
  export function socketPathTooLongError(socketPath, max) {
556
650
  return {
557
651
  message: `Session directory path is too long for the daemon socket (${Buffer.byteLength(socketPath)} bytes, at most ${max}): ${socketPath}`,
558
- suggestion: SESSION_DIR_SUGGESTION,
652
+ suggestion: sessionDirSuggestion(),
559
653
  };
560
654
  }
561
655
  /**
@@ -1882,6 +1976,104 @@ export function cdpCallError(method, message) {
1882
1976
  notFound: false,
1883
1977
  };
1884
1978
  }
1979
+ /**
1980
+ * `bdg cdp` when Chrome answered -32601: it has no such method (for the
1981
+ * page target). What it says depends on why, as far as the bundled protocol
1982
+ * tells: an unknown domain, a redirect to a method the protocol lacks, a
1983
+ * Chrome older than the protocol, or a method only Chrome could know (typed
1984
+ * in one case, it gets a reminder that such names are case-sensitive).
1985
+ *
1986
+ * @param method - CDP method
1987
+ * @param chromeMessage - Chrome's error, e.g. "'Foo.bar' wasn't found"
1988
+ * @param cause - Why Chrome may lack it
1989
+ * @returns Message and suggestion
1990
+ */
1991
+ export function cdpMethodNotImplementedError(method, chromeMessage, cause) {
1992
+ const search = sessionCommand('bdg cdp --search <keyword>');
1993
+ switch (cause.kind) {
1994
+ case 'unknownDomain':
1995
+ return {
1996
+ message: `Unknown CDP domain ${cause.domain}: it is not in bdg's bundled protocol, and this Chrome doesn't implement ${method} (${chromeMessage})`,
1997
+ suggestion: joinLines(cause.similar.length > 0 ? `Did you mean: ${cause.similar.join(', ')}?` : undefined, `List the domains: ${sessionCommand('bdg cdp --list')}`),
1998
+ };
1999
+ case 'deadRedirect':
2000
+ return {
2001
+ message: `This Chrome doesn't implement ${method}: the protocol redirects it to ${cause.target}, which does not exist (${chromeMessage})`,
2002
+ suggestion: cause.similar.length > 0
2003
+ ? `Did you mean: ${cause.similar.join(', ')}? See: ${sessionCommand(`bdg cdp ${cause.similar[0]} --describe`)}`
2004
+ : `Find another method: ${search}`,
2005
+ };
2006
+ case 'older':
2007
+ return {
2008
+ message: `This Chrome doesn't implement ${method} (${chromeMessage})`,
2009
+ suggestion: `bdg's bundled protocol has it, but this Chrome is older (or ${method} is not available on a page). Use a newer Chrome, or find another method: ${search}`,
2010
+ };
2011
+ case 'unlisted':
2012
+ return {
2013
+ message: `This Chrome doesn't implement ${method} (${chromeMessage})`,
2014
+ suggestion: cause.oneCase
2015
+ ? `CDP method names are case-sensitive for methods bdg doesn't know: ${method} was sent as typed. Type it in lowerCamelCase as Chrome names it (getCookies, not getcookies), or find a method: ${search}`
2016
+ : `Check the spelling (Chrome's method names are case-sensitive), or find a method: ${search}`,
2017
+ };
2018
+ }
2019
+ }
2020
+ /**
2021
+ * `bdg cdp <Domain.Type>` without `--describe`: a type cannot be called.
2022
+ *
2023
+ * @param name - Full type name, e.g. Network.CookieSameSite
2024
+ * @returns Message and suggestion
2025
+ */
2026
+ export function cdpTypeNotMethodError(name) {
2027
+ return {
2028
+ message: `${name} is a protocol type, not a method`,
2029
+ suggestion: `Use: bdg cdp ${name} --describe (to see its values or properties)`,
2030
+ };
2031
+ }
2032
+ /**
2033
+ * `bdg cdp <name>` for a close typo of bundled methods, or a name that is
2034
+ * not `Domain.method`.
2035
+ *
2036
+ * @param input - Name as typed
2037
+ * @param similar - Methods to suggest
2038
+ * @param listHint - First suggestion line (how to find methods)
2039
+ * @returns Message and suggestion
2040
+ */
2041
+ export function cdpMethodNotFoundError(input, similar, listHint) {
2042
+ const didYouMean = similar.length > 0 ? ['', 'Did you mean:', ...similar.map((name) => ` - ${name}`)] : [];
2043
+ return {
2044
+ message: `Method '${input}' not found`,
2045
+ suggestion: [listHint, ...didYouMean].join('\n'),
2046
+ };
2047
+ }
2048
+ /**
2049
+ * `bdg cdp <name>` for a close typo of bundled methods or domains: did you
2050
+ * mean, or how to send it as typed (a method newer than the bundled protocol).
2051
+ *
2052
+ * @param input - Name as typed
2053
+ * @param similar - Methods to suggest
2054
+ * @param listHint - First suggestion line (how to find methods)
2055
+ * @returns Message and suggestion
2056
+ */
2057
+ export function cdpMethodTypoError(input, similar, listHint) {
2058
+ const err = cdpMethodNotFoundError(input, similar, listHint);
2059
+ return {
2060
+ message: err.message,
2061
+ suggestion: `${err.suggestion}\n\nTo send it as typed (a method newer than bdg's protocol): ${sessionCommand(`bdg cdp ${input} --send-anyway`)}`,
2062
+ };
2063
+ }
2064
+ /**
2065
+ * `bdg cdp <Domain.method> --describe` for a method the bundled protocol lacks.
2066
+ *
2067
+ * @param method - Method as typed
2068
+ * @param protocolVersion - Bundled devtools-protocol version
2069
+ * @returns Message and suggestion
2070
+ */
2071
+ export function cdpMethodNotInBundledProtocolError(method, protocolVersion) {
2072
+ return {
2073
+ message: `Method '${method}' is not in the bundled protocol (devtools-protocol ${protocolVersion})`,
2074
+ suggestion: `bdg cdp ${method} sends it to Chrome as is, which may still have it. Methods bdg knows: bdg cdp --search <keyword>`,
2075
+ };
2076
+ }
1885
2077
  /**
1886
2078
  * The skill file is not where the package should have it (a broken or
1887
2079
  * partial install).