@onmax/nuxt-better-auth 0.0.2-alpha.9 → 0.0.3

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.
Files changed (74) hide show
  1. package/README.md +57 -17
  2. package/dist/module.d.mts +28 -1
  3. package/dist/module.json +3 -3
  4. package/dist/module.mjs +1258 -351
  5. package/dist/runtime/app/components/BetterAuthState.d.vue.ts +4 -4
  6. package/dist/runtime/app/components/BetterAuthState.vue +1 -0
  7. package/dist/runtime/app/components/BetterAuthState.vue.d.ts +4 -4
  8. package/dist/runtime/app/composables/runWithSessionRefresh.d.ts +1 -0
  9. package/dist/runtime/app/composables/runWithSessionRefresh.js +12 -0
  10. package/dist/runtime/app/composables/useAction.d.ts +2 -0
  11. package/dist/runtime/app/composables/useAction.js +6 -0
  12. package/dist/runtime/app/composables/useAuthAsyncData.d.ts +6 -0
  13. package/dist/runtime/app/composables/useAuthAsyncData.js +16 -0
  14. package/dist/runtime/app/composables/useAuthClient.d.ts +9 -0
  15. package/dist/runtime/app/composables/useAuthClient.js +34 -0
  16. package/dist/runtime/app/composables/useAuthClientAction.d.ts +3 -0
  17. package/dist/runtime/app/composables/useAuthClientAction.js +15 -0
  18. package/dist/runtime/app/composables/useAuthRequestFetch.d.ts +11 -0
  19. package/dist/runtime/app/composables/useAuthRequestFetch.js +4 -0
  20. package/dist/runtime/app/composables/useSignIn.d.ts +16 -0
  21. package/dist/runtime/app/composables/useSignIn.js +8 -0
  22. package/dist/runtime/app/composables/useSignUp.d.ts +5 -0
  23. package/dist/runtime/app/composables/useSignUp.js +8 -0
  24. package/dist/runtime/app/composables/useUserSession.d.ts +6 -5
  25. package/dist/runtime/app/composables/useUserSession.js +189 -100
  26. package/dist/runtime/app/composables/useUserSessionState.d.ts +3 -0
  27. package/dist/runtime/app/composables/useUserSessionState.js +4 -0
  28. package/dist/runtime/app/internal/auth-action-error.d.ts +3 -0
  29. package/dist/runtime/app/internal/auth-action-error.js +33 -0
  30. package/dist/runtime/app/internal/auth-action-handles.d.ts +21 -0
  31. package/dist/runtime/app/internal/auth-action-handles.js +105 -0
  32. package/dist/runtime/app/internal/redirect-helpers.d.ts +4 -0
  33. package/dist/runtime/app/internal/redirect-helpers.js +37 -0
  34. package/dist/runtime/app/internal/session-fetch.d.ts +12 -0
  35. package/dist/runtime/app/internal/session-fetch.js +56 -0
  36. package/dist/runtime/app/internal/utils.d.ts +1 -0
  37. package/dist/runtime/app/internal/utils.js +3 -0
  38. package/dist/runtime/app/internal/vue-safe-auth-proxy.d.ts +3 -0
  39. package/dist/runtime/app/internal/vue-safe-auth-proxy.js +68 -0
  40. package/dist/runtime/app/internal/wrap-auth-method.d.ts +18 -0
  41. package/dist/runtime/app/internal/wrap-auth-method.js +69 -0
  42. package/dist/runtime/app/middleware/auth.global.js +80 -15
  43. package/dist/runtime/app/pages/__better-auth-devtools.vue +293 -339
  44. package/dist/runtime/composables.d.ts +12 -0
  45. package/dist/runtime/composables.js +10 -0
  46. package/dist/runtime/config.d.ts +69 -15
  47. package/dist/runtime/config.js +9 -2
  48. package/dist/runtime/internal/auth-route-rules.d.ts +1 -0
  49. package/dist/runtime/internal/auth-route-rules.js +24 -0
  50. package/dist/runtime/server/api/_better-auth/_schema.d.ts +1 -5
  51. package/dist/runtime/server/api/_better-auth/_schema.js +2 -1
  52. package/dist/runtime/server/api/_better-auth/accounts.get.d.ts +2 -2
  53. package/dist/runtime/server/api/_better-auth/accounts.get.js +3 -2
  54. package/dist/runtime/server/api/_better-auth/config.get.d.ts +9 -3
  55. package/dist/runtime/server/api/_better-auth/config.get.js +18 -6
  56. package/dist/runtime/server/api/_better-auth/sessions.delete.js +3 -2
  57. package/dist/runtime/server/api/_better-auth/sessions.get.d.ts +5 -3
  58. package/dist/runtime/server/api/_better-auth/sessions.get.js +3 -2
  59. package/dist/runtime/server/api/_better-auth/users.get.d.ts +2 -2
  60. package/dist/runtime/server/api/_better-auth/users.get.js +3 -2
  61. package/dist/runtime/server/api/auth/[...all].js +1 -1
  62. package/dist/runtime/server/middleware/route-access.js +4 -2
  63. package/dist/runtime/server/tsconfig.json +9 -1
  64. package/dist/runtime/server/utils/auth.d.ts +16 -8
  65. package/dist/runtime/server/utils/auth.js +229 -23
  66. package/dist/runtime/server/utils/custom-secondary-storage.d.ts +6 -0
  67. package/dist/runtime/server/utils/custom-secondary-storage.js +8 -0
  68. package/dist/runtime/server/utils/session.d.ts +7 -8
  69. package/dist/runtime/server/utils/session.js +256 -5
  70. package/dist/runtime/server/virtual-modules.d.ts +27 -0
  71. package/dist/runtime/types/augment.d.ts +18 -4
  72. package/dist/runtime/types.d.ts +12 -13
  73. package/dist/types.d.mts +1 -1
  74. package/package.json +53 -47
@@ -1,32 +1,238 @@
1
+ import { betterAuth } from "better-auth";
2
+ import { getRequestHost, getRequestProtocol } from "h3";
3
+ import { useRuntimeConfig } from "nitropack/runtime";
4
+ import { withoutProtocol } from "ufo";
1
5
  import { createDatabase, db } from "#auth/database";
2
6
  import { createSecondaryStorage } from "#auth/secondary-storage";
3
7
  import createServerAuth from "#auth/server";
4
- import { betterAuth } from "better-auth";
5
- import { consola } from "consola";
6
- import { getRequestURL } from "h3";
7
- import { useRuntimeConfig } from "nitropack/runtime";
8
- const logger = consola.withTag("nuxt-better-auth");
9
- function getBaseURL(event, siteUrl) {
10
- if (siteUrl)
11
- return siteUrl;
12
- const origin = getRequestURL(event).origin;
13
- if (process.env.NODE_ENV === "production")
14
- throw new Error("siteUrl must be configured in production. Set NUXT_PUBLIC_SITE_URL or configure in nuxt.config.");
15
- logger.warn("siteUrl not set, auto-detected:", origin);
8
+ import { resolveCustomSecondaryStorageRequirement } from "./custom-secondary-storage.js";
9
+ const _authCache = /* @__PURE__ */ new Map();
10
+ const requestAuthKey = Symbol.for("nuxt-better-auth.requestAuth");
11
+ let _baseURLInferenceLogged = false;
12
+ let _customSecondaryStorageMisconfigWarned = false;
13
+ const fallbackRequestAuthContext = /* @__PURE__ */ new WeakMap();
14
+ function getRequestAuthContext(event) {
15
+ const eventWithContext = event;
16
+ if (eventWithContext.context && typeof eventWithContext.context === "object")
17
+ return eventWithContext.context;
18
+ let context = fallbackRequestAuthContext.get(event);
19
+ if (!context) {
20
+ context = {};
21
+ fallbackRequestAuthContext.set(event, context);
22
+ }
23
+ return context;
24
+ }
25
+ function normalizeLoopbackOrigin(origin) {
26
+ if (!import.meta.dev)
27
+ return origin;
28
+ try {
29
+ const url = new URL(origin);
30
+ if (url.hostname === "127.0.0.1" || url.hostname === "::1" || url.hostname === "[::1]") {
31
+ url.hostname = "localhost";
32
+ return url.origin;
33
+ }
34
+ } catch {
35
+ }
16
36
  return origin;
17
37
  }
18
- export async function serverAuth(event) {
19
- if (event.context._betterAuth)
20
- return event.context._betterAuth;
38
+ function logInferredBaseURL(baseURL, source) {
39
+ if (!import.meta.dev || _baseURLInferenceLogged)
40
+ return;
41
+ _baseURLInferenceLogged = true;
42
+ console.warn(`[nuxt-better-auth] Using inferred baseURL "${baseURL}" from ${source}. Set runtimeConfig.public.siteUrl for deterministic OAuth callbacks.`);
43
+ }
44
+ function validateURL(url) {
45
+ try {
46
+ return normalizeLoopbackOrigin(new URL(url).origin);
47
+ } catch {
48
+ throw new Error(`Invalid siteUrl: "${url}". Must be a valid URL.`);
49
+ }
50
+ }
51
+ function resolveConfiguredSiteUrl(config) {
52
+ if (typeof config.public.siteUrl !== "string" || !config.public.siteUrl)
53
+ return void 0;
54
+ return validateURL(config.public.siteUrl);
55
+ }
56
+ function resolveEventOrigin(event) {
57
+ if (!event)
58
+ return void 0;
59
+ const host = getRequestHost(event, { xForwardedHost: true });
60
+ const protocol = getRequestProtocol(event, { xForwardedProto: true });
61
+ if (!host || !protocol)
62
+ return void 0;
63
+ try {
64
+ return validateURL(`${protocol}://${host}`);
65
+ } catch {
66
+ return void 0;
67
+ }
68
+ }
69
+ function getNitroOrigin() {
70
+ const cert = process.env.NITRO_SSL_CERT;
71
+ const key = process.env.NITRO_SSL_KEY;
72
+ let host = process.env.NITRO_HOST || process.env.HOST;
73
+ let port;
74
+ if (import.meta.dev)
75
+ port = process.env.NITRO_PORT || process.env.PORT || "3000";
76
+ let protocol = cert && key || !import.meta.dev ? "https" : "http";
77
+ try {
78
+ if ((import.meta.dev || import.meta.prerender) && process.env.__NUXT_DEV__) {
79
+ const origin = JSON.parse(process.env.__NUXT_DEV__).proxy.url;
80
+ host = withoutProtocol(origin);
81
+ protocol = origin.includes("https") ? "https" : "http";
82
+ } else if ((import.meta.dev || import.meta.prerender) && process.env.NUXT_VITE_NODE_OPTIONS) {
83
+ const origin = JSON.parse(process.env.NUXT_VITE_NODE_OPTIONS).baseURL.replace("/__nuxt_vite_node__", "");
84
+ host = withoutProtocol(origin);
85
+ protocol = origin.includes("https") ? "https" : "http";
86
+ }
87
+ } catch {
88
+ }
89
+ if (!host)
90
+ return void 0;
91
+ if (host.startsWith("[") && host.includes("]:")) {
92
+ const lastBracketColon = host.lastIndexOf("]:");
93
+ const extractedPort = host.slice(lastBracketColon + 2);
94
+ host = host.slice(0, lastBracketColon + 1);
95
+ if (extractedPort)
96
+ port = extractedPort;
97
+ } else if (host.includes(":") && !host.startsWith("[")) {
98
+ const hostParts = host.split(":");
99
+ port = hostParts.pop();
100
+ host = hostParts.join(":");
101
+ }
102
+ const portSuffix = port ? `:${port}` : "";
103
+ return `${protocol}://${host}${portSuffix}`;
104
+ }
105
+ function resolveEnvironmentOrigin() {
106
+ const nitroOrigin = getNitroOrigin();
107
+ if (nitroOrigin)
108
+ return { origin: validateURL(nitroOrigin), source: "Nitro environment detection" };
109
+ if (process.env.VERCEL_URL)
110
+ return { origin: validateURL(`https://${process.env.VERCEL_URL}`), source: "VERCEL_URL" };
111
+ if (process.env.CF_PAGES_URL)
112
+ return { origin: validateURL(`https://${process.env.CF_PAGES_URL}`), source: "CF_PAGES_URL" };
113
+ if (process.env.URL)
114
+ return { origin: validateURL(process.env.URL.startsWith("http") ? process.env.URL : `https://${process.env.URL}`), source: "URL" };
115
+ return void 0;
116
+ }
117
+ function resolveDevFallback() {
118
+ if (!import.meta.dev)
119
+ return void 0;
120
+ return { origin: "http://localhost:3000", source: "development fallback" };
121
+ }
122
+ function getBaseURL(event) {
123
+ const config = useRuntimeConfig();
124
+ const configuredSiteUrl = resolveConfiguredSiteUrl(config);
125
+ if (configuredSiteUrl)
126
+ return configuredSiteUrl;
127
+ const eventOrigin = resolveEventOrigin(event);
128
+ if (eventOrigin) {
129
+ logInferredBaseURL(eventOrigin, "request origin");
130
+ return eventOrigin;
131
+ }
132
+ const environmentOrigin = resolveEnvironmentOrigin();
133
+ if (environmentOrigin) {
134
+ logInferredBaseURL(environmentOrigin.origin, environmentOrigin.source);
135
+ return environmentOrigin.origin;
136
+ }
137
+ const devFallback = resolveDevFallback();
138
+ if (devFallback) {
139
+ logInferredBaseURL(devFallback.origin, devFallback.source);
140
+ return devFallback.origin;
141
+ }
142
+ throw new Error("siteUrl required. Set NUXT_PUBLIC_SITE_URL.");
143
+ }
144
+ function dedupeOrigins(origins) {
145
+ return [...new Set(origins)];
146
+ }
147
+ function getDevTrustedOrigins() {
148
+ const fallbackOrigin = "http://localhost:3000";
149
+ const nitroOrigin = getNitroOrigin();
150
+ if (!nitroOrigin)
151
+ return [fallbackOrigin];
152
+ try {
153
+ const url = new URL(nitroOrigin);
154
+ const protocol = url.protocol === "https:" ? "https" : "http";
155
+ const port = url.port || "3000";
156
+ const localhostOrigin = `${protocol}://localhost:${port}`;
157
+ return dedupeOrigins([localhostOrigin, url.origin]);
158
+ } catch {
159
+ return [fallbackOrigin];
160
+ }
161
+ }
162
+ function getRequestOrigin(request) {
163
+ if (!request)
164
+ return void 0;
165
+ try {
166
+ return new URL(request.url).origin;
167
+ } catch {
168
+ return void 0;
169
+ }
170
+ }
171
+ function withDevTrustedOrigins(trustedOrigins) {
172
+ if (!import.meta.dev)
173
+ return trustedOrigins;
174
+ const devOrigins = getDevTrustedOrigins();
175
+ const mergeOrigins = (origins, request) => {
176
+ const validOrigins = origins.filter((origin) => typeof origin === "string");
177
+ const requestOrigin = getRequestOrigin(request);
178
+ return dedupeOrigins(requestOrigin ? [...validOrigins, ...devOrigins, requestOrigin] : [...validOrigins, ...devOrigins]);
179
+ };
180
+ if (typeof trustedOrigins === "function") {
181
+ return async (request) => {
182
+ const resolvedOrigins = await trustedOrigins(request);
183
+ return mergeOrigins(resolvedOrigins, request);
184
+ };
185
+ }
186
+ if (Array.isArray(trustedOrigins)) {
187
+ const baseOrigins = mergeOrigins(trustedOrigins);
188
+ return async (request) => {
189
+ return mergeOrigins(baseOrigins, request);
190
+ };
191
+ }
192
+ return async (request) => {
193
+ return mergeOrigins([], request);
194
+ };
195
+ }
196
+ export function serverAuth(event) {
21
197
  const runtimeConfig = useRuntimeConfig();
22
- const database = createDatabase();
23
- const userConfig = createServerAuth({ runtimeConfig, db });
24
- event.context._betterAuth = betterAuth({
198
+ const siteUrl = getBaseURL(event);
199
+ const requestOrigin = resolveEventOrigin(event);
200
+ const hasExplicitSiteUrl = runtimeConfig.public.siteUrl && typeof runtimeConfig.public.siteUrl === "string";
201
+ const cacheKey = hasExplicitSiteUrl ? "__explicit__" : siteUrl;
202
+ const requestContext = event ? getRequestAuthContext(event) : void 0;
203
+ if (requestContext?.[requestAuthKey])
204
+ return requestContext[requestAuthKey];
205
+ const database = createDatabase(event);
206
+ const userConfig = createServerAuth({ runtimeConfig, db, requestOrigin });
207
+ const trustedOrigins = withDevTrustedOrigins(userConfig.trustedOrigins);
208
+ const hubSecondaryStorage = runtimeConfig.auth?.hubSecondaryStorage;
209
+ const customSecondaryStorage = resolveCustomSecondaryStorageRequirement(hubSecondaryStorage, userConfig.secondaryStorage != null, Boolean(import.meta.dev));
210
+ if (customSecondaryStorage?.shouldThrow)
211
+ throw new Error(customSecondaryStorage.message);
212
+ if (customSecondaryStorage?.shouldWarn && !_customSecondaryStorageMisconfigWarned) {
213
+ _customSecondaryStorageMisconfigWarned = true;
214
+ console.warn(customSecondaryStorage.message);
215
+ }
216
+ if (!database) {
217
+ const cached = _authCache.get(cacheKey);
218
+ if (cached) {
219
+ if (requestContext)
220
+ requestContext[requestAuthKey] = cached;
221
+ return cached;
222
+ }
223
+ }
224
+ const authOptions = {
25
225
  ...userConfig,
26
- ...database && { database },
27
- secondaryStorage: createSecondaryStorage(),
226
+ ...database ? { database } : {},
227
+ ...hubSecondaryStorage === true ? { secondaryStorage: createSecondaryStorage() } : {},
28
228
  secret: runtimeConfig.betterAuthSecret,
29
- baseURL: getBaseURL(event, runtimeConfig.public.siteUrl)
30
- });
31
- return event.context._betterAuth;
229
+ baseURL: siteUrl,
230
+ trustedOrigins
231
+ };
232
+ const auth = betterAuth(authOptions);
233
+ if (requestContext)
234
+ requestContext[requestAuthKey] = auth;
235
+ if (!database)
236
+ _authCache.set(cacheKey, auth);
237
+ return auth;
32
238
  }
@@ -0,0 +1,6 @@
1
+ export type HubSecondaryStorageMode = boolean | 'custom' | undefined;
2
+ export declare function resolveCustomSecondaryStorageRequirement(hubSecondaryStorage: HubSecondaryStorageMode, userHasSecondaryStorage: boolean, isDev: boolean): {
3
+ shouldThrow: boolean;
4
+ shouldWarn: boolean;
5
+ message: string;
6
+ } | null;
@@ -0,0 +1,8 @@
1
+ export function resolveCustomSecondaryStorageRequirement(hubSecondaryStorage, userHasSecondaryStorage, isDev) {
2
+ if (hubSecondaryStorage !== "custom")
3
+ return null;
4
+ if (userHasSecondaryStorage)
5
+ return null;
6
+ const message = '[nuxt-better-auth] hubSecondaryStorage: "custom" requires secondaryStorage in defineServerAuth().';
7
+ return { shouldThrow: !isDev, shouldWarn: isDev, message };
8
+ }
@@ -1,9 +1,8 @@
1
1
  import type { H3Event } from 'h3';
2
- import type { AuthSession, AuthUser, RequireSessionOptions } from '../../types.js';
3
- interface FullSession {
4
- user: AuthUser;
5
- session: AuthSession;
6
- }
7
- export declare function getUserSession(event: H3Event): Promise<FullSession | null>;
8
- export declare function requireUserSession(event: H3Event, options?: RequireSessionOptions): Promise<FullSession>;
9
- export {};
2
+ import type { AppSession, AuthSession, RequireSessionOptions } from '#nuxt-better-auth';
3
+ export declare function getRequestSession(event: H3Event): Promise<AppSession | null>;
4
+ export declare function getUserSession(event: H3Event): Promise<AppSession | null>;
5
+ export declare function refreshSessionCookieCache(event: H3Event): Promise<AppSession | null>;
6
+ export declare function setSessionCookie(event: H3Event, token: string): Promise<void>;
7
+ export declare function createSession(event: H3Event, userId: string): Promise<AuthSession>;
8
+ export declare function requireUserSession(event: H3Event, options?: RequireSessionOptions): Promise<AppSession>;
@@ -1,13 +1,264 @@
1
- import { createError } from "h3";
1
+ import { createError, splitCookiesString } from "h3";
2
2
  import { matchesUser } from "../../utils/match-user.js";
3
3
  import { serverAuth } from "./auth.js";
4
+ const requestSessionLoadKey = Symbol.for("nuxt-better-auth.requestSessionLoad");
5
+ const signingAlgorithm = { name: "HMAC", hash: "SHA-256" };
6
+ const cookiePairSeparatorRE = /;\s*/;
7
+ const fallbackRequestSessionContext = /* @__PURE__ */ new WeakMap();
8
+ function getRequestSessionContext(event) {
9
+ const eventWithContext = event;
10
+ if (eventWithContext.context && typeof eventWithContext.context === "object")
11
+ return eventWithContext.context;
12
+ let context = fallbackRequestSessionContext.get(event);
13
+ if (!context) {
14
+ context = {};
15
+ fallbackRequestSessionContext.set(event, context);
16
+ }
17
+ return context;
18
+ }
19
+ function getRequestHeaders(event) {
20
+ return getRequestSessionContext(event).requestHeaders ?? event.headers;
21
+ }
22
+ function loadSession(event) {
23
+ const auth = serverAuth(event);
24
+ return auth.api.getSession({ headers: getRequestHeaders(event) });
25
+ }
26
+ function loadFreshSession(event) {
27
+ const auth = serverAuth(event);
28
+ return auth.api.getSession({
29
+ headers: getRequestHeaders(event),
30
+ query: { disableCookieCache: true },
31
+ returnHeaders: true
32
+ });
33
+ }
34
+ function getServerAuthContext(event) {
35
+ const auth = serverAuth(event);
36
+ return auth.$context;
37
+ }
38
+ function getCookieName(name, prefix) {
39
+ if (prefix === "secure")
40
+ return name.startsWith("__Secure-") ? name : `__Secure-${name}`;
41
+ if (prefix === "host")
42
+ return name.startsWith("__Host-") ? name : `__Host-${name}`;
43
+ if (prefix)
44
+ return void 0;
45
+ return name;
46
+ }
47
+ function serializeCookieHeader(name, value, attributes = {}, valueIsEncoded = false) {
48
+ const cookieName = getCookieName(name, attributes.prefix);
49
+ if (!cookieName)
50
+ throw new Error(`Unsupported cookie prefix: ${attributes.prefix}`);
51
+ const cookieValue = valueIsEncoded ? value : encodeURIComponent(value);
52
+ const cookie = [`${cookieName}=${cookieValue}`];
53
+ const options = { ...attributes };
54
+ if (cookieName.startsWith("__Secure-") && !options.secure)
55
+ options.secure = true;
56
+ if (cookieName.startsWith("__Host-")) {
57
+ options.secure = true;
58
+ options.path = "/";
59
+ delete options.domain;
60
+ }
61
+ if (typeof options.maxAge === "number" && options.maxAge >= 0)
62
+ cookie.push(`Max-Age=${Math.floor(options.maxAge)}`);
63
+ if (options.domain && options.prefix !== "host")
64
+ cookie.push(`Domain=${options.domain}`);
65
+ if (options.path)
66
+ cookie.push(`Path=${options.path}`);
67
+ if (options.expires)
68
+ cookie.push(`Expires=${options.expires.toUTCString()}`);
69
+ if (options.httpOnly)
70
+ cookie.push("HttpOnly");
71
+ if (options.partitioned)
72
+ options.secure = true;
73
+ if (options.secure)
74
+ cookie.push("Secure");
75
+ if (options.sameSite) {
76
+ const normalizedSameSite = options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1);
77
+ cookie.push(`SameSite=${normalizedSameSite}`);
78
+ }
79
+ if (options.partitioned)
80
+ cookie.push("Partitioned");
81
+ return cookie.join("; ");
82
+ }
83
+ function serializeCookie(name, value, attributes = {}) {
84
+ return serializeCookieHeader(name, value, attributes);
85
+ }
86
+ async function signCookieValue(value, secret) {
87
+ const key = await crypto.subtle.importKey(
88
+ "raw",
89
+ new TextEncoder().encode(secret),
90
+ signingAlgorithm,
91
+ false,
92
+ ["sign", "verify"]
93
+ );
94
+ const signature = await crypto.subtle.sign(
95
+ signingAlgorithm.name,
96
+ key,
97
+ new TextEncoder().encode(value)
98
+ );
99
+ return encodeURIComponent(`${value}.${btoa(String.fromCharCode(...new Uint8Array(signature)))}`);
100
+ }
101
+ async function serializeSignedCookie(name, value, secret, attributes = {}) {
102
+ return serializeCookieHeader(name, await signCookieValue(value, secret), attributes, true);
103
+ }
104
+ function appendCookieHeader(event, header) {
105
+ const nodeResponse = event.node?.res;
106
+ if (nodeResponse?.setHeader) {
107
+ const current = nodeResponse.getHeader?.("set-cookie");
108
+ if (Array.isArray(current))
109
+ nodeResponse.setHeader("set-cookie", [...current, header]);
110
+ else if (typeof current === "string")
111
+ nodeResponse.setHeader("set-cookie", [current, header]);
112
+ else
113
+ nodeResponse.setHeader("set-cookie", [header]);
114
+ return;
115
+ }
116
+ const responseHeaders = event.response?.headers;
117
+ responseHeaders?.append("set-cookie", header);
118
+ }
119
+ function getSetCookieHeaders(headers) {
120
+ const getSetCookie = headers.getSetCookie;
121
+ const cookies = getSetCookie?.call(headers);
122
+ if (cookies?.length)
123
+ return cookies.flatMap((cookie) => splitCookiesString(cookie));
124
+ const header = headers.get("set-cookie");
125
+ return header ? splitCookiesString(header) : [];
126
+ }
127
+ function appendSetCookieHeaders(event, headers) {
128
+ for (const header of getSetCookieHeaders(headers))
129
+ appendCookieHeader(event, header);
130
+ }
131
+ function parseRequestCookies(cookieHeader) {
132
+ const cookies = /* @__PURE__ */ new Map();
133
+ if (!cookieHeader)
134
+ return cookies;
135
+ for (const pair of cookieHeader.split(cookiePairSeparatorRE)) {
136
+ if (!pair)
137
+ continue;
138
+ const separatorIndex = pair.indexOf("=");
139
+ if (separatorIndex < 0)
140
+ continue;
141
+ cookies.set(pair.slice(0, separatorIndex), pair.slice(separatorIndex + 1));
142
+ }
143
+ return cookies;
144
+ }
145
+ function serializeRequestCookies(cookies) {
146
+ if (!cookies.size)
147
+ return null;
148
+ return Array.from(cookies.entries()).map(([name, value]) => `${name}=${value}`).join("; ");
149
+ }
150
+ function extractResponseCookieValue(header) {
151
+ const separatorIndex = header.indexOf(";");
152
+ const cookiePair = separatorIndex >= 0 ? header.slice(0, separatorIndex) : header;
153
+ return cookiePair.slice(cookiePair.indexOf("=") + 1);
154
+ }
155
+ function getChunkedCookieNames(event, cookieName) {
156
+ const cookieNames = /* @__PURE__ */ new Set([cookieName]);
157
+ for (const name of parseRequestCookies(event.headers.get("cookie")).keys()) {
158
+ if (name.startsWith(`${cookieName}.`))
159
+ cookieNames.add(name);
160
+ }
161
+ return Array.from(cookieNames);
162
+ }
163
+ function expireCookie(event, cookieName, attributes) {
164
+ appendCookieHeader(event, serializeCookie(cookieName, "", {
165
+ ...attributes,
166
+ expires: /* @__PURE__ */ new Date(0),
167
+ maxAge: 0
168
+ }));
169
+ }
170
+ function expireCookies(event, cookie) {
171
+ for (const cookieName of getChunkedCookieNames(event, cookie.name))
172
+ expireCookie(event, cookieName, cookie.attributes);
173
+ }
174
+ function updateRequestHeaders(event, sessionCookie, clearedCookieNames) {
175
+ const requestContext = getRequestSessionContext(event);
176
+ const requestHeaders = new Headers(event.headers);
177
+ const cookies = parseRequestCookies(event.headers.get("cookie"));
178
+ for (const name of clearedCookieNames)
179
+ cookies.delete(name);
180
+ const sessionTokenName = sessionCookie.slice(0, sessionCookie.indexOf("="));
181
+ cookies.set(sessionTokenName, extractResponseCookieValue(sessionCookie));
182
+ const nextCookieHeader = serializeRequestCookies(cookies);
183
+ if (nextCookieHeader)
184
+ requestHeaders.set("cookie", nextCookieHeader);
185
+ else
186
+ requestHeaders.delete("cookie");
187
+ requestContext.requestHeaders = requestHeaders;
188
+ }
189
+ export async function getRequestSession(event) {
190
+ const context = getRequestSessionContext(event);
191
+ if (context.requestSession !== void 0)
192
+ return context.requestSession;
193
+ const inFlight = context[requestSessionLoadKey];
194
+ if (inFlight)
195
+ return inFlight;
196
+ const load = loadSession(event);
197
+ context[requestSessionLoadKey] = load;
198
+ try {
199
+ const session = await load;
200
+ context.requestSession = session;
201
+ return session;
202
+ } finally {
203
+ delete context[requestSessionLoadKey];
204
+ }
205
+ }
4
206
  export async function getUserSession(event) {
5
- const auth = await serverAuth(event);
6
- const session = await auth.api.getSession({ headers: event.headers });
7
- return session;
207
+ const context = getRequestSessionContext(event);
208
+ if (context.requestSession !== void 0)
209
+ return context.requestSession;
210
+ const inFlight = context[requestSessionLoadKey];
211
+ if (inFlight)
212
+ return inFlight;
213
+ return loadSession(event);
214
+ }
215
+ export async function refreshSessionCookieCache(event) {
216
+ const context = getRequestSessionContext(event);
217
+ const inFlight = context[requestSessionLoadKey];
218
+ if (inFlight)
219
+ await inFlight.catch(() => void 0);
220
+ delete context.requestSession;
221
+ const load = loadFreshSession(event).then(({ headers, response }) => {
222
+ appendSetCookieHeaders(event, headers);
223
+ context.requestSession = response;
224
+ return response;
225
+ });
226
+ context[requestSessionLoadKey] = load;
227
+ try {
228
+ return await load;
229
+ } finally {
230
+ if (context[requestSessionLoadKey] === load)
231
+ delete context[requestSessionLoadKey];
232
+ }
233
+ }
234
+ export async function setSessionCookie(event, token) {
235
+ const context = await getServerAuthContext(event);
236
+ const sessionCookie = await serializeSignedCookie(
237
+ context.authCookies.sessionToken.name,
238
+ token,
239
+ context.secret,
240
+ {
241
+ ...context.authCookies.sessionToken.attributes,
242
+ maxAge: context.sessionConfig.expiresIn
243
+ }
244
+ );
245
+ appendCookieHeader(event, sessionCookie);
246
+ expireCookies(event, context.authCookies.sessionData);
247
+ expireCookies(event, context.authCookies.dontRememberToken);
248
+ const requestContext = getRequestSessionContext(event);
249
+ delete requestContext.requestSession;
250
+ delete requestContext[requestSessionLoadKey];
251
+ updateRequestHeaders(event, sessionCookie, [
252
+ ...getChunkedCookieNames(event, context.authCookies.sessionData.name),
253
+ ...getChunkedCookieNames(event, context.authCookies.dontRememberToken.name)
254
+ ]);
255
+ }
256
+ export async function createSession(event, userId) {
257
+ const context = await getServerAuthContext(event);
258
+ return context.internalAdapter.createSession?.(userId, false);
8
259
  }
9
260
  export async function requireUserSession(event, options) {
10
- const session = await getUserSession(event);
261
+ const session = await getRequestSession(event);
11
262
  if (!session)
12
263
  throw createError({ statusCode: 401, statusMessage: "Authentication required" });
13
264
  if (options?.user) {
@@ -0,0 +1,27 @@
1
+ declare module '#auth/database' {
2
+ export const db: any
3
+ export function createDatabase(...args: any[]): any
4
+ }
5
+
6
+ declare module '#imports' {
7
+ export function getRouteRules(event: any): any
8
+ export function useRuntimeConfig(): any
9
+ }
10
+
11
+ declare module '#auth/secondary-storage' {
12
+ export function createSecondaryStorage(...args: any[]): any
13
+ }
14
+
15
+ declare module '#auth/schema' {
16
+ export const schema: any
17
+ }
18
+
19
+ declare module '#auth/server' {
20
+ const createServerAuth: any
21
+ export default createServerAuth
22
+ }
23
+
24
+ declare module '@nuxthub/db' {
25
+ export const db: any
26
+ export const schema: any
27
+ }
@@ -21,15 +21,15 @@ export interface AuthSession {
21
21
  export interface ServerAuthContext {
22
22
  runtimeConfig: Record<string, unknown>;
23
23
  db: unknown;
24
+ requestOrigin?: string;
25
+ }
26
+ export interface AuthSocialProviderRegistry {
24
27
  }
25
28
  export interface UserSessionComposable {
26
- client: unknown;
27
29
  user: Ref<AuthUser | null>;
28
30
  session: Ref<AuthSession | null>;
29
31
  loggedIn: ComputedRef<boolean>;
30
32
  ready: ComputedRef<boolean>;
31
- signIn: unknown;
32
- signUp: unknown;
33
33
  fetchSession: (options?: {
34
34
  headers?: HeadersInit;
35
35
  force?: boolean;
@@ -38,5 +38,19 @@ export interface UserSessionComposable {
38
38
  signOut: (options?: {
39
39
  onSuccess?: () => void | Promise<void>;
40
40
  }) => Promise<void>;
41
- updateUser: (updates: Partial<AuthUser>) => void;
41
+ updateUser: (updates: Partial<AuthUser>) => Promise<void>;
42
+ }
43
+ export type UserMatch<T> = {
44
+ [K in keyof T]?: T[K] | T[K][];
45
+ };
46
+ export interface AppSession {
47
+ user: AuthUser;
48
+ session: AuthSession;
49
+ }
50
+ export interface RequireSessionOptions {
51
+ user?: UserMatch<AuthUser>;
52
+ rule?: (ctx: {
53
+ user: AuthUser;
54
+ session: AuthSession;
55
+ }) => boolean | Promise<boolean>;
42
56
  }
@@ -1,11 +1,17 @@
1
1
  import type { NitroRouteRules } from 'nitropack/types';
2
- import type { AuthSession, AuthUser } from './types/augment.js';
3
- export type { AuthSession, AuthUser, ServerAuthContext, UserSessionComposable } from './types/augment.js';
4
- export type { Auth, InferSession, InferUser } from 'better-auth';
2
+ import type { AuthSocialProviderRegistry, AuthUser, UserMatch } from '#nuxt-better-auth';
3
+ export type { AppSession, AuthSession, AuthSocialProviderRegistry, AuthUser, RequireSessionOptions, ServerAuthContext, UserMatch, UserSessionComposable } from './types/augment.js';
4
+ export type AuthSocialProviderId = AuthSocialProviderRegistry extends {
5
+ ids: infer T;
6
+ } ? Extract<T, string> : never;
7
+ export type { Auth, InferPluginTypes, InferSessionFromClient as InferSession, InferUserFromClient as InferUser } from 'better-auth';
8
+ export interface AuthActionError {
9
+ message: string;
10
+ code?: string;
11
+ status?: number;
12
+ raw: unknown;
13
+ }
5
14
  export type AuthMode = 'guest' | 'user';
6
- export type UserMatch<T> = {
7
- [K in keyof T]?: T[K] | T[K][];
8
- };
9
15
  export type AuthMeta = false | AuthMode | {
10
16
  only?: AuthMode;
11
17
  redirectTo?: string;
@@ -14,10 +20,3 @@ export type AuthMeta = false | AuthMode | {
14
20
  export type AuthRouteRules = NitroRouteRules & {
15
21
  auth?: AuthMeta;
16
22
  };
17
- export interface RequireSessionOptions {
18
- user?: UserMatch<AuthUser>;
19
- rule?: (ctx: {
20
- user: AuthUser;
21
- session: AuthSession;
22
- }) => boolean | Promise<boolean>;
23
- }
package/dist/types.d.mts CHANGED
@@ -6,6 +6,6 @@ export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<
6
6
 
7
7
  export { type BetterAuthModuleOptions, type defineClientAuth, type defineServerAuth } from '../dist/runtime/config.js'
8
8
 
9
- export { type Auth, type AuthMeta, type AuthMode, type AuthRouteRules, type AuthSession, type AuthUser, type InferSession, type InferUser, type RequireSessionOptions, type ServerAuthContext, type UserMatch } from '../dist/runtime/types.js'
9
+ export { type AppSession, type Auth, type AuthActionError, type AuthMeta, type AuthMode, type AuthRouteRules, type AuthSession, type AuthSocialProviderId, type AuthUser, type InferSession, type InferUser, type RequireSessionOptions, type ServerAuthContext, type UserMatch } from '../dist/runtime/types.js'
10
10
 
11
11
  export { default } from './module.mjs'