@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/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.37-alpha.0";
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.37-alpha.0";
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
- safeAddress: stringField(process.env.HAVEN_SAFE_ADDRESS),
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
- safeAddress: stringField(raw.safe_address ?? raw.safeAddress),
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
- async function fetchX402SignContext(identity, paymentId, fetchImpl = fetch) {
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
- { headers: { Authorization: `Bearer ${identity.apiKey}` } }
693
+ {
694
+ headers: { Authorization: `Bearer ${identity.apiKey}` },
695
+ signal: AbortSignal.timeout(timeoutMs)
696
+ }
640
697
  );
641
698
  } catch (err) {
642
- throw new HavenSigningError(
643
- `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.`
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
- const body = await response.json().catch(() => ({}));
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 HavenSigningError(
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 HavenSigningError(
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.37-alpha.0";
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