@reclaimprotocol/agent 0.1.6 → 0.1.9
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 +39 -2
- package/lib/authoring/tools.js +2 -2
- package/lib/cdp/eviction.js +30 -17
- package/lib/cdp/launcher.js +1 -1
- package/lib/config/store.js +20 -7
- package/lib/mcp/tools/agent/attach.js +2 -2
- package/lib/old/client.d.ts +4 -0
- package/lib/old/client.js +107 -101
- package/lib/old/login-cdp.js +2 -2
- package/lib/old/sdk-client.js +55 -43
- package/lib/old/to-register.d.ts +2 -2
- package/lib/old/to-register.js +6 -3
- package/lib/old/tools/publish.js +29 -10
- package/lib/proof/zk-files.js +2 -2
- package/package.json +3 -3
- package/src/old/client.ts +4 -0
- package/src/old/to-register.ts +9 -5
- package/src/old/tools/publish.ts +30 -10
package/README.md
CHANGED
|
@@ -6,7 +6,9 @@ This package **is** the Reclaim MCP server (bin: `reclaim-mcp-server`). It depen
|
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
-
**Prerequisites:** Node ≥ 22
|
|
9
|
+
**Prerequisites:** **Node ≥ 20** — **works best on a current LTS release (22 or 24)** — and a local Chrome / Chromium / Edge (used for capture and the dashboard login). The first time you call `run_proof`, the agent downloads the ZK circuit files it needs (~280 MB) — so allow a moment for that first proof. The download is deferred to first proof on purpose (not an install step), so the MCP server itself starts immediately.
|
|
10
|
+
|
|
11
|
+
> **Any Node ≥ 20 works, including non-LTS lines like 25** however an LTS line (22 or 24) is *recommended*.
|
|
10
12
|
|
|
11
13
|
It runs as a **stdio MCP server**. Point any MCP-capable agent at this command:
|
|
12
14
|
|
|
@@ -18,6 +20,17 @@ npx -y --package=@reclaimprotocol/agent reclaim-mcp-server
|
|
|
18
20
|
|
|
19
21
|
### Claude Code
|
|
20
22
|
|
|
23
|
+
**Recommended — install the plugin from the marketplace** (bundles this MCP server; no `claude mcp add` and no `-p` collision to worry about — the server's `how_it_works` tool serves the authoring guide on demand):
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
/plugin marketplace add reclaimprotocol/builder
|
|
27
|
+
/plugin install reclaim@reclaim
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This is the preferred path — prefer it over the manual `claude mcp add` below unless you have a specific reason not to (e.g. you're pinning a local build).
|
|
31
|
+
|
|
32
|
+
**Advanced / fallback — add the MCP server directly** (skip if you used the plugin above):
|
|
33
|
+
|
|
21
34
|
```bash
|
|
22
35
|
# project scope → writes .mcp.json; add `-s user` for a global install
|
|
23
36
|
claude mcp add reclaim -- npx -y --package=@reclaimprotocol/agent reclaim-mcp-server
|
|
@@ -36,6 +49,30 @@ claude mcp add reclaim -- npx -y --package=@reclaimprotocol/agent reclaim-mcp-se
|
|
|
36
49
|
}
|
|
37
50
|
```
|
|
38
51
|
|
|
52
|
+
### Claude Desktop (macOS / Windows app)
|
|
53
|
+
|
|
54
|
+
Claude Desktop is the standalone consumer app — **separate from Claude Code**, and it does **not** support the plugin marketplace (`/plugin …` is Claude Code only). Configure the MCP server manually via its config file:
|
|
55
|
+
|
|
56
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
57
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
58
|
+
|
|
59
|
+
Edit it (via **Settings → Developer → Edit Config**, or open the file directly) and add:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"reclaim": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["-y", "--package=@reclaimprotocol/agent", "reclaim-mcp-server"]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Then **fully quit and reopen** Claude Desktop (a window close is not enough) so it re-reads the config and starts the server.
|
|
73
|
+
|
|
74
|
+
> **Node must be on the app's PATH.** Claude Desktop launches the server as a subprocess using the environment it inherits at startup — it does **not** bundle Node. If the server shows as failed, either install Node ≥ 20 and relaunch, or set `"command"` to an **absolute path** to `npx`/`node` (find it with `which npx`), since GUI-launched apps sometimes get a minimal PATH. Chrome capture works the same as anywhere else — see [Chrome / CDP](#platform-notes).
|
|
75
|
+
|
|
39
76
|
### Cursor
|
|
40
77
|
|
|
41
78
|
Add to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project):
|
|
@@ -189,7 +226,7 @@ npm run download:zk-files --workspace=packages/agent
|
|
|
189
226
|
|
|
190
227
|
## Platform notes
|
|
191
228
|
|
|
192
|
-
- **Node >=
|
|
229
|
+
- **Node >=20** is required to run the published package (declared in `engines`) — it ships compiled `lib/*.js`, so no TypeScript type-stripping is needed at runtime. Any line ≥ 20 works, including non-LTS like 25: the one native addon that used to break this, `re2`, is an **optional** dependency as of `@reclaimprotocol/attestor-core` 5.0.8 and degrades to native `RegExp` when its binary is absent. (The other native dep, `koffi`, is N-API — ABI-independent, all-platform prebuilts — so it was never version-sensitive.) An LTS line (22/24) is recommended so `re2` is present for faster, ReDoS-safe matching. Working on the package **from a checkout** additionally needs **Node >=22.18**, because the test suite and dev workflow run bare `.ts` files directly and unflagged TypeScript type-stripping landed in 22.18.
|
|
193
230
|
- **Chrome 136+ silently disables `--remote-debugging-port`** when launched against the default user profile. `dedicated` mode (the default) sidesteps this by always passing `--user-data-dir=~/.reclaim/chrome-profile`.
|
|
194
231
|
|
|
195
232
|
## Tests
|
package/lib/authoring/tools.js
CHANGED
|
@@ -81,7 +81,7 @@ export function authoringTools(resolveBackend) {
|
|
|
81
81
|
inputSchema: objectSchema({ url: { type: 'string' }, timeoutMs: { type: 'number' } }, ['url']),
|
|
82
82
|
}, async (args) => {
|
|
83
83
|
const backend = resolveBackend(args);
|
|
84
|
-
const timeoutMs = Number(args.timeoutMs) ||
|
|
84
|
+
const timeoutMs = Number(args.timeoutMs) || 30000;
|
|
85
85
|
await backend.sendCdp('Page.enable');
|
|
86
86
|
// Start listening BEFORE navigating so the load event isn't missed.
|
|
87
87
|
const load = backend.waitForEvent('Page.loadEventFired', timeoutMs);
|
|
@@ -107,7 +107,7 @@ export function authoringTools(resolveBackend) {
|
|
|
107
107
|
}, async (args) => {
|
|
108
108
|
const backend = resolveBackend(args);
|
|
109
109
|
const expr = String(args.expression);
|
|
110
|
-
const deadline = Date.now() + (Number(args.timeoutMs) ||
|
|
110
|
+
const deadline = Date.now() + (Number(args.timeoutMs) || 180000);
|
|
111
111
|
while (Date.now() < deadline) {
|
|
112
112
|
const { value } = await evalInPage(backend, expr);
|
|
113
113
|
if (value) {
|
package/lib/cdp/eviction.js
CHANGED
|
@@ -1,26 +1,38 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _BodyStore_store, _BodyStore_bytes, _BodyStore_opts;
|
|
1
13
|
export class BodyStore {
|
|
2
|
-
#store = new Map(); // insertion order = LRU order
|
|
3
|
-
#bytes = 0;
|
|
4
|
-
#opts;
|
|
5
14
|
constructor(opts) {
|
|
6
|
-
this
|
|
15
|
+
_BodyStore_store.set(this, new Map()); // insertion order = LRU order
|
|
16
|
+
_BodyStore_bytes.set(this, 0);
|
|
17
|
+
_BodyStore_opts.set(this, void 0);
|
|
18
|
+
__classPrivateFieldSet(this, _BodyStore_opts, opts, "f");
|
|
7
19
|
}
|
|
8
20
|
set(requestId, body) {
|
|
9
|
-
if (this
|
|
10
|
-
this
|
|
11
|
-
this
|
|
21
|
+
if (__classPrivateFieldGet(this, _BodyStore_store, "f").has(requestId)) {
|
|
22
|
+
__classPrivateFieldSet(this, _BodyStore_bytes, __classPrivateFieldGet(this, _BodyStore_bytes, "f") - byteLen(__classPrivateFieldGet(this, _BodyStore_store, "f").get(requestId)), "f");
|
|
23
|
+
__classPrivateFieldGet(this, _BodyStore_store, "f").delete(requestId);
|
|
12
24
|
}
|
|
13
|
-
this
|
|
14
|
-
this
|
|
15
|
-
while (this
|
|
16
|
-
const oldestKey = this
|
|
17
|
-
const oldestVal = this
|
|
18
|
-
this
|
|
19
|
-
this
|
|
25
|
+
__classPrivateFieldGet(this, _BodyStore_store, "f").set(requestId, body);
|
|
26
|
+
__classPrivateFieldSet(this, _BodyStore_bytes, __classPrivateFieldGet(this, _BodyStore_bytes, "f") + byteLen(body), "f");
|
|
27
|
+
while (__classPrivateFieldGet(this, _BodyStore_bytes, "f") > __classPrivateFieldGet(this, _BodyStore_opts, "f").maxBytes && __classPrivateFieldGet(this, _BodyStore_store, "f").size > 0) {
|
|
28
|
+
const oldestKey = __classPrivateFieldGet(this, _BodyStore_store, "f").keys().next().value;
|
|
29
|
+
const oldestVal = __classPrivateFieldGet(this, _BodyStore_store, "f").get(oldestKey);
|
|
30
|
+
__classPrivateFieldSet(this, _BodyStore_bytes, __classPrivateFieldGet(this, _BodyStore_bytes, "f") - byteLen(oldestVal), "f");
|
|
31
|
+
__classPrivateFieldGet(this, _BodyStore_store, "f").delete(oldestKey);
|
|
20
32
|
}
|
|
21
33
|
}
|
|
22
34
|
get(requestId) {
|
|
23
|
-
const body = this
|
|
35
|
+
const body = __classPrivateFieldGet(this, _BodyStore_store, "f").get(requestId);
|
|
24
36
|
if (body === undefined) {
|
|
25
37
|
return {
|
|
26
38
|
available: false,
|
|
@@ -28,11 +40,12 @@ export class BodyStore {
|
|
|
28
40
|
};
|
|
29
41
|
}
|
|
30
42
|
// Refresh LRU position by re-inserting.
|
|
31
|
-
this
|
|
32
|
-
this
|
|
43
|
+
__classPrivateFieldGet(this, _BodyStore_store, "f").delete(requestId);
|
|
44
|
+
__classPrivateFieldGet(this, _BodyStore_store, "f").set(requestId, body);
|
|
33
45
|
return { available: true, body };
|
|
34
46
|
}
|
|
35
47
|
}
|
|
48
|
+
_BodyStore_store = new WeakMap(), _BodyStore_bytes = new WeakMap(), _BodyStore_opts = new WeakMap();
|
|
36
49
|
function byteLen(s) {
|
|
37
50
|
return Buffer.byteLength(s, 'utf8');
|
|
38
51
|
}
|
package/lib/cdp/launcher.js
CHANGED
|
@@ -85,7 +85,7 @@ export function launchChrome(opts) {
|
|
|
85
85
|
});
|
|
86
86
|
return child;
|
|
87
87
|
}
|
|
88
|
-
export async function waitForCdpReady(port, timeoutMs =
|
|
88
|
+
export async function waitForCdpReady(port, timeoutMs = 10000) {
|
|
89
89
|
const deadline = Date.now() + timeoutMs;
|
|
90
90
|
while (Date.now() < deadline) {
|
|
91
91
|
try {
|
package/lib/config/store.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _ConfigStore_path;
|
|
1
13
|
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
|
|
2
14
|
import { dirname, join } from 'node:path';
|
|
3
15
|
import { reclaimHomeDirPath } from "../paths.js";
|
|
@@ -9,16 +21,16 @@ import { reclaimHomeDirPath } from "../paths.js";
|
|
|
9
21
|
* own validation (token expiry, credential shape) on top.
|
|
10
22
|
*/
|
|
11
23
|
export class ConfigStore {
|
|
12
|
-
#path;
|
|
13
24
|
constructor(path = defaultConfigPath()) {
|
|
14
|
-
this
|
|
25
|
+
_ConfigStore_path.set(this, void 0);
|
|
26
|
+
__classPrivateFieldSet(this, _ConfigStore_path, path, "f");
|
|
15
27
|
}
|
|
16
28
|
read() {
|
|
17
|
-
if (!existsSync(this
|
|
29
|
+
if (!existsSync(__classPrivateFieldGet(this, _ConfigStore_path, "f"))) {
|
|
18
30
|
return undefined;
|
|
19
31
|
}
|
|
20
32
|
try {
|
|
21
|
-
return JSON.parse(readFileSync(this
|
|
33
|
+
return JSON.parse(readFileSync(__classPrivateFieldGet(this, _ConfigStore_path, "f"), 'utf8'));
|
|
22
34
|
}
|
|
23
35
|
catch {
|
|
24
36
|
return undefined;
|
|
@@ -31,16 +43,17 @@ export class ConfigStore {
|
|
|
31
43
|
*/
|
|
32
44
|
write(patch) {
|
|
33
45
|
const next = { ...this.read(), ...patch, version: 1 };
|
|
34
|
-
const dir = dirname(this
|
|
46
|
+
const dir = dirname(__classPrivateFieldGet(this, _ConfigStore_path, "f"));
|
|
35
47
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
36
48
|
chmodSync(dir, 0o700);
|
|
37
|
-
writeFileSync(this
|
|
49
|
+
writeFileSync(__classPrivateFieldGet(this, _ConfigStore_path, "f"), JSON.stringify(next, null, 2) + '\n', {
|
|
38
50
|
mode: 0o600,
|
|
39
51
|
});
|
|
40
|
-
chmodSync(this
|
|
52
|
+
chmodSync(__classPrivateFieldGet(this, _ConfigStore_path, "f"), 0o600);
|
|
41
53
|
return next;
|
|
42
54
|
}
|
|
43
55
|
}
|
|
56
|
+
_ConfigStore_path = new WeakMap();
|
|
44
57
|
export function defaultConfigPath() {
|
|
45
58
|
return join(reclaimHomeDirPath(), 'config.json');
|
|
46
59
|
}
|
|
@@ -46,11 +46,11 @@ export function attachTool(state) {
|
|
|
46
46
|
}
|
|
47
47
|
catch {
|
|
48
48
|
launchChrome({ port: cfg.port, profileDir: defaultProfileDir() });
|
|
49
|
-
await waitForCdpReady(cfg.port,
|
|
49
|
+
await waitForCdpReady(cfg.port, 10000);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
else {
|
|
53
|
-
await waitForCdpReady(cfg.port,
|
|
53
|
+
await waitForCdpReady(cfg.port, 2000).catch(() => {
|
|
54
54
|
throw new Error(`attach mode: nothing answering CDP on port ${cfg.port}. ` +
|
|
55
55
|
'Chrome must be launched with BOTH ' +
|
|
56
56
|
`--remote-debugging-port=${cfg.port} AND ` +
|
package/lib/old/client.d.ts
CHANGED
|
@@ -44,6 +44,10 @@ export interface RegisterProviderBody {
|
|
|
44
44
|
};
|
|
45
45
|
/** Accepted at register too. */
|
|
46
46
|
pageTitle?: string;
|
|
47
|
+
/** Accepted at register too — verified straight from the register
|
|
48
|
+
* controller's destructure + its `providerConfig` write, both of which
|
|
49
|
+
* include it alongside `pageTitle`/`userAgent`. */
|
|
50
|
+
stepsToFollow?: string;
|
|
47
51
|
}
|
|
48
52
|
export interface UpdateProviderConfigBody {
|
|
49
53
|
providerConfig: Record<string, unknown>;
|
package/lib/old/client.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _ReclaimOldClient_instances, _ReclaimOldClient_identity, _ReclaimOldClient_fetch, _ReclaimOldClient_request, _ReclaimOldClient_authHeaderName, _ReclaimOldClient_authHeaderValue, _ReclaimOldClient_requireIdentity, _ReclaimOldClient_parseBody, _ReclaimOldClient_asBoom;
|
|
1
13
|
import { Boom } from '@hapi/boom';
|
|
2
14
|
import { NAME, VERSION } from "../pkg.js";
|
|
3
15
|
/** Default origin of the OLD devtools backend. The client appends the
|
|
@@ -18,43 +30,42 @@ export const DEFAULT_OLD_LOGS_URL = 'https://logs.reclaimprotocol.org';
|
|
|
18
30
|
* identically to builder-mode `ProblemError`s.
|
|
19
31
|
*/
|
|
20
32
|
export class ReclaimOldClient {
|
|
21
|
-
baseUrl;
|
|
22
|
-
logsBaseUrl;
|
|
23
|
-
#identity;
|
|
24
|
-
#fetch;
|
|
25
33
|
constructor(opts = {}) {
|
|
34
|
+
_ReclaimOldClient_instances.add(this);
|
|
35
|
+
_ReclaimOldClient_identity.set(this, void 0);
|
|
36
|
+
_ReclaimOldClient_fetch.set(this, void 0);
|
|
26
37
|
this.baseUrl = (opts.baseUrl || DEFAULT_OLD_API_URL).replace(/\/+$/, '');
|
|
27
38
|
this.logsBaseUrl = (opts.logsBaseUrl || DEFAULT_OLD_LOGS_URL)
|
|
28
39
|
.replace(/\/+$/, '');
|
|
29
|
-
this
|
|
30
|
-
this
|
|
40
|
+
__classPrivateFieldSet(this, _ReclaimOldClient_identity, opts.identity, "f");
|
|
41
|
+
__classPrivateFieldSet(this, _ReclaimOldClient_fetch, opts.fetch ?? fetch, "f");
|
|
31
42
|
}
|
|
32
43
|
setIdentity(identity) {
|
|
33
|
-
this
|
|
44
|
+
__classPrivateFieldSet(this, _ReclaimOldClient_identity, identity, "f");
|
|
34
45
|
}
|
|
35
46
|
getIdentity() {
|
|
36
|
-
return this
|
|
47
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_identity, "f");
|
|
37
48
|
}
|
|
38
49
|
/** Validate + provision a bearer identity. The backend creates the user
|
|
39
50
|
* row on first login, which is what makes later authed calls work. */
|
|
40
51
|
loginWithToken() {
|
|
41
|
-
return this
|
|
52
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', '/users/login', { auth: true });
|
|
42
53
|
}
|
|
43
54
|
registerProvider(body) {
|
|
44
|
-
return this
|
|
55
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', '/providers/register', { body, auth: true });
|
|
45
56
|
}
|
|
46
57
|
updateProviderConfig(providerId, body) {
|
|
47
|
-
return this
|
|
58
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', `/providers/${encodeURIComponent(providerId)}/config`, { body, auth: true });
|
|
48
59
|
}
|
|
49
60
|
listVersions(providerId) {
|
|
50
|
-
return this
|
|
61
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', `/providers/${encodeURIComponent(providerId)}/versions`, { auth: true });
|
|
51
62
|
}
|
|
52
63
|
/** Full `providerConfig` (loginUrl, customInjection, requestData, ...) for
|
|
53
64
|
* one version — the latest when `version` is omitted. Readable for ANY
|
|
54
65
|
* non-archived provider (not owner-restricted), same as the dashboard's
|
|
55
66
|
* edit-form prefill fetch. */
|
|
56
67
|
getProviderConfig(providerId, version) {
|
|
57
|
-
return this
|
|
68
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', `/providers/${encodeURIComponent(providerId)}/config`, {
|
|
58
69
|
auth: true,
|
|
59
70
|
query: version ? { versionNumber: version } : undefined,
|
|
60
71
|
});
|
|
@@ -65,7 +76,7 @@ export class ReclaimOldClient {
|
|
|
65
76
|
* fields sent here are simply ignored (this endpoint only reads the
|
|
66
77
|
* ones above from the body). */
|
|
67
78
|
updateProviderMetadata(providerId, body) {
|
|
68
|
-
return this
|
|
79
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', `/providers/${encodeURIComponent(providerId)}`, { body, auth: true });
|
|
69
80
|
}
|
|
70
81
|
/** Analytics logs for a verification session, from the logs service (a
|
|
71
82
|
* DIFFERENT host than the devtools API — hence its own fetch, not
|
|
@@ -78,20 +89,20 @@ export class ReclaimOldClient {
|
|
|
78
89
|
Accept: 'application/json',
|
|
79
90
|
'User-Agent': `${NAME}/${VERSION}`,
|
|
80
91
|
};
|
|
81
|
-
if (this
|
|
82
|
-
headers[this
|
|
92
|
+
if (__classPrivateFieldGet(this, _ReclaimOldClient_identity, "f")) {
|
|
93
|
+
headers[__classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_authHeaderName).call(this)] = __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_authHeaderValue).call(this);
|
|
83
94
|
}
|
|
84
|
-
const res = await this
|
|
85
|
-
const json = await this
|
|
95
|
+
const res = await __classPrivateFieldGet(this, _ReclaimOldClient_fetch, "f").call(this, url, { method: 'GET', headers });
|
|
96
|
+
const json = await __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_parseBody).call(this, res);
|
|
86
97
|
if (!res.ok) {
|
|
87
|
-
throw this
|
|
98
|
+
throw __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_asBoom).call(this, res, json);
|
|
88
99
|
}
|
|
89
100
|
return json;
|
|
90
101
|
}
|
|
91
102
|
getMyProviders(query = {}) {
|
|
92
103
|
// Every one of these query params is REQUIRED by the backend
|
|
93
104
|
// validator (missing/invalid → 400), so default them all here.
|
|
94
|
-
return this
|
|
105
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', '/providers/user/paginated', {
|
|
95
106
|
auth: true,
|
|
96
107
|
query: {
|
|
97
108
|
pageKey: query.pageKey ?? 0,
|
|
@@ -104,88 +115,83 @@ export class ReclaimOldClient {
|
|
|
104
115
|
},
|
|
105
116
|
});
|
|
106
117
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
search.append(k, String(v));
|
|
116
|
-
}
|
|
117
|
-
const qs = search.toString();
|
|
118
|
-
if (qs) {
|
|
119
|
-
url += `?${qs}`;
|
|
118
|
+
}
|
|
119
|
+
_ReclaimOldClient_identity = new WeakMap(), _ReclaimOldClient_fetch = new WeakMap(), _ReclaimOldClient_instances = new WeakSet(), _ReclaimOldClient_request = async function _ReclaimOldClient_request(method, path, opts = {}) {
|
|
120
|
+
let url = `${this.baseUrl}/api${path}`;
|
|
121
|
+
if (opts.query) {
|
|
122
|
+
const search = new URLSearchParams();
|
|
123
|
+
for (const [k, v] of Object.entries(opts.query)) {
|
|
124
|
+
if (v === undefined) {
|
|
125
|
+
continue;
|
|
120
126
|
}
|
|
127
|
+
search.append(k, String(v));
|
|
121
128
|
}
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
};
|
|
126
|
-
if (opts.auth) {
|
|
127
|
-
headers[this.#authHeaderName()] = this.#authHeaderValue();
|
|
129
|
+
const qs = search.toString();
|
|
130
|
+
if (qs) {
|
|
131
|
+
url += `?${qs}`;
|
|
128
132
|
}
|
|
129
|
-
const init = { method, headers };
|
|
130
|
-
if (method !== 'GET' && method !== 'HEAD') {
|
|
131
|
-
init.body = JSON.stringify(opts.body ?? {});
|
|
132
|
-
headers['Content-Type'] = 'application/json';
|
|
133
|
-
}
|
|
134
|
-
const res = await this.#fetch(url, init);
|
|
135
|
-
const json = await this.#parseBody(res);
|
|
136
|
-
// Old API convention: { message, ...data, isSuccess }. Treat a non-2xx
|
|
137
|
-
// OR an explicit isSuccess:false as an error so a 200-with-failure
|
|
138
|
-
// body never slips through as success.
|
|
139
|
-
const failed = !res.ok ||
|
|
140
|
-
(json !== undefined &&
|
|
141
|
-
typeof json === 'object' &&
|
|
142
|
-
json.isSuccess === false);
|
|
143
|
-
if (failed) {
|
|
144
|
-
throw this.#asBoom(res, json);
|
|
145
|
-
}
|
|
146
|
-
return json;
|
|
147
|
-
}
|
|
148
|
-
#authHeaderName() {
|
|
149
|
-
const id = this.#requireIdentity();
|
|
150
|
-
return id.kind === 'bearer' ? 'Authorization' : 'x-eth-uid';
|
|
151
|
-
}
|
|
152
|
-
#authHeaderValue() {
|
|
153
|
-
const id = this.#requireIdentity();
|
|
154
|
-
return id.kind === 'bearer' ? `Bearer ${id.token}` : id.uid;
|
|
155
133
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
134
|
+
const headers = {
|
|
135
|
+
Accept: 'application/json',
|
|
136
|
+
'User-Agent': `${NAME}/${VERSION}`,
|
|
137
|
+
};
|
|
138
|
+
if (opts.auth) {
|
|
139
|
+
headers[__classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_authHeaderName).call(this)] = __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_authHeaderValue).call(this);
|
|
140
|
+
}
|
|
141
|
+
const init = { method, headers };
|
|
142
|
+
if (method !== 'GET' && method !== 'HEAD') {
|
|
143
|
+
init.body = JSON.stringify(opts.body ?? {});
|
|
144
|
+
headers['Content-Type'] = 'application/json';
|
|
145
|
+
}
|
|
146
|
+
const res = await __classPrivateFieldGet(this, _ReclaimOldClient_fetch, "f").call(this, url, init);
|
|
147
|
+
const json = await __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_parseBody).call(this, res);
|
|
148
|
+
// Old API convention: { message, ...data, isSuccess }. Treat a non-2xx
|
|
149
|
+
// OR an explicit isSuccess:false as an error so a 200-with-failure
|
|
150
|
+
// body never slips through as success.
|
|
151
|
+
const failed = !res.ok ||
|
|
152
|
+
(json !== undefined &&
|
|
153
|
+
typeof json === 'object' &&
|
|
154
|
+
json.isSuccess === false);
|
|
155
|
+
if (failed) {
|
|
156
|
+
throw __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_asBoom).call(this, res, json);
|
|
157
|
+
}
|
|
158
|
+
return json;
|
|
159
|
+
}, _ReclaimOldClient_authHeaderName = function _ReclaimOldClient_authHeaderName() {
|
|
160
|
+
const id = __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_requireIdentity).call(this);
|
|
161
|
+
return id.kind === 'bearer' ? 'Authorization' : 'x-eth-uid';
|
|
162
|
+
}, _ReclaimOldClient_authHeaderValue = function _ReclaimOldClient_authHeaderValue() {
|
|
163
|
+
const id = __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_requireIdentity).call(this);
|
|
164
|
+
return id.kind === 'bearer' ? `Bearer ${id.token}` : id.uid;
|
|
165
|
+
}, _ReclaimOldClient_requireIdentity = function _ReclaimOldClient_requireIdentity() {
|
|
166
|
+
if (!__classPrivateFieldGet(this, _ReclaimOldClient_identity, "f")) {
|
|
167
|
+
throw new Boom('Not authenticated against old devtools. Call reclaim_authenticate ' +
|
|
168
|
+
'with a dashboard token (or eth uid) first.', { statusCode: 401, data: { status: 401, detail: 'no identity set' } });
|
|
169
|
+
}
|
|
170
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_identity, "f");
|
|
171
|
+
}, _ReclaimOldClient_parseBody = async function _ReclaimOldClient_parseBody(res) {
|
|
172
|
+
if (res.status === 204 || res.headers.get('content-length') === '0') {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
return await res.json();
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
}, _ReclaimOldClient_asBoom = function _ReclaimOldClient_asBoom(res, json) {
|
|
182
|
+
const message = (json && typeof json === 'object' &&
|
|
183
|
+
typeof json.message === 'string'
|
|
184
|
+
? json.message
|
|
185
|
+
: undefined) || res.statusText || 'Old devtools request failed';
|
|
186
|
+
// Shape `data` like a ProblemDetails so remapErrorAsResponse can render
|
|
187
|
+
// `${message}: ${data.detail}` and expose the raw body as structured.
|
|
188
|
+
return new Boom(message, {
|
|
189
|
+
statusCode: res.ok ? 502 : res.status,
|
|
190
|
+
data: {
|
|
191
|
+
status: res.status,
|
|
192
|
+
title: message,
|
|
193
|
+
detail: message,
|
|
194
|
+
body: json,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
};
|
package/lib/old/login-cdp.js
CHANGED
|
@@ -88,7 +88,7 @@ export const EXTRACT_TOKEN_JS = `(async () => {
|
|
|
88
88
|
*/
|
|
89
89
|
export async function captureFirebaseTokenViaCdp(opts) {
|
|
90
90
|
const loginUrl = opts.loginUrl || oldLoginUrl() || DEFAULT_LOGIN_URL;
|
|
91
|
-
const timeoutMs = opts.timeoutMs ??
|
|
91
|
+
const timeoutMs = opts.timeoutMs ?? 180000;
|
|
92
92
|
const pollMs = opts.pollMs ?? 1000;
|
|
93
93
|
const cfg = new ConfigStore().read()?.browser_agent;
|
|
94
94
|
const mode = cfg?.attachMode ?? 'dedicated';
|
|
@@ -105,7 +105,7 @@ export async function captureFirebaseTokenViaCdp(opts) {
|
|
|
105
105
|
'--user-data-dir, or switch to dedicated mode (attach_chrome).');
|
|
106
106
|
}
|
|
107
107
|
launchChrome({ port, profileDir: defaultProfileDir() });
|
|
108
|
-
await waitForCdpReady(port,
|
|
108
|
+
await waitForCdpReady(port, 10000);
|
|
109
109
|
launchedByUs = true;
|
|
110
110
|
}
|
|
111
111
|
const handles = await connectCdp(port);
|
package/lib/old/sdk-client.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _ReclaimSdkClient_instances, _ReclaimSdkClient_fetch, _ReclaimSdkClient_get;
|
|
1
13
|
import { Boom } from '@hapi/boom';
|
|
2
14
|
import { NAME, VERSION } from "../pkg.js";
|
|
3
15
|
/**
|
|
@@ -25,61 +37,61 @@ export const DEFAULT_SDK_API_URL = 'https://api.reclaimprotocol.org';
|
|
|
25
37
|
* the same way as every other tool in this package.
|
|
26
38
|
*/
|
|
27
39
|
export class ReclaimSdkClient {
|
|
28
|
-
baseUrl;
|
|
29
|
-
#fetch;
|
|
30
40
|
constructor(opts = {}) {
|
|
41
|
+
_ReclaimSdkClient_instances.add(this);
|
|
42
|
+
_ReclaimSdkClient_fetch.set(this, void 0);
|
|
31
43
|
this.baseUrl = (opts.baseUrl || DEFAULT_SDK_API_URL).replace(/\/+$/, '');
|
|
32
|
-
this
|
|
44
|
+
__classPrivateFieldSet(this, _ReclaimSdkClient_fetch, opts.fetch ?? fetch, "f");
|
|
33
45
|
}
|
|
34
46
|
/** Full provider + providerConfig (includes `customInjection`). Latest
|
|
35
47
|
* version when `versionNumber` is omitted. */
|
|
36
48
|
getProvider(providerId, versionNumber) {
|
|
37
|
-
return this
|
|
49
|
+
return __classPrivateFieldGet(this, _ReclaimSdkClient_instances, "m", _ReclaimSdkClient_get).call(this, `/providers/${encodeURIComponent(providerId)}`, versionNumber);
|
|
38
50
|
}
|
|
39
51
|
/** Trimmed runtime recipe (no `customInjection`; adds
|
|
40
52
|
* `isScriptRequestingClaim`). Latest version when `versionNumber` is
|
|
41
53
|
* omitted. */
|
|
42
54
|
getProviderConfigs(providerId, versionNumber) {
|
|
43
|
-
return this
|
|
55
|
+
return __classPrivateFieldGet(this, _ReclaimSdkClient_instances, "m", _ReclaimSdkClient_get).call(this, `/providers/${encodeURIComponent(providerId)}/configs`, versionNumber);
|
|
44
56
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
}
|
|
58
|
+
_ReclaimSdkClient_fetch = new WeakMap(), _ReclaimSdkClient_instances = new WeakSet(), _ReclaimSdkClient_get = async function _ReclaimSdkClient_get(path, versionNumber) {
|
|
59
|
+
let url = `${this.baseUrl}/api${path}`;
|
|
60
|
+
if (versionNumber) {
|
|
61
|
+
url += `?versionNumber=${encodeURIComponent(versionNumber)}`;
|
|
62
|
+
}
|
|
63
|
+
const res = await __classPrivateFieldGet(this, _ReclaimSdkClient_fetch, "f").call(this, url, {
|
|
64
|
+
method: 'GET',
|
|
65
|
+
headers: {
|
|
66
|
+
Accept: 'application/json',
|
|
67
|
+
'User-Agent': `${NAME}/${VERSION}`,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
let json;
|
|
71
|
+
try {
|
|
72
|
+
json = await res.json();
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
json = undefined;
|
|
76
|
+
}
|
|
77
|
+
const failed = !res.ok ||
|
|
78
|
+
(json !== undefined &&
|
|
79
|
+
typeof json === 'object' &&
|
|
80
|
+
json.isSuccess === false);
|
|
81
|
+
if (failed) {
|
|
82
|
+
const message = (json && typeof json === 'object' &&
|
|
83
|
+
typeof json.message === 'string'
|
|
84
|
+
? json.message
|
|
85
|
+
: undefined) || res.statusText || 'SDK backend request failed';
|
|
86
|
+
throw new Boom(message, {
|
|
87
|
+
statusCode: res.ok ? 502 : res.status,
|
|
88
|
+
data: {
|
|
89
|
+
status: res.status,
|
|
90
|
+
title: message,
|
|
91
|
+
detail: message,
|
|
92
|
+
body: json,
|
|
55
93
|
},
|
|
56
94
|
});
|
|
57
|
-
let json;
|
|
58
|
-
try {
|
|
59
|
-
json = await res.json();
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
json = undefined;
|
|
63
|
-
}
|
|
64
|
-
const failed = !res.ok ||
|
|
65
|
-
(json !== undefined &&
|
|
66
|
-
typeof json === 'object' &&
|
|
67
|
-
json.isSuccess === false);
|
|
68
|
-
if (failed) {
|
|
69
|
-
const message = (json && typeof json === 'object' &&
|
|
70
|
-
typeof json.message === 'string'
|
|
71
|
-
? json.message
|
|
72
|
-
: undefined) || res.statusText || 'SDK backend request failed';
|
|
73
|
-
throw new Boom(message, {
|
|
74
|
-
statusCode: res.ok ? 502 : res.status,
|
|
75
|
-
data: {
|
|
76
|
-
status: res.status,
|
|
77
|
-
title: message,
|
|
78
|
-
detail: message,
|
|
79
|
-
body: json,
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
return json;
|
|
84
95
|
}
|
|
85
|
-
|
|
96
|
+
return json;
|
|
97
|
+
};
|
package/lib/old/to-register.d.ts
CHANGED
|
@@ -41,8 +41,8 @@ export interface OldProviderOpts {
|
|
|
41
41
|
* fresh entries with {@link injectedRequestDataFrom}; a carried-forward
|
|
42
42
|
* value (read back from an existing version) passes through unchanged. */
|
|
43
43
|
allowedInjectedRequestData?: OldInjectedRequestData[];
|
|
44
|
-
/**
|
|
45
|
-
*
|
|
44
|
+
/** Accepted at register too (verified from the register controller's
|
|
45
|
+
* destructure + providerConfig write — same as `userAgent`/`pageTitle`). */
|
|
46
46
|
stepsToFollow?: string;
|
|
47
47
|
/** Config (add-version) ONLY — the register endpoint never reads this
|
|
48
48
|
* field from the request body. */
|
package/lib/old/to-register.js
CHANGED
|
@@ -114,15 +114,18 @@ export function providerToRegisterBody(providers, opts) {
|
|
|
114
114
|
if (opts.customInjection !== undefined) {
|
|
115
115
|
body.customInjection = opts.customInjection;
|
|
116
116
|
}
|
|
117
|
-
// Register also accepts these
|
|
118
|
-
//
|
|
119
|
-
//
|
|
117
|
+
// Register also accepts these three (unlike allowedInjectedRequestData /
|
|
118
|
+
// useIncognitoWebview / extensionConfig, which the register controller
|
|
119
|
+
// never reads from the body at all).
|
|
120
120
|
if (opts.userAgent !== undefined) {
|
|
121
121
|
body.userAgent = opts.userAgent;
|
|
122
122
|
}
|
|
123
123
|
if (opts.pageTitle !== undefined) {
|
|
124
124
|
body.pageTitle = opts.pageTitle;
|
|
125
125
|
}
|
|
126
|
+
if (opts.stepsToFollow !== undefined) {
|
|
127
|
+
body.stepsToFollow = opts.stepsToFollow;
|
|
128
|
+
}
|
|
126
129
|
return body;
|
|
127
130
|
}
|
|
128
131
|
/** Body for `POST /api/providers/:providerId/config` — adds a new version to
|
package/lib/old/tools/publish.js
CHANGED
|
@@ -7,9 +7,9 @@ const DEFAULT_VERSION_INFO = 'Updated from MCP browser capture';
|
|
|
7
7
|
/** Fields with no partial-patch equivalent on this backend: a version always
|
|
8
8
|
* replaces the WHOLE `providerConfig`, so omitting one of these on
|
|
9
9
|
* add-version must carry forward the current value rather than publish it
|
|
10
|
-
* blank. `allowedInjectedRequestData` is handled alongside these (
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* blank. `allowedInjectedRequestData` is handled alongside these (further
|
|
11
|
+
* down, inline) since it needs translation when freshly authored, unlike
|
|
12
|
+
* these — which pass through unchanged either way. */
|
|
13
13
|
const PRESERVABLE_KEYS = [
|
|
14
14
|
'customInjection',
|
|
15
15
|
'userAgent',
|
|
@@ -30,12 +30,22 @@ function extractProviderConfig(resp) {
|
|
|
30
30
|
return undefined;
|
|
31
31
|
}
|
|
32
32
|
/** Prefer the caller's explicit value; otherwise fall back to `current`'s
|
|
33
|
-
* value (if any) and record `fieldName` as carried forward.
|
|
33
|
+
* value (if any) and record `fieldName` as carried forward.
|
|
34
|
+
*
|
|
35
|
+
* `current === null` is treated the SAME as `undefined` (nothing to carry),
|
|
36
|
+
* not as a real value to preserve. These are all optional fields with no
|
|
37
|
+
* Prisma default — a version where one was never set reads back as
|
|
38
|
+
* `null`, not a missing key, because Prisma normalizes an absent optional
|
|
39
|
+
* field to `null` on read. Carrying that `null` "forward" would falsely
|
|
40
|
+
* claim the field was preserved when really nothing was ever there — it
|
|
41
|
+
* most likely means an EARLIER version already lost it (e.g. published
|
|
42
|
+
* before this field had carry-forward support at all), not that this call
|
|
43
|
+
* is doing anything wrong. */
|
|
34
44
|
function resolveField(explicit, current, fieldName, carried) {
|
|
35
45
|
if (explicit !== undefined) {
|
|
36
46
|
return explicit;
|
|
37
47
|
}
|
|
38
|
-
if (current !== undefined) {
|
|
48
|
+
if (current !== undefined && current !== null) {
|
|
39
49
|
carried.push(fieldName);
|
|
40
50
|
return current;
|
|
41
51
|
}
|
|
@@ -108,10 +118,16 @@ export function createVersionFromCaptureTool(client) {
|
|
|
108
118
|
'`useIncognitoWebview`, `extensionConfig` that you OMIT is carried ' +
|
|
109
119
|
'forward unchanged from the currently-published version (so ' +
|
|
110
120
|
're-publishing requestData never wipes a working login script or ' +
|
|
111
|
-
'other config someone set via the dashboard).
|
|
112
|
-
'
|
|
113
|
-
'
|
|
114
|
-
'
|
|
121
|
+
'other config someone set via the dashboard). This can only carry ' +
|
|
122
|
+
'forward what the CURRENT version actually has — if an earlier ' +
|
|
123
|
+
'version already lost a field (e.g. published before this tool ' +
|
|
124
|
+
'carried it forward at all), there is nothing left to preserve and ' +
|
|
125
|
+
'the result legitimately comes back empty/null for that field; ' +
|
|
126
|
+
'that is not this call failing to carry it forward. Pass an ' +
|
|
127
|
+
'explicit value (`""`, `[]`, `false`, ...) to intentionally clear ' +
|
|
128
|
+
'one of them instead, or call get_provider_version_config FIRST ' +
|
|
129
|
+
'to see exactly what is live today, rather than assuming this ' +
|
|
130
|
+
'call recovered something that may already be gone. ' +
|
|
115
131
|
'`allowedInjectedRequestData`/`useIncognitoWebview`/' +
|
|
116
132
|
'`extensionConfig` only take effect on add-version — the register ' +
|
|
117
133
|
'endpoint (no `providerId`) ignores them. \n\n' +
|
|
@@ -241,7 +257,7 @@ export function createVersionFromCaptureTool(client) {
|
|
|
241
257
|
stepsToFollow: {
|
|
242
258
|
type: 'string',
|
|
243
259
|
description: 'Free-text setup/manual-verification steps shown to the ' +
|
|
244
|
-
'dev/verifier.
|
|
260
|
+
'dev/verifier. Accepted on register too.',
|
|
245
261
|
},
|
|
246
262
|
useIncognitoWebview: {
|
|
247
263
|
type: 'boolean',
|
|
@@ -320,6 +336,9 @@ export function createVersionFromCaptureTool(client) {
|
|
|
320
336
|
if (args.pageTitle !== undefined) {
|
|
321
337
|
opts.pageTitle = args.pageTitle;
|
|
322
338
|
}
|
|
339
|
+
if (args.stepsToFollow !== undefined) {
|
|
340
|
+
opts.stepsToFollow = args.stepsToFollow;
|
|
341
|
+
}
|
|
323
342
|
const body = providerToRegisterBody(providers, opts);
|
|
324
343
|
return withNotes(await client.registerProvider(body));
|
|
325
344
|
}
|
package/lib/proof/zk-files.js
CHANGED
|
@@ -24,10 +24,10 @@ let inFlight;
|
|
|
24
24
|
* so a stray write to fd 1 mid-session would corrupt the protocol.
|
|
25
25
|
*/
|
|
26
26
|
export function ensureZkFiles() {
|
|
27
|
-
inFlight
|
|
27
|
+
inFlight ?? (inFlight = download().catch((err) => {
|
|
28
28
|
inFlight = undefined;
|
|
29
29
|
throw err;
|
|
30
|
-
});
|
|
30
|
+
}));
|
|
31
31
|
return inFlight;
|
|
32
32
|
}
|
|
33
33
|
async function download() {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reclaimprotocol/agent",
|
|
3
3
|
"title": "Reclaim Agent",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.9",
|
|
5
5
|
"description": "Reclaim Protocol agent — SDK, CLI, and MCP server in one package. SDK + CLI talk to the builder backend; MCP server adds Chrome CDP capture, provider synthesis, replay, and zkTLS proof.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./lib/index.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"README.md"
|
|
45
45
|
],
|
|
46
46
|
"engines": {
|
|
47
|
-
"node": ">=
|
|
47
|
+
"node": ">=20"
|
|
48
48
|
},
|
|
49
49
|
"repository": {
|
|
50
50
|
"url": "https://github.com/reclaimprotocol/builder",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"@hapi/boom": "^9.1.4",
|
|
85
85
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
86
|
-
"@reclaimprotocol/attestor-core": "^5.0.
|
|
86
|
+
"@reclaimprotocol/attestor-core": "^5.0.8",
|
|
87
87
|
"@reclaimprotocol/client": "*",
|
|
88
88
|
"@reclaimprotocol/tls": "^0.1.3",
|
|
89
89
|
"chrome-remote-interface": "^0.33.0",
|
package/src/old/client.ts
CHANGED
|
@@ -43,6 +43,10 @@ export interface RegisterProviderBody {
|
|
|
43
43
|
userAgent?: { ios?: string, android?: string }
|
|
44
44
|
/** Accepted at register too. */
|
|
45
45
|
pageTitle?: string
|
|
46
|
+
/** Accepted at register too — verified straight from the register
|
|
47
|
+
* controller's destructure + its `providerConfig` write, both of which
|
|
48
|
+
* include it alongside `pageTitle`/`userAgent`. */
|
|
49
|
+
stepsToFollow?: string
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
export interface UpdateProviderConfigBody {
|
package/src/old/to-register.ts
CHANGED
|
@@ -50,8 +50,8 @@ export interface OldProviderOpts {
|
|
|
50
50
|
* fresh entries with {@link injectedRequestDataFrom}; a carried-forward
|
|
51
51
|
* value (read back from an existing version) passes through unchanged. */
|
|
52
52
|
allowedInjectedRequestData?: OldInjectedRequestData[]
|
|
53
|
-
/**
|
|
54
|
-
*
|
|
53
|
+
/** Accepted at register too (verified from the register controller's
|
|
54
|
+
* destructure + providerConfig write — same as `userAgent`/`pageTitle`). */
|
|
55
55
|
stepsToFollow?: string
|
|
56
56
|
/** Config (add-version) ONLY — the register endpoint never reads this
|
|
57
57
|
* field from the request body. */
|
|
@@ -231,9 +231,9 @@ export function providerToRegisterBody(
|
|
|
231
231
|
body.customInjection = opts.customInjection
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
// Register also accepts these
|
|
235
|
-
//
|
|
236
|
-
//
|
|
234
|
+
// Register also accepts these three (unlike allowedInjectedRequestData /
|
|
235
|
+
// useIncognitoWebview / extensionConfig, which the register controller
|
|
236
|
+
// never reads from the body at all).
|
|
237
237
|
if(opts.userAgent !== undefined) {
|
|
238
238
|
body.userAgent = opts.userAgent
|
|
239
239
|
}
|
|
@@ -242,6 +242,10 @@ export function providerToRegisterBody(
|
|
|
242
242
|
body.pageTitle = opts.pageTitle
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
if(opts.stepsToFollow !== undefined) {
|
|
246
|
+
body.stepsToFollow = opts.stepsToFollow
|
|
247
|
+
}
|
|
248
|
+
|
|
245
249
|
return body
|
|
246
250
|
}
|
|
247
251
|
|
package/src/old/tools/publish.ts
CHANGED
|
@@ -23,9 +23,9 @@ const DEFAULT_VERSION_INFO = 'Updated from MCP browser capture'
|
|
|
23
23
|
/** Fields with no partial-patch equivalent on this backend: a version always
|
|
24
24
|
* replaces the WHOLE `providerConfig`, so omitting one of these on
|
|
25
25
|
* add-version must carry forward the current value rather than publish it
|
|
26
|
-
* blank. `allowedInjectedRequestData` is handled alongside these (
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* blank. `allowedInjectedRequestData` is handled alongside these (further
|
|
27
|
+
* down, inline) since it needs translation when freshly authored, unlike
|
|
28
|
+
* these — which pass through unchanged either way. */
|
|
29
29
|
const PRESERVABLE_KEYS = [
|
|
30
30
|
'customInjection',
|
|
31
31
|
'userAgent',
|
|
@@ -51,7 +51,17 @@ function extractProviderConfig(
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/** Prefer the caller's explicit value; otherwise fall back to `current`'s
|
|
54
|
-
* value (if any) and record `fieldName` as carried forward.
|
|
54
|
+
* value (if any) and record `fieldName` as carried forward.
|
|
55
|
+
*
|
|
56
|
+
* `current === null` is treated the SAME as `undefined` (nothing to carry),
|
|
57
|
+
* not as a real value to preserve. These are all optional fields with no
|
|
58
|
+
* Prisma default — a version where one was never set reads back as
|
|
59
|
+
* `null`, not a missing key, because Prisma normalizes an absent optional
|
|
60
|
+
* field to `null` on read. Carrying that `null` "forward" would falsely
|
|
61
|
+
* claim the field was preserved when really nothing was ever there — it
|
|
62
|
+
* most likely means an EARLIER version already lost it (e.g. published
|
|
63
|
+
* before this field had carry-forward support at all), not that this call
|
|
64
|
+
* is doing anything wrong. */
|
|
55
65
|
function resolveField<T>(
|
|
56
66
|
explicit: T | undefined,
|
|
57
67
|
current: unknown,
|
|
@@ -62,7 +72,7 @@ function resolveField<T>(
|
|
|
62
72
|
return explicit
|
|
63
73
|
}
|
|
64
74
|
|
|
65
|
-
if(current !== undefined) {
|
|
75
|
+
if(current !== undefined && current !== null) {
|
|
66
76
|
carried.push(fieldName)
|
|
67
77
|
return current as T
|
|
68
78
|
}
|
|
@@ -163,10 +173,16 @@ export function createVersionFromCaptureTool(
|
|
|
163
173
|
'`useIncognitoWebview`, `extensionConfig` that you OMIT is carried ' +
|
|
164
174
|
'forward unchanged from the currently-published version (so ' +
|
|
165
175
|
're-publishing requestData never wipes a working login script or ' +
|
|
166
|
-
'other config someone set via the dashboard).
|
|
167
|
-
'
|
|
168
|
-
'
|
|
169
|
-
'
|
|
176
|
+
'other config someone set via the dashboard). This can only carry ' +
|
|
177
|
+
'forward what the CURRENT version actually has — if an earlier ' +
|
|
178
|
+
'version already lost a field (e.g. published before this tool ' +
|
|
179
|
+
'carried it forward at all), there is nothing left to preserve and ' +
|
|
180
|
+
'the result legitimately comes back empty/null for that field; ' +
|
|
181
|
+
'that is not this call failing to carry it forward. Pass an ' +
|
|
182
|
+
'explicit value (`""`, `[]`, `false`, ...) to intentionally clear ' +
|
|
183
|
+
'one of them instead, or call get_provider_version_config FIRST ' +
|
|
184
|
+
'to see exactly what is live today, rather than assuming this ' +
|
|
185
|
+
'call recovered something that may already be gone. ' +
|
|
170
186
|
'`allowedInjectedRequestData`/`useIncognitoWebview`/' +
|
|
171
187
|
'`extensionConfig` only take effect on add-version — the register ' +
|
|
172
188
|
'endpoint (no `providerId`) ignores them. \n\n' +
|
|
@@ -308,7 +324,7 @@ export function createVersionFromCaptureTool(
|
|
|
308
324
|
type: 'string',
|
|
309
325
|
description:
|
|
310
326
|
'Free-text setup/manual-verification steps shown to the ' +
|
|
311
|
-
'dev/verifier.
|
|
327
|
+
'dev/verifier. Accepted on register too.',
|
|
312
328
|
},
|
|
313
329
|
useIncognitoWebview: {
|
|
314
330
|
type: 'boolean',
|
|
@@ -415,6 +431,10 @@ export function createVersionFromCaptureTool(
|
|
|
415
431
|
opts.pageTitle = args.pageTitle
|
|
416
432
|
}
|
|
417
433
|
|
|
434
|
+
if(args.stepsToFollow !== undefined) {
|
|
435
|
+
opts.stepsToFollow = args.stepsToFollow
|
|
436
|
+
}
|
|
437
|
+
|
|
418
438
|
const body = providerToRegisterBody(providers, opts)
|
|
419
439
|
return withNotes(await client.registerProvider(body))
|
|
420
440
|
}
|