@atproto/jwk 0.1.0 → 0.1.2
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/CHANGELOG.md +18 -0
- package/dist/alg.d.ts.map +1 -1
- package/dist/alg.js +3 -2
- package/dist/alg.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/jwt-decode.js +1 -2
- package/dist/jwt-decode.js.map +1 -1
- package/dist/jwt-verify.d.ts +3 -4
- package/dist/jwt-verify.d.ts.map +1 -1
- package/dist/jwt.d.ts +2611 -157
- package/dist/jwt.d.ts.map +1 -1
- package/dist/jwt.js +8 -4
- package/dist/jwt.js.map +1 -1
- package/dist/key.d.ts +15 -11
- package/dist/key.d.ts.map +1 -1
- package/dist/key.js +8 -7
- package/dist/key.js.map +1 -1
- package/dist/keyset.d.ts +7 -5
- package/dist/keyset.d.ts.map +1 -1
- package/dist/keyset.js +7 -0
- package/dist/keyset.js.map +1 -1
- package/dist/util.d.ts +10 -4
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +3 -3
- package/dist/util.js.map +1 -1
- package/package.json +2 -2
- package/src/alg.ts +2 -1
- package/src/index.ts +5 -0
- package/src/jwt-verify.ts +3 -5
- package/src/jwt.ts +145 -141
- package/src/key.ts +23 -18
- package/src/keyset.ts +17 -9
- package/src/util.ts +24 -6
- package/tsconfig.build.tsbuildinfo +1 -0
package/src/jwt.ts
CHANGED
|
@@ -24,150 +24,154 @@ export const isUnsignedJwt = (data: unknown): data is UnsignedJwt =>
|
|
|
24
24
|
/**
|
|
25
25
|
* @see {@link https://www.rfc-editor.org/rfc/rfc7515.html#section-4}
|
|
26
26
|
*/
|
|
27
|
-
export const jwtHeaderSchema = z
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
27
|
+
export const jwtHeaderSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
/** "alg" (Algorithm) Header Parameter */
|
|
30
|
+
alg: z.string(),
|
|
31
|
+
/** "jku" (JWK Set URL) Header Parameter */
|
|
32
|
+
jku: z.string().url().optional(),
|
|
33
|
+
/** "jwk" (JSON Web Key) Header Parameter */
|
|
34
|
+
jwk: z
|
|
35
|
+
.object({
|
|
36
|
+
kty: z.string(),
|
|
37
|
+
crv: z.string().optional(),
|
|
38
|
+
x: z.string().optional(),
|
|
39
|
+
y: z.string().optional(),
|
|
40
|
+
e: z.string().optional(),
|
|
41
|
+
n: z.string().optional(),
|
|
42
|
+
})
|
|
43
|
+
.optional(),
|
|
44
|
+
/** "kid" (Key ID) Header Parameter */
|
|
45
|
+
kid: z.string().optional(),
|
|
46
|
+
/** "x5u" (X.509 URL) Header Parameter */
|
|
47
|
+
x5u: z.string().optional(),
|
|
48
|
+
/** "x5c" (X.509 Certificate Chain) Header Parameter */
|
|
49
|
+
x5c: z.array(z.string()).optional(),
|
|
50
|
+
/** "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter */
|
|
51
|
+
x5t: z.string().optional(),
|
|
52
|
+
/** "x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Header Parameter */
|
|
53
|
+
'x5t#S256': z.string().optional(),
|
|
54
|
+
/** "typ" (Type) Header Parameter */
|
|
55
|
+
typ: z.string().optional(),
|
|
56
|
+
/** "cty" (Content Type) Header Parameter */
|
|
57
|
+
cty: z.string().optional(),
|
|
58
|
+
/** "crit" (Critical) Header Parameter */
|
|
59
|
+
crit: z.array(z.string()).optional(),
|
|
60
|
+
})
|
|
61
|
+
.passthrough()
|
|
60
62
|
|
|
61
63
|
export type JwtHeader = z.infer<typeof jwtHeaderSchema>
|
|
62
64
|
|
|
63
65
|
// https://www.iana.org/assignments/jwt/jwt.xhtml
|
|
64
|
-
export const jwtPayloadSchema = z
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
66
|
+
export const jwtPayloadSchema = z
|
|
67
|
+
.object({
|
|
68
|
+
iss: z.string().optional(),
|
|
69
|
+
aud: z.union([z.string(), z.array(z.string()).nonempty()]).optional(),
|
|
70
|
+
sub: z.string().optional(),
|
|
71
|
+
exp: z.number().int().optional(),
|
|
72
|
+
nbf: z.number().int().optional(),
|
|
73
|
+
iat: z.number().int().optional(),
|
|
74
|
+
jti: z.string().optional(),
|
|
75
|
+
htm: z.string().optional(),
|
|
76
|
+
htu: z.string().optional(),
|
|
77
|
+
ath: z.string().optional(),
|
|
78
|
+
acr: z.string().optional(),
|
|
79
|
+
azp: z.string().optional(),
|
|
80
|
+
amr: z.array(z.string()).optional(),
|
|
81
|
+
// https://datatracker.ietf.org/doc/html/rfc7800
|
|
82
|
+
cnf: z
|
|
83
|
+
.object({
|
|
84
|
+
kid: z.string().optional(), // Key ID
|
|
85
|
+
jwk: jwkPubSchema.optional(), // JWK
|
|
86
|
+
jwe: z.string().optional(), // Encrypted key
|
|
87
|
+
jku: z.string().url().optional(), // JWK Set URI ("kid" should also be provided)
|
|
88
|
+
|
|
89
|
+
// https://datatracker.ietf.org/doc/html/rfc9449#section-6.1
|
|
90
|
+
jkt: z.string().optional(),
|
|
91
|
+
|
|
92
|
+
// https://datatracker.ietf.org/doc/html/rfc8705
|
|
93
|
+
'x5t#S256': z.string().optional(), // X.509 Certificate SHA-256 Thumbprint
|
|
94
|
+
|
|
95
|
+
// https://datatracker.ietf.org/doc/html/rfc9203
|
|
96
|
+
osc: z.string().optional(), // OSCORE_Input_Material carrying the parameters for using OSCORE per-message security with implicit key confirmation
|
|
97
|
+
})
|
|
98
|
+
.optional(),
|
|
99
|
+
|
|
100
|
+
client_id: z.string().optional(),
|
|
101
|
+
|
|
102
|
+
scope: z.string().optional(),
|
|
103
|
+
nonce: z.string().optional(),
|
|
104
|
+
|
|
105
|
+
at_hash: z.string().optional(),
|
|
106
|
+
c_hash: z.string().optional(),
|
|
107
|
+
s_hash: z.string().optional(),
|
|
108
|
+
auth_time: z.number().int().optional(),
|
|
109
|
+
|
|
110
|
+
// https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
|
|
111
|
+
|
|
112
|
+
// OpenID: "profile" scope
|
|
113
|
+
name: z.string().optional(),
|
|
114
|
+
family_name: z.string().optional(),
|
|
115
|
+
given_name: z.string().optional(),
|
|
116
|
+
middle_name: z.string().optional(),
|
|
117
|
+
nickname: z.string().optional(),
|
|
118
|
+
preferred_username: z.string().optional(),
|
|
119
|
+
gender: z.string().optional(), // OpenID only defines "male" and "female" without forbidding other values
|
|
120
|
+
picture: z.string().url().optional(),
|
|
121
|
+
profile: z.string().url().optional(),
|
|
122
|
+
website: z.string().url().optional(),
|
|
123
|
+
birthdate: z
|
|
124
|
+
.string()
|
|
125
|
+
.regex(/\d{4}-\d{2}-\d{2}/) // YYYY-MM-DD
|
|
126
|
+
.optional(),
|
|
127
|
+
zoneinfo: z
|
|
128
|
+
.string()
|
|
129
|
+
.regex(/^[A-Za-z0-9_/]+$/)
|
|
130
|
+
.optional(),
|
|
131
|
+
locale: z
|
|
132
|
+
.string()
|
|
133
|
+
.regex(/^[a-z]{2}(-[A-Z]{2})?$/)
|
|
134
|
+
.optional(),
|
|
135
|
+
updated_at: z.number().int().optional(),
|
|
136
|
+
|
|
137
|
+
// OpenID: "email" scope
|
|
138
|
+
email: z.string().optional(),
|
|
139
|
+
email_verified: z.boolean().optional(),
|
|
140
|
+
|
|
141
|
+
// OpenID: "phone" scope
|
|
142
|
+
phone_number: z.string().optional(),
|
|
143
|
+
phone_number_verified: z.boolean().optional(),
|
|
144
|
+
|
|
145
|
+
// OpenID: "address" scope
|
|
146
|
+
// https://openid.net/specs/openid-connect-core-1_0.html#AddressClaim
|
|
147
|
+
address: z
|
|
148
|
+
.object({
|
|
149
|
+
formatted: z.string().optional(),
|
|
150
|
+
street_address: z.string().optional(),
|
|
151
|
+
locality: z.string().optional(),
|
|
152
|
+
region: z.string().optional(),
|
|
153
|
+
postal_code: z.string().optional(),
|
|
154
|
+
country: z.string().optional(),
|
|
155
|
+
})
|
|
156
|
+
.optional(),
|
|
157
|
+
|
|
158
|
+
// https://datatracker.ietf.org/doc/html/rfc9396#section-14.2
|
|
159
|
+
authorization_details: z
|
|
160
|
+
.array(
|
|
161
|
+
z
|
|
162
|
+
.object({
|
|
163
|
+
type: z.string(),
|
|
164
|
+
// https://datatracker.ietf.org/doc/html/rfc9396#section-2.2
|
|
165
|
+
locations: z.array(z.string()).optional(),
|
|
166
|
+
actions: z.array(z.string()).optional(),
|
|
167
|
+
datatypes: z.array(z.string()).optional(),
|
|
168
|
+
identifier: z.string().optional(),
|
|
169
|
+
privileges: z.array(z.string()).optional(),
|
|
170
|
+
})
|
|
171
|
+
.passthrough(),
|
|
172
|
+
)
|
|
173
|
+
.optional(),
|
|
174
|
+
})
|
|
175
|
+
.passthrough()
|
|
172
176
|
|
|
173
177
|
export type JwtPayload = z.infer<typeof jwtPayloadSchema>
|
package/src/key.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { jwkAlgorithms } from './alg.js'
|
|
2
2
|
import { JwkError } from './errors.js'
|
|
3
3
|
import { Jwk, jwkSchema } from './jwk.js'
|
|
4
|
-
import { VerifyOptions,
|
|
4
|
+
import { VerifyOptions, VerifyResult } from './jwt-verify.js'
|
|
5
5
|
import { JwtHeader, JwtPayload, SignedJwt } from './jwt.js'
|
|
6
6
|
import { cachedGetter } from './util.js'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const jwkSchemaReadonly = jwkSchema.readonly()
|
|
9
|
+
|
|
10
|
+
export abstract class Key<J extends Jwk = Jwk> {
|
|
11
|
+
constructor(protected readonly jwk: Readonly<J>) {
|
|
10
12
|
// A key should always be used either for signing or encryption.
|
|
11
13
|
if (!jwk.use) throw new JwkError('Missing "use" Parameter value')
|
|
12
14
|
}
|
|
@@ -24,25 +26,28 @@ export abstract class Key {
|
|
|
24
26
|
return false
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
get privateJwk():
|
|
29
|
+
get privateJwk(): Readonly<J> | undefined {
|
|
28
30
|
return this.isPrivate ? this.jwk : undefined
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
@cachedGetter
|
|
32
|
-
get publicJwk():
|
|
34
|
+
get publicJwk():
|
|
35
|
+
| Readonly<Exclude<J, { kty: 'oct' }> & { d?: never }>
|
|
36
|
+
| undefined {
|
|
33
37
|
if (this.isSymetric) return undefined
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
|
|
39
|
+
return jwkSchemaReadonly.parse({
|
|
40
|
+
...this.jwk,
|
|
41
|
+
d: undefined,
|
|
42
|
+
k: undefined,
|
|
43
|
+
}) as Exclude<J, { kty: 'oct' }> & { d?: never }
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
@cachedGetter
|
|
42
|
-
get bareJwk(): Jwk | undefined {
|
|
47
|
+
get bareJwk(): Readonly<Jwk> | undefined {
|
|
43
48
|
if (this.isSymetric) return undefined
|
|
44
49
|
const { kty, crv, e, n, x, y } = this.jwk as any
|
|
45
|
-
return
|
|
50
|
+
return jwkSchemaReadonly.parse({ crv, e, kty, n, x, y })
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
get use() {
|
|
@@ -64,7 +69,7 @@ export abstract class Key {
|
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
get crv() {
|
|
67
|
-
return (this.jwk as { crv: undefined } | Extract<
|
|
72
|
+
return (this.jwk as { crv: undefined } | Extract<J, { crv: unknown }>).crv
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
/**
|
|
@@ -73,7 +78,7 @@ export abstract class Key {
|
|
|
73
78
|
*/
|
|
74
79
|
@cachedGetter
|
|
75
80
|
get algorithms(): readonly string[] {
|
|
76
|
-
return Array.from(jwkAlgorithms(this.jwk))
|
|
81
|
+
return Object.freeze(Array.from(jwkAlgorithms(this.jwk)))
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
/**
|
|
@@ -86,8 +91,8 @@ export abstract class Key {
|
|
|
86
91
|
*
|
|
87
92
|
* @throws {JwtVerifyError} if the JWT is invalid
|
|
88
93
|
*/
|
|
89
|
-
abstract verifyJwt<
|
|
90
|
-
|
|
91
|
-
C
|
|
92
|
-
|
|
94
|
+
abstract verifyJwt<C extends string = never>(
|
|
95
|
+
token: SignedJwt,
|
|
96
|
+
options?: VerifyOptions<C>,
|
|
97
|
+
): Promise<VerifyResult<C>>
|
|
93
98
|
}
|
package/src/keyset.ts
CHANGED
|
@@ -7,13 +7,15 @@ import {
|
|
|
7
7
|
JwtVerifyError,
|
|
8
8
|
} from './errors.js'
|
|
9
9
|
import { Jwk } from './jwk.js'
|
|
10
|
-
import { Jwks } from './jwks.js'
|
|
10
|
+
import { Jwks, JwksPub } from './jwks.js'
|
|
11
11
|
import { unsafeDecodeJwt } from './jwt-decode.js'
|
|
12
12
|
import { VerifyOptions, VerifyResult } from './jwt-verify.js'
|
|
13
13
|
import { JwtHeader, JwtPayload, SignedJwt } from './jwt.js'
|
|
14
14
|
import { Key } from './key.js'
|
|
15
15
|
import {
|
|
16
|
+
DeepReadonly,
|
|
16
17
|
Override,
|
|
18
|
+
UnReadonly,
|
|
17
19
|
cachedGetter,
|
|
18
20
|
isDefined,
|
|
19
21
|
matchesAny,
|
|
@@ -80,6 +82,10 @@ export class Keyset<K extends Key = Key> implements Iterable<K> {
|
|
|
80
82
|
this.keys = Object.freeze(keys)
|
|
81
83
|
}
|
|
82
84
|
|
|
85
|
+
get size(): number {
|
|
86
|
+
return this.keys.length
|
|
87
|
+
}
|
|
88
|
+
|
|
83
89
|
@cachedGetter
|
|
84
90
|
get signAlgorithms(): readonly string[] {
|
|
85
91
|
const algorithms = new Set<string>()
|
|
@@ -95,14 +101,14 @@ export class Keyset<K extends Key = Key> implements Iterable<K> {
|
|
|
95
101
|
}
|
|
96
102
|
|
|
97
103
|
@cachedGetter
|
|
98
|
-
get publicJwks():
|
|
104
|
+
get publicJwks(): DeepReadonly<JwksPub> {
|
|
99
105
|
return {
|
|
100
106
|
keys: Array.from(this, extractPublicJwk).filter(isDefined),
|
|
101
107
|
}
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
@cachedGetter
|
|
105
|
-
get privateJwks(): Jwks {
|
|
111
|
+
get privateJwks(): DeepReadonly<Jwks> {
|
|
106
112
|
return {
|
|
107
113
|
keys: Array.from(this, extractPrivateJwk).filter(isDefined),
|
|
108
114
|
}
|
|
@@ -207,13 +213,10 @@ export class Keyset<K extends Key = Key> implements Iterable<K> {
|
|
|
207
213
|
}
|
|
208
214
|
}
|
|
209
215
|
|
|
210
|
-
async verifyJwt<
|
|
211
|
-
P extends Record<string, unknown> = JwtPayload,
|
|
212
|
-
C extends string = string,
|
|
213
|
-
>(
|
|
216
|
+
async verifyJwt<C extends string = never>(
|
|
214
217
|
token: SignedJwt,
|
|
215
218
|
options?: VerifyOptions<C>,
|
|
216
|
-
): Promise<VerifyResult<
|
|
219
|
+
): Promise<VerifyResult<C> & { key: K }> {
|
|
217
220
|
const { header } = unsafeDecodeJwt(token)
|
|
218
221
|
const { kid, alg } = header
|
|
219
222
|
|
|
@@ -221,7 +224,7 @@ export class Keyset<K extends Key = Key> implements Iterable<K> {
|
|
|
221
224
|
|
|
222
225
|
for (const key of this.list({ kid, alg })) {
|
|
223
226
|
try {
|
|
224
|
-
const result = await key.verifyJwt<
|
|
227
|
+
const result = await key.verifyJwt<C>(token, options)
|
|
225
228
|
return { ...result, key }
|
|
226
229
|
} catch (err) {
|
|
227
230
|
errors.push(err)
|
|
@@ -237,4 +240,9 @@ export class Keyset<K extends Key = Key> implements Iterable<K> {
|
|
|
237
240
|
throw JwtVerifyError.from(errors, ERR_JWT_INVALID)
|
|
238
241
|
}
|
|
239
242
|
}
|
|
243
|
+
|
|
244
|
+
toJSON(): JwksPub {
|
|
245
|
+
// Make a copy to prevent mutation of the original keyset
|
|
246
|
+
return structuredClone(this.publicJwks) as UnReadonly<JwksPub>
|
|
247
|
+
}
|
|
240
248
|
}
|
package/src/util.ts
CHANGED
|
@@ -5,14 +5,32 @@ import { RefinementCtx, ZodIssueCode } from 'zod'
|
|
|
5
5
|
export type Simplify<T> = { [K in keyof T]: T[K] } & {}
|
|
6
6
|
export type Override<T, V> = Simplify<V & Omit<T, keyof V>>
|
|
7
7
|
|
|
8
|
-
export type RequiredKey<T, K extends
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
export type RequiredKey<T, K extends keyof T = never> = Simplify<
|
|
9
|
+
T & {
|
|
10
|
+
[L in K]-?: unknown extends T[L]
|
|
11
|
+
? NonNullable<unknown> | null
|
|
12
|
+
: Exclude<T[L], undefined>
|
|
13
|
+
}
|
|
14
14
|
>
|
|
15
15
|
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
17
|
+
export type DeepReadonly<T> = T extends Function
|
|
18
|
+
? T
|
|
19
|
+
: T extends object
|
|
20
|
+
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
|
|
21
|
+
: T extends readonly (infer U)[]
|
|
22
|
+
? readonly DeepReadonly<U>[]
|
|
23
|
+
: T
|
|
24
|
+
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
26
|
+
export type UnReadonly<T> = T extends Function
|
|
27
|
+
? T
|
|
28
|
+
: T extends object
|
|
29
|
+
? { -readonly [K in keyof T]: UnReadonly<T[K]> }
|
|
30
|
+
: T extends readonly (infer U)[]
|
|
31
|
+
? UnReadonly<U>[]
|
|
32
|
+
: T
|
|
33
|
+
|
|
16
34
|
export const isDefined = <T>(i: T | undefined): i is T => i !== undefined
|
|
17
35
|
|
|
18
36
|
export const preferredOrderCmp =
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/alg.ts","./src/errors.ts","./src/index.ts","./src/jwk.ts","./src/jwks.ts","./src/jwt-decode.ts","./src/jwt-verify.ts","./src/jwt.ts","./src/key.ts","./src/keyset.ts","./src/util.ts"],"version":"5.6.3"}
|