@reclaimprotocol/agent 0.1.1-dev.1 → 0.1.2

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 (232) hide show
  1. package/README.md +1 -1
  2. package/lib/cdp/capture-engine.d.ts +66 -0
  3. package/lib/cdp/capture-engine.js +153 -0
  4. package/lib/cdp/capture.d.ts +9 -20
  5. package/lib/cdp/capture.js +14 -138
  6. package/lib/cdp/index.d.ts +3 -0
  7. package/lib/cdp/index.js +6 -0
  8. package/lib/cdp/launcher.js +4 -3
  9. package/lib/config/store.d.ts +7 -6
  10. package/lib/config/store.js +2 -2
  11. package/lib/consts.d.ts +68 -0
  12. package/lib/consts.js +134 -0
  13. package/lib/index.d.ts +2 -2
  14. package/lib/index.js +1 -1
  15. package/lib/logger.js +2 -1
  16. package/lib/mcp/api/operations.gen.d.ts +100 -48
  17. package/lib/mcp/api/operations.gen.js +1129 -194
  18. package/lib/mcp/api/to-zod.d.ts +24 -0
  19. package/lib/mcp/api/to-zod.js +94 -0
  20. package/lib/mcp/api/tools.js +1 -1
  21. package/lib/mcp/credentials/authenticate.d.ts +3 -0
  22. package/lib/mcp/{tools/credentials → credentials}/authenticate.js +3 -3
  23. package/lib/mcp/credentials/build.d.ts +5 -0
  24. package/lib/mcp/credentials/build.js +18 -0
  25. package/lib/mcp/{tools/credentials → credentials}/cache.d.ts +9 -9
  26. package/lib/mcp/{tools/credentials → credentials}/cache.js +36 -19
  27. package/lib/mcp/credentials/import.d.ts +2 -0
  28. package/lib/mcp/{tools/credentials → credentials}/import.js +2 -2
  29. package/lib/mcp/credentials/issue.d.ts +2 -0
  30. package/lib/mcp/{tools/credentials → credentials}/issue.js +4 -4
  31. package/lib/mcp/credentials/keypair.d.ts +17 -0
  32. package/lib/mcp/credentials/keypair.js +48 -0
  33. package/lib/mcp/credentials/link.d.ts +3 -0
  34. package/lib/mcp/credentials/link.js +107 -0
  35. package/lib/mcp/{tools/credentials → credentials}/list-cached.d.ts +1 -1
  36. package/lib/mcp/{tools/credentials → credentials}/list-cached.js +5 -5
  37. package/lib/mcp/credentials/owner-key.d.ts +23 -0
  38. package/lib/mcp/credentials/owner-key.js +58 -0
  39. package/lib/mcp/credentials/paths.d.ts +12 -0
  40. package/lib/mcp/credentials/paths.js +35 -0
  41. package/lib/mcp/credentials/poll.d.ts +27 -0
  42. package/lib/mcp/credentials/poll.js +61 -0
  43. package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.d.ts +1 -1
  44. package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.js +2 -2
  45. package/lib/mcp/credentials/session-cache.d.ts +14 -0
  46. package/lib/mcp/credentials/session-cache.js +42 -0
  47. package/lib/mcp/{tools/credentials → credentials}/status.d.ts +1 -1
  48. package/lib/mcp/credentials/status.js +76 -0
  49. package/lib/mcp/instructions.d.ts +1 -0
  50. package/lib/mcp/instructions.js +11 -0
  51. package/lib/mcp/register.d.ts +38 -0
  52. package/lib/mcp/register.js +80 -0
  53. package/lib/mcp/server.d.ts +2 -8
  54. package/lib/mcp/server.js +3 -33
  55. package/lib/mcp/start.js +17 -11
  56. package/lib/mcp/tools/agent/build.d.ts +5 -9
  57. package/lib/mcp/tools/agent/build.js +7 -24
  58. package/lib/mcp/tools/agent/index.d.ts +2 -0
  59. package/lib/mcp/tools/agent/index.js +3 -0
  60. package/lib/mcp/tools/agent/proof.js +3 -7
  61. package/lib/mcp/tools/agent/propose.js +13 -2
  62. package/lib/mcp/tools/agent/publish.js +172 -75
  63. package/lib/mcp/tools/agent/replay.js +0 -5
  64. package/lib/mcp/tools/analyze.d.ts +3 -0
  65. package/lib/mcp/tools/analyze.js +26 -0
  66. package/lib/mcp/tools/attach.d.ts +11 -0
  67. package/lib/mcp/tools/attach.js +72 -0
  68. package/lib/mcp/tools/authenticate/authenticate.js +107 -0
  69. package/lib/mcp/tools/authenticate/build.d.ts +15 -0
  70. package/lib/mcp/tools/authenticate/build.js +28 -0
  71. package/lib/mcp/tools/authenticate/decrypt-key.d.ts +19 -0
  72. package/lib/mcp/tools/authenticate/decrypt-key.js +46 -0
  73. package/lib/mcp/tools/authenticate/eth-key.d.ts +31 -0
  74. package/lib/mcp/tools/authenticate/eth-key.js +116 -0
  75. package/lib/mcp/tools/authenticate/import.js +57 -0
  76. package/lib/mcp/tools/authenticate/index.d.ts +2 -0
  77. package/lib/mcp/tools/authenticate/index.js +4 -0
  78. package/lib/mcp/tools/authenticate/issue.js +42 -0
  79. package/lib/mcp/tools/authenticate/resolve-owner-key.d.ts +13 -0
  80. package/lib/mcp/tools/authenticate/resolve-owner-key.js +53 -0
  81. package/lib/mcp/tools/capture.d.ts +10 -0
  82. package/lib/mcp/tools/capture.js +142 -0
  83. package/lib/mcp/tools/eval.d.ts +5 -0
  84. package/lib/mcp/tools/eval.js +127 -0
  85. package/lib/mcp/tools/find.d.ts +3 -0
  86. package/lib/mcp/tools/find.js +60 -0
  87. package/lib/mcp/tools/index.d.ts +3 -0
  88. package/lib/mcp/tools/index.js +6 -0
  89. package/lib/mcp/tools/owner-key.d.ts +2 -0
  90. package/lib/mcp/tools/owner-key.js +63 -0
  91. package/lib/mcp/tools/proof.d.ts +3 -0
  92. package/lib/mcp/tools/proof.js +214 -0
  93. package/lib/mcp/tools/propose.d.ts +9 -0
  94. package/lib/mcp/tools/propose.js +75 -0
  95. package/lib/mcp/tools/publish.d.ts +3 -0
  96. package/lib/mcp/tools/publish.js +59 -0
  97. package/lib/mcp/tools/replay.d.ts +3 -0
  98. package/lib/mcp/tools/replay.js +46 -0
  99. package/lib/mcp/tools/session.d.ts +10 -0
  100. package/lib/mcp/tools/session.js +29 -0
  101. package/lib/mcp/tools/verification/build.d.ts +12 -0
  102. package/lib/mcp/tools/verification/build.js +14 -0
  103. package/lib/mcp/tools/verification/diagnose.d.ts +11 -0
  104. package/lib/mcp/tools/verification/diagnose.js +132 -0
  105. package/lib/mcp/tools/verification/index.d.ts +1 -0
  106. package/lib/mcp/tools/verification/index.js +2 -0
  107. package/lib/mcp/tools/verification/result.d.ts +11 -0
  108. package/lib/mcp/tools/verification/result.js +126 -0
  109. package/lib/mcp/verifications/build.d.ts +5 -0
  110. package/lib/mcp/verifications/build.js +14 -0
  111. package/lib/mcp/verifications/create.d.ts +3 -0
  112. package/lib/mcp/verifications/create.js +57 -0
  113. package/lib/mcp/verifications/find.d.ts +3 -0
  114. package/lib/mcp/verifications/find.js +37 -0
  115. package/lib/mcp/verifications/get.d.ts +3 -0
  116. package/lib/mcp/verifications/get.js +26 -0
  117. package/lib/mcp/verifications/update.d.ts +3 -0
  118. package/lib/mcp/verifications/update.js +78 -0
  119. package/lib/old/client.d.ts +3 -0
  120. package/lib/old/flag.d.ts +4 -1
  121. package/lib/old/flag.js +4 -3
  122. package/lib/old/identity.d.ts +0 -10
  123. package/lib/old/identity.js +8 -7
  124. package/lib/old/instructions.d.ts +0 -6
  125. package/lib/old/instructions.js +6 -24
  126. package/lib/old/login-cdp.d.ts +0 -3
  127. package/lib/old/login-cdp.js +2 -4
  128. package/lib/old/to-register.d.ts +3 -0
  129. package/lib/old/to-register.js +32 -7
  130. package/lib/old/tools/authenticate.js +2 -1
  131. package/lib/old/tools/publish.js +71 -10
  132. package/lib/paths.js +2 -2
  133. package/lib/proof/attestor.d.ts +33 -1
  134. package/lib/proof/attestor.js +67 -64
  135. package/lib/proof/index.d.ts +5 -0
  136. package/lib/proof/index.js +6 -0
  137. package/lib/proof/proof-core.d.ts +35 -0
  138. package/lib/proof/proof-core.js +84 -0
  139. package/lib/provider/index.d.ts +5 -0
  140. package/lib/provider/index.js +9 -0
  141. package/lib/provider/injection-doc.d.ts +1 -0
  142. package/lib/provider/injection-doc.js +17 -0
  143. package/lib/provider/match-redaction-warning.d.ts +25 -0
  144. package/lib/provider/match-redaction-warning.js +35 -0
  145. package/lib/provider/schema.d.ts +16 -0
  146. package/lib/provider/schema.js +11 -1
  147. package/lib/provider/to-version.d.ts +61 -12
  148. package/lib/provider/to-version.js +109 -24
  149. package/lib/provider/verification-checks.d.ts +12 -0
  150. package/lib/provider/verification-checks.js +30 -0
  151. package/lib/routes.gen.d.ts +271 -0
  152. package/lib/routes.gen.js +73 -0
  153. package/lib/types/openapi.gen.d.ts +3967 -0
  154. package/lib/types/openapi.gen.js +5 -0
  155. package/package.json +16 -7
  156. package/skill/SKILL.md +35 -14
  157. package/skill/builder-mode.md +13 -0
  158. package/skill/injection-api.md +42 -0
  159. package/skill/old-mode.md +15 -0
  160. package/src/cdp/capture-engine.ts +256 -0
  161. package/src/cdp/capture.ts +25 -185
  162. package/src/cdp/index.ts +6 -0
  163. package/src/cdp/launcher.ts +5 -4
  164. package/src/config/store.ts +7 -6
  165. package/src/consts.ts +164 -0
  166. package/src/index.ts +2 -4
  167. package/src/logger.ts +2 -1
  168. package/src/mcp/api/operations.gen.ts +1155 -194
  169. package/src/mcp/api/to-zod.ts +115 -0
  170. package/src/mcp/api/tools.ts +9 -3
  171. package/src/mcp/instructions.ts +15 -0
  172. package/src/mcp/server.ts +5 -50
  173. package/src/mcp/start.ts +27 -11
  174. package/src/mcp/tools/agent/build.ts +7 -27
  175. package/src/mcp/tools/agent/index.ts +4 -0
  176. package/src/mcp/tools/agent/proof.ts +3 -8
  177. package/src/mcp/tools/agent/propose.ts +13 -2
  178. package/src/mcp/tools/agent/publish.ts +218 -92
  179. package/src/mcp/tools/agent/replay.ts +0 -5
  180. package/src/mcp/tools/{credentials → authenticate}/authenticate.ts +9 -8
  181. package/src/mcp/tools/authenticate/build.ts +32 -0
  182. package/src/mcp/tools/authenticate/decrypt-key.ts +59 -0
  183. package/src/mcp/tools/authenticate/eth-key.ts +162 -0
  184. package/src/mcp/tools/authenticate/import.ts +73 -0
  185. package/src/mcp/tools/authenticate/index.ts +4 -0
  186. package/src/mcp/tools/authenticate/issue.ts +50 -0
  187. package/src/mcp/tools/authenticate/resolve-owner-key.ts +60 -0
  188. package/src/mcp/tools/index.ts +6 -0
  189. package/src/mcp/tools/verification/build.ts +16 -0
  190. package/src/mcp/tools/verification/index.ts +2 -0
  191. package/src/mcp/tools/verification/result.ts +154 -0
  192. package/src/old/client.ts +3 -0
  193. package/src/old/flag.ts +4 -3
  194. package/src/old/identity.ts +8 -7
  195. package/src/old/instructions.ts +10 -25
  196. package/src/old/login-cdp.ts +2 -5
  197. package/src/old/to-register.ts +58 -26
  198. package/src/old/tools/authenticate.ts +2 -1
  199. package/src/old/tools/publish.ts +92 -16
  200. package/src/paths.ts +2 -2
  201. package/src/proof/attestor.ts +114 -72
  202. package/src/proof/index.ts +21 -0
  203. package/src/proof/proof-core.ts +119 -0
  204. package/src/provider/index.ts +20 -0
  205. package/src/provider/injection-doc.ts +21 -0
  206. package/src/provider/match-redaction-warning.ts +53 -0
  207. package/src/provider/schema.ts +23 -0
  208. package/src/provider/to-version.ts +180 -33
  209. package/src/provider/verification-checks.ts +36 -0
  210. package/lib/mcp/tools/credentials/build.d.ts +0 -16
  211. package/lib/mcp/tools/credentials/build.js +0 -33
  212. package/lib/mcp/tools/credentials/status.js +0 -62
  213. package/src/mcp/tools/credentials/build.ts +0 -37
  214. package/src/mcp/tools/credentials/cache.ts +0 -161
  215. package/src/mcp/tools/credentials/env-file.ts +0 -101
  216. package/src/mcp/tools/credentials/import.ts +0 -72
  217. package/src/mcp/tools/credentials/issue.ts +0 -107
  218. package/src/mcp/tools/credentials/list-cached.ts +0 -66
  219. package/src/mcp/tools/credentials/register.ts +0 -49
  220. package/src/mcp/tools/credentials/resolve-owner-key.ts +0 -78
  221. package/src/mcp/tools/credentials/status.ts +0 -82
  222. package/src/types/openapi.ts +0 -7
  223. /package/lib/mcp/{tools/credentials → credentials}/env-file.d.ts +0 -0
  224. /package/lib/mcp/{tools/credentials → credentials}/env-file.js +0 -0
  225. /package/lib/mcp/{tools/credentials → credentials}/register.d.ts +0 -0
  226. /package/lib/mcp/{tools/credentials → credentials}/register.js +0 -0
  227. /package/lib/mcp/tools/{credentials → authenticate}/authenticate.d.ts +0 -0
  228. /package/lib/mcp/tools/{credentials → authenticate}/import.d.ts +0 -0
  229. /package/lib/mcp/tools/{credentials → authenticate}/issue.d.ts +0 -0
  230. /package/lib/mcp/tools/{credentials → authenticate}/session-cache.d.ts +0 -0
  231. /package/lib/mcp/tools/{credentials → authenticate}/session-cache.js +0 -0
  232. /package/src/mcp/tools/{credentials → authenticate}/session-cache.ts +0 -0
@@ -0,0 +1,6 @@
1
+ export { runAttestorProof, tailLogs, warnsAndErrors } from "./attestor.js";
2
+ export { buildHttpParams, ensureAttestorCrypto, parseClaim, resolveAttestorUrl, } from "./proof-core.js";
3
+ export { ensureZkFiles } from "./zk-files.js";
4
+ // Re-exported attestor-core claim primitive so the agent is the single
5
+ // integration point with @reclaimprotocol/attestor-core across the builder.
6
+ export { createClaimOnAttestor } from '@reclaimprotocol/attestor-core';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Shared attestor-claim plumbing used by both proof callers: the agent's MCP
3
+ * `run_proof` (which resolves the owner key from the credential cache and
4
+ * captures trace logs) and the app's verification runner (which signs with an
5
+ * ephemeral per-session key and builds a nested-proof claim). Only those
6
+ * concerns differ — building the HTTP params, resolving the attestor URL, and
7
+ * parsing the claim response are identical, so they live here.
8
+ */
9
+ import type { ProviderParams } from '@reclaimprotocol/attestor-core';
10
+ import type { ReclaimProvider } from '../provider/schema.ts';
11
+ /** One-time crypto backend init for `@reclaimprotocol/tls` (idempotent). The
12
+ * package ships with an empty `crypto = {}` and defers the backend to the
13
+ * caller; without this the first proof dies inside the TLS client with
14
+ * `crypto.randomBytes is not a function`. Shared by every attestor caller —
15
+ * the agent MCP `run_proof` tool and the app's verification runner. */
16
+ export declare function ensureAttestorCrypto(): void;
17
+ /** Resolve the attestor websocket URL: explicit override → env → public
18
+ * default. Resolved per-call so an env change or per-request override takes
19
+ * effect without restarting. */
20
+ export declare function resolveAttestorUrl(override?: string): string;
21
+ /** Map a verification's provider recipe straight to the attestor's HTTP
22
+ * params — never synthesized from captured traffic. */
23
+ export declare function buildHttpParams(provider: ReclaimProvider): ProviderParams<'http'>;
24
+ export interface ParsedClaim {
25
+ /** ProviderClaimData: provider, parameters, context, owner, identifier, … */
26
+ claimData?: Record<string, unknown>;
27
+ extractedParameters: Record<string, string>;
28
+ extractedValue: string;
29
+ identifier?: string;
30
+ owner?: string;
31
+ }
32
+ /** Pull claimData + decoded `context.extractedParameters` (plus identifier /
33
+ * owner) out of a `createClaimOnAttestor` result. The full result still
34
+ * carries signatures the caller may need for nested-proof building. */
35
+ export declare function parseClaim(claim: unknown): ParsedClaim;
@@ -0,0 +1,84 @@
1
+ import { setCryptoImplementation } from '@reclaimprotocol/tls';
2
+ import { webcryptoCrypto } from '@reclaimprotocol/tls/webcrypto';
3
+ import { attestorUrlOverride, FALLBACK_ATTESTOR_URL } from "../consts.js";
4
+ import { normalizeGeoLocation } from "../provider/schema.js";
5
+ let cryptoInitialized = false;
6
+ /** One-time crypto backend init for `@reclaimprotocol/tls` (idempotent). The
7
+ * package ships with an empty `crypto = {}` and defers the backend to the
8
+ * caller; without this the first proof dies inside the TLS client with
9
+ * `crypto.randomBytes is not a function`. Shared by every attestor caller —
10
+ * the agent MCP `run_proof` tool and the app's verification runner. */
11
+ export function ensureAttestorCrypto() {
12
+ if (cryptoInitialized) {
13
+ return;
14
+ }
15
+ setCryptoImplementation(webcryptoCrypto);
16
+ cryptoInitialized = true;
17
+ }
18
+ /** Resolve the attestor websocket URL: explicit override → env → public
19
+ * default. Resolved per-call so an env change or per-request override takes
20
+ * effect without restarting. */
21
+ export function resolveAttestorUrl(override) {
22
+ return (override ?? attestorUrlOverride() ?? FALLBACK_ATTESTOR_URL);
23
+ }
24
+ /** Map a verification's provider recipe straight to the attestor's HTTP
25
+ * params — never synthesized from captured traffic. */
26
+ export function buildHttpParams(provider) {
27
+ // A blank egress is treated as unset: omit it so the local proof uses the
28
+ // tester's own egress rather than shipping a blank or an unresolved template.
29
+ const geoLocation = normalizeGeoLocation(provider.geoLocation);
30
+ return {
31
+ url: provider.url,
32
+ method: provider.method,
33
+ ...(provider.headers !== undefined && { headers: provider.headers }),
34
+ ...(provider.body !== undefined && { body: provider.body }),
35
+ responseMatches: provider.responseMatches,
36
+ responseRedactions: provider.responseRedactions ?? [],
37
+ ...(provider.paramValues !== undefined && {
38
+ paramValues: provider.paramValues,
39
+ }),
40
+ ...(provider.writeRedactionMode !== undefined && {
41
+ writeRedactionMode: provider.writeRedactionMode,
42
+ }),
43
+ ...(provider.additionalClientOptions !== undefined && {
44
+ additionalClientOptions: provider.additionalClientOptions,
45
+ }),
46
+ ...(geoLocation !== undefined && { geoLocation }),
47
+ };
48
+ }
49
+ /** Pull claimData + decoded `context.extractedParameters` (plus identifier /
50
+ * owner) out of a `createClaimOnAttestor` result. The full result still
51
+ * carries signatures the caller may need for nested-proof building. */
52
+ export function parseClaim(claim) {
53
+ const claimRecord = claim;
54
+ const claimData = claimRecord['claim'];
55
+ // claimData.context is a JSON-encoded string carrying
56
+ // { extractedParameters: {...}, providerHash, ... }.
57
+ let context = {};
58
+ const rawContext = claimData?.['context'];
59
+ if (typeof rawContext === 'string') {
60
+ try {
61
+ context = JSON.parse(rawContext);
62
+ }
63
+ catch {
64
+ // Leave context empty if it isn't valid JSON.
65
+ }
66
+ }
67
+ const extractedParameters = context['extractedParameters'] ?? {};
68
+ const parsed = {
69
+ extractedParameters,
70
+ extractedValue: Object.values(extractedParameters)[0] ?? '',
71
+ };
72
+ if (claimData) {
73
+ parsed.claimData = claimData;
74
+ }
75
+ const identifier = claimData?.['identifier'];
76
+ if (typeof identifier === 'string') {
77
+ parsed.identifier = identifier;
78
+ }
79
+ const owner = claimData?.['owner'];
80
+ if (typeof owner === 'string') {
81
+ parsed.owner = owner;
82
+ }
83
+ return parsed;
84
+ }
@@ -0,0 +1,5 @@
1
+ export { extractGraphqlOp, looksLikeGraphqlEndpoint } from './graphql.ts';
2
+ export type { CapturedRequest, HttpMethod, OprfMode, ReclaimProvider, RequestConcern, ResponseMatch, ResponseRedaction, SecretParamRef, } from './schema.ts';
3
+ export { classifyHeader, splitSecrets } from './secrets.ts';
4
+ export { hashProviderParams, providers } from '@reclaimprotocol/attestor-core';
5
+ export type { ProviderParams } from '@reclaimprotocol/attestor-core';
@@ -0,0 +1,9 @@
1
+ // Provider primitives shared with the app's capture pipeline:
2
+ // the attestor-derived recipe types, secret classification, and the GraphQL
3
+ // op parser. Exposed as `@reclaimprotocol/agent/provider`.
4
+ export { extractGraphqlOp, looksLikeGraphqlEndpoint } from "./graphql.js";
5
+ export { classifyHeader, splitSecrets } from "./secrets.js";
6
+ // Re-exported attestor-core provider primitives (the registry, the param hash,
7
+ // and the param type) so the builder imports them via the agent rather than
8
+ // depending on @reclaimprotocol/attestor-core directly.
9
+ export { hashProviderParams, providers } from '@reclaimprotocol/attestor-core';
@@ -0,0 +1 @@
1
+ export declare const INJECTION_GUIDE: string;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Guidance for authoring page-injection scripts (`webSettings.jsUserScripts` on
3
+ * the builder, `customInjection` on old-devtools), surfaced to the authoring
4
+ * model from the publish tool description. The prose lives in
5
+ * `skill/injection-api.md` so it can be edited as markdown without touching
6
+ * code — the same pattern as `mcp/instructions.ts`. The path resolves the same
7
+ * from `src/provider` (dev) and `lib/provider` (published): both are two levels
8
+ * below the package root.
9
+ *
10
+ * The guide leads with plain browser JavaScript (navigation/interaction via
11
+ * standard APIs; the client already intercepts page requests) and treats
12
+ * `window.Reclaim` as a rarely-needed edge-case bridge, pointing at the
13
+ * authoritative `src/support/env.d.ts` rather than reproducing its surface.
14
+ */
15
+ import { readFileSync } from 'node:fs';
16
+ import { fileURLToPath } from 'node:url';
17
+ export const INJECTION_GUIDE = readFileSync(fileURLToPath(new URL('../../skill/injection-api.md', import.meta.url)), 'utf8').trim();
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Non-blocking advisory for a request whose `responseMatches` count is less
3
+ * than its `responseRedactions` count.
4
+ *
5
+ * Some verification clients (notably the InApp SDK) pair the two arrays by
6
+ * index and may not behave correctly when there are fewer matches than
7
+ * redactions. This is NOT enforced — the author keeps full control over what
8
+ * they publish in either old-devtools or builder mode. The tools surface these
9
+ * strings so the dev can make an informed decision (e.g. add a functional match
10
+ * per redaction) rather than being blocked.
11
+ */
12
+ /** One request's match/redaction counts, with a human label for the message. */
13
+ export interface RequestCounts {
14
+ label: string;
15
+ matchCount: number;
16
+ redactionCount: number;
17
+ }
18
+ /** Build advisory warnings for any request with matchCount < redactionCount.
19
+ * Returns an empty array when everything is fine. */
20
+ export declare function matchRedactionWarnings(requests: RequestCounts[]): string[];
21
+ /** Counts for a single drafted request shape (provider or injected request). */
22
+ export declare function countsFor(label: string, req: {
23
+ responseMatches?: unknown[];
24
+ responseRedactions?: unknown[];
25
+ }): RequestCounts;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Non-blocking advisory for a request whose `responseMatches` count is less
3
+ * than its `responseRedactions` count.
4
+ *
5
+ * Some verification clients (notably the InApp SDK) pair the two arrays by
6
+ * index and may not behave correctly when there are fewer matches than
7
+ * redactions. This is NOT enforced — the author keeps full control over what
8
+ * they publish in either old-devtools or builder mode. The tools surface these
9
+ * strings so the dev can make an informed decision (e.g. add a functional match
10
+ * per redaction) rather than being blocked.
11
+ */
12
+ /** Build advisory warnings for any request with matchCount < redactionCount.
13
+ * Returns an empty array when everything is fine. */
14
+ export function matchRedactionWarnings(requests) {
15
+ const warnings = [];
16
+ for (const req of requests) {
17
+ if (req.matchCount < req.redactionCount) {
18
+ warnings.push(`${req.label}: ${req.matchCount} response match(es) but ` +
19
+ `${req.redactionCount} response redaction(s). Some verification ` +
20
+ 'clients (e.g. the InApp SDK) may not work correctly when ' +
21
+ 'responseMatches is shorter than responseRedactions — they pair the ' +
22
+ 'two by index. This is allowed; add a functional match per redaction ' +
23
+ 'if you hit verification issues.');
24
+ }
25
+ }
26
+ return warnings;
27
+ }
28
+ /** Counts for a single drafted request shape (provider or injected request). */
29
+ export function countsFor(label, req) {
30
+ return {
31
+ label,
32
+ matchCount: req.responseMatches?.length ?? 0,
33
+ redactionCount: req.responseRedactions?.length ?? 0,
34
+ };
35
+ }
@@ -61,7 +61,23 @@ export interface ReclaimProvider {
61
61
  responseRedactions?: ResponseRedaction[];
62
62
  /** Public param refs (templated into URL/body), populated by draft layer. */
63
63
  paramValues?: Record<string, string>;
64
+ /** Redaction mode for the transcript (attestor default: 'key-update'). */
65
+ writeRedactionMode?: HttpParams['writeRedactionMode'];
66
+ /** TLS client options applied to the attestor tunnel. */
67
+ additionalClientOptions?: HttpParams['additionalClientOptions'];
68
+ /** Proxy egress: 2-letter ISO country or `{{param}}`. Blank/omitted ⇒
69
+ * `{{DYNAMIC_GEO}}` on publish (resolved to the verifying user's country).
70
+ */
71
+ geoLocation?: HttpParams['geoLocation'];
64
72
  }
73
+ /** Egress placeholder resolved to the verifying user's country at
74
+ * verification time — the default when a provider declares no explicit egress.
75
+ */
76
+ export declare const DYNAMIC_GEO = "{{DYNAMIC_GEO}}";
77
+ /** `geoLocation` must never be blank. Trims the input and treats an empty
78
+ * string as unset so callers apply their own default (publish → `DYNAMIC_GEO`;
79
+ * a local proof omits it and uses the tester's egress). */
80
+ export declare function normalizeGeoLocation(value: string | undefined): string | undefined;
65
81
  /** A reference to a secret param. Raw value lives only in server memory. */
66
82
  export interface SecretParamRef {
67
83
  name: string;
@@ -1 +1,11 @@
1
- export {};
1
+ /** Egress placeholder resolved to the verifying user's country at
2
+ * verification time — the default when a provider declares no explicit egress.
3
+ */
4
+ export const DYNAMIC_GEO = '{{DYNAMIC_GEO}}';
5
+ /** `geoLocation` must never be blank. Trims the input and treats an empty
6
+ * string as unset so callers apply their own default (publish → `DYNAMIC_GEO`;
7
+ * a local proof omits it and uses the tester's egress). */
8
+ export function normalizeGeoLocation(value) {
9
+ const trimmed = value?.trim();
10
+ return trimmed ? trimmed : undefined;
11
+ }
@@ -1,22 +1,71 @@
1
1
  import type { ReclaimClient } from '@reclaimprotocol/client';
2
- import type { CreateProviderVersionRequest as CreateVersionBody, ProviderVersionRef as VersionRef } from '../types/openapi.ts';
3
- import type { ReclaimProvider } from './schema.ts';
2
+ import type { CreateProviderVersionRequest, ProviderVersionRef } from '@reclaimprotocol/client/openapi';
3
+ import type { HttpMethod, ReclaimProvider, ResponseMatch, ResponseRedaction } from './schema.ts';
4
+ /** One entry of the version's `requests[]` (a `RequestSelection`), derived
5
+ * from the openapi type so it can't drift from what the server accepts. */
6
+ type RequestSelection = CreateProviderVersionRequest['requests'][number];
7
+ /** The subset of a draft a request selection is built from — the only fields
8
+ * `providerToRequestSelection` reads. A full `ReclaimProvider` satisfies it,
9
+ * as does a lighter injected-request draft (no `name`/`paramValues`). */
10
+ export interface DraftRequest {
11
+ url: string;
12
+ method: HttpMethod;
13
+ body?: string;
14
+ writeRedactionMode?: ReclaimProvider['writeRedactionMode'];
15
+ additionalClientOptions?: ReclaimProvider['additionalClientOptions'];
16
+ responseMatches?: ResponseMatch[];
17
+ responseRedactions?: ResponseRedaction[];
18
+ }
19
+ /** A request the page's injection script is allowed to fire, plus the
20
+ * pagination/optionality flags of `RequestSelectionTemplate`. Reuses the
21
+ * shared `DraftRequest` shape — no provider `name`/`paramValues` required. */
22
+ export interface AllowedJsRequest extends DraftRequest {
23
+ /** Allow the template to match many requests (e.g. pagination). Default
24
+ * true. */
25
+ multiple?: boolean;
26
+ /** Fail validation if no request matches this template. Default true. */
27
+ required?: boolean;
28
+ }
29
+ /** Optional extras for a create-version body beyond the request list. */
30
+ export interface CreateVersionOptions {
31
+ notes?: string;
32
+ version?: ProviderVersionRef;
33
+ /** JS injected before every page load (`webSettings.jsUserScripts`). */
34
+ jsUserScripts?: string;
35
+ /** Requests the injection script may fire, as `RequestSelectionTemplate`s. */
36
+ allowedJsRequests?: AllowedJsRequest[];
37
+ }
4
38
  /**
5
- * Translate a drafted ReclaimProvider into the body for
6
- * POST /providers/{providerId}/versions.
7
- *
8
- * `initialUrl` is the landing page the user navigated to during
9
- * capture — distinct from `provider.url` which is the specific
10
- * API URL the attestor replays.
39
+ * Derive the version's `requiredContext` JSON Schema from the
40
+ * `{{context.<name>}}` placeholders across EVERY request's url/body (plus any
41
+ * injected requests and the injection script) — mechanical, so a published
42
+ * recipe can never reference a context value the Builder doesn't require.
43
+ * Returns undefined when nothing references context (the field is optional).
44
+ * Authors can refine types/descriptions in the version editor.
45
+ */
46
+ export declare function deriveRequiredContext(providers: ReclaimProvider[], injection?: {
47
+ allowedJsRequests?: AllowedJsRequest[];
48
+ jsUserScripts?: string;
49
+ }): CreateProviderVersionRequest['requiredContext'];
50
+ /**
51
+ * Translate one drafted request into a `RequestSelection`. Shared by the
52
+ * top-level `requests` and by `allowedJsRequests`.
11
53
  *
12
- * Secrets are NOT persisted — the verification client re-supplies
13
- * them at runtime via `credentials: 'include'`.
54
+ * `responseMatches`/`responseRedactions` are INDEPENDENT parallel arrays,
55
+ * isomorphic to the attestor's `ProviderParams<'http'>` (no nested fold).
56
+ * `responseRedactions` decide which portions of the response are revealed;
57
+ * `responseMatches` then run against the union of the revealed content. Neither
58
+ * depends on the other's length or order, so both pass through untouched.
59
+ * (The old-devtools translator has its own opt-in index-pairing concern; the
60
+ * builder deliberately does not.)
14
61
  */
15
- export declare function providerToCreateVersionRequest(provider: ReclaimProvider, initialUrl: string, notes?: string, version?: VersionRef): CreateVersionBody;
62
+ export declare function providerToRequestSelection(provider: DraftRequest): RequestSelection;
63
+ export declare function providerToCreateVersionRequest(providers: ReclaimProvider[], initialUrl: string, opts?: CreateVersionOptions): CreateProviderVersionRequest;
16
64
  /**
17
65
  * Fetch the current versions for a provider and return the next version above
18
66
  * the highest existing one (bumping the patch number), or 1.0.0 when the
19
67
  * provider has no versions yet. A failed lookup propagates — silently
20
68
  * resetting to 1.0.0 would re-publish a v3 provider as v1.0.0.
21
69
  */
22
- export declare function nextVersion(client: ReclaimClient, providerId: string): Promise<VersionRef>;
70
+ export declare function nextVersion(client: ReclaimClient, providerId: string): Promise<ProviderVersionRef>;
71
+ export {};
@@ -1,3 +1,4 @@
1
+ import { DYNAMIC_GEO, normalizeGeoLocation } from "./schema.js";
1
2
  /**
2
3
  * Translate a drafted ReclaimProvider into the body for
3
4
  * POST /providers/{providerId}/versions.
@@ -9,34 +10,118 @@
9
10
  * Secrets are NOT persisted — the verification client re-supplies
10
11
  * them at runtime via `credentials: 'include'`.
11
12
  */
12
- export function providerToCreateVersionRequest(provider, initialUrl, notes, version) {
13
- // Inline responseRedactions into matches[*].extract (1-to-1 by index).
14
- const matches = (provider.responseMatches ?? []).map((match, i) => {
15
- const redaction = provider.responseRedactions?.[i];
16
- return {
17
- type: match.type,
18
- value: match.value,
19
- isOptional: false,
20
- ...(redaction ? { extract: redaction } : {}),
21
- };
13
+ /** `{{context.<name>}}` placeholders in a request URL/body: values the
14
+ * CONSUMER supplies at verification time via the session `context`. Bare
15
+ * `{{name}}` placeholders (extraction params) are not consumer-supplied
16
+ * and are ignored. */
17
+ const CONTEXT_PARAM_RE = /\{\{context\.([A-Za-z_][A-Za-z0-9_]*)\}\}/g;
18
+ /**
19
+ * Derive the version's `requiredContext` JSON Schema from the
20
+ * `{{context.<name>}}` placeholders across EVERY request's url/body (plus any
21
+ * injected requests and the injection script) — mechanical, so a published
22
+ * recipe can never reference a context value the Builder doesn't require.
23
+ * Returns undefined when nothing references context (the field is optional).
24
+ * Authors can refine types/descriptions in the version editor.
25
+ */
26
+ export function deriveRequiredContext(providers, injection = {}) {
27
+ const parts = [];
28
+ for (const p of [...providers, ...(injection.allowedJsRequests ?? [])]) {
29
+ parts.push(p.url, p.body ?? '');
30
+ }
31
+ if (injection.jsUserScripts) {
32
+ parts.push(injection.jsUserScripts);
33
+ }
34
+ const haystack = parts.join('\n');
35
+ const names = new Set();
36
+ for (const m of haystack.matchAll(CONTEXT_PARAM_RE)) {
37
+ names.add(m[1]);
38
+ }
39
+ if (!names.size) {
40
+ return undefined;
41
+ }
42
+ const properties = {};
43
+ for (const name of names) {
44
+ properties[name] = { type: 'string' };
45
+ }
46
+ return { type: 'object', required: [...names], properties };
47
+ }
48
+ /**
49
+ * Translate one drafted request into a `RequestSelection`. Shared by the
50
+ * top-level `requests` and by `allowedJsRequests`.
51
+ *
52
+ * `responseMatches`/`responseRedactions` are INDEPENDENT parallel arrays,
53
+ * isomorphic to the attestor's `ProviderParams<'http'>` (no nested fold).
54
+ * `responseRedactions` decide which portions of the response are revealed;
55
+ * `responseMatches` then run against the union of the revealed content. Neither
56
+ * depends on the other's length or order, so both pass through untouched.
57
+ * (The old-devtools translator has its own opt-in index-pairing concern; the
58
+ * builder deliberately does not.)
59
+ */
60
+ export function providerToRequestSelection(provider) {
61
+ const responseMatches = (provider.responseMatches ?? []).map((match) => ({
62
+ type: match.type,
63
+ value: match.value,
64
+ isOptional: false,
65
+ }));
66
+ const responseRedactions = provider.responseRedactions ?? [];
67
+ return {
68
+ url: provider.url,
69
+ method: provider.method,
70
+ credentials: 'include',
71
+ ...(provider.body ? { requestBodyTemplate: provider.body } : {}),
72
+ ...(provider.writeRedactionMode
73
+ ? { writeRedactionMode: provider.writeRedactionMode }
74
+ : {}),
75
+ ...(provider.additionalClientOptions
76
+ ? { additionalClientOptions: provider.additionalClientOptions }
77
+ : {}),
78
+ ...(responseMatches.length > 0 ? { responseMatches } : {}),
79
+ ...(responseRedactions.length > 0 ? { responseRedactions } : {}),
80
+ };
81
+ }
82
+ /** First provider that declares an explicit (non-default) egress wins; if none
83
+ * do, fall back to DYNAMIC_GEO (resolved to the verifying user's country). */
84
+ function pickGeoLocation(providers) {
85
+ for (const provider of providers) {
86
+ const geo = normalizeGeoLocation(provider.geoLocation);
87
+ if (geo) {
88
+ return geo;
89
+ }
90
+ }
91
+ return DYNAMIC_GEO;
92
+ }
93
+ export function providerToCreateVersionRequest(providers, initialUrl, opts = {}) {
94
+ const { notes, version, jsUserScripts, allowedJsRequests } = opts;
95
+ const requiredContext = deriveRequiredContext(providers, {
96
+ allowedJsRequests,
97
+ jsUserScripts,
22
98
  });
99
+ // Each injected request carries its template flags (default true/true per
100
+ // RequestSelectionTemplate) on top of the shared request shape.
101
+ const allowedJs = (allowedJsRequests ?? []).map((req) => ({
102
+ ...providerToRequestSelection(req),
103
+ multiple: req.multiple ?? true,
104
+ required: req.required ?? true,
105
+ }));
106
+ const script = jsUserScripts?.trim();
23
107
  return {
24
108
  version: version ?? { major: 1, minor: 0, patch: 0 },
25
109
  initialUrl,
26
- requests: [
27
- {
28
- url: provider.url,
29
- method: provider.method,
30
- credentials: 'include',
31
- ...(provider.body ? { requestBodyTemplate: provider.body } : {}),
32
- ...(matches.length > 0 ? { matches } : {}),
33
- },
34
- ],
35
- allowedJsRequests: [],
36
- webSettings: { geoLocation: '{{DYNAMIC_GEO}}' },
37
- ...(provider.paramValues
38
- ? { requiredParameters: provider.paramValues }
39
- : {}),
110
+ // Every drafted provider becomes one request — the recipe runs them all.
111
+ requests: providers.map(providerToRequestSelection),
112
+ allowedJsRequests: allowedJs,
113
+ // Mirror the builder openapi defaults explicitly — the server does not
114
+ // apply schema defaults to request bodies.
115
+ webSettings: {
116
+ geoLocation: pickGeoLocation(providers),
117
+ clientOptions: { portal: { useProxy: true } },
118
+ // Only set when non-empty; an empty string would store a no-op script.
119
+ ...(script ? { jsUserScripts: script } : {}),
120
+ },
121
+ // Derived from `{{context.<name>}}` placeholders only — a captured
122
+ // provider's `paramValues` are extracted response parameters, not
123
+ // consumer context, and never become requiredContext.
124
+ ...(requiredContext ? { requiredContext } : {}),
40
125
  ...(notes ? { notes } : {}),
41
126
  };
42
127
  }
@@ -0,0 +1,12 @@
1
+ import type { ReclaimProvider } from './schema.ts';
2
+ /**
3
+ * Advisory pre-publish lint for a drafted provider — never a gate. Surfaces
4
+ * only what the AUTHOR must decide; everything testable is tested by the
5
+ * verification client itself (CDP capture sees all traffic — navigations,
6
+ * XHRs, fetches — and `checkCandidate` in packages/app src/verify/run.ts
7
+ * selects the captured request that satisfies the recipe, skipping the
8
+ * rest). Interpolation and matching are plain text and work for any
9
+ * captured content; extract selectors apply client-side in spec order
10
+ * xPath → jsonPath → regex, each to the prior selection.
11
+ */
12
+ export declare function verificationWarnings(provider: ReclaimProvider): string[];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Advisory pre-publish lint for a drafted provider — never a gate. Surfaces
3
+ * only what the AUTHOR must decide; everything testable is tested by the
4
+ * verification client itself (CDP capture sees all traffic — navigations,
5
+ * XHRs, fetches — and `checkCandidate` in packages/app src/verify/run.ts
6
+ * selects the captured request that satisfies the recipe, skipping the
7
+ * rest). Interpolation and matching are plain text and work for any
8
+ * captured content; extract selectors apply client-side in spec order
9
+ * xPath → jsonPath → regex, each to the prior selection.
10
+ */
11
+ export function verificationWarnings(provider) {
12
+ const out = [];
13
+ // Untemplated user-specific URL parts: any captured param value baked
14
+ // literally into the URL makes the provider user-specific. Only the dev
15
+ // can decide: consumer-supplied → {{context.<name>}} (declared in
16
+ // requiredContext; consumers then send the exact value and the VC matches
17
+ // only that value), bare {{<name>}} (resolved from the end-user's own
18
+ // traffic), or re-capture a non-user-specific endpoint.
19
+ for (const [name, value] of Object.entries(provider.paramValues ?? {})) {
20
+ if (value.length >= 3 && provider.url.includes(value)) {
21
+ out.push(`The URL contains the captured value "${value}" (param ` +
22
+ `"${name}") as a literal. Decide with the dev: if consumers ` +
23
+ 'supply it, replace with {{context.' + name + '}} (published ' +
24
+ 'requiredContext will require it; verification matches only ' +
25
+ 'the supplied value). Leaving it literal pins the provider ' +
26
+ 'to this user.');
27
+ }
28
+ }
29
+ return out;
30
+ }