@finueva/auth 0.32.0 → 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/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/device.d.ts +15 -11
- package/dist/device.js +439 -150
- package/dist/index.d.ts +3 -3
- package/dist/index.js +467 -162
- package/dist/server.d.ts +27 -25
- package/dist/server.js +933 -971
- package/dist/{types-BU8vZrhF.d.ts → types-QJnXZXYY.d.ts} +73 -5
- package/package.json +8 -8
package/dist/device.js
CHANGED
|
@@ -1,3 +1,182 @@
|
|
|
1
|
+
//#region src/errors.ts
|
|
2
|
+
const messages = {
|
|
3
|
+
invalid_credentials: "The credentials are invalid.",
|
|
4
|
+
invalid_auth_input: "The authentication input is invalid.",
|
|
5
|
+
account_conflict: "The account is not available.",
|
|
6
|
+
social_signup_required: "No account is available for this social sign-in. Start sign-up to create one.",
|
|
7
|
+
google_recovery_in_progress: "A Google connection is already being completed. Return to that sign-in, or wait up to ten minutes and restart.",
|
|
8
|
+
google_recovery_not_required: "Google account recovery is not required.",
|
|
9
|
+
google_recovery_invalid: "The Google account recovery request is invalid.",
|
|
10
|
+
google_recovery_expired: "Google account recovery has expired. Start Google sign-in again.",
|
|
11
|
+
google_recovery_account_mismatch: "Sign in to the existing account associated with this Google identity.",
|
|
12
|
+
password_reset_invalid: "The password reset request is invalid.",
|
|
13
|
+
authentication_required: "Authentication is required.",
|
|
14
|
+
request_origin_denied: "The request origin is not allowed.",
|
|
15
|
+
invalid_request: "The request is invalid.",
|
|
16
|
+
invalid_invitation: "The invitation is invalid.",
|
|
17
|
+
invitation_unavailable: "The invitation is not available.",
|
|
18
|
+
recipient_unavailable: "The recipient is unavailable.",
|
|
19
|
+
invitation_recipient_mismatch: "The invitation cannot be accepted by this account.",
|
|
20
|
+
invitation_recovery_required: "Invitation administration requires separate recovery.",
|
|
21
|
+
membership_removal_recovery_required: "Membership removal requires separate recovery.",
|
|
22
|
+
email_verification_required: "Email verification is required.",
|
|
23
|
+
invalid_workspace_selection: "The workspace selection is invalid.",
|
|
24
|
+
organization_context_too_large: "The organization context is too large.",
|
|
25
|
+
credential_rate_limited: "Credential requests are temporarily limited.",
|
|
26
|
+
auth_request_rate_limited: "Authentication requests are temporarily limited.",
|
|
27
|
+
organization_slug_unavailable: "The organization address is unavailable.",
|
|
28
|
+
state_conflict: "The authentication state conflicts with the request.",
|
|
29
|
+
access_denied: "Access is denied.",
|
|
30
|
+
platform_target_unavailable: "The platform administration target is unavailable.",
|
|
31
|
+
platform_quorum_unavailable: "Platform administration quorum is unavailable.",
|
|
32
|
+
platform_recovery_required: "Platform administration requires separate recovery.",
|
|
33
|
+
identity_authority_unavailable: "Authentication is temporarily unavailable.",
|
|
34
|
+
two_factor_required: "A second authentication factor is required.",
|
|
35
|
+
two_factor_code_invalid: "The verification code is invalid.",
|
|
36
|
+
two_factor_challenge_expired: "The second-factor challenge has ended. Sign in again.",
|
|
37
|
+
two_factor_locked: "Second-factor verification is temporarily locked.",
|
|
38
|
+
recent_sign_in_required: "A recent sign-in is required.",
|
|
39
|
+
enterprise_recovery_required: "Enterprise administration evidence requires operator recovery.",
|
|
40
|
+
recent_authentication_required: "A ready recent-authentication action is required.",
|
|
41
|
+
organization_closure_confirmation_mismatch: "The confirmation does not match the organization.",
|
|
42
|
+
organization_closure_cancellation_ended: "The closure cancellation period has ended.",
|
|
43
|
+
ceremony_return_refused: "The return address is not registered for this application.",
|
|
44
|
+
password_sign_in_required: "A password sign-in method is required for this passkey change.",
|
|
45
|
+
account_deletion_pending: "This account is scheduled for deletion.",
|
|
46
|
+
account_restore_unavailable: "The restore ticket or link is used or expired, or the account is not scheduled for deletion."
|
|
47
|
+
};
|
|
48
|
+
var AuthError = class extends Error {
|
|
49
|
+
code;
|
|
50
|
+
status;
|
|
51
|
+
retryAfterSeconds;
|
|
52
|
+
accountDeletion;
|
|
53
|
+
constructor(code, status, retryAfterSeconds, details) {
|
|
54
|
+
super(messages[code]);
|
|
55
|
+
this.name = "AuthError";
|
|
56
|
+
this.code = code;
|
|
57
|
+
this.status = status;
|
|
58
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
59
|
+
if (details?.accountDeletion) this.accountDeletion = details.accountDeletion;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/account-deletion.ts
|
|
64
|
+
function isObject$1(value) {
|
|
65
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66
|
+
}
|
|
67
|
+
function authorityUnavailable$1() {
|
|
68
|
+
return new AuthError("identity_authority_unavailable", 503);
|
|
69
|
+
}
|
|
70
|
+
const idPattern$2 = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
|
|
71
|
+
const tokenPattern = /^[A-Za-z0-9_-]{43}$(?![\s\S])/;
|
|
72
|
+
const idempotencyPattern = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$(?![\s\S])/;
|
|
73
|
+
const MAX_SOLE_ORGANIZATIONS = 20;
|
|
74
|
+
const MAX_BLOCKING_ORGANIZATIONS = 100;
|
|
75
|
+
const organizationBlockers = new Set(["owner_with_members", "enterprise_connection"]);
|
|
76
|
+
const accountBlockers = new Set(["managed_account", "platform_role"]);
|
|
77
|
+
const stepUps = new Set([
|
|
78
|
+
"recent_sign_in",
|
|
79
|
+
"password",
|
|
80
|
+
"sign_in_again"
|
|
81
|
+
]);
|
|
82
|
+
function exact$3(value, keys) {
|
|
83
|
+
return isObject$1(value) && Object.keys(value).length === keys.length && keys.every((key) => {
|
|
84
|
+
return Object.hasOwn(value, key);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function isoDate(value) {
|
|
88
|
+
if (typeof value !== "string") throw authorityUnavailable$1();
|
|
89
|
+
const parsed = new Date(value);
|
|
90
|
+
if (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== value) throw authorityUnavailable$1();
|
|
91
|
+
return parsed;
|
|
92
|
+
}
|
|
93
|
+
function organization(value, keys) {
|
|
94
|
+
if (!exact$3(value, keys) || typeof value.id !== "string" || !idPattern$2.test(value.id) || typeof value.name !== "string" || value.name.length === 0 || value.name.length > 255 || value.slug !== null && (typeof value.slug !== "string" || value.slug.length === 0 || value.slug.length > 255)) throw authorityUnavailable$1();
|
|
95
|
+
return {
|
|
96
|
+
id: value.id,
|
|
97
|
+
name: value.name,
|
|
98
|
+
slug: value.slug
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function normalizeAccountDeletionStartRequest(value) {
|
|
102
|
+
if (!isObject$1(value) || typeof value.idempotencyKey !== "string" || !idempotencyPattern.test(value.idempotencyKey)) throw new TypeError("idempotencyKey is invalid");
|
|
103
|
+
const ids = value.soleOrganizationIds;
|
|
104
|
+
if (!Array.isArray(ids) || ids.length > MAX_SOLE_ORGANIZATIONS || !ids.every((id) => {
|
|
105
|
+
return typeof id === "string" && idPattern$2.test(id);
|
|
106
|
+
})) throw new TypeError("soleOrganizationIds is invalid");
|
|
107
|
+
return {
|
|
108
|
+
idempotencyKey: value.idempotencyKey,
|
|
109
|
+
soleOrganizationIds: [...ids]
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function normalizeAccountDeletionEligibility(value) {
|
|
113
|
+
if (!exact$3(value, [
|
|
114
|
+
"accountBlocker",
|
|
115
|
+
"blockingOrganizations",
|
|
116
|
+
"deleteAfter",
|
|
117
|
+
"eligible",
|
|
118
|
+
"soleOrganizations",
|
|
119
|
+
"stepUp"
|
|
120
|
+
]) || typeof value.eligible !== "boolean" || value.accountBlocker !== null && !accountBlockers.has(value.accountBlocker) || !Array.isArray(value.blockingOrganizations) || value.blockingOrganizations.length > MAX_BLOCKING_ORGANIZATIONS || !Array.isArray(value.soleOrganizations) || value.soleOrganizations.length > MAX_SOLE_ORGANIZATIONS || !stepUps.has(value.stepUp)) throw authorityUnavailable$1();
|
|
121
|
+
const blockingOrganizations = value.blockingOrganizations.map((entry) => {
|
|
122
|
+
const summary = organization(entry, [
|
|
123
|
+
"id",
|
|
124
|
+
"name",
|
|
125
|
+
"reason",
|
|
126
|
+
"slug"
|
|
127
|
+
]);
|
|
128
|
+
const reason = entry.reason;
|
|
129
|
+
if (!organizationBlockers.has(reason)) throw authorityUnavailable$1();
|
|
130
|
+
return {
|
|
131
|
+
...summary,
|
|
132
|
+
reason
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
eligible: value.eligible,
|
|
137
|
+
accountBlocker: value.accountBlocker,
|
|
138
|
+
blockingOrganizations,
|
|
139
|
+
soleOrganizations: value.soleOrganizations.map((entry) => {
|
|
140
|
+
return organization(entry, [
|
|
141
|
+
"id",
|
|
142
|
+
"name",
|
|
143
|
+
"slug"
|
|
144
|
+
]);
|
|
145
|
+
}),
|
|
146
|
+
stepUp: value.stepUp,
|
|
147
|
+
deleteAfter: isoDate(value.deleteAfter)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function normalizeAccountDeletionRestoreInput(value) {
|
|
151
|
+
if (exact$3(value, ["restoreTicket"]) && typeof value.restoreTicket === "string" && tokenPattern.test(value.restoreTicket)) return { restoreTicket: value.restoreTicket };
|
|
152
|
+
if (exact$3(value, ["restoreLinkToken"]) && typeof value.restoreLinkToken === "string" && tokenPattern.test(value.restoreLinkToken)) return { restoreLinkToken: value.restoreLinkToken };
|
|
153
|
+
throw new TypeError("restore input is invalid");
|
|
154
|
+
}
|
|
155
|
+
function normalizeAccountDeletionRestore(value) {
|
|
156
|
+
if (!exact$3(value, ["status"]) || value.status !== "restored") throw authorityUnavailable$1();
|
|
157
|
+
}
|
|
158
|
+
function accountDeletionPending(value, status) {
|
|
159
|
+
if (status !== 403 || !isObject$1(value) || value.code !== "ACCOUNT_DELETION_PENDING") return null;
|
|
160
|
+
let deleteAfter;
|
|
161
|
+
try {
|
|
162
|
+
deleteAfter = isoDate(value.deleteAfter);
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const restoreTicket = typeof value.restoreTicket === "string" && tokenPattern.test(value.restoreTicket) ? value.restoreTicket : null;
|
|
167
|
+
return {
|
|
168
|
+
deleteAfter,
|
|
169
|
+
restoreTicket
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function fromAccountDeletionError(value, status) {
|
|
173
|
+
const code = isObject$1(value) ? value.code : void 0;
|
|
174
|
+
if (status === 401) return new AuthError("authentication_required", 401);
|
|
175
|
+
if (status === 403) return new AuthError("request_origin_denied", 403);
|
|
176
|
+
if (status === 404 && code === "RESTORE_UNAVAILABLE") return new AuthError("account_restore_unavailable", 404);
|
|
177
|
+
if (status === 400 || status === 413 || status === 415) return new AuthError("invalid_request", 400);
|
|
178
|
+
return authorityUnavailable$1();
|
|
179
|
+
}
|
|
1
180
|
String.fromCharCode;
|
|
2
181
|
const HASH_RE = /#/g;
|
|
3
182
|
const AMPERSAND_RE = /&/g;
|
|
@@ -173,69 +352,11 @@ function stringifyParsedURL(parsed) {
|
|
|
173
352
|
return (parsed.protocol || parsed[protocolRelative] ? (parsed.protocol || "") + "//" : "") + auth + host + pathname + search + hash;
|
|
174
353
|
}
|
|
175
354
|
//#endregion
|
|
176
|
-
//#region src/errors.ts
|
|
177
|
-
const messages = {
|
|
178
|
-
invalid_credentials: "The credentials are invalid.",
|
|
179
|
-
invalid_auth_input: "The authentication input is invalid.",
|
|
180
|
-
account_conflict: "The account is not available.",
|
|
181
|
-
social_signup_required: "No account is available for this social sign-in. Start sign-up to create one.",
|
|
182
|
-
google_recovery_in_progress: "A Google connection is already being completed. Return to that sign-in, or wait up to ten minutes and restart.",
|
|
183
|
-
google_recovery_not_required: "Google account recovery is not required.",
|
|
184
|
-
google_recovery_invalid: "The Google account recovery request is invalid.",
|
|
185
|
-
google_recovery_expired: "Google account recovery has expired. Start Google sign-in again.",
|
|
186
|
-
google_recovery_account_mismatch: "Sign in to the existing account associated with this Google identity.",
|
|
187
|
-
password_reset_invalid: "The password reset request is invalid.",
|
|
188
|
-
authentication_required: "Authentication is required.",
|
|
189
|
-
request_origin_denied: "The request origin is not allowed.",
|
|
190
|
-
invalid_request: "The request is invalid.",
|
|
191
|
-
invalid_invitation: "The invitation is invalid.",
|
|
192
|
-
invitation_unavailable: "The invitation is not available.",
|
|
193
|
-
recipient_unavailable: "The recipient is unavailable.",
|
|
194
|
-
invitation_recipient_mismatch: "The invitation cannot be accepted by this account.",
|
|
195
|
-
invitation_recovery_required: "Invitation administration requires separate recovery.",
|
|
196
|
-
membership_removal_recovery_required: "Membership removal requires separate recovery.",
|
|
197
|
-
email_verification_required: "Email verification is required.",
|
|
198
|
-
invalid_workspace_selection: "The workspace selection is invalid.",
|
|
199
|
-
organization_context_too_large: "The organization context is too large.",
|
|
200
|
-
credential_rate_limited: "Credential requests are temporarily limited.",
|
|
201
|
-
auth_request_rate_limited: "Authentication requests are temporarily limited.",
|
|
202
|
-
organization_slug_unavailable: "The organization address is unavailable.",
|
|
203
|
-
state_conflict: "The authentication state conflicts with the request.",
|
|
204
|
-
access_denied: "Access is denied.",
|
|
205
|
-
platform_target_unavailable: "The platform administration target is unavailable.",
|
|
206
|
-
platform_quorum_unavailable: "Platform administration quorum is unavailable.",
|
|
207
|
-
platform_recovery_required: "Platform administration requires separate recovery.",
|
|
208
|
-
identity_authority_unavailable: "Authentication is temporarily unavailable.",
|
|
209
|
-
two_factor_required: "A second authentication factor is required.",
|
|
210
|
-
two_factor_code_invalid: "The verification code is invalid.",
|
|
211
|
-
two_factor_challenge_expired: "The second-factor challenge has ended. Sign in again.",
|
|
212
|
-
two_factor_locked: "Second-factor verification is temporarily locked.",
|
|
213
|
-
recent_sign_in_required: "A recent sign-in is required.",
|
|
214
|
-
enterprise_recovery_required: "Enterprise administration evidence requires operator recovery.",
|
|
215
|
-
recent_authentication_required: "A ready recent-authentication action is required.",
|
|
216
|
-
organization_closure_confirmation_mismatch: "The confirmation does not match the organization.",
|
|
217
|
-
organization_closure_cancellation_ended: "The closure cancellation period has ended.",
|
|
218
|
-
ceremony_return_refused: "The return address is not registered for this application.",
|
|
219
|
-
password_sign_in_required: "A password sign-in method is required for this passkey change."
|
|
220
|
-
};
|
|
221
|
-
var AuthError = class extends Error {
|
|
222
|
-
code;
|
|
223
|
-
status;
|
|
224
|
-
retryAfterSeconds;
|
|
225
|
-
constructor(code, status, retryAfterSeconds) {
|
|
226
|
-
super(messages[code]);
|
|
227
|
-
this.name = "AuthError";
|
|
228
|
-
this.code = code;
|
|
229
|
-
this.status = status;
|
|
230
|
-
this.retryAfterSeconds = retryAfterSeconds;
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
//#endregion
|
|
234
355
|
//#region src/shared.ts
|
|
235
356
|
const DRIVE_CREDENTIAL_LIFETIME_SECONDS = 840;
|
|
236
357
|
const id = /^[A-Za-z0-9_-]{1,128}$/;
|
|
237
358
|
const email = /^[^\s@]+@[^\s@]+$/;
|
|
238
|
-
const MAX_SOCIAL_ID_TOKEN_BYTES =
|
|
359
|
+
const MAX_SOCIAL_ID_TOKEN_BYTES = 16384;
|
|
239
360
|
function normalizeEmail(value) {
|
|
240
361
|
if (typeof value !== "string") throw new TypeError("email is invalid");
|
|
241
362
|
const normalized = value.trim().toLowerCase();
|
|
@@ -249,7 +370,9 @@ function normalizePassword(value, name = "password", minLength = 8) {
|
|
|
249
370
|
function normalizeSocialIdTokenInput(value) {
|
|
250
371
|
if (!isObject(value)) throw new TypeError("social ID token input is invalid");
|
|
251
372
|
const keys = Object.keys(value);
|
|
252
|
-
if (keys.length !== 3 && keys.length !== 4 || keys.some((key) =>
|
|
373
|
+
if (keys.length !== 3 && keys.length !== 4 || keys.some((key) => {
|
|
374
|
+
return key !== "provider" && key !== "idToken" && key !== "nonce" && key !== "signUp";
|
|
375
|
+
}) || value.provider !== "google" && value.provider !== "apple" || typeof value.signUp !== "boolean" || typeof value.idToken !== "string" || value.idToken.length < 1 || new TextEncoder().encode(value.idToken).byteLength > MAX_SOCIAL_ID_TOKEN_BYTES || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.idToken) || value.nonce !== void 0 && (typeof value.nonce !== "string" || value.nonce.length < 1 || value.nonce.length > 256 || !/^[\x20-\x7e]+$/.test(value.nonce))) throw new TypeError("social ID token input is invalid");
|
|
253
376
|
return {
|
|
254
377
|
provider: value.provider,
|
|
255
378
|
idToken: value.idToken,
|
|
@@ -276,13 +399,23 @@ function normalizeName(value) {
|
|
|
276
399
|
function normalizeProfileInput(value) {
|
|
277
400
|
if (!isObject(value)) throw new TypeError("profile input is invalid");
|
|
278
401
|
const keys = Object.keys(value);
|
|
279
|
-
if (keys.length === 0 || keys.length > 2 || keys.some((key) =>
|
|
402
|
+
if (keys.length === 0 || keys.length > 2 || keys.some((key) => {
|
|
403
|
+
return key !== "name" && key !== "image";
|
|
404
|
+
}) || value.name === void 0 && value.image === void 0) throw new TypeError("profile input is invalid");
|
|
280
405
|
const result = {};
|
|
281
406
|
if (value.name !== void 0) result.name = normalizeName(value.name);
|
|
282
407
|
if (value.image !== void 0) result.image = value.image === null ? null : normalizeProfileImage(value.image);
|
|
283
408
|
return result;
|
|
284
409
|
}
|
|
285
|
-
function
|
|
410
|
+
function isPrivateIpv4(hostname) {
|
|
411
|
+
const parts = hostname.split(".").map(Number);
|
|
412
|
+
if (parts.length !== 4 || parts.some((part) => {
|
|
413
|
+
return !Number.isInteger(part) || part < 0 || part > 255;
|
|
414
|
+
})) return false;
|
|
415
|
+
const [first, second] = parts;
|
|
416
|
+
return first === 10 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168;
|
|
417
|
+
}
|
|
418
|
+
function normalizeOrigin(value, name, allowPrivateNetwork = false) {
|
|
286
419
|
if (value.length === 0 || value.length > 2048 || /[^\x20-\x7e]/.test(value)) throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
287
420
|
let url;
|
|
288
421
|
try {
|
|
@@ -291,7 +424,7 @@ function normalizeOrigin(value, name) {
|
|
|
291
424
|
throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
292
425
|
}
|
|
293
426
|
const local = url.hostname === "localhost" || url.hostname.endsWith(".localhost") || url.hostname === "127.0.0.1";
|
|
294
|
-
if (url.protocol !== "https:" && !(local && url.protocol === "http:") || url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.origin !== value) throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
427
|
+
if (url.protocol !== "https:" && !((local || allowPrivateNetwork && isPrivateIpv4(url.hostname)) && url.protocol === "http:") || url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.origin !== value) throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
295
428
|
return url.origin;
|
|
296
429
|
}
|
|
297
430
|
function normalizeTimeout(value) {
|
|
@@ -318,7 +451,7 @@ function normalizeSession(value) {
|
|
|
318
451
|
};
|
|
319
452
|
}
|
|
320
453
|
function normalizeDriveCredential(value, now) {
|
|
321
|
-
if (!isObject(value) || value.tokenType !== "Bearer" || value.expiresIn !== DRIVE_CREDENTIAL_LIFETIME_SECONDS || typeof value.token !== "string" || value.token.length === 0 || new TextEncoder().encode(`Bearer ${value.token}`).byteLength >
|
|
454
|
+
if (!isObject(value) || value.tokenType !== "Bearer" || value.expiresIn !== DRIVE_CREDENTIAL_LIFETIME_SECONDS || typeof value.token !== "string" || value.token.length === 0 || new TextEncoder().encode(`Bearer ${value.token}`).byteLength > 16384) throw authorityUnavailable();
|
|
322
455
|
return {
|
|
323
456
|
tokenType: "Bearer",
|
|
324
457
|
token: value.token,
|
|
@@ -327,7 +460,9 @@ function normalizeDriveCredential(value, now) {
|
|
|
327
460
|
}
|
|
328
461
|
function normalizeOrganizationPageInput(value) {
|
|
329
462
|
if (value === void 0) return new URLSearchParams();
|
|
330
|
-
if (!isObject(value) || Object.keys(value).some((key) =>
|
|
463
|
+
if (!isObject(value) || Object.keys(value).some((key) => {
|
|
464
|
+
return key !== "limit" && key !== "cursor";
|
|
465
|
+
})) throw new AuthError("invalid_request", 400);
|
|
331
466
|
const input = value;
|
|
332
467
|
const query = new URLSearchParams();
|
|
333
468
|
if (input.limit !== void 0) {
|
|
@@ -342,17 +477,23 @@ function normalizeOrganizationPageInput(value) {
|
|
|
342
477
|
}
|
|
343
478
|
function normalizeOrganizationMemberPageInput(value) {
|
|
344
479
|
if (value === void 0) return new URLSearchParams();
|
|
345
|
-
if (!isObject(value) || Object.keys(value).some((key) =>
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
480
|
+
if (!isObject(value) || Object.keys(value).some((key) => {
|
|
481
|
+
return ![
|
|
482
|
+
"limit",
|
|
483
|
+
"cursor",
|
|
484
|
+
"search"
|
|
485
|
+
].includes(key);
|
|
486
|
+
})) throw new AuthError("invalid_request", 400);
|
|
350
487
|
const { search, ...page } = value;
|
|
351
488
|
const query = normalizeOrganizationPageInput(page);
|
|
352
489
|
if (search !== void 0) {
|
|
353
490
|
if (typeof search !== "string") throw new AuthError("invalid_request", 400);
|
|
354
|
-
const prefix = search.trim().replace(/[A-Z]/g, (character) =>
|
|
355
|
-
|
|
491
|
+
const prefix = search.trim().replace(/[A-Z]/g, (character) => {
|
|
492
|
+
return character.toLowerCase();
|
|
493
|
+
});
|
|
494
|
+
if (!prefix || prefix.length > 128 || Array.from(prefix).some((character) => {
|
|
495
|
+
return character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127;
|
|
496
|
+
})) throw new AuthError("invalid_request", 400);
|
|
356
497
|
query.set("search", prefix);
|
|
357
498
|
}
|
|
358
499
|
return query;
|
|
@@ -472,7 +613,9 @@ function normalizeOrganizationMemberInvitationCreationInput(value) {
|
|
|
472
613
|
throw new AuthError("invalid_request", 400);
|
|
473
614
|
}
|
|
474
615
|
if (new TextEncoder().encode(normalizedEmail).byteLength > 320 || !boundedString(value.idempotencyKey, 255) || value.teamIds !== void 0 && (!Array.isArray(value.teamIds) || value.teamIds.length > 100)) throw new AuthError("invalid_request", 400);
|
|
475
|
-
const teamIds = value.teamIds?.map((teamId) =>
|
|
616
|
+
const teamIds = value.teamIds?.map((teamId) => {
|
|
617
|
+
return normalizeIdInput(teamId);
|
|
618
|
+
});
|
|
476
619
|
if (teamIds && new Set(teamIds).size !== teamIds.length) throw new AuthError("invalid_request", 400);
|
|
477
620
|
return {
|
|
478
621
|
email: normalizedEmail,
|
|
@@ -492,7 +635,9 @@ function normalizeOrganizations(value) {
|
|
|
492
635
|
exact$2(value, ["nextCursor", "organizations"]);
|
|
493
636
|
if (!Array.isArray(value.organizations) || value.organizations.length > 100) throw authorityUnavailable();
|
|
494
637
|
return {
|
|
495
|
-
organizations: unique(value.organizations.map(normalizeOrganization), (item) =>
|
|
638
|
+
organizations: unique(value.organizations.map(normalizeOrganization), (item) => {
|
|
639
|
+
return item.id;
|
|
640
|
+
}),
|
|
496
641
|
nextCursor: nullableCursor(value.nextCursor)
|
|
497
642
|
};
|
|
498
643
|
}
|
|
@@ -513,7 +658,11 @@ function normalizeOrganizationMembers(value) {
|
|
|
513
658
|
"userId"
|
|
514
659
|
]);
|
|
515
660
|
if (!isId(member.id) || !isId(member.userId) || !boundedString(member.name, 255) || typeof member.email !== "string" || member.email.length > 320 || !email.test(member.email) || !role(member.role) || typeof member.owner !== "boolean" || !Array.isArray(member.teamIds) || member.teamIds.length > 100) throw authorityUnavailable();
|
|
516
|
-
const teamIds = unique(member.teamIds.map((teamId) =>
|
|
661
|
+
const teamIds = unique(member.teamIds.map((teamId) => {
|
|
662
|
+
return normalizeResponseId(teamId);
|
|
663
|
+
}), (item) => {
|
|
664
|
+
return item;
|
|
665
|
+
});
|
|
517
666
|
return {
|
|
518
667
|
id: member.id,
|
|
519
668
|
userId: member.userId,
|
|
@@ -525,7 +674,9 @@ function normalizeOrganizationMembers(value) {
|
|
|
525
674
|
joinedAt: responseDate(member.joinedAt),
|
|
526
675
|
teamIds
|
|
527
676
|
};
|
|
528
|
-
}), (item) =>
|
|
677
|
+
}), (item) => {
|
|
678
|
+
return item.id;
|
|
679
|
+
}),
|
|
529
680
|
nextCursor: nullableCursor(value.nextCursor)
|
|
530
681
|
};
|
|
531
682
|
}
|
|
@@ -547,7 +698,9 @@ function normalizeOrganizationTeams(value) {
|
|
|
547
698
|
category: team.category,
|
|
548
699
|
createdAt: responseDate(team.createdAt)
|
|
549
700
|
};
|
|
550
|
-
}), (item) =>
|
|
701
|
+
}), (item) => {
|
|
702
|
+
return item.id;
|
|
703
|
+
}),
|
|
551
704
|
nextCursor: nullableCursor(value.nextCursor)
|
|
552
705
|
};
|
|
553
706
|
}
|
|
@@ -555,7 +708,11 @@ function normalizeOrganizationTeamMembers(value) {
|
|
|
555
708
|
exact$2(value, ["memberIds", "nextCursor"]);
|
|
556
709
|
if (!Array.isArray(value.memberIds) || value.memberIds.length > 100) throw authorityUnavailable();
|
|
557
710
|
return {
|
|
558
|
-
memberIds: unique(value.memberIds.map((item) =>
|
|
711
|
+
memberIds: unique(value.memberIds.map((item) => {
|
|
712
|
+
return normalizeResponseId(item);
|
|
713
|
+
}), (item) => {
|
|
714
|
+
return item;
|
|
715
|
+
}),
|
|
559
716
|
nextCursor: nullableCursor(value.nextCursor)
|
|
560
717
|
};
|
|
561
718
|
}
|
|
@@ -577,7 +734,9 @@ function normalizeOrganizationInvitation(value) {
|
|
|
577
734
|
id: value.id,
|
|
578
735
|
email: value.email,
|
|
579
736
|
role: value.role,
|
|
580
|
-
teamIds: unique(value.teamIds.map(normalizeResponseId), (item) =>
|
|
737
|
+
teamIds: unique(value.teamIds.map(normalizeResponseId), (item) => {
|
|
738
|
+
return item;
|
|
739
|
+
}),
|
|
581
740
|
inviter: {
|
|
582
741
|
membershipId: value.inviter.membershipId,
|
|
583
742
|
name: value.inviter.name
|
|
@@ -591,7 +750,9 @@ function normalizeOrganizationInvitations(value) {
|
|
|
591
750
|
exact$2(value, ["invitations", "nextCursor"]);
|
|
592
751
|
if (!Array.isArray(value.invitations) || value.invitations.length > 100) throw authorityUnavailable();
|
|
593
752
|
return {
|
|
594
|
-
invitations: unique(value.invitations.map(normalizeOrganizationInvitation), (item) =>
|
|
753
|
+
invitations: unique(value.invitations.map(normalizeOrganizationInvitation), (item) => {
|
|
754
|
+
return item.id;
|
|
755
|
+
}),
|
|
595
756
|
nextCursor: nullableCursor(value.nextCursor)
|
|
596
757
|
};
|
|
597
758
|
}
|
|
@@ -628,7 +789,9 @@ function normalizeReceivedInvitation(value) {
|
|
|
628
789
|
id: team.id,
|
|
629
790
|
name: team.name
|
|
630
791
|
};
|
|
631
|
-
}), (item) =>
|
|
792
|
+
}), (item) => {
|
|
793
|
+
return item.id;
|
|
794
|
+
}),
|
|
632
795
|
inviterName: value.inviterName,
|
|
633
796
|
expiresAt: responseDate(value.expiresAt)
|
|
634
797
|
};
|
|
@@ -637,7 +800,9 @@ function normalizeReceivedInvitations(value) {
|
|
|
637
800
|
exact$2(value, ["invitations", "nextCursor"]);
|
|
638
801
|
if (!Array.isArray(value.invitations) || value.invitations.length > 100) throw authorityUnavailable();
|
|
639
802
|
return {
|
|
640
|
-
invitations: unique(value.invitations.map(normalizeReceivedInvitation), (item) =>
|
|
803
|
+
invitations: unique(value.invitations.map(normalizeReceivedInvitation), (item) => {
|
|
804
|
+
return item.id;
|
|
805
|
+
}),
|
|
641
806
|
nextCursor: nullableCursor(value.nextCursor)
|
|
642
807
|
};
|
|
643
808
|
}
|
|
@@ -657,6 +822,8 @@ function fromAuthorityError(value, fallbackStatus, retryAfter) {
|
|
|
657
822
|
}
|
|
658
823
|
function fromAccountAuthorityError(value, status, retryAfter) {
|
|
659
824
|
const code = isObject(value) && typeof value.code === "string" ? value.code : void 0;
|
|
825
|
+
const pendingDeletion = accountDeletionPending(value, status);
|
|
826
|
+
if (pendingDeletion) return new AuthError("account_deletion_pending", 403, void 0, { accountDeletion: pendingDeletion });
|
|
660
827
|
if (status === 403 && (code === "INVALID_ORIGIN" || code === "MISSING_OR_NULL_ORIGIN")) return new AuthError("request_origin_denied", 403);
|
|
661
828
|
if (code === "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL") return new AuthError("account_conflict", 409);
|
|
662
829
|
if (code === "INVALID_TOKEN") return new AuthError("password_reset_invalid", 422);
|
|
@@ -859,7 +1026,7 @@ function mapError(code, status) {
|
|
|
859
1026
|
};
|
|
860
1027
|
}
|
|
861
1028
|
function parseRetryAfter(value) {
|
|
862
|
-
if (!value || !/^\d+$/.test(value)) return
|
|
1029
|
+
if (!value || !/^\d+$/.test(value)) return;
|
|
863
1030
|
const seconds = Number(value);
|
|
864
1031
|
return Number.isSafeInteger(seconds) && seconds >= 1 && seconds <= 3600 ? seconds : void 0;
|
|
865
1032
|
}
|
|
@@ -924,7 +1091,7 @@ function unique(items, key) {
|
|
|
924
1091
|
}
|
|
925
1092
|
function credentialSessionId(token) {
|
|
926
1093
|
const parts = token.split(".");
|
|
927
|
-
if (parts.length !== 3 || !/^[A-Za-z0-9_-]+$/.test(parts[1])) return
|
|
1094
|
+
if (parts.length !== 3 || !/^[A-Za-z0-9_-]+$/.test(parts[1])) return;
|
|
928
1095
|
try {
|
|
929
1096
|
const base64 = parts[1].replaceAll("-", "+").replaceAll("_", "/");
|
|
930
1097
|
const decoded = atob(base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "="));
|
|
@@ -944,23 +1111,27 @@ function userApiApplication(input) {
|
|
|
944
1111
|
return input.applicationId;
|
|
945
1112
|
}
|
|
946
1113
|
function normalizeUserApiCredential(value, startedAt) {
|
|
947
|
-
if (!value || typeof value !== "object" || Array.isArray(value) || !("tokenType" in value) || value.tokenType !== "Bearer" || !("token" in value) || typeof value.token !== "string" || value.token.length + 7 >
|
|
1114
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !("tokenType" in value) || value.tokenType !== "Bearer" || !("token" in value) || typeof value.token !== "string" || value.token.length + 7 > 16384 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.token) || !("expiresIn" in value) || typeof value.expiresIn !== "number" || !Number.isInteger(value.expiresIn) || value.expiresIn < 1 || value.expiresIn > 840 || Object.keys(value).sort().join(",") !== "expiresIn,token,tokenType") throw new AuthError("identity_authority_unavailable", 503);
|
|
948
1115
|
return {
|
|
949
1116
|
tokenType: "Bearer",
|
|
950
1117
|
token: value.token,
|
|
951
1118
|
expiresAt: new Date(startedAt + value.expiresIn * 1e3)
|
|
952
1119
|
};
|
|
953
1120
|
}
|
|
954
|
-
function createUserApiCredentialCache(issue, now, currentSessionId = () =>
|
|
1121
|
+
function createUserApiCredentialCache(issue, now, currentSessionId = () => {}) {
|
|
955
1122
|
let generation = 0;
|
|
956
1123
|
let cached;
|
|
957
1124
|
let pending;
|
|
958
|
-
const copy = (value) =>
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1125
|
+
const copy = (value) => {
|
|
1126
|
+
return {
|
|
1127
|
+
...value,
|
|
1128
|
+
expiresAt: new Date(value.expiresAt)
|
|
1129
|
+
};
|
|
1130
|
+
};
|
|
962
1131
|
return {
|
|
963
|
-
hasAuthority: () =>
|
|
1132
|
+
hasAuthority: () => {
|
|
1133
|
+
return Boolean(cached || pending);
|
|
1134
|
+
},
|
|
964
1135
|
retainSession(sessionId) {
|
|
965
1136
|
if (cached?.sessionId === sessionId && !pending) return;
|
|
966
1137
|
generation += 1;
|
|
@@ -1144,8 +1315,10 @@ function mergeHeaders(input, defaults, Headers) {
|
|
|
1144
1315
|
return headers;
|
|
1145
1316
|
}
|
|
1146
1317
|
async function callHooks(context, hooks) {
|
|
1147
|
-
if (hooks)
|
|
1148
|
-
|
|
1318
|
+
if (hooks) {
|
|
1319
|
+
if (Array.isArray(hooks)) for (const hook of hooks) await hook(context);
|
|
1320
|
+
else await hooks(context);
|
|
1321
|
+
}
|
|
1149
1322
|
}
|
|
1150
1323
|
const retryStatusCodes = new Set([
|
|
1151
1324
|
408,
|
|
@@ -1276,7 +1449,7 @@ function createFetch(globalOptions = {}) {
|
|
|
1276
1449
|
}
|
|
1277
1450
|
//#endregion
|
|
1278
1451
|
//#region src/http.ts
|
|
1279
|
-
const MAX_RESPONSE_BYTES =
|
|
1452
|
+
const MAX_RESPONSE_BYTES = 65536;
|
|
1280
1453
|
async function requestJsonResponse(url, options) {
|
|
1281
1454
|
let response;
|
|
1282
1455
|
try {
|
|
@@ -1299,7 +1472,7 @@ async function requestJsonResponse(url, options) {
|
|
|
1299
1472
|
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
1300
1473
|
if (response.status >= 300 || response.status < 200 || contentType !== "application/json") {
|
|
1301
1474
|
const body = contentType === "application/json" ? await readJson(response, options.maxResponseBytes, options.signal) : void 0;
|
|
1302
|
-
response.body?.cancel().catch(() =>
|
|
1475
|
+
response.body?.cancel().catch(() => {});
|
|
1303
1476
|
throw (options.mapError ?? fromAuthorityError)(body, response.status, response.headers.get("retry-after"));
|
|
1304
1477
|
}
|
|
1305
1478
|
return {
|
|
@@ -1310,17 +1483,17 @@ async function requestJsonResponse(url, options) {
|
|
|
1310
1483
|
async function readJson(response, maximum = MAX_RESPONSE_BYTES, signal) {
|
|
1311
1484
|
const length = response.headers.get("content-length");
|
|
1312
1485
|
if (length && (!/^\d+$/.test(length) || Number(length) > maximum)) {
|
|
1313
|
-
response.body?.cancel().catch(() =>
|
|
1486
|
+
response.body?.cancel().catch(() => {});
|
|
1314
1487
|
throw authorityUnavailable();
|
|
1315
1488
|
}
|
|
1316
1489
|
if (!response.body) throw authorityUnavailable();
|
|
1317
1490
|
if (signal?.aborted) {
|
|
1318
|
-
response.body.cancel().catch(() =>
|
|
1491
|
+
response.body.cancel().catch(() => {});
|
|
1319
1492
|
throw authorityUnavailable();
|
|
1320
1493
|
}
|
|
1321
1494
|
const reader = response.body.getReader();
|
|
1322
1495
|
const cancel = () => {
|
|
1323
|
-
reader.cancel().catch(() =>
|
|
1496
|
+
reader.cancel().catch(() => {});
|
|
1324
1497
|
};
|
|
1325
1498
|
signal?.addEventListener("abort", cancel, { once: true });
|
|
1326
1499
|
const chunks = [];
|
|
@@ -1335,7 +1508,7 @@ async function readJson(response, maximum = MAX_RESPONSE_BYTES, signal) {
|
|
|
1335
1508
|
chunks.push(value);
|
|
1336
1509
|
}
|
|
1337
1510
|
} catch (error) {
|
|
1338
|
-
reader.cancel().catch(() =>
|
|
1511
|
+
reader.cancel().catch(() => {});
|
|
1339
1512
|
throw error;
|
|
1340
1513
|
} finally {
|
|
1341
1514
|
signal?.removeEventListener("abort", cancel);
|
|
@@ -1377,7 +1550,9 @@ const itemKeys$1 = [
|
|
|
1377
1550
|
"userAgent"
|
|
1378
1551
|
];
|
|
1379
1552
|
function exact$1(value, keys) {
|
|
1380
|
-
return isObject(value) && Object.keys(value).length === keys.length && keys.every((key) =>
|
|
1553
|
+
return isObject(value) && Object.keys(value).length === keys.length && keys.every((key) => {
|
|
1554
|
+
return Object.hasOwn(value, key);
|
|
1555
|
+
});
|
|
1381
1556
|
}
|
|
1382
1557
|
function date$1(value) {
|
|
1383
1558
|
if (typeof value !== "string") throw authorityUnavailable();
|
|
@@ -1410,8 +1585,12 @@ function normalizeSessionSummary(value) {
|
|
|
1410
1585
|
function normalizeSessionInventory(value) {
|
|
1411
1586
|
if (!exact$1(value, ["sessions", "truncated"]) || !Array.isArray(value.sessions) || value.sessions.length > MAX_SESSIONS || typeof value.truncated !== "boolean") throw authorityUnavailable();
|
|
1412
1587
|
const sessions = value.sessions.map(normalizeSessionSummary);
|
|
1413
|
-
if (new Set(sessions.map((session) =>
|
|
1414
|
-
|
|
1588
|
+
if (new Set(sessions.map((session) => {
|
|
1589
|
+
return session.id;
|
|
1590
|
+
})).size !== sessions.length) throw authorityUnavailable();
|
|
1591
|
+
if (sessions.filter((session) => {
|
|
1592
|
+
return session.current;
|
|
1593
|
+
}).length !== 1) throw authorityUnavailable();
|
|
1415
1594
|
return {
|
|
1416
1595
|
sessions,
|
|
1417
1596
|
truncated: value.truncated
|
|
@@ -1446,7 +1625,9 @@ const itemKeys = [
|
|
|
1446
1625
|
"name"
|
|
1447
1626
|
];
|
|
1448
1627
|
function exact(value, keys) {
|
|
1449
|
-
return isObject(value) && Object.keys(value).length === keys.length && keys.every((key) =>
|
|
1628
|
+
return isObject(value) && Object.keys(value).length === keys.length && keys.every((key) => {
|
|
1629
|
+
return Object.hasOwn(value, key);
|
|
1630
|
+
});
|
|
1450
1631
|
}
|
|
1451
1632
|
function date(value) {
|
|
1452
1633
|
if (typeof value !== "string") throw authorityUnavailable();
|
|
@@ -1519,6 +1700,11 @@ function normalizeCeremonyHandoffInput(value) {
|
|
|
1519
1700
|
}
|
|
1520
1701
|
throw new TypeError("request action is invalid");
|
|
1521
1702
|
}
|
|
1703
|
+
case "user_closure": return {
|
|
1704
|
+
purpose: input.purpose,
|
|
1705
|
+
...base,
|
|
1706
|
+
request: normalizeAccountDeletionStartRequest(input.request)
|
|
1707
|
+
};
|
|
1522
1708
|
default: throw new TypeError("purpose is invalid");
|
|
1523
1709
|
}
|
|
1524
1710
|
}
|
|
@@ -1563,7 +1749,9 @@ function normalizePasskeySummary(value) {
|
|
|
1563
1749
|
function normalizePasskeyInventory(value) {
|
|
1564
1750
|
if (!exact(value, ["passkeys", "truncated"]) || !Array.isArray(value.passkeys) || value.passkeys.length > MAX_PASSKEYS || typeof value.truncated !== "boolean") throw authorityUnavailable();
|
|
1565
1751
|
const passkeys = value.passkeys.map(normalizePasskeySummary);
|
|
1566
|
-
if (new Set(passkeys.map((passkey) =>
|
|
1752
|
+
if (new Set(passkeys.map((passkey) => {
|
|
1753
|
+
return passkey.id;
|
|
1754
|
+
})).size !== passkeys.length) throw authorityUnavailable();
|
|
1567
1755
|
return {
|
|
1568
1756
|
passkeys,
|
|
1569
1757
|
truncated: value.truncated
|
|
@@ -1580,6 +1768,7 @@ function fromCeremonyHandoffError(value, status, retryAfter) {
|
|
|
1580
1768
|
if (status === 403) return new AuthError("request_origin_denied", 403);
|
|
1581
1769
|
if (status === 404) return new AuthError("state_conflict", 409);
|
|
1582
1770
|
if (status === 409 && code === "PASSWORD_REQUIRED") return new AuthError("password_sign_in_required", 409);
|
|
1771
|
+
if (status === 409 && code === "RECENT_SIGN_IN_REQUIRED") return new AuthError("recent_sign_in_required", 409);
|
|
1583
1772
|
if (status === 409) return new AuthError("state_conflict", 409);
|
|
1584
1773
|
if (status === 429) return new AuthError("auth_request_rate_limited", 429, parseRetryAfter(retryAfter));
|
|
1585
1774
|
return authorityUnavailable();
|
|
@@ -1588,9 +1777,9 @@ function fromCeremonyHandoffError(value, status, retryAfter) {
|
|
|
1588
1777
|
//#region src/device.ts
|
|
1589
1778
|
const DEVICE_SCOPE = "openid";
|
|
1590
1779
|
const GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
1591
|
-
const MAX_TOKEN_BYTES =
|
|
1592
|
-
const MAX_POLLING_MS =
|
|
1593
|
-
const REFRESH_WINDOW_MS =
|
|
1780
|
+
const MAX_TOKEN_BYTES = 16377;
|
|
1781
|
+
const MAX_POLLING_MS = 9e5;
|
|
1782
|
+
const REFRESH_WINDOW_MS = 12e4;
|
|
1594
1783
|
const errorMessages = {
|
|
1595
1784
|
device_access_denied: "Device authorization was denied.",
|
|
1596
1785
|
device_authorization_cancelled: "Device authorization was cancelled.",
|
|
@@ -1615,7 +1804,7 @@ function createDeviceAuth(options) {
|
|
|
1615
1804
|
if (typeof requestFetch !== "function") throw new TypeError("fetch is required");
|
|
1616
1805
|
const now = options.now ?? Date.now;
|
|
1617
1806
|
const timeoutMs = normalizeTimeout(options.timeoutMs);
|
|
1618
|
-
const maxPollingMs = options.maxPollingMs ??
|
|
1807
|
+
const maxPollingMs = options.maxPollingMs ?? 6e5;
|
|
1619
1808
|
if (!Number.isSafeInteger(maxPollingMs) || maxPollingMs < 1 || maxPollingMs > MAX_POLLING_MS) throw new TypeError("maxPollingMs must be an integer from 1 to 900000");
|
|
1620
1809
|
let token = null;
|
|
1621
1810
|
let hydrated = false;
|
|
@@ -1629,10 +1818,12 @@ function createDeviceAuth(options) {
|
|
|
1629
1818
|
let persistenceTail = Promise.resolve();
|
|
1630
1819
|
let persistencePending = 0;
|
|
1631
1820
|
const userApiCredentials = createUserApiCredentialCache(async (applicationId) => {
|
|
1632
|
-
const authority = await serializeAuthority(async () =>
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1821
|
+
const authority = await serializeAuthority(async () => {
|
|
1822
|
+
return {
|
|
1823
|
+
current: await readToken(),
|
|
1824
|
+
generation: authorityGeneration
|
|
1825
|
+
};
|
|
1826
|
+
});
|
|
1636
1827
|
if (!authority.current) throw new AuthError("authentication_required", 401);
|
|
1637
1828
|
const response = await authenticated("user-api-credential", authority.current, { applicationId });
|
|
1638
1829
|
if (authority.generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
@@ -1651,7 +1842,7 @@ function createDeviceAuth(options) {
|
|
|
1651
1842
|
return operation();
|
|
1652
1843
|
};
|
|
1653
1844
|
const request = authorityTail.then(guardedOperation, guardedOperation);
|
|
1654
|
-
authorityTail = request.then(() =>
|
|
1845
|
+
authorityTail = request.then(() => {}, () => {});
|
|
1655
1846
|
return request;
|
|
1656
1847
|
}
|
|
1657
1848
|
async function readToken() {
|
|
@@ -1671,16 +1862,22 @@ function createDeviceAuth(options) {
|
|
|
1671
1862
|
}
|
|
1672
1863
|
async function hydrate() {
|
|
1673
1864
|
try {
|
|
1674
|
-
const persisted = options.persistence ? await persistenceCall((signal) =>
|
|
1865
|
+
const persisted = options.persistence ? await persistenceCall((signal) => {
|
|
1866
|
+
return options.persistence.read(signal);
|
|
1867
|
+
}) : null;
|
|
1675
1868
|
let loaded;
|
|
1676
1869
|
try {
|
|
1677
1870
|
loaded = normalizeToken(persisted, now());
|
|
1678
1871
|
} catch {
|
|
1679
1872
|
token = null;
|
|
1680
|
-
if (options.persistence && persisted !== null) await persistenceCall((signal) =>
|
|
1873
|
+
if (options.persistence && persisted !== null) await persistenceCall((signal) => {
|
|
1874
|
+
return options.persistence.delete(signal);
|
|
1875
|
+
}).catch(() => {});
|
|
1681
1876
|
throw unavailable();
|
|
1682
1877
|
}
|
|
1683
|
-
if (options.persistence && persisted !== null && !loaded) await persistenceCall((signal) =>
|
|
1878
|
+
if (options.persistence && persisted !== null && !loaded) await persistenceCall((signal) => {
|
|
1879
|
+
return options.persistence.delete(signal);
|
|
1880
|
+
});
|
|
1684
1881
|
token = loaded;
|
|
1685
1882
|
} catch (error) {
|
|
1686
1883
|
token = null;
|
|
@@ -1703,7 +1900,9 @@ function createDeviceAuth(options) {
|
|
|
1703
1900
|
scope: DEVICE_SCOPE
|
|
1704
1901
|
},
|
|
1705
1902
|
signal: requestOptions.signal,
|
|
1706
|
-
mapError: () =>
|
|
1903
|
+
mapError: () => {
|
|
1904
|
+
return invalid();
|
|
1905
|
+
}
|
|
1707
1906
|
})).value, now());
|
|
1708
1907
|
} catch (error) {
|
|
1709
1908
|
if (requestOptions.signal?.aborted) throw cancelled();
|
|
@@ -1760,7 +1959,7 @@ function createDeviceAuth(options) {
|
|
|
1760
1959
|
next = normalizeTokenResponse(response.value, now());
|
|
1761
1960
|
} catch {
|
|
1762
1961
|
if (recoverableAccessToken) await revokeToken(recoverableAccessToken);
|
|
1763
|
-
await clearToken().catch(() =>
|
|
1962
|
+
await clearToken().catch(() => {});
|
|
1764
1963
|
throw unavailable();
|
|
1765
1964
|
}
|
|
1766
1965
|
try {
|
|
@@ -1821,6 +2020,22 @@ function createDeviceAuth(options) {
|
|
|
1821
2020
|
mapError: fromCeremonyHandoffError
|
|
1822
2021
|
})).value);
|
|
1823
2022
|
}
|
|
2023
|
+
async function accountDeletionRequest(method, path, body, normalize, bearer) {
|
|
2024
|
+
const current = bearer ? await readToken() : void 0;
|
|
2025
|
+
if (bearer && !current) throw new AuthError("authentication_required", 401);
|
|
2026
|
+
return normalize((await requestJsonResponse(joinURL(authOrigin, "api/v1/auth/user/closure", path), {
|
|
2027
|
+
fetch: requestFetch,
|
|
2028
|
+
timeoutMs,
|
|
2029
|
+
method,
|
|
2030
|
+
credentials: "omit",
|
|
2031
|
+
headers: {
|
|
2032
|
+
...current ? { authorization: `Bearer ${current.accessToken}` } : {},
|
|
2033
|
+
...body ? { "content-type": "application/json" } : {}
|
|
2034
|
+
},
|
|
2035
|
+
...body ? { body } : {},
|
|
2036
|
+
mapError: fromAccountDeletionError
|
|
2037
|
+
})).value);
|
|
2038
|
+
}
|
|
1824
2039
|
async function revoke(path) {
|
|
1825
2040
|
const current = await readToken();
|
|
1826
2041
|
if (!current) return;
|
|
@@ -1844,7 +2059,9 @@ function createDeviceAuth(options) {
|
|
|
1844
2059
|
}
|
|
1845
2060
|
async function replaceToken(next) {
|
|
1846
2061
|
try {
|
|
1847
|
-
if (options.persistence) await persistenceCall((signal) =>
|
|
2062
|
+
if (options.persistence) await persistenceCall((signal) => {
|
|
2063
|
+
return options.persistence.replace(copyToken(next), signal);
|
|
2064
|
+
});
|
|
1848
2065
|
} catch {
|
|
1849
2066
|
throw unavailable();
|
|
1850
2067
|
}
|
|
@@ -1896,7 +2113,7 @@ function createDeviceAuth(options) {
|
|
|
1896
2113
|
credentials: "omit",
|
|
1897
2114
|
headers: { authorization: `Bearer ${accessToken}` },
|
|
1898
2115
|
body: { token: accessToken }
|
|
1899
|
-
}).catch(() =>
|
|
2116
|
+
}).catch(() => {});
|
|
1900
2117
|
}
|
|
1901
2118
|
async function clearToken() {
|
|
1902
2119
|
token = null;
|
|
@@ -1928,7 +2145,7 @@ function createDeviceAuth(options) {
|
|
|
1928
2145
|
hydrated = true;
|
|
1929
2146
|
authorityGeneration += 1;
|
|
1930
2147
|
clearCredential();
|
|
1931
|
-
await removePersisted().catch(() =>
|
|
2148
|
+
await removePersisted().catch(() => {});
|
|
1932
2149
|
}
|
|
1933
2150
|
async function accountRequest(path, body, mapError = fromAccountAuthorityError) {
|
|
1934
2151
|
clearCredential();
|
|
@@ -1965,7 +2182,7 @@ function createDeviceAuth(options) {
|
|
|
1965
2182
|
hydrated = true;
|
|
1966
2183
|
authorityGeneration += 1;
|
|
1967
2184
|
clearCredential();
|
|
1968
|
-
await removePersisted().catch(() =>
|
|
2185
|
+
await removePersisted().catch(() => {});
|
|
1969
2186
|
throw unavailable();
|
|
1970
2187
|
}
|
|
1971
2188
|
return session;
|
|
@@ -1981,13 +2198,15 @@ function createDeviceAuth(options) {
|
|
|
1981
2198
|
credentials: "omit",
|
|
1982
2199
|
headers: { authorization: `Bearer ${current.accessToken}` },
|
|
1983
2200
|
mapError: fromOrganizationReadAuthorityError,
|
|
1984
|
-
maxResponseBytes:
|
|
2201
|
+
maxResponseBytes: 262144
|
|
1985
2202
|
})).value);
|
|
1986
2203
|
}
|
|
1987
2204
|
async function removePersisted() {
|
|
1988
2205
|
if (!options.persistence) return;
|
|
1989
2206
|
try {
|
|
1990
|
-
await persistenceCall((signal) =>
|
|
2207
|
+
await persistenceCall((signal) => {
|
|
2208
|
+
return options.persistence.delete(signal);
|
|
2209
|
+
});
|
|
1991
2210
|
} catch {
|
|
1992
2211
|
throw unavailable();
|
|
1993
2212
|
}
|
|
@@ -2005,14 +2224,28 @@ function createDeviceAuth(options) {
|
|
|
2005
2224
|
} catch (error) {
|
|
2006
2225
|
return Promise.reject(error);
|
|
2007
2226
|
}
|
|
2008
|
-
return serializeAuthority(() =>
|
|
2227
|
+
return serializeAuthority(() => {
|
|
2228
|
+
return pollForToken(snapshot, signal);
|
|
2229
|
+
}, true);
|
|
2230
|
+
},
|
|
2231
|
+
getToken: () => {
|
|
2232
|
+
return serializeAuthority(async () => {
|
|
2233
|
+
return copyTokenOrNull(await readToken());
|
|
2234
|
+
});
|
|
2235
|
+
},
|
|
2236
|
+
getSession: () => {
|
|
2237
|
+
return serializeAuthority(getSession, true);
|
|
2238
|
+
},
|
|
2239
|
+
listOrganizations: (input) => {
|
|
2240
|
+
return serializeAuthority(() => {
|
|
2241
|
+
return organizationRead("", input, normalizeOrganizations);
|
|
2242
|
+
});
|
|
2009
2243
|
},
|
|
2010
|
-
getToken: () => serializeAuthority(async () => copyTokenOrNull(await readToken())),
|
|
2011
|
-
getSession: () => serializeAuthority(getSession, true),
|
|
2012
|
-
listOrganizations: (input) => serializeAuthority(() => organizationRead("", input, normalizeOrganizations)),
|
|
2013
2244
|
getOrganization(organizationId) {
|
|
2014
2245
|
try {
|
|
2015
|
-
return serializeAuthority(() =>
|
|
2246
|
+
return serializeAuthority(() => {
|
|
2247
|
+
return organizationRead(normalizeIdInput(organizationId), void 0, normalizeOrganization);
|
|
2248
|
+
});
|
|
2016
2249
|
} catch (error) {
|
|
2017
2250
|
return Promise.reject(error);
|
|
2018
2251
|
}
|
|
@@ -2020,12 +2253,22 @@ function createDeviceAuth(options) {
|
|
|
2020
2253
|
async getOrganizationMemberAuthority(organizationId, memberId) {
|
|
2021
2254
|
const organization = normalizeIdInput(organizationId);
|
|
2022
2255
|
const member = normalizeIdInput(memberId);
|
|
2023
|
-
return serializeAuthority(() =>
|
|
2256
|
+
return serializeAuthority(() => {
|
|
2257
|
+
return organizationRead(`${organization}/members/${member}/authority`, void 0, (value) => {
|
|
2258
|
+
return normalizeOrganizationMemberAuthority(value, organization, member);
|
|
2259
|
+
});
|
|
2260
|
+
});
|
|
2024
2261
|
},
|
|
2025
2262
|
async getOrganizationMemberAuthorityV2(organizationId, memberId) {
|
|
2026
2263
|
const organization = normalizeIdInput(organizationId);
|
|
2027
2264
|
const member = normalizeIdInput(memberId);
|
|
2028
|
-
return serializeAuthority(() =>
|
|
2265
|
+
return serializeAuthority(() => {
|
|
2266
|
+
return organizationRead(`${organization}/members/${member}/authority`, void 0, (value) => {
|
|
2267
|
+
return normalizeOrganizationMemberAuthorityV2(value, organization, member);
|
|
2268
|
+
}, () => {
|
|
2269
|
+
return new URLSearchParams({ version: "2" });
|
|
2270
|
+
});
|
|
2271
|
+
});
|
|
2029
2272
|
},
|
|
2030
2273
|
createOrganization(name, slug, idempotencyKey) {
|
|
2031
2274
|
let body;
|
|
@@ -2159,43 +2402,59 @@ function createDeviceAuth(options) {
|
|
|
2159
2402
|
},
|
|
2160
2403
|
listOrganizationMembers(organizationId, input) {
|
|
2161
2404
|
try {
|
|
2162
|
-
return serializeAuthority(() =>
|
|
2405
|
+
return serializeAuthority(() => {
|
|
2406
|
+
return organizationRead(`${normalizeIdInput(organizationId)}/members`, input, normalizeOrganizationMembers, normalizeOrganizationMemberPageInput);
|
|
2407
|
+
});
|
|
2163
2408
|
} catch (error) {
|
|
2164
2409
|
return Promise.reject(error);
|
|
2165
2410
|
}
|
|
2166
2411
|
},
|
|
2167
2412
|
listOrganizationTeams(organizationId, input) {
|
|
2168
2413
|
try {
|
|
2169
|
-
return serializeAuthority(() =>
|
|
2414
|
+
return serializeAuthority(() => {
|
|
2415
|
+
return organizationRead(`${normalizeIdInput(organizationId)}/teams`, input, normalizeOrganizationTeams);
|
|
2416
|
+
});
|
|
2170
2417
|
} catch (error) {
|
|
2171
2418
|
return Promise.reject(error);
|
|
2172
2419
|
}
|
|
2173
2420
|
},
|
|
2174
2421
|
listOrganizationTeamMembers(organizationId, teamId, input) {
|
|
2175
2422
|
try {
|
|
2176
|
-
return serializeAuthority(() =>
|
|
2423
|
+
return serializeAuthority(() => {
|
|
2424
|
+
return organizationRead(`${normalizeIdInput(organizationId)}/teams/${normalizeIdInput(teamId)}/members`, input, normalizeOrganizationTeamMembers);
|
|
2425
|
+
});
|
|
2177
2426
|
} catch (error) {
|
|
2178
2427
|
return Promise.reject(error);
|
|
2179
2428
|
}
|
|
2180
2429
|
},
|
|
2181
2430
|
listOrganizationInvitations(organizationId, input) {
|
|
2182
2431
|
try {
|
|
2183
|
-
return serializeAuthority(() =>
|
|
2432
|
+
return serializeAuthority(() => {
|
|
2433
|
+
return organizationRead(`${normalizeIdInput(organizationId)}/invitations`, input, normalizeOrganizationInvitations);
|
|
2434
|
+
});
|
|
2184
2435
|
} catch (error) {
|
|
2185
2436
|
return Promise.reject(error);
|
|
2186
2437
|
}
|
|
2187
2438
|
},
|
|
2188
2439
|
getOrganizationInvitation(organizationId, invitationId) {
|
|
2189
2440
|
try {
|
|
2190
|
-
return serializeAuthority(() =>
|
|
2441
|
+
return serializeAuthority(() => {
|
|
2442
|
+
return organizationRead(`${normalizeIdInput(organizationId)}/invitations/${normalizeIdInput(invitationId)}`, void 0, normalizeOrganizationInvitation);
|
|
2443
|
+
});
|
|
2191
2444
|
} catch (error) {
|
|
2192
2445
|
return Promise.reject(error);
|
|
2193
2446
|
}
|
|
2194
2447
|
},
|
|
2195
|
-
listReceivedInvitations: (input) =>
|
|
2448
|
+
listReceivedInvitations: (input) => {
|
|
2449
|
+
return serializeAuthority(() => {
|
|
2450
|
+
return organizationRead("received-invitations", input, normalizeReceivedInvitations);
|
|
2451
|
+
});
|
|
2452
|
+
},
|
|
2196
2453
|
getReceivedInvitation(invitationId) {
|
|
2197
2454
|
try {
|
|
2198
|
-
return serializeAuthority(() =>
|
|
2455
|
+
return serializeAuthority(() => {
|
|
2456
|
+
return organizationRead(`received-invitations/${normalizeIdInput(invitationId)}`, void 0, normalizeReceivedInvitation);
|
|
2457
|
+
});
|
|
2199
2458
|
} catch (error) {
|
|
2200
2459
|
return Promise.reject(error);
|
|
2201
2460
|
}
|
|
@@ -2234,7 +2493,9 @@ function createDeviceAuth(options) {
|
|
|
2234
2493
|
}, true);
|
|
2235
2494
|
},
|
|
2236
2495
|
listSessions() {
|
|
2237
|
-
return serializeAuthority(() =>
|
|
2496
|
+
return serializeAuthority(() => {
|
|
2497
|
+
return sessionInventoryRequest("GET", "", normalizeSessionInventory);
|
|
2498
|
+
});
|
|
2238
2499
|
},
|
|
2239
2500
|
revokeSession(sessionId) {
|
|
2240
2501
|
let id;
|
|
@@ -2248,7 +2509,9 @@ function createDeviceAuth(options) {
|
|
|
2248
2509
|
});
|
|
2249
2510
|
},
|
|
2250
2511
|
revokeOtherSessions() {
|
|
2251
|
-
return serializeAuthority(() =>
|
|
2512
|
+
return serializeAuthority(() => {
|
|
2513
|
+
return sessionInventoryRequest("POST", "revoke-others", normalizeOtherSessionRevocation);
|
|
2514
|
+
});
|
|
2252
2515
|
},
|
|
2253
2516
|
createCeremonyHandoff(input) {
|
|
2254
2517
|
let body;
|
|
@@ -2257,10 +2520,22 @@ function createDeviceAuth(options) {
|
|
|
2257
2520
|
} catch (error) {
|
|
2258
2521
|
return Promise.reject(error);
|
|
2259
2522
|
}
|
|
2260
|
-
return serializeAuthority(() =>
|
|
2523
|
+
return serializeAuthority(() => {
|
|
2524
|
+
return ceremonyRequest("POST", "ceremony-handoffs", body, normalizeCeremonyHandoff);
|
|
2525
|
+
});
|
|
2526
|
+
},
|
|
2527
|
+
getAccountDeletionEligibility() {
|
|
2528
|
+
return serializeAuthority(() => {
|
|
2529
|
+
return accountDeletionRequest("GET", "eligibility", void 0, normalizeAccountDeletionEligibility, true);
|
|
2530
|
+
});
|
|
2531
|
+
},
|
|
2532
|
+
async restoreAccount(input) {
|
|
2533
|
+
await accountDeletionRequest("POST", "restore", normalizeAccountDeletionRestoreInput(input), normalizeAccountDeletionRestore, false);
|
|
2261
2534
|
},
|
|
2262
2535
|
listPasskeys() {
|
|
2263
|
-
return serializeAuthority(() =>
|
|
2536
|
+
return serializeAuthority(() => {
|
|
2537
|
+
return ceremonyRequest("GET", "passkeys", void 0, normalizePasskeyInventory);
|
|
2538
|
+
});
|
|
2264
2539
|
},
|
|
2265
2540
|
renamePasskey(passkeyId, name) {
|
|
2266
2541
|
let path;
|
|
@@ -2432,15 +2707,25 @@ function createDeviceAuth(options) {
|
|
|
2432
2707
|
};
|
|
2433
2708
|
return request;
|
|
2434
2709
|
},
|
|
2435
|
-
revokeCurrentDevice: () =>
|
|
2436
|
-
|
|
2710
|
+
revokeCurrentDevice: () => {
|
|
2711
|
+
return serializeAuthority(() => {
|
|
2712
|
+
return revoke("revoke-session");
|
|
2713
|
+
}, true);
|
|
2714
|
+
},
|
|
2715
|
+
revokeAllSessions: () => {
|
|
2716
|
+
return serializeAuthority(() => {
|
|
2717
|
+
return revoke("revoke-sessions");
|
|
2718
|
+
}, true);
|
|
2719
|
+
}
|
|
2437
2720
|
};
|
|
2438
2721
|
async function persistenceCall(operation) {
|
|
2439
2722
|
const operationTimeoutMs = Math.min(timeoutMs, 1e3);
|
|
2440
2723
|
persistencePending += 1;
|
|
2441
2724
|
const settledRequest = persistenceTail.then(async () => {
|
|
2442
2725
|
const controller = new AbortController();
|
|
2443
|
-
const timer = setTimeout(() =>
|
|
2726
|
+
const timer = setTimeout(() => {
|
|
2727
|
+
return controller.abort();
|
|
2728
|
+
}, operationTimeoutMs);
|
|
2444
2729
|
try {
|
|
2445
2730
|
return await operation(controller.signal);
|
|
2446
2731
|
} finally {
|
|
@@ -2449,13 +2734,15 @@ function createDeviceAuth(options) {
|
|
|
2449
2734
|
}).finally(() => {
|
|
2450
2735
|
persistencePending -= 1;
|
|
2451
2736
|
});
|
|
2452
|
-
persistenceTail = settledRequest.then(() =>
|
|
2737
|
+
persistenceTail = settledRequest.then(() => {}, () => {});
|
|
2453
2738
|
let publicTimer;
|
|
2454
2739
|
try {
|
|
2455
2740
|
return await Promise.race([settledRequest.catch(() => {
|
|
2456
2741
|
throw unavailable();
|
|
2457
2742
|
}), new Promise((_, reject) => {
|
|
2458
|
-
publicTimer = setTimeout(() =>
|
|
2743
|
+
publicTimer = setTimeout(() => {
|
|
2744
|
+
return reject(unavailable());
|
|
2745
|
+
}, operationTimeoutMs);
|
|
2459
2746
|
})]);
|
|
2460
2747
|
} finally {
|
|
2461
2748
|
if (publicTimer) clearTimeout(publicTimer);
|
|
@@ -2466,8 +2753,10 @@ function copyTokenOrNull(value) {
|
|
|
2466
2753
|
return value ? copyToken(value) : null;
|
|
2467
2754
|
}
|
|
2468
2755
|
function normalizePollSignal(value) {
|
|
2469
|
-
if (value === void 0) return
|
|
2470
|
-
if (!isObject(value) || Object.keys(value).some((key) =>
|
|
2756
|
+
if (value === void 0) return;
|
|
2757
|
+
if (!isObject(value) || Object.keys(value).some((key) => {
|
|
2758
|
+
return key !== "signal";
|
|
2759
|
+
}) || value.signal !== void 0 && !(value.signal instanceof AbortSignal)) throw new TypeError("poll options are invalid");
|
|
2471
2760
|
return value.signal;
|
|
2472
2761
|
}
|
|
2473
2762
|
var DeviceProtocolError = class extends Error {
|
|
@@ -2500,7 +2789,7 @@ function normalizeAuthorizationInput(value, currentTime) {
|
|
|
2500
2789
|
};
|
|
2501
2790
|
}
|
|
2502
2791
|
function normalizeTokenResponse(value, currentTime) {
|
|
2503
|
-
if (!isObject(value) || !boundedSecret(value.access_token) || value.token_type !== "Bearer" || value.scope !== DEVICE_SCOPE || !Number.isSafeInteger(value.expires_in) || value.expires_in < 1 || value.expires_in >
|
|
2792
|
+
if (!isObject(value) || !boundedSecret(value.access_token) || value.token_type !== "Bearer" || value.scope !== DEVICE_SCOPE || !Number.isSafeInteger(value.expires_in) || value.expires_in < 1 || value.expires_in > 2678400) throw unavailable();
|
|
2504
2793
|
return {
|
|
2505
2794
|
accessToken: value.access_token,
|
|
2506
2795
|
tokenType: "Bearer",
|