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