@haven_ai/signer 0.1.37-alpha.0 → 0.2.1-alpha.0
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 +46 -3
- package/dist/cli.cjs +99 -14
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +99 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +101 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -3
- package/dist/index.d.ts +63 -3
- package/dist/index.js +100 -15
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -282,6 +282,17 @@ declare function signerInstructions(): string;
|
|
|
282
282
|
interface SignerCredentials {
|
|
283
283
|
delegateKey: string;
|
|
284
284
|
agentId?: string;
|
|
285
|
+
/**
|
|
286
|
+
* The Haven account (smart account) the agent spends from — #2908, the
|
|
287
|
+
* account-vocabulary name. Same value as `safeAddress`.
|
|
288
|
+
*/
|
|
289
|
+
accountAddress?: string;
|
|
290
|
+
/**
|
|
291
|
+
* @deprecated #2908 — same value as {@link SignerCredentials.accountAddress}.
|
|
292
|
+
* Removed from this shape in the release after the one carrying #2908
|
|
293
|
+
* (#2914). The credential-FILE keys it was read from are a different
|
|
294
|
+
* matter — see `readAccountAddressField`.
|
|
295
|
+
*/
|
|
285
296
|
safeAddress?: string;
|
|
286
297
|
chainId?: number;
|
|
287
298
|
network?: string;
|
|
@@ -289,6 +300,23 @@ interface SignerCredentials {
|
|
|
289
300
|
/** Absolute path the key was loaded from, if a file was used. */
|
|
290
301
|
sourcePath?: string;
|
|
291
302
|
}
|
|
303
|
+
interface RawCredentialFile {
|
|
304
|
+
delegate_key?: unknown;
|
|
305
|
+
delegateKey?: unknown;
|
|
306
|
+
agent_id?: unknown;
|
|
307
|
+
agentId?: unknown;
|
|
308
|
+
/** #2908: what `@haven_ai/connect` writes from this release on. */
|
|
309
|
+
account_address?: unknown;
|
|
310
|
+
/** Pre-#2908 spelling — read PERMANENTLY, see `readAccountAddressField`. */
|
|
311
|
+
safe_address?: unknown;
|
|
312
|
+
/** Pre-#2908 spelling — read PERMANENTLY, see `readAccountAddressField`. */
|
|
313
|
+
safeAddress?: unknown;
|
|
314
|
+
chain_id?: unknown;
|
|
315
|
+
chainId?: unknown;
|
|
316
|
+
network?: unknown;
|
|
317
|
+
x402_binding_signer?: unknown;
|
|
318
|
+
x402BindingSigner?: unknown;
|
|
319
|
+
}
|
|
292
320
|
/**
|
|
293
321
|
* Resolve the delegate key for the edge signer.
|
|
294
322
|
*
|
|
@@ -301,6 +329,30 @@ interface SignerCredentials {
|
|
|
301
329
|
* `delegate_key` and ignore the rest.
|
|
302
330
|
*/
|
|
303
331
|
declare function loadSignerCredentials(path?: string | undefined): Promise<SignerCredentials>;
|
|
332
|
+
/**
|
|
333
|
+
* The account address off a credential FILE: `account_address` (what
|
|
334
|
+
* `@haven_ai/connect` writes from #2908 on) first, then the two pre-#2908
|
|
335
|
+
* spellings.
|
|
336
|
+
*
|
|
337
|
+
* The two old fallbacks are PERMANENT, not part of the one-release naming
|
|
338
|
+
* window (#2906, decision 2a): a credential file on disk was written once and
|
|
339
|
+
* never rewrites itself, so a signer that stopped reading `safe_address`
|
|
340
|
+
* would silently lose the address for every agent connected before this
|
|
341
|
+
* release — the consent hash would change and the spend-context prompt would
|
|
342
|
+
* say "not provided". Two lines, kept for as long as the file format exists.
|
|
343
|
+
*
|
|
344
|
+
* Exported for the mutation tests: dropping `account_address` fails the
|
|
345
|
+
* new-shape test, dropping either old key fails the old-shape test.
|
|
346
|
+
*/
|
|
347
|
+
declare function readAccountAddressField(raw: Pick<RawCredentialFile, 'account_address' | 'safe_address' | 'safeAddress'>): string | undefined;
|
|
348
|
+
/**
|
|
349
|
+
* The account address off the process environment, new name first:
|
|
350
|
+
* `HAVEN_ACCOUNT_ADDRESS` (the survivor, decided on #2906) then the two
|
|
351
|
+
* names the dashboard handoff emitted before #2908 — `HAVEN_WALLET_ADDRESS`
|
|
352
|
+
* and `HAVEN_SAFE_ADDRESS`. Unlike the file fallbacks these two ARE
|
|
353
|
+
* window-scoped: they are dropped at #2914, one release after this one.
|
|
354
|
+
*/
|
|
355
|
+
declare function readAccountAddressEnv(env: NodeJS.ProcessEnv): string | undefined;
|
|
304
356
|
/**
|
|
305
357
|
* Warn (best-effort, POSIX only) when the credential file is readable beyond
|
|
306
358
|
* its owner. Mirrors `@haven_ai/mcp`'s check — the delegate key is the most
|
|
@@ -368,9 +420,17 @@ interface ToolFailure {
|
|
|
368
420
|
/**
|
|
369
421
|
* #1309: precise recovery guidance as DATA, not just prose inside `message`
|
|
370
422
|
* — the same text the hosted quote's advisory `signer_compatibility.fallback`
|
|
371
|
-
* carries when the refusal is an out-of-date signer.
|
|
423
|
+
* carries when the refusal is an out-of-date signer. #3001 reuses this same
|
|
424
|
+
* field for every sign-context refusal (`'typed_data_b64'`).
|
|
372
425
|
*/
|
|
373
426
|
fallback?: string;
|
|
427
|
+
/**
|
|
428
|
+
* #3001: present on `SIGN_CONTEXT_REFUSED` — the HTTP status the backend
|
|
429
|
+
* answered the `/x402/:id/sign-context` fetch with (404, 410, …).
|
|
430
|
+
*/
|
|
431
|
+
http_status?: number;
|
|
432
|
+
/** #3001: the backend's own `error_code` on `SIGN_CONTEXT_REFUSED` (`expired`, `already_executed`, `not_signable`, `sign_context_unavailable`). */
|
|
433
|
+
backend_error_code?: string;
|
|
374
434
|
}
|
|
375
435
|
type ToolPayload<T = unknown> = ToolSuccess<T> | ToolFailure;
|
|
376
436
|
interface ToolHandlerOptions {
|
|
@@ -416,7 +476,7 @@ declare function renderSignerConsentBlock(input: SignerConsentInput, hash: strin
|
|
|
416
476
|
declare function ensureSignerConsent(input: SignerConsentInput, options?: SignerConsentOptions): Promise<SignerConsentDecision>;
|
|
417
477
|
|
|
418
478
|
declare const SIGNER_NAME = "@haven_ai/signer";
|
|
419
|
-
declare const SIGNER_VERSION = "0.1
|
|
479
|
+
declare const SIGNER_VERSION = "0.2.1-alpha.0";
|
|
420
480
|
interface SignerOptions {
|
|
421
481
|
/** Path to a Haven credential JSON file (delegate_key is read from it). */
|
|
422
482
|
credentialsPath?: string;
|
|
@@ -481,4 +541,4 @@ declare function assertSupportedNodeVersion(nodeVersion?: string): void;
|
|
|
481
541
|
declare function runSignerStdioServer(options?: SignerOptions): Promise<void>;
|
|
482
542
|
declare function runSignerConsentGate(signer: EdgeSigner, credentials: SignerCredentials | undefined, options: SignerOptions): Promise<SignerConsentDecision>;
|
|
483
543
|
|
|
484
|
-
export { type EdgeSigner, type ResolvedSignerRuntime, SIGNER_ACK_ENV, SIGNER_CAPABILITY_KEY, SIGNER_NAME, SIGNER_VERSION, SUPPORTED_SWEEP_BINDING_VERSIONS, SUPPORTED_X402_EXPECTED_VERSIONS, type SignerCompatibility, type SignerConsentDecision, type SignerConsentInput, type SignerConsentOptions, type SignerCredentials, type SignerOptions, type SignerToolName, type SigningAuditContext, type SigningAuditEntry, type ToolFailure, type ToolPayload, type ToolSuccess, type X402ExpectedPayment, type X402FundingSignatureResult, type X402HeaderResult, appendSigningAuditEntry, assertSupportedBindingVersion, assertSupportedNodeVersion, assertX402MatchesExpected, buildSignerMcpServer, computeSignerConsentHash, createEdgeSigner, createSigningAuditEntry, createToolHandlers, defaultSigningAuditPath, ensureSignerConsent, hashPayloadForAudit, loadSignerCredentials, renderSignerConsentBlock, resolveEdgeSigner, resolveSignerRuntime, runSignerConsentGate, runSignerStdioServer, signerCapabilityAdvertisement, signerCompatibility, signerInstructions, toolDescriptions, toolSchemas, warnIfCredentialFilePermissive };
|
|
544
|
+
export { type EdgeSigner, type ResolvedSignerRuntime, SIGNER_ACK_ENV, SIGNER_CAPABILITY_KEY, SIGNER_NAME, SIGNER_VERSION, SUPPORTED_SWEEP_BINDING_VERSIONS, SUPPORTED_X402_EXPECTED_VERSIONS, type SignerCompatibility, type SignerConsentDecision, type SignerConsentInput, type SignerConsentOptions, type SignerCredentials, type SignerOptions, type SignerToolName, type SigningAuditContext, type SigningAuditEntry, type ToolFailure, type ToolPayload, type ToolSuccess, type X402ExpectedPayment, type X402FundingSignatureResult, type X402HeaderResult, appendSigningAuditEntry, assertSupportedBindingVersion, assertSupportedNodeVersion, assertX402MatchesExpected, buildSignerMcpServer, computeSignerConsentHash, createEdgeSigner, createSigningAuditEntry, createToolHandlers, defaultSigningAuditPath, ensureSignerConsent, hashPayloadForAudit, loadSignerCredentials, readAccountAddressEnv, readAccountAddressField, renderSignerConsentBlock, resolveEdgeSigner, resolveSignerRuntime, runSignerConsentGate, runSignerStdioServer, signerCapabilityAdvertisement, signerCompatibility, signerInstructions, toolDescriptions, toolSchemas, warnIfCredentialFilePermissive };
|
package/dist/index.d.ts
CHANGED
|
@@ -282,6 +282,17 @@ declare function signerInstructions(): string;
|
|
|
282
282
|
interface SignerCredentials {
|
|
283
283
|
delegateKey: string;
|
|
284
284
|
agentId?: string;
|
|
285
|
+
/**
|
|
286
|
+
* The Haven account (smart account) the agent spends from — #2908, the
|
|
287
|
+
* account-vocabulary name. Same value as `safeAddress`.
|
|
288
|
+
*/
|
|
289
|
+
accountAddress?: string;
|
|
290
|
+
/**
|
|
291
|
+
* @deprecated #2908 — same value as {@link SignerCredentials.accountAddress}.
|
|
292
|
+
* Removed from this shape in the release after the one carrying #2908
|
|
293
|
+
* (#2914). The credential-FILE keys it was read from are a different
|
|
294
|
+
* matter — see `readAccountAddressField`.
|
|
295
|
+
*/
|
|
285
296
|
safeAddress?: string;
|
|
286
297
|
chainId?: number;
|
|
287
298
|
network?: string;
|
|
@@ -289,6 +300,23 @@ interface SignerCredentials {
|
|
|
289
300
|
/** Absolute path the key was loaded from, if a file was used. */
|
|
290
301
|
sourcePath?: string;
|
|
291
302
|
}
|
|
303
|
+
interface RawCredentialFile {
|
|
304
|
+
delegate_key?: unknown;
|
|
305
|
+
delegateKey?: unknown;
|
|
306
|
+
agent_id?: unknown;
|
|
307
|
+
agentId?: unknown;
|
|
308
|
+
/** #2908: what `@haven_ai/connect` writes from this release on. */
|
|
309
|
+
account_address?: unknown;
|
|
310
|
+
/** Pre-#2908 spelling — read PERMANENTLY, see `readAccountAddressField`. */
|
|
311
|
+
safe_address?: unknown;
|
|
312
|
+
/** Pre-#2908 spelling — read PERMANENTLY, see `readAccountAddressField`. */
|
|
313
|
+
safeAddress?: unknown;
|
|
314
|
+
chain_id?: unknown;
|
|
315
|
+
chainId?: unknown;
|
|
316
|
+
network?: unknown;
|
|
317
|
+
x402_binding_signer?: unknown;
|
|
318
|
+
x402BindingSigner?: unknown;
|
|
319
|
+
}
|
|
292
320
|
/**
|
|
293
321
|
* Resolve the delegate key for the edge signer.
|
|
294
322
|
*
|
|
@@ -301,6 +329,30 @@ interface SignerCredentials {
|
|
|
301
329
|
* `delegate_key` and ignore the rest.
|
|
302
330
|
*/
|
|
303
331
|
declare function loadSignerCredentials(path?: string | undefined): Promise<SignerCredentials>;
|
|
332
|
+
/**
|
|
333
|
+
* The account address off a credential FILE: `account_address` (what
|
|
334
|
+
* `@haven_ai/connect` writes from #2908 on) first, then the two pre-#2908
|
|
335
|
+
* spellings.
|
|
336
|
+
*
|
|
337
|
+
* The two old fallbacks are PERMANENT, not part of the one-release naming
|
|
338
|
+
* window (#2906, decision 2a): a credential file on disk was written once and
|
|
339
|
+
* never rewrites itself, so a signer that stopped reading `safe_address`
|
|
340
|
+
* would silently lose the address for every agent connected before this
|
|
341
|
+
* release — the consent hash would change and the spend-context prompt would
|
|
342
|
+
* say "not provided". Two lines, kept for as long as the file format exists.
|
|
343
|
+
*
|
|
344
|
+
* Exported for the mutation tests: dropping `account_address` fails the
|
|
345
|
+
* new-shape test, dropping either old key fails the old-shape test.
|
|
346
|
+
*/
|
|
347
|
+
declare function readAccountAddressField(raw: Pick<RawCredentialFile, 'account_address' | 'safe_address' | 'safeAddress'>): string | undefined;
|
|
348
|
+
/**
|
|
349
|
+
* The account address off the process environment, new name first:
|
|
350
|
+
* `HAVEN_ACCOUNT_ADDRESS` (the survivor, decided on #2906) then the two
|
|
351
|
+
* names the dashboard handoff emitted before #2908 — `HAVEN_WALLET_ADDRESS`
|
|
352
|
+
* and `HAVEN_SAFE_ADDRESS`. Unlike the file fallbacks these two ARE
|
|
353
|
+
* window-scoped: they are dropped at #2914, one release after this one.
|
|
354
|
+
*/
|
|
355
|
+
declare function readAccountAddressEnv(env: NodeJS.ProcessEnv): string | undefined;
|
|
304
356
|
/**
|
|
305
357
|
* Warn (best-effort, POSIX only) when the credential file is readable beyond
|
|
306
358
|
* its owner. Mirrors `@haven_ai/mcp`'s check — the delegate key is the most
|
|
@@ -368,9 +420,17 @@ interface ToolFailure {
|
|
|
368
420
|
/**
|
|
369
421
|
* #1309: precise recovery guidance as DATA, not just prose inside `message`
|
|
370
422
|
* — the same text the hosted quote's advisory `signer_compatibility.fallback`
|
|
371
|
-
* carries when the refusal is an out-of-date signer.
|
|
423
|
+
* carries when the refusal is an out-of-date signer. #3001 reuses this same
|
|
424
|
+
* field for every sign-context refusal (`'typed_data_b64'`).
|
|
372
425
|
*/
|
|
373
426
|
fallback?: string;
|
|
427
|
+
/**
|
|
428
|
+
* #3001: present on `SIGN_CONTEXT_REFUSED` — the HTTP status the backend
|
|
429
|
+
* answered the `/x402/:id/sign-context` fetch with (404, 410, …).
|
|
430
|
+
*/
|
|
431
|
+
http_status?: number;
|
|
432
|
+
/** #3001: the backend's own `error_code` on `SIGN_CONTEXT_REFUSED` (`expired`, `already_executed`, `not_signable`, `sign_context_unavailable`). */
|
|
433
|
+
backend_error_code?: string;
|
|
374
434
|
}
|
|
375
435
|
type ToolPayload<T = unknown> = ToolSuccess<T> | ToolFailure;
|
|
376
436
|
interface ToolHandlerOptions {
|
|
@@ -416,7 +476,7 @@ declare function renderSignerConsentBlock(input: SignerConsentInput, hash: strin
|
|
|
416
476
|
declare function ensureSignerConsent(input: SignerConsentInput, options?: SignerConsentOptions): Promise<SignerConsentDecision>;
|
|
417
477
|
|
|
418
478
|
declare const SIGNER_NAME = "@haven_ai/signer";
|
|
419
|
-
declare const SIGNER_VERSION = "0.1
|
|
479
|
+
declare const SIGNER_VERSION = "0.2.1-alpha.0";
|
|
420
480
|
interface SignerOptions {
|
|
421
481
|
/** Path to a Haven credential JSON file (delegate_key is read from it). */
|
|
422
482
|
credentialsPath?: string;
|
|
@@ -481,4 +541,4 @@ declare function assertSupportedNodeVersion(nodeVersion?: string): void;
|
|
|
481
541
|
declare function runSignerStdioServer(options?: SignerOptions): Promise<void>;
|
|
482
542
|
declare function runSignerConsentGate(signer: EdgeSigner, credentials: SignerCredentials | undefined, options: SignerOptions): Promise<SignerConsentDecision>;
|
|
483
543
|
|
|
484
|
-
export { type EdgeSigner, type ResolvedSignerRuntime, SIGNER_ACK_ENV, SIGNER_CAPABILITY_KEY, SIGNER_NAME, SIGNER_VERSION, SUPPORTED_SWEEP_BINDING_VERSIONS, SUPPORTED_X402_EXPECTED_VERSIONS, type SignerCompatibility, type SignerConsentDecision, type SignerConsentInput, type SignerConsentOptions, type SignerCredentials, type SignerOptions, type SignerToolName, type SigningAuditContext, type SigningAuditEntry, type ToolFailure, type ToolPayload, type ToolSuccess, type X402ExpectedPayment, type X402FundingSignatureResult, type X402HeaderResult, appendSigningAuditEntry, assertSupportedBindingVersion, assertSupportedNodeVersion, assertX402MatchesExpected, buildSignerMcpServer, computeSignerConsentHash, createEdgeSigner, createSigningAuditEntry, createToolHandlers, defaultSigningAuditPath, ensureSignerConsent, hashPayloadForAudit, loadSignerCredentials, renderSignerConsentBlock, resolveEdgeSigner, resolveSignerRuntime, runSignerConsentGate, runSignerStdioServer, signerCapabilityAdvertisement, signerCompatibility, signerInstructions, toolDescriptions, toolSchemas, warnIfCredentialFilePermissive };
|
|
544
|
+
export { type EdgeSigner, type ResolvedSignerRuntime, SIGNER_ACK_ENV, SIGNER_CAPABILITY_KEY, SIGNER_NAME, SIGNER_VERSION, SUPPORTED_SWEEP_BINDING_VERSIONS, SUPPORTED_X402_EXPECTED_VERSIONS, type SignerCompatibility, type SignerConsentDecision, type SignerConsentInput, type SignerConsentOptions, type SignerCredentials, type SignerOptions, type SignerToolName, type SigningAuditContext, type SigningAuditEntry, type ToolFailure, type ToolPayload, type ToolSuccess, type X402ExpectedPayment, type X402FundingSignatureResult, type X402HeaderResult, appendSigningAuditEntry, assertSupportedBindingVersion, assertSupportedNodeVersion, assertX402MatchesExpected, buildSignerMcpServer, computeSignerConsentHash, createEdgeSigner, createSigningAuditEntry, createToolHandlers, defaultSigningAuditPath, ensureSignerConsent, hashPayloadForAudit, loadSignerCredentials, readAccountAddressEnv, readAccountAddressField, renderSignerConsentBlock, resolveEdgeSigner, resolveSignerRuntime, runSignerConsentGate, runSignerStdioServer, signerCapabilityAdvertisement, signerCompatibility, signerInstructions, toolDescriptions, toolSchemas, warnIfCredentialFilePermissive };
|
package/dist/index.js
CHANGED
|
@@ -501,10 +501,12 @@ async function loadSignerCredentials(path = process.env.HAVEN_CREDENTIALS) {
|
|
|
501
501
|
if (path) return loadFromFile(path);
|
|
502
502
|
const envKey = stringField(process.env.HAVEN_DELEGATE_KEY);
|
|
503
503
|
if (envKey) {
|
|
504
|
+
const accountAddress = readAccountAddressEnv(process.env);
|
|
504
505
|
return {
|
|
505
506
|
delegateKey: envKey,
|
|
506
507
|
agentId: stringField(process.env.HAVEN_AGENT_ID),
|
|
507
|
-
|
|
508
|
+
accountAddress,
|
|
509
|
+
safeAddress: accountAddress,
|
|
508
510
|
chainId: chainIdField(process.env.HAVEN_CHAIN_ID, "HAVEN_CHAIN_ID"),
|
|
509
511
|
network: stringField(process.env.HAVEN_NETWORK),
|
|
510
512
|
x402BindingSigner: stringField(process.env.HAVEN_X402_BINDING_SIGNER)
|
|
@@ -534,10 +536,12 @@ async function loadFromFile(path) {
|
|
|
534
536
|
if (!delegateKey) {
|
|
535
537
|
throw new Error("Haven credentials are missing delegate_key \u2014 the edge signer needs it to sign.");
|
|
536
538
|
}
|
|
539
|
+
const accountAddress = readAccountAddressField(raw);
|
|
537
540
|
return {
|
|
538
541
|
delegateKey,
|
|
539
542
|
agentId: stringField(raw.agent_id ?? raw.agentId),
|
|
540
|
-
|
|
543
|
+
accountAddress,
|
|
544
|
+
safeAddress: accountAddress,
|
|
541
545
|
chainId: chainIdField(raw.chain_id ?? raw.chainId, "chain_id"),
|
|
542
546
|
network: stringField(raw.network),
|
|
543
547
|
x402BindingSigner: stringField(
|
|
@@ -546,6 +550,12 @@ async function loadFromFile(path) {
|
|
|
546
550
|
sourcePath: path
|
|
547
551
|
};
|
|
548
552
|
}
|
|
553
|
+
function readAccountAddressField(raw) {
|
|
554
|
+
return stringField(raw.account_address ?? raw.safe_address ?? raw.safeAddress);
|
|
555
|
+
}
|
|
556
|
+
function readAccountAddressEnv(env) {
|
|
557
|
+
return stringField(env.HAVEN_ACCOUNT_ADDRESS ?? env.HAVEN_WALLET_ADDRESS ?? env.HAVEN_SAFE_ADDRESS);
|
|
558
|
+
}
|
|
549
559
|
function stringField(value) {
|
|
550
560
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
551
561
|
}
|
|
@@ -617,6 +627,49 @@ function stableStringify(value) {
|
|
|
617
627
|
const object = value;
|
|
618
628
|
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(",")}}`;
|
|
619
629
|
}
|
|
630
|
+
var HavenSignContextError = class extends HavenSigningError {
|
|
631
|
+
/**
|
|
632
|
+
* #3001 / #3010 review: the recovery path, when signing OTHER bytes is
|
|
633
|
+
* actually a remedy — a transport failure (timeout, unreachable) or a
|
|
634
|
+
* body this signer could not read. `typed_data_b64` is NOT in the default
|
|
635
|
+
* quote result since #1272: obtain it by re-running the SAME quote tool
|
|
636
|
+
* with the SAME idempotency_key plus `include_signing_payload: true`.
|
|
637
|
+
* Absent on a backend REFUSAL: an expired, executed or unsignable intent
|
|
638
|
+
* cannot be rescued by re-signing its bytes.
|
|
639
|
+
*/
|
|
640
|
+
fallback;
|
|
641
|
+
/**
|
|
642
|
+
* #3001: `AgentPaymentNextAction` values the signer already emits — the
|
|
643
|
+
* version-mismatch refusal's `stop_and_tell_user` for the classes where
|
|
644
|
+
* retrying the same call cannot help, and `payment_window_expired` (with
|
|
645
|
+
* `retry_with_new_quote`) for the backend's 410 `expired`, exactly as the
|
|
646
|
+
* plain `HavenError` branch already does for that code.
|
|
647
|
+
*/
|
|
648
|
+
next_action;
|
|
649
|
+
retry_with_new_quote;
|
|
650
|
+
/** Present only for `SIGN_CONTEXT_REFUSED` (the backend's HTTP status). */
|
|
651
|
+
http_status;
|
|
652
|
+
/** Present only for `SIGN_CONTEXT_REFUSED`: the backend's own `error_code`. */
|
|
653
|
+
backend_error_code;
|
|
654
|
+
constructor(message, code, refusal) {
|
|
655
|
+
super(message);
|
|
656
|
+
this.code = code;
|
|
657
|
+
this.name = "HavenSignContextError";
|
|
658
|
+
if (code === "SIGN_CONTEXT_REFUSED") {
|
|
659
|
+
this.http_status = refusal?.httpStatus;
|
|
660
|
+
this.backend_error_code = refusal?.errorCode;
|
|
661
|
+
if (refusal?.httpStatus === 410 || refusal?.errorCode === "expired") {
|
|
662
|
+
this.next_action = AgentPaymentNextAction.PaymentWindowExpired;
|
|
663
|
+
this.retry_with_new_quote = true;
|
|
664
|
+
} else {
|
|
665
|
+
this.next_action = AgentPaymentNextAction.StopAndTellUser;
|
|
666
|
+
}
|
|
667
|
+
} else {
|
|
668
|
+
this.fallback = "typed_data_b64";
|
|
669
|
+
this.next_action = AgentPaymentNextAction.StopAndTellUser;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
};
|
|
620
673
|
async function loadHavenIdentity(credentialsPath) {
|
|
621
674
|
if (!credentialsPath) return null;
|
|
622
675
|
try {
|
|
@@ -631,30 +684,50 @@ async function loadHavenIdentity(credentialsPath) {
|
|
|
631
684
|
return null;
|
|
632
685
|
}
|
|
633
686
|
}
|
|
634
|
-
|
|
687
|
+
var SIGN_CONTEXT_TIMEOUT_MS = 15e3;
|
|
688
|
+
async function fetchX402SignContext(identity, paymentId, fetchImpl = fetch, timeoutMs = SIGN_CONTEXT_TIMEOUT_MS) {
|
|
635
689
|
let response;
|
|
636
690
|
try {
|
|
637
691
|
response = await fetchImpl(
|
|
638
692
|
`${identity.apiUrl}/x402/${encodeURIComponent(paymentId)}/sign-context`,
|
|
639
|
-
{
|
|
693
|
+
{
|
|
694
|
+
headers: { Authorization: `Bearer ${identity.apiKey}` },
|
|
695
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
696
|
+
}
|
|
640
697
|
);
|
|
641
698
|
} catch (err) {
|
|
642
|
-
|
|
643
|
-
|
|
699
|
+
const timedOut = err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError");
|
|
700
|
+
throw new HavenSignContextError(
|
|
701
|
+
timedOut ? `Haven did not answer the signing-context fetch for ${paymentId} within ${timeoutMs} ms. Retry, or pass typed_data_b64 from the quote result instead.` : `Could not reach Haven to fetch the signing context for ${paymentId}: ${err instanceof Error ? err.message : String(err)}. Retry, or pass typed_data_b64 from the quote result instead.`,
|
|
702
|
+
timedOut ? "SIGN_CONTEXT_TIMEOUT" : "SIGN_CONTEXT_UNREACHABLE"
|
|
644
703
|
);
|
|
645
704
|
}
|
|
646
|
-
|
|
705
|
+
let body;
|
|
706
|
+
try {
|
|
707
|
+
body = await response.json();
|
|
708
|
+
} catch (err) {
|
|
709
|
+
if (err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError")) {
|
|
710
|
+
throw new HavenSignContextError(
|
|
711
|
+
`Haven did not finish sending the signing context for ${paymentId} within ${timeoutMs} ms. Retry, or pass typed_data_b64 from the quote result instead.`,
|
|
712
|
+
"SIGN_CONTEXT_TIMEOUT"
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
body = {};
|
|
716
|
+
}
|
|
647
717
|
if (!response.ok) {
|
|
648
718
|
const detail = typeof body.error === "string" ? body.error : `HTTP ${response.status}`;
|
|
649
|
-
throw new
|
|
650
|
-
`Haven refused the signing-context fetch for ${paymentId}: ${detail}` + (response.status === 404 ? " \u2014 check the payment_id came from this agent\u2019s own quote." : response.status === 410 ? " Re-run the quote with the same idempotency key, then sign the fresh payment_id." : "")
|
|
719
|
+
throw new HavenSignContextError(
|
|
720
|
+
`Haven refused the signing-context fetch for ${paymentId}: ${detail}` + (response.status === 404 ? " \u2014 check the payment_id came from this agent\u2019s own quote." : response.status === 410 ? " Re-run the quote with the same idempotency key, then sign the fresh payment_id." : ""),
|
|
721
|
+
"SIGN_CONTEXT_REFUSED",
|
|
722
|
+
{ httpStatus: response.status, errorCode: typeof body.error_code === "string" ? body.error_code : void 0 }
|
|
651
723
|
);
|
|
652
724
|
}
|
|
653
725
|
const signData = body.sign_data;
|
|
654
726
|
const x402Expected = body.x402_expected;
|
|
655
727
|
if (!signData || typeof signData.hash !== "string" || !signData.typed_data || typeof signData.typed_data !== "object" || !x402Expected) {
|
|
656
|
-
throw new
|
|
657
|
-
"The Haven sign-context response is missing sign_data.typed_data or x402_expected \u2014 the backend may predate #1263. Pass typed_data_b64 from the quote result instead."
|
|
728
|
+
throw new HavenSignContextError(
|
|
729
|
+
"The Haven sign-context response is missing sign_data.typed_data or x402_expected \u2014 the backend may predate #1263. Pass typed_data_b64 from the quote result instead.",
|
|
730
|
+
"SIGN_CONTEXT_MALFORMED"
|
|
658
731
|
);
|
|
659
732
|
}
|
|
660
733
|
const paymentRequired = body.payment_required;
|
|
@@ -1085,6 +1158,18 @@ function normalizeError(err) {
|
|
|
1085
1158
|
next_action: AgentPaymentNextAction.StopAndTellUser
|
|
1086
1159
|
};
|
|
1087
1160
|
}
|
|
1161
|
+
if (err instanceof HavenSignContextError) {
|
|
1162
|
+
return {
|
|
1163
|
+
success: false,
|
|
1164
|
+
code: err.code,
|
|
1165
|
+
message: err.message,
|
|
1166
|
+
next_action: err.next_action,
|
|
1167
|
+
...err.fallback !== void 0 ? { fallback: err.fallback } : {},
|
|
1168
|
+
...err.retry_with_new_quote ? { retry_with_new_quote: true } : {},
|
|
1169
|
+
...err.http_status !== void 0 ? { http_status: err.http_status } : {},
|
|
1170
|
+
...err.backend_error_code !== void 0 ? { backend_error_code: err.backend_error_code } : {}
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1088
1173
|
if (err instanceof HavenSigningError) {
|
|
1089
1174
|
return { success: false, code: err.code, message: err.message };
|
|
1090
1175
|
}
|
|
@@ -1231,7 +1316,7 @@ async function writeAckFile(path, hash) {
|
|
|
1231
1316
|
);
|
|
1232
1317
|
}
|
|
1233
1318
|
var SIGNER_NAME = "@haven_ai/signer";
|
|
1234
|
-
var SIGNER_VERSION = "0.1
|
|
1319
|
+
var SIGNER_VERSION = "0.2.1-alpha.0";
|
|
1235
1320
|
async function resolveEdgeSigner(options = {}) {
|
|
1236
1321
|
const { signer } = await resolveSignerRuntime(options);
|
|
1237
1322
|
return signer;
|
|
@@ -1270,7 +1355,7 @@ function buildSignerMcpServer(signer, options = {}) {
|
|
|
1270
1355
|
audit: {
|
|
1271
1356
|
auditPath: options.auditPath ?? defaultSigningAuditPath(credentialsPath),
|
|
1272
1357
|
delegateAddress: signer.delegateAddress,
|
|
1273
|
-
safeAddress: options.credentials?.safeAddress,
|
|
1358
|
+
safeAddress: options.credentials?.accountAddress ?? options.credentials?.safeAddress,
|
|
1274
1359
|
chainId: options.credentials?.chainId
|
|
1275
1360
|
},
|
|
1276
1361
|
// #1263: the payment_id signing path — the ONLY network call this server
|
|
@@ -1320,7 +1405,7 @@ async function runSignerConsentGate(signer, credentials, options) {
|
|
|
1320
1405
|
return ensureSignerConsent(
|
|
1321
1406
|
{
|
|
1322
1407
|
delegateAddress: signer.delegateAddress,
|
|
1323
|
-
safeAddress: credentials?.safeAddress,
|
|
1408
|
+
safeAddress: credentials?.accountAddress ?? credentials?.safeAddress,
|
|
1324
1409
|
agentId: credentials?.agentId,
|
|
1325
1410
|
chainId: credentials?.chainId,
|
|
1326
1411
|
network: credentials?.network,
|
|
@@ -1341,6 +1426,6 @@ function toMcpResult(payload) {
|
|
|
1341
1426
|
};
|
|
1342
1427
|
}
|
|
1343
1428
|
|
|
1344
|
-
export { SIGNER_ACK_ENV, SIGNER_CAPABILITY_KEY, SIGNER_NAME, SIGNER_VERSION, SUPPORTED_SWEEP_BINDING_VERSIONS, SUPPORTED_X402_EXPECTED_VERSIONS, appendSigningAuditEntry, assertSupportedBindingVersion, assertSupportedNodeVersion, assertX402MatchesExpected, buildSignerMcpServer, computeSignerConsentHash, createEdgeSigner, createSigningAuditEntry, createToolHandlers, defaultSigningAuditPath, ensureSignerConsent, hashPayloadForAudit, loadSignerCredentials, renderSignerConsentBlock, resolveEdgeSigner, resolveSignerRuntime, runSignerConsentGate, runSignerStdioServer, signerCapabilityAdvertisement, signerCompatibility, signerInstructions, toolDescriptions, toolSchemas, warnIfCredentialFilePermissive };
|
|
1429
|
+
export { SIGNER_ACK_ENV, SIGNER_CAPABILITY_KEY, SIGNER_NAME, SIGNER_VERSION, SUPPORTED_SWEEP_BINDING_VERSIONS, SUPPORTED_X402_EXPECTED_VERSIONS, appendSigningAuditEntry, assertSupportedBindingVersion, assertSupportedNodeVersion, assertX402MatchesExpected, buildSignerMcpServer, computeSignerConsentHash, createEdgeSigner, createSigningAuditEntry, createToolHandlers, defaultSigningAuditPath, ensureSignerConsent, hashPayloadForAudit, loadSignerCredentials, readAccountAddressEnv, readAccountAddressField, renderSignerConsentBlock, resolveEdgeSigner, resolveSignerRuntime, runSignerConsentGate, runSignerStdioServer, signerCapabilityAdvertisement, signerCompatibility, signerInstructions, toolDescriptions, toolSchemas, warnIfCredentialFilePermissive };
|
|
1345
1430
|
//# sourceMappingURL=index.js.map
|
|
1346
1431
|
//# sourceMappingURL=index.js.map
|