use-convex 1.3.0 → 2.0.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 +104 -59
- package/dist/module.d.mts +62 -39
- package/dist/module.mjs +68 -17
- package/dist/runtime/auth/oauth.d.ts +96 -0
- package/dist/runtime/auth/oauth.js +170 -0
- package/dist/runtime/auth/sessionRoutes.d.ts +37 -0
- package/dist/runtime/auth/sessionRoutes.js +41 -0
- package/dist/runtime/composables/useAuth.d.ts +81 -48
- package/dist/runtime/composables/useAuth.js +69 -461
- package/dist/runtime/composables/useAuthToken.d.ts +2 -2
- package/dist/runtime/composables/useAuthToken.js +4 -0
- package/dist/runtime/composables/useConvexAuth.js +1 -1
- package/dist/runtime/composables/useConvexPaginatedQuery.js +6 -1
- package/dist/runtime/composables/useConvexQuery.js +6 -1
- package/dist/runtime/plugin.auth.client.d.ts +8 -3
- package/dist/runtime/plugin.auth.client.js +207 -31
- package/dist/runtime/plugin.server.js +8 -2
- package/dist/runtime/server/auth.d.ts +7 -2
- package/dist/runtime/server/auth.js +14 -3
- package/dist/runtime/server/convexAuth/refresh.d.ts +3 -0
- package/dist/runtime/server/convexAuth/refresh.js +5 -0
- package/dist/runtime/server/convexAuth/session.middleware.d.ts +10 -0
- package/dist/runtime/server/convexAuth/session.middleware.js +37 -0
- package/dist/runtime/server/convexAuth/setup.d.ts +21 -0
- package/dist/runtime/server/convexAuth/setup.js +90 -0
- package/dist/runtime/server/convexAuth/signin.d.ts +3 -0
- package/dist/runtime/server/convexAuth/signin.js +5 -0
- package/dist/runtime/server/convexAuth/signout.d.ts +3 -0
- package/dist/runtime/server/convexAuth/signout.js +5 -0
- package/dist/runtime/server/convexConfig.d.ts +2 -6
- package/dist/runtime/server/fetch.d.ts +2 -1
- package/dist/runtime/server/fetch.js +3 -8
- package/dist/runtime/utils/authClientOptions.d.ts +33 -40
- package/dist/runtime/utils/authClientOptions.js +1 -64
- package/dist/runtime/utils/authCookie.d.ts +8 -14
- package/dist/runtime/utils/authCookie.js +23 -27
- package/dist/runtime/utils/authStorage.d.ts +76 -79
- package/dist/runtime/utils/authStorage.js +60 -141
- package/dist/runtime/utils/context.d.ts +40 -3
- package/dist/types.d.mts +4 -2
- package/package.json +10 -5
- package/dist/runtime/server/api/convex/auth/session.d.ts +0 -36
- package/dist/runtime/server/api/convex/auth/session.js +0 -90
- package/dist/runtime/server/authCookies.d.ts +0 -9
- package/dist/runtime/server/authCookies.js +0 -64
- package/dist/runtime/server/sameOrigin.d.ts +0 -14
- package/dist/runtime/server/sameOrigin.js +0 -29
- package/dist/runtime/utils/authMutex.d.ts +0 -15
- package/dist/runtime/utils/authMutex.js +0 -47
- package/dist/runtime/utils/oauthRedirect.d.ts +0 -5
- package/dist/runtime/utils/oauthRedirect.js +0 -13
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AuthTokenFetcher, ConvexClient, ConvexHttpClient } from 'convex/browser';
|
|
2
|
-
import type {
|
|
2
|
+
import type { FunctionReference } from 'convex/server';
|
|
3
|
+
import type { ComputedRef, InjectionKey, Ref, ShallowRef } from 'vue';
|
|
3
4
|
import type { CreateHttpClientOptions } from './http.js';
|
|
4
5
|
export interface ConvexAuthContext {
|
|
5
6
|
/**
|
|
@@ -19,6 +20,36 @@ export interface ConvexAuthContext {
|
|
|
19
20
|
isAuthenticated: Ref<boolean>;
|
|
20
21
|
isRefreshing: Ref<boolean>;
|
|
21
22
|
}
|
|
23
|
+
/** Snapshot of the Convex Auth client (`AuthState` in `@convex-dev/auth`). */
|
|
24
|
+
export interface ConvexAuthSnapshot {
|
|
25
|
+
isLoading: boolean;
|
|
26
|
+
isAuthenticated: boolean;
|
|
27
|
+
token: string | null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Runs a method's sign-in function. Direct to the deployment in SPA mode,
|
|
31
|
+
* through the Nitro auth proxy in SSR mode (which moves the refresh token
|
|
32
|
+
* into an httpOnly cookie).
|
|
33
|
+
*/
|
|
34
|
+
export interface ConvexAuthSignInApi {
|
|
35
|
+
mutation: (fn: FunctionReference<'mutation'>, args: Record<string, unknown>) => Promise<any>;
|
|
36
|
+
action: (fn: FunctionReference<'action'>, args: Record<string, unknown>) => Promise<any>;
|
|
37
|
+
}
|
|
38
|
+
/** First-party Convex Auth v2 binding, set by the auth client plugin. */
|
|
39
|
+
export interface ConvexAuthBinding {
|
|
40
|
+
mode: 'ssr' | 'spa';
|
|
41
|
+
state: ShallowRef<ConvexAuthSnapshot>;
|
|
42
|
+
signInApi: ConvexAuthSignInApi;
|
|
43
|
+
/** Adopt a session returned by a method's sign-in function. */
|
|
44
|
+
setSession: (session: {
|
|
45
|
+
accessToken: string;
|
|
46
|
+
userId: string;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
}) => Promise<void>;
|
|
49
|
+
signOut: () => Promise<void>;
|
|
50
|
+
/** Values an ambient sign-in (e.g. OAuth) publishes, read reactively. */
|
|
51
|
+
ambientValue: <T>(id: string, key: string) => Readonly<Ref<T | undefined>>;
|
|
52
|
+
}
|
|
22
53
|
export interface ConvexNuxtContext {
|
|
23
54
|
url: string;
|
|
24
55
|
/**
|
|
@@ -26,14 +57,20 @@ export interface ConvexNuxtContext {
|
|
|
26
57
|
*/
|
|
27
58
|
client: ConvexClient | null;
|
|
28
59
|
/**
|
|
29
|
-
* JWT
|
|
30
|
-
*
|
|
60
|
+
* JWT for HttpClient snapshots: the SSR session token (Convex Auth SSR
|
|
61
|
+
* mode or a BYO cookie), then the live Convex Auth access token on the
|
|
62
|
+
* client. Reactive so sign-in/out re-runs HttpClient fetches.
|
|
31
63
|
*/
|
|
32
64
|
ssrToken: ComputedRef<string | undefined>;
|
|
33
65
|
/**
|
|
34
66
|
* Shared auth state for useConvexAuth.
|
|
35
67
|
*/
|
|
36
68
|
auth: ConvexAuthContext;
|
|
69
|
+
/**
|
|
70
|
+
* Convex Auth v2 client binding (`convex.auth.provider: 'convex-auth'`,
|
|
71
|
+
* browser only). `null` on the server and for BYO providers.
|
|
72
|
+
*/
|
|
73
|
+
convexAuth?: ConvexAuthBinding | null;
|
|
37
74
|
/**
|
|
38
75
|
* Create a fresh HttpClient for one-shot fetches (SSR / Nitro / refresh).
|
|
39
76
|
* Prefer a new client per call — HttpClient is stateful.
|
package/dist/types.d.mts
CHANGED
|
@@ -4,7 +4,7 @@ declare module '@nuxt/schema' {
|
|
|
4
4
|
interface PublicRuntimeConfig extends ModulePublicRuntimeConfig {}
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export { type
|
|
7
|
+
export { type ConvexAuthSession, type ConvexSignInResult, type OAuthCompleteResult, type OAuthFlowError, type OAuthProviderRefs, type OAuthSignInOptions, type OAuthStartResult, type UseAuthReturn } from '../dist/runtime/composables/useAuth.js'
|
|
8
8
|
|
|
9
9
|
export { type ConvexQueryArgs, type UseConvexQueryOptions, type UseConvexQueryReturn } from '../dist/runtime/composables/useConvexQuery.js'
|
|
10
10
|
|
|
@@ -30,7 +30,9 @@ export { type ConnectionState } from '../dist/runtime/composables/useConvexConne
|
|
|
30
30
|
|
|
31
31
|
export { type ConvexGate } from '../dist/runtime/composables/useConvexGate.js'
|
|
32
32
|
|
|
33
|
-
export { type ConvexAuthClientOptions, type ConvexAuthStorageMode, type ConvexAuthTokenStorage, type configureConvexAuth } from '../dist/runtime/utils/authClientOptions.js'
|
|
33
|
+
export { type ConvexAmbientSignIn, type ConvexAuthClientOptions, type ConvexAuthStorageMode, type ConvexAuthTokenStorage, type configureConvexAuth } from '../dist/runtime/utils/authClientOptions.js'
|
|
34
|
+
|
|
35
|
+
export { type ConvexAuthServerRuntimeConfig } from '../dist/runtime/utils/authStorage.js'
|
|
34
36
|
|
|
35
37
|
export { default } from './module.mjs'
|
|
36
38
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "use-convex",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "First-class Convex integration for Nuxt",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -44,13 +44,12 @@
|
|
|
44
44
|
"h3": "^1.15.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@auth
|
|
48
|
-
"@convex-dev/auth": "^0.0.95",
|
|
47
|
+
"@convex-dev/auth": "^2.0.0",
|
|
49
48
|
"@nuxt/module-builder": "^1.0.0",
|
|
50
49
|
"@nuxt/schema": "^4.0.0",
|
|
51
50
|
"@nuxt/test-utils": "^3.23.0",
|
|
52
51
|
"@types/node": "^26.5.0",
|
|
53
|
-
"convex": "^1.
|
|
52
|
+
"convex": "^1.48.0",
|
|
54
53
|
"convex-test": "^0.0.56",
|
|
55
54
|
"happy-dom": "^20.14.0",
|
|
56
55
|
"nitropack": "^2.13.0",
|
|
@@ -63,10 +62,16 @@
|
|
|
63
62
|
"vue-tsc": "^3.0.0"
|
|
64
63
|
},
|
|
65
64
|
"peerDependencies": {
|
|
66
|
-
"convex": "^
|
|
65
|
+
"@convex-dev/auth": "^2.0.0",
|
|
66
|
+
"convex": "^1.48.0",
|
|
67
67
|
"nuxt": "^4.0.0",
|
|
68
68
|
"vue": "^3.5.0"
|
|
69
69
|
},
|
|
70
|
+
"peerDependenciesMeta": {
|
|
71
|
+
"@convex-dev/auth": {
|
|
72
|
+
"optional": true
|
|
73
|
+
}
|
|
74
|
+
},
|
|
70
75
|
"packageManager": "pnpm@10.0.0",
|
|
71
76
|
"pnpm": {
|
|
72
77
|
"overrides": {
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persist / read / refresh HttpOnly auth cookies.
|
|
3
|
-
*
|
|
4
|
-
* - GET → `{ hasSession }` only (no JWT in the response body)
|
|
5
|
-
* - POST `{ getToken: true }` → `{ hasSession, token }` for ConvexClient.setAuth
|
|
6
|
-
* - POST `{ refresh: true }` → refresh cookies, return `{ token }`
|
|
7
|
-
* - POST `{ token, refreshToken }` → set cookies
|
|
8
|
-
* - DELETE → clear cookies
|
|
9
|
-
*
|
|
10
|
-
* All methods require same-origin (fail-closed). Returning the JWT only via
|
|
11
|
-
* POST reduces accidental leakage via prefetch/logs; XSS can still obtain a
|
|
12
|
-
* token once ConvexClient needs it in memory — HttpOnly mitigates cookie theft,
|
|
13
|
-
* not XSS session theft.
|
|
14
|
-
*/
|
|
15
|
-
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
hasSession: boolean;
|
|
17
|
-
ok?: undefined;
|
|
18
|
-
token?: undefined;
|
|
19
|
-
} | {
|
|
20
|
-
ok: boolean;
|
|
21
|
-
hasSession?: undefined;
|
|
22
|
-
token?: undefined;
|
|
23
|
-
} | {
|
|
24
|
-
hasSession: boolean;
|
|
25
|
-
token: string | null;
|
|
26
|
-
ok?: undefined;
|
|
27
|
-
} | {
|
|
28
|
-
token: null;
|
|
29
|
-
hasSession?: undefined;
|
|
30
|
-
ok?: undefined;
|
|
31
|
-
} | {
|
|
32
|
-
token: string;
|
|
33
|
-
hasSession?: undefined;
|
|
34
|
-
ok?: undefined;
|
|
35
|
-
}>>;
|
|
36
|
-
export default _default;
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { ConvexHttpClient } from "convex/browser";
|
|
2
|
-
import { makeFunctionReference } from "convex/server";
|
|
3
|
-
import { createError, defineEventHandler, readBody } from "h3";
|
|
4
|
-
import { useRuntimeConfig } from "nitropack/runtime";
|
|
5
|
-
import { readHttpOnlyJwt, readHttpOnlyRefresh, setAuthCookies } from "../../../authCookies.js";
|
|
6
|
-
import { isHttpOnlyAuth } from "../../../../utils/authStorage.js";
|
|
7
|
-
import { assertSameOrigin } from "../../../sameOrigin.js";
|
|
8
|
-
import { MISSING_URL_HINT } from "../../../../utils/errors.js";
|
|
9
|
-
const authSignIn = makeFunctionReference(
|
|
10
|
-
"auth:signIn"
|
|
11
|
-
);
|
|
12
|
-
function convexUrl(event) {
|
|
13
|
-
const config = useRuntimeConfig(event);
|
|
14
|
-
const url = config.public?.convex?.url ?? process.env.NUXT_PUBLIC_CONVEX_URL;
|
|
15
|
-
if (!url) {
|
|
16
|
-
throw createError({
|
|
17
|
-
statusCode: 500,
|
|
18
|
-
message: MISSING_URL_HINT
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
return url;
|
|
22
|
-
}
|
|
23
|
-
function requireHttpOnly(event) {
|
|
24
|
-
const config = useRuntimeConfig(event);
|
|
25
|
-
const auth = config.public?.convex?.auth;
|
|
26
|
-
if (!isHttpOnlyAuth(auth)) {
|
|
27
|
-
throw createError({
|
|
28
|
-
statusCode: 404,
|
|
29
|
-
message: "HttpOnly auth is not enabled"
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
export default defineEventHandler(async (event) => {
|
|
34
|
-
requireHttpOnly(event);
|
|
35
|
-
assertSameOrigin(event);
|
|
36
|
-
if (event.method === "GET") {
|
|
37
|
-
const token = readHttpOnlyJwt(event);
|
|
38
|
-
return {
|
|
39
|
-
hasSession: !!token
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
if (event.method === "DELETE") {
|
|
43
|
-
setAuthCookies(event, { token: null });
|
|
44
|
-
return { ok: true };
|
|
45
|
-
}
|
|
46
|
-
if (event.method === "POST") {
|
|
47
|
-
const body = await readBody(event);
|
|
48
|
-
if (body?.getToken) {
|
|
49
|
-
const token = readHttpOnlyJwt(event);
|
|
50
|
-
return {
|
|
51
|
-
hasSession: !!token,
|
|
52
|
-
token: token ?? null
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
if (body?.refresh) {
|
|
56
|
-
const refreshToken = readHttpOnlyRefresh(event);
|
|
57
|
-
if (!refreshToken) {
|
|
58
|
-
setAuthCookies(event, { token: null });
|
|
59
|
-
return { token: null };
|
|
60
|
-
}
|
|
61
|
-
const http = new ConvexHttpClient(convexUrl(event));
|
|
62
|
-
try {
|
|
63
|
-
const result = await http.action(authSignIn, { refreshToken });
|
|
64
|
-
const tokens = result.tokens ?? null;
|
|
65
|
-
if (!tokens) {
|
|
66
|
-
setAuthCookies(event, { token: null });
|
|
67
|
-
return { token: null };
|
|
68
|
-
}
|
|
69
|
-
setAuthCookies(event, {
|
|
70
|
-
token: tokens.token,
|
|
71
|
-
refreshToken: tokens.refreshToken
|
|
72
|
-
});
|
|
73
|
-
return { token: tokens.token };
|
|
74
|
-
} catch {
|
|
75
|
-
setAuthCookies(event, { token: null });
|
|
76
|
-
return { token: null };
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (!body?.token) {
|
|
80
|
-
setAuthCookies(event, { token: null });
|
|
81
|
-
return { ok: true };
|
|
82
|
-
}
|
|
83
|
-
setAuthCookies(event, {
|
|
84
|
-
token: body.token,
|
|
85
|
-
refreshToken: body.refreshToken ?? null
|
|
86
|
-
});
|
|
87
|
-
return { ok: true };
|
|
88
|
-
}
|
|
89
|
-
throw createError({ statusCode: 405, message: "Method not allowed" });
|
|
90
|
-
});
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { H3Event } from 'h3';
|
|
2
|
-
export interface AuthCookieSet {
|
|
3
|
-
token: string | null;
|
|
4
|
-
refreshToken?: string | null;
|
|
5
|
-
}
|
|
6
|
-
/** Persist or clear HttpOnly auth cookies + readable presence marker. */
|
|
7
|
-
export declare function setAuthCookies(event: H3Event, tokens: AuthCookieSet): void;
|
|
8
|
-
export declare function readHttpOnlyJwt(event: H3Event): string | undefined;
|
|
9
|
-
export declare function readHttpOnlyRefresh(event: H3Event): string | undefined;
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { deleteCookie, getCookie, getRequestHeader, setCookie } from "h3";
|
|
2
|
-
import {
|
|
3
|
-
AUTH_JWT_COOKIE_MAX_AGE,
|
|
4
|
-
isHttpOnlyAuth,
|
|
5
|
-
resolveAuthCookieName,
|
|
6
|
-
resolveAuthPresentCookieName,
|
|
7
|
-
resolveAuthRefreshCookieName
|
|
8
|
-
} from "../utils/authStorage.js";
|
|
9
|
-
import { readConvexConfig } from "./convexConfig.js";
|
|
10
|
-
function readAuthConfig(event) {
|
|
11
|
-
return readConvexConfig(event)?.auth;
|
|
12
|
-
}
|
|
13
|
-
function isLocalHost(event) {
|
|
14
|
-
const host = getRequestHeader(event, "host") ?? "";
|
|
15
|
-
return host.startsWith("localhost") || host.startsWith("127.0.0.1") || host.startsWith("[::1]");
|
|
16
|
-
}
|
|
17
|
-
function cookieOptions(event, httpOnly) {
|
|
18
|
-
const local = isLocalHost(event);
|
|
19
|
-
return {
|
|
20
|
-
httpOnly,
|
|
21
|
-
secure: !local,
|
|
22
|
-
sameSite: "lax",
|
|
23
|
-
path: "/",
|
|
24
|
-
maxAge: AUTH_JWT_COOKIE_MAX_AGE
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
export function setAuthCookies(event, tokens) {
|
|
28
|
-
const auth = readAuthConfig(event);
|
|
29
|
-
if (!isHttpOnlyAuth(auth)) {
|
|
30
|
-
throw new Error("[use-convex] setAuthCookies requires convex.auth.httpOnly: true");
|
|
31
|
-
}
|
|
32
|
-
const jwtName = resolveAuthCookieName(auth);
|
|
33
|
-
const refreshName = resolveAuthRefreshCookieName(auth);
|
|
34
|
-
const presentName = resolveAuthPresentCookieName(auth);
|
|
35
|
-
const httpOpts = cookieOptions(event, true);
|
|
36
|
-
const presentOpts = cookieOptions(event, false);
|
|
37
|
-
if (!tokens.token) {
|
|
38
|
-
deleteCookie(event, jwtName, httpOpts);
|
|
39
|
-
deleteCookie(event, refreshName, httpOpts);
|
|
40
|
-
deleteCookie(event, presentName, presentOpts);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
setCookie(event, jwtName, tokens.token, httpOpts);
|
|
44
|
-
if (tokens.refreshToken) {
|
|
45
|
-
setCookie(event, refreshName, tokens.refreshToken, httpOpts);
|
|
46
|
-
}
|
|
47
|
-
setCookie(event, presentName, "1", presentOpts);
|
|
48
|
-
}
|
|
49
|
-
export function readHttpOnlyJwt(event) {
|
|
50
|
-
const auth = readAuthConfig(event);
|
|
51
|
-
const name = resolveAuthCookieName(auth);
|
|
52
|
-
if (!name) {
|
|
53
|
-
return void 0;
|
|
54
|
-
}
|
|
55
|
-
return getCookie(event, name) || void 0;
|
|
56
|
-
}
|
|
57
|
-
export function readHttpOnlyRefresh(event) {
|
|
58
|
-
const auth = readAuthConfig(event);
|
|
59
|
-
const name = resolveAuthRefreshCookieName(auth);
|
|
60
|
-
if (!name) {
|
|
61
|
-
return void 0;
|
|
62
|
-
}
|
|
63
|
-
return getCookie(event, name) || void 0;
|
|
64
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type H3Event } from 'h3';
|
|
2
|
-
/**
|
|
3
|
-
* Fail-closed same-origin guard for cookie-bearing auth routes.
|
|
4
|
-
*
|
|
5
|
-
* Accepts the request when:
|
|
6
|
-
* - `Sec-Fetch-Site` is `same-origin` or `none` (user-initiated / same origin), or
|
|
7
|
-
* - `Origin` matches the trusted request origin (scheme + host), using
|
|
8
|
-
* `Host` and `getRequestProtocol` (honors `X-Forwarded-Proto` behind proxies).
|
|
9
|
-
*
|
|
10
|
-
* Rejects when `Sec-Fetch-Site` is `cross-site` / `same-site`, or when neither
|
|
11
|
-
* signal can confirm same-origin. Missing both headers is rejected.
|
|
12
|
-
* Scheme-mismatched Origins (e.g. `http://` vs HTTPS request) are rejected.
|
|
13
|
-
*/
|
|
14
|
-
export declare function assertSameOrigin(event: H3Event): void;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { createError, getRequestHeader, getRequestProtocol } from "h3";
|
|
2
|
-
export function assertSameOrigin(event) {
|
|
3
|
-
const secFetchSite = getRequestHeader(event, "sec-fetch-site");
|
|
4
|
-
if (secFetchSite === "same-origin" || secFetchSite === "none") {
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
if (secFetchSite === "cross-site" || secFetchSite === "same-site") {
|
|
8
|
-
throw createError({
|
|
9
|
-
statusCode: 403,
|
|
10
|
-
message: "Forbidden"
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
const origin = getRequestHeader(event, "origin");
|
|
14
|
-
const host = getRequestHeader(event, "host");
|
|
15
|
-
if (origin && host) {
|
|
16
|
-
try {
|
|
17
|
-
const originUrl = new URL(origin);
|
|
18
|
-
const protocol = getRequestProtocol(event, { xForwardedProto: true });
|
|
19
|
-
if (originUrl.protocol === `${protocol}:` && originUrl.host === host) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
} catch {
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
throw createError({
|
|
26
|
-
statusCode: 403,
|
|
27
|
-
message: "Forbidden"
|
|
28
|
-
});
|
|
29
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Single-flight mutex for token refresh (mirrors @convex-dev/auth/react).
|
|
3
|
-
* Prefers `navigator.locks` when available; falls back to an in-memory queue.
|
|
4
|
-
*/
|
|
5
|
-
type MutexState = {
|
|
6
|
-
currentlyRunning: Promise<void> | null;
|
|
7
|
-
waiting: Array<() => Promise<void>>;
|
|
8
|
-
};
|
|
9
|
-
declare global {
|
|
10
|
-
var __convexNuxtAuthMutexes: Record<string, MutexState> | undefined;
|
|
11
|
-
}
|
|
12
|
-
export declare function withRefreshMutex<T>(key: string, callback: () => Promise<T>): Promise<T>;
|
|
13
|
-
/** Test helper — clear in-memory mutex state between tests. */
|
|
14
|
-
export declare function resetAuthMutexesForTests(): void;
|
|
15
|
-
export {};
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export async function withRefreshMutex(key, callback) {
|
|
2
|
-
const lockManager = typeof navigator !== "undefined" ? navigator.locks : void 0;
|
|
3
|
-
if (lockManager !== void 0) {
|
|
4
|
-
return await lockManager.request(key, callback);
|
|
5
|
-
}
|
|
6
|
-
return await manualMutex(key, callback);
|
|
7
|
-
}
|
|
8
|
-
async function manualMutex(key, callback) {
|
|
9
|
-
return await new Promise((resolve, reject) => {
|
|
10
|
-
const wrapped = () => callback().then(resolve).catch(reject).then(() => void 0);
|
|
11
|
-
void enqueueCallbackForMutex(key, wrapped);
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
function getMutexValue(key) {
|
|
15
|
-
if (globalThis.__convexNuxtAuthMutexes === void 0) {
|
|
16
|
-
globalThis.__convexNuxtAuthMutexes = {};
|
|
17
|
-
}
|
|
18
|
-
let mutex = globalThis.__convexNuxtAuthMutexes[key];
|
|
19
|
-
if (mutex === void 0) {
|
|
20
|
-
mutex = { currentlyRunning: null, waiting: [] };
|
|
21
|
-
globalThis.__convexNuxtAuthMutexes[key] = mutex;
|
|
22
|
-
}
|
|
23
|
-
return mutex;
|
|
24
|
-
}
|
|
25
|
-
async function enqueueCallbackForMutex(key, callback) {
|
|
26
|
-
const mutex = getMutexValue(key);
|
|
27
|
-
if (mutex.currentlyRunning === null) {
|
|
28
|
-
globalThis.__convexNuxtAuthMutexes[key] = {
|
|
29
|
-
currentlyRunning: callback().finally(() => {
|
|
30
|
-
const next = getMutexValue(key).waiting.shift();
|
|
31
|
-
getMutexValue(key).currentlyRunning = null;
|
|
32
|
-
if (next !== void 0) {
|
|
33
|
-
void enqueueCallbackForMutex(key, next);
|
|
34
|
-
}
|
|
35
|
-
}),
|
|
36
|
-
waiting: []
|
|
37
|
-
};
|
|
38
|
-
} else {
|
|
39
|
-
globalThis.__convexNuxtAuthMutexes[key] = {
|
|
40
|
-
...mutex,
|
|
41
|
-
waiting: [...mutex.waiting, callback]
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
export function resetAuthMutexesForTests() {
|
|
46
|
-
globalThis.__convexNuxtAuthMutexes = void 0;
|
|
47
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { useConvexError } from "./errors.js";
|
|
2
|
-
export function parseOAuthRedirect(redirect) {
|
|
3
|
-
let url;
|
|
4
|
-
try {
|
|
5
|
-
url = new URL(redirect);
|
|
6
|
-
} catch {
|
|
7
|
-
throw useConvexError("Invalid OAuth redirect URL");
|
|
8
|
-
}
|
|
9
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
10
|
-
throw useConvexError("OAuth redirect must be http(s)");
|
|
11
|
-
}
|
|
12
|
-
return url;
|
|
13
|
-
}
|