@atproto/jwk 0.6.0 → 0.7.0-next.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/keyset.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
3
2
  var useValue = arguments.length > 2;
4
3
  for (var i = 0; i < initializers.length; i++) {
@@ -33,200 +32,185 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
33
32
  if (target) Object.defineProperty(target, contextIn.name, descriptor);
34
33
  done = true;
35
34
  };
36
- Object.defineProperty(exports, "__esModule", { value: true });
37
- exports.Keyset = void 0;
38
- const errors_js_1 = require("./errors.js");
39
- const jwt_decode_js_1 = require("./jwt-decode.js");
40
- const util_js_1 = require("./util.js");
35
+ import { ERR_JWKS_NO_MATCHING_KEY, ERR_JWK_NOT_FOUND, ERR_JWT_INVALID, JwkError, JwtCreateError, JwtVerifyError, } from './errors.js';
36
+ import { unsafeDecodeJwt } from './jwt-decode.js';
37
+ import { cachedGetter, isDefined, matchesAny, preferredOrderCmp, } from './util.js';
41
38
  const extractPrivateJwk = (key) => key.privateJwk;
42
39
  const extractPublicJwk = (key) => key.publicJwk;
43
40
  let Keyset = (() => {
44
- var _a;
45
41
  let _instanceExtraInitializers = [];
46
42
  let _get_signAlgorithms_decorators;
47
43
  let _get_publicJwks_decorators;
48
44
  let _get_privateJwks_decorators;
49
- return _a = class Keyset {
50
- constructor(iterable,
51
- /**
52
- * The preferred algorithms to use when signing a JWT using this keyset.
53
- *
54
- * @see {@link https://datatracker.ietf.org/doc/html/rfc7518#section-3.1}
55
- */
56
- preferredSigningAlgorithms = iterable instanceof
57
- _a
58
- ? [...iterable.preferredSigningAlgorithms]
59
- : [
60
- // Prefer elliptic curve algorithms
61
- 'EdDSA',
62
- 'ES256K',
63
- 'ES256',
64
- // https://datatracker.ietf.org/doc/html/rfc7518#section-3.5
65
- 'PS256',
66
- 'PS384',
67
- 'PS512',
68
- 'HS256',
69
- 'HS384',
70
- 'HS512',
71
- ]) {
72
- Object.defineProperty(this, "preferredSigningAlgorithms", {
73
- enumerable: true,
74
- configurable: true,
75
- writable: true,
76
- value: (__runInitializers(this, _instanceExtraInitializers), preferredSigningAlgorithms)
77
- });
78
- Object.defineProperty(this, "keys", {
79
- enumerable: true,
80
- configurable: true,
81
- writable: true,
82
- value: void 0
83
- });
84
- const keys = [];
85
- const keyIds = new Set();
86
- for (const key of iterable) {
87
- if (!key)
88
- continue;
89
- keys.push(key);
90
- if (key.kid) {
91
- if (keyIds.has(key.kid))
92
- throw new errors_js_1.JwkError(`Duplicate key: ${key.kid}`);
93
- else
94
- keyIds.add(key.kid);
95
- }
45
+ return class Keyset {
46
+ static {
47
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
48
+ __esDecorate(this, null, _get_signAlgorithms_decorators, { kind: "getter", name: "signAlgorithms", static: false, private: false, access: { has: obj => "signAlgorithms" in obj, get: obj => obj.signAlgorithms }, metadata: _metadata }, null, _instanceExtraInitializers);
49
+ __esDecorate(this, null, _get_publicJwks_decorators, { kind: "getter", name: "publicJwks", static: false, private: false, access: { has: obj => "publicJwks" in obj, get: obj => obj.publicJwks }, metadata: _metadata }, null, _instanceExtraInitializers);
50
+ __esDecorate(this, null, _get_privateJwks_decorators, { kind: "getter", name: "privateJwks", static: false, private: false, access: { has: obj => "privateJwks" in obj, get: obj => obj.privateJwks }, metadata: _metadata }, null, _instanceExtraInitializers);
51
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
52
+ }
53
+ constructor(iterable,
54
+ /**
55
+ * The preferred algorithms to use when signing a JWT using this keyset.
56
+ *
57
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc7518#section-3.1}
58
+ */
59
+ preferredSigningAlgorithms = iterable instanceof
60
+ Keyset
61
+ ? [...iterable.preferredSigningAlgorithms]
62
+ : [
63
+ // Prefer elliptic curve algorithms
64
+ 'EdDSA',
65
+ 'ES256K',
66
+ 'ES256',
67
+ // https://datatracker.ietf.org/doc/html/rfc7518#section-3.5
68
+ 'PS256',
69
+ 'PS384',
70
+ 'PS512',
71
+ 'HS256',
72
+ 'HS384',
73
+ 'HS512',
74
+ ]) {
75
+ this.preferredSigningAlgorithms = (__runInitializers(this, _instanceExtraInitializers), preferredSigningAlgorithms);
76
+ const keys = [];
77
+ const keyIds = new Set();
78
+ for (const key of iterable) {
79
+ if (!key)
80
+ continue;
81
+ keys.push(key);
82
+ if (key.kid) {
83
+ if (keyIds.has(key.kid))
84
+ throw new JwkError(`Duplicate key: ${key.kid}`);
85
+ else
86
+ keyIds.add(key.kid);
96
87
  }
97
- this.keys = Object.freeze(keys);
98
- }
99
- get size() {
100
- return this.keys.length;
101
88
  }
102
- get signAlgorithms() {
103
- const algorithms = new Set();
104
- for (const key of this) {
105
- if (key.use !== 'sig')
106
- continue;
107
- for (const alg of key.algorithms) {
108
- algorithms.add(alg);
109
- }
89
+ this.keys = Object.freeze(keys);
90
+ }
91
+ get size() {
92
+ return this.keys.length;
93
+ }
94
+ get signAlgorithms() {
95
+ const algorithms = new Set();
96
+ for (const key of this) {
97
+ if (key.use !== 'sig')
98
+ continue;
99
+ for (const alg of key.algorithms) {
100
+ algorithms.add(alg);
110
101
  }
111
- return Object.freeze([...algorithms].sort((0, util_js_1.preferredOrderCmp)(this.preferredSigningAlgorithms)));
112
- }
113
- get publicJwks() {
114
- return Object.freeze({
115
- keys: Object.freeze(Array.from(this, extractPublicJwk).filter(util_js_1.isDefined)),
116
- });
117
102
  }
118
- get privateJwks() {
119
- return Object.freeze({
120
- keys: Object.freeze(Array.from(this, extractPrivateJwk).filter(util_js_1.isDefined)),
121
- });
122
- }
123
- has(kid) {
124
- return this.keys.some((key) => key.kid === kid);
125
- }
126
- get(options) {
127
- const key = this.find(options);
128
- if (key)
129
- return key;
130
- throw new errors_js_1.JwkError(`Key not found ${options.kid ?? options.alg ?? options.usage ?? '<unknown>'}`, errors_js_1.ERR_JWK_NOT_FOUND);
103
+ return Object.freeze([...algorithms].sort(preferredOrderCmp(this.preferredSigningAlgorithms)));
104
+ }
105
+ get publicJwks() {
106
+ return Object.freeze({
107
+ keys: Object.freeze(Array.from(this, extractPublicJwk).filter(isDefined)),
108
+ });
109
+ }
110
+ get privateJwks() {
111
+ return Object.freeze({
112
+ keys: Object.freeze(Array.from(this, extractPrivateJwk).filter(isDefined)),
113
+ });
114
+ }
115
+ has(kid) {
116
+ return this.keys.some((key) => key.kid === kid);
117
+ }
118
+ get(options) {
119
+ const key = this.find(options);
120
+ if (key)
121
+ return key;
122
+ throw new JwkError(`Key not found ${options.kid ?? options.alg ?? options.usage ?? '<unknown>'}`, ERR_JWK_NOT_FOUND);
123
+ }
124
+ find(options) {
125
+ for (const key of this.list(options)) {
126
+ return key;
131
127
  }
132
- find(options) {
133
- for (const key of this.list(options)) {
134
- return key;
128
+ return undefined;
129
+ }
130
+ *list(options) {
131
+ for (const key of this) {
132
+ if (key.isActive(options) && key.matches(options)) {
133
+ yield key;
135
134
  }
136
- return undefined;
137
135
  }
138
- *list(options) {
139
- for (const key of this) {
140
- if (key.isActive(options) && key.matches(options)) {
141
- yield key;
136
+ }
137
+ findPrivateKey({ kid, alg, usage, ...options }) {
138
+ const matchingKeys = [];
139
+ // Allow the loop bellow to return early when a single "alg" is provided
140
+ if (Array.isArray(alg) && alg.length === 1)
141
+ alg = alg[0];
142
+ for (const key of this.list({ ...options, kid, alg, usage })) {
143
+ // Skip negotiation if a single "alg" was provided
144
+ if (typeof alg === 'string')
145
+ return { key, alg };
146
+ matchingKeys.push(key);
147
+ }
148
+ const isAllowedAlg = matchesAny(alg);
149
+ const candidates = matchingKeys.map((key) => [key, key.algorithms.filter(isAllowedAlg)]);
150
+ // Return the first candidates that matches the preferred algorithms
151
+ for (const prefAlg of this.preferredSigningAlgorithms) {
152
+ for (const [matchingKey, matchingAlgs] of candidates) {
153
+ if (matchingAlgs.includes(prefAlg)) {
154
+ return { key: matchingKey, alg: prefAlg };
142
155
  }
143
156
  }
144
157
  }
145
- findPrivateKey({ kid, alg, usage, ...options }) {
146
- const matchingKeys = [];
147
- // Allow the loop bellow to return early when a single "alg" is provided
148
- if (Array.isArray(alg) && alg.length === 1)
149
- alg = alg[0];
150
- for (const key of this.list({ ...options, kid, alg, usage })) {
151
- // Skip negotiation if a single "alg" was provided
152
- if (typeof alg === 'string')
153
- return { key, alg };
154
- matchingKeys.push(key);
158
+ // Return any candidate
159
+ for (const [matchingKey, matchingAlgs] of candidates) {
160
+ for (const alg of matchingAlgs) {
161
+ return { key: matchingKey, alg };
155
162
  }
156
- const isAllowedAlg = (0, util_js_1.matchesAny)(alg);
157
- const candidates = matchingKeys.map((key) => [key, key.algorithms.filter(isAllowedAlg)]);
158
- // Return the first candidates that matches the preferred algorithms
159
- for (const prefAlg of this.preferredSigningAlgorithms) {
160
- for (const [matchingKey, matchingAlgs] of candidates) {
161
- if (matchingAlgs.includes(prefAlg)) {
162
- return { key: matchingKey, alg: prefAlg };
163
- }
164
- }
165
- }
166
- // Return any candidate
167
- for (const [matchingKey, matchingAlgs] of candidates) {
168
- for (const alg of matchingAlgs) {
169
- return { key: matchingKey, alg };
170
- }
163
+ }
164
+ throw new JwkError(`No private key found for ${kid || alg || usage}`, ERR_JWK_NOT_FOUND);
165
+ }
166
+ [(_get_signAlgorithms_decorators = [cachedGetter], _get_publicJwks_decorators = [cachedGetter], _get_privateJwks_decorators = [cachedGetter], Symbol.iterator)]() {
167
+ return this.keys.values();
168
+ }
169
+ async createJwt({ alg: sAlg, kid: sKid, ...header }, payload) {
170
+ try {
171
+ const { key, alg } = this.findPrivateKey({
172
+ alg: sAlg,
173
+ kid: sKid,
174
+ usage: 'sign',
175
+ allowRevoked: false, // For explicitness (default value is false)
176
+ });
177
+ const protectedHeader = { ...header, alg, kid: key.kid };
178
+ if (typeof payload === 'function') {
179
+ payload = await payload(protectedHeader, key);
171
180
  }
172
- throw new errors_js_1.JwkError(`No private key found for ${kid || alg || usage}`, errors_js_1.ERR_JWK_NOT_FOUND);
181
+ return await key.createJwt(protectedHeader, payload);
173
182
  }
174
- [(_get_signAlgorithms_decorators = [util_js_1.cachedGetter], _get_publicJwks_decorators = [util_js_1.cachedGetter], _get_privateJwks_decorators = [util_js_1.cachedGetter], Symbol.iterator)]() {
175
- return this.keys.values();
183
+ catch (err) {
184
+ throw JwtCreateError.from(err);
176
185
  }
177
- async createJwt({ alg: sAlg, kid: sKid, ...header }, payload) {
186
+ }
187
+ async verifyJwt(token, options) {
188
+ const { header } = unsafeDecodeJwt(token);
189
+ const { kid, alg } = header;
190
+ const errors = [];
191
+ for (const key of this.list({ ...options, kid, alg, usage: 'verify' })) {
178
192
  try {
179
- const { key, alg } = this.findPrivateKey({
180
- alg: sAlg,
181
- kid: sKid,
182
- usage: 'sign',
183
- allowRevoked: false, // For explicitness (default value is false)
184
- });
185
- const protectedHeader = { ...header, alg, kid: key.kid };
186
- if (typeof payload === 'function') {
187
- payload = await payload(protectedHeader, key);
188
- }
189
- return await key.createJwt(protectedHeader, payload);
193
+ const result = await key.verifyJwt(token, options);
194
+ return { ...result, key };
190
195
  }
191
196
  catch (err) {
192
- throw errors_js_1.JwtCreateError.from(err);
193
- }
194
- }
195
- async verifyJwt(token, options) {
196
- const { header } = (0, jwt_decode_js_1.unsafeDecodeJwt)(token);
197
- const { kid, alg } = header;
198
- const errors = [];
199
- for (const key of this.list({ ...options, kid, alg, usage: 'verify' })) {
200
- try {
201
- const result = await key.verifyJwt(token, options);
202
- return { ...result, key };
203
- }
204
- catch (err) {
205
- errors.push(err);
206
- }
207
- }
208
- switch (errors.length) {
209
- case 0:
210
- throw new errors_js_1.JwtVerifyError('No key matched', errors_js_1.ERR_JWKS_NO_MATCHING_KEY);
211
- case 1:
212
- throw errors_js_1.JwtVerifyError.from(errors[0], errors_js_1.ERR_JWT_INVALID);
213
- default:
214
- throw errors_js_1.JwtVerifyError.from(errors, errors_js_1.ERR_JWT_INVALID);
197
+ errors.push(err);
215
198
  }
216
199
  }
217
- toJSON() {
218
- // Make a copy to allow mutation of the result
219
- return structuredClone(this.publicJwks);
200
+ switch (errors.length) {
201
+ case 0:
202
+ throw new JwtVerifyError('No key matched', ERR_JWKS_NO_MATCHING_KEY);
203
+ case 1:
204
+ throw JwtVerifyError.from(errors[0], ERR_JWT_INVALID);
205
+ default:
206
+ throw JwtVerifyError.from(errors, ERR_JWT_INVALID);
220
207
  }
221
- },
222
- (() => {
223
- const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
224
- __esDecorate(_a, null, _get_signAlgorithms_decorators, { kind: "getter", name: "signAlgorithms", static: false, private: false, access: { has: obj => "signAlgorithms" in obj, get: obj => obj.signAlgorithms }, metadata: _metadata }, null, _instanceExtraInitializers);
225
- __esDecorate(_a, null, _get_publicJwks_decorators, { kind: "getter", name: "publicJwks", static: false, private: false, access: { has: obj => "publicJwks" in obj, get: obj => obj.publicJwks }, metadata: _metadata }, null, _instanceExtraInitializers);
226
- __esDecorate(_a, null, _get_privateJwks_decorators, { kind: "getter", name: "privateJwks", static: false, private: false, access: { has: obj => "privateJwks" in obj, get: obj => obj.privateJwks }, metadata: _metadata }, null, _instanceExtraInitializers);
227
- if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
228
- })(),
229
- _a;
208
+ }
209
+ toJSON() {
210
+ // Make a copy to allow mutation of the result
211
+ return structuredClone(this.publicJwks);
212
+ }
213
+ };
230
214
  })();
231
- exports.Keyset = Keyset;
215
+ export { Keyset };
232
216
  //# sourceMappingURL=keyset.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keyset.js","sourceRoot":"","sources":["../src/keyset.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ERR_JWKS_NO_MATCHING_KEY,\n ERR_JWK_NOT_FOUND,\n ERR_JWT_INVALID,\n JwkError,\n JwtCreateError,\n JwtVerifyError,\n} from './errors.js'\nimport { PrivateKeyUsage } from './jwk.js'\nimport { JwksPub } from './jwks.js'\nimport { unsafeDecodeJwt } from './jwt-decode.js'\nimport { VerifyOptions, VerifyResult } from './jwt-verify.js'\nimport { JwtHeader, JwtPayload, SignedJwt } from './jwt.js'\nimport { ActivityCheckOptions, Key, KeyMatchOptions } from './key.js'\nimport {\n Override,\n cachedGetter,\n isDefined,\n matchesAny,\n preferredOrderCmp,\n} from './util.js'\n\nexport type { ActivityCheckOptions, KeyMatchOptions }\nexport type FindKeyOptions = KeyMatchOptions & ActivityCheckOptions\n\nexport type JwtSignHeader = Override<\n JwtHeader,\n Pick<FindKeyOptions, 'alg' | 'kid'>\n>\n\nexport type JwtPayloadGetter<P = JwtPayload> = (\n header: JwtHeader,\n key: Key,\n) => P | PromiseLike<P>\n\nconst extractPrivateJwk = (key: Key) => key.privateJwk\nconst extractPublicJwk = (key: Key) => key.publicJwk\n\nexport class Keyset<K extends Key = Key> implements Iterable<K> {\n private readonly keys: readonly K[]\n\n constructor(\n iterable: Iterable<K | null | undefined | false>,\n /**\n * The preferred algorithms to use when signing a JWT using this keyset.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc7518#section-3.1}\n */\n public readonly preferredSigningAlgorithms: readonly string[] = iterable instanceof\n Keyset\n ? [...iterable.preferredSigningAlgorithms]\n : [\n // Prefer elliptic curve algorithms\n 'EdDSA',\n 'ES256K',\n 'ES256',\n // https://datatracker.ietf.org/doc/html/rfc7518#section-3.5\n 'PS256',\n 'PS384',\n 'PS512',\n 'HS256',\n 'HS384',\n 'HS512',\n ],\n ) {\n const keys: K[] = []\n\n const keyIds = new Set<string>()\n for (const key of iterable) {\n if (!key) continue\n\n keys.push(key)\n\n if (key.kid) {\n if (keyIds.has(key.kid)) throw new JwkError(`Duplicate key: ${key.kid}`)\n else keyIds.add(key.kid)\n }\n }\n\n this.keys = Object.freeze(keys)\n }\n\n get size(): number {\n return this.keys.length\n }\n\n @cachedGetter\n get signAlgorithms(): readonly string[] {\n const algorithms = new Set<string>()\n for (const key of this) {\n if (key.use !== 'sig') continue\n for (const alg of key.algorithms) {\n algorithms.add(alg)\n }\n }\n return Object.freeze(\n [...algorithms].sort(preferredOrderCmp(this.preferredSigningAlgorithms)),\n )\n }\n\n @cachedGetter\n get publicJwks() {\n return Object.freeze({\n keys: Object.freeze(Array.from(this, extractPublicJwk).filter(isDefined)),\n })\n }\n\n @cachedGetter\n get privateJwks() {\n return Object.freeze({\n keys: Object.freeze(\n Array.from(this, extractPrivateJwk).filter(isDefined),\n ),\n })\n }\n\n has(kid: string): boolean {\n return this.keys.some((key) => key.kid === kid)\n }\n\n get(options: FindKeyOptions): K {\n const key = this.find(options)\n if (key) return key\n\n throw new JwkError(\n `Key not found ${options.kid ?? options.alg ?? options.usage ?? '<unknown>'}`,\n ERR_JWK_NOT_FOUND,\n )\n }\n\n find(options: FindKeyOptions): K | undefined {\n for (const key of this.list(options)) {\n return key\n }\n\n return undefined\n }\n\n *list<O extends FindKeyOptions>(options: O) {\n for (const key of this) {\n if (key.isActive(options) && key.matches(options)) {\n yield key\n }\n }\n }\n\n findPrivateKey({\n kid,\n alg,\n usage,\n ...options\n }: FindKeyOptions & { usage: PrivateKeyUsage }): {\n key: Key\n alg: string\n } {\n const matchingKeys: Key[] = []\n\n // Allow the loop bellow to return early when a single \"alg\" is provided\n if (Array.isArray(alg) && alg.length === 1) alg = alg[0]\n\n for (const key of this.list({ ...options, kid, alg, usage })) {\n // Skip negotiation if a single \"alg\" was provided\n if (typeof alg === 'string') return { key, alg }\n\n matchingKeys.push(key)\n }\n\n const isAllowedAlg = matchesAny(alg)\n const candidates = matchingKeys.map(\n (key) => [key, key.algorithms.filter(isAllowedAlg)] as const,\n )\n\n // Return the first candidates that matches the preferred algorithms\n for (const prefAlg of this.preferredSigningAlgorithms) {\n for (const [matchingKey, matchingAlgs] of candidates) {\n if (matchingAlgs.includes(prefAlg)) {\n return { key: matchingKey, alg: prefAlg }\n }\n }\n }\n\n // Return any candidate\n for (const [matchingKey, matchingAlgs] of candidates) {\n for (const alg of matchingAlgs) {\n return { key: matchingKey, alg }\n }\n }\n\n throw new JwkError(\n `No private key found for ${kid || alg || usage}`,\n ERR_JWK_NOT_FOUND,\n )\n }\n\n [Symbol.iterator](): IterableIterator<K> {\n return this.keys.values()\n }\n\n async createJwt(\n { alg: sAlg, kid: sKid, ...header }: JwtSignHeader,\n payload: JwtPayload | JwtPayloadGetter,\n ): Promise<SignedJwt> {\n try {\n const { key, alg } = this.findPrivateKey({\n alg: sAlg,\n kid: sKid,\n usage: 'sign',\n allowRevoked: false, // For explicitness (default value is false)\n })\n const protectedHeader = { ...header, alg, kid: key.kid }\n\n if (typeof payload === 'function') {\n payload = await payload(protectedHeader, key)\n }\n\n return await key.createJwt(protectedHeader, payload)\n } catch (err) {\n throw JwtCreateError.from(err)\n }\n }\n\n async verifyJwt<C extends string = never>(\n token: SignedJwt,\n options?: ActivityCheckOptions & VerifyOptions<C>,\n ): Promise<VerifyResult<C> & { key: K }> {\n const { header } = unsafeDecodeJwt(token)\n const { kid, alg } = header\n\n const errors: unknown[] = []\n\n for (const key of this.list({ ...options, kid, alg, usage: 'verify' })) {\n try {\n const result = await key.verifyJwt<C>(token, options)\n return { ...result, key }\n } catch (err) {\n errors.push(err)\n }\n }\n\n switch (errors.length) {\n case 0:\n throw new JwtVerifyError('No key matched', ERR_JWKS_NO_MATCHING_KEY)\n case 1:\n throw JwtVerifyError.from(errors[0], ERR_JWT_INVALID)\n default:\n throw JwtVerifyError.from(errors, ERR_JWT_INVALID)\n }\n }\n\n toJSON() {\n // Make a copy to allow mutation of the result\n return structuredClone(this.publicJwks) as JwksPub\n }\n}\n"]}
1
+ {"version":3,"file":"keyset.js","sourceRoot":"","sources":["../src/keyset.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ERR_JWKS_NO_MATCHING_KEY,\n ERR_JWK_NOT_FOUND,\n ERR_JWT_INVALID,\n JwkError,\n JwtCreateError,\n JwtVerifyError,\n} from './errors.js'\nimport { PrivateKeyUsage } from './jwk.js'\nimport { JwksPub } from './jwks.js'\nimport { unsafeDecodeJwt } from './jwt-decode.js'\nimport { VerifyOptions, VerifyResult } from './jwt-verify.js'\nimport { JwtHeader, JwtPayload, SignedJwt } from './jwt.js'\nimport { ActivityCheckOptions, Key, KeyMatchOptions } from './key.js'\nimport {\n Override,\n cachedGetter,\n isDefined,\n matchesAny,\n preferredOrderCmp,\n} from './util.js'\n\nexport type { ActivityCheckOptions, KeyMatchOptions }\nexport type FindKeyOptions = KeyMatchOptions & ActivityCheckOptions\n\nexport type JwtSignHeader = Override<\n JwtHeader,\n Pick<FindKeyOptions, 'alg' | 'kid'>\n>\n\nexport type JwtPayloadGetter<P = JwtPayload> = (\n header: JwtHeader,\n key: Key,\n) => P | PromiseLike<P>\n\nconst extractPrivateJwk = (key: Key) => key.privateJwk\nconst extractPublicJwk = (key: Key) => key.publicJwk\n\nexport class Keyset<K extends Key = Key> implements Iterable<K> {\n private readonly keys: readonly K[]\n\n constructor(\n iterable: Iterable<K | null | undefined | false>,\n /**\n * The preferred algorithms to use when signing a JWT using this keyset.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc7518#section-3.1}\n */\n public readonly preferredSigningAlgorithms: readonly string[] = iterable instanceof\n Keyset\n ? [...iterable.preferredSigningAlgorithms]\n : [\n // Prefer elliptic curve algorithms\n 'EdDSA',\n 'ES256K',\n 'ES256',\n // https://datatracker.ietf.org/doc/html/rfc7518#section-3.5\n 'PS256',\n 'PS384',\n 'PS512',\n 'HS256',\n 'HS384',\n 'HS512',\n ],\n ) {\n const keys: K[] = []\n\n const keyIds = new Set<string>()\n for (const key of iterable) {\n if (!key) continue\n\n keys.push(key)\n\n if (key.kid) {\n if (keyIds.has(key.kid)) throw new JwkError(`Duplicate key: ${key.kid}`)\n else keyIds.add(key.kid)\n }\n }\n\n this.keys = Object.freeze(keys)\n }\n\n get size(): number {\n return this.keys.length\n }\n\n @cachedGetter\n get signAlgorithms(): readonly string[] {\n const algorithms = new Set<string>()\n for (const key of this) {\n if (key.use !== 'sig') continue\n for (const alg of key.algorithms) {\n algorithms.add(alg)\n }\n }\n return Object.freeze(\n [...algorithms].sort(preferredOrderCmp(this.preferredSigningAlgorithms)),\n )\n }\n\n @cachedGetter\n get publicJwks() {\n return Object.freeze({\n keys: Object.freeze(Array.from(this, extractPublicJwk).filter(isDefined)),\n })\n }\n\n @cachedGetter\n get privateJwks() {\n return Object.freeze({\n keys: Object.freeze(\n Array.from(this, extractPrivateJwk).filter(isDefined),\n ),\n })\n }\n\n has(kid: string): boolean {\n return this.keys.some((key) => key.kid === kid)\n }\n\n get(options: FindKeyOptions): K {\n const key = this.find(options)\n if (key) return key\n\n throw new JwkError(\n `Key not found ${options.kid ?? options.alg ?? options.usage ?? '<unknown>'}`,\n ERR_JWK_NOT_FOUND,\n )\n }\n\n find(options: FindKeyOptions): K | undefined {\n for (const key of this.list(options)) {\n return key\n }\n\n return undefined\n }\n\n *list<O extends FindKeyOptions>(options: O) {\n for (const key of this) {\n if (key.isActive(options) && key.matches(options)) {\n yield key\n }\n }\n }\n\n findPrivateKey({\n kid,\n alg,\n usage,\n ...options\n }: FindKeyOptions & { usage: PrivateKeyUsage }): {\n key: Key\n alg: string\n } {\n const matchingKeys: Key[] = []\n\n // Allow the loop bellow to return early when a single \"alg\" is provided\n if (Array.isArray(alg) && alg.length === 1) alg = alg[0]\n\n for (const key of this.list({ ...options, kid, alg, usage })) {\n // Skip negotiation if a single \"alg\" was provided\n if (typeof alg === 'string') return { key, alg }\n\n matchingKeys.push(key)\n }\n\n const isAllowedAlg = matchesAny(alg)\n const candidates = matchingKeys.map(\n (key) => [key, key.algorithms.filter(isAllowedAlg)] as const,\n )\n\n // Return the first candidates that matches the preferred algorithms\n for (const prefAlg of this.preferredSigningAlgorithms) {\n for (const [matchingKey, matchingAlgs] of candidates) {\n if (matchingAlgs.includes(prefAlg)) {\n return { key: matchingKey, alg: prefAlg }\n }\n }\n }\n\n // Return any candidate\n for (const [matchingKey, matchingAlgs] of candidates) {\n for (const alg of matchingAlgs) {\n return { key: matchingKey, alg }\n }\n }\n\n throw new JwkError(\n `No private key found for ${kid || alg || usage}`,\n ERR_JWK_NOT_FOUND,\n )\n }\n\n [Symbol.iterator](): IterableIterator<K> {\n return this.keys.values()\n }\n\n async createJwt(\n { alg: sAlg, kid: sKid, ...header }: JwtSignHeader,\n payload: JwtPayload | JwtPayloadGetter,\n ): Promise<SignedJwt> {\n try {\n const { key, alg } = this.findPrivateKey({\n alg: sAlg,\n kid: sKid,\n usage: 'sign',\n allowRevoked: false, // For explicitness (default value is false)\n })\n const protectedHeader = { ...header, alg, kid: key.kid }\n\n if (typeof payload === 'function') {\n payload = await payload(protectedHeader, key)\n }\n\n return await key.createJwt(protectedHeader, payload)\n } catch (err) {\n throw JwtCreateError.from(err)\n }\n }\n\n async verifyJwt<C extends string = never>(\n token: SignedJwt,\n options?: ActivityCheckOptions & VerifyOptions<C>,\n ): Promise<VerifyResult<C> & { key: K }> {\n const { header } = unsafeDecodeJwt(token)\n const { kid, alg } = header\n\n const errors: unknown[] = []\n\n for (const key of this.list({ ...options, kid, alg, usage: 'verify' })) {\n try {\n const result = await key.verifyJwt<C>(token, options)\n return { ...result, key }\n } catch (err) {\n errors.push(err)\n }\n }\n\n switch (errors.length) {\n case 0:\n throw new JwtVerifyError('No key matched', ERR_JWKS_NO_MATCHING_KEY)\n case 1:\n throw JwtVerifyError.from(errors[0], ERR_JWT_INVALID)\n default:\n throw JwtVerifyError.from(errors, ERR_JWT_INVALID)\n }\n }\n\n toJSON() {\n // Make a copy to allow mutation of the result\n return structuredClone(this.publicJwks) as JwksPub\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAgB,MAAM,KAAK,CAAA;AAGjD,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAA;AACvD,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;AAE3D,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,GAAG,KAAK,IAAI,QAAQ,CAC9D,CAAC,GAAG;KACD,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,GAC5B,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,GAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;CAC7B,CACF,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,GAAG,CAAC,GAAG,SAAS,KAAG,CAAC,IAAI,CAAoB,CAAA;AAEzE,eAAO,MAAM,iBAAiB,GAC3B,CAAC,EAAE,OAAO,SAAS,CAAC,EAAE,MACtB,GAAG,CAAC,EAAE,GAAG,CAAC,WAOV,CAAA;AAEH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EACrE,KAAK,EAAE,IAAI,GAAG,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,EAAE,GACzC,CAAC,CAAC,EAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAMxB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,EAC9C,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EACtB,UAAU,2BAA2B,CAAC,CAAC,EAAE,CAAC,CAAC,MAE1B,MAAM,CAAC,MASzB,CAAA;AAGD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAIpD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,IA2BrE,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,KAAK,eAAe,CAClB,CAAC,SAAS,MAAM,EAChB,GAAG,SAAS,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,IAC7B,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,GACvB,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,GACX,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,CAAA;AAEvD;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,GAAI,CAAC,SAAS,MAAM,EAC/D,OAAO,CAAC,EACR,sBAAiB,MAST,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,IAAI,IAAI,eAAe,CAAC,CAAC,CA2CrE,CAAA;AAED,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,EACxE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,GAAG,OAAO,CAE7C"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAgB,MAAM,KAAK,CAAA;AAEjD,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAA;AACvD,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;AAE3D,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,GAAG,KAAK,IAAI,QAAQ,CAC9D,CAAC,GAAG;KACD,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,GAC5B,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,GAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;CAC7B,CACF,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,GAAG,CAAC,GAAG,SAAS,KAAG,CAAC,IAAI,CAAoB,CAAA;AAEzE,eAAO,MAAM,iBAAiB,GAC3B,CAAC,EAAE,OAAO,SAAS,CAAC,EAAE,MACtB,GAAG,CAAC,EAAE,GAAG,CAAC,WAOV,CAAA;AAGH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EACrE,KAAK,EAAE,IAAI,GAAG,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,EAAE,GACzC,CAAC,CAAC,EAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAMxB;AAGD;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,EAC9C,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EACtB,UAAU,2BAA2B,CAAC,CAAC,EAAE,CAAC,CAAC,MAE1B,MAAM,CAAC,MASzB,CAAA;AAGD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAIpD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,IA2BrE,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,KAAK,eAAe,CAClB,CAAC,SAAS,MAAM,EAChB,GAAG,SAAS,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,IAC7B,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,GACvB,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,GACX,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,CAAA;AAEvD;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,GAAI,CAAC,SAAS,MAAM,EAC/D,OAAO,CAAC,EACR,sBAAiB,MAST,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,IAAI,IAAI,eAAe,CAAC,CAAC,CA2CrE,CAAA;AAED,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,EACxE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,GAAG,OAAO,CAE7C"}
package/dist/util.js CHANGED
@@ -1,14 +1,7 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.segmentedStringRefinementFactory = exports.jwtCharsRefinement = exports.cachedGetter = exports.preferredOrderCmp = exports.isDefined = void 0;
4
- exports.matchesAny = matchesAny;
5
- exports.parseB64uJson = parseB64uJson;
6
- exports.isLastOccurrence = isLastOccurrence;
7
- const base64_1 = require("multiformats/bases/base64");
8
- const zod_1 = require("zod");
9
- const isDefined = (i) => i !== undefined;
10
- exports.isDefined = isDefined;
11
- const preferredOrderCmp = (order) => (a, b) => {
1
+ import { base64url } from 'multiformats/bases/base64';
2
+ import { ZodIssueCode } from 'zod';
3
+ export const isDefined = (i) => i !== undefined;
4
+ export const preferredOrderCmp = (order) => (a, b) => {
12
5
  const aIdx = order.indexOf(a);
13
6
  const bIdx = order.indexOf(b);
14
7
  if (aIdx === bIdx)
@@ -19,18 +12,19 @@ const preferredOrderCmp = (order) => (a, b) => {
19
12
  return -1;
20
13
  return aIdx - bIdx;
21
14
  };
22
- exports.preferredOrderCmp = preferredOrderCmp;
23
- function matchesAny(value) {
15
+ /* eslint-disable @typescript-eslint/no-unused-vars -- `v` is used at runtime in the returned type guards; v8 false-positive */
16
+ export function matchesAny(value) {
24
17
  return value == null
25
18
  ? (v) => true
26
19
  : Array.isArray(value)
27
20
  ? (v) => value.includes(v)
28
21
  : (v) => v === value;
29
22
  }
23
+ /* eslint-enable @typescript-eslint/no-unused-vars */
30
24
  /**
31
25
  * Decorator to cache the result of a getter on a class instance.
32
26
  */
33
- const cachedGetter = (target, _context) => {
27
+ export const cachedGetter = (target, _context) => {
34
28
  return function () {
35
29
  const value = target.call(this);
36
30
  Object.defineProperty(this, target.name, {
@@ -41,10 +35,9 @@ const cachedGetter = (target, _context) => {
41
35
  return value;
42
36
  };
43
37
  };
44
- exports.cachedGetter = cachedGetter;
45
38
  const decoder = new TextDecoder();
46
- function parseB64uJson(input) {
47
- const inputBytes = base64_1.base64url.baseDecode(input);
39
+ export function parseB64uJson(input) {
40
+ const inputBytes = base64url.baseDecode(input);
48
41
  const json = decoder.decode(inputBytes);
49
42
  return JSON.parse(json);
50
43
  }
@@ -55,7 +48,7 @@ function parseB64uJson(input) {
55
48
  * const jwtSchema = z.string().superRefine(jwtCharsRefinement)
56
49
  * ```
57
50
  */
58
- const jwtCharsRefinement = (data, ctx) => {
51
+ export const jwtCharsRefinement = (data, ctx) => {
59
52
  // Note: this is a hot path, let's avoid using a RegExp
60
53
  let char;
61
54
  for (let i = 0; i < data.length; i++) {
@@ -76,13 +69,12 @@ const jwtCharsRefinement = (data, ctx) => {
76
69
  // Invalid char might be a surrogate pair
77
70
  const invalidChar = String.fromCodePoint(data.codePointAt(i));
78
71
  return ctx.addIssue({
79
- code: zod_1.ZodIssueCode.custom,
72
+ code: ZodIssueCode.custom,
80
73
  message: `Invalid character "${invalidChar}" in JWT at position ${i}`,
81
74
  });
82
75
  }
83
76
  }
84
77
  };
85
- exports.jwtCharsRefinement = jwtCharsRefinement;
86
78
  /**
87
79
  * @example
88
80
  * ```ts
@@ -90,7 +82,7 @@ exports.jwtCharsRefinement = jwtCharsRefinement;
90
82
  * type Jwt = z.infer<typeof jwtSchema> // `${string}.${string}.${string}`
91
83
  * ```
92
84
  */
93
- const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
85
+ export const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
94
86
  if (!Number.isFinite(count) || count < 1 || (count | 0) !== count) {
95
87
  throw new TypeError(`Count must be a natural number (got ${count})`);
96
88
  }
@@ -99,7 +91,7 @@ const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
99
91
  return (data, ctx) => {
100
92
  if (data.length < minTotalLength) {
101
93
  ctx.addIssue({
102
- code: zod_1.ZodIssueCode.custom,
94
+ code: ZodIssueCode.custom,
103
95
  message: `${errorPrefix}: too short`,
104
96
  });
105
97
  return false;
@@ -109,14 +101,14 @@ const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
109
101
  const nextDot = data.indexOf('.', currentStart);
110
102
  if (nextDot === -1) {
111
103
  ctx.addIssue({
112
- code: zod_1.ZodIssueCode.custom,
104
+ code: ZodIssueCode.custom,
113
105
  message: `${errorPrefix}: expected ${count} segments, got ${i + 1}`,
114
106
  });
115
107
  return false;
116
108
  }
117
109
  if (nextDot - currentStart < minPartLength) {
118
110
  ctx.addIssue({
119
- code: zod_1.ZodIssueCode.custom,
111
+ code: ZodIssueCode.custom,
120
112
  message: `${errorPrefix}: segment ${i + 1} is too short`,
121
113
  });
122
114
  return false;
@@ -125,14 +117,14 @@ const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
125
117
  }
126
118
  if (data.indexOf('.', currentStart) !== -1) {
127
119
  ctx.addIssue({
128
- code: zod_1.ZodIssueCode.custom,
120
+ code: ZodIssueCode.custom,
129
121
  message: `${errorPrefix}: too many segments`,
130
122
  });
131
123
  return false;
132
124
  }
133
125
  if (data.length - currentStart < minPartLength) {
134
126
  ctx.addIssue({
135
- code: zod_1.ZodIssueCode.custom,
127
+ code: ZodIssueCode.custom,
136
128
  message: `${errorPrefix}: last segment is too short`,
137
129
  });
138
130
  return false;
@@ -140,8 +132,7 @@ const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
140
132
  return true;
141
133
  };
142
134
  };
143
- exports.segmentedStringRefinementFactory = segmentedStringRefinementFactory;
144
- function isLastOccurrence(v, i, arr) {
135
+ export function isLastOccurrence(v, i, arr) {
145
136
  return arr.indexOf(v, i + 1) === -1;
146
137
  }
147
138
  //# sourceMappingURL=util.js.map
package/dist/util.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64url } from 'multiformats/bases/base64'\nimport { RefinementCtx, ZodIssueCode } from 'zod'\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport type Simplify<T> = { [K in keyof T]: T[K] } & {}\nexport type Override<T, V> = Simplify<V & Omit<T, keyof V>>\n\nexport type RequiredKey<T, K extends keyof T = never> = Simplify<\n T & {\n [L in K]-?: unknown extends T[L]\n ? NonNullable<unknown> | null\n : Exclude<T[L], undefined>\n }\n>\n\nexport const isDefined = <T>(i: T | undefined): i is T => i !== undefined\n\nexport const preferredOrderCmp =\n <T>(order: readonly T[]) =>\n (a: T, b: T) => {\n const aIdx = order.indexOf(a)\n const bIdx = order.indexOf(b)\n if (aIdx === bIdx) return 0\n if (aIdx === -1) return 1\n if (bIdx === -1) return -1\n return aIdx - bIdx\n }\n\nexport function matchesAny<T extends string | number | symbol | boolean>(\n value: null | undefined | T | readonly T[],\n): (v: unknown) => v is T {\n return value == null\n ? (v): v is T => true\n : Array.isArray(value)\n ? (v): v is T => value.includes(v)\n : (v): v is T => v === value\n}\n\n/**\n * Decorator to cache the result of a getter on a class instance.\n */\nexport const cachedGetter = <T extends object, V>(\n target: (this: T) => V,\n _context: ClassGetterDecoratorContext<T, V>,\n) => {\n return function (this: T) {\n const value = target.call(this)\n Object.defineProperty(this, target.name, {\n get: () => value,\n enumerable: true,\n configurable: true,\n })\n return value\n }\n}\n\nconst decoder = new TextDecoder()\nexport function parseB64uJson(input: string): unknown {\n const inputBytes = base64url.baseDecode(input)\n const json = decoder.decode(inputBytes)\n return JSON.parse(json)\n}\n\n/**\n * @example\n * ```ts\n * // jwtSchema will only allow base64url chars & \".\" (dot)\n * const jwtSchema = z.string().superRefine(jwtCharsRefinement)\n * ```\n */\nexport const jwtCharsRefinement = (data: string, ctx: RefinementCtx): void => {\n // Note: this is a hot path, let's avoid using a RegExp\n let char\n\n for (let i = 0; i < data.length; i++) {\n char = data.charCodeAt(i)\n\n if (\n // Base64 URL encoding (most frequent)\n (65 <= char && char <= 90) || // A-Z\n (97 <= char && char <= 122) || // a-z\n (48 <= char && char <= 57) || // 0-9\n char === 45 || // -\n char === 95 || // _\n // Boundary (least frequent, check last)\n char === 46 // .\n ) {\n // continue\n } else {\n // Invalid char might be a surrogate pair\n const invalidChar = String.fromCodePoint(data.codePointAt(i)!)\n return ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `Invalid character \"${invalidChar}\" in JWT at position ${i}`,\n })\n }\n }\n}\n\n/**\n * @example\n * ```ts\n * type SegmentedString3 = SegmentedString<3> // `${string}.${string}.${string}`\n * type SegmentedString4 = SegmentedString<4> // `${string}.${string}.${string}.${string}`\n * ```\n *\n * @note\n * This utility only provides one way type safety (A SegmentedString<4> can be\n * assigned to SegmentedString<3> but not vice versa). The purpose of this\n * utility is to improve DX by avoiding as many potential errors as build time.\n * DO NOT rely on this to enforce security or data integrity.\n */\ntype SegmentedString<\n C extends number,\n Acc extends string[] = [string],\n> = Acc['length'] extends C\n ? `${Acc[0]}`\n : `${Acc[0]}.${SegmentedString<C, [string, ...Acc]>}`\n\n/**\n * @example\n * ```ts\n * const jwtSchema = z.string().superRefine(segmentedStringRefinementFactory(3))\n * type Jwt = z.infer<typeof jwtSchema> // `${string}.${string}.${string}`\n * ```\n */\nexport const segmentedStringRefinementFactory = <C extends number>(\n count: C,\n minPartLength = 2,\n) => {\n if (!Number.isFinite(count) || count < 1 || (count | 0) !== count) {\n throw new TypeError(`Count must be a natural number (got ${count})`)\n }\n\n const minTotalLength = count * minPartLength + (count - 1)\n const errorPrefix = `Invalid JWT format`\n\n return (data: string, ctx: RefinementCtx): data is SegmentedString<C> => {\n if (data.length < minTotalLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: too short`,\n })\n return false\n }\n let currentStart = 0\n for (let i = 0; i < count - 1; i++) {\n const nextDot = data.indexOf('.', currentStart)\n if (nextDot === -1) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: expected ${count} segments, got ${i + 1}`,\n })\n return false\n }\n if (nextDot - currentStart < minPartLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: segment ${i + 1} is too short`,\n })\n return false\n }\n currentStart = nextDot + 1\n }\n if (data.indexOf('.', currentStart) !== -1) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: too many segments`,\n })\n return false\n }\n if (data.length - currentStart < minPartLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: last segment is too short`,\n })\n return false\n }\n return true\n }\n}\n\nexport function isLastOccurrence<\n T extends number | boolean | string | null | undefined | symbol | bigint,\n>(v: T, i: number, arr: readonly T[]): boolean {\n return arr.indexOf(v, i + 1) === -1\n}\n"]}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64url } from 'multiformats/bases/base64'\nimport { RefinementCtx, ZodIssueCode } from 'zod'\n\nexport type Simplify<T> = { [K in keyof T]: T[K] } & {}\nexport type Override<T, V> = Simplify<V & Omit<T, keyof V>>\n\nexport type RequiredKey<T, K extends keyof T = never> = Simplify<\n T & {\n [L in K]-?: unknown extends T[L]\n ? NonNullable<unknown> | null\n : Exclude<T[L], undefined>\n }\n>\n\nexport const isDefined = <T>(i: T | undefined): i is T => i !== undefined\n\nexport const preferredOrderCmp =\n <T>(order: readonly T[]) =>\n (a: T, b: T) => {\n const aIdx = order.indexOf(a)\n const bIdx = order.indexOf(b)\n if (aIdx === bIdx) return 0\n if (aIdx === -1) return 1\n if (bIdx === -1) return -1\n return aIdx - bIdx\n }\n\n/* eslint-disable @typescript-eslint/no-unused-vars -- `v` is used at runtime in the returned type guards; v8 false-positive */\nexport function matchesAny<T extends string | number | symbol | boolean>(\n value: null | undefined | T | readonly T[],\n): (v: unknown) => v is T {\n return value == null\n ? (v): v is T => true\n : Array.isArray(value)\n ? (v): v is T => value.includes(v)\n : (v): v is T => v === value\n}\n/* eslint-enable @typescript-eslint/no-unused-vars */\n\n/**\n * Decorator to cache the result of a getter on a class instance.\n */\nexport const cachedGetter = <T extends object, V>(\n target: (this: T) => V,\n _context: ClassGetterDecoratorContext<T, V>,\n) => {\n return function (this: T) {\n const value = target.call(this)\n Object.defineProperty(this, target.name, {\n get: () => value,\n enumerable: true,\n configurable: true,\n })\n return value\n }\n}\n\nconst decoder = new TextDecoder()\nexport function parseB64uJson(input: string): unknown {\n const inputBytes = base64url.baseDecode(input)\n const json = decoder.decode(inputBytes)\n return JSON.parse(json)\n}\n\n/**\n * @example\n * ```ts\n * // jwtSchema will only allow base64url chars & \".\" (dot)\n * const jwtSchema = z.string().superRefine(jwtCharsRefinement)\n * ```\n */\nexport const jwtCharsRefinement = (data: string, ctx: RefinementCtx): void => {\n // Note: this is a hot path, let's avoid using a RegExp\n let char\n\n for (let i = 0; i < data.length; i++) {\n char = data.charCodeAt(i)\n\n if (\n // Base64 URL encoding (most frequent)\n (65 <= char && char <= 90) || // A-Z\n (97 <= char && char <= 122) || // a-z\n (48 <= char && char <= 57) || // 0-9\n char === 45 || // -\n char === 95 || // _\n // Boundary (least frequent, check last)\n char === 46 // .\n ) {\n // continue\n } else {\n // Invalid char might be a surrogate pair\n const invalidChar = String.fromCodePoint(data.codePointAt(i)!)\n return ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `Invalid character \"${invalidChar}\" in JWT at position ${i}`,\n })\n }\n }\n}\n\n/**\n * @example\n * ```ts\n * type SegmentedString3 = SegmentedString<3> // `${string}.${string}.${string}`\n * type SegmentedString4 = SegmentedString<4> // `${string}.${string}.${string}.${string}`\n * ```\n *\n * @note\n * This utility only provides one way type safety (A SegmentedString<4> can be\n * assigned to SegmentedString<3> but not vice versa). The purpose of this\n * utility is to improve DX by avoiding as many potential errors as build time.\n * DO NOT rely on this to enforce security or data integrity.\n */\ntype SegmentedString<\n C extends number,\n Acc extends string[] = [string],\n> = Acc['length'] extends C\n ? `${Acc[0]}`\n : `${Acc[0]}.${SegmentedString<C, [string, ...Acc]>}`\n\n/**\n * @example\n * ```ts\n * const jwtSchema = z.string().superRefine(segmentedStringRefinementFactory(3))\n * type Jwt = z.infer<typeof jwtSchema> // `${string}.${string}.${string}`\n * ```\n */\nexport const segmentedStringRefinementFactory = <C extends number>(\n count: C,\n minPartLength = 2,\n) => {\n if (!Number.isFinite(count) || count < 1 || (count | 0) !== count) {\n throw new TypeError(`Count must be a natural number (got ${count})`)\n }\n\n const minTotalLength = count * minPartLength + (count - 1)\n const errorPrefix = `Invalid JWT format`\n\n return (data: string, ctx: RefinementCtx): data is SegmentedString<C> => {\n if (data.length < minTotalLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: too short`,\n })\n return false\n }\n let currentStart = 0\n for (let i = 0; i < count - 1; i++) {\n const nextDot = data.indexOf('.', currentStart)\n if (nextDot === -1) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: expected ${count} segments, got ${i + 1}`,\n })\n return false\n }\n if (nextDot - currentStart < minPartLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: segment ${i + 1} is too short`,\n })\n return false\n }\n currentStart = nextDot + 1\n }\n if (data.indexOf('.', currentStart) !== -1) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: too many segments`,\n })\n return false\n }\n if (data.length - currentStart < minPartLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: last segment is too short`,\n })\n return false\n }\n return true\n }\n}\n\nexport function isLastOccurrence<\n T extends number | boolean | string | null | undefined | symbol | bigint,\n>(v: T, i: number, arr: readonly T[]): boolean {\n return arr.indexOf(v, i + 1) === -1\n}\n"]}