@agent-score/commerce 1.3.2 → 1.5.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.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -22,22 +32,30 @@ var index_exports = {};
22
32
  __export(index_exports, {
23
33
  AGENTSCORE_UCP_CAPABILITY: () => AGENTSCORE_UCP_CAPABILITY,
24
34
  FIXABLE_DENIAL_REASONS: () => FIXABLE_DENIAL_REASONS,
35
+ UCPVerificationError: () => UCPVerificationError,
36
+ UCP_A2A_EXTENSION_URI: () => UCP_A2A_EXTENSION_URI,
25
37
  buildA2AAgentCard: () => buildA2AAgentCard,
26
38
  buildAgentMemoryHint: () => buildAgentMemoryHint,
27
39
  buildContactSupportNextSteps: () => buildContactSupportNextSteps,
40
+ buildJWKSResponse: () => buildJWKSResponse,
28
41
  buildSignerMismatchBody: () => buildSignerMismatchBody,
29
42
  buildUCPProfile: () => buildUCPProfile,
30
43
  denialReasonStatus: () => denialReasonStatus,
31
44
  denialReasonToBody: () => denialReasonToBody,
32
45
  extractPaymentSigner: () => extractPaymentSigner,
33
46
  extractPaymentSignerAddress: () => extractPaymentSignerAddress,
47
+ generateUCPSigningKey: () => generateUCPSigningKey,
34
48
  isFixableDenial: () => isFixableDenial,
35
49
  policyToGateOptions: () => policyToGateOptions,
36
50
  readX402PaymentHeader: () => readX402PaymentHeader,
37
51
  runGateWithEnforcement: () => runGateWithEnforcement,
38
52
  shippingCountryAllowed: () => shippingCountryAllowed,
39
53
  shippingStateAllowed: () => shippingStateAllowed,
40
- verificationAgentInstructions: () => verificationAgentInstructions
54
+ signUCPProfile: () => signUCPProfile,
55
+ ucpA2AExtension: () => ucpA2AExtension,
56
+ ucpSigningKeyFromJWK: () => ucpSigningKeyFromJWK,
57
+ verificationAgentInstructions: () => verificationAgentInstructions,
58
+ verifyUCPProfile: () => verifyUCPProfile
41
59
  });
42
60
  module.exports = __toCommonJS(index_exports);
43
61
 
@@ -366,6 +384,13 @@ function readX402PaymentHeader(request) {
366
384
  }
367
385
 
368
386
  // src/identity/a2a.ts
387
+ var UCP_A2A_EXTENSION_URI = "https://ucp.dev/2026-04-08/specification/reference";
388
+ function ucpA2AExtension(capabilities = {}) {
389
+ return {
390
+ uri: UCP_A2A_EXTENSION_URI,
391
+ params: { capabilities }
392
+ };
393
+ }
369
394
  var PROTOCOL_VERSION = "1.0";
370
395
  var CARD_VERSION = 1;
371
396
  function buildA2AAgentCard(input) {
@@ -397,17 +422,62 @@ function buildA2AAgentCard(input) {
397
422
  if (input.description !== void 0) card.description = input.description;
398
423
  if (input.url !== void 0) card.url = input.url;
399
424
  if (input.capabilities !== void 0) card.capabilities = input.capabilities;
425
+ if (input.extensions && input.extensions.length > 0) card.extensions = input.extensions;
400
426
  if (input.extras !== void 0) card.extras = input.extras;
401
427
  return card;
402
428
  }
403
429
 
404
430
  // src/identity/ucp.ts
431
+ function ucpSigningKeyFromJWK(jwk) {
432
+ if (!jwk || typeof jwk !== "object") {
433
+ throw new Error(`ucpSigningKeyFromJWK expected a non-null object; got ${typeof jwk}.`);
434
+ }
435
+ if (typeof jwk.kid !== "string" || !jwk.kid) {
436
+ throw new Error("ucpSigningKeyFromJWK: JWK missing required field `kid` (or non-string).");
437
+ }
438
+ if (typeof jwk.kty !== "string" || !jwk.kty) {
439
+ throw new Error("ucpSigningKeyFromJWK: JWK missing required field `kty` (or non-string).");
440
+ }
441
+ if (jwk.kty !== "OKP" && jwk.kty !== "EC" && jwk.kty !== "RSA") {
442
+ throw new Error(
443
+ `ucpSigningKeyFromJWK: kty=${JSON.stringify(jwk.kty)} is not a supported asymmetric key type (expected OKP, EC, or RSA). Symmetric \`oct\` keys are rejected because they cannot publicly verify a JWS in the trust-mode UCP flow.`
444
+ );
445
+ }
446
+ if ((jwk.kty === "EC" || jwk.kty === "OKP") && (typeof jwk.crv !== "string" || !jwk.crv)) {
447
+ throw new Error(`ucpSigningKeyFromJWK: kty=${jwk.kty} requires a non-empty \`crv\` field (e.g., "P-256" for EC, "Ed25519" for OKP).`);
448
+ }
449
+ return jwk;
450
+ }
405
451
  var DEFAULT_VERSION = "2026-04-17";
406
- var SPEC_URL = "https://ucp.dev/";
407
- var AGENTSCORE_CAPABILITY_NAME = "agentscore-identity";
452
+ var AGENTSCORE_CAPABILITY_NAME = "sh.agentscore.identity";
408
453
  var AGENTSCORE_CAPABILITY_VERSION = "1";
454
+ var AGENTSCORE_DEFAULT_SPEC_URL = "https://agentscore.sh/specification/identity";
455
+ var AGENTSCORE_DEFAULT_SCHEMA_URL = "https://agentscore.sh/schemas/ucp/sh-agentscore-identity-v1.json";
456
+ var AGENTSCORE_EXTENDS = ["dev.ucp.shopping.checkout", "dev.ucp.shopping.cart"];
457
+ var RESERVED_TOP_LEVEL = /* @__PURE__ */ new Set([
458
+ "ucp",
459
+ "signing_keys",
460
+ "signature",
461
+ "__proto__",
462
+ "constructor",
463
+ "prototype"
464
+ ]);
465
+ var RESERVED_UCP_FIELDS = /* @__PURE__ */ new Set([
466
+ "version",
467
+ "name",
468
+ "services",
469
+ "capabilities",
470
+ "payment_handlers",
471
+ "supported_versions",
472
+ "__proto__",
473
+ "constructor",
474
+ "prototype"
475
+ ]);
409
476
  function buildUCPProfile(input) {
410
- const baseCapabilities = [...input.capabilities ?? []];
477
+ const capabilities = {};
478
+ for (const [name, bindings] of Object.entries(input.capabilities ?? {})) {
479
+ capabilities[name] = [...bindings];
480
+ }
411
481
  if (input.data) {
412
482
  const operatorId = input.data.resolved_operator;
413
483
  if (operatorId) {
@@ -415,36 +485,332 @@ function buildUCPProfile(input) {
415
485
  const accountVerification = input.data.account_verification;
416
486
  const claims = {
417
487
  operator_id: operatorId,
418
- kyc_level: accountVerification?.kyc_level ?? operatorVerification?.level ?? "none",
488
+ kyc_level: accountVerification?.kyc_level || operatorVerification?.level || "none",
419
489
  sanctions_clear: accountVerification?.sanctions_clear === true,
420
- age_bracket: accountVerification?.age_bracket ?? "unknown",
421
- jurisdiction: accountVerification?.jurisdiction ?? "",
422
- verified_at: accountVerification?.verified_at ?? operatorVerification?.verified_at ?? null,
490
+ age_bracket: accountVerification?.age_bracket || "unknown",
491
+ jurisdiction: accountVerification?.jurisdiction || "",
492
+ verified_at: accountVerification?.verified_at || operatorVerification?.verified_at || null,
423
493
  verify_url: input.data.verify_url ?? null,
424
494
  issuer: "https://agentscore.sh"
425
495
  };
426
- baseCapabilities.push({
427
- name: AGENTSCORE_CAPABILITY_NAME,
496
+ const agentscoreBinding = {
428
497
  version: AGENTSCORE_CAPABILITY_VERSION,
429
- schema: input.agentscoreSchemaUrl ?? "https://agentscore.sh/schemas/ucp/agentscore-identity.v1.json",
498
+ spec: input.agentscore_spec_url ?? AGENTSCORE_DEFAULT_SPEC_URL,
499
+ schema: input.agentscore_schema_url ?? AGENTSCORE_DEFAULT_SCHEMA_URL,
500
+ extends: AGENTSCORE_EXTENDS,
501
+ // `claims` is our vendor extra on the binding; allowed per spec via the
502
+ // `[k: string]: unknown` index signature on UCPCapabilityBinding.
430
503
  claims
431
- });
504
+ };
505
+ const existing = capabilities[AGENTSCORE_CAPABILITY_NAME];
506
+ if (existing) existing.push(agentscoreBinding);
507
+ else capabilities[AGENTSCORE_CAPABILITY_NAME] = [agentscoreBinding];
432
508
  }
433
509
  }
434
- const profile = {
510
+ const ucp = {
435
511
  version: input.version ?? DEFAULT_VERSION,
436
- spec: SPEC_URL,
437
- services: input.services,
438
- capabilities: baseCapabilities,
439
- payment_handlers: input.payment_handlers ?? [],
512
+ services: input.services ?? {},
513
+ capabilities,
514
+ payment_handlers: input.payment_handlers ?? {}
515
+ };
516
+ if (input.name !== void 0) ucp.name = input.name;
517
+ if (input.supported_versions !== void 0) ucp.supported_versions = input.supported_versions;
518
+ if (input.ucp_extras) {
519
+ for (const k of Object.keys(input.ucp_extras)) {
520
+ if (RESERVED_UCP_FIELDS.has(k)) {
521
+ throw new Error(`buildUCPProfile: ucp_extras key "${k}" collides with a reserved \`ucp\` field; rejected.`);
522
+ }
523
+ }
524
+ Object.assign(ucp, input.ucp_extras);
525
+ }
526
+ const profile = {
527
+ ucp,
440
528
  signing_keys: input.signing_keys
441
529
  };
442
- if (input.name !== void 0) profile.name = input.name;
443
- if (input.extras) Object.assign(profile, input.extras);
530
+ if (input.extras) {
531
+ for (const k of Object.keys(input.extras)) {
532
+ if (RESERVED_TOP_LEVEL.has(k)) {
533
+ throw new Error(`buildUCPProfile: extras key "${k}" collides with a reserved profile field; rejected.`);
534
+ }
535
+ }
536
+ Object.assign(profile, input.extras);
537
+ }
444
538
  return profile;
445
539
  }
446
540
  var AGENTSCORE_UCP_CAPABILITY = AGENTSCORE_CAPABILITY_NAME;
447
541
 
542
+ // src/identity/ucp-jwks.ts
543
+ var JOSE_INSTALL_HINT = "Install the optional peer dependency: `npm install jose@^6` (or `bun add jose`). Tested against jose v6.x.";
544
+ var ALLOWED_ALGS = ["EdDSA", "ES256"];
545
+ var PROFILE_TYP = "agentscore-profile+jws";
546
+ var UCPVerificationError = class extends Error {
547
+ constructor(code, message) {
548
+ super(message);
549
+ this.code = code;
550
+ this.name = "UCPVerificationError";
551
+ }
552
+ code;
553
+ };
554
+ async function loadJose() {
555
+ try {
556
+ return await import("jose");
557
+ } catch (err) {
558
+ throw new Error(
559
+ `UCP signing requires the \`jose\` library, which is an optional peer dependency. ${JOSE_INSTALL_HINT}
560
+ Original error: ${err instanceof Error ? err.message : String(err)}`
561
+ );
562
+ }
563
+ }
564
+ function canonicalizeProfile(profile) {
565
+ const stripped = { ...profile };
566
+ delete stripped.signature;
567
+ return stableStringify(stripped);
568
+ }
569
+ function stableStringify(value) {
570
+ if (value === void 0) {
571
+ throw new Error(
572
+ "stableStringify: undefined values are not allowed in canonicalized JSON. Object fields with no value must be omitted."
573
+ );
574
+ }
575
+ if (typeof value === "function" || typeof value === "symbol") {
576
+ throw new Error(`stableStringify: ${typeof value} values are not allowed in canonicalized JSON.`);
577
+ }
578
+ if (typeof value === "bigint") {
579
+ throw new Error("stableStringify: BigInt values are not allowed; use a decimal string.");
580
+ }
581
+ if (value instanceof Date) {
582
+ throw new Error(
583
+ "stableStringify: Date instances are not allowed; serialize to an ISO string before passing."
584
+ );
585
+ }
586
+ if (value instanceof Map || value instanceof Set || value instanceof WeakMap || value instanceof WeakSet) {
587
+ throw new Error(
588
+ `stableStringify: ${value.constructor.name} values are not allowed; convert to a plain object/array first.`
589
+ );
590
+ }
591
+ if (ArrayBuffer.isView(value)) {
592
+ throw new Error("stableStringify: typed arrays are not allowed; convert to a plain array first.");
593
+ }
594
+ if (typeof value === "number") {
595
+ if (!Number.isFinite(value)) {
596
+ throw new Error(
597
+ `UCP profile canonicalization rejects non-finite Number ${value}. Use a decimal string for any value that may be NaN/Infinity.`
598
+ );
599
+ }
600
+ if (!Number.isInteger(value)) {
601
+ throw new Error(
602
+ `UCP profile canonicalization rejects non-integer Number ${value}. Use a decimal string (e.g. "9.99") for monetary or fractional fields to preserve cross-language byte-parity.`
603
+ );
604
+ }
605
+ if (!Number.isSafeInteger(value)) {
606
+ throw new Error(
607
+ `stableStringify: integer ${value} exceeds Number.MAX_SAFE_INTEGER. For values >2^53, use a decimal string to preserve cross-language byte parity.`
608
+ );
609
+ }
610
+ }
611
+ if (typeof value === "string") {
612
+ if (value.includes("\u2028") || value.includes("\u2029")) {
613
+ throw new Error(
614
+ "stableStringify: strings containing U+2028 (LINE SEPARATOR) or U+2029 (PARAGRAPH SEPARATOR) are not allowed; cross-language byte parity requires neither be present (Node JSON.stringify on older V8 escapes them; Python json.dumps with ensure_ascii=False does not)."
615
+ );
616
+ }
617
+ return JSON.stringify(value);
618
+ }
619
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
620
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
621
+ const obj = value;
622
+ const keys = Object.keys(obj).sort((a, b) => {
623
+ const aPoints = [...a].map((c) => c.codePointAt(0));
624
+ const bPoints = [...b].map((c) => c.codePointAt(0));
625
+ const len = Math.min(aPoints.length, bPoints.length);
626
+ for (let i = 0; i < len; i += 1) {
627
+ if (aPoints[i] !== bPoints[i]) return aPoints[i] - bPoints[i];
628
+ }
629
+ return aPoints.length - bPoints.length;
630
+ });
631
+ for (const k of keys) {
632
+ if (k.includes("\u2028") || k.includes("\u2029")) {
633
+ throw new Error(
634
+ "stableStringify: object keys containing U+2028 (LINE SEPARATOR) or U+2029 (PARAGRAPH SEPARATOR) are not allowed; cross-language byte parity (Node JSON.stringify on older V8 escapes them; Python json.dumps with ensure_ascii=False does not)."
635
+ );
636
+ }
637
+ }
638
+ const pairs = keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`);
639
+ return `{${pairs.join(",")}}`;
640
+ }
641
+ async function generateUCPSigningKey(opts) {
642
+ const jose = await loadJose();
643
+ const alg = opts.alg ?? "EdDSA";
644
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: true });
645
+ const exportedJwk = await jose.exportJWK(publicKey);
646
+ const publicJWK = {
647
+ kid: opts.kid,
648
+ alg,
649
+ use: "sig",
650
+ ...exportedJwk
651
+ };
652
+ return { privateKey, publicJWK };
653
+ }
654
+ async function signUCPProfile(profile, opts) {
655
+ const jose = await loadJose();
656
+ const alg = opts.alg ?? "EdDSA";
657
+ if (!ALLOWED_ALGS.includes(alg)) {
658
+ throw new Error(
659
+ `signUCPProfile: alg ${JSON.stringify(opts.alg)} is not in the supported set [${ALLOWED_ALGS.join(", ")}].`
660
+ );
661
+ }
662
+ if (typeof opts.kid !== "string" || !opts.kid) {
663
+ throw new Error("signUCPProfile: opts.kid must be a non-empty string.");
664
+ }
665
+ const kids = (profile.signing_keys ?? []).map((k) => k.kid);
666
+ if (!kids.includes(opts.kid)) {
667
+ throw new Error(
668
+ `signUCPProfile: kid ${JSON.stringify(opts.kid)} is not present in profile.signing_keys[] (declared kids: ${JSON.stringify(kids)}). Verifiers will not find the key.`
669
+ );
670
+ }
671
+ const canonicalBody = canonicalizeProfile(profile);
672
+ const payloadBytes = new TextEncoder().encode(canonicalBody);
673
+ const signature = await new jose.CompactSign(payloadBytes).setProtectedHeader({ alg, kid: opts.kid, typ: PROFILE_TYP }).sign(opts.signingKey);
674
+ return { ...profile, signature };
675
+ }
676
+ async function verifyUCPProfile(profile, jwks) {
677
+ if (profile === null || typeof profile !== "object" || Array.isArray(profile)) {
678
+ throw new UCPVerificationError(
679
+ "no_signature",
680
+ `UCP profile must be a JSON object; got ${profile === null ? "null" : Array.isArray(profile) ? "array" : typeof profile}.`
681
+ );
682
+ }
683
+ const jose = await loadJose();
684
+ if (!jwks || typeof jwks !== "object" || !Array.isArray(jwks.keys)) {
685
+ throw new UCPVerificationError(
686
+ "malformed_jwks",
687
+ `UCP verifier expected JWKS shape { keys: [...] }; got ${jwks === null ? "null" : typeof jwks === "object" ? "object without keys[] array" : typeof jwks}.`
688
+ );
689
+ }
690
+ const stripped = { ...profile };
691
+ const sig = stripped.signature;
692
+ delete stripped.signature;
693
+ if (typeof sig !== "string" || !sig) {
694
+ throw new UCPVerificationError(
695
+ "no_signature",
696
+ `UCP profile signature must be a non-empty string; got ${sig === void 0 ? "undefined" : typeof sig}.`
697
+ );
698
+ }
699
+ let header;
700
+ try {
701
+ const protectedB64 = sig.split(".")[0];
702
+ if (!protectedB64) throw new Error("JWS protected header segment is empty.");
703
+ const headerJson = new TextDecoder().decode(jose.base64url.decode(protectedB64));
704
+ const parsed = JSON.parse(headerJson);
705
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
706
+ throw new Error("JWS protected header is not a JSON object.");
707
+ }
708
+ header = parsed;
709
+ } catch (err) {
710
+ throw new UCPVerificationError(
711
+ "malformed_jws",
712
+ `JWS protected header is not valid base64url-encoded JSON: ${err instanceof Error ? err.message : String(err)}`
713
+ );
714
+ }
715
+ if (header.typ !== PROFILE_TYP) {
716
+ throw new UCPVerificationError("wrong_typ", `UCP signature typ must be "${PROFILE_TYP}"; got ${String(header.typ)}.`);
717
+ }
718
+ if (!ALLOWED_ALGS.includes(header.alg)) {
719
+ throw new UCPVerificationError("unsupported_alg", `UCP signing alg must be one of ${ALLOWED_ALGS.join(", ")}; got ${String(header.alg)}.`);
720
+ }
721
+ if (typeof header.kid !== "string" || !header.kid) {
722
+ throw new UCPVerificationError(
723
+ "missing_kid",
724
+ `UCP signature header kid must be a non-empty string; got ${header.kid === void 0 ? "undefined" : typeof header.kid}.`
725
+ );
726
+ }
727
+ if ("crit" in header) {
728
+ const crit = header.crit;
729
+ if (!Array.isArray(crit) || crit.length === 0 || !crit.every((c) => typeof c === "string")) {
730
+ throw new UCPVerificationError(
731
+ "malformed_jws",
732
+ `JWS protected header crit must be a non-empty array of strings; got ${JSON.stringify(crit)}.`
733
+ );
734
+ }
735
+ throw new UCPVerificationError(
736
+ "unrecognized_critical_header",
737
+ `JWS protected header advertises unrecognized crit headers: ${JSON.stringify(crit)}.`
738
+ );
739
+ }
740
+ let signedPayload;
741
+ try {
742
+ const verified = await jose.compactVerify(
743
+ sig,
744
+ async (h) => {
745
+ const kid = h.kid;
746
+ if (typeof kid !== "string" || !kid) {
747
+ throw new UCPVerificationError(
748
+ "missing_kid",
749
+ `UCP signature header kid must be a non-empty string; got ${kid === void 0 ? "undefined" : typeof kid}.`
750
+ );
751
+ }
752
+ const matches = jwks.keys.filter(
753
+ (k) => k != null && typeof k === "object" && k.kid === kid
754
+ );
755
+ if (matches.length === 0) throw new UCPVerificationError("kid_not_found", `No JWK in JWKS matching kid=${JSON.stringify(kid)}.`);
756
+ if (matches.length > 1) throw new UCPVerificationError("duplicate_kid", `JWKS contains ${matches.length} keys with kid=${JSON.stringify(kid)}; expected exactly one.`);
757
+ const matchedKey = matches[0];
758
+ if (matchedKey.use != null && matchedKey.use !== "sig") {
759
+ throw new UCPVerificationError("unusable_key", `JWK with kid=${kid} has use=${JSON.stringify(matchedKey.use)}; expected "sig".`);
760
+ }
761
+ if (matchedKey.alg != null && matchedKey.alg !== h.alg) {
762
+ throw new UCPVerificationError(
763
+ "unusable_key",
764
+ `JWK alg ${JSON.stringify(matchedKey.alg)} does not match JWS header alg ${JSON.stringify(h.alg)}.`
765
+ );
766
+ }
767
+ return jose.importJWK(matches[0], h.alg);
768
+ }
769
+ );
770
+ signedPayload = verified.payload;
771
+ } catch (err) {
772
+ if (err instanceof UCPVerificationError) throw err;
773
+ if (err instanceof Error && err.name === "JOSEAlgNotAllowed") {
774
+ throw new UCPVerificationError("unsupported_alg", `UCP signing alg not allowed: ${err.message}`);
775
+ }
776
+ if (err instanceof Error && err.name === "JWSSignatureVerificationFailed") {
777
+ throw new UCPVerificationError("signature_invalid", `UCP signature verification failed: ${err.message}`);
778
+ }
779
+ if (err instanceof Error && err.name === "JWSInvalid") {
780
+ throw new UCPVerificationError("malformed_jws", `Malformed JWS: ${err.message}`);
781
+ }
782
+ if (err instanceof Error && err.name === "JOSENotSupported") {
783
+ throw new UCPVerificationError("unrecognized_critical_header", `UCP signing rejected unrecognized critical header: ${err.message}`);
784
+ }
785
+ throw err;
786
+ }
787
+ let canonicalBody;
788
+ try {
789
+ canonicalBody = canonicalizeProfile(stripped);
790
+ } catch (err) {
791
+ throw new UCPVerificationError(
792
+ "body_mismatch",
793
+ `Failed to canonicalize received profile for verification: ${err instanceof Error ? err.message : String(err)}`
794
+ );
795
+ }
796
+ const expectedPayload = new TextEncoder().encode(canonicalBody);
797
+ if (!constantTimeEqual(signedPayload, expectedPayload)) {
798
+ throw new UCPVerificationError("body_mismatch", "UCP profile body does not match the signed payload (tampered or non-canonical).");
799
+ }
800
+ return true;
801
+ }
802
+ function constantTimeEqual(a, b) {
803
+ if (a.length !== b.length) return false;
804
+ let diff = 0;
805
+ for (let i = 0; i < a.length; i += 1) {
806
+ diff |= a[i] ^ b[i];
807
+ }
808
+ return diff === 0;
809
+ }
810
+ function buildJWKSResponse(keys) {
811
+ return { keys };
812
+ }
813
+
448
814
  // src/identity/policy.ts
449
815
  function policyToGateOptions(policy, base) {
450
816
  if (!policy || !policy.enforcement) return null;
@@ -495,21 +861,29 @@ function shippingStateAllowed(state, country, policy) {
495
861
  0 && (module.exports = {
496
862
  AGENTSCORE_UCP_CAPABILITY,
497
863
  FIXABLE_DENIAL_REASONS,
864
+ UCPVerificationError,
865
+ UCP_A2A_EXTENSION_URI,
498
866
  buildA2AAgentCard,
499
867
  buildAgentMemoryHint,
500
868
  buildContactSupportNextSteps,
869
+ buildJWKSResponse,
501
870
  buildSignerMismatchBody,
502
871
  buildUCPProfile,
503
872
  denialReasonStatus,
504
873
  denialReasonToBody,
505
874
  extractPaymentSigner,
506
875
  extractPaymentSignerAddress,
876
+ generateUCPSigningKey,
507
877
  isFixableDenial,
508
878
  policyToGateOptions,
509
879
  readX402PaymentHeader,
510
880
  runGateWithEnforcement,
511
881
  shippingCountryAllowed,
512
882
  shippingStateAllowed,
513
- verificationAgentInstructions
883
+ signUCPProfile,
884
+ ucpA2AExtension,
885
+ ucpSigningKeyFromJWK,
886
+ verificationAgentInstructions,
887
+ verifyUCPProfile
514
888
  });
515
889
  //# sourceMappingURL=index.js.map