@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.
- package/README.md +1 -1
- package/lib/cdp/capture-engine.d.ts +66 -0
- package/lib/cdp/capture-engine.js +153 -0
- package/lib/cdp/capture.d.ts +9 -20
- package/lib/cdp/capture.js +14 -138
- package/lib/cdp/index.d.ts +3 -0
- package/lib/cdp/index.js +6 -0
- package/lib/cdp/launcher.js +4 -3
- package/lib/config/store.d.ts +7 -6
- package/lib/config/store.js +2 -2
- package/lib/consts.d.ts +68 -0
- package/lib/consts.js +134 -0
- package/lib/index.d.ts +2 -2
- package/lib/index.js +1 -1
- package/lib/logger.js +2 -1
- package/lib/mcp/api/operations.gen.d.ts +100 -48
- package/lib/mcp/api/operations.gen.js +1129 -194
- package/lib/mcp/api/to-zod.d.ts +24 -0
- package/lib/mcp/api/to-zod.js +94 -0
- package/lib/mcp/api/tools.js +1 -1
- package/lib/mcp/credentials/authenticate.d.ts +3 -0
- package/lib/mcp/{tools/credentials → credentials}/authenticate.js +3 -3
- package/lib/mcp/credentials/build.d.ts +5 -0
- package/lib/mcp/credentials/build.js +18 -0
- package/lib/mcp/{tools/credentials → credentials}/cache.d.ts +9 -9
- package/lib/mcp/{tools/credentials → credentials}/cache.js +36 -19
- package/lib/mcp/credentials/import.d.ts +2 -0
- package/lib/mcp/{tools/credentials → credentials}/import.js +2 -2
- package/lib/mcp/credentials/issue.d.ts +2 -0
- package/lib/mcp/{tools/credentials → credentials}/issue.js +4 -4
- package/lib/mcp/credentials/keypair.d.ts +17 -0
- package/lib/mcp/credentials/keypair.js +48 -0
- package/lib/mcp/credentials/link.d.ts +3 -0
- package/lib/mcp/credentials/link.js +107 -0
- package/lib/mcp/{tools/credentials → credentials}/list-cached.d.ts +1 -1
- package/lib/mcp/{tools/credentials → credentials}/list-cached.js +5 -5
- package/lib/mcp/credentials/owner-key.d.ts +23 -0
- package/lib/mcp/credentials/owner-key.js +58 -0
- package/lib/mcp/credentials/paths.d.ts +12 -0
- package/lib/mcp/credentials/paths.js +35 -0
- package/lib/mcp/credentials/poll.d.ts +27 -0
- package/lib/mcp/credentials/poll.js +61 -0
- package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.d.ts +1 -1
- package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.js +2 -2
- package/lib/mcp/credentials/session-cache.d.ts +14 -0
- package/lib/mcp/credentials/session-cache.js +42 -0
- package/lib/mcp/{tools/credentials → credentials}/status.d.ts +1 -1
- package/lib/mcp/credentials/status.js +76 -0
- package/lib/mcp/instructions.d.ts +1 -0
- package/lib/mcp/instructions.js +11 -0
- package/lib/mcp/register.d.ts +38 -0
- package/lib/mcp/register.js +80 -0
- package/lib/mcp/server.d.ts +2 -8
- package/lib/mcp/server.js +3 -33
- package/lib/mcp/start.js +17 -11
- package/lib/mcp/tools/agent/build.d.ts +5 -9
- package/lib/mcp/tools/agent/build.js +7 -24
- package/lib/mcp/tools/agent/index.d.ts +2 -0
- package/lib/mcp/tools/agent/index.js +3 -0
- package/lib/mcp/tools/agent/proof.js +3 -7
- package/lib/mcp/tools/agent/propose.js +13 -2
- package/lib/mcp/tools/agent/publish.js +172 -75
- package/lib/mcp/tools/agent/replay.js +0 -5
- package/lib/mcp/tools/analyze.d.ts +3 -0
- package/lib/mcp/tools/analyze.js +26 -0
- package/lib/mcp/tools/attach.d.ts +11 -0
- package/lib/mcp/tools/attach.js +72 -0
- package/lib/mcp/tools/authenticate/authenticate.js +107 -0
- package/lib/mcp/tools/authenticate/build.d.ts +15 -0
- package/lib/mcp/tools/authenticate/build.js +28 -0
- package/lib/mcp/tools/authenticate/decrypt-key.d.ts +19 -0
- package/lib/mcp/tools/authenticate/decrypt-key.js +46 -0
- package/lib/mcp/tools/authenticate/eth-key.d.ts +31 -0
- package/lib/mcp/tools/authenticate/eth-key.js +116 -0
- package/lib/mcp/tools/authenticate/import.js +57 -0
- package/lib/mcp/tools/authenticate/index.d.ts +2 -0
- package/lib/mcp/tools/authenticate/index.js +4 -0
- package/lib/mcp/tools/authenticate/issue.js +42 -0
- package/lib/mcp/tools/authenticate/resolve-owner-key.d.ts +13 -0
- package/lib/mcp/tools/authenticate/resolve-owner-key.js +53 -0
- package/lib/mcp/tools/capture.d.ts +10 -0
- package/lib/mcp/tools/capture.js +142 -0
- package/lib/mcp/tools/eval.d.ts +5 -0
- package/lib/mcp/tools/eval.js +127 -0
- package/lib/mcp/tools/find.d.ts +3 -0
- package/lib/mcp/tools/find.js +60 -0
- package/lib/mcp/tools/index.d.ts +3 -0
- package/lib/mcp/tools/index.js +6 -0
- package/lib/mcp/tools/owner-key.d.ts +2 -0
- package/lib/mcp/tools/owner-key.js +63 -0
- package/lib/mcp/tools/proof.d.ts +3 -0
- package/lib/mcp/tools/proof.js +214 -0
- package/lib/mcp/tools/propose.d.ts +9 -0
- package/lib/mcp/tools/propose.js +75 -0
- package/lib/mcp/tools/publish.d.ts +3 -0
- package/lib/mcp/tools/publish.js +59 -0
- package/lib/mcp/tools/replay.d.ts +3 -0
- package/lib/mcp/tools/replay.js +46 -0
- package/lib/mcp/tools/session.d.ts +10 -0
- package/lib/mcp/tools/session.js +29 -0
- package/lib/mcp/tools/verification/build.d.ts +12 -0
- package/lib/mcp/tools/verification/build.js +14 -0
- package/lib/mcp/tools/verification/diagnose.d.ts +11 -0
- package/lib/mcp/tools/verification/diagnose.js +132 -0
- package/lib/mcp/tools/verification/index.d.ts +1 -0
- package/lib/mcp/tools/verification/index.js +2 -0
- package/lib/mcp/tools/verification/result.d.ts +11 -0
- package/lib/mcp/tools/verification/result.js +126 -0
- package/lib/mcp/verifications/build.d.ts +5 -0
- package/lib/mcp/verifications/build.js +14 -0
- package/lib/mcp/verifications/create.d.ts +3 -0
- package/lib/mcp/verifications/create.js +57 -0
- package/lib/mcp/verifications/find.d.ts +3 -0
- package/lib/mcp/verifications/find.js +37 -0
- package/lib/mcp/verifications/get.d.ts +3 -0
- package/lib/mcp/verifications/get.js +26 -0
- package/lib/mcp/verifications/update.d.ts +3 -0
- package/lib/mcp/verifications/update.js +78 -0
- package/lib/old/client.d.ts +3 -0
- package/lib/old/flag.d.ts +4 -1
- package/lib/old/flag.js +4 -3
- package/lib/old/identity.d.ts +0 -10
- package/lib/old/identity.js +8 -7
- package/lib/old/instructions.d.ts +0 -6
- package/lib/old/instructions.js +6 -24
- package/lib/old/login-cdp.d.ts +0 -3
- package/lib/old/login-cdp.js +2 -4
- package/lib/old/to-register.d.ts +3 -0
- package/lib/old/to-register.js +32 -7
- package/lib/old/tools/authenticate.js +2 -1
- package/lib/old/tools/publish.js +71 -10
- package/lib/paths.js +2 -2
- package/lib/proof/attestor.d.ts +33 -1
- package/lib/proof/attestor.js +67 -64
- package/lib/proof/index.d.ts +5 -0
- package/lib/proof/index.js +6 -0
- package/lib/proof/proof-core.d.ts +35 -0
- package/lib/proof/proof-core.js +84 -0
- package/lib/provider/index.d.ts +5 -0
- package/lib/provider/index.js +9 -0
- package/lib/provider/injection-doc.d.ts +1 -0
- package/lib/provider/injection-doc.js +17 -0
- package/lib/provider/match-redaction-warning.d.ts +25 -0
- package/lib/provider/match-redaction-warning.js +35 -0
- package/lib/provider/schema.d.ts +16 -0
- package/lib/provider/schema.js +11 -1
- package/lib/provider/to-version.d.ts +61 -12
- package/lib/provider/to-version.js +109 -24
- package/lib/provider/verification-checks.d.ts +12 -0
- package/lib/provider/verification-checks.js +30 -0
- package/lib/routes.gen.d.ts +271 -0
- package/lib/routes.gen.js +73 -0
- package/lib/types/openapi.gen.d.ts +3967 -0
- package/lib/types/openapi.gen.js +5 -0
- package/package.json +16 -7
- package/skill/SKILL.md +35 -14
- package/skill/builder-mode.md +13 -0
- package/skill/injection-api.md +42 -0
- package/skill/old-mode.md +15 -0
- package/src/cdp/capture-engine.ts +256 -0
- package/src/cdp/capture.ts +25 -185
- package/src/cdp/index.ts +6 -0
- package/src/cdp/launcher.ts +5 -4
- package/src/config/store.ts +7 -6
- package/src/consts.ts +164 -0
- package/src/index.ts +2 -4
- package/src/logger.ts +2 -1
- package/src/mcp/api/operations.gen.ts +1155 -194
- package/src/mcp/api/to-zod.ts +115 -0
- package/src/mcp/api/tools.ts +9 -3
- package/src/mcp/instructions.ts +15 -0
- package/src/mcp/server.ts +5 -50
- package/src/mcp/start.ts +27 -11
- package/src/mcp/tools/agent/build.ts +7 -27
- package/src/mcp/tools/agent/index.ts +4 -0
- package/src/mcp/tools/agent/proof.ts +3 -8
- package/src/mcp/tools/agent/propose.ts +13 -2
- package/src/mcp/tools/agent/publish.ts +218 -92
- package/src/mcp/tools/agent/replay.ts +0 -5
- package/src/mcp/tools/{credentials → authenticate}/authenticate.ts +9 -8
- package/src/mcp/tools/authenticate/build.ts +32 -0
- package/src/mcp/tools/authenticate/decrypt-key.ts +59 -0
- package/src/mcp/tools/authenticate/eth-key.ts +162 -0
- package/src/mcp/tools/authenticate/import.ts +73 -0
- package/src/mcp/tools/authenticate/index.ts +4 -0
- package/src/mcp/tools/authenticate/issue.ts +50 -0
- package/src/mcp/tools/authenticate/resolve-owner-key.ts +60 -0
- package/src/mcp/tools/index.ts +6 -0
- package/src/mcp/tools/verification/build.ts +16 -0
- package/src/mcp/tools/verification/index.ts +2 -0
- package/src/mcp/tools/verification/result.ts +154 -0
- package/src/old/client.ts +3 -0
- package/src/old/flag.ts +4 -3
- package/src/old/identity.ts +8 -7
- package/src/old/instructions.ts +10 -25
- package/src/old/login-cdp.ts +2 -5
- package/src/old/to-register.ts +58 -26
- package/src/old/tools/authenticate.ts +2 -1
- package/src/old/tools/publish.ts +92 -16
- package/src/paths.ts +2 -2
- package/src/proof/attestor.ts +114 -72
- package/src/proof/index.ts +21 -0
- package/src/proof/proof-core.ts +119 -0
- package/src/provider/index.ts +20 -0
- package/src/provider/injection-doc.ts +21 -0
- package/src/provider/match-redaction-warning.ts +53 -0
- package/src/provider/schema.ts +23 -0
- package/src/provider/to-version.ts +180 -33
- package/src/provider/verification-checks.ts +36 -0
- package/lib/mcp/tools/credentials/build.d.ts +0 -16
- package/lib/mcp/tools/credentials/build.js +0 -33
- package/lib/mcp/tools/credentials/status.js +0 -62
- package/src/mcp/tools/credentials/build.ts +0 -37
- package/src/mcp/tools/credentials/cache.ts +0 -161
- package/src/mcp/tools/credentials/env-file.ts +0 -101
- package/src/mcp/tools/credentials/import.ts +0 -72
- package/src/mcp/tools/credentials/issue.ts +0 -107
- package/src/mcp/tools/credentials/list-cached.ts +0 -66
- package/src/mcp/tools/credentials/register.ts +0 -49
- package/src/mcp/tools/credentials/resolve-owner-key.ts +0 -78
- package/src/mcp/tools/credentials/status.ts +0 -82
- package/src/types/openapi.ts +0 -7
- /package/lib/mcp/{tools/credentials → credentials}/env-file.d.ts +0 -0
- /package/lib/mcp/{tools/credentials → credentials}/env-file.js +0 -0
- /package/lib/mcp/{tools/credentials → credentials}/register.d.ts +0 -0
- /package/lib/mcp/{tools/credentials → credentials}/register.js +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/authenticate.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/import.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/issue.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/session-cache.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/session-cache.js +0 -0
- /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
|
+
}
|
package/lib/provider/schema.d.ts
CHANGED
|
@@ -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;
|
package/lib/provider/schema.js
CHANGED
|
@@ -1 +1,11 @@
|
|
|
1
|
-
|
|
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
|
|
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
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
-
*
|
|
13
|
-
*
|
|
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
|
|
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<
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
+
}
|