browser-debugger-cli 0.15.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 (133) hide show
  1. package/.claude/skills/bdg/SKILL.md +2 -1
  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 +200 -133
  11. package/dist/commands/cleanup.js +18 -4
  12. package/dist/commands/dom/formInteraction.js +8 -4
  13. package/dist/commands/dom/helpers/index.d.ts +4 -4
  14. package/dist/commands/dom/helpers/index.js +3 -3
  15. package/dist/commands/dom/helpers/query.d.ts +2 -2
  16. package/dist/commands/dom/helpers/query.js +2 -2
  17. package/dist/commands/dom/helpers/screenshot.d.ts +21 -26
  18. package/dist/commands/dom/helpers/screenshot.js +50 -668
  19. package/dist/commands/dom/screenshot.js +56 -36
  20. package/dist/commands/optionBehaviors.js +18 -8
  21. package/dist/commands/shared/CommandRunner.d.ts +5 -0
  22. package/dist/commands/shared/CommandRunner.js +18 -3
  23. package/dist/commands/shared/interrupt.d.ts +40 -0
  24. package/dist/commands/shared/interrupt.js +73 -0
  25. package/dist/commands/shared/optionTypes.d.ts +2 -0
  26. package/dist/commands/shared/startHelpers.d.ts +26 -3
  27. package/dist/commands/shared/startHelpers.js +145 -23
  28. package/dist/commands/types.d.ts +5 -0
  29. package/dist/connection/cdp.js +1 -16
  30. package/dist/connection/chromeIdentity.d.ts +24 -5
  31. package/dist/connection/chromeIdentity.js +53 -22
  32. package/dist/connection/launcher.d.ts +34 -1
  33. package/dist/connection/launcher.js +98 -10
  34. package/dist/connection/typed-cdp.d.ts +3 -2
  35. package/dist/constants.d.ts +1 -1
  36. package/dist/constants.js +1 -1
  37. package/dist/daemon/SessionController.d.ts +10 -5
  38. package/dist/daemon/SessionController.js +15 -8
  39. package/dist/daemon/ipcServer.js +1 -1
  40. package/dist/daemon/launcher.d.ts +5 -0
  41. package/dist/daemon/launcher.js +8 -1
  42. package/dist/daemon/session/Session.d.ts +5 -1
  43. package/dist/daemon/session/Session.js +9 -8
  44. package/dist/daemon/session/TelemetryStore.d.ts +5 -0
  45. package/dist/daemon/session/TelemetryStore.js +4 -0
  46. package/dist/daemon/session/captureGate.d.ts +59 -0
  47. package/dist/daemon/session/captureGate.js +96 -0
  48. package/dist/daemon/session/chromeConnection.d.ts +16 -1
  49. package/dist/daemon/session/chromeConnection.js +34 -4
  50. package/dist/daemon/session/collectors.d.ts +15 -0
  51. package/dist/daemon/session/collectors.js +39 -2
  52. package/dist/daemon/session/commandRegistry.d.ts +14 -1
  53. package/dist/daemon/session/commandRegistry.js +46 -11
  54. package/dist/daemon/session/downloads.d.ts +32 -0
  55. package/dist/daemon/session/downloads.js +96 -0
  56. package/dist/daemon/session/interactions.d.ts +3 -2
  57. package/dist/daemon/session/interactions.js +7 -2
  58. package/dist/daemon/session/plugins.js +6 -0
  59. package/dist/daemon.js +12843 -11482
  60. package/dist/errors/CommandError.d.ts +2 -0
  61. package/dist/errors/issues.d.ts +1 -1
  62. package/dist/errors/messages.d.ts +58 -0
  63. package/dist/errors/messages.js +112 -0
  64. package/dist/index.js +999 -1020
  65. package/dist/ipc/client.d.ts +14 -1
  66. package/dist/ipc/client.js +21 -4
  67. package/dist/ipc/protocol/commands.d.ts +32 -2
  68. package/dist/ipc/protocol/commands.js +1 -0
  69. package/dist/ipc/protocol/domTypes.d.ts +24 -1
  70. package/dist/ipc/session/queries.d.ts +3 -0
  71. package/dist/ipc/session/types.d.ts +5 -0
  72. package/dist/ipc/transport/IPCError.d.ts +9 -0
  73. package/dist/ipc/transport/IPCError.js +12 -0
  74. package/dist/ipc/transport/errors.d.ts +2 -1
  75. package/dist/ipc/transport/errors.js +4 -1
  76. package/dist/ipc/transport/index.d.ts +4 -2
  77. package/dist/ipc/transport/index.js +13 -3
  78. package/dist/runtime/dom/actionEffects.d.ts +48 -9
  79. package/dist/runtime/dom/actionEffects.js +269 -34
  80. package/dist/runtime/dom/actionEffectsScripts.d.ts +45 -0
  81. package/dist/runtime/dom/actionEffectsScripts.js +101 -2
  82. package/dist/runtime/dom/captureArea.d.ts +35 -0
  83. package/dist/runtime/dom/captureArea.js +203 -0
  84. package/dist/runtime/dom/elementInfo.d.ts +10 -8
  85. package/dist/runtime/dom/elementInfo.js +8 -6
  86. package/dist/runtime/dom/formDiscovery.d.ts +1 -1
  87. package/dist/runtime/page/bdgWorld.d.ts +9 -0
  88. package/dist/runtime/page/bdgWorld.js +11 -0
  89. package/dist/runtime/page/captureEmulation.d.ts +119 -0
  90. package/dist/runtime/page/captureEmulation.js +189 -0
  91. package/dist/runtime/page/captureScroll.d.ts +24 -0
  92. package/dist/runtime/page/captureScroll.js +124 -0
  93. package/dist/runtime/page/screenshot.d.ts +41 -0
  94. package/dist/runtime/page/screenshot.js +394 -0
  95. package/dist/session/paths.d.ts +14 -0
  96. package/dist/session/paths.js +25 -0
  97. package/dist/telemetry/downloads.d.ts +127 -0
  98. package/dist/telemetry/downloads.js +265 -0
  99. package/dist/telemetry/har/builder.js +22 -7
  100. package/dist/telemetry/har/sanitize.d.ts +7 -3
  101. package/dist/telemetry/har/sanitize.js +52 -6
  102. package/dist/telemetry/har/sanitizeBody.d.ts +47 -7
  103. package/dist/telemetry/har/sanitizeBody.js +429 -56
  104. package/dist/telemetry/har/types.d.ts +2 -0
  105. package/dist/telemetry/network.d.ts +4 -4
  106. package/dist/telemetry/network.js +38 -4
  107. package/dist/telemetry/networkRetention.d.ts +35 -14
  108. package/dist/telemetry/networkRetention.js +62 -26
  109. package/dist/types.d.ts +9 -14
  110. package/dist/ui/OutputBuilder.d.ts +3 -2
  111. package/dist/ui/OutputBuilder.js +4 -3
  112. package/dist/ui/formatters/cdp.d.ts +32 -9
  113. package/dist/ui/formatters/cdp.js +77 -6
  114. package/dist/ui/formatters/details.js +7 -15
  115. package/dist/ui/formatters/preview.d.ts +2 -0
  116. package/dist/ui/formatters/preview.js +7 -1
  117. package/dist/ui/formatters/status.js +6 -1
  118. package/dist/ui/formatting.d.ts +7 -0
  119. package/dist/ui/formatting.js +13 -0
  120. package/dist/ui/logging/logger.d.ts +1 -1
  121. package/dist/ui/messages/chrome.d.ts +13 -0
  122. package/dist/ui/messages/chrome.js +26 -0
  123. package/dist/ui/messages/commands.d.ts +71 -3
  124. package/dist/ui/messages/commands.js +98 -3
  125. package/dist/ui/messages/networkMessages.d.ts +24 -5
  126. package/dist/ui/messages/networkMessages.js +31 -8
  127. package/dist/utils/async.d.ts +3 -2
  128. package/dist/utils/async.js +16 -3
  129. package/dist/utils/http.d.ts +11 -4
  130. package/dist/utils/http.js +5 -3
  131. package/package.json +18 -4
  132. /package/dist/{commands/dom → runtime/page}/screenshotResize.d.ts +0 -0
  133. /package/dist/{commands/dom → runtime/page}/screenshotResize.js +0 -0
@@ -56,9 +56,10 @@ bdg page info # URL and title
56
56
  Page: navigated to https://app.test/secure (200) # navigation (or "URL changed ... (same document)")
57
57
  New text: "Your password is invalid!" (div#flash) # alert/status/aria-live messages that appeared
58
58
  ⚠ Element Clicked (no visible effect observed ...) # nothing changed - wrong element or a broken handler
59
+ Download: report.txt → ~/.bdg/downloads/report.txt (completed, 15 B) # files go to <session dir>/downloads
59
60
  ```
60
61
 
61
- - In `--json`: `navigation`, `messages`, `effect: "none"` and pending work (timers, spinners) are fields on `data`.
62
+ - In `--json`: `navigation`, `messages`, `downloads`, `effect: "none"` and pending work (timers, spinners) are fields on `data`.
62
63
  - Results the page shows later are not waited for: follow up with `bdg dom wait`.
63
64
 
64
65
  ```bash
@@ -0,0 +1,92 @@
1
+ /**
2
+ * What `bdg cdp <name>` calls: the bundled protocol follows Chromium's
3
+ * tip of tree, so the user's Chrome can have methods it lacks (and lack
4
+ * methods it has). A well-formed name is sent even when the schema does not
5
+ * know it, unless it is a close typo of a method or domain the schema knows.
6
+ */
7
+ /** What a `Domain.method` name resolves to */
8
+ export type MethodTarget =
9
+ /** A method in the bundled protocol, with its casing */
10
+ {
11
+ kind: 'known';
12
+ method: string;
13
+ }
14
+ /** A well-formed method the bundled protocol lacks, sent as typed (known domain recased) */
15
+ | {
16
+ kind: 'unlisted';
17
+ method: string;
18
+ }
19
+ /**
20
+ * A close typo of bundled methods (suggestions may be empty when only the
21
+ * domain is close), with the method to send if the user insists
22
+ */
23
+ | {
24
+ kind: 'typo';
25
+ method: string;
26
+ suggestions: string[];
27
+ }
28
+ /** A protocol type, not a method */
29
+ | {
30
+ kind: 'type';
31
+ name: string;
32
+ }
33
+ /** Not `Domain.method` */
34
+ | {
35
+ kind: 'malformed';
36
+ };
37
+ /**
38
+ * Decide what `bdg cdp <name>` calls.
39
+ *
40
+ * @param input - Method name as typed (case-insensitive for bundled methods)
41
+ * @returns Known, unlisted, typo, type or malformed
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * resolveMethodTarget('network.getcookies'); // known Network.getCookies
46
+ * resolveMethodTarget('Storage.getRelatedWebsiteSets'); // unlisted: sent as is
47
+ * resolveMethodTarget('Network.getCookes'); // typo of Network.getCookies
48
+ * ```
49
+ */
50
+ export declare function resolveMethodTarget(input: string): MethodTarget;
51
+ /**
52
+ * Why Chrome may have answered that it has no method bdg sent (-32601), as
53
+ * far as the bundled protocol tells.
54
+ */
55
+ export type MissingMethodCause =
56
+ /** A bundled method: this Chrome is older than the bundled protocol (or the method is not for pages) */
57
+ {
58
+ kind: 'older';
59
+ }
60
+ /** A bundled method redirected to a method the protocol lacks, with methods close to that one */
61
+ | {
62
+ kind: 'deadRedirect';
63
+ target: string;
64
+ similar: string[];
65
+ }
66
+ /** A domain the bundled protocol lacks too, with bundled domains close to it */
67
+ | {
68
+ kind: 'unknownDomain';
69
+ domain: string;
70
+ similar: string[];
71
+ }
72
+ /** A method of a bundled domain the bundled protocol lacks; `oneCase` when typed in one case */
73
+ | {
74
+ kind: 'unlisted';
75
+ oneCase: boolean;
76
+ };
77
+ /**
78
+ * Why Chrome has no method bdg sent (it answered -32601): a bundled method
79
+ * this Chrome is older than, one redirected to a method the protocol lacks,
80
+ * a domain neither knows, or a method the bundled protocol lacks.
81
+ *
82
+ * @param method - Method as sent (`Domain.method`, a bundled domain recased)
83
+ * @returns The cause
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * missingMethodCause('Page.deleteCookie'); // deadRedirect to Network.deleteCookie
88
+ * missingMethodCause('Foo.bar'); // unknownDomain Foo
89
+ * ```
90
+ */
91
+ export declare function missingMethodCause(method: string): MissingMethodCause;
92
+ //# sourceMappingURL=methodTarget.d.ts.map
@@ -0,0 +1,159 @@
1
+ /**
2
+ * What `bdg cdp <name>` calls: the bundled protocol follows Chromium's
3
+ * tip of tree, so the user's Chrome can have methods it lacks (and lack
4
+ * methods it has). A well-formed name is sent even when the schema does not
5
+ * know it, unless it is a close typo of a method or domain the schema knows.
6
+ */
7
+ import { findCommand, findDomain, findType, loadProtocol, normalizeMethod, } from './protocol.js';
8
+ import { levenshteinDistance } from '../utils/levenshtein.js';
9
+ import { findSimilar } from '../utils/suggestions.js';
10
+ /** `Domain.method`: letters and digits, starting with a letter */
11
+ const METHOD_NAME = /^[A-Za-z][A-Za-z0-9]*\.[A-Za-z][A-Za-z0-9]*$/;
12
+ /**
13
+ * Most edits a name can be off a known one and still count as its typo: 1
14
+ * for names of up to 5 letters (so `Foo` is not taken for `Log`), else 2.
15
+ *
16
+ * @param name - Name as typed
17
+ * @returns Edit distance limit
18
+ */
19
+ function typoLimit(name) {
20
+ return name.length <= 5 ? 1 : 2;
21
+ }
22
+ /**
23
+ * Names close enough to count as typos of the input, closest first.
24
+ *
25
+ * @param input - Name as typed
26
+ * @param candidates - Known names
27
+ * @returns Close candidates
28
+ */
29
+ function closeNames(input, candidates) {
30
+ const lower = input.toLowerCase();
31
+ return candidates
32
+ .map((name) => ({ name, distance: levenshteinDistance(lower, name.toLowerCase()) }))
33
+ .filter(({ distance }) => distance > 0 && distance <= typoLimit(input))
34
+ .sort((a, b) => a.distance - b.distance)
35
+ .map(({ name }) => name);
36
+ }
37
+ /**
38
+ * Methods of a domain close to the typed method name.
39
+ *
40
+ * @param domainName - Domain with its schema casing
41
+ * @param methodName - Method part as typed
42
+ * @returns Full names of close methods
43
+ */
44
+ function closeMethods(domainName, methodName) {
45
+ const commands = findDomain(domainName)?.commands ?? [];
46
+ const exact = commands.find((c) => c.name.toLowerCase() === methodName.toLowerCase());
47
+ const names = exact
48
+ ? [exact.name]
49
+ : closeNames(methodName, commands.map((c) => c.name));
50
+ return names.map((name) => `${domainName}.${name}`);
51
+ }
52
+ /**
53
+ * Resolve a domain the schema does not know: a typo of a known domain, or a
54
+ * domain to send as is.
55
+ *
56
+ * @param domainName - Domain part as typed
57
+ * @param methodName - Method part as typed
58
+ * @returns Typo with suggested methods, or an unlisted method
59
+ */
60
+ function resolveUnknownDomain(domainName, methodName) {
61
+ const domains = closeNames(domainName, loadProtocol().domains.map((d) => d.domain));
62
+ const method = `${domainName}.${methodName}`;
63
+ if (domains.length === 0)
64
+ return { kind: 'unlisted', method };
65
+ return { kind: 'typo', method, suggestions: domains.flatMap((d) => closeMethods(d, methodName)) };
66
+ }
67
+ /**
68
+ * Decide what `bdg cdp <name>` calls.
69
+ *
70
+ * @param input - Method name as typed (case-insensitive for bundled methods)
71
+ * @returns Known, unlisted, typo, type or malformed
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * resolveMethodTarget('network.getcookies'); // known Network.getCookies
76
+ * resolveMethodTarget('Storage.getRelatedWebsiteSets'); // unlisted: sent as is
77
+ * resolveMethodTarget('Network.getCookes'); // typo of Network.getCookies
78
+ * ```
79
+ */
80
+ export function resolveMethodTarget(input) {
81
+ if (!METHOD_NAME.test(input))
82
+ return { kind: 'malformed' };
83
+ const known = normalizeMethod(input);
84
+ if (known)
85
+ return { kind: 'known', method: known };
86
+ const [domainName = '', methodName = ''] = input.split('.');
87
+ const domain = findDomain(domainName);
88
+ if (!domain)
89
+ return resolveUnknownDomain(domainName, methodName);
90
+ const type = findType(domain.domain, methodName);
91
+ if (type)
92
+ return { kind: 'type', name: `${domain.domain}.${type.id}` };
93
+ const method = `${domain.domain}.${methodName}`;
94
+ const suggestions = closeMethods(domain.domain, methodName);
95
+ return suggestions.length > 0
96
+ ? { kind: 'typo', method, suggestions }
97
+ : { kind: 'unlisted', method };
98
+ }
99
+ /**
100
+ * Names close to a name, for a "Did you mean" after Chrome refused it: up
101
+ * to half its length off (at most 3), so `Foo` is not taken for `Log`.
102
+ *
103
+ * @param name - Name as sent
104
+ * @param candidates - Known names
105
+ * @returns Close names, closest first
106
+ */
107
+ function similarNames(name, candidates) {
108
+ return findSimilar(name, candidates, {
109
+ maxDistance: Math.min(3, Math.max(1, Math.floor(name.length / 2))),
110
+ });
111
+ }
112
+ /**
113
+ * Whether a method name is all lower or all upper case, which a CDP method
114
+ * of more than one word never is (they are lowerCamelCase).
115
+ *
116
+ * @param methodName - Method part as sent
117
+ * @returns True for e.g. `getrelatedwebsitesets`
118
+ */
119
+ function isOneCase(methodName) {
120
+ return methodName === methodName.toLowerCase() || methodName === methodName.toUpperCase();
121
+ }
122
+ /**
123
+ * Why Chrome has no method bdg sent (it answered -32601): a bundled method
124
+ * this Chrome is older than, one redirected to a method the protocol lacks,
125
+ * a domain neither knows, or a method the bundled protocol lacks.
126
+ *
127
+ * @param method - Method as sent (`Domain.method`, a bundled domain recased)
128
+ * @returns The cause
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * missingMethodCause('Page.deleteCookie'); // deadRedirect to Network.deleteCookie
133
+ * missingMethodCause('Foo.bar'); // unknownDomain Foo
134
+ * ```
135
+ */
136
+ export function missingMethodCause(method) {
137
+ const [domainName = '', methodName = ''] = method.split('.');
138
+ const domain = findDomain(domainName);
139
+ if (!domain) {
140
+ const domains = loadProtocol().domains.map((d) => d.domain);
141
+ return {
142
+ kind: 'unknownDomain',
143
+ domain: domainName,
144
+ similar: similarNames(domainName, domains),
145
+ };
146
+ }
147
+ const command = findCommand(domain.domain, methodName);
148
+ if (!command)
149
+ return { kind: 'unlisted', oneCase: isOneCase(methodName) };
150
+ if (!command.redirect || findCommand(command.redirect, command.name))
151
+ return { kind: 'older' };
152
+ const targetMethods = findDomain(command.redirect)?.commands?.map((c) => c.name) ?? [];
153
+ return {
154
+ kind: 'deadRedirect',
155
+ target: `${command.redirect}.${command.name}`,
156
+ similar: similarNames(command.name, targetMethods).map((name) => `${command.redirect}.${name}`),
157
+ };
158
+ }
159
+ //# sourceMappingURL=methodTarget.js.map
@@ -5,7 +5,14 @@
5
5
  * devtools-protocol package. Provides utilities for domain/method lookup
6
6
  * and introspection.
7
7
  */
8
- import type { ProtocolSchema, Domain, Command } from './types.js';
8
+ import type { ProtocolSchema, Domain, Command, Type } from './types.js';
9
+ /**
10
+ * Version of the bundled devtools-protocol package, which names the Chromium
11
+ * revision its schema comes from.
12
+ *
13
+ * @returns e.g. '0.0.1710668'
14
+ */
15
+ export declare function getBundledProtocolVersion(): string;
9
16
  /**
10
17
  * Load the CDP protocol schema.
11
18
  *
@@ -53,6 +60,14 @@ export declare function findDomain(domainName: string): Domain | undefined;
53
60
  * ```
54
61
  */
55
62
  export declare function findCommand(domainName: string, commandName: string): Command | undefined;
63
+ /**
64
+ * Find a type within a domain (case-insensitive).
65
+ *
66
+ * @param domainName - Domain name (e.g., 'Network')
67
+ * @param typeName - Type id (e.g., 'CookieSameSite', 'cookiesamesite')
68
+ * @returns Type definition or undefined if not found
69
+ */
70
+ export declare function findType(domainName: string, typeName: string): Type | undefined;
56
71
  /**
57
72
  * Normalize a CDP method name to proper casing.
58
73
  *
@@ -10,6 +10,16 @@ import { createRequire } from 'module';
10
10
  import { dirname, join } from 'path';
11
11
  const require = createRequire(import.meta.url);
12
12
  let cachedProtocol = null;
13
+ /**
14
+ * Version of the bundled devtools-protocol package, which names the Chromium
15
+ * revision its schema comes from.
16
+ *
17
+ * @returns e.g. '0.0.1710668'
18
+ */
19
+ export function getBundledProtocolVersion() {
20
+ const packageJson = JSON.parse(readFileSync(require.resolve('devtools-protocol/package.json'), 'utf-8'));
21
+ return packageJson.version;
22
+ }
13
23
  /**
14
24
  * Load the CDP protocol schema.
15
25
  *
@@ -83,6 +93,17 @@ export function findCommand(domainName, commandName) {
83
93
  const normalized = commandName.toLowerCase();
84
94
  return domain.commands.find((c) => c.name.toLowerCase() === normalized);
85
95
  }
96
+ /**
97
+ * Find a type within a domain (case-insensitive).
98
+ *
99
+ * @param domainName - Domain name (e.g., 'Network')
100
+ * @param typeName - Type id (e.g., 'CookieSameSite', 'cookiesamesite')
101
+ * @returns Type definition or undefined if not found
102
+ */
103
+ export function findType(domainName, typeName) {
104
+ const normalized = typeName.toLowerCase();
105
+ return findDomain(domainName)?.types?.find((t) => t.id.toLowerCase() === normalized);
106
+ }
86
107
  /**
87
108
  * Normalize a CDP method name to proper casing.
88
109
  *
@@ -27,6 +27,16 @@ export interface MethodSchema {
27
27
  parameters: ParameterSchema[];
28
28
  /** Return value schema */
29
29
  returns: ReturnSchema[];
30
+ /**
31
+ * The method implementing this one (the schema's `redirect`) and its
32
+ * parameters; `resolved` is false when the protocol lacks that method
33
+ * (e.g. Page.deleteCookie names Network.deleteCookie)
34
+ */
35
+ redirect?: {
36
+ method: string;
37
+ resolved: boolean;
38
+ parameters: ParameterSchema[];
39
+ };
30
40
  /** Usage example (JSON) */
31
41
  example?: {
32
42
  command: string;
@@ -45,12 +55,43 @@ export interface ParameterSchema {
45
55
  required: boolean;
46
56
  /** Human-readable description */
47
57
  description?: string;
48
- /** Enum values (if type is enum) */
58
+ /** Enum values (inline, or of the referenced type) */
49
59
  enum?: string[];
60
+ /** Referenced protocol type with its domain (e.g. 'Network.CookieSameSite'), for `--describe` */
61
+ ref?: string;
62
+ /** Base type of the referenced type (e.g. 'number' for Network.TimeSinceEpoch, 'object') */
63
+ refType?: string;
50
64
  /** Array item type (if type is array) */
51
65
  items?: string;
52
66
  /** Deprecated flag */
53
67
  deprecated?: boolean;
68
+ /** Experimental flag */
69
+ experimental?: boolean;
70
+ }
71
+ /**
72
+ * Protocol type (`Network.CookieSameSite`, `Network.Cookie`) for agent consumption.
73
+ */
74
+ export interface TypeSchema {
75
+ /** Full type name (Domain.Type) */
76
+ name: string;
77
+ /** Domain name */
78
+ domain: string;
79
+ /** Type id */
80
+ id: string;
81
+ /** Base type (string, object, array, ...) */
82
+ baseType: string;
83
+ /** Human-readable description */
84
+ description?: string;
85
+ /** Whether type is experimental */
86
+ experimental?: boolean;
87
+ /** Whether type is deprecated */
88
+ deprecated?: boolean;
89
+ /** Enum values (string enums) */
90
+ enum?: string[];
91
+ /** Array item type */
92
+ items?: string;
93
+ /** Properties (object types) */
94
+ properties?: ParameterSchema[];
54
95
  }
55
96
  /**
56
97
  * Return value schema for agent consumption.
@@ -100,6 +141,19 @@ export interface DomainSummary {
100
141
  * ```
101
142
  */
102
143
  export declare function getMethodSchema(domainName: string, methodName: string): MethodSchema | undefined;
144
+ /**
145
+ * Get structured schema for a protocol type.
146
+ *
147
+ * @param domainName - Domain name (case-insensitive)
148
+ * @param typeName - Type id (case-insensitive)
149
+ * @returns Type schema or undefined if not found
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * getTypeSchema('Network', 'CookieSameSite')?.enum; // ['Strict', 'Lax', 'None']
154
+ * ```
155
+ */
156
+ export declare function getTypeSchema(domainName: string, typeName: string): TypeSchema | undefined;
103
157
  /**
104
158
  * Get all methods in a domain.
105
159
  *
@@ -7,7 +7,7 @@
7
7
  * - Self-describing tools
8
8
  * - Structured context without verbosity
9
9
  */
10
- import { loadProtocol, findDomain, findCommand } from './protocol.js';
10
+ import { loadProtocol, findDomain, findCommand, findType } from './protocol.js';
11
11
  /**
12
12
  * Get structured schema for a specific method.
13
13
  *
@@ -40,31 +40,20 @@ export function getMethodSchema(domainName, methodName) {
40
40
  * @returns Structured method schema
41
41
  */
42
42
  function buildMethodSchema(domainName, command) {
43
- const parameters = command.parameters?.map(paramToSchema) ?? [];
43
+ const parameters = command.parameters?.map((p) => paramToSchema(domainName, p)) ?? [];
44
44
  const returns = command.returns?.map(returnToSchema) ?? [];
45
- const example = {
46
- command: `bdg cdp ${domainName}.${command.name}`,
47
- };
48
- if (parameters.length > 0) {
49
- const exampleParams = {};
50
- parameters.forEach((p) => {
51
- if (!p.required)
52
- return; // Skip optional params in example
53
- exampleParams[p.name] = getExampleValue(p);
54
- });
55
- if (Object.keys(exampleParams).length > 0) {
56
- example.params = exampleParams;
57
- example.command += ` --params '${JSON.stringify(exampleParams)}'`;
58
- }
59
- }
45
+ const redirect = buildRedirect(command);
46
+ const exampleSource = parameters.length > 0 ? parameters : (redirect?.parameters ?? []);
60
47
  const schema = {
61
48
  name: `${domainName}.${command.name}`,
62
49
  domain: domainName,
63
50
  method: command.name,
64
51
  parameters,
65
52
  returns,
66
- example,
53
+ example: buildExample(`${domainName}.${command.name}`, exampleSource),
67
54
  };
55
+ if (redirect)
56
+ schema.redirect = redirect;
68
57
  if (command.description)
69
58
  schema.description = command.description;
70
59
  if (command.experimental)
@@ -74,24 +63,122 @@ function buildMethodSchema(domainName, command) {
74
63
  return schema;
75
64
  }
76
65
  /**
77
- * Convert protocol parameter to schema.
66
+ * The method a redirected command runs (e.g. DOM.highlightNode runs
67
+ * Overlay.highlightNode), with the parameters Chrome checks, and whether the
68
+ * protocol has that method.
69
+ *
70
+ * @param command - Command from protocol
71
+ * @returns Redirect target, or undefined when the command has none
72
+ */
73
+ function buildRedirect(command) {
74
+ if (!command.redirect)
75
+ return undefined;
76
+ const target = findCommand(command.redirect, command.name);
77
+ return {
78
+ method: `${command.redirect}.${command.name}`,
79
+ resolved: target !== undefined,
80
+ parameters: target?.parameters?.map((p) => paramToSchema(command.redirect ?? '', p)) ?? [],
81
+ };
82
+ }
83
+ /**
84
+ * Example command with the required parameters.
85
+ *
86
+ * @param methodName - Full method name
87
+ * @param parameters - Parameters to take the required ones from
88
+ * @returns Example command and its parameters
89
+ */
90
+ function buildExample(methodName, parameters) {
91
+ const example = { command: `bdg cdp ${methodName}` };
92
+ const required = parameters.filter((p) => p.required);
93
+ if (required.length === 0)
94
+ return example;
95
+ const exampleParams = Object.fromEntries(required.map((p) => [p.name, getExampleValue(p)]));
96
+ example.params = exampleParams;
97
+ example.command += ` --params '${JSON.stringify(exampleParams)}'`;
98
+ return example;
99
+ }
100
+ /**
101
+ * A protocol type a `$ref` names, resolved against the domain it is used in.
102
+ *
103
+ * @param domainName - Domain of the parameter (for refs without a domain)
104
+ * @param ref - `$ref` value, e.g. 'CookieSameSite' or 'Runtime.RemoteObject'
105
+ * @returns Full type name and definition, or undefined when the schema lacks it
106
+ */
107
+ function lookupRef(domainName, ref) {
108
+ const [refDomain, id] = ref.includes('.') ? ref.split('.') : [domainName, ref];
109
+ const type = refDomain && id ? findType(refDomain, id) : undefined;
110
+ return type && { name: `${refDomain}.${type.id}`, type };
111
+ }
112
+ /**
113
+ * Convert protocol parameter (or object property) to schema; a `$ref` gets its
114
+ * full type name and, for an enum type, its values.
115
+ *
116
+ * @param domainName - Domain the parameter belongs to
117
+ * @param param - Protocol parameter
118
+ * @returns Parameter schema
78
119
  */
79
- function paramToSchema(param) {
120
+ function paramToSchema(domainName, param) {
80
121
  const schema = {
81
122
  name: param.name,
82
123
  type: resolveType(param),
83
124
  required: !param.optional,
84
125
  };
126
+ const referenced = param.$ref ? lookupRef(domainName, param.$ref) : undefined;
127
+ const values = param.enum ?? referenced?.type.enum;
85
128
  if (param.description)
86
129
  schema.description = param.description;
87
130
  if (param.deprecated)
88
131
  schema.deprecated = param.deprecated;
89
- if (param.enum)
90
- schema.enum = param.enum;
132
+ if (param.experimental)
133
+ schema.experimental = param.experimental;
134
+ if (values)
135
+ schema.enum = values;
136
+ if (referenced) {
137
+ schema.ref = referenced.name;
138
+ schema.refType = referenced.type.type;
139
+ }
91
140
  if (param.items)
92
141
  schema.items = resolveType(param.items);
93
142
  return schema;
94
143
  }
144
+ /**
145
+ * Get structured schema for a protocol type.
146
+ *
147
+ * @param domainName - Domain name (case-insensitive)
148
+ * @param typeName - Type id (case-insensitive)
149
+ * @returns Type schema or undefined if not found
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * getTypeSchema('Network', 'CookieSameSite')?.enum; // ['Strict', 'Lax', 'None']
154
+ * ```
155
+ */
156
+ export function getTypeSchema(domainName, typeName) {
157
+ const domain = findDomain(domainName);
158
+ const type = domain && findType(domain.domain, typeName);
159
+ if (!domain || !type)
160
+ return undefined;
161
+ const schema = {
162
+ name: `${domain.domain}.${type.id}`,
163
+ domain: domain.domain,
164
+ id: type.id,
165
+ baseType: type.type,
166
+ };
167
+ if (type.description)
168
+ schema.description = type.description;
169
+ if (type.experimental)
170
+ schema.experimental = type.experimental;
171
+ if (type.deprecated)
172
+ schema.deprecated = type.deprecated;
173
+ if (type.enum)
174
+ schema.enum = type.enum;
175
+ if (type.items)
176
+ schema.items = resolveType(type.items);
177
+ if (type.properties) {
178
+ schema.properties = type.properties.map((p) => paramToSchema(domain.domain, p));
179
+ }
180
+ return schema;
181
+ }
95
182
  /**
96
183
  * Convert protocol return value to schema.
97
184
  */
@@ -120,7 +207,24 @@ function resolveType(typeRef) {
120
207
  return typeRef.type ?? 'any';
121
208
  }
122
209
  /**
123
- * Get example value for a parameter type.
210
+ * Example values for parameters whose name says what a realistic value is,
211
+ * where the type's placeholder would do something else (`width: 0` disables
212
+ * `Emulation.setDeviceMetricsOverride`, `url: "example"` is no URL).
213
+ */
214
+ const EXAMPLE_VALUES = {
215
+ width: 1280,
216
+ height: 800,
217
+ x: 100,
218
+ y: 100,
219
+ deviceScaleFactor: 1,
220
+ scale: 1,
221
+ timeout: 5000,
222
+ responseCode: 200,
223
+ url: 'https://example.com',
224
+ };
225
+ /**
226
+ * Get example value for a parameter: a realistic value for its name, else
227
+ * one for its type (1 for numbers, so it never means "off").
124
228
  *
125
229
  * @param param - Parameter schema
126
230
  * @returns Example value
@@ -129,12 +233,17 @@ function getExampleValue(param) {
129
233
  if (param.enum && param.enum.length > 0) {
130
234
  return param.enum[0];
131
235
  }
132
- switch (param.type) {
236
+ const type = param.refType ?? param.type;
237
+ const named = Object.hasOwn(EXAMPLE_VALUES, param.name) ? EXAMPLE_VALUES[param.name] : undefined;
238
+ const namedType = typeof named === 'number' ? ['integer', 'number'] : ['string'];
239
+ if (named !== undefined && namedType.includes(type))
240
+ return named;
241
+ switch (type) {
133
242
  case 'string':
134
243
  return 'example';
135
244
  case 'integer':
136
245
  case 'number':
137
- return 0;
246
+ return 1;
138
247
  case 'boolean':
139
248
  return true;
140
249
  case 'array':
@@ -69,7 +69,7 @@ export interface Command {
69
69
  experimental?: boolean;
70
70
  /** Whether command is deprecated */
71
71
  deprecated?: boolean;
72
- /** URL to specification */
72
+ /** Domain whose command of the same name implements this one (e.g. 'Overlay' for DOM.highlightNode) */
73
73
  redirect?: string;
74
74
  }
75
75
  /**
@@ -105,6 +105,8 @@ export interface Type {
105
105
  items?: TypeRef;
106
106
  /** Whether type is experimental */
107
107
  experimental?: boolean;
108
+ /** Whether type is deprecated */
109
+ deprecated?: boolean;
108
110
  }
109
111
  /**
110
112
  * CDP Domain (e.g., Network, Runtime, DOM).