@finueva/auth 0.13.0 → 0.14.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/server.d.ts +19 -1
- package/dist/server.js +543 -439
- package/package.json +1 -1
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import { A as PersonalWorkspaceSelection, C as OrganizationPage, D as OrganizationTeamMemberPage, E as OrganizationTeamDisplay, G as SocialIdTokenProvider, K as UpdateOrganizationDisplayInput, O as OrganizationTeamPage, Q as AuthErrorStatus, R as ReceivedOrganizationInvitation, S as OrganizationMemberPage, T as OrganizationTeam, V as ResentOrganizationInvitation, W as SocialIdTokenInput, X as AuthError, Y as WorkspaceSelection, Z as AuthErrorCode, _ as OrganizationDisplay, b as OrganizationMember, c as AuthUser, d as CreatedOrganizationMemberInvitation, f as CreatedOrganizationTeam, g as InvitationAcceptance, k as OrganizationWorkspaceSelection, l as CanceledOrganizationInvitation, m as DriveCredentialInput, o as AuthSession, p as DriveCredential, q as UpdateOrganizationTeamDisplayInput, r as AuthOrganization, t as AcceptInvitationInput, u as CreateOrganizationMemberInvitationInput, v as OrganizationInvitation, w as OrganizationPageInput, x as OrganizationMemberAuthority, y as OrganizationInvitationPage, z as ReceivedOrganizationInvitationPage } from "./types-Dsu3nEaN.js";
|
|
2
|
+
//#region src/provisioning.d.ts
|
|
3
|
+
interface DriveProvisioningAuthOptions {
|
|
4
|
+
authOrigin: string;
|
|
5
|
+
fetch?: typeof globalThis.fetch;
|
|
6
|
+
now?: () => number;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
}
|
|
9
|
+
interface DriveProvisioningCredential {
|
|
10
|
+
tokenType: "Bearer";
|
|
11
|
+
token: string;
|
|
12
|
+
expiresAt: Date;
|
|
13
|
+
}
|
|
14
|
+
interface FinuevaDriveProvisioningAuth {
|
|
15
|
+
getDriveProvisioningCredential(clientAssertion: string): Promise<DriveProvisioningCredential>;
|
|
16
|
+
}
|
|
17
|
+
/** Service authority only. Never pass an incoming User request or session to this client. */
|
|
18
|
+
declare function createDriveProvisioningAuth(options: DriveProvisioningAuthOptions): FinuevaDriveProvisioningAuth;
|
|
19
|
+
//#endregion
|
|
2
20
|
//#region src/server.d.ts
|
|
3
21
|
interface ServerAuthOptions {
|
|
4
22
|
authOrigin: string;
|
|
@@ -42,4 +60,4 @@ interface FinuevaServerAuth {
|
|
|
42
60
|
}
|
|
43
61
|
declare function createServerAuth(options: ServerAuthOptions): FinuevaServerAuth;
|
|
44
62
|
//#endregion
|
|
45
|
-
export { type AcceptInvitationInput, AuthError, type AuthErrorCode, type AuthErrorStatus, type AuthOrganization, type AuthSession, type AuthUser, type CanceledOrganizationInvitation, type CreateOrganizationMemberInvitationInput, type CreatedOrganizationMemberInvitation, type CreatedOrganizationTeam, type DriveCredential, type DriveCredentialInput, FinuevaServerAuth, type InvitationAcceptance, type OrganizationDisplay, type OrganizationInvitation, type OrganizationInvitationPage, type OrganizationMember, type OrganizationMemberAuthority, type OrganizationMemberPage, type OrganizationPage, type OrganizationPageInput, type OrganizationTeam, type OrganizationTeamDisplay, type OrganizationTeamMemberPage, type OrganizationTeamPage, type OrganizationWorkspaceSelection, type PersonalWorkspaceSelection, type ReceivedOrganizationInvitation, type ReceivedOrganizationInvitationPage, type ResentOrganizationInvitation, ServerAuthOptions, ServerInvitationAcceptance, ServerSignOutResult, ServerSocialIdTokenSession, type SocialIdTokenInput, type SocialIdTokenProvider, type UpdateOrganizationDisplayInput, type UpdateOrganizationTeamDisplayInput, type WorkspaceSelection, createServerAuth };
|
|
63
|
+
export { type AcceptInvitationInput, AuthError, type AuthErrorCode, type AuthErrorStatus, type AuthOrganization, type AuthSession, type AuthUser, type CanceledOrganizationInvitation, type CreateOrganizationMemberInvitationInput, type CreatedOrganizationMemberInvitation, type CreatedOrganizationTeam, type DriveCredential, type DriveCredentialInput, type DriveProvisioningAuthOptions, type DriveProvisioningCredential, type FinuevaDriveProvisioningAuth, FinuevaServerAuth, type InvitationAcceptance, type OrganizationDisplay, type OrganizationInvitation, type OrganizationInvitationPage, type OrganizationMember, type OrganizationMemberAuthority, type OrganizationMemberPage, type OrganizationPage, type OrganizationPageInput, type OrganizationTeam, type OrganizationTeamDisplay, type OrganizationTeamMemberPage, type OrganizationTeamPage, type OrganizationWorkspaceSelection, type PersonalWorkspaceSelection, type ReceivedOrganizationInvitation, type ReceivedOrganizationInvitationPage, type ResentOrganizationInvitation, ServerAuthOptions, ServerInvitationAcceptance, ServerSignOutResult, ServerSocialIdTokenSession, type SocialIdTokenInput, type SocialIdTokenProvider, type UpdateOrganizationDisplayInput, type UpdateOrganizationTeamDisplayInput, type WorkspaceSelection, createDriveProvisioningAuth, createServerAuth };
|
package/dist/server.js
CHANGED
|
@@ -211,477 +211,214 @@ var AuthError = class extends Error {
|
|
|
211
211
|
}
|
|
212
212
|
};
|
|
213
213
|
//#endregion
|
|
214
|
-
//#region
|
|
215
|
-
const
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return
|
|
214
|
+
//#region src/shared.ts
|
|
215
|
+
const DRIVE_CREDENTIAL_LIFETIME_SECONDS = 840;
|
|
216
|
+
const id = /^[A-Za-z0-9_-]{1,128}$/;
|
|
217
|
+
const email = /^[^\s@]+@[^\s@]+$/;
|
|
218
|
+
const MAX_SOCIAL_ID_TOKEN_BYTES = 16 * 1024;
|
|
219
|
+
function normalizeEmail(value) {
|
|
220
|
+
if (typeof value !== "string") throw new TypeError("email is invalid");
|
|
221
|
+
const normalized = value.trim().toLowerCase();
|
|
222
|
+
if (normalized.length === 0 || normalized.length > 320 || !email.test(normalized)) throw new TypeError("email is invalid");
|
|
223
|
+
return normalized;
|
|
224
224
|
}
|
|
225
|
-
function
|
|
226
|
-
|
|
225
|
+
function normalizeSocialIdTokenInput(value) {
|
|
226
|
+
if (!isObject(value)) throw new TypeError("social ID token input is invalid");
|
|
227
|
+
const keys = Object.keys(value);
|
|
228
|
+
if (keys.length !== 3 && keys.length !== 4 || keys.some((key) => key !== "provider" && key !== "idToken" && key !== "nonce" && key !== "signUp") || 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");
|
|
229
|
+
return {
|
|
230
|
+
provider: value.provider,
|
|
231
|
+
idToken: value.idToken,
|
|
232
|
+
...value.nonce === void 0 ? {} : { nonce: value.nonce },
|
|
233
|
+
signUp: value.signUp
|
|
234
|
+
};
|
|
227
235
|
}
|
|
228
|
-
function
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (!JsonSigRx.test(value)) {
|
|
242
|
-
if (options.strict) throw new SyntaxError("[destr] Invalid JSON");
|
|
243
|
-
return value;
|
|
244
|
-
}
|
|
236
|
+
function socialIdTokenRequest(value) {
|
|
237
|
+
return {
|
|
238
|
+
provider: value.provider,
|
|
239
|
+
idToken: {
|
|
240
|
+
token: value.idToken,
|
|
241
|
+
...value.nonce === void 0 ? {} : { nonce: value.nonce }
|
|
242
|
+
},
|
|
243
|
+
requestSignUp: value.signUp
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function normalizeOrigin(value, name) {
|
|
247
|
+
if (value.length === 0 || value.length > 2048 || /[^\x20-\x7e]/.test(value)) throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
248
|
+
let url;
|
|
245
249
|
try {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
return JSON.parse(value);
|
|
251
|
-
} catch (error) {
|
|
252
|
-
if (options.strict) throw error;
|
|
253
|
-
return value;
|
|
250
|
+
url = new URL(value);
|
|
251
|
+
} catch {
|
|
252
|
+
throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
254
253
|
}
|
|
254
|
+
const local = url.hostname === "localhost" || url.hostname.endsWith(".localhost") || url.hostname === "127.0.0.1";
|
|
255
|
+
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`);
|
|
256
|
+
return url.origin;
|
|
255
257
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
super(message, opts);
|
|
261
|
-
this.name = "FetchError";
|
|
262
|
-
if (opts?.cause && !this.cause) this.cause = opts.cause;
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
function createFetchError(ctx) {
|
|
266
|
-
const errorMessage = ctx.error?.message || ctx.error?.toString() || "";
|
|
267
|
-
const method = ctx.request?.method || ctx.options?.method || "GET";
|
|
268
|
-
const url = ctx.request?.url || String(ctx.request) || "/";
|
|
269
|
-
const fetchError = new FetchError(`${`[${method}] ${JSON.stringify(url)}`}: ${ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : "<no response>"}${errorMessage ? ` ${errorMessage}` : ""}`, ctx.error ? { cause: ctx.error } : void 0);
|
|
270
|
-
for (const key of [
|
|
271
|
-
"request",
|
|
272
|
-
"options",
|
|
273
|
-
"response"
|
|
274
|
-
]) Object.defineProperty(fetchError, key, { get() {
|
|
275
|
-
return ctx[key];
|
|
276
|
-
} });
|
|
277
|
-
for (const [key, refKey] of [
|
|
278
|
-
["data", "_data"],
|
|
279
|
-
["status", "status"],
|
|
280
|
-
["statusCode", "status"],
|
|
281
|
-
["statusText", "statusText"],
|
|
282
|
-
["statusMessage", "statusText"]
|
|
283
|
-
]) Object.defineProperty(fetchError, key, { get() {
|
|
284
|
-
return ctx.response && ctx.response[refKey];
|
|
285
|
-
} });
|
|
286
|
-
return fetchError;
|
|
258
|
+
function normalizeTimeout(value) {
|
|
259
|
+
const timeout = value ?? 1e4;
|
|
260
|
+
if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 6e4) throw new TypeError("timeoutMs must be an integer from 1 to 60000");
|
|
261
|
+
return timeout;
|
|
287
262
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
263
|
+
function normalizeSession(value) {
|
|
264
|
+
if (value === null) return null;
|
|
265
|
+
if (!isObject(value) || !isObject(value.session) || !isObject(value.user)) throw authorityUnavailable();
|
|
266
|
+
const expiresAt = toDate(value.session.expiresAt);
|
|
267
|
+
const image = value.user.image;
|
|
268
|
+
if (!isId(value.session.id) || !expiresAt || !isId(value.user.id) || typeof value.user.name !== "string" || value.user.name.length > 256 || typeof value.user.email !== "string" || value.user.email.length > 320 || !email.test(value.user.email) || typeof value.user.emailVerified !== "boolean" || image !== null && image !== void 0 && (typeof image !== "string" || image.length > 2048)) throw authorityUnavailable();
|
|
269
|
+
return {
|
|
270
|
+
id: value.session.id,
|
|
271
|
+
expiresAt,
|
|
272
|
+
user: {
|
|
273
|
+
id: value.user.id,
|
|
274
|
+
name: value.user.name,
|
|
275
|
+
email: value.user.email,
|
|
276
|
+
emailVerified: value.user.emailVerified,
|
|
277
|
+
image: image ?? null
|
|
278
|
+
}
|
|
279
|
+
};
|
|
296
280
|
}
|
|
297
|
-
function
|
|
298
|
-
if (value ===
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (value instanceof FormData || value instanceof URLSearchParams) return false;
|
|
305
|
-
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
|
|
281
|
+
function normalizeDriveCredential(value, now) {
|
|
282
|
+
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 > 16 * 1024) throw authorityUnavailable();
|
|
283
|
+
return {
|
|
284
|
+
tokenType: "Bearer",
|
|
285
|
+
token: value.token,
|
|
286
|
+
expiresAt: new Date(now + value.expiresIn * 1e3)
|
|
287
|
+
};
|
|
306
288
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
"
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
return
|
|
289
|
+
function normalizeOrganizationPageInput(value) {
|
|
290
|
+
if (value === void 0) return new URLSearchParams();
|
|
291
|
+
if (!isObject(value) || Object.keys(value).some((key) => key !== "limit" && key !== "cursor")) throw new AuthError("invalid_request", 400);
|
|
292
|
+
const input = value;
|
|
293
|
+
const query = new URLSearchParams();
|
|
294
|
+
if (input.limit !== void 0) {
|
|
295
|
+
if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 100) throw new AuthError("invalid_request", 400);
|
|
296
|
+
query.set("limit", String(input.limit));
|
|
297
|
+
}
|
|
298
|
+
if (input.cursor !== void 0) {
|
|
299
|
+
if (typeof input.cursor !== "string" || input.cursor.length < 1 || input.cursor.length > 820 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(input.cursor)) throw new AuthError("invalid_request", 400);
|
|
300
|
+
query.set("cursor", input.cursor);
|
|
301
|
+
}
|
|
302
|
+
return query;
|
|
321
303
|
}
|
|
322
|
-
function
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
304
|
+
function normalizeIdInput(value) {
|
|
305
|
+
if (!isId(value)) throw new AuthError("invalid_request", 400);
|
|
306
|
+
return value;
|
|
307
|
+
}
|
|
308
|
+
function normalizeOrganization(value) {
|
|
309
|
+
exact(value, [
|
|
310
|
+
"capabilities",
|
|
311
|
+
"id",
|
|
312
|
+
"lifecycle",
|
|
313
|
+
"logo",
|
|
314
|
+
"name",
|
|
315
|
+
"role",
|
|
316
|
+
"slug"
|
|
317
|
+
]);
|
|
318
|
+
if (!isId(value.id) || !boundedString(value.name, 255) || !boundedString(value.slug, 255) || value.lifecycle !== "ordinary" && value.lifecycle !== "managed" || !role(value.role) || !isObject(value.capabilities)) throw authorityUnavailable();
|
|
319
|
+
exact(value.capabilities, [
|
|
320
|
+
"readInvitations",
|
|
321
|
+
"readMembers",
|
|
322
|
+
"readTeams"
|
|
323
|
+
]);
|
|
324
|
+
if (value.capabilities.readMembers !== true || value.capabilities.readTeams !== true || typeof value.capabilities.readInvitations !== "boolean") throw authorityUnavailable();
|
|
325
|
+
return {
|
|
326
|
+
id: value.id,
|
|
327
|
+
name: value.name,
|
|
328
|
+
slug: value.slug,
|
|
329
|
+
logo: nullableHttpsUrl(value.logo),
|
|
330
|
+
lifecycle: value.lifecycle,
|
|
331
|
+
role: value.role,
|
|
332
|
+
capabilities: {
|
|
333
|
+
readMembers: true,
|
|
334
|
+
readTeams: true,
|
|
335
|
+
readInvitations: value.capabilities.readInvitations
|
|
336
|
+
}
|
|
330
337
|
};
|
|
338
|
+
}
|
|
339
|
+
function normalizeOrganizationDisplayInput(value) {
|
|
340
|
+
if (!isObject(value) || Object.keys(value).sort().join(",") !== "logo,name,slug") throw new AuthError("invalid_request", 400);
|
|
341
|
+
if (!boundedString(value.name, 255) || !boundedString(value.slug, 255)) throw new AuthError("invalid_request", 400);
|
|
342
|
+
let logo;
|
|
343
|
+
try {
|
|
344
|
+
logo = nullableHttpsUrl(value.logo);
|
|
345
|
+
} catch {
|
|
346
|
+
throw new AuthError("invalid_request", 400);
|
|
347
|
+
}
|
|
331
348
|
return {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
params: query,
|
|
336
|
-
headers
|
|
349
|
+
name: value.name,
|
|
350
|
+
slug: value.slug,
|
|
351
|
+
logo
|
|
337
352
|
};
|
|
338
353
|
}
|
|
339
|
-
function
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
354
|
+
function normalizeOrganizationDisplay(value) {
|
|
355
|
+
try {
|
|
356
|
+
return normalizeOrganizationDisplayInput(value);
|
|
357
|
+
} catch {
|
|
358
|
+
throw authorityUnavailable();
|
|
359
|
+
}
|
|
344
360
|
}
|
|
345
|
-
|
|
346
|
-
if (
|
|
347
|
-
|
|
361
|
+
function normalizeOrganizationTeamDisplayInput(value) {
|
|
362
|
+
if (!isObject(value) || Object.keys(value).join(",") !== "name" || !boundedString(value.name, 255)) throw new AuthError("invalid_request", 400);
|
|
363
|
+
return { name: value.name };
|
|
348
364
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
500,
|
|
355
|
-
502,
|
|
356
|
-
503,
|
|
357
|
-
504
|
|
358
|
-
]);
|
|
359
|
-
const nullBodyResponses = new Set([
|
|
360
|
-
101,
|
|
361
|
-
204,
|
|
362
|
-
205,
|
|
363
|
-
304
|
|
364
|
-
]);
|
|
365
|
-
function createFetch(globalOptions = {}) {
|
|
366
|
-
const { fetch = globalThis.fetch, Headers = globalThis.Headers, AbortController = globalThis.AbortController } = globalOptions;
|
|
367
|
-
async function onError(context) {
|
|
368
|
-
const isAbort = context.error && context.error.name === "AbortError" && !context.options.timeout || false;
|
|
369
|
-
if (context.options.retry !== false && !isAbort) {
|
|
370
|
-
let retries;
|
|
371
|
-
if (typeof context.options.retry === "number") retries = context.options.retry;
|
|
372
|
-
else retries = isPayloadMethod(context.options.method) ? 0 : 1;
|
|
373
|
-
const responseCode = context.response && context.response.status || 500;
|
|
374
|
-
if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) {
|
|
375
|
-
const retryDelay = typeof context.options.retryDelay === "function" ? context.options.retryDelay(context) : context.options.retryDelay || 0;
|
|
376
|
-
if (retryDelay > 0) await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
377
|
-
return $fetchRaw(context.request, {
|
|
378
|
-
...context.options,
|
|
379
|
-
retry: retries - 1
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
const error = createFetchError(context);
|
|
384
|
-
if (Error.captureStackTrace) Error.captureStackTrace(error, $fetchRaw);
|
|
385
|
-
throw error;
|
|
365
|
+
function normalizeOrganizationTeamDisplay(value) {
|
|
366
|
+
try {
|
|
367
|
+
return normalizeOrganizationTeamDisplayInput(value);
|
|
368
|
+
} catch {
|
|
369
|
+
throw authorityUnavailable();
|
|
386
370
|
}
|
|
387
|
-
const $fetchRaw = async function $fetchRaw2(_request, _options = {}) {
|
|
388
|
-
const context = {
|
|
389
|
-
request: _request,
|
|
390
|
-
options: resolveFetchOptions(_request, _options, globalOptions.defaults, Headers),
|
|
391
|
-
response: void 0,
|
|
392
|
-
error: void 0
|
|
393
|
-
};
|
|
394
|
-
if (context.options.method) context.options.method = context.options.method.toUpperCase();
|
|
395
|
-
if (context.options.onRequest) {
|
|
396
|
-
await callHooks(context, context.options.onRequest);
|
|
397
|
-
if (!(context.options.headers instanceof Headers)) context.options.headers = new Headers(context.options.headers || {});
|
|
398
|
-
}
|
|
399
|
-
if (typeof context.request === "string") {
|
|
400
|
-
if (context.options.baseURL) context.request = withBase(context.request, context.options.baseURL);
|
|
401
|
-
if (context.options.query) {
|
|
402
|
-
context.request = withQuery(context.request, context.options.query);
|
|
403
|
-
delete context.options.query;
|
|
404
|
-
}
|
|
405
|
-
if ("query" in context.options) delete context.options.query;
|
|
406
|
-
if ("params" in context.options) delete context.options.params;
|
|
407
|
-
}
|
|
408
|
-
if (context.options.body && isPayloadMethod(context.options.method)) {
|
|
409
|
-
if (isJSONSerializable(context.options.body)) {
|
|
410
|
-
const contentType = context.options.headers.get("content-type");
|
|
411
|
-
if (typeof context.options.body !== "string") context.options.body = contentType === "application/x-www-form-urlencoded" ? new URLSearchParams(context.options.body).toString() : JSON.stringify(context.options.body);
|
|
412
|
-
if (!contentType) context.options.headers.set("content-type", "application/json");
|
|
413
|
-
if (!context.options.headers.has("accept")) context.options.headers.set("accept", "application/json");
|
|
414
|
-
} else if ("pipeTo" in context.options.body && typeof context.options.body.pipeTo === "function" || typeof context.options.body.pipe === "function") {
|
|
415
|
-
if (!("duplex" in context.options)) context.options.duplex = "half";
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
let abortTimeout;
|
|
419
|
-
if (!context.options.signal && context.options.timeout) {
|
|
420
|
-
const controller = new AbortController();
|
|
421
|
-
abortTimeout = setTimeout(() => {
|
|
422
|
-
const error = new Error("[TimeoutError]: The operation was aborted due to timeout");
|
|
423
|
-
error.name = "TimeoutError";
|
|
424
|
-
error.code = 23;
|
|
425
|
-
controller.abort(error);
|
|
426
|
-
}, context.options.timeout);
|
|
427
|
-
context.options.signal = controller.signal;
|
|
428
|
-
}
|
|
429
|
-
try {
|
|
430
|
-
context.response = await fetch(context.request, context.options);
|
|
431
|
-
} catch (error) {
|
|
432
|
-
context.error = error;
|
|
433
|
-
if (context.options.onRequestError) await callHooks(context, context.options.onRequestError);
|
|
434
|
-
return await onError(context);
|
|
435
|
-
} finally {
|
|
436
|
-
if (abortTimeout) clearTimeout(abortTimeout);
|
|
437
|
-
}
|
|
438
|
-
if ((context.response.body || context.response._bodyInit) && !nullBodyResponses.has(context.response.status) && context.options.method !== "HEAD") {
|
|
439
|
-
const responseType = (context.options.parseResponse ? "json" : context.options.responseType) || detectResponseType(context.response.headers.get("content-type") || "");
|
|
440
|
-
switch (responseType) {
|
|
441
|
-
case "json": {
|
|
442
|
-
const data = await context.response.text();
|
|
443
|
-
const parseFunction = context.options.parseResponse || destr;
|
|
444
|
-
context.response._data = parseFunction(data);
|
|
445
|
-
break;
|
|
446
|
-
}
|
|
447
|
-
case "stream":
|
|
448
|
-
context.response._data = context.response.body || context.response._bodyInit;
|
|
449
|
-
break;
|
|
450
|
-
default: context.response._data = await context.response[responseType]();
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
if (context.options.onResponse) await callHooks(context, context.options.onResponse);
|
|
454
|
-
if (!context.options.ignoreResponseError && context.response.status >= 400 && context.response.status < 600) {
|
|
455
|
-
if (context.options.onResponseError) await callHooks(context, context.options.onResponseError);
|
|
456
|
-
return await onError(context);
|
|
457
|
-
}
|
|
458
|
-
return context.response;
|
|
459
|
-
};
|
|
460
|
-
const $fetch = async function $fetch2(request, options) {
|
|
461
|
-
return (await $fetchRaw(request, options))._data;
|
|
462
|
-
};
|
|
463
|
-
$fetch.raw = $fetchRaw;
|
|
464
|
-
$fetch.native = (...args) => fetch(...args);
|
|
465
|
-
$fetch.create = (defaultOptions = {}, customGlobalOptions = {}) => createFetch({
|
|
466
|
-
...globalOptions,
|
|
467
|
-
...customGlobalOptions,
|
|
468
|
-
defaults: {
|
|
469
|
-
...globalOptions.defaults,
|
|
470
|
-
...customGlobalOptions.defaults,
|
|
471
|
-
...defaultOptions
|
|
472
|
-
}
|
|
473
|
-
});
|
|
474
|
-
return $fetch;
|
|
475
|
-
}
|
|
476
|
-
//#endregion
|
|
477
|
-
//#region src/shared.ts
|
|
478
|
-
const DRIVE_CREDENTIAL_LIFETIME_SECONDS = 840;
|
|
479
|
-
const id = /^[A-Za-z0-9_-]{1,128}$/;
|
|
480
|
-
const email = /^[^\s@]+@[^\s@]+$/;
|
|
481
|
-
const MAX_SOCIAL_ID_TOKEN_BYTES = 16 * 1024;
|
|
482
|
-
function normalizeEmail(value) {
|
|
483
|
-
if (typeof value !== "string") throw new TypeError("email is invalid");
|
|
484
|
-
const normalized = value.trim().toLowerCase();
|
|
485
|
-
if (normalized.length === 0 || normalized.length > 320 || !email.test(normalized)) throw new TypeError("email is invalid");
|
|
486
|
-
return normalized;
|
|
487
371
|
}
|
|
488
|
-
function
|
|
489
|
-
if (!
|
|
490
|
-
const keys = Object.keys(value);
|
|
491
|
-
if (keys.length !== 3 && keys.length !== 4 || keys.some((key) => key !== "provider" && key !== "idToken" && key !== "nonce" && key !== "signUp") || 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");
|
|
372
|
+
function normalizeOrganizationTeamCreationInput(name, idempotencyKey) {
|
|
373
|
+
if (!boundedString(name, 255) || !boundedString(idempotencyKey, 255)) throw new AuthError("invalid_request", 400);
|
|
492
374
|
return {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
...value.nonce === void 0 ? {} : { nonce: value.nonce },
|
|
496
|
-
signUp: value.signUp
|
|
375
|
+
name,
|
|
376
|
+
idempotencyKey
|
|
497
377
|
};
|
|
498
378
|
}
|
|
499
|
-
function
|
|
379
|
+
function normalizeCreatedOrganizationTeam(value) {
|
|
380
|
+
exact(value, ["id", "name"]);
|
|
381
|
+
if (!isId(value.id) || !boundedString(value.name, 255)) throw authorityUnavailable();
|
|
500
382
|
return {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
token: value.idToken,
|
|
504
|
-
...value.nonce === void 0 ? {} : { nonce: value.nonce }
|
|
505
|
-
},
|
|
506
|
-
requestSignUp: value.signUp
|
|
383
|
+
id: value.id,
|
|
384
|
+
name: value.name
|
|
507
385
|
};
|
|
508
386
|
}
|
|
509
|
-
function
|
|
510
|
-
if (
|
|
511
|
-
|
|
387
|
+
function normalizeOrganizationMemberInvitationCreationInput(value) {
|
|
388
|
+
if (!isObject(value)) throw new AuthError("invalid_request", 400);
|
|
389
|
+
const keys = Object.keys(value).sort().join(",");
|
|
390
|
+
if (keys !== "email,idempotencyKey" && keys !== "email,idempotencyKey,teamIds") throw new AuthError("invalid_request", 400);
|
|
391
|
+
let normalizedEmail;
|
|
512
392
|
try {
|
|
513
|
-
|
|
393
|
+
normalizedEmail = normalizeEmail(value.email);
|
|
514
394
|
} catch {
|
|
515
|
-
throw new
|
|
395
|
+
throw new AuthError("invalid_request", 400);
|
|
516
396
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
function normalizeTimeout(value) {
|
|
522
|
-
const timeout = value ?? 1e4;
|
|
523
|
-
if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 6e4) throw new TypeError("timeoutMs must be an integer from 1 to 60000");
|
|
524
|
-
return timeout;
|
|
525
|
-
}
|
|
526
|
-
function normalizeSession(value) {
|
|
527
|
-
if (value === null) return null;
|
|
528
|
-
if (!isObject(value) || !isObject(value.session) || !isObject(value.user)) throw authorityUnavailable();
|
|
529
|
-
const expiresAt = toDate(value.session.expiresAt);
|
|
530
|
-
const image = value.user.image;
|
|
531
|
-
if (!isId(value.session.id) || !expiresAt || !isId(value.user.id) || typeof value.user.name !== "string" || value.user.name.length > 256 || typeof value.user.email !== "string" || value.user.email.length > 320 || !email.test(value.user.email) || typeof value.user.emailVerified !== "boolean" || image !== null && image !== void 0 && (typeof image !== "string" || image.length > 2048)) throw authorityUnavailable();
|
|
397
|
+
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);
|
|
398
|
+
const teamIds = value.teamIds?.map((teamId) => normalizeIdInput(teamId));
|
|
399
|
+
if (teamIds && new Set(teamIds).size !== teamIds.length) throw new AuthError("invalid_request", 400);
|
|
532
400
|
return {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
id: value.user.id,
|
|
537
|
-
name: value.user.name,
|
|
538
|
-
email: value.user.email,
|
|
539
|
-
emailVerified: value.user.emailVerified,
|
|
540
|
-
image: image ?? null
|
|
541
|
-
}
|
|
401
|
+
email: normalizedEmail,
|
|
402
|
+
...teamIds === void 0 ? {} : { teamIds },
|
|
403
|
+
idempotencyKey: value.idempotencyKey
|
|
542
404
|
};
|
|
543
405
|
}
|
|
544
|
-
function
|
|
545
|
-
|
|
406
|
+
function normalizeCreatedOrganizationMemberInvitation(value) {
|
|
407
|
+
exact(value, ["expiresAt", "id"]);
|
|
408
|
+
if (!isId(value.id)) throw authorityUnavailable();
|
|
546
409
|
return {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
expiresAt: new Date(now + value.expiresIn * 1e3)
|
|
410
|
+
id: value.id,
|
|
411
|
+
expiresAt: responseDate(value.expiresAt)
|
|
550
412
|
};
|
|
551
413
|
}
|
|
552
|
-
function
|
|
553
|
-
|
|
554
|
-
if (
|
|
555
|
-
|
|
556
|
-
const query = new URLSearchParams();
|
|
557
|
-
if (input.limit !== void 0) {
|
|
558
|
-
if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 100) throw new AuthError("invalid_request", 400);
|
|
559
|
-
query.set("limit", String(input.limit));
|
|
560
|
-
}
|
|
561
|
-
if (input.cursor !== void 0) {
|
|
562
|
-
if (typeof input.cursor !== "string" || input.cursor.length < 1 || input.cursor.length > 820 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(input.cursor)) throw new AuthError("invalid_request", 400);
|
|
563
|
-
query.set("cursor", input.cursor);
|
|
564
|
-
}
|
|
565
|
-
return query;
|
|
414
|
+
function normalizeResentOrganizationInvitation(value, invitationId) {
|
|
415
|
+
const invitation = normalizeCreatedOrganizationMemberInvitation(value);
|
|
416
|
+
if (invitation.id !== invitationId) throw authorityUnavailable();
|
|
417
|
+
return invitation;
|
|
566
418
|
}
|
|
567
|
-
function
|
|
568
|
-
if (!
|
|
569
|
-
return
|
|
570
|
-
}
|
|
571
|
-
function normalizeOrganization(value) {
|
|
572
|
-
exact(value, [
|
|
573
|
-
"capabilities",
|
|
574
|
-
"id",
|
|
575
|
-
"lifecycle",
|
|
576
|
-
"logo",
|
|
577
|
-
"name",
|
|
578
|
-
"role",
|
|
579
|
-
"slug"
|
|
580
|
-
]);
|
|
581
|
-
if (!isId(value.id) || !boundedString(value.name, 255) || !boundedString(value.slug, 255) || value.lifecycle !== "ordinary" && value.lifecycle !== "managed" || !role(value.role) || !isObject(value.capabilities)) throw authorityUnavailable();
|
|
582
|
-
exact(value.capabilities, [
|
|
583
|
-
"readInvitations",
|
|
584
|
-
"readMembers",
|
|
585
|
-
"readTeams"
|
|
586
|
-
]);
|
|
587
|
-
if (value.capabilities.readMembers !== true || value.capabilities.readTeams !== true || typeof value.capabilities.readInvitations !== "boolean") throw authorityUnavailable();
|
|
588
|
-
return {
|
|
589
|
-
id: value.id,
|
|
590
|
-
name: value.name,
|
|
591
|
-
slug: value.slug,
|
|
592
|
-
logo: nullableHttpsUrl(value.logo),
|
|
593
|
-
lifecycle: value.lifecycle,
|
|
594
|
-
role: value.role,
|
|
595
|
-
capabilities: {
|
|
596
|
-
readMembers: true,
|
|
597
|
-
readTeams: true,
|
|
598
|
-
readInvitations: value.capabilities.readInvitations
|
|
599
|
-
}
|
|
600
|
-
};
|
|
601
|
-
}
|
|
602
|
-
function normalizeOrganizationDisplayInput(value) {
|
|
603
|
-
if (!isObject(value) || Object.keys(value).sort().join(",") !== "logo,name,slug") throw new AuthError("invalid_request", 400);
|
|
604
|
-
if (!boundedString(value.name, 255) || !boundedString(value.slug, 255)) throw new AuthError("invalid_request", 400);
|
|
605
|
-
let logo;
|
|
606
|
-
try {
|
|
607
|
-
logo = nullableHttpsUrl(value.logo);
|
|
608
|
-
} catch {
|
|
609
|
-
throw new AuthError("invalid_request", 400);
|
|
610
|
-
}
|
|
611
|
-
return {
|
|
612
|
-
name: value.name,
|
|
613
|
-
slug: value.slug,
|
|
614
|
-
logo
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
function normalizeOrganizationDisplay(value) {
|
|
618
|
-
try {
|
|
619
|
-
return normalizeOrganizationDisplayInput(value);
|
|
620
|
-
} catch {
|
|
621
|
-
throw authorityUnavailable();
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
function normalizeOrganizationTeamDisplayInput(value) {
|
|
625
|
-
if (!isObject(value) || Object.keys(value).join(",") !== "name" || !boundedString(value.name, 255)) throw new AuthError("invalid_request", 400);
|
|
626
|
-
return { name: value.name };
|
|
627
|
-
}
|
|
628
|
-
function normalizeOrganizationTeamDisplay(value) {
|
|
629
|
-
try {
|
|
630
|
-
return normalizeOrganizationTeamDisplayInput(value);
|
|
631
|
-
} catch {
|
|
632
|
-
throw authorityUnavailable();
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
function normalizeOrganizationTeamCreationInput(name, idempotencyKey) {
|
|
636
|
-
if (!boundedString(name, 255) || !boundedString(idempotencyKey, 255)) throw new AuthError("invalid_request", 400);
|
|
637
|
-
return {
|
|
638
|
-
name,
|
|
639
|
-
idempotencyKey
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
function normalizeCreatedOrganizationTeam(value) {
|
|
643
|
-
exact(value, ["id", "name"]);
|
|
644
|
-
if (!isId(value.id) || !boundedString(value.name, 255)) throw authorityUnavailable();
|
|
645
|
-
return {
|
|
646
|
-
id: value.id,
|
|
647
|
-
name: value.name
|
|
648
|
-
};
|
|
649
|
-
}
|
|
650
|
-
function normalizeOrganizationMemberInvitationCreationInput(value) {
|
|
651
|
-
if (!isObject(value)) throw new AuthError("invalid_request", 400);
|
|
652
|
-
const keys = Object.keys(value).sort().join(",");
|
|
653
|
-
if (keys !== "email,idempotencyKey" && keys !== "email,idempotencyKey,teamIds") throw new AuthError("invalid_request", 400);
|
|
654
|
-
let normalizedEmail;
|
|
655
|
-
try {
|
|
656
|
-
normalizedEmail = normalizeEmail(value.email);
|
|
657
|
-
} catch {
|
|
658
|
-
throw new AuthError("invalid_request", 400);
|
|
659
|
-
}
|
|
660
|
-
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);
|
|
661
|
-
const teamIds = value.teamIds?.map((teamId) => normalizeIdInput(teamId));
|
|
662
|
-
if (teamIds && new Set(teamIds).size !== teamIds.length) throw new AuthError("invalid_request", 400);
|
|
663
|
-
return {
|
|
664
|
-
email: normalizedEmail,
|
|
665
|
-
...teamIds === void 0 ? {} : { teamIds },
|
|
666
|
-
idempotencyKey: value.idempotencyKey
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
function normalizeCreatedOrganizationMemberInvitation(value) {
|
|
670
|
-
exact(value, ["expiresAt", "id"]);
|
|
671
|
-
if (!isId(value.id)) throw authorityUnavailable();
|
|
672
|
-
return {
|
|
673
|
-
id: value.id,
|
|
674
|
-
expiresAt: responseDate(value.expiresAt)
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
function normalizeResentOrganizationInvitation(value, invitationId) {
|
|
678
|
-
const invitation = normalizeCreatedOrganizationMemberInvitation(value);
|
|
679
|
-
if (invitation.id !== invitationId) throw authorityUnavailable();
|
|
680
|
-
return invitation;
|
|
681
|
-
}
|
|
682
|
-
function normalizeOrganizationInvitationAdministrationInput(idempotencyKey) {
|
|
683
|
-
if (!boundedString(idempotencyKey, 255)) throw new AuthError("invalid_request", 400);
|
|
684
|
-
return { idempotencyKey };
|
|
419
|
+
function normalizeOrganizationInvitationAdministrationInput(idempotencyKey) {
|
|
420
|
+
if (!boundedString(idempotencyKey, 255)) throw new AuthError("invalid_request", 400);
|
|
421
|
+
return { idempotencyKey };
|
|
685
422
|
}
|
|
686
423
|
function normalizeCanceledOrganizationInvitation(value) {
|
|
687
424
|
exact(value, ["status"]);
|
|
@@ -1065,6 +802,373 @@ function isObject(value) {
|
|
|
1065
802
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1066
803
|
}
|
|
1067
804
|
//#endregion
|
|
805
|
+
//#region src/provisioning.ts
|
|
806
|
+
const MAX_BYTES = 16 * 1024;
|
|
807
|
+
const compactJwt = /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/;
|
|
808
|
+
function isCompactCredential(value) {
|
|
809
|
+
return typeof value === "string" && value.length + 7 <= MAX_BYTES && compactJwt.test(value);
|
|
810
|
+
}
|
|
811
|
+
function createDriveProvisioningAuth(options) {
|
|
812
|
+
const url = joinURL(normalizeOrigin(options.authOrigin, "authOrigin"), "api/v1/auth/drive-provisioning-credential");
|
|
813
|
+
const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
814
|
+
if (typeof fetchImpl !== "function") throw new TypeError("fetch is required");
|
|
815
|
+
const timeoutMs = normalizeTimeout(options.timeoutMs);
|
|
816
|
+
const now = options.now ?? Date.now;
|
|
817
|
+
let inFlight = false;
|
|
818
|
+
return { async getDriveProvisioningCredential(clientAssertion) {
|
|
819
|
+
if (!isCompactCredential(clientAssertion)) throw new AuthError("invalid_request", 400);
|
|
820
|
+
if (inFlight) throw new AuthError("state_conflict", 409);
|
|
821
|
+
inFlight = true;
|
|
822
|
+
const controller = new AbortController();
|
|
823
|
+
let reader;
|
|
824
|
+
let timer;
|
|
825
|
+
let exchangeStarted = false;
|
|
826
|
+
let authorityError;
|
|
827
|
+
try {
|
|
828
|
+
const startedAt = now();
|
|
829
|
+
if (!Number.isSafeInteger(startedAt) || startedAt < 0 || startedAt > 86399999997e5) throw authorityUnavailable();
|
|
830
|
+
const deadline = new Promise((_, reject) => {
|
|
831
|
+
timer = setTimeout(() => {
|
|
832
|
+
reject(authorityUnavailable());
|
|
833
|
+
controller.abort();
|
|
834
|
+
reader?.cancel().catch(() => {});
|
|
835
|
+
}, timeoutMs);
|
|
836
|
+
});
|
|
837
|
+
const exchange = async () => {
|
|
838
|
+
const response = await fetchImpl(url, {
|
|
839
|
+
method: "POST",
|
|
840
|
+
headers: {
|
|
841
|
+
authorization: `Bearer ${clientAssertion}`,
|
|
842
|
+
accept: "application/json"
|
|
843
|
+
},
|
|
844
|
+
credentials: "omit",
|
|
845
|
+
cache: "no-store",
|
|
846
|
+
redirect: "manual",
|
|
847
|
+
signal: controller.signal
|
|
848
|
+
});
|
|
849
|
+
if (controller.signal.aborted) {
|
|
850
|
+
response.body?.cancel().catch(() => {});
|
|
851
|
+
throw authorityUnavailable();
|
|
852
|
+
}
|
|
853
|
+
if (!response.body) throw authorityUnavailable();
|
|
854
|
+
reader = response.body.getReader();
|
|
855
|
+
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
856
|
+
const length = response.headers.get("content-length");
|
|
857
|
+
if (contentType !== "application/json" || length !== null && (!/^\d+$/.test(length) || Number(length) > MAX_BYTES)) throw authorityUnavailable();
|
|
858
|
+
const bytes = new Uint8Array(MAX_BYTES);
|
|
859
|
+
let size = 0;
|
|
860
|
+
while (true) {
|
|
861
|
+
const chunk = await reader.read();
|
|
862
|
+
if (chunk.done) break;
|
|
863
|
+
if (controller.signal.aborted || size + chunk.value.byteLength > MAX_BYTES) throw authorityUnavailable();
|
|
864
|
+
bytes.set(chunk.value, size);
|
|
865
|
+
size += chunk.value.byteLength;
|
|
866
|
+
}
|
|
867
|
+
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size)));
|
|
868
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw authorityUnavailable();
|
|
869
|
+
const record = value;
|
|
870
|
+
if (response.status !== 200) {
|
|
871
|
+
if (Object.keys(record).length !== 2 || !("code" in record) || !("message" in record)) throw authorityUnavailable();
|
|
872
|
+
if (response.status === 401 && record.code === "UNAUTHORIZED" && record.message === "The ecosystem client assertion is invalid.") {
|
|
873
|
+
authorityError = new AuthError("authentication_required", 401);
|
|
874
|
+
throw authorityError;
|
|
875
|
+
}
|
|
876
|
+
const retryAfter = response.headers.get("retry-after");
|
|
877
|
+
if (response.status === 429 && record.code === "TOO_MANY_REQUESTS" && record.message === "Ecosystem credential exchanges are temporarily limited." && retryAfter !== null && /^(?:[1-9]|[1-5][0-9]|60)$/.test(retryAfter)) {
|
|
878
|
+
authorityError = new AuthError("auth_request_rate_limited", 429, Number(retryAfter));
|
|
879
|
+
throw authorityError;
|
|
880
|
+
}
|
|
881
|
+
throw authorityUnavailable();
|
|
882
|
+
}
|
|
883
|
+
if (Object.keys(record).length !== 3 || record.tokenType !== "Bearer" || record.expiresIn !== 300 || !isCompactCredential(record.token)) throw authorityUnavailable();
|
|
884
|
+
const expiresAt = new Date(Math.floor(startedAt / 1e3) * 1e3 + 3e5);
|
|
885
|
+
const completedAt = now();
|
|
886
|
+
if (!Number.isSafeInteger(completedAt) || completedAt < 0 || completedAt >= expiresAt.getTime()) throw authorityUnavailable();
|
|
887
|
+
return {
|
|
888
|
+
tokenType: "Bearer",
|
|
889
|
+
token: record.token,
|
|
890
|
+
expiresAt
|
|
891
|
+
};
|
|
892
|
+
};
|
|
893
|
+
exchangeStarted = true;
|
|
894
|
+
return await Promise.race([exchange().finally(() => {
|
|
895
|
+
inFlight = false;
|
|
896
|
+
}), deadline]);
|
|
897
|
+
} catch (error) {
|
|
898
|
+
if (authorityError && error === authorityError) throw authorityError;
|
|
899
|
+
throw authorityUnavailable();
|
|
900
|
+
} finally {
|
|
901
|
+
clearTimeout(timer);
|
|
902
|
+
controller.abort();
|
|
903
|
+
reader?.cancel().catch(() => {});
|
|
904
|
+
if (!exchangeStarted) inFlight = false;
|
|
905
|
+
}
|
|
906
|
+
} };
|
|
907
|
+
}
|
|
908
|
+
//#endregion
|
|
909
|
+
//#region ../../node_modules/.pnpm/destr@2.0.5/node_modules/destr/dist/index.mjs
|
|
910
|
+
const suspectProtoRx = /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/;
|
|
911
|
+
const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
|
|
912
|
+
const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;
|
|
913
|
+
function jsonParseTransform(key, value) {
|
|
914
|
+
if (key === "__proto__" || key === "constructor" && value && typeof value === "object" && "prototype" in value) {
|
|
915
|
+
warnKeyDropped(key);
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
return value;
|
|
919
|
+
}
|
|
920
|
+
function warnKeyDropped(key) {
|
|
921
|
+
console.warn(`[destr] Dropping "${key}" key to prevent prototype pollution.`);
|
|
922
|
+
}
|
|
923
|
+
function destr(value, options = {}) {
|
|
924
|
+
if (typeof value !== "string") return value;
|
|
925
|
+
if (value[0] === "\"" && value[value.length - 1] === "\"" && value.indexOf("\\") === -1) return value.slice(1, -1);
|
|
926
|
+
const _value = value.trim();
|
|
927
|
+
if (_value.length <= 9) switch (_value.toLowerCase()) {
|
|
928
|
+
case "true": return true;
|
|
929
|
+
case "false": return false;
|
|
930
|
+
case "undefined": return;
|
|
931
|
+
case "null": return null;
|
|
932
|
+
case "nan": return NaN;
|
|
933
|
+
case "infinity": return Number.POSITIVE_INFINITY;
|
|
934
|
+
case "-infinity": return Number.NEGATIVE_INFINITY;
|
|
935
|
+
}
|
|
936
|
+
if (!JsonSigRx.test(value)) {
|
|
937
|
+
if (options.strict) throw new SyntaxError("[destr] Invalid JSON");
|
|
938
|
+
return value;
|
|
939
|
+
}
|
|
940
|
+
try {
|
|
941
|
+
if (suspectProtoRx.test(value) || suspectConstructorRx.test(value)) {
|
|
942
|
+
if (options.strict) throw new Error("[destr] Possible prototype pollution");
|
|
943
|
+
return JSON.parse(value, jsonParseTransform);
|
|
944
|
+
}
|
|
945
|
+
return JSON.parse(value);
|
|
946
|
+
} catch (error) {
|
|
947
|
+
if (options.strict) throw error;
|
|
948
|
+
return value;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
//#endregion
|
|
952
|
+
//#region ../../node_modules/.pnpm/ofetch@1.5.1/node_modules/ofetch/dist/shared/ofetch.CWycOUEr.mjs
|
|
953
|
+
var FetchError = class extends Error {
|
|
954
|
+
constructor(message, opts) {
|
|
955
|
+
super(message, opts);
|
|
956
|
+
this.name = "FetchError";
|
|
957
|
+
if (opts?.cause && !this.cause) this.cause = opts.cause;
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
function createFetchError(ctx) {
|
|
961
|
+
const errorMessage = ctx.error?.message || ctx.error?.toString() || "";
|
|
962
|
+
const method = ctx.request?.method || ctx.options?.method || "GET";
|
|
963
|
+
const url = ctx.request?.url || String(ctx.request) || "/";
|
|
964
|
+
const fetchError = new FetchError(`${`[${method}] ${JSON.stringify(url)}`}: ${ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : "<no response>"}${errorMessage ? ` ${errorMessage}` : ""}`, ctx.error ? { cause: ctx.error } : void 0);
|
|
965
|
+
for (const key of [
|
|
966
|
+
"request",
|
|
967
|
+
"options",
|
|
968
|
+
"response"
|
|
969
|
+
]) Object.defineProperty(fetchError, key, { get() {
|
|
970
|
+
return ctx[key];
|
|
971
|
+
} });
|
|
972
|
+
for (const [key, refKey] of [
|
|
973
|
+
["data", "_data"],
|
|
974
|
+
["status", "status"],
|
|
975
|
+
["statusCode", "status"],
|
|
976
|
+
["statusText", "statusText"],
|
|
977
|
+
["statusMessage", "statusText"]
|
|
978
|
+
]) Object.defineProperty(fetchError, key, { get() {
|
|
979
|
+
return ctx.response && ctx.response[refKey];
|
|
980
|
+
} });
|
|
981
|
+
return fetchError;
|
|
982
|
+
}
|
|
983
|
+
const payloadMethods = new Set(Object.freeze([
|
|
984
|
+
"PATCH",
|
|
985
|
+
"POST",
|
|
986
|
+
"PUT",
|
|
987
|
+
"DELETE"
|
|
988
|
+
]));
|
|
989
|
+
function isPayloadMethod(method = "GET") {
|
|
990
|
+
return payloadMethods.has(method.toUpperCase());
|
|
991
|
+
}
|
|
992
|
+
function isJSONSerializable(value) {
|
|
993
|
+
if (value === void 0) return false;
|
|
994
|
+
const t = typeof value;
|
|
995
|
+
if (t === "string" || t === "number" || t === "boolean" || t === null) return true;
|
|
996
|
+
if (t !== "object") return false;
|
|
997
|
+
if (Array.isArray(value)) return true;
|
|
998
|
+
if (value.buffer) return false;
|
|
999
|
+
if (value instanceof FormData || value instanceof URLSearchParams) return false;
|
|
1000
|
+
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
|
|
1001
|
+
}
|
|
1002
|
+
const textTypes = new Set([
|
|
1003
|
+
"image/svg",
|
|
1004
|
+
"application/xml",
|
|
1005
|
+
"application/xhtml",
|
|
1006
|
+
"application/html"
|
|
1007
|
+
]);
|
|
1008
|
+
const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;
|
|
1009
|
+
function detectResponseType(_contentType = "") {
|
|
1010
|
+
if (!_contentType) return "json";
|
|
1011
|
+
const contentType = _contentType.split(";").shift() || "";
|
|
1012
|
+
if (JSON_RE.test(contentType)) return "json";
|
|
1013
|
+
if (contentType === "text/event-stream") return "stream";
|
|
1014
|
+
if (textTypes.has(contentType) || contentType.startsWith("text/")) return "text";
|
|
1015
|
+
return "blob";
|
|
1016
|
+
}
|
|
1017
|
+
function resolveFetchOptions(request, input, defaults, Headers) {
|
|
1018
|
+
const headers = mergeHeaders(input?.headers ?? request?.headers, defaults?.headers, Headers);
|
|
1019
|
+
let query;
|
|
1020
|
+
if (defaults?.query || defaults?.params || input?.params || input?.query) query = {
|
|
1021
|
+
...defaults?.params,
|
|
1022
|
+
...defaults?.query,
|
|
1023
|
+
...input?.params,
|
|
1024
|
+
...input?.query
|
|
1025
|
+
};
|
|
1026
|
+
return {
|
|
1027
|
+
...defaults,
|
|
1028
|
+
...input,
|
|
1029
|
+
query,
|
|
1030
|
+
params: query,
|
|
1031
|
+
headers
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
function mergeHeaders(input, defaults, Headers) {
|
|
1035
|
+
if (!defaults) return new Headers(input);
|
|
1036
|
+
const headers = new Headers(defaults);
|
|
1037
|
+
if (input) for (const [key, value] of Symbol.iterator in input || Array.isArray(input) ? input : new Headers(input)) headers.set(key, value);
|
|
1038
|
+
return headers;
|
|
1039
|
+
}
|
|
1040
|
+
async function callHooks(context, hooks) {
|
|
1041
|
+
if (hooks) if (Array.isArray(hooks)) for (const hook of hooks) await hook(context);
|
|
1042
|
+
else await hooks(context);
|
|
1043
|
+
}
|
|
1044
|
+
const retryStatusCodes = new Set([
|
|
1045
|
+
408,
|
|
1046
|
+
409,
|
|
1047
|
+
425,
|
|
1048
|
+
429,
|
|
1049
|
+
500,
|
|
1050
|
+
502,
|
|
1051
|
+
503,
|
|
1052
|
+
504
|
|
1053
|
+
]);
|
|
1054
|
+
const nullBodyResponses = new Set([
|
|
1055
|
+
101,
|
|
1056
|
+
204,
|
|
1057
|
+
205,
|
|
1058
|
+
304
|
|
1059
|
+
]);
|
|
1060
|
+
function createFetch(globalOptions = {}) {
|
|
1061
|
+
const { fetch = globalThis.fetch, Headers = globalThis.Headers, AbortController = globalThis.AbortController } = globalOptions;
|
|
1062
|
+
async function onError(context) {
|
|
1063
|
+
const isAbort = context.error && context.error.name === "AbortError" && !context.options.timeout || false;
|
|
1064
|
+
if (context.options.retry !== false && !isAbort) {
|
|
1065
|
+
let retries;
|
|
1066
|
+
if (typeof context.options.retry === "number") retries = context.options.retry;
|
|
1067
|
+
else retries = isPayloadMethod(context.options.method) ? 0 : 1;
|
|
1068
|
+
const responseCode = context.response && context.response.status || 500;
|
|
1069
|
+
if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) {
|
|
1070
|
+
const retryDelay = typeof context.options.retryDelay === "function" ? context.options.retryDelay(context) : context.options.retryDelay || 0;
|
|
1071
|
+
if (retryDelay > 0) await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
1072
|
+
return $fetchRaw(context.request, {
|
|
1073
|
+
...context.options,
|
|
1074
|
+
retry: retries - 1
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
const error = createFetchError(context);
|
|
1079
|
+
if (Error.captureStackTrace) Error.captureStackTrace(error, $fetchRaw);
|
|
1080
|
+
throw error;
|
|
1081
|
+
}
|
|
1082
|
+
const $fetchRaw = async function $fetchRaw2(_request, _options = {}) {
|
|
1083
|
+
const context = {
|
|
1084
|
+
request: _request,
|
|
1085
|
+
options: resolveFetchOptions(_request, _options, globalOptions.defaults, Headers),
|
|
1086
|
+
response: void 0,
|
|
1087
|
+
error: void 0
|
|
1088
|
+
};
|
|
1089
|
+
if (context.options.method) context.options.method = context.options.method.toUpperCase();
|
|
1090
|
+
if (context.options.onRequest) {
|
|
1091
|
+
await callHooks(context, context.options.onRequest);
|
|
1092
|
+
if (!(context.options.headers instanceof Headers)) context.options.headers = new Headers(context.options.headers || {});
|
|
1093
|
+
}
|
|
1094
|
+
if (typeof context.request === "string") {
|
|
1095
|
+
if (context.options.baseURL) context.request = withBase(context.request, context.options.baseURL);
|
|
1096
|
+
if (context.options.query) {
|
|
1097
|
+
context.request = withQuery(context.request, context.options.query);
|
|
1098
|
+
delete context.options.query;
|
|
1099
|
+
}
|
|
1100
|
+
if ("query" in context.options) delete context.options.query;
|
|
1101
|
+
if ("params" in context.options) delete context.options.params;
|
|
1102
|
+
}
|
|
1103
|
+
if (context.options.body && isPayloadMethod(context.options.method)) {
|
|
1104
|
+
if (isJSONSerializable(context.options.body)) {
|
|
1105
|
+
const contentType = context.options.headers.get("content-type");
|
|
1106
|
+
if (typeof context.options.body !== "string") context.options.body = contentType === "application/x-www-form-urlencoded" ? new URLSearchParams(context.options.body).toString() : JSON.stringify(context.options.body);
|
|
1107
|
+
if (!contentType) context.options.headers.set("content-type", "application/json");
|
|
1108
|
+
if (!context.options.headers.has("accept")) context.options.headers.set("accept", "application/json");
|
|
1109
|
+
} else if ("pipeTo" in context.options.body && typeof context.options.body.pipeTo === "function" || typeof context.options.body.pipe === "function") {
|
|
1110
|
+
if (!("duplex" in context.options)) context.options.duplex = "half";
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
let abortTimeout;
|
|
1114
|
+
if (!context.options.signal && context.options.timeout) {
|
|
1115
|
+
const controller = new AbortController();
|
|
1116
|
+
abortTimeout = setTimeout(() => {
|
|
1117
|
+
const error = new Error("[TimeoutError]: The operation was aborted due to timeout");
|
|
1118
|
+
error.name = "TimeoutError";
|
|
1119
|
+
error.code = 23;
|
|
1120
|
+
controller.abort(error);
|
|
1121
|
+
}, context.options.timeout);
|
|
1122
|
+
context.options.signal = controller.signal;
|
|
1123
|
+
}
|
|
1124
|
+
try {
|
|
1125
|
+
context.response = await fetch(context.request, context.options);
|
|
1126
|
+
} catch (error) {
|
|
1127
|
+
context.error = error;
|
|
1128
|
+
if (context.options.onRequestError) await callHooks(context, context.options.onRequestError);
|
|
1129
|
+
return await onError(context);
|
|
1130
|
+
} finally {
|
|
1131
|
+
if (abortTimeout) clearTimeout(abortTimeout);
|
|
1132
|
+
}
|
|
1133
|
+
if ((context.response.body || context.response._bodyInit) && !nullBodyResponses.has(context.response.status) && context.options.method !== "HEAD") {
|
|
1134
|
+
const responseType = (context.options.parseResponse ? "json" : context.options.responseType) || detectResponseType(context.response.headers.get("content-type") || "");
|
|
1135
|
+
switch (responseType) {
|
|
1136
|
+
case "json": {
|
|
1137
|
+
const data = await context.response.text();
|
|
1138
|
+
const parseFunction = context.options.parseResponse || destr;
|
|
1139
|
+
context.response._data = parseFunction(data);
|
|
1140
|
+
break;
|
|
1141
|
+
}
|
|
1142
|
+
case "stream":
|
|
1143
|
+
context.response._data = context.response.body || context.response._bodyInit;
|
|
1144
|
+
break;
|
|
1145
|
+
default: context.response._data = await context.response[responseType]();
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
if (context.options.onResponse) await callHooks(context, context.options.onResponse);
|
|
1149
|
+
if (!context.options.ignoreResponseError && context.response.status >= 400 && context.response.status < 600) {
|
|
1150
|
+
if (context.options.onResponseError) await callHooks(context, context.options.onResponseError);
|
|
1151
|
+
return await onError(context);
|
|
1152
|
+
}
|
|
1153
|
+
return context.response;
|
|
1154
|
+
};
|
|
1155
|
+
const $fetch = async function $fetch2(request, options) {
|
|
1156
|
+
return (await $fetchRaw(request, options))._data;
|
|
1157
|
+
};
|
|
1158
|
+
$fetch.raw = $fetchRaw;
|
|
1159
|
+
$fetch.native = (...args) => fetch(...args);
|
|
1160
|
+
$fetch.create = (defaultOptions = {}, customGlobalOptions = {}) => createFetch({
|
|
1161
|
+
...globalOptions,
|
|
1162
|
+
...customGlobalOptions,
|
|
1163
|
+
defaults: {
|
|
1164
|
+
...globalOptions.defaults,
|
|
1165
|
+
...customGlobalOptions.defaults,
|
|
1166
|
+
...defaultOptions
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
return $fetch;
|
|
1170
|
+
}
|
|
1171
|
+
//#endregion
|
|
1068
1172
|
//#region src/http.ts
|
|
1069
1173
|
const MAX_RESPONSE_BYTES = 64 * 1024;
|
|
1070
1174
|
async function requestJson(url, options) {
|
|
@@ -1431,4 +1535,4 @@ function authAuthorizationHeader(value) {
|
|
|
1431
1535
|
return value;
|
|
1432
1536
|
}
|
|
1433
1537
|
//#endregion
|
|
1434
|
-
export { AuthError, createServerAuth };
|
|
1538
|
+
export { AuthError, createDriveProvisioningAuth, createServerAuth };
|