@finueva/auth 0.6.0 → 0.7.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/README.md +50 -4
- package/dist/device.d.ts +8 -2
- package/dist/device.js +570 -56
- package/dist/index.d.ts +2 -3
- package/dist/index.js +321 -101
- package/dist/server.d.ts +6 -3
- package/dist/server.js +126 -35
- package/dist/{types-HSdjQWMZ.d.ts → types-B1SZbs6Z.d.ts} +28 -1
- package/package.json +2 -1
- package/dist/errors-Crd93Rah.d.ts +0 -11
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
import { n as AuthErrorCode, r as AuthErrorStatus, t as AuthError } from "./errors-Crd93Rah.js";
|
|
1
|
+
import { C as AuthErrorStatus, S as AuthErrorCode, _ as SocialIdTokenInput, a as AuthPersistenceDriver, b as WorkspaceSelection, c as AuthUser, d as FinuevaAuthClient, f as InvitationAcceptance, g as SignInInput, h as SendVerificationEmailInput, i as AuthPersistence, l as DriveCredential, m as PersonalWorkspaceSelection, n as AuthClientOptions, o as AuthSession, p as OrganizationWorkspaceSelection, r as AuthOrganization, s as AuthState, t as AcceptInvitationInput, u as DriveCredentialInput, v as SocialIdTokenProvider, x as AuthError, y as UpdateProfileInput } from "./types-B1SZbs6Z.js";
|
|
3
2
|
//#region src/client.d.ts
|
|
4
3
|
declare function createAuthClient(options: AuthClientOptions): FinuevaAuthClient;
|
|
5
4
|
//#endregion
|
|
6
|
-
export { type AcceptInvitationInput, type AuthClientOptions, AuthError, type AuthErrorCode, type AuthErrorStatus, type AuthOrganization, type AuthPersistence, type AuthPersistenceDriver, type AuthSession, type AuthState, type AuthUser, type DriveCredential, type DriveCredentialInput, type FinuevaAuthClient, type InvitationAcceptance, type OrganizationWorkspaceSelection, type PersonalWorkspaceSelection, type SendVerificationEmailInput, type SignInInput, type WorkspaceSelection, createAuthClient };
|
|
5
|
+
export { type AcceptInvitationInput, type AuthClientOptions, AuthError, type AuthErrorCode, type AuthErrorStatus, type AuthOrganization, type AuthPersistence, type AuthPersistenceDriver, type AuthSession, type AuthState, type AuthUser, type DriveCredential, type DriveCredentialInput, type FinuevaAuthClient, type InvitationAcceptance, type OrganizationWorkspaceSelection, type PersonalWorkspaceSelection, type SendVerificationEmailInput, type SignInInput, type SocialIdTokenInput, type SocialIdTokenProvider, type UpdateProfileInput, type WorkspaceSelection, createAuthClient };
|
package/dist/index.js
CHANGED
|
@@ -1879,6 +1879,9 @@ function stringifyParsedURL(parsed) {
|
|
|
1879
1879
|
//#region src/errors.ts
|
|
1880
1880
|
const messages = {
|
|
1881
1881
|
invalid_credentials: "The credentials are invalid.",
|
|
1882
|
+
invalid_auth_input: "The authentication input is invalid.",
|
|
1883
|
+
account_conflict: "The account is not available.",
|
|
1884
|
+
password_reset_invalid: "The password reset request is invalid.",
|
|
1882
1885
|
authentication_required: "Authentication is required.",
|
|
1883
1886
|
request_origin_denied: "The request origin is not allowed.",
|
|
1884
1887
|
invalid_invitation: "The invitation is invalid.",
|
|
@@ -1888,6 +1891,7 @@ const messages = {
|
|
|
1888
1891
|
invalid_workspace_selection: "The workspace selection is invalid.",
|
|
1889
1892
|
organization_context_too_large: "The organization context is too large.",
|
|
1890
1893
|
credential_rate_limited: "Credential requests are temporarily limited.",
|
|
1894
|
+
auth_request_rate_limited: "Authentication requests are temporarily limited.",
|
|
1891
1895
|
state_conflict: "The authentication state conflicts with the request.",
|
|
1892
1896
|
access_denied: "Access is denied.",
|
|
1893
1897
|
identity_authority_unavailable: "Authentication is temporarily unavailable."
|
|
@@ -2172,6 +2176,69 @@ function createFetch(globalOptions = {}) {
|
|
|
2172
2176
|
const DRIVE_CREDENTIAL_LIFETIME_SECONDS = 840;
|
|
2173
2177
|
const id = /^[A-Za-z0-9_-]{1,128}$/;
|
|
2174
2178
|
const email = /^[^\s@]+@[^\s@]+$/;
|
|
2179
|
+
const passwordResetToken = /^[A-Za-z0-9_-]{1,512}$/;
|
|
2180
|
+
const MAX_SOCIAL_ID_TOKEN_BYTES = 16 * 1024;
|
|
2181
|
+
function normalizeEmail(value) {
|
|
2182
|
+
if (typeof value !== "string") throw new TypeError("email is invalid");
|
|
2183
|
+
const normalized = value.trim().toLowerCase();
|
|
2184
|
+
if (normalized.length === 0 || normalized.length > 320 || !email.test(normalized)) throw new TypeError("email is invalid");
|
|
2185
|
+
return normalized;
|
|
2186
|
+
}
|
|
2187
|
+
function normalizePassword(value, name = "password", minLength = 8) {
|
|
2188
|
+
if (typeof value !== "string" || value.length < minLength || value.length > 128) throw new TypeError(`${name} is invalid`);
|
|
2189
|
+
return value;
|
|
2190
|
+
}
|
|
2191
|
+
function normalizeSocialIdTokenInput(value) {
|
|
2192
|
+
if (!isObject(value)) throw new TypeError("social ID token input is invalid");
|
|
2193
|
+
const keys = Object.keys(value);
|
|
2194
|
+
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");
|
|
2195
|
+
return {
|
|
2196
|
+
provider: value.provider,
|
|
2197
|
+
idToken: value.idToken,
|
|
2198
|
+
...value.nonce === void 0 ? {} : { nonce: value.nonce },
|
|
2199
|
+
signUp: value.signUp
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
function socialIdTokenRequest(value) {
|
|
2203
|
+
return {
|
|
2204
|
+
provider: value.provider,
|
|
2205
|
+
idToken: {
|
|
2206
|
+
token: value.idToken,
|
|
2207
|
+
...value.nonce === void 0 ? {} : { nonce: value.nonce }
|
|
2208
|
+
},
|
|
2209
|
+
requestSignUp: value.signUp
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
function normalizeName(value) {
|
|
2213
|
+
if (typeof value !== "string") throw new TypeError("name is invalid");
|
|
2214
|
+
const normalized = value.trim();
|
|
2215
|
+
if (normalized.length === 0 || normalized.length > 256) throw new TypeError("name is invalid");
|
|
2216
|
+
return normalized;
|
|
2217
|
+
}
|
|
2218
|
+
function normalizeProfileInput(value) {
|
|
2219
|
+
if (!isObject(value)) throw new TypeError("profile input is invalid");
|
|
2220
|
+
const keys = Object.keys(value);
|
|
2221
|
+
if (keys.length === 0 || keys.length > 2 || keys.some((key) => key !== "name" && key !== "image") || value.name === void 0 && value.image === void 0) throw new TypeError("profile input is invalid");
|
|
2222
|
+
const result = {};
|
|
2223
|
+
if (value.name !== void 0) result.name = normalizeName(value.name);
|
|
2224
|
+
if (value.image !== void 0) result.image = value.image === null ? null : normalizeProfileImage(value.image);
|
|
2225
|
+
return result;
|
|
2226
|
+
}
|
|
2227
|
+
function normalizePasswordResetToken(value) {
|
|
2228
|
+
if (typeof value !== "string" || !passwordResetToken.test(value)) throw new TypeError("password reset token is invalid");
|
|
2229
|
+
return value;
|
|
2230
|
+
}
|
|
2231
|
+
function normalizeSameAppURL(value, appOrigin, name) {
|
|
2232
|
+
if (typeof value !== "string" || value.length > 2048 || /[^\x20-\x7e]/.test(value)) throw new TypeError(`${name} must belong to appOrigin`);
|
|
2233
|
+
let url;
|
|
2234
|
+
try {
|
|
2235
|
+
url = new URL(value);
|
|
2236
|
+
} catch {
|
|
2237
|
+
throw new TypeError(`${name} must belong to appOrigin`);
|
|
2238
|
+
}
|
|
2239
|
+
if (url.origin !== appOrigin || url.username || url.password || url.toString() !== value) throw new TypeError(`${name} must belong to appOrigin`);
|
|
2240
|
+
return value;
|
|
2241
|
+
}
|
|
2175
2242
|
function normalizeOrigin(value, name) {
|
|
2176
2243
|
if (value.length === 0 || value.length > 2048 || /[^\x20-\x7e]/.test(value)) throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
2177
2244
|
let url;
|
|
@@ -2208,7 +2275,7 @@ function normalizeSession(value) {
|
|
|
2208
2275
|
};
|
|
2209
2276
|
}
|
|
2210
2277
|
function normalizeDriveCredential(value, now) {
|
|
2211
|
-
if (!isObject(value) || value.tokenType !== "Bearer" || value.expiresIn !== DRIVE_CREDENTIAL_LIFETIME_SECONDS || typeof value.token !== "string" || value.token.length === 0 || value.token.
|
|
2278
|
+
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();
|
|
2212
2279
|
return {
|
|
2213
2280
|
tokenType: "Bearer",
|
|
2214
2281
|
token: value.token,
|
|
@@ -2235,19 +2302,12 @@ function normalizeInvitationInput(value) {
|
|
|
2235
2302
|
function normalizeVerificationEmailInput(value, appOrigin) {
|
|
2236
2303
|
if (!isObject(value)) throw new TypeError("verification email input is invalid");
|
|
2237
2304
|
const keys = Object.keys(value);
|
|
2238
|
-
if (keys.length !== 1 && keys.length !== 2 || !keys.includes("email") || keys.length === 2 && !keys.includes("callbackURL") || typeof value.email !== "string"
|
|
2239
|
-
|
|
2240
|
-
if (
|
|
2241
|
-
let callback;
|
|
2242
|
-
try {
|
|
2243
|
-
callback = new URL(value.callbackURL);
|
|
2244
|
-
} catch {
|
|
2245
|
-
throw new TypeError("callbackURL must belong to appOrigin");
|
|
2246
|
-
}
|
|
2247
|
-
if (callback.origin !== appOrigin || callback.username || callback.password || callback.toString() !== value.callbackURL) throw new TypeError("callbackURL must belong to appOrigin");
|
|
2305
|
+
if (keys.length !== 1 && keys.length !== 2 || !keys.includes("email") || keys.length === 2 && !keys.includes("callbackURL") || typeof value.email !== "string") throw new TypeError("verification email input is invalid");
|
|
2306
|
+
const normalizedEmail = normalizeEmail(value.email);
|
|
2307
|
+
if (value.callbackURL === void 0) return { email: normalizedEmail };
|
|
2248
2308
|
return {
|
|
2249
|
-
email:
|
|
2250
|
-
callbackURL: value.callbackURL
|
|
2309
|
+
email: normalizedEmail,
|
|
2310
|
+
callbackURL: normalizeSameAppURL(value.callbackURL, appOrigin, "callbackURL")
|
|
2251
2311
|
};
|
|
2252
2312
|
}
|
|
2253
2313
|
function normalizeVerificationEmailResponse(value) {
|
|
@@ -2271,6 +2331,26 @@ function fromAuthorityError(value, fallbackStatus, retryAfter) {
|
|
|
2271
2331
|
const mapped = mapError(isObject(value) && typeof value.code === "string" ? value.code : void 0, fallbackStatus);
|
|
2272
2332
|
return new AuthError(mapped.code, mapped.status, parseRetryAfter(retryAfter));
|
|
2273
2333
|
}
|
|
2334
|
+
function fromAccountAuthorityError(value, status, retryAfter) {
|
|
2335
|
+
const code = isObject(value) && typeof value.code === "string" ? value.code : void 0;
|
|
2336
|
+
if (status === 403 && (code === "INVALID_ORIGIN" || code === "MISSING_OR_NULL_ORIGIN")) return new AuthError("request_origin_denied", 403);
|
|
2337
|
+
if (code === "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL") return new AuthError("account_conflict", 409);
|
|
2338
|
+
if (code === "INVALID_TOKEN") return new AuthError("password_reset_invalid", 422);
|
|
2339
|
+
if (code === "INVALID_PASSWORD" || code === "INVALID_EMAIL_OR_PASSWORD") return new AuthError("invalid_credentials", 401);
|
|
2340
|
+
if (code === "INVALID_EMAIL" || code === "PASSWORD_TOO_SHORT" || code === "PASSWORD_TOO_LONG" || code === "BODY_MUST_BE_AN_OBJECT" || code === "EMAIL_CAN_NOT_BE_UPDATED") return new AuthError("invalid_auth_input", 422);
|
|
2341
|
+
if (status === 401) return new AuthError("authentication_required", 401);
|
|
2342
|
+
if (status === 403) return new AuthError("access_denied", 403);
|
|
2343
|
+
if (status === 409) return new AuthError("state_conflict", 409);
|
|
2344
|
+
if (status === 429) return new AuthError("auth_request_rate_limited", 429, parseRetryAfter(retryAfter));
|
|
2345
|
+
if (status === 400 || status === 422) return new AuthError("invalid_auth_input", 422);
|
|
2346
|
+
return authorityUnavailable();
|
|
2347
|
+
}
|
|
2348
|
+
function fromSocialIdTokenAuthorityError(value, status, retryAfter) {
|
|
2349
|
+
const code = isObject(value) && typeof value.code === "string" ? value.code : void 0;
|
|
2350
|
+
if (code === "INVALID_TOKEN" || code === "FAILED_TO_GET_USER_INFO" || code === "USER_EMAIL_NOT_FOUND") return new AuthError("invalid_credentials", 401);
|
|
2351
|
+
if (code === "OAUTH_LINK_ERROR") return new AuthError("account_conflict", 409);
|
|
2352
|
+
return fromAccountAuthorityError(value, status, retryAfter);
|
|
2353
|
+
}
|
|
2274
2354
|
function authorityUnavailable() {
|
|
2275
2355
|
return new AuthError("identity_authority_unavailable", 503);
|
|
2276
2356
|
}
|
|
@@ -2350,6 +2430,18 @@ function toDate(value) {
|
|
|
2350
2430
|
const result = value instanceof Date ? value : typeof value === "string" ? new Date(value) : void 0;
|
|
2351
2431
|
return result && Number.isFinite(result.getTime()) ? result : void 0;
|
|
2352
2432
|
}
|
|
2433
|
+
function normalizeProfileImage(value) {
|
|
2434
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 2048 || /[^\x20-\x7e]/.test(value)) throw new TypeError("profile image is invalid");
|
|
2435
|
+
let url;
|
|
2436
|
+
try {
|
|
2437
|
+
url = new URL(value);
|
|
2438
|
+
} catch {
|
|
2439
|
+
throw new TypeError("profile image is invalid");
|
|
2440
|
+
}
|
|
2441
|
+
const local = url.hostname === "localhost" || url.hostname.endsWith(".localhost") || url.hostname === "127.0.0.1";
|
|
2442
|
+
if (url.protocol !== "https:" && !(local && url.protocol === "http:") || url.username || url.password || url.toString() !== value) throw new TypeError("profile image is invalid");
|
|
2443
|
+
return value;
|
|
2444
|
+
}
|
|
2353
2445
|
function isId(value) {
|
|
2354
2446
|
return typeof value === "string" && id.test(value);
|
|
2355
2447
|
}
|
|
@@ -2369,7 +2461,7 @@ async function requestJsonResponse(url, options) {
|
|
|
2369
2461
|
method: options.method,
|
|
2370
2462
|
headers: options.headers,
|
|
2371
2463
|
body: options.body,
|
|
2372
|
-
credentials: "include",
|
|
2464
|
+
credentials: options.credentials ?? "include",
|
|
2373
2465
|
retry: 0,
|
|
2374
2466
|
timeout: options.timeoutMs,
|
|
2375
2467
|
redirect: "manual",
|
|
@@ -3181,12 +3273,14 @@ function createAuthClient(options) {
|
|
|
3181
3273
|
basePath: "/api/v1/auth",
|
|
3182
3274
|
fetchOptions: {
|
|
3183
3275
|
customFetchImpl: fetchImpl,
|
|
3276
|
+
credentials: "include",
|
|
3184
3277
|
retry: 0,
|
|
3185
3278
|
timeout: timeoutMs
|
|
3186
3279
|
}
|
|
3187
3280
|
});
|
|
3188
3281
|
const persistence = createSessionPersistence(options.persistence, authOrigin, now, timeoutMs);
|
|
3189
3282
|
const authStateListeners = new Set();
|
|
3283
|
+
const sessionListeners = new Set();
|
|
3190
3284
|
let authState = { status: "loading" };
|
|
3191
3285
|
let authStateStarted = false;
|
|
3192
3286
|
let credential;
|
|
@@ -3194,15 +3288,29 @@ function createAuthClient(options) {
|
|
|
3194
3288
|
let selectedWorkspaceKey;
|
|
3195
3289
|
let credentialGeneration = 0;
|
|
3196
3290
|
let authorityGeneration = 0;
|
|
3197
|
-
let
|
|
3198
|
-
let
|
|
3291
|
+
let sessionReadEpoch = 0;
|
|
3292
|
+
let activeAccountMutationGeneration;
|
|
3199
3293
|
let invitationAbort;
|
|
3200
3294
|
let invitationRequest;
|
|
3201
3295
|
let signOutRequest;
|
|
3202
3296
|
let sessionId;
|
|
3297
|
+
let sessionUserId;
|
|
3298
|
+
let sessionSignalSubscribed = false;
|
|
3299
|
+
let betterAuthRefetching = false;
|
|
3300
|
+
let suppressBetterAuthSettlement = false;
|
|
3301
|
+
let signalRefreshPending = false;
|
|
3302
|
+
let signalRefreshScheduled = false;
|
|
3303
|
+
let signalRefreshRequest;
|
|
3203
3304
|
function setAuthState(state) {
|
|
3204
3305
|
authState = state;
|
|
3205
|
-
for (const listener of authStateListeners)
|
|
3306
|
+
for (const listener of authStateListeners) try {
|
|
3307
|
+
listener(state);
|
|
3308
|
+
} catch {}
|
|
3309
|
+
}
|
|
3310
|
+
function emitSession(session) {
|
|
3311
|
+
for (const listener of sessionListeners) try {
|
|
3312
|
+
listener(session);
|
|
3313
|
+
} catch {}
|
|
3206
3314
|
}
|
|
3207
3315
|
function unavailable() {
|
|
3208
3316
|
setAuthState({
|
|
@@ -3229,26 +3337,16 @@ function createAuthClient(options) {
|
|
|
3229
3337
|
});
|
|
3230
3338
|
persistence.remove();
|
|
3231
3339
|
}
|
|
3340
|
+
emitSession(normalized);
|
|
3232
3341
|
return normalized;
|
|
3233
3342
|
}
|
|
3234
3343
|
function startAuthState() {
|
|
3235
3344
|
if (authStateStarted) return;
|
|
3236
3345
|
authStateStarted = true;
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
if (state.error) {
|
|
3240
|
-
unavailable();
|
|
3241
|
-
return;
|
|
3242
|
-
}
|
|
3243
|
-
try {
|
|
3244
|
-
const session = normalizeSession(state.data);
|
|
3245
|
-
if (session && (locallySignedOut || signOutRequest)) return;
|
|
3246
|
-
acceptAuthoritySession(session);
|
|
3247
|
-
} catch {
|
|
3248
|
-
unavailable();
|
|
3249
|
-
}
|
|
3250
|
-
});
|
|
3346
|
+
subscribeToSessionSignals();
|
|
3347
|
+
const hydrationGeneration = authorityGeneration;
|
|
3251
3348
|
persistence.hydrate((session) => {
|
|
3349
|
+
if (hydrationGeneration !== authorityGeneration || activeAccountMutationGeneration !== void 0) return;
|
|
3252
3350
|
if (authState.status === "loading") setAuthState({
|
|
3253
3351
|
status: "cached",
|
|
3254
3352
|
session,
|
|
@@ -3260,7 +3358,45 @@ function createAuthClient(options) {
|
|
|
3260
3358
|
authoritative: false
|
|
3261
3359
|
});
|
|
3262
3360
|
});
|
|
3263
|
-
|
|
3361
|
+
getSession().catch(() => void 0);
|
|
3362
|
+
}
|
|
3363
|
+
function subscribeToSessionSignals() {
|
|
3364
|
+
if (sessionSignalSubscribed) return;
|
|
3365
|
+
sessionSignalSubscribed = true;
|
|
3366
|
+
let initialized = false;
|
|
3367
|
+
betterAuth.useSession.subscribe((state) => {
|
|
3368
|
+
const refetching = state.isRefetching === true;
|
|
3369
|
+
if (!initialized) {
|
|
3370
|
+
initialized = true;
|
|
3371
|
+
betterAuthRefetching = refetching;
|
|
3372
|
+
return;
|
|
3373
|
+
}
|
|
3374
|
+
const settled = betterAuthRefetching && !refetching;
|
|
3375
|
+
betterAuthRefetching = refetching;
|
|
3376
|
+
if (refetching && signOutRequest) suppressBetterAuthSettlement = true;
|
|
3377
|
+
if (!settled) return;
|
|
3378
|
+
if (suppressBetterAuthSettlement) {
|
|
3379
|
+
suppressBetterAuthSettlement = false;
|
|
3380
|
+
return;
|
|
3381
|
+
}
|
|
3382
|
+
queueSignalRefresh();
|
|
3383
|
+
});
|
|
3384
|
+
}
|
|
3385
|
+
function queueSignalRefresh() {
|
|
3386
|
+
signalRefreshPending = true;
|
|
3387
|
+
if (signalRefreshScheduled || signalRefreshRequest || signOutRequest || activeAccountMutationGeneration !== void 0) return;
|
|
3388
|
+
signalRefreshScheduled = true;
|
|
3389
|
+
queueMicrotask(runSignalRefresh);
|
|
3390
|
+
}
|
|
3391
|
+
function runSignalRefresh() {
|
|
3392
|
+
signalRefreshScheduled = false;
|
|
3393
|
+
if (!signalRefreshPending || signalRefreshRequest || signOutRequest || activeAccountMutationGeneration !== void 0) return;
|
|
3394
|
+
signalRefreshPending = false;
|
|
3395
|
+
const request = refreshAuthoritySession(authorityGeneration).then(() => void 0, () => void 0).finally(() => {
|
|
3396
|
+
if (signalRefreshRequest === request) signalRefreshRequest = void 0;
|
|
3397
|
+
if (signalRefreshPending) queueSignalRefresh();
|
|
3398
|
+
});
|
|
3399
|
+
signalRefreshRequest = request;
|
|
3264
3400
|
}
|
|
3265
3401
|
function clearCredential() {
|
|
3266
3402
|
credential = void 0;
|
|
@@ -3270,44 +3406,52 @@ function createAuthClient(options) {
|
|
|
3270
3406
|
}
|
|
3271
3407
|
function updateSession(session) {
|
|
3272
3408
|
const unboundCredential = !sessionId && (credential || credentialRequests.size > 0);
|
|
3273
|
-
if (!session || unboundCredential || sessionId && session.id !== sessionId) clearCredential();
|
|
3409
|
+
if (!session || unboundCredential || sessionId && (session.id !== sessionId || session.user.id !== sessionUserId)) clearCredential();
|
|
3274
3410
|
sessionId = session?.id;
|
|
3411
|
+
sessionUserId = session?.user.id;
|
|
3275
3412
|
return session;
|
|
3276
3413
|
}
|
|
3277
|
-
async function
|
|
3278
|
-
|
|
3279
|
-
locallySignedOut = false;
|
|
3280
|
-
const generation = authorityGeneration;
|
|
3281
|
-
let result;
|
|
3282
|
-
try {
|
|
3283
|
-
result = await betterAuth.getSession();
|
|
3284
|
-
} catch {
|
|
3285
|
-
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3286
|
-
unavailable();
|
|
3287
|
-
throw authorityUnavailable();
|
|
3288
|
-
}
|
|
3289
|
-
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3290
|
-
if (result.error) {
|
|
3291
|
-
unavailable();
|
|
3292
|
-
throw fromAuthorityError(result.error, result.error.status);
|
|
3293
|
-
}
|
|
3414
|
+
async function refreshAuthoritySession(generation) {
|
|
3415
|
+
const readEpoch = ++sessionReadEpoch;
|
|
3294
3416
|
try {
|
|
3295
|
-
|
|
3417
|
+
const response = await requestJsonResponse(joinURL(authOrigin, "api/v1/auth/get-session"), {
|
|
3418
|
+
fetch: fetchImpl,
|
|
3419
|
+
timeoutMs,
|
|
3420
|
+
method: "GET"
|
|
3421
|
+
});
|
|
3422
|
+
if (generation !== authorityGeneration || readEpoch !== sessionReadEpoch) throw new AuthError("state_conflict", 409);
|
|
3423
|
+
return acceptAuthoritySession(normalizeSession(response.value), generation);
|
|
3296
3424
|
} catch (error) {
|
|
3297
|
-
if (
|
|
3425
|
+
if (generation !== authorityGeneration || readEpoch !== sessionReadEpoch) throw new AuthError("state_conflict", 409);
|
|
3426
|
+
if (error instanceof AuthError && error.code === "state_conflict") throw error;
|
|
3298
3427
|
unavailable();
|
|
3428
|
+
if (error instanceof AuthError) throw error;
|
|
3299
3429
|
throw authorityUnavailable();
|
|
3300
3430
|
}
|
|
3301
3431
|
}
|
|
3432
|
+
function getSession() {
|
|
3433
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3434
|
+
return refreshAuthoritySession(authorityGeneration);
|
|
3435
|
+
}
|
|
3302
3436
|
function signOut() {
|
|
3303
3437
|
if (signOutRequest) return signOutRequest;
|
|
3438
|
+
if (activeAccountMutationGeneration !== void 0) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3304
3439
|
const pendingInvitation = invitationRequest;
|
|
3305
3440
|
invitationAbort?.abort();
|
|
3306
3441
|
const generation = ++authorityGeneration;
|
|
3307
|
-
|
|
3442
|
+
sessionReadEpoch += 1;
|
|
3308
3443
|
clearCredential();
|
|
3309
3444
|
sessionId = void 0;
|
|
3445
|
+
sessionUserId = void 0;
|
|
3446
|
+
if (betterAuthRefetching) suppressBetterAuthSettlement = true;
|
|
3447
|
+
signalRefreshPending = false;
|
|
3310
3448
|
persistence.remove();
|
|
3449
|
+
setAuthState({
|
|
3450
|
+
status: "unavailable",
|
|
3451
|
+
session: null,
|
|
3452
|
+
authoritative: false
|
|
3453
|
+
});
|
|
3454
|
+
emitSession(null);
|
|
3311
3455
|
const request = (async () => {
|
|
3312
3456
|
await pendingInvitation?.catch(() => void 0);
|
|
3313
3457
|
let result;
|
|
@@ -3315,13 +3459,11 @@ function createAuthClient(options) {
|
|
|
3315
3459
|
result = await betterAuth.signOut();
|
|
3316
3460
|
} catch {
|
|
3317
3461
|
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3318
|
-
locallySignedOut = false;
|
|
3319
3462
|
unavailable();
|
|
3320
3463
|
throw authorityUnavailable();
|
|
3321
3464
|
}
|
|
3322
3465
|
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3323
3466
|
if (result.error) {
|
|
3324
|
-
locallySignedOut = false;
|
|
3325
3467
|
unavailable();
|
|
3326
3468
|
throw fromAuthorityError(result.error, result.error.status);
|
|
3327
3469
|
}
|
|
@@ -3330,12 +3472,68 @@ function createAuthClient(options) {
|
|
|
3330
3472
|
session: null,
|
|
3331
3473
|
authoritative: true
|
|
3332
3474
|
});
|
|
3475
|
+
emitSession(null);
|
|
3333
3476
|
})().finally(() => {
|
|
3334
|
-
if (signOutRequest === request)
|
|
3477
|
+
if (signOutRequest === request) {
|
|
3478
|
+
signOutRequest = void 0;
|
|
3479
|
+
signalRefreshPending = false;
|
|
3480
|
+
}
|
|
3335
3481
|
});
|
|
3336
3482
|
signOutRequest = request;
|
|
3337
3483
|
return request;
|
|
3338
3484
|
}
|
|
3485
|
+
async function runAccountMutation(operation) {
|
|
3486
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0) throw new AuthError("state_conflict", 409);
|
|
3487
|
+
const pendingInvitation = invitationRequest;
|
|
3488
|
+
invitationAbort?.abort();
|
|
3489
|
+
const generation = ++authorityGeneration;
|
|
3490
|
+
sessionReadEpoch += 1;
|
|
3491
|
+
activeAccountMutationGeneration = generation;
|
|
3492
|
+
clearCredential();
|
|
3493
|
+
sessionId = void 0;
|
|
3494
|
+
sessionUserId = void 0;
|
|
3495
|
+
persistence.remove();
|
|
3496
|
+
setAuthState({
|
|
3497
|
+
status: "unavailable",
|
|
3498
|
+
session: null,
|
|
3499
|
+
authoritative: false
|
|
3500
|
+
});
|
|
3501
|
+
emitSession(null);
|
|
3502
|
+
try {
|
|
3503
|
+
await pendingInvitation?.catch(() => void 0);
|
|
3504
|
+
try {
|
|
3505
|
+
const data = await operation();
|
|
3506
|
+
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3507
|
+
return {
|
|
3508
|
+
data,
|
|
3509
|
+
session: await refreshAuthoritySession(generation)
|
|
3510
|
+
};
|
|
3511
|
+
} catch (error) {
|
|
3512
|
+
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3513
|
+
if (error instanceof AuthError) {
|
|
3514
|
+
unavailable();
|
|
3515
|
+
throw error;
|
|
3516
|
+
}
|
|
3517
|
+
unavailable();
|
|
3518
|
+
throw authorityUnavailable();
|
|
3519
|
+
}
|
|
3520
|
+
} finally {
|
|
3521
|
+
if (activeAccountMutationGeneration === generation) {
|
|
3522
|
+
activeAccountMutationGeneration = void 0;
|
|
3523
|
+
if (signalRefreshPending) queueSignalRefresh();
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
}
|
|
3527
|
+
async function accountRequest(path, body, mapError = fromAccountAuthorityError) {
|
|
3528
|
+
return (await requestJsonResponse(joinURL(authOrigin, "api/v1/auth", path), {
|
|
3529
|
+
fetch: fetchImpl,
|
|
3530
|
+
timeoutMs,
|
|
3531
|
+
method: "POST",
|
|
3532
|
+
headers: { "content-type": "application/json; charset=utf-8" },
|
|
3533
|
+
body,
|
|
3534
|
+
mapError
|
|
3535
|
+
})).value;
|
|
3536
|
+
}
|
|
3339
3537
|
return {
|
|
3340
3538
|
acceptInvitation(input) {
|
|
3341
3539
|
let invitation;
|
|
@@ -3344,7 +3542,7 @@ function createAuthClient(options) {
|
|
|
3344
3542
|
} catch (error) {
|
|
3345
3543
|
return Promise.reject(error);
|
|
3346
3544
|
}
|
|
3347
|
-
if (signOutRequest ||
|
|
3545
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3348
3546
|
const generation = authorityGeneration;
|
|
3349
3547
|
const controller = new AbortController();
|
|
3350
3548
|
clearCredential();
|
|
@@ -3377,7 +3575,7 @@ function createAuthClient(options) {
|
|
|
3377
3575
|
},
|
|
3378
3576
|
getSession,
|
|
3379
3577
|
async listOrganizations() {
|
|
3380
|
-
if (signOutRequest ||
|
|
3578
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) throw new AuthError("state_conflict", 409);
|
|
3381
3579
|
const generation = authorityGeneration;
|
|
3382
3580
|
try {
|
|
3383
3581
|
const value = await requestJson(joinURL(authOrigin, "api/v1/auth/organization/list"), {
|
|
@@ -3393,37 +3591,60 @@ function createAuthClient(options) {
|
|
|
3393
3591
|
}
|
|
3394
3592
|
},
|
|
3395
3593
|
async signIn(input) {
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3594
|
+
const body = {
|
|
3595
|
+
email: normalizeEmail(input?.email),
|
|
3596
|
+
password: normalizePassword(input?.password)
|
|
3597
|
+
};
|
|
3598
|
+
const result = await runAccountMutation(() => accountRequest("sign-in/email", body));
|
|
3599
|
+
if (!result.session) throw new AuthError("authentication_required", 401);
|
|
3600
|
+
return result.session;
|
|
3601
|
+
},
|
|
3602
|
+
async signInWithSocialIdToken(input) {
|
|
3603
|
+
const body = socialIdTokenRequest(normalizeSocialIdTokenInput(input));
|
|
3604
|
+
const result = await runAccountMutation(() => accountRequest("sign-in/social", body, fromSocialIdTokenAuthorityError));
|
|
3605
|
+
if (!result.session) throw new AuthError("authentication_required", 401);
|
|
3606
|
+
return result.session;
|
|
3607
|
+
},
|
|
3608
|
+
async signUp(email, password, name) {
|
|
3609
|
+
const body = {
|
|
3610
|
+
email: normalizeEmail(email),
|
|
3611
|
+
password: normalizePassword(password, "password", 10),
|
|
3612
|
+
name: normalizeName(name)
|
|
3613
|
+
};
|
|
3614
|
+
const result = await runAccountMutation(() => accountRequest("sign-up/email", body));
|
|
3615
|
+
if (!result.session) throw new AuthError("authentication_required", 401);
|
|
3616
|
+
return result.session;
|
|
3617
|
+
},
|
|
3618
|
+
async updateProfile(input) {
|
|
3619
|
+
const body = normalizeProfileInput(input);
|
|
3620
|
+
const result = await runAccountMutation(() => accountRequest("update-user", body));
|
|
3621
|
+
if (!result.session) throw new AuthError("authentication_required", 401);
|
|
3622
|
+
return result.session;
|
|
3623
|
+
},
|
|
3624
|
+
async changePassword(currentPassword, newPassword, revokeOtherSessions = true) {
|
|
3625
|
+
const current = normalizePassword(currentPassword, "currentPassword");
|
|
3626
|
+
const next = normalizePassword(newPassword, "newPassword", 10);
|
|
3627
|
+
if (typeof revokeOtherSessions !== "boolean") throw new TypeError("revokeOtherSessions is invalid");
|
|
3628
|
+
const result = await runAccountMutation(() => accountRequest("change-password", {
|
|
3629
|
+
currentPassword: current,
|
|
3630
|
+
newPassword: next,
|
|
3631
|
+
revokeOtherSessions
|
|
3632
|
+
}));
|
|
3633
|
+
if (!result.session) throw new AuthError("authentication_required", 401);
|
|
3634
|
+
return result.session;
|
|
3635
|
+
},
|
|
3636
|
+
async requestPasswordReset(email, redirectTo) {
|
|
3637
|
+
normalizeVerificationEmailResponse(await accountRequest("request-password-reset", {
|
|
3638
|
+
email: normalizeEmail(email),
|
|
3639
|
+
redirectTo: normalizeSameAppURL(redirectTo, appOrigin, "redirectTo")
|
|
3640
|
+
}));
|
|
3641
|
+
},
|
|
3642
|
+
async resetPassword(token, newPassword) {
|
|
3643
|
+
const body = {
|
|
3644
|
+
token: normalizePasswordResetToken(token),
|
|
3645
|
+
newPassword: normalizePassword(newPassword, "newPassword", 10)
|
|
3646
|
+
};
|
|
3647
|
+
normalizeVerificationEmailResponse((await runAccountMutation(() => accountRequest("reset-password", body))).data);
|
|
3427
3648
|
},
|
|
3428
3649
|
async sendVerificationEmail(input) {
|
|
3429
3650
|
const body = normalizeVerificationEmailInput(input, appOrigin);
|
|
@@ -3443,7 +3664,7 @@ function createAuthClient(options) {
|
|
|
3443
3664
|
} catch (error) {
|
|
3444
3665
|
return Promise.reject(error);
|
|
3445
3666
|
}
|
|
3446
|
-
if (invitationRequest) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3667
|
+
if (invitationRequest || signOutRequest || activeAccountMutationGeneration !== void 0) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3447
3668
|
const workspaceKey = workspace.type === "personal" ? "personal" : `organization:${workspace.organizationId}`;
|
|
3448
3669
|
if (selectedWorkspaceKey !== workspaceKey) {
|
|
3449
3670
|
credential = void 0;
|
|
@@ -3480,21 +3701,20 @@ function createAuthClient(options) {
|
|
|
3480
3701
|
},
|
|
3481
3702
|
onAuthStateChange(listener) {
|
|
3482
3703
|
authStateListeners.add(listener);
|
|
3483
|
-
|
|
3704
|
+
try {
|
|
3705
|
+
listener(authState);
|
|
3706
|
+
} catch {}
|
|
3484
3707
|
startAuthState();
|
|
3485
3708
|
return () => authStateListeners.delete(listener);
|
|
3486
3709
|
},
|
|
3487
3710
|
onSessionChange(listener) {
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
}
|
|
3496
|
-
listener(session);
|
|
3497
|
-
});
|
|
3711
|
+
sessionListeners.add(listener);
|
|
3712
|
+
try {
|
|
3713
|
+
if (authState.status === "authenticated") listener(authState.session);
|
|
3714
|
+
else if (authState.status === "unauthenticated") listener(null);
|
|
3715
|
+
} catch {}
|
|
3716
|
+
startAuthState();
|
|
3717
|
+
return () => sessionListeners.delete(listener);
|
|
3498
3718
|
}
|
|
3499
3719
|
};
|
|
3500
3720
|
}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { _ as WorkspaceSelection, c as AuthUser, f as InvitationAcceptance, l as DriveCredential, m as PersonalWorkspaceSelection, o as AuthSession, p as OrganizationWorkspaceSelection, r as AuthOrganization, t as AcceptInvitationInput, u as DriveCredentialInput } from "./types-
|
|
2
|
-
import { n as AuthErrorCode, r as AuthErrorStatus, t as AuthError } from "./errors-Crd93Rah.js";
|
|
1
|
+
import { C as AuthErrorStatus, S as AuthErrorCode, _ as SocialIdTokenInput, b as WorkspaceSelection, c as AuthUser, f as InvitationAcceptance, l as DriveCredential, m as PersonalWorkspaceSelection, o as AuthSession, p as OrganizationWorkspaceSelection, r as AuthOrganization, t as AcceptInvitationInput, u as DriveCredentialInput, v as SocialIdTokenProvider, x as AuthError } from "./types-B1SZbs6Z.js";
|
|
3
2
|
//#region src/server.d.ts
|
|
4
3
|
interface ServerAuthOptions {
|
|
5
4
|
authOrigin: string;
|
|
@@ -15,13 +14,17 @@ interface ServerSignOutResult {
|
|
|
15
14
|
interface ServerInvitationAcceptance extends InvitationAcceptance {
|
|
16
15
|
applyCookies(headers: Headers): void;
|
|
17
16
|
}
|
|
17
|
+
interface ServerSocialIdTokenSession extends AuthSession {
|
|
18
|
+
applyCookies(headers: Headers): void;
|
|
19
|
+
}
|
|
18
20
|
interface FinuevaServerAuth {
|
|
19
21
|
acceptInvitation(input: AcceptInvitationInput): Promise<ServerInvitationAcceptance>;
|
|
20
22
|
getSession(): Promise<AuthSession | null>;
|
|
21
23
|
listOrganizations(): Promise<AuthOrganization[]>;
|
|
24
|
+
signInWithSocialIdToken(input: SocialIdTokenInput): Promise<ServerSocialIdTokenSession>;
|
|
22
25
|
getDriveCredential(input: DriveCredentialInput): Promise<DriveCredential>;
|
|
23
26
|
signOut(): Promise<ServerSignOutResult>;
|
|
24
27
|
}
|
|
25
28
|
declare function createServerAuth(options: ServerAuthOptions): FinuevaServerAuth;
|
|
26
29
|
//#endregion
|
|
27
|
-
export { type AcceptInvitationInput, AuthError, type AuthErrorCode, type AuthErrorStatus, type AuthOrganization, type AuthSession, type AuthUser, type DriveCredential, type DriveCredentialInput, FinuevaServerAuth, type InvitationAcceptance, type OrganizationWorkspaceSelection, type PersonalWorkspaceSelection, ServerAuthOptions, ServerInvitationAcceptance, ServerSignOutResult, type WorkspaceSelection, createServerAuth };
|
|
30
|
+
export { type AcceptInvitationInput, AuthError, type AuthErrorCode, type AuthErrorStatus, type AuthOrganization, type AuthSession, type AuthUser, type DriveCredential, type DriveCredentialInput, FinuevaServerAuth, type InvitationAcceptance, type OrganizationWorkspaceSelection, type PersonalWorkspaceSelection, ServerAuthOptions, ServerInvitationAcceptance, ServerSignOutResult, ServerSocialIdTokenSession, type SocialIdTokenInput, type SocialIdTokenProvider, type WorkspaceSelection, createServerAuth };
|