@finueva/auth 0.5.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/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/device.d.ts +8 -2
- package/dist/device.js +616 -101
- package/dist/index.d.ts +2 -3
- package/dist/index.js +323 -102
- package/dist/server.d.ts +6 -3
- package/dist/server.js +127 -35
- package/dist/{types-HSdjQWMZ.d.ts → types-B1SZbs6Z.d.ts} +28 -1
- package/package.json +3 -2
- 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
|
@@ -1635,7 +1635,7 @@ function createAuthClient$1(options) {
|
|
|
1635
1635
|
}, $fetch, pluginPathMethods, pluginsAtoms, atomListeners);
|
|
1636
1636
|
}
|
|
1637
1637
|
//#endregion
|
|
1638
|
-
//#region ../../node_modules/.pnpm/@chiballc+utils@2.
|
|
1638
|
+
//#region ../../node_modules/.pnpm/@chiballc+utils@2.5.0_@hono+zod-openapi@1.5.1_hono@4.13.0_zod@4.4.3__hono@4.13.0_magic-_deb761a9672ce7cf69932b564bd2142d/node_modules/@chiballc/utils/dist/index.mjs
|
|
1639
1639
|
function isPromise(arg) {
|
|
1640
1640
|
return arg && typeof arg.then === "function";
|
|
1641
1641
|
}
|
|
@@ -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."
|
|
@@ -2169,8 +2173,72 @@ function createFetch(globalOptions = {}) {
|
|
|
2169
2173
|
}
|
|
2170
2174
|
//#endregion
|
|
2171
2175
|
//#region src/shared.ts
|
|
2176
|
+
const DRIVE_CREDENTIAL_LIFETIME_SECONDS = 840;
|
|
2172
2177
|
const id = /^[A-Za-z0-9_-]{1,128}$/;
|
|
2173
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
|
+
}
|
|
2174
2242
|
function normalizeOrigin(value, name) {
|
|
2175
2243
|
if (value.length === 0 || value.length > 2048 || /[^\x20-\x7e]/.test(value)) throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
2176
2244
|
let url;
|
|
@@ -2207,7 +2275,7 @@ function normalizeSession(value) {
|
|
|
2207
2275
|
};
|
|
2208
2276
|
}
|
|
2209
2277
|
function normalizeDriveCredential(value, now) {
|
|
2210
|
-
if (!isObject(value) || value.tokenType !== "Bearer" || value.expiresIn !==
|
|
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();
|
|
2211
2279
|
return {
|
|
2212
2280
|
tokenType: "Bearer",
|
|
2213
2281
|
token: value.token,
|
|
@@ -2234,19 +2302,12 @@ function normalizeInvitationInput(value) {
|
|
|
2234
2302
|
function normalizeVerificationEmailInput(value, appOrigin) {
|
|
2235
2303
|
if (!isObject(value)) throw new TypeError("verification email input is invalid");
|
|
2236
2304
|
const keys = Object.keys(value);
|
|
2237
|
-
if (keys.length !== 1 && keys.length !== 2 || !keys.includes("email") || keys.length === 2 && !keys.includes("callbackURL") || typeof value.email !== "string"
|
|
2238
|
-
|
|
2239
|
-
if (
|
|
2240
|
-
let callback;
|
|
2241
|
-
try {
|
|
2242
|
-
callback = new URL(value.callbackURL);
|
|
2243
|
-
} catch {
|
|
2244
|
-
throw new TypeError("callbackURL must belong to appOrigin");
|
|
2245
|
-
}
|
|
2246
|
-
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 };
|
|
2247
2308
|
return {
|
|
2248
|
-
email:
|
|
2249
|
-
callbackURL: value.callbackURL
|
|
2309
|
+
email: normalizedEmail,
|
|
2310
|
+
callbackURL: normalizeSameAppURL(value.callbackURL, appOrigin, "callbackURL")
|
|
2250
2311
|
};
|
|
2251
2312
|
}
|
|
2252
2313
|
function normalizeVerificationEmailResponse(value) {
|
|
@@ -2270,6 +2331,26 @@ function fromAuthorityError(value, fallbackStatus, retryAfter) {
|
|
|
2270
2331
|
const mapped = mapError(isObject(value) && typeof value.code === "string" ? value.code : void 0, fallbackStatus);
|
|
2271
2332
|
return new AuthError(mapped.code, mapped.status, parseRetryAfter(retryAfter));
|
|
2272
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
|
+
}
|
|
2273
2354
|
function authorityUnavailable() {
|
|
2274
2355
|
return new AuthError("identity_authority_unavailable", 503);
|
|
2275
2356
|
}
|
|
@@ -2349,6 +2430,18 @@ function toDate(value) {
|
|
|
2349
2430
|
const result = value instanceof Date ? value : typeof value === "string" ? new Date(value) : void 0;
|
|
2350
2431
|
return result && Number.isFinite(result.getTime()) ? result : void 0;
|
|
2351
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
|
+
}
|
|
2352
2445
|
function isId(value) {
|
|
2353
2446
|
return typeof value === "string" && id.test(value);
|
|
2354
2447
|
}
|
|
@@ -2368,7 +2461,7 @@ async function requestJsonResponse(url, options) {
|
|
|
2368
2461
|
method: options.method,
|
|
2369
2462
|
headers: options.headers,
|
|
2370
2463
|
body: options.body,
|
|
2371
|
-
credentials: "include",
|
|
2464
|
+
credentials: options.credentials ?? "include",
|
|
2372
2465
|
retry: 0,
|
|
2373
2466
|
timeout: options.timeoutMs,
|
|
2374
2467
|
redirect: "manual",
|
|
@@ -3180,12 +3273,14 @@ function createAuthClient(options) {
|
|
|
3180
3273
|
basePath: "/api/v1/auth",
|
|
3181
3274
|
fetchOptions: {
|
|
3182
3275
|
customFetchImpl: fetchImpl,
|
|
3276
|
+
credentials: "include",
|
|
3183
3277
|
retry: 0,
|
|
3184
3278
|
timeout: timeoutMs
|
|
3185
3279
|
}
|
|
3186
3280
|
});
|
|
3187
3281
|
const persistence = createSessionPersistence(options.persistence, authOrigin, now, timeoutMs);
|
|
3188
3282
|
const authStateListeners = new Set();
|
|
3283
|
+
const sessionListeners = new Set();
|
|
3189
3284
|
let authState = { status: "loading" };
|
|
3190
3285
|
let authStateStarted = false;
|
|
3191
3286
|
let credential;
|
|
@@ -3193,15 +3288,29 @@ function createAuthClient(options) {
|
|
|
3193
3288
|
let selectedWorkspaceKey;
|
|
3194
3289
|
let credentialGeneration = 0;
|
|
3195
3290
|
let authorityGeneration = 0;
|
|
3196
|
-
let
|
|
3197
|
-
let
|
|
3291
|
+
let sessionReadEpoch = 0;
|
|
3292
|
+
let activeAccountMutationGeneration;
|
|
3198
3293
|
let invitationAbort;
|
|
3199
3294
|
let invitationRequest;
|
|
3200
3295
|
let signOutRequest;
|
|
3201
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;
|
|
3202
3304
|
function setAuthState(state) {
|
|
3203
3305
|
authState = state;
|
|
3204
|
-
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 {}
|
|
3205
3314
|
}
|
|
3206
3315
|
function unavailable() {
|
|
3207
3316
|
setAuthState({
|
|
@@ -3228,26 +3337,16 @@ function createAuthClient(options) {
|
|
|
3228
3337
|
});
|
|
3229
3338
|
persistence.remove();
|
|
3230
3339
|
}
|
|
3340
|
+
emitSession(normalized);
|
|
3231
3341
|
return normalized;
|
|
3232
3342
|
}
|
|
3233
3343
|
function startAuthState() {
|
|
3234
3344
|
if (authStateStarted) return;
|
|
3235
3345
|
authStateStarted = true;
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
if (state.error) {
|
|
3239
|
-
unavailable();
|
|
3240
|
-
return;
|
|
3241
|
-
}
|
|
3242
|
-
try {
|
|
3243
|
-
const session = normalizeSession(state.data);
|
|
3244
|
-
if (session && (locallySignedOut || signOutRequest)) return;
|
|
3245
|
-
acceptAuthoritySession(session);
|
|
3246
|
-
} catch {
|
|
3247
|
-
unavailable();
|
|
3248
|
-
}
|
|
3249
|
-
});
|
|
3346
|
+
subscribeToSessionSignals();
|
|
3347
|
+
const hydrationGeneration = authorityGeneration;
|
|
3250
3348
|
persistence.hydrate((session) => {
|
|
3349
|
+
if (hydrationGeneration !== authorityGeneration || activeAccountMutationGeneration !== void 0) return;
|
|
3251
3350
|
if (authState.status === "loading") setAuthState({
|
|
3252
3351
|
status: "cached",
|
|
3253
3352
|
session,
|
|
@@ -3259,7 +3358,45 @@ function createAuthClient(options) {
|
|
|
3259
3358
|
authoritative: false
|
|
3260
3359
|
});
|
|
3261
3360
|
});
|
|
3262
|
-
|
|
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;
|
|
3263
3400
|
}
|
|
3264
3401
|
function clearCredential() {
|
|
3265
3402
|
credential = void 0;
|
|
@@ -3269,44 +3406,52 @@ function createAuthClient(options) {
|
|
|
3269
3406
|
}
|
|
3270
3407
|
function updateSession(session) {
|
|
3271
3408
|
const unboundCredential = !sessionId && (credential || credentialRequests.size > 0);
|
|
3272
|
-
if (!session || unboundCredential || sessionId && session.id !== sessionId) clearCredential();
|
|
3409
|
+
if (!session || unboundCredential || sessionId && (session.id !== sessionId || session.user.id !== sessionUserId)) clearCredential();
|
|
3273
3410
|
sessionId = session?.id;
|
|
3411
|
+
sessionUserId = session?.user.id;
|
|
3274
3412
|
return session;
|
|
3275
3413
|
}
|
|
3276
|
-
async function
|
|
3277
|
-
|
|
3278
|
-
locallySignedOut = false;
|
|
3279
|
-
const generation = authorityGeneration;
|
|
3280
|
-
let result;
|
|
3281
|
-
try {
|
|
3282
|
-
result = await betterAuth.getSession();
|
|
3283
|
-
} catch {
|
|
3284
|
-
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3285
|
-
unavailable();
|
|
3286
|
-
throw authorityUnavailable();
|
|
3287
|
-
}
|
|
3288
|
-
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3289
|
-
if (result.error) {
|
|
3290
|
-
unavailable();
|
|
3291
|
-
throw fromAuthorityError(result.error, result.error.status);
|
|
3292
|
-
}
|
|
3414
|
+
async function refreshAuthoritySession(generation) {
|
|
3415
|
+
const readEpoch = ++sessionReadEpoch;
|
|
3293
3416
|
try {
|
|
3294
|
-
|
|
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);
|
|
3295
3424
|
} catch (error) {
|
|
3296
|
-
if (
|
|
3425
|
+
if (generation !== authorityGeneration || readEpoch !== sessionReadEpoch) throw new AuthError("state_conflict", 409);
|
|
3426
|
+
if (error instanceof AuthError && error.code === "state_conflict") throw error;
|
|
3297
3427
|
unavailable();
|
|
3428
|
+
if (error instanceof AuthError) throw error;
|
|
3298
3429
|
throw authorityUnavailable();
|
|
3299
3430
|
}
|
|
3300
3431
|
}
|
|
3432
|
+
function getSession() {
|
|
3433
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3434
|
+
return refreshAuthoritySession(authorityGeneration);
|
|
3435
|
+
}
|
|
3301
3436
|
function signOut() {
|
|
3302
3437
|
if (signOutRequest) return signOutRequest;
|
|
3438
|
+
if (activeAccountMutationGeneration !== void 0) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3303
3439
|
const pendingInvitation = invitationRequest;
|
|
3304
3440
|
invitationAbort?.abort();
|
|
3305
3441
|
const generation = ++authorityGeneration;
|
|
3306
|
-
|
|
3442
|
+
sessionReadEpoch += 1;
|
|
3307
3443
|
clearCredential();
|
|
3308
3444
|
sessionId = void 0;
|
|
3445
|
+
sessionUserId = void 0;
|
|
3446
|
+
if (betterAuthRefetching) suppressBetterAuthSettlement = true;
|
|
3447
|
+
signalRefreshPending = false;
|
|
3309
3448
|
persistence.remove();
|
|
3449
|
+
setAuthState({
|
|
3450
|
+
status: "unavailable",
|
|
3451
|
+
session: null,
|
|
3452
|
+
authoritative: false
|
|
3453
|
+
});
|
|
3454
|
+
emitSession(null);
|
|
3310
3455
|
const request = (async () => {
|
|
3311
3456
|
await pendingInvitation?.catch(() => void 0);
|
|
3312
3457
|
let result;
|
|
@@ -3314,13 +3459,11 @@ function createAuthClient(options) {
|
|
|
3314
3459
|
result = await betterAuth.signOut();
|
|
3315
3460
|
} catch {
|
|
3316
3461
|
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3317
|
-
locallySignedOut = false;
|
|
3318
3462
|
unavailable();
|
|
3319
3463
|
throw authorityUnavailable();
|
|
3320
3464
|
}
|
|
3321
3465
|
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3322
3466
|
if (result.error) {
|
|
3323
|
-
locallySignedOut = false;
|
|
3324
3467
|
unavailable();
|
|
3325
3468
|
throw fromAuthorityError(result.error, result.error.status);
|
|
3326
3469
|
}
|
|
@@ -3329,12 +3472,68 @@ function createAuthClient(options) {
|
|
|
3329
3472
|
session: null,
|
|
3330
3473
|
authoritative: true
|
|
3331
3474
|
});
|
|
3475
|
+
emitSession(null);
|
|
3332
3476
|
})().finally(() => {
|
|
3333
|
-
if (signOutRequest === request)
|
|
3477
|
+
if (signOutRequest === request) {
|
|
3478
|
+
signOutRequest = void 0;
|
|
3479
|
+
signalRefreshPending = false;
|
|
3480
|
+
}
|
|
3334
3481
|
});
|
|
3335
3482
|
signOutRequest = request;
|
|
3336
3483
|
return request;
|
|
3337
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
|
+
}
|
|
3338
3537
|
return {
|
|
3339
3538
|
acceptInvitation(input) {
|
|
3340
3539
|
let invitation;
|
|
@@ -3343,7 +3542,7 @@ function createAuthClient(options) {
|
|
|
3343
3542
|
} catch (error) {
|
|
3344
3543
|
return Promise.reject(error);
|
|
3345
3544
|
}
|
|
3346
|
-
if (signOutRequest ||
|
|
3545
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3347
3546
|
const generation = authorityGeneration;
|
|
3348
3547
|
const controller = new AbortController();
|
|
3349
3548
|
clearCredential();
|
|
@@ -3376,7 +3575,7 @@ function createAuthClient(options) {
|
|
|
3376
3575
|
},
|
|
3377
3576
|
getSession,
|
|
3378
3577
|
async listOrganizations() {
|
|
3379
|
-
if (signOutRequest ||
|
|
3578
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) throw new AuthError("state_conflict", 409);
|
|
3380
3579
|
const generation = authorityGeneration;
|
|
3381
3580
|
try {
|
|
3382
3581
|
const value = await requestJson(joinURL(authOrigin, "api/v1/auth/organization/list"), {
|
|
@@ -3392,37 +3591,60 @@ function createAuthClient(options) {
|
|
|
3392
3591
|
}
|
|
3393
3592
|
},
|
|
3394
3593
|
async signIn(input) {
|
|
3395
|
-
|
|
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
|
-
|
|
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);
|
|
3426
3648
|
},
|
|
3427
3649
|
async sendVerificationEmail(input) {
|
|
3428
3650
|
const body = normalizeVerificationEmailInput(input, appOrigin);
|
|
@@ -3442,7 +3664,7 @@ function createAuthClient(options) {
|
|
|
3442
3664
|
} catch (error) {
|
|
3443
3665
|
return Promise.reject(error);
|
|
3444
3666
|
}
|
|
3445
|
-
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));
|
|
3446
3668
|
const workspaceKey = workspace.type === "personal" ? "personal" : `organization:${workspace.organizationId}`;
|
|
3447
3669
|
if (selectedWorkspaceKey !== workspaceKey) {
|
|
3448
3670
|
credential = void 0;
|
|
@@ -3479,21 +3701,20 @@ function createAuthClient(options) {
|
|
|
3479
3701
|
},
|
|
3480
3702
|
onAuthStateChange(listener) {
|
|
3481
3703
|
authStateListeners.add(listener);
|
|
3482
|
-
|
|
3704
|
+
try {
|
|
3705
|
+
listener(authState);
|
|
3706
|
+
} catch {}
|
|
3483
3707
|
startAuthState();
|
|
3484
3708
|
return () => authStateListeners.delete(listener);
|
|
3485
3709
|
},
|
|
3486
3710
|
onSessionChange(listener) {
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
}
|
|
3495
|
-
listener(session);
|
|
3496
|
-
});
|
|
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);
|
|
3497
3718
|
}
|
|
3498
3719
|
};
|
|
3499
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 };
|