@reclaimprotocol/agent 0.1.17 → 0.1.20

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 (171) hide show
  1. package/README.md +6 -2
  2. package/lib/authoring/backend.d.ts +4 -0
  3. package/lib/authoring/tools.js +4 -1
  4. package/lib/cdp/capture.d.ts +2 -2
  5. package/lib/cdp/capture.js +25 -21
  6. package/lib/cdp/client.d.ts +39 -1
  7. package/lib/cdp/client.js +125 -1
  8. package/lib/consts.d.ts +7 -0
  9. package/lib/consts.js +15 -0
  10. package/lib/mcp/api/operations.gen.js +33 -9
  11. package/lib/mcp/instructions.js +27 -3
  12. package/lib/mcp/start.js +12 -8
  13. package/lib/mcp/tools/agent/attach.d.ts +18 -4
  14. package/lib/mcp/tools/agent/attach.js +142 -52
  15. package/lib/mcp/tools/agent/build.d.ts +1 -1
  16. package/lib/mcp/tools/agent/build.js +5 -3
  17. package/lib/mcp/tools/agent/capture.d.ts +1 -0
  18. package/lib/mcp/tools/agent/capture.js +8 -1
  19. package/lib/mcp/tools/agent/eval.js +2 -3
  20. package/lib/mcp/tools/agent/how-it-works.d.ts +1 -1
  21. package/lib/mcp/tools/agent/how-it-works.js +1 -1
  22. package/lib/mcp/tools/agent/publish.js +55 -1
  23. package/lib/mcp/tools/agent/session.d.ts +2 -2
  24. package/lib/mcp/tools/agent/session.js +21 -5
  25. package/lib/mcp/tools/agent/shared.js +4 -6
  26. package/lib/mcp/tools/authenticate/authenticate.d.ts +1 -1
  27. package/lib/mcp/tools/authenticate/authenticate.js +10 -4
  28. package/lib/mcp/tools/authenticate/builder-access.d.ts +8 -0
  29. package/lib/mcp/tools/authenticate/builder-access.js +31 -0
  30. package/lib/mcp/tools/authenticate/index.d.ts +1 -0
  31. package/lib/mcp/tools/authenticate/index.js +1 -0
  32. package/lib/mcp/tools/mode/mode.d.ts +3 -2
  33. package/lib/mcp/tools/mode/mode.js +24 -4
  34. package/lib/old/login-cdp.js +11 -3
  35. package/lib/old/to-register.d.ts +16 -8
  36. package/lib/old/to-register.js +29 -21
  37. package/lib/old/tools/publish.js +109 -9
  38. package/lib/provider/draft.d.ts +20 -0
  39. package/lib/provider/draft.js +75 -51
  40. package/lib/provider/index.d.ts +1 -1
  41. package/lib/provider/index.js +1 -1
  42. package/lib/provider/injection-doc.js +4 -3
  43. package/lib/provider/schema.d.ts +26 -1
  44. package/lib/provider/secrets.d.ts +37 -0
  45. package/lib/provider/secrets.js +147 -6
  46. package/lib/provider/to-version.d.ts +26 -2
  47. package/lib/provider/to-version.js +29 -5
  48. package/package.json +2 -2
  49. package/skill/SKILL.builder.md +43 -95
  50. package/skill/SKILL.common.md +102 -0
  51. package/skill/SKILL.old.md +20 -74
  52. package/skill/builder-mode.md +4 -2
  53. package/skill/injection-api.md +95 -10
  54. package/skill/old-mode.md +5 -3
  55. package/src/authoring/backend.ts +4 -0
  56. package/src/authoring/tools.ts +4 -1
  57. package/src/cdp/capture.ts +24 -24
  58. package/src/cdp/client.ts +197 -2
  59. package/src/consts.ts +20 -0
  60. package/src/mcp/api/operations.gen.ts +33 -9
  61. package/src/mcp/instructions.ts +36 -3
  62. package/src/mcp/start.ts +13 -8
  63. package/src/mcp/tools/agent/attach.ts +198 -57
  64. package/src/mcp/tools/agent/build.ts +9 -2
  65. package/src/mcp/tools/agent/capture.ts +10 -1
  66. package/src/mcp/tools/agent/eval.ts +2 -3
  67. package/src/mcp/tools/agent/how-it-works.ts +1 -1
  68. package/src/mcp/tools/agent/publish.ts +64 -1
  69. package/src/mcp/tools/agent/session.ts +29 -8
  70. package/src/mcp/tools/agent/shared.ts +5 -10
  71. package/src/mcp/tools/authenticate/authenticate.ts +14 -4
  72. package/src/mcp/tools/authenticate/builder-access.ts +42 -0
  73. package/src/mcp/tools/authenticate/index.ts +4 -0
  74. package/src/mcp/tools/mode/mode.ts +28 -4
  75. package/src/old/login-cdp.ts +13 -3
  76. package/src/old/to-register.ts +50 -27
  77. package/src/old/tools/publish.ts +131 -9
  78. package/src/provider/draft.ts +98 -56
  79. package/src/provider/index.ts +9 -1
  80. package/src/provider/injection-doc.ts +4 -3
  81. package/src/provider/schema.ts +27 -1
  82. package/src/provider/secrets.ts +171 -6
  83. package/src/provider/to-version.ts +53 -7
  84. package/lib/authoring/find.d.ts +0 -3
  85. package/lib/authoring/find.js +0 -54
  86. package/lib/authoring/propose.d.ts +0 -3
  87. package/lib/authoring/propose.js +0 -109
  88. package/lib/authoring/replay.d.ts +0 -10
  89. package/lib/authoring/replay.js +0 -34
  90. package/lib/cli/args.d.ts +0 -14
  91. package/lib/cli/args.js +0 -19
  92. package/lib/cli/commands.d.ts +0 -1
  93. package/lib/cli/commands.js +0 -19
  94. package/lib/cli.d.ts +0 -1
  95. package/lib/cli.js +0 -7
  96. package/lib/mcp/credentials/authenticate.d.ts +0 -3
  97. package/lib/mcp/credentials/authenticate.js +0 -108
  98. package/lib/mcp/credentials/build.d.ts +0 -5
  99. package/lib/mcp/credentials/build.js +0 -18
  100. package/lib/mcp/credentials/cache.d.ts +0 -70
  101. package/lib/mcp/credentials/cache.js +0 -131
  102. package/lib/mcp/credentials/env-file.d.ts +0 -25
  103. package/lib/mcp/credentials/env-file.js +0 -71
  104. package/lib/mcp/credentials/import.d.ts +0 -2
  105. package/lib/mcp/credentials/import.js +0 -52
  106. package/lib/mcp/credentials/issue.d.ts +0 -2
  107. package/lib/mcp/credentials/issue.js +0 -84
  108. package/lib/mcp/credentials/keypair.d.ts +0 -17
  109. package/lib/mcp/credentials/keypair.js +0 -48
  110. package/lib/mcp/credentials/link.d.ts +0 -3
  111. package/lib/mcp/credentials/link.js +0 -107
  112. package/lib/mcp/credentials/list-cached.d.ts +0 -2
  113. package/lib/mcp/credentials/list-cached.js +0 -55
  114. package/lib/mcp/credentials/owner-key.d.ts +0 -23
  115. package/lib/mcp/credentials/owner-key.js +0 -58
  116. package/lib/mcp/credentials/paths.d.ts +0 -12
  117. package/lib/mcp/credentials/paths.js +0 -35
  118. package/lib/mcp/credentials/poll.d.ts +0 -27
  119. package/lib/mcp/credentials/poll.js +0 -61
  120. package/lib/mcp/credentials/register.d.ts +0 -18
  121. package/lib/mcp/credentials/register.js +0 -30
  122. package/lib/mcp/credentials/resolve-owner-key.d.ts +0 -12
  123. package/lib/mcp/credentials/resolve-owner-key.js +0 -68
  124. package/lib/mcp/credentials/session-cache.d.ts +0 -14
  125. package/lib/mcp/credentials/session-cache.js +0 -42
  126. package/lib/mcp/credentials/status.d.ts +0 -3
  127. package/lib/mcp/credentials/status.js +0 -76
  128. package/lib/mcp/register.d.ts +0 -38
  129. package/lib/mcp/register.js +0 -80
  130. package/lib/mcp/tools/analyze.d.ts +0 -3
  131. package/lib/mcp/tools/analyze.js +0 -26
  132. package/lib/mcp/tools/attach.d.ts +0 -11
  133. package/lib/mcp/tools/attach.js +0 -72
  134. package/lib/mcp/tools/capture.d.ts +0 -10
  135. package/lib/mcp/tools/capture.js +0 -142
  136. package/lib/mcp/tools/eval.d.ts +0 -5
  137. package/lib/mcp/tools/eval.js +0 -127
  138. package/lib/mcp/tools/find.d.ts +0 -3
  139. package/lib/mcp/tools/find.js +0 -60
  140. package/lib/mcp/tools/owner-key.d.ts +0 -2
  141. package/lib/mcp/tools/owner-key.js +0 -63
  142. package/lib/mcp/tools/proof.d.ts +0 -3
  143. package/lib/mcp/tools/proof.js +0 -214
  144. package/lib/mcp/tools/propose.d.ts +0 -9
  145. package/lib/mcp/tools/propose.js +0 -75
  146. package/lib/mcp/tools/publish.d.ts +0 -3
  147. package/lib/mcp/tools/publish.js +0 -59
  148. package/lib/mcp/tools/replay.d.ts +0 -3
  149. package/lib/mcp/tools/replay.js +0 -46
  150. package/lib/mcp/tools/session.d.ts +0 -10
  151. package/lib/mcp/tools/session.js +0 -29
  152. package/lib/mcp/tools/verification/diagnose.d.ts +0 -11
  153. package/lib/mcp/tools/verification/diagnose.js +0 -132
  154. package/lib/mcp/verifications/build.d.ts +0 -5
  155. package/lib/mcp/verifications/build.js +0 -14
  156. package/lib/mcp/verifications/create.d.ts +0 -3
  157. package/lib/mcp/verifications/create.js +0 -57
  158. package/lib/mcp/verifications/find.d.ts +0 -3
  159. package/lib/mcp/verifications/find.js +0 -37
  160. package/lib/mcp/verifications/get.d.ts +0 -3
  161. package/lib/mcp/verifications/get.js +0 -26
  162. package/lib/mcp/verifications/update.d.ts +0 -3
  163. package/lib/mcp/verifications/update.js +0 -78
  164. package/lib/old/tools/get-version-config.d.ts +0 -17
  165. package/lib/old/tools/get-version-config.js +0 -47
  166. package/lib/routes.gen.d.ts +0 -271
  167. package/lib/routes.gen.js +0 -73
  168. package/lib/types/openapi.d.ts +0 -4
  169. package/lib/types/openapi.gen.d.ts +0 -3967
  170. package/lib/types/openapi.gen.js +0 -5
  171. package/lib/types/openapi.js +0 -1
@@ -14,9 +14,10 @@
14
14
  * It also covers the HAWKEYE-style live-interception path (`injectionType` /
15
15
  * `interceptorType`, `disableRequestReplay` / `isDocumentRequestReplayEnabled`)
16
16
  * and `bodySniff`, reverse-engineered from the old-devtools Prisma schema,
17
- * controller code, and dashboard field hints — neither publish tool exposes
18
- * these as inputs (both only build the standard replay flow), so this is
19
- * read-the-field-and-recognize-it documentation, not authoring guidance.
17
+ * controller code, and dashboard field hints. The replay flag IS settable via
18
+ * the publish tools (`disableRequestReplay` on old-devtools — add-version or
19
+ * the register follow-up; `interceptorOptions` on the builder), so this is
20
+ * recognition + authoring guidance for the remaining internals.
20
21
  */
21
22
  import { readFileSync } from 'node:fs';
22
23
  import { fileURLToPath } from 'node:url';
@@ -11,6 +11,24 @@ export type HttpMethod = HttpParams['method'];
11
11
  * jsonPath/xPath belong on the redaction, not here.
12
12
  */
13
13
  export type ResponseMatch = HttpParams['responseMatches'][number];
14
+ /**
15
+ * A response match as drafted for PUBLISH: the attestor's match plus
16
+ * `isOptional` — a backend-side matcher flag (both the old devtools backend
17
+ * and the builder store it; the attestor's own params have no such field, so
18
+ * `propose_provider` drafts never set it — only an explicit publish input
19
+ * does). Default false on both backends.
20
+ */
21
+ export type DraftResponseMatch = ResponseMatch & {
22
+ isOptional?: boolean;
23
+ };
24
+ /** How the verification client supplies cookies/auth when replaying a
25
+ * request. Both backends accept the same enum (old devtools on
26
+ * `requestData`, builder on `RequestSelection`); default `include`. */
27
+ export type WebCredentials = 'omit' | 'same-origin' | 'include';
28
+ /** Old-devtools `urlType` for a requestData entry. The builder backend has
29
+ * no such field (templating is implicit in the URL's `{{param}}`
30
+ * placeholders), so the builder translator ignores it. */
31
+ export type OldUrlType = 'REGEX' | 'CONSTANT' | 'TEMPLATE';
14
32
  /**
15
33
  * Selector telling the prover which portion of the response to reveal:
16
34
  * `xPath`/`jsonPath` narrows the slice, `regex` (with named groups) matches
@@ -59,8 +77,15 @@ export interface ReclaimProvider {
59
77
  method: HttpMethod;
60
78
  headers?: Record<string, string>;
61
79
  body?: string;
62
- responseMatches: ResponseMatch[];
80
+ responseMatches: DraftResponseMatch[];
63
81
  responseRedactions?: ResponseRedaction[];
82
+ /** How the verification client supplies cookies/auth on replay. Both
83
+ * backends default to `include` when unset. */
84
+ credentials?: WebCredentials;
85
+ /** Old-devtools-only url type override (`REGEX`/`CONSTANT`/`TEMPLATE`).
86
+ * Auto-derived from `{{param}}` placeholders when unset; ignored by the
87
+ * builder backend. */
88
+ urlType?: OldUrlType;
64
89
  /** Public param refs (templated into URL/body), populated by draft layer. */
65
90
  paramValues?: Record<string, string>;
66
91
  /** Redaction mode for the transcript (attestor default: 'key-update'). */
@@ -1,5 +1,42 @@
1
+ import type { ReclaimProvider } from './schema.ts';
1
2
  export declare function classifyHeader(name: string): boolean;
3
+ /** Drop {@link STRIP_REQUEST_HEADERS} and HTTP/2 pseudo-headers. Call this on
4
+ * the RAW captured headers before {@link splitSecrets} — both the draft-time
5
+ * authoring flow and the live per-user verification capture need it, so
6
+ * neither ends up sending a duplicate `Host` or an invalid `:authority` to
7
+ * the attestor via either the public or the secret channel. */
8
+ export declare function stripTransportHeaders(headers: Record<string, string>): Record<string, string>;
2
9
  export declare function splitSecrets(headers: Record<string, string>): {
3
10
  secrets: Record<string, string>;
4
11
  publics: Record<string, string>;
5
12
  };
13
+ /** Total characters write-redaction can hide from the attestor, summed
14
+ * ACROSS EVERY secret-classified value used in the URL — not a per-value
15
+ * cap. Default mode (`'key-update'`, also what an unset field resolves to)
16
+ * caps at 2; `'zk'` at 12. At or under the budget the overlap is genuinely
17
+ * hidden; over it, the value (or the combination of values) is effectively
18
+ * still visible to the attestor regardless of secret-marking. */
19
+ export declare function secretUrlCharBudget(writeRedactionMode: ReclaimProvider['writeRedactionMode']): number;
20
+ /** A `paramValues`/context key is secret iff its name contains `SECRET`
21
+ * (case-insensitive) — e.g. `SECRET_apiKey`, `context.SECRET_apiKey`. Same
22
+ * naming-convention classifier reclaim-inapp-sdk and reclaim-portal use for
23
+ * their `witnessParams`/`paramValues` maps (no separate boolean flag). */
24
+ export declare function classifyParamName(name: string): boolean;
25
+ /** Split a `paramValues` map (bare `{{name}}` / `{{context.<name>}}` entries)
26
+ * into public (→ `params.paramValues`, revealed to the attestor) and secret
27
+ * (→ `secretParams.paramValues`) by {@link classifyParamName}. A secret
28
+ * value used in the URL is still hidden — up to {@link secretUrlCharBudget}
29
+ * characters, summed across every such value in that URL. */
30
+ export declare function splitSecretParamValues(paramValues: Record<string, string>): {
31
+ secrets: Record<string, string>;
32
+ publics: Record<string, string>;
33
+ };
34
+ /** Reject a proof attempt whose URL/geoLocation templates SECRET-named
35
+ * context param(s) whose ACTUAL values (now known — the consumer supplied
36
+ * them at session-create) exceed the write-redaction budget once summed.
37
+ * Structural placement (which params end up in the URL) is knowable at
38
+ * publish time and isn't rejected there — only the real values decide
39
+ * whether it fits, and those only exist once a verification session is
40
+ * underway. Checks the placeholder TOKEN (`{{<key>}}`), not a value search —
41
+ * the URL/geoLocation explicitly reference the param by name. */
42
+ export declare function assertSecretParamValuesFitUrlBudget(url: string, geoLocation: string | undefined, secretParamValues: Record<string, string>, writeRedactionMode: ReclaimProvider['writeRedactionMode']): void;
@@ -1,11 +1,89 @@
1
- const SECRET_EXACT = new Set(['cookie', 'authorization', 'proxy-authorization']);
2
- const SECRET_SUFFIXES = ['-token', '-key', '-secret', '-auth'];
1
+ /** Headers safe to reveal to the attestor unredacted — everything else
2
+ * (`Cookie`, `Authorization`, any custom header, even ones that look inert
3
+ * like `Content-Type`) is secret by default. Allowlist, not a denylist:
4
+ * same exact list `reclaim-inapp-sdk` (`_PUBLIC_HEADERS_ALLOW_LIST`,
5
+ * `request.dart`) and `reclaim-portal` (`DEFAULT_PUBLIC_HEADERS`,
6
+ * `claim-builder.ts`) use for their own `witnessParams`/header split. */
7
+ const PUBLIC_HEADERS = new Set([
8
+ 'user-agent',
9
+ 'accept',
10
+ 'accept-language',
11
+ 'accept-encoding',
12
+ 'sec-fetch-mode',
13
+ 'sec-fetch-site',
14
+ 'sec-fetch-user',
15
+ 'origin',
16
+ 'x-requested-with',
17
+ 'sec-ch-ua',
18
+ 'sec-ch-ua-mobile',
19
+ ]);
3
20
  export function classifyHeader(name) {
4
- const lower = name.toLowerCase();
5
- if (SECRET_EXACT.has(lower)) {
6
- return true;
21
+ return !PUBLIC_HEADERS.has(name.toLowerCase());
22
+ }
23
+ /** Headers that must NOT survive into EITHER the public or secret side —
24
+ * structural/transport, never a credential. Three kinds:
25
+ * - Conditional headers (`if-none-match`/`if-modified-since`/…): a captured
26
+ * cached ETag/date makes the origin answer 304/412 when the attestor
27
+ * re-issues, and the attestor treats non-2xx as failure. We always want
28
+ * the full fresh response.
29
+ * - Transfer headers the ATTESTOR sets itself (`connection: close`,
30
+ * `accept-encoding: identity`). Passing our own duplicates/collides with
31
+ * the request the attestor builds, so leave them out.
32
+ * - Host / framing headers the TRANSPORT owns (`host`, `content-length`,
33
+ * `transfer-encoding`). The attestor derives `Host` from the URL and sets
34
+ * its own; a baked `Host` produces a DUPLICATE that fails the receipt
35
+ * check / 400s the origin. A stale `content-length` breaks a
36
+ * re-serialized body.
37
+ * Must be stripped BEFORE `splitSecrets`, not after: under the allowlist
38
+ * classifier these all fall into `secrets` (none are on `PUBLIC_HEADERS`),
39
+ * and a header like `Host` — whose value trivially mirrors the URL's
40
+ * hostname, by definition — would trip a URL-conflict check on a
41
+ * structural, not a privacy, coincidence. */
42
+ const STRIP_REQUEST_HEADERS = new Set([
43
+ 'if-none-match',
44
+ 'if-modified-since',
45
+ 'if-match',
46
+ 'if-unmodified-since',
47
+ 'if-range',
48
+ 'connection',
49
+ 'accept-encoding',
50
+ 'host',
51
+ 'content-length',
52
+ 'transfer-encoding',
53
+ // Per-session anti-CSRF tokens: never portable (baking one in replays a
54
+ // single captured user's token for everyone, which the origin rejects).
55
+ // The allowlist classifier already routes these to `secrets` — a proof
56
+ // attempt sends the CURRENT user's own captured value, which is correct —
57
+ // but stripping them here means they never even take that path, and
58
+ // definitely never survive into a persisted, public recipe.
59
+ 'csrf',
60
+ 'x-csrf',
61
+ 'xsrf',
62
+ 'x-xsrf',
63
+ 'x-csrf-token',
64
+ 'xsrf-token',
65
+ ]);
66
+ /** True for an HTTP/2 pseudo-header (`:authority`, `:method`, `:path`,
67
+ * `:scheme`, which CDP surfaces on h2 captures) — never a valid request
68
+ * header the attestor can replay. Same BEFORE-the-split reasoning as
69
+ * {@link STRIP_REQUEST_HEADERS}. */
70
+ function isPseudoHeader(name) {
71
+ return name.startsWith(':');
72
+ }
73
+ /** Drop {@link STRIP_REQUEST_HEADERS} and HTTP/2 pseudo-headers. Call this on
74
+ * the RAW captured headers before {@link splitSecrets} — both the draft-time
75
+ * authoring flow and the live per-user verification capture need it, so
76
+ * neither ends up sending a duplicate `Host` or an invalid `:authority` to
77
+ * the attestor via either the public or the secret channel. */
78
+ export function stripTransportHeaders(headers) {
79
+ const out = {};
80
+ for (const [k, v] of Object.entries(headers)) {
81
+ if (STRIP_REQUEST_HEADERS.has(k.toLowerCase()) || isPseudoHeader(k)) {
82
+ continue;
83
+ }
84
+ out[k] = v;
7
85
  }
8
- return SECRET_SUFFIXES.some((s) => lower.endsWith(s));
86
+ return out;
9
87
  }
10
88
  export function splitSecrets(headers) {
11
89
  const secrets = {};
@@ -20,3 +98,66 @@ export function splitSecrets(headers) {
20
98
  }
21
99
  return { secrets, publics };
22
100
  }
101
+ /** Total characters write-redaction can hide from the attestor, summed
102
+ * ACROSS EVERY secret-classified value used in the URL — not a per-value
103
+ * cap. Default mode (`'key-update'`, also what an unset field resolves to)
104
+ * caps at 2; `'zk'` at 12. At or under the budget the overlap is genuinely
105
+ * hidden; over it, the value (or the combination of values) is effectively
106
+ * still visible to the attestor regardless of secret-marking. */
107
+ export function secretUrlCharBudget(writeRedactionMode) {
108
+ return writeRedactionMode === 'zk' ? 12 : 2;
109
+ }
110
+ /** A `paramValues`/context key is secret iff its name contains `SECRET`
111
+ * (case-insensitive) — e.g. `SECRET_apiKey`, `context.SECRET_apiKey`. Same
112
+ * naming-convention classifier reclaim-inapp-sdk and reclaim-portal use for
113
+ * their `witnessParams`/`paramValues` maps (no separate boolean flag). */
114
+ export function classifyParamName(name) {
115
+ return name.toUpperCase().includes('SECRET');
116
+ }
117
+ /** Split a `paramValues` map (bare `{{name}}` / `{{context.<name>}}` entries)
118
+ * into public (→ `params.paramValues`, revealed to the attestor) and secret
119
+ * (→ `secretParams.paramValues`) by {@link classifyParamName}. A secret
120
+ * value used in the URL is still hidden — up to {@link secretUrlCharBudget}
121
+ * characters, summed across every such value in that URL. */
122
+ export function splitSecretParamValues(paramValues) {
123
+ const secrets = {};
124
+ const publics = {};
125
+ for (const [k, v] of Object.entries(paramValues)) {
126
+ if (classifyParamName(k)) {
127
+ secrets[k] = v;
128
+ }
129
+ else {
130
+ publics[k] = v;
131
+ }
132
+ }
133
+ return { secrets, publics };
134
+ }
135
+ /** Reject a proof attempt whose URL/geoLocation templates SECRET-named
136
+ * context param(s) whose ACTUAL values (now known — the consumer supplied
137
+ * them at session-create) exceed the write-redaction budget once summed.
138
+ * Structural placement (which params end up in the URL) is knowable at
139
+ * publish time and isn't rejected there — only the real values decide
140
+ * whether it fits, and those only exist once a verification session is
141
+ * underway. Checks the placeholder TOKEN (`{{<key>}}`), not a value search —
142
+ * the URL/geoLocation explicitly reference the param by name. */
143
+ export function assertSecretParamValuesFitUrlBudget(url, geoLocation, secretParamValues, writeRedactionMode) {
144
+ const haystack = `${url}\n${geoLocation ?? ''}`;
145
+ let redactedChars = 0;
146
+ const used = [];
147
+ for (const [key, value] of Object.entries(secretParamValues)) {
148
+ if (haystack.includes(`{{${key}}}`)) {
149
+ redactedChars += value.length;
150
+ used.push(key);
151
+ }
152
+ }
153
+ const budget = secretUrlCharBudget(writeRedactionMode);
154
+ if (redactedChars > budget) {
155
+ throw new Error(`secret context param(s) ${used.map((k) => `"${k}"`).join(', ')} `
156
+ + `are templated into the URL/geoLocation ("${url}") with a `
157
+ + `combined value length of ${redactedChars} character(s) — over `
158
+ + `the ${budget}-character budget write-redaction `
159
+ + `(${writeRedactionMode ?? 'key-update'}) can actually hide there. `
160
+ + "Ask the consumer for a shorter value, switch to 'zk' if that "
161
+ + 'raises the budget enough, or move this param to the body.');
162
+ }
163
+ }
@@ -1,6 +1,6 @@
1
1
  import type { ReclaimClient } from '@reclaimprotocol/client';
2
2
  import type { CreateProviderVersionRequest, ProviderVersionRef } from '@reclaimprotocol/client/openapi';
3
- import type { HttpMethod, ReclaimProvider, ResponseMatch, ResponseRedaction } from './schema.ts';
3
+ import type { DraftResponseMatch, HttpMethod, OldUrlType, ReclaimProvider, ResponseRedaction, WebCredentials } from './schema.ts';
4
4
  /** One entry of the version's `requests[]` (a `RequestSelection`), derived
5
5
  * from the openapi type so it can't drift from what the server accepts. */
6
6
  type RequestSelection = CreateProviderVersionRequest['requests'][number];
@@ -13,8 +13,15 @@ export interface DraftRequest {
13
13
  body?: string;
14
14
  writeRedactionMode?: ReclaimProvider['writeRedactionMode'];
15
15
  additionalClientOptions?: ReclaimProvider['additionalClientOptions'];
16
- responseMatches?: ResponseMatch[];
16
+ responseMatches?: DraftResponseMatch[];
17
17
  responseRedactions?: ResponseRedaction[];
18
+ /** How the verification client supplies cookies/auth on replay. Default
19
+ * `include` (both backends). */
20
+ credentials?: WebCredentials;
21
+ /** Old-devtools `urlType` override. Ignored by THIS translator (the
22
+ * builder backend has no urlType) — read only by the old-devtools
23
+ * translator (`old/to-register.ts`). */
24
+ urlType?: OldUrlType;
18
25
  }
19
26
  /** A request the page's injection script is allowed to fire, plus the
20
27
  * pagination/optionality flags of `RequestSelectionTemplate`. Reuses the
@@ -47,6 +54,16 @@ export interface CreateVersionOptions {
47
54
  jsUserScripts?: string;
48
55
  /** Requests the injection script may fire, as `RequestSelectionTemplate`s. */
49
56
  allowedJsRequests?: AllowedJsRequest[];
57
+ /** In-app interception options, mapped verbatim to
58
+ * `webSettings.clientOptions.inapp.interceptorOptions`. `interceptorType`
59
+ * is required by the backend whenever the object is present.
60
+ * `isDocumentRequestReplayEnabled` is the INVERSE of old-devtools'
61
+ * `disableRequestReplay` (default false). */
62
+ interceptorOptions?: {
63
+ interceptorType: 'HAWKEYE' | 'MSWJS' | 'CDP';
64
+ isDocumentRequestReplayEnabled?: boolean;
65
+ interceptorSettings?: string;
66
+ };
50
67
  }
51
68
  /**
52
69
  * Derive the version's `requiredContext` JSON Schema from the
@@ -55,6 +72,13 @@ export interface CreateVersionOptions {
55
72
  * recipe can never reference a context value the Builder doesn't require.
56
73
  * Returns undefined when nothing references context (the field is optional).
57
74
  * Authors can refine types/descriptions in the version editor.
75
+ *
76
+ * A SECRET-named context param (see `classifyParamName`) is NOT rejected here
77
+ * even when it's templated into the URL/geoLocation — write-redaction can
78
+ * still hide it there, up to `secretUrlCharBudget` characters (summed across
79
+ * every such value in that URL). Whether it actually fits is only knowable
80
+ * once a real value exists, so that check runs at verification time
81
+ * (`verify/run.ts`), against the consumer's actual supplied value — not here.
58
82
  */
59
83
  export declare function deriveRequiredContext(providers: ReclaimProvider[], injection?: {
60
84
  allowedJsRequests?: AllowedJsRequest[];
@@ -22,10 +22,20 @@ const CONTEXT_PARAM_RE = /\{\{context\.([A-Za-z_][A-Za-z0-9_]*)\}\}/g;
22
22
  * recipe can never reference a context value the Builder doesn't require.
23
23
  * Returns undefined when nothing references context (the field is optional).
24
24
  * Authors can refine types/descriptions in the version editor.
25
+ *
26
+ * A SECRET-named context param (see `classifyParamName`) is NOT rejected here
27
+ * even when it's templated into the URL/geoLocation — write-redaction can
28
+ * still hide it there, up to `secretUrlCharBudget` characters (summed across
29
+ * every such value in that URL). Whether it actually fits is only knowable
30
+ * once a real value exists, so that check runs at verification time
31
+ * (`verify/run.ts`), against the consumer's actual supplied value — not here.
25
32
  */
26
33
  export function deriveRequiredContext(providers, injection = {}) {
27
34
  const parts = [];
28
- for (const p of [...providers, ...(injection.allowedJsRequests ?? [])]) {
35
+ for (const p of providers) {
36
+ parts.push(p.url, p.body ?? '');
37
+ }
38
+ for (const p of injection.allowedJsRequests ?? []) {
29
39
  parts.push(p.url, p.body ?? '');
30
40
  }
31
41
  if (injection.jsUserScripts) {
@@ -61,13 +71,13 @@ export function providerToRequestSelection(provider) {
61
71
  const responseMatches = (provider.responseMatches ?? []).map((match) => ({
62
72
  type: match.type,
63
73
  value: match.value,
64
- isOptional: false,
74
+ isOptional: match.isOptional ?? false,
65
75
  }));
66
76
  const responseRedactions = provider.responseRedactions ?? [];
67
77
  return {
68
78
  url: provider.url,
69
79
  method: provider.method,
70
- credentials: 'include',
80
+ credentials: provider.credentials ?? 'include',
71
81
  ...(provider.body ? { requestBodyTemplate: provider.body } : {}),
72
82
  ...(provider.writeRedactionMode
73
83
  ? { writeRedactionMode: provider.writeRedactionMode }
@@ -91,7 +101,7 @@ function pickGeoLocation(providers) {
91
101
  return DYNAMIC_GEO;
92
102
  }
93
103
  export function providerToCreateVersionRequest(providers, initialUrl, opts = {}) {
94
- const { notes, version, jsUserScripts, allowedJsRequests } = opts;
104
+ const { notes, version, jsUserScripts, allowedJsRequests, interceptorOptions, } = opts;
95
105
  const requiredContext = deriveRequiredContext(providers, {
96
106
  allowedJsRequests,
97
107
  jsUserScripts,
@@ -118,7 +128,21 @@ export function providerToCreateVersionRequest(providers, initialUrl, opts = {})
118
128
  // apply schema defaults to request bodies.
119
129
  webSettings: {
120
130
  geoLocation: pickGeoLocation(providers),
121
- clientOptions: { portal: { useProxy: true } },
131
+ clientOptions: {
132
+ portal: { useProxy: true },
133
+ ...(interceptorOptions
134
+ ? {
135
+ inapp: {
136
+ interceptorOptions: {
137
+ // openapi `default: false` — the generated type
138
+ // requires the key even when the author omits it.
139
+ isDocumentRequestReplayEnabled: false,
140
+ ...interceptorOptions,
141
+ },
142
+ },
143
+ }
144
+ : {}),
145
+ },
122
146
  // Only set when non-empty; an empty string would store a no-op script.
123
147
  ...(script ? { jsUserScripts: script } : {}),
124
148
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@reclaimprotocol/agent",
3
3
  "title": "Reclaim Agent",
4
- "version": "0.1.17",
4
+ "version": "0.1.20",
5
5
  "description": "Reclaim Protocol's tools for agents — Reclaim Protocol lets your app verify **data points** about its users — a follower count, an account balance, an order history. This package gives your AI coding agent the tools to **find, build, test and fix the _data verification providers_** (the recipes that verify a data point) by inspecting and replaying captured requests, checking sessions, evaluate proofs, publishing updates, and much more.",
6
6
  "type": "module",
7
7
  "main": "./lib/index.js",
@@ -83,7 +83,7 @@
83
83
  "@modelcontextprotocol/sdk": "^1.29.0",
84
84
  "@noble/hashes": "^2.2.0",
85
85
  "@reclaimprotocol/attestor-core": "^5.0.8",
86
- "@reclaimprotocol/client": "0.1.17",
86
+ "@reclaimprotocol/client": "0.1.20",
87
87
  "@reclaimprotocol/tls": "^0.1.3",
88
88
  "chrome-remote-interface": "^0.33.0",
89
89
  "domhandler": "^6.0.0",