@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
package/src/provider/schema.ts
CHANGED
|
@@ -69,6 +69,29 @@ export interface ReclaimProvider {
|
|
|
69
69
|
responseRedactions?: ResponseRedaction[]
|
|
70
70
|
/** Public param refs (templated into URL/body), populated by draft layer. */
|
|
71
71
|
paramValues?: Record<string, string>
|
|
72
|
+
/** Redaction mode for the transcript (attestor default: 'key-update'). */
|
|
73
|
+
writeRedactionMode?: HttpParams['writeRedactionMode']
|
|
74
|
+
/** TLS client options applied to the attestor tunnel. */
|
|
75
|
+
additionalClientOptions?: HttpParams['additionalClientOptions']
|
|
76
|
+
/** Proxy egress: 2-letter ISO country or `{{param}}`. Blank/omitted ⇒
|
|
77
|
+
* `{{DYNAMIC_GEO}}` on publish (resolved to the verifying user's country).
|
|
78
|
+
*/
|
|
79
|
+
geoLocation?: HttpParams['geoLocation']
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Egress placeholder resolved to the verifying user's country at
|
|
83
|
+
* verification time — the default when a provider declares no explicit egress.
|
|
84
|
+
*/
|
|
85
|
+
export const DYNAMIC_GEO = '{{DYNAMIC_GEO}}'
|
|
86
|
+
|
|
87
|
+
/** `geoLocation` must never be blank. Trims the input and treats an empty
|
|
88
|
+
* string as unset so callers apply their own default (publish → `DYNAMIC_GEO`;
|
|
89
|
+
* a local proof omits it and uses the tester's egress). */
|
|
90
|
+
export function normalizeGeoLocation(
|
|
91
|
+
value: string | undefined,
|
|
92
|
+
): string | undefined {
|
|
93
|
+
const trimmed = value?.trim()
|
|
94
|
+
return trimmed ? trimmed : undefined
|
|
72
95
|
}
|
|
73
96
|
|
|
74
97
|
/** A reference to a secret param. Raw value lives only in server memory. */
|
|
@@ -1,9 +1,53 @@
|
|
|
1
1
|
import type { ReclaimClient } from '@reclaimprotocol/client'
|
|
2
2
|
import type {
|
|
3
|
-
CreateProviderVersionRequest
|
|
4
|
-
ProviderVersionRef
|
|
5
|
-
} from '
|
|
6
|
-
import type {
|
|
3
|
+
CreateProviderVersionRequest,
|
|
4
|
+
ProviderVersionRef,
|
|
5
|
+
} from '@reclaimprotocol/client/openapi'
|
|
6
|
+
import type {
|
|
7
|
+
HttpMethod,
|
|
8
|
+
ReclaimProvider,
|
|
9
|
+
ResponseMatch,
|
|
10
|
+
ResponseRedaction,
|
|
11
|
+
} from './schema.ts'
|
|
12
|
+
import { DYNAMIC_GEO, normalizeGeoLocation } from './schema.ts'
|
|
13
|
+
|
|
14
|
+
/** One entry of the version's `requests[]` (a `RequestSelection`), derived
|
|
15
|
+
* from the openapi type so it can't drift from what the server accepts. */
|
|
16
|
+
type RequestSelection = CreateProviderVersionRequest['requests'][number]
|
|
17
|
+
|
|
18
|
+
/** The subset of a draft a request selection is built from — the only fields
|
|
19
|
+
* `providerToRequestSelection` reads. A full `ReclaimProvider` satisfies it,
|
|
20
|
+
* as does a lighter injected-request draft (no `name`/`paramValues`). */
|
|
21
|
+
export interface DraftRequest {
|
|
22
|
+
url: string
|
|
23
|
+
method: HttpMethod
|
|
24
|
+
body?: string
|
|
25
|
+
writeRedactionMode?: ReclaimProvider['writeRedactionMode']
|
|
26
|
+
additionalClientOptions?: ReclaimProvider['additionalClientOptions']
|
|
27
|
+
responseMatches?: ResponseMatch[]
|
|
28
|
+
responseRedactions?: ResponseRedaction[]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** A request the page's injection script is allowed to fire, plus the
|
|
32
|
+
* pagination/optionality flags of `RequestSelectionTemplate`. Reuses the
|
|
33
|
+
* shared `DraftRequest` shape — no provider `name`/`paramValues` required. */
|
|
34
|
+
export interface AllowedJsRequest extends DraftRequest {
|
|
35
|
+
/** Allow the template to match many requests (e.g. pagination). Default
|
|
36
|
+
* true. */
|
|
37
|
+
multiple?: boolean
|
|
38
|
+
/** Fail validation if no request matches this template. Default true. */
|
|
39
|
+
required?: boolean
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Optional extras for a create-version body beyond the request list. */
|
|
43
|
+
export interface CreateVersionOptions {
|
|
44
|
+
notes?: string
|
|
45
|
+
version?: ProviderVersionRef
|
|
46
|
+
/** JS injected before every page load (`webSettings.jsUserScripts`). */
|
|
47
|
+
jsUserScripts?: string
|
|
48
|
+
/** Requests the injection script may fire, as `RequestSelectionTemplate`s. */
|
|
49
|
+
allowedJsRequests?: AllowedJsRequest[]
|
|
50
|
+
}
|
|
7
51
|
|
|
8
52
|
/**
|
|
9
53
|
* Translate a drafted ReclaimProvider into the body for
|
|
@@ -16,40 +60,143 @@ import type { ReclaimProvider } from './schema.ts'
|
|
|
16
60
|
* Secrets are NOT persisted — the verification client re-supplies
|
|
17
61
|
* them at runtime via `credentials: 'include'`.
|
|
18
62
|
*/
|
|
63
|
+
/** `{{context.<name>}}` placeholders in a request URL/body: values the
|
|
64
|
+
* CONSUMER supplies at verification time via the session `context`. Bare
|
|
65
|
+
* `{{name}}` placeholders (extraction params) are not consumer-supplied
|
|
66
|
+
* and are ignored. */
|
|
67
|
+
const CONTEXT_PARAM_RE = /\{\{context\.([A-Za-z_][A-Za-z0-9_]*)\}\}/g
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Derive the version's `requiredContext` JSON Schema from the
|
|
71
|
+
* `{{context.<name>}}` placeholders across EVERY request's url/body (plus any
|
|
72
|
+
* injected requests and the injection script) — mechanical, so a published
|
|
73
|
+
* recipe can never reference a context value the Builder doesn't require.
|
|
74
|
+
* Returns undefined when nothing references context (the field is optional).
|
|
75
|
+
* Authors can refine types/descriptions in the version editor.
|
|
76
|
+
*/
|
|
77
|
+
export function deriveRequiredContext(
|
|
78
|
+
providers: ReclaimProvider[],
|
|
79
|
+
injection: {
|
|
80
|
+
allowedJsRequests?: AllowedJsRequest[]
|
|
81
|
+
jsUserScripts?: string
|
|
82
|
+
} = {},
|
|
83
|
+
): CreateProviderVersionRequest['requiredContext'] {
|
|
84
|
+
const parts: string[] = []
|
|
85
|
+
for(const p of [...providers, ...(injection.allowedJsRequests ?? [])]) {
|
|
86
|
+
parts.push(p.url, p.body ?? '')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if(injection.jsUserScripts) {
|
|
90
|
+
parts.push(injection.jsUserScripts)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const haystack = parts.join('\n')
|
|
94
|
+
const names = new Set<string>()
|
|
95
|
+
for(const m of haystack.matchAll(CONTEXT_PARAM_RE)) {
|
|
96
|
+
names.add(m[1])
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if(!names.size) {
|
|
100
|
+
return undefined
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const properties: Record<string, unknown> = {}
|
|
104
|
+
for(const name of names) {
|
|
105
|
+
properties[name] = { type: 'string' }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return { type: 'object', required: [...names], properties }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Translate one drafted request into a `RequestSelection`. Shared by the
|
|
113
|
+
* top-level `requests` and by `allowedJsRequests`.
|
|
114
|
+
*
|
|
115
|
+
* `responseMatches`/`responseRedactions` are INDEPENDENT parallel arrays,
|
|
116
|
+
* isomorphic to the attestor's `ProviderParams<'http'>` (no nested fold).
|
|
117
|
+
* `responseRedactions` decide which portions of the response are revealed;
|
|
118
|
+
* `responseMatches` then run against the union of the revealed content. Neither
|
|
119
|
+
* depends on the other's length or order, so both pass through untouched.
|
|
120
|
+
* (The old-devtools translator has its own opt-in index-pairing concern; the
|
|
121
|
+
* builder deliberately does not.)
|
|
122
|
+
*/
|
|
123
|
+
export function providerToRequestSelection(
|
|
124
|
+
provider: DraftRequest,
|
|
125
|
+
): RequestSelection {
|
|
126
|
+
const responseMatches = (provider.responseMatches ?? []).map((match) => ({
|
|
127
|
+
type: match.type,
|
|
128
|
+
value: match.value,
|
|
129
|
+
isOptional: false,
|
|
130
|
+
}))
|
|
131
|
+
const responseRedactions = provider.responseRedactions ?? []
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
url: provider.url,
|
|
135
|
+
method: provider.method,
|
|
136
|
+
credentials: 'include',
|
|
137
|
+
...(provider.body ? { requestBodyTemplate: provider.body } : {}),
|
|
138
|
+
...(provider.writeRedactionMode
|
|
139
|
+
? { writeRedactionMode: provider.writeRedactionMode }
|
|
140
|
+
: {}),
|
|
141
|
+
...(provider.additionalClientOptions
|
|
142
|
+
? { additionalClientOptions: provider.additionalClientOptions }
|
|
143
|
+
: {}),
|
|
144
|
+
...(responseMatches.length > 0 ? { responseMatches } : {}),
|
|
145
|
+
...(responseRedactions.length > 0 ? { responseRedactions } : {}),
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** First provider that declares an explicit (non-default) egress wins; if none
|
|
150
|
+
* do, fall back to DYNAMIC_GEO (resolved to the verifying user's country). */
|
|
151
|
+
function pickGeoLocation(providers: ReclaimProvider[]): string {
|
|
152
|
+
for(const provider of providers) {
|
|
153
|
+
const geo = normalizeGeoLocation(provider.geoLocation)
|
|
154
|
+
if(geo) {
|
|
155
|
+
return geo
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return DYNAMIC_GEO
|
|
160
|
+
}
|
|
161
|
+
|
|
19
162
|
export function providerToCreateVersionRequest(
|
|
20
|
-
|
|
163
|
+
providers: ReclaimProvider[],
|
|
21
164
|
initialUrl: string,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
type: match.type,
|
|
30
|
-
value: match.value,
|
|
31
|
-
isOptional: false,
|
|
32
|
-
...(redaction ? { extract: redaction } : {}),
|
|
33
|
-
}
|
|
165
|
+
opts: CreateVersionOptions = {},
|
|
166
|
+
): CreateProviderVersionRequest {
|
|
167
|
+
const { notes, version, jsUserScripts, allowedJsRequests } = opts
|
|
168
|
+
const requiredContext = deriveRequiredContext(providers, {
|
|
169
|
+
allowedJsRequests,
|
|
170
|
+
jsUserScripts,
|
|
34
171
|
})
|
|
35
172
|
|
|
173
|
+
// Each injected request carries its template flags (default true/true per
|
|
174
|
+
// RequestSelectionTemplate) on top of the shared request shape.
|
|
175
|
+
const allowedJs = (allowedJsRequests ?? []).map((req) => ({
|
|
176
|
+
...providerToRequestSelection(req),
|
|
177
|
+
multiple: req.multiple ?? true,
|
|
178
|
+
required: req.required ?? true,
|
|
179
|
+
}))
|
|
180
|
+
const script = jsUserScripts?.trim()
|
|
181
|
+
|
|
36
182
|
return {
|
|
37
183
|
version: version ?? { major: 1, minor: 0, patch: 0 },
|
|
38
184
|
initialUrl,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
185
|
+
// Every drafted provider becomes one request — the recipe runs them all.
|
|
186
|
+
requests: providers.map(providerToRequestSelection),
|
|
187
|
+
allowedJsRequests: allowedJs,
|
|
188
|
+
// Mirror the builder openapi defaults explicitly — the server does not
|
|
189
|
+
// apply schema defaults to request bodies.
|
|
190
|
+
webSettings: {
|
|
191
|
+
geoLocation: pickGeoLocation(providers),
|
|
192
|
+
clientOptions: { portal: { useProxy: true } },
|
|
193
|
+
// Only set when non-empty; an empty string would store a no-op script.
|
|
194
|
+
...(script ? { jsUserScripts: script } : {}),
|
|
195
|
+
},
|
|
196
|
+
// Derived from `{{context.<name>}}` placeholders only — a captured
|
|
197
|
+
// provider's `paramValues` are extracted response parameters, not
|
|
198
|
+
// consumer context, and never become requiredContext.
|
|
199
|
+
...(requiredContext ? { requiredContext } : {}),
|
|
53
200
|
...(notes ? { notes } : {}),
|
|
54
201
|
}
|
|
55
202
|
}
|
|
@@ -63,11 +210,11 @@ export function providerToCreateVersionRequest(
|
|
|
63
210
|
export async function nextVersion(
|
|
64
211
|
client: ReclaimClient,
|
|
65
212
|
providerId: string,
|
|
66
|
-
): Promise<
|
|
213
|
+
): Promise<ProviderVersionRef> {
|
|
67
214
|
const list = (await client.call('ListProviderVersions', {
|
|
68
215
|
params: { providerId },
|
|
69
216
|
query: {},
|
|
70
|
-
})) as { items?: Array<{ version:
|
|
217
|
+
})) as { items?: Array<{ version: ProviderVersionRef }> }
|
|
71
218
|
|
|
72
219
|
if(!list.items?.length) {
|
|
73
220
|
return { major: 1, minor: 0, patch: 0 }
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ReclaimProvider } from './schema.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Advisory pre-publish lint for a drafted provider — never a gate. Surfaces
|
|
5
|
+
* only what the AUTHOR must decide; everything testable is tested by the
|
|
6
|
+
* verification client itself (CDP capture sees all traffic — navigations,
|
|
7
|
+
* XHRs, fetches — and `checkCandidate` in packages/app src/verify/run.ts
|
|
8
|
+
* selects the captured request that satisfies the recipe, skipping the
|
|
9
|
+
* rest). Interpolation and matching are plain text and work for any
|
|
10
|
+
* captured content; extract selectors apply client-side in spec order
|
|
11
|
+
* xPath → jsonPath → regex, each to the prior selection.
|
|
12
|
+
*/
|
|
13
|
+
export function verificationWarnings(provider: ReclaimProvider): string[] {
|
|
14
|
+
const out: string[] = []
|
|
15
|
+
|
|
16
|
+
// Untemplated user-specific URL parts: any captured param value baked
|
|
17
|
+
// literally into the URL makes the provider user-specific. Only the dev
|
|
18
|
+
// can decide: consumer-supplied → {{context.<name>}} (declared in
|
|
19
|
+
// requiredContext; consumers then send the exact value and the VC matches
|
|
20
|
+
// only that value), bare {{<name>}} (resolved from the end-user's own
|
|
21
|
+
// traffic), or re-capture a non-user-specific endpoint.
|
|
22
|
+
for(const [name, value] of Object.entries(provider.paramValues ?? {})) {
|
|
23
|
+
if(value.length >= 3 && provider.url.includes(value)) {
|
|
24
|
+
out.push(
|
|
25
|
+
`The URL contains the captured value "${value}" (param ` +
|
|
26
|
+
`"${name}") as a literal. Decide with the dev: if consumers ` +
|
|
27
|
+
'supply it, replace with {{context.' + name + '}} (published ' +
|
|
28
|
+
'requiredContext will require it; verification matches only ' +
|
|
29
|
+
'the supplied value). Leaving it literal pins the provider ' +
|
|
30
|
+
'to this user.',
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return out
|
|
36
|
+
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { ReclaimClient } from '@reclaimprotocol/client';
|
|
2
|
-
import type { RegisteredTool } from '../../server.ts';
|
|
3
|
-
/**
|
|
4
|
-
* Local-only credential tools — no backend client needed. These manage app
|
|
5
|
-
* key-pairs entirely on disk / in the env (mint, import, list, resolve which
|
|
6
|
-
* key to sign proofs with), so they are useful in BOTH builder and
|
|
7
|
-
* OLD-devtools mode.
|
|
8
|
-
*/
|
|
9
|
-
export declare function buildLocalCredentialTools(): RegisteredTool[];
|
|
10
|
-
/**
|
|
11
|
-
* Full builder-mode credential set: the local tools plus the two that talk to
|
|
12
|
-
* the builder backend (`reclaim_authenticate` device-code flow,
|
|
13
|
-
* `reclaim_status`). Old mode does NOT use these — it has its own
|
|
14
|
-
* authenticate and no credential-status analog.
|
|
15
|
-
*/
|
|
16
|
-
export declare function buildCredentialTools(client: ReclaimClient): RegisteredTool[];
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { authenticateTool } from "./authenticate.js";
|
|
2
|
-
import { importTool } from "./import.js";
|
|
3
|
-
import { issueTool } from "./issue.js";
|
|
4
|
-
import { listCachedTool } from "./list-cached.js";
|
|
5
|
-
import { resolveOwnerKeyTool } from "./resolve-owner-key.js";
|
|
6
|
-
import { statusTool } from "./status.js";
|
|
7
|
-
/**
|
|
8
|
-
* Local-only credential tools — no backend client needed. These manage app
|
|
9
|
-
* key-pairs entirely on disk / in the env (mint, import, list, resolve which
|
|
10
|
-
* key to sign proofs with), so they are useful in BOTH builder and
|
|
11
|
-
* OLD-devtools mode.
|
|
12
|
-
*/
|
|
13
|
-
export function buildLocalCredentialTools() {
|
|
14
|
-
return [
|
|
15
|
-
listCachedTool(),
|
|
16
|
-
resolveOwnerKeyTool(),
|
|
17
|
-
issueTool(),
|
|
18
|
-
importTool(),
|
|
19
|
-
];
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Full builder-mode credential set: the local tools plus the two that talk to
|
|
23
|
-
* the builder backend (`reclaim_authenticate` device-code flow,
|
|
24
|
-
* `reclaim_status`). Old mode does NOT use these — it has its own
|
|
25
|
-
* authenticate and no credential-status analog.
|
|
26
|
-
*/
|
|
27
|
-
export function buildCredentialTools(client) {
|
|
28
|
-
return [
|
|
29
|
-
authenticateTool(client),
|
|
30
|
-
statusTool(client),
|
|
31
|
-
...buildLocalCredentialTools(),
|
|
32
|
-
];
|
|
33
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { deriveFromPrivateKey, } from '@reclaimprotocol/client';
|
|
2
|
-
import assert from 'node:assert';
|
|
3
|
-
import { findProjectRoot } from "../../../paths.js";
|
|
4
|
-
import { defineTool } from "../../server.js";
|
|
5
|
-
import { suggestCredentialForDir } from "./cache.js";
|
|
6
|
-
export function statusTool(client) {
|
|
7
|
-
return defineTool({
|
|
8
|
-
name: 'reclaim_status',
|
|
9
|
-
description: 'Report the live mode (SANDBOX | PRODUCTION | REVOKED) ' +
|
|
10
|
-
'of a Reclaim app credential. Pass `address` — or omit it ' +
|
|
11
|
-
'to derive the address from RECLAIM_PRIVATE_KEY, falling ' +
|
|
12
|
-
'back to the best cached credential for this directory. ' +
|
|
13
|
-
'Useful to confirm a credential is linked to an org ' +
|
|
14
|
-
'with billing before running a production flow.',
|
|
15
|
-
inputSchema: {
|
|
16
|
-
type: 'object',
|
|
17
|
-
properties: {
|
|
18
|
-
address: {
|
|
19
|
-
type: 'string',
|
|
20
|
-
pattern: '^0x[0-9a-fA-F]{40}$',
|
|
21
|
-
description: 'Lowercase ETH address. Defaults to the address ' +
|
|
22
|
-
'derived from RECLAIM_PRIVATE_KEY, then the cached ' +
|
|
23
|
-
'credential suggested for the current directory.',
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
}, async (args) => {
|
|
28
|
-
let address = args.address?.toLowerCase();
|
|
29
|
-
if (!address && process.env.RECLAIM_PRIVATE_KEY) {
|
|
30
|
-
address = deriveFromPrivateKey(process.env.RECLAIM_PRIVATE_KEY).address;
|
|
31
|
-
}
|
|
32
|
-
if (!address) {
|
|
33
|
-
address = suggestCredentialForDir(findProjectRoot(process.cwd()))
|
|
34
|
-
?.credential.address;
|
|
35
|
-
}
|
|
36
|
-
assert(address, new Error('No address given, RECLAIM_PRIVATE_KEY is not set, and the ' +
|
|
37
|
-
'cache is empty. Run issue_credentials or import_credentials ' +
|
|
38
|
-
'first.'));
|
|
39
|
-
const credResult = await client
|
|
40
|
-
.call('GetCredentialByAddress', { params: { address } });
|
|
41
|
-
const cred = credResult.data;
|
|
42
|
-
// A registered credential always carries an `id`; its absence means
|
|
43
|
-
// the server had no row for this address — a local-only credential.
|
|
44
|
-
const localOnly = !cred.id;
|
|
45
|
-
return {
|
|
46
|
-
address: cred.address,
|
|
47
|
-
mode: cred.mode,
|
|
48
|
-
orgId: cred.orgId,
|
|
49
|
-
label: cred.label,
|
|
50
|
-
revokedAt: cred.revokedAt,
|
|
51
|
-
lastUsedAt: cred.lastUsedAt,
|
|
52
|
-
...(localOnly ? {
|
|
53
|
-
note: 'Local-only credential — not registered with the server. '
|
|
54
|
-
+ 'It operates in SANDBOX, which is all you need to publish '
|
|
55
|
-
+ 'a verification (only an auth token is required — no '
|
|
56
|
-
+ 'credential link). Linking it to an org with billing (via '
|
|
57
|
-
+ 'link_credential) is only needed for the upcoming feature '
|
|
58
|
-
+ 'that runs verifications for your own app’s users.',
|
|
59
|
-
} : {}),
|
|
60
|
-
};
|
|
61
|
-
});
|
|
62
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { ReclaimClient } from '@reclaimprotocol/client'
|
|
2
|
-
import type { RegisteredTool } from '../../server.ts'
|
|
3
|
-
import { authenticateTool } from './authenticate.ts'
|
|
4
|
-
import { importTool } from './import.ts'
|
|
5
|
-
import { issueTool } from './issue.ts'
|
|
6
|
-
import { listCachedTool } from './list-cached.ts'
|
|
7
|
-
import { resolveOwnerKeyTool } from './resolve-owner-key.ts'
|
|
8
|
-
import { statusTool } from './status.ts'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Local-only credential tools — no backend client needed. These manage app
|
|
12
|
-
* key-pairs entirely on disk / in the env (mint, import, list, resolve which
|
|
13
|
-
* key to sign proofs with), so they are useful in BOTH builder and
|
|
14
|
-
* OLD-devtools mode.
|
|
15
|
-
*/
|
|
16
|
-
export function buildLocalCredentialTools(): RegisteredTool[] {
|
|
17
|
-
return [
|
|
18
|
-
listCachedTool(),
|
|
19
|
-
resolveOwnerKeyTool(),
|
|
20
|
-
issueTool(),
|
|
21
|
-
importTool(),
|
|
22
|
-
]
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Full builder-mode credential set: the local tools plus the two that talk to
|
|
27
|
-
* the builder backend (`reclaim_authenticate` device-code flow,
|
|
28
|
-
* `reclaim_status`). Old mode does NOT use these — it has its own
|
|
29
|
-
* authenticate and no credential-status analog.
|
|
30
|
-
*/
|
|
31
|
-
export function buildCredentialTools(client: ReclaimClient): RegisteredTool[] {
|
|
32
|
-
return [
|
|
33
|
-
authenticateTool(client),
|
|
34
|
-
statusTool(client),
|
|
35
|
-
...buildLocalCredentialTools(),
|
|
36
|
-
]
|
|
37
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { deriveFromPrivateKey } from '@reclaimprotocol/client'
|
|
2
|
-
import { ConfigStore } from '../../../config/store.ts'
|
|
3
|
-
import { findProjectRoot } from '../../../paths.ts'
|
|
4
|
-
import { readPrivateKeyFromEnvFile } from './env-file.ts'
|
|
5
|
-
|
|
6
|
-
export type CachedCredential = {
|
|
7
|
-
address: string
|
|
8
|
-
privateKey: string
|
|
9
|
-
label?: string
|
|
10
|
-
orgId?: string
|
|
11
|
-
createdAt: string
|
|
12
|
-
/** Project dir where this credential was first created. */
|
|
13
|
-
createdIn: string
|
|
14
|
-
/** All project dirs this credential has been used in ("used by"). */
|
|
15
|
-
projectDirs: string[]
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
type CacheFile = {
|
|
19
|
-
version: 1
|
|
20
|
-
credentials: CachedCredential[]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const EMPTY: CacheFile = { version: 1, credentials: [] }
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Read the `credentials` section of the unified config. Returns an empty
|
|
27
|
-
* doc if missing or malformed — we'd rather lose the cache than crash the
|
|
28
|
-
* CLI on a corrupted file the user can re-create.
|
|
29
|
-
*/
|
|
30
|
-
export function readCredentialsFromCache(): CacheFile {
|
|
31
|
-
const creds = new ConfigStore().read()?.credentials
|
|
32
|
-
if(!Array.isArray(creds)) {
|
|
33
|
-
return { ...EMPTY }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return { version: 1, credentials: creds }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Persist the `credentials` section, merging into the unified config so
|
|
41
|
-
* other sections (browser_agent, session) survive untouched. We rewrite
|
|
42
|
-
* the whole list each save; it's tiny and the alternative (append-only)
|
|
43
|
-
* loses our ability to deduplicate `projectDirs`.
|
|
44
|
-
*/
|
|
45
|
-
export function writeCache(doc: CacheFile) {
|
|
46
|
-
new ConfigStore().write({ credentials: doc.credentials })
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Upsert a credential entry. If a row already exists for `address`,
|
|
51
|
-
* we merge the new `projectDirs` into the existing list, refresh
|
|
52
|
-
* mutable fields, and keep the original `createdAt` / `createdIn`
|
|
53
|
-
* (backfilling `createdIn` from the new entry when an old row lacks it).
|
|
54
|
-
*/
|
|
55
|
-
export function upsertCredential(entry: CachedCredential) {
|
|
56
|
-
const doc = readCredentialsFromCache()
|
|
57
|
-
const idx = doc.credentials.findIndex(
|
|
58
|
-
(c) => c.address === entry.address.toLowerCase(),
|
|
59
|
-
)
|
|
60
|
-
const merged: CachedCredential = {
|
|
61
|
-
...entry,
|
|
62
|
-
address: entry.address.toLowerCase(),
|
|
63
|
-
projectDirs: Array.from(
|
|
64
|
-
new Set([
|
|
65
|
-
...(doc.credentials[idx]?.projectDirs ?? []),
|
|
66
|
-
...entry.projectDirs,
|
|
67
|
-
]),
|
|
68
|
-
),
|
|
69
|
-
createdAt: doc.credentials[idx]?.createdAt ?? entry.createdAt,
|
|
70
|
-
createdIn: doc.credentials[idx]?.createdIn ?? entry.createdIn,
|
|
71
|
-
}
|
|
72
|
-
if(idx >= 0) {
|
|
73
|
-
doc.credentials[idx] = merged
|
|
74
|
-
} else {
|
|
75
|
-
doc.credentials.unshift(merged)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
writeCache(doc)
|
|
79
|
-
return merged
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Look up a cached credential by address. Case-insensitive. */
|
|
83
|
-
export function findCredentialFromCachedBy(
|
|
84
|
-
address: string
|
|
85
|
-
): CachedCredential | undefined {
|
|
86
|
-
const doc = readCredentialsFromCache()
|
|
87
|
-
const lc = address.toLowerCase()
|
|
88
|
-
return doc.credentials.find((c) => c.address === lc)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export type SuggestionReason = 'createdIn' | 'usedIn' | 'newest'
|
|
92
|
-
|
|
93
|
-
export type CredentialSuggestion = {
|
|
94
|
-
credential: CachedCredential
|
|
95
|
-
reason: SuggestionReason
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Pick the best cached credential for `dir`. Ranking tiers:
|
|
100
|
-
* 1. created in `dir` (reason: 'createdIn')
|
|
101
|
-
* 2. previously used in `dir` (reason: 'usedIn')
|
|
102
|
-
* 3. most recently created (reason: 'newest')
|
|
103
|
-
* Within every tier, newest `createdAt` wins; address ascending is the
|
|
104
|
-
* final deterministic tie-break. Returns undefined only on an empty cache.
|
|
105
|
-
*
|
|
106
|
-
* Pass a pre-read `creds` array to avoid a redundant `readCache()` (and to
|
|
107
|
-
* rank against the same snapshot the caller already holds).
|
|
108
|
-
*/
|
|
109
|
-
export function suggestCredentialForDir(
|
|
110
|
-
dir: string,
|
|
111
|
-
creds: CachedCredential[] = readCredentialsFromCache().credentials,
|
|
112
|
-
): CredentialSuggestion | undefined {
|
|
113
|
-
if(creds.length === 0) {
|
|
114
|
-
return undefined
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const byNewest = (a: CachedCredential, b: CachedCredential) => {
|
|
118
|
-
return (b.createdAt ?? '').localeCompare(a.createdAt ?? '') ||
|
|
119
|
-
a.address.localeCompare(b.address)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const createdHere = creds.filter((c) => c.createdIn === dir).sort(byNewest)
|
|
123
|
-
if(createdHere[0]) {
|
|
124
|
-
return { credential: createdHere[0], reason: 'createdIn' }
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const usedHere = creds
|
|
128
|
-
.filter((c) => c.projectDirs.includes(dir))
|
|
129
|
-
.sort(byNewest)
|
|
130
|
-
if(usedHere[0]) {
|
|
131
|
-
return { credential: usedHere[0], reason: 'usedIn' }
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return { credential: [...creds].sort(byNewest)[0], reason: 'newest' }
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Resolve the private key to sign attestor proofs with (the claim
|
|
139
|
-
* "owner"). Reuses the app credential rather than a dedicated key — for
|
|
140
|
-
* build-time test proofs the developer is both the app and the proof
|
|
141
|
-
* owner, and the owner identity is immaterial to whether the provider's
|
|
142
|
-
* matching works.
|
|
143
|
-
*
|
|
144
|
-
* The owner is chosen up front (see the `resolve_owner_key` tool) and
|
|
145
|
-
* passed by `address`; this just fetches the matching private key:
|
|
146
|
-
* - the `RECLAIM_PRIVATE_KEY` env / project `.env` key, if it derives
|
|
147
|
-
* to `address` (the dev pinned it), else
|
|
148
|
-
* - the cached credential with that address.
|
|
149
|
-
* Returns undefined when no key for `address` is known.
|
|
150
|
-
*/
|
|
151
|
-
export function resolveOwnerPrivateKey(address: string): string | undefined {
|
|
152
|
-
const target = address.toLowerCase()
|
|
153
|
-
const envKey =
|
|
154
|
-
process.env.RECLAIM_PRIVATE_KEY ??
|
|
155
|
-
readPrivateKeyFromEnvFile(findProjectRoot(process.cwd()))
|
|
156
|
-
if(envKey && deriveFromPrivateKey(envKey).address === target) {
|
|
157
|
-
return envKey
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return findCredentialFromCachedBy(target)?.privateKey
|
|
161
|
-
}
|