@orangecheck/me-client 0.32.4 → 0.34.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.mjs CHANGED
@@ -267,8 +267,8 @@ async function hmacSha256Hex(secret, message) {
267
267
  false,
268
268
  ["sign"]
269
269
  );
270
- const sig = await crypto.subtle.sign("HMAC", key, enc.encode(message));
271
- return Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
270
+ const sig2 = await crypto.subtle.sign("HMAC", key, enc.encode(message));
271
+ return Array.from(new Uint8Array(sig2)).map((b) => b.toString(16).padStart(2, "0")).join("");
272
272
  }
273
273
  async function signBody(secret, serializedBody) {
274
274
  const t = Math.floor(Date.now() / 1e3);
@@ -678,46 +678,27 @@ var config = {
678
678
  // node_modules/jose/dist/webapi/lib/buffer_utils.js
679
679
  new TextEncoder();
680
680
  var decoder = new TextDecoder();
681
-
682
- // node_modules/jose/dist/webapi/lib/base64.js
683
- function decodeBase64(encoded) {
684
- if (Uint8Array.fromBase64) {
685
- return Uint8Array.fromBase64(encoded);
686
- }
687
- const binary = atob(encoded);
688
- const bytes = new Uint8Array(binary.length);
689
- for (let i = 0; i < binary.length; i++) {
681
+ new TextDecoder("utf-8", { fatal: true });
682
+ function decodeBase64(encoded, url = false) {
683
+ if (Uint8Array.fromBase64)
684
+ return Uint8Array.fromBase64(encoded, { alphabet: url ? "base64url" : "base64" });
685
+ if (url) {
686
+ if (encoded.includes("+") || encoded.includes("/"))
687
+ throw new TypeError("Invalid base64url");
688
+ encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
689
+ }
690
+ const binary = atob(encoded), bytes = new Uint8Array(binary.length);
691
+ for (let i = 0; i < binary.length; i++)
690
692
  bytes[i] = binary.charCodeAt(i);
691
- }
692
693
  return bytes;
693
694
  }
694
695
 
695
- // node_modules/jose/dist/webapi/util/base64url.js
696
- function decode(input) {
697
- if (Uint8Array.fromBase64) {
698
- return Uint8Array.fromBase64(typeof input === "string" ? input : decoder.decode(input), {
699
- alphabet: "base64url"
700
- });
701
- }
702
- let encoded = input;
703
- if (encoded instanceof Uint8Array) {
704
- encoded = decoder.decode(encoded);
705
- }
706
- encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
707
- try {
708
- return decodeBase64(encoded);
709
- } catch {
710
- throw new TypeError("The input to be decoded is not correctly encoded.");
711
- }
712
- }
713
-
714
696
  // node_modules/jose/dist/webapi/util/errors.js
715
697
  var JOSEError = class extends Error {
716
698
  constructor(message, options) {
717
699
  super(message, options);
718
700
  __publicField(this, "code", "ERR_JOSE_GENERIC");
719
- this.name = this.constructor.name;
720
- Error.captureStackTrace?.(this, this.constructor);
701
+ this.name = this.constructor.name, Error.captureStackTrace?.(this, this.constructor);
721
702
  }
722
703
  };
723
704
  __publicField(JOSEError, "code", "ERR_JOSE_GENERIC");
@@ -732,166 +713,258 @@ var _a, _b;
732
713
  var JWKSMultipleMatchingKeys = class extends (_b = JOSEError, _a = Symbol.asyncIterator, _b) {
733
714
  constructor(message = "multiple matching keys found in the JSON Web Key Set", options) {
734
715
  super(message, options);
735
- __publicField(this, _a);
716
+ __publicField(this, _a, async function* () {
717
+ });
736
718
  __publicField(this, "code", "ERR_JWKS_MULTIPLE_MATCHING_KEYS");
737
719
  }
738
720
  };
739
721
  __publicField(JWKSMultipleMatchingKeys, "code", "ERR_JWKS_MULTIPLE_MATCHING_KEYS");
740
722
 
741
- // node_modules/jose/dist/webapi/lib/type_checks.js
742
- var isObjectLike = (value) => typeof value === "object" && value !== null;
723
+ // node_modules/jose/dist/webapi/util/base64url.js
724
+ var invalid = "The input to be decoded is not correctly encoded.";
725
+ function decode(input) {
726
+ try {
727
+ return decodeBase64(typeof input == "string" ? input : decoder.decode(input), true);
728
+ } catch (cause) {
729
+ throw new TypeError(invalid, { cause });
730
+ }
731
+ }
732
+
733
+ // node_modules/jose/dist/webapi/lib/validate.js
743
734
  function isObject(input) {
744
- if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") {
735
+ if (typeof input != "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]")
745
736
  return false;
746
- }
747
- if (Object.getPrototypeOf(input) === null) {
748
- return true;
749
- }
750
- let proto = input;
751
- while (Object.getPrototypeOf(proto) !== null) {
752
- proto = Object.getPrototypeOf(proto);
753
- }
754
- return Object.getPrototypeOf(input) === proto;
737
+ const prototype = Object.getPrototypeOf(input);
738
+ return prototype === null || Object.getPrototypeOf(prototype) === null;
755
739
  }
756
740
 
757
- // node_modules/jose/dist/webapi/lib/jwk_to_key.js
758
- var unsupportedAlg = 'Invalid or unsupported JWK "alg" (Algorithm) Parameter value';
759
- function subtleMapping(jwk) {
760
- let algorithm;
761
- let keyUsages;
762
- switch (jwk.kty) {
763
- case "AKP": {
764
- switch (jwk.alg) {
765
- case "ML-DSA-44":
766
- case "ML-DSA-65":
767
- case "ML-DSA-87":
768
- algorithm = { name: jwk.alg };
769
- keyUsages = jwk.priv ? ["sign"] : ["verify"];
770
- break;
771
- default:
772
- throw new JOSENotSupported(unsupportedAlg);
773
- }
774
- break;
775
- }
776
- case "RSA": {
777
- switch (jwk.alg) {
778
- case "PS256":
779
- case "PS384":
780
- case "PS512":
781
- algorithm = { name: "RSA-PSS", hash: `SHA-${jwk.alg.slice(-3)}` };
782
- keyUsages = jwk.d ? ["sign"] : ["verify"];
783
- break;
784
- case "RS256":
785
- case "RS384":
786
- case "RS512":
787
- algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${jwk.alg.slice(-3)}` };
788
- keyUsages = jwk.d ? ["sign"] : ["verify"];
789
- break;
790
- case "RSA-OAEP":
791
- case "RSA-OAEP-256":
792
- case "RSA-OAEP-384":
793
- case "RSA-OAEP-512":
794
- algorithm = {
795
- name: "RSA-OAEP",
796
- hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`
797
- };
798
- keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
799
- break;
800
- default:
801
- throw new JOSENotSupported(unsupportedAlg);
802
- }
803
- break;
804
- }
805
- case "EC": {
806
- switch (jwk.alg) {
807
- case "ES256":
808
- case "ES384":
809
- case "ES512":
810
- algorithm = {
811
- name: "ECDSA",
812
- namedCurve: { ES256: "P-256", ES384: "P-384", ES512: "P-521" }[jwk.alg]
813
- };
814
- keyUsages = jwk.d ? ["sign"] : ["verify"];
815
- break;
816
- case "ECDH-ES":
817
- case "ECDH-ES+A128KW":
818
- case "ECDH-ES+A192KW":
819
- case "ECDH-ES+A256KW":
820
- algorithm = { name: "ECDH", namedCurve: jwk.crv };
821
- keyUsages = jwk.d ? ["deriveBits"] : [];
822
- break;
823
- default:
824
- throw new JOSENotSupported(unsupportedAlg);
825
- }
826
- break;
827
- }
828
- case "OKP": {
829
- switch (jwk.alg) {
830
- case "Ed25519":
831
- case "EdDSA":
832
- algorithm = { name: "Ed25519" };
833
- keyUsages = jwk.d ? ["sign"] : ["verify"];
834
- break;
835
- case "ECDH-ES":
836
- case "ECDH-ES+A128KW":
837
- case "ECDH-ES+A192KW":
838
- case "ECDH-ES+A256KW":
839
- algorithm = { name: jwk.crv };
840
- keyUsages = jwk.d ? ["deriveBits"] : [];
841
- break;
842
- default:
843
- throw new JOSENotSupported(unsupportedAlg);
844
- }
845
- break;
846
- }
847
- default:
848
- throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
849
- }
850
- return { algorithm, keyUsages };
741
+ // node_modules/jose/dist/webapi/lib/key.js
742
+ function snapshotJwk(jwk) {
743
+ return { __proto__: null, ...jwk };
851
744
  }
852
- async function jwkToKey(jwk) {
853
- if (!jwk.alg) {
854
- throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
855
- }
856
- const { algorithm, keyUsages } = subtleMapping(jwk);
857
- const keyData = { ...jwk };
858
- if (keyData.kty !== "AKP") {
859
- delete keyData.alg;
860
- }
861
- delete keyData.use;
862
- return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);
745
+ function normalizeJwk(jwk) {
746
+ const normalized = snapshotJwk(jwk);
747
+ if (normalized.ext !== void 0 && typeof normalized.ext != "boolean")
748
+ throw new TypeError('"ext" (Extractable) Parameter must be a boolean');
749
+ if (normalized.key_ops !== void 0) {
750
+ const value = normalized.key_ops, keyOps = Array.isArray(value) ? [...value] : void 0;
751
+ if (!keyOps || keyOps.some((operation) => typeof operation != "string") || new Set(keyOps).size !== keyOps.length)
752
+ throw new TypeError('"key_ops" (Key Operations) Parameter must be an array of unique strings');
753
+ normalized.key_ops = keyOps;
754
+ }
755
+ return normalized;
756
+ }
757
+ async function jwkToKey(entry, jwk, extractable) {
758
+ if (!entry.kty.includes(jwk.kty))
759
+ throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
760
+ const algorithm = entry.resolve?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle, isPrivate = !!(jwk.d || jwk.priv), keyData = { ...jwk, ext: jwk.ext };
761
+ return keyData.kty !== "AKP" && delete keyData.alg, delete keyData.use, crypto.subtle.importKey("jwk", keyData, algorithm, keyData.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);
762
+ }
763
+
764
+ // node_modules/jose/dist/webapi/lib/key_descriptor.js
765
+ function table(entries) {
766
+ const out = { __proto__: null };
767
+ for (const alg in entries)
768
+ out[alg] = { ...entries[alg], alg };
769
+ return out;
770
+ }
771
+
772
+ // node_modules/jose/dist/webapi/lib/jwe_algorithms.js
773
+ var wrap = [
774
+ ["encrypt", "wrapKey"],
775
+ ["decrypt", "unwrapKey"]
776
+ ];
777
+ var derive = [[], ["deriveBits"]];
778
+ var none = [[], []];
779
+ function rsaes(bits) {
780
+ return {
781
+ kty: ["RSA"],
782
+ mode: "key-encryption",
783
+ subtle: { name: "RSA-OAEP", hash: `SHA-${bits}` },
784
+ usages: wrap,
785
+ ops: ["wrapKey", "unwrapKey"]
786
+ };
787
+ }
788
+ function ecdh(mode) {
789
+ return {
790
+ kty: ["EC", "OKP"],
791
+ mode,
792
+ subtle: { name: "ECDH" },
793
+ resolve: ({ kty, crv, asymmetricKeyType }) => {
794
+ if (crv === "X25519" || asymmetricKeyType === "x25519")
795
+ return { name: "X25519" };
796
+ if (kty === "OKP")
797
+ throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
798
+ return { name: "ECDH", namedCurve: crv };
799
+ },
800
+ usages: derive,
801
+ ops: [void 0, "deriveBits"]
802
+ };
803
+ }
804
+ function aeskw(bits, gcm = false) {
805
+ return {
806
+ kty: ["oct"],
807
+ mode: "key-wrapping",
808
+ secret: true,
809
+ subtle: { name: gcm ? "AES-GCM" : "AES-KW", length: bits },
810
+ usages: none,
811
+ ops: gcm ? ["encrypt", "decrypt"] : ["wrapKey", "unwrapKey"]
812
+ };
813
+ }
814
+ function pbes2() {
815
+ return {
816
+ kty: ["oct"],
817
+ mode: "key-wrapping",
818
+ secret: true,
819
+ subtle: { name: "PBKDF2" },
820
+ usages: none,
821
+ ops: ["deriveBits", "deriveBits"]
822
+ };
823
+ }
824
+ var JWE = table({
825
+ dir: {
826
+ kty: ["oct"],
827
+ mode: "direct-encryption",
828
+ secret: true,
829
+ subtle: { name: "AES-GCM" },
830
+ usages: none,
831
+ ops: ["encrypt", "decrypt"]
832
+ },
833
+ "RSA-OAEP": rsaes(1),
834
+ "RSA-OAEP-256": rsaes(256),
835
+ "RSA-OAEP-384": rsaes(384),
836
+ "RSA-OAEP-512": rsaes(512),
837
+ "ECDH-ES": ecdh("direct-key-agreement"),
838
+ "ECDH-ES+A128KW": ecdh("key-agreement-with-key-wrapping"),
839
+ "ECDH-ES+A192KW": ecdh("key-agreement-with-key-wrapping"),
840
+ "ECDH-ES+A256KW": ecdh("key-agreement-with-key-wrapping"),
841
+ A128KW: aeskw(128),
842
+ A192KW: aeskw(192),
843
+ A256KW: aeskw(256),
844
+ A128GCMKW: aeskw(128, true),
845
+ A192GCMKW: aeskw(192, true),
846
+ A256GCMKW: aeskw(256, true),
847
+ "PBES2-HS256+A128KW": pbes2(),
848
+ "PBES2-HS384+A192KW": pbes2(),
849
+ "PBES2-HS512+A256KW": pbes2()
850
+ });
851
+ var contentOps = ["encrypt", "decrypt"];
852
+ function contentEncryption(bits, cbc = false) {
853
+ return {
854
+ kty: ["oct"],
855
+ secret: true,
856
+ subtle: { name: cbc ? "AES-CBC" : "AES-GCM", length: bits },
857
+ usages: none,
858
+ ops: contentOps,
859
+ cekBits: bits,
860
+ ivBits: cbc ? 128 : 96,
861
+ cbc
862
+ };
863
+ }
864
+ table({
865
+ A128GCM: contentEncryption(128),
866
+ A192GCM: contentEncryption(192),
867
+ A256GCM: contentEncryption(256),
868
+ "A128CBC-HS256": contentEncryption(256, true),
869
+ "A192CBC-HS384": contentEncryption(384, true),
870
+ "A256CBC-HS512": contentEncryption(512, true)
871
+ });
872
+
873
+ // node_modules/jose/dist/webapi/lib/jws_algorithms.js
874
+ var sig = [["verify"], ["sign"]];
875
+ function hmac(bits) {
876
+ const subtle = { name: "HMAC", hash: `SHA-${bits}` };
877
+ return { kty: ["oct"], secret: true, subtle, signing: subtle, usages: sig };
878
+ }
879
+ function rsa(bits, saltLength) {
880
+ const subtle = { name: saltLength ? "RSA-PSS" : "RSASSA-PKCS1-v1_5", hash: `SHA-${bits}` };
881
+ return {
882
+ kty: ["RSA"],
883
+ subtle,
884
+ signing: saltLength ? { ...subtle, saltLength } : subtle,
885
+ usages: sig,
886
+ minRsaBits: 2048
887
+ };
888
+ }
889
+ function ecdsa(crv, bits) {
890
+ return {
891
+ kty: ["EC"],
892
+ crv,
893
+ subtle: { name: "ECDSA", namedCurve: crv },
894
+ signing: { name: "ECDSA", hash: `SHA-${bits}` },
895
+ usages: sig
896
+ };
897
+ }
898
+ function eddsa() {
899
+ const subtle = { name: "Ed25519" };
900
+ return {
901
+ kty: ["OKP"],
902
+ crv: "Ed25519",
903
+ subtle,
904
+ signing: subtle,
905
+ usages: sig
906
+ };
907
+ }
908
+ function mldsa(parameterSet) {
909
+ const subtle = { name: `ML-DSA-${parameterSet}` };
910
+ return {
911
+ kty: ["AKP"],
912
+ subtle,
913
+ signing: subtle,
914
+ usages: sig
915
+ };
916
+ }
917
+ var JWS = table({
918
+ HS256: hmac(256),
919
+ HS384: hmac(384),
920
+ HS512: hmac(512),
921
+ RS256: rsa(256),
922
+ RS384: rsa(384),
923
+ RS512: rsa(512),
924
+ PS256: rsa(256, 32),
925
+ PS384: rsa(384, 48),
926
+ PS512: rsa(512, 64),
927
+ ES256: ecdsa("P-256", 256),
928
+ ES384: ecdsa("P-384", 384),
929
+ ES512: ecdsa("P-521", 512),
930
+ EdDSA: eddsa(),
931
+ Ed25519: eddsa(),
932
+ "ML-DSA-44": mldsa(44),
933
+ "ML-DSA-65": mldsa(65),
934
+ "ML-DSA-87": mldsa(87)
935
+ });
936
+
937
+ // node_modules/jose/dist/webapi/lib/key_algorithm.js
938
+ function unsupportedAlg(source = 'JWK "alg" (Algorithm) Parameter') {
939
+ throw new JOSENotSupported(`Invalid or unsupported ${source} value`);
940
+ }
941
+ function keyAlgorithm(alg, source) {
942
+ return (typeof alg == "string" ? JWS[alg] ?? JWE[alg] : void 0) ?? unsupportedAlg(source);
863
943
  }
864
944
 
865
945
  // node_modules/jose/dist/webapi/key/import.js
866
946
  async function importJWK(jwk, alg, options) {
867
- if (!isObject(jwk)) {
947
+ if (!isObject(jwk))
868
948
  throw new TypeError("JWK must be an object");
869
- }
870
- let ext;
871
- ext ?? (ext = jwk.ext);
872
- switch (jwk.kty) {
949
+ const normalized = normalizeJwk(jwk), { alg: jwkAlg } = normalized;
950
+ if (normalized.kty !== "oct" && !alg)
951
+ ;
952
+ switch (normalized.kty) {
873
953
  case "oct":
874
- if (typeof jwk.k !== "string" || !jwk.k) {
954
+ if (typeof normalized.k != "string")
875
955
  throw new TypeError('missing "k" (Key Value) Parameter value');
876
- }
877
- return decode(jwk.k);
878
- case "RSA":
879
- if ("oth" in jwk && jwk.oth !== void 0) {
880
- throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
881
- }
882
- return jwkToKey({ ...jwk, alg, ext });
956
+ return decode(normalized.k);
883
957
  case "AKP": {
884
- if (typeof jwk.alg !== "string" || !jwk.alg) {
958
+ if (typeof jwkAlg != "string" || !jwkAlg)
885
959
  throw new TypeError('missing "alg" (Algorithm) Parameter value');
886
- }
887
- if (alg !== jwk.alg) {
960
+ if (alg !== jwkAlg)
888
961
  throw new TypeError("JWK alg and alg option value mismatch");
889
- }
890
- return jwkToKey({ ...jwk, ext });
962
+ return jwkToKey(keyAlgorithm(alg), normalized);
891
963
  }
964
+ case "RSA":
892
965
  case "EC":
893
966
  case "OKP":
894
- return jwkToKey({ ...jwk, alg, ext });
967
+ return jwkToKey(keyAlgorithm(alg), normalized);
895
968
  default:
896
969
  throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
897
970
  }
@@ -901,9 +974,12 @@ async function importJWK(jwk, alg, options) {
901
974
  var DEFAULT_ISSUER = "https://me.ochk.io";
902
975
  var JWKS_PATH = "/api/dev-jwks";
903
976
  var DEFAULT_TTL_MS = 60 * 60 * 1e3;
977
+ var DEFAULT_MAX_STALE_MS = 6 * 60 * 60 * 1e3;
978
+ var FORCED_REFRESH_MIN_INTERVAL_MS = 6e4;
904
979
  var jwksCache = /* @__PURE__ */ new Map();
905
980
  var inflight = /* @__PURE__ */ new Map();
906
- async function fetchJwks(issuer, ttlMs) {
981
+ var lastForcedRefresh = /* @__PURE__ */ new Map();
982
+ async function fetchJwks(issuer, ttlMs, maxStaleMs = DEFAULT_MAX_STALE_MS) {
907
983
  const cached = jwksCache.get(issuer);
908
984
  if (cached && Date.now() - cached.fetchedAt < ttlMs) return cached;
909
985
  const existing = inflight.get(issuer);
@@ -930,7 +1006,7 @@ async function fetchJwks(issuer, ttlMs) {
930
1006
  return entry;
931
1007
  } catch (err) {
932
1008
  const stale = jwksCache.get(issuer);
933
- if (stale) return stale;
1009
+ if (stale && Date.now() - stale.fetchedAt < maxStaleMs) return stale;
934
1010
  throw err;
935
1011
  }
936
1012
  })().finally(() => {
@@ -960,14 +1036,14 @@ function toArrayBuffer(view) {
960
1036
  new Uint8Array(buf).set(view);
961
1037
  return buf;
962
1038
  }
963
- async function verifyEd25519(key, sig, msg) {
1039
+ async function verifyEd25519(key, sig2, msg) {
964
1040
  const subtle = typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle ? globalThis.crypto.subtle : null;
965
1041
  if (!subtle) return false;
966
1042
  try {
967
1043
  return await subtle.verify(
968
1044
  "Ed25519",
969
1045
  key,
970
- toArrayBuffer(sig),
1046
+ toArrayBuffer(sig2),
971
1047
  toArrayBuffer(msg)
972
1048
  );
973
1049
  } catch {
@@ -977,8 +1053,8 @@ async function verifyEd25519(key, sig, msg) {
977
1053
  async function verify2(rawBody, sigHex, kid, options = {}) {
978
1054
  if (!sigHex) return { ok: false, reason: "missing signature" };
979
1055
  if (!kid) return { ok: false, reason: "missing kid" };
980
- const sig = hexToBytes(sigHex);
981
- if (!sig) return { ok: false, reason: "malformed signature (expected hex)" };
1056
+ const sig2 = hexToBytes(sigHex);
1057
+ if (!sig2) return { ok: false, reason: "malformed signature (expected hex)" };
982
1058
  const msg = toBytes(rawBody);
983
1059
  let key;
984
1060
  if (options.jwk) {
@@ -993,12 +1069,13 @@ async function verify2(rawBody, sigHex, kid, options = {}) {
993
1069
  } else {
994
1070
  const issuer = options.issuer ?? DEFAULT_ISSUER;
995
1071
  const ttl = options.jwksCacheTtlMs ?? DEFAULT_TTL_MS;
1072
+ const maxStale = options.jwksMaxStaleMs ?? DEFAULT_MAX_STALE_MS;
996
1073
  try {
997
- let entry = await fetchJwks(issuer, ttl);
1074
+ let entry = await fetchJwks(issuer, ttl, maxStale);
998
1075
  key = entry.keys[kid];
999
- if (!key) {
1000
- jwksCache.delete(issuer);
1001
- entry = await fetchJwks(issuer, ttl);
1076
+ if (!key && Date.now() - (lastForcedRefresh.get(issuer) ?? 0) >= FORCED_REFRESH_MIN_INTERVAL_MS) {
1077
+ lastForcedRefresh.set(issuer, Date.now());
1078
+ entry = await fetchJwks(issuer, 0, maxStale);
1002
1079
  key = entry.keys[kid];
1003
1080
  }
1004
1081
  } catch (err) {
@@ -1006,7 +1083,7 @@ async function verify2(rawBody, sigHex, kid, options = {}) {
1006
1083
  }
1007
1084
  if (!key) return { ok: false, reason: `kid ${kid} not in JWKS` };
1008
1085
  }
1009
- const ok = await verifyEd25519(key, sig, msg);
1086
+ const ok = await verifyEd25519(key, sig2, msg);
1010
1087
  return ok ? { ok: true } : { ok: false, reason: "signature does not match" };
1011
1088
  }
1012
1089
  async function fetchJwksForce(issuer = DEFAULT_ISSUER) {
@@ -1140,10 +1217,13 @@ var family = { scopes };
1140
1217
  // src/identity.ts
1141
1218
  var DEFAULT_ISSUER2 = "https://me.ochk.io";
1142
1219
  var DEFAULT_TTL_MS2 = 60 * 60 * 1e3;
1220
+ var DEFAULT_MAX_STALE_MS2 = 6 * 60 * 60 * 1e3;
1221
+ var FORCED_REFRESH_MIN_INTERVAL_MS2 = 6e4;
1143
1222
  var ENVELOPE_JWKS_PATH = "/.well-known/oc-envelope-jwks.json";
1144
1223
  var jwksCache2 = /* @__PURE__ */ new Map();
1145
1224
  var inflight2 = /* @__PURE__ */ new Map();
1146
- async function fetchEnvelopeJwks(issuer, ttlMs) {
1225
+ var lastForcedRefresh2 = /* @__PURE__ */ new Map();
1226
+ async function fetchEnvelopeJwks(issuer, ttlMs, maxStaleMs = DEFAULT_MAX_STALE_MS2) {
1147
1227
  const cached = jwksCache2.get(issuer);
1148
1228
  if (cached && Date.now() - cached.fetchedAt < ttlMs) return cached;
1149
1229
  const existing = inflight2.get(issuer);
@@ -1170,7 +1250,7 @@ async function fetchEnvelopeJwks(issuer, ttlMs) {
1170
1250
  return entry;
1171
1251
  } catch (err) {
1172
1252
  const stale = jwksCache2.get(issuer);
1173
- if (stale) return stale;
1253
+ if (stale && Date.now() - stale.fetchedAt < maxStaleMs) return stale;
1174
1254
  throw err;
1175
1255
  }
1176
1256
  })().finally(() => {
@@ -1219,14 +1299,14 @@ function toArrayBuffer2(view) {
1219
1299
  new Uint8Array(buf).set(view);
1220
1300
  return buf;
1221
1301
  }
1222
- async function verifyEd255192(key, sig, msg) {
1302
+ async function verifyEd255192(key, sig2, msg) {
1223
1303
  const subtle = typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle ? globalThis.crypto.subtle : null;
1224
1304
  if (!subtle) return false;
1225
1305
  try {
1226
1306
  return await subtle.verify(
1227
1307
  "Ed25519",
1228
1308
  key,
1229
- toArrayBuffer2(sig),
1309
+ toArrayBuffer2(sig2),
1230
1310
  toArrayBuffer2(msg)
1231
1311
  );
1232
1312
  } catch {
@@ -1336,12 +1416,13 @@ async function verifyActivityAttestation(bundle, options = {}) {
1336
1416
  } else {
1337
1417
  const issuer = options.issuer ?? DEFAULT_ISSUER2;
1338
1418
  const ttl = options.jwksCacheTtlMs ?? DEFAULT_TTL_MS2;
1419
+ const maxStale = options.jwksMaxStaleMs ?? DEFAULT_MAX_STALE_MS2;
1339
1420
  try {
1340
- let entry = await fetchEnvelopeJwks(issuer, ttl);
1421
+ let entry = await fetchEnvelopeJwks(issuer, ttl, maxStale);
1341
1422
  key = entry.keys[bundle.kid] ?? null;
1342
- if (!key) {
1343
- jwksCache2.delete(issuer);
1344
- entry = await fetchEnvelopeJwks(issuer, ttl);
1423
+ if (!key && Date.now() - (lastForcedRefresh2.get(issuer) ?? 0) >= FORCED_REFRESH_MIN_INTERVAL_MS2) {
1424
+ lastForcedRefresh2.set(issuer, Date.now());
1425
+ entry = await fetchEnvelopeJwks(issuer, 0, maxStale);
1345
1426
  key = entry.keys[bundle.kid] ?? null;
1346
1427
  }
1347
1428
  checks.push({