@nuxtjs/better-auth 0.3.1 → 0.3.2

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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +12 -0
  3. package/dist/module.d.mts +2 -2
  4. package/dist/module.json +1 -1
  5. package/dist/module.mjs +297 -93
  6. package/dist/runtime/app/composables/runWithSessionRefresh.js +2 -1
  7. package/dist/runtime/app/composables/useAuthRequestFetch.d.ts +1 -1
  8. package/dist/runtime/app/composables/useAuthRequestFetch.js +22 -2
  9. package/dist/runtime/app/composables/useSignIn.d.ts +1 -4
  10. package/dist/runtime/app/composables/useUserSession.js +33 -8
  11. package/dist/runtime/app/internal/redirect-helpers.js +22 -1
  12. package/dist/runtime/app/internal/session-fetch.d.ts +1 -0
  13. package/dist/runtime/app/internal/session-fetch.js +22 -8
  14. package/dist/runtime/app/internal/wrap-auth-method.d.ts +3 -2
  15. package/dist/runtime/app/internal/wrap-auth-method.js +9 -7
  16. package/dist/runtime/app/plugins/session.client.js +2 -1
  17. package/dist/runtime/app/plugins/session.server.js +8 -3
  18. package/dist/runtime/composables.d.ts +2 -0
  19. package/dist/runtime/internal/auth-route-rules.d.ts +3 -0
  20. package/dist/runtime/internal/auth-route-rules.js +10 -0
  21. package/dist/runtime/server/internal/cookie-headers.d.ts +3 -0
  22. package/dist/runtime/server/internal/cookie-headers.js +30 -0
  23. package/dist/runtime/server/internal/nitro2.d.ts +4 -2
  24. package/dist/runtime/server/internal/nitro2.js +2 -2
  25. package/dist/runtime/server/internal/nitro3.d.ts +2 -1
  26. package/dist/runtime/server/internal/nitro3.js +5 -32
  27. package/dist/runtime/server/middleware/route-access.js +7 -4
  28. package/dist/runtime/server/utils/auth.js +11 -2
  29. package/dist/runtime/server/utils/session.js +34 -32
  30. package/dist/runtime/test-utils/e2e.d.ts +18 -0
  31. package/dist/runtime/test-utils/e2e.js +48 -0
  32. package/dist/runtime/test-utils/module.d.ts +6 -0
  33. package/dist/runtime/test-utils/module.js +18 -0
  34. package/dist/runtime/test-utils/runtime.d.ts +25 -0
  35. package/dist/runtime/test-utils/runtime.js +56 -0
  36. package/dist/runtime/test-utils/server/handler.d.ts +2 -0
  37. package/dist/runtime/test-utils/server/handler.js +34 -0
  38. package/dist/runtime/test-utils/server/plugin.d.ts +23 -0
  39. package/dist/runtime/test-utils/server/plugin.js +2 -0
  40. package/dist/runtime/types.d.ts +1 -1
  41. package/dist/types.d.mts +2 -8
  42. package/package.json +29 -4
@@ -1,7 +1,9 @@
1
1
  import { matchesUser } from "../../utils/match-user.js";
2
- import { createAuthError, splitCookiesString } from "../internal/nitro-compat.js";
2
+ import { createAuthError } from "../internal/nitro-compat.js";
3
+ import { appendCookieHeader, appendSetCookieHeaders } from "../internal/cookie-headers.js";
3
4
  import { serverAuth } from "./auth.js";
4
5
  const requestSessionLoadKey = Symbol.for("nuxt-better-auth.requestSessionLoad");
6
+ const requestSessionMutationKey = Symbol.for("nuxt-better-auth.requestSessionMutation");
5
7
  const signingAlgorithm = { name: "HMAC", hash: "SHA-256" };
6
8
  const cookiePairSeparatorRE = /;\s*/;
7
9
  const fallbackRequestSessionContext = /* @__PURE__ */ new WeakMap();
@@ -23,9 +25,15 @@ function getIncomingRequestHeaders(event) {
23
25
  function getRequestHeaders(event) {
24
26
  return getRequestSessionContext(event).requestHeaders ?? getIncomingRequestHeaders(event);
25
27
  }
26
- function loadSession(event) {
28
+ async function loadSession(event) {
27
29
  const auth = serverAuth(event);
28
- return auth.api.getSession({ headers: getRequestHeaders(event) });
30
+ const result = await auth.api.getSession({
31
+ headers: getRequestHeaders(event),
32
+ returnHeaders: true
33
+ });
34
+ if (result && typeof result === "object" && "headers" in result && result.headers instanceof Headers && "response" in result)
35
+ return result;
36
+ return { headers: new Headers(), response: result };
29
37
  }
30
38
  function loadFreshSession(event) {
31
39
  const auth = serverAuth(event);
@@ -105,33 +113,11 @@ async function signCookieValue(value, secret) {
105
113
  async function serializeSignedCookie(name, value, secret, attributes = {}) {
106
114
  return serializeCookieHeader(name, await signCookieValue(value, secret), attributes, true);
107
115
  }
108
- function appendCookieHeader(event, header) {
109
- const nodeResponse = event.node?.res;
110
- if (nodeResponse?.setHeader) {
111
- const current = nodeResponse.getHeader?.("set-cookie");
112
- if (Array.isArray(current))
113
- nodeResponse.setHeader("set-cookie", [...current, header]);
114
- else if (typeof current === "string")
115
- nodeResponse.setHeader("set-cookie", [current, header]);
116
- else
117
- nodeResponse.setHeader("set-cookie", [header]);
118
- return;
119
- }
120
- const eventWithResponse = event;
121
- const responseHeaders = eventWithResponse.res?.headers ?? eventWithResponse.response?.headers;
122
- responseHeaders?.append("set-cookie", header);
123
- }
124
- function getSetCookieHeaders(headers) {
125
- const getSetCookie = headers.getSetCookie;
126
- const cookies = getSetCookie?.call(headers);
127
- if (cookies?.length)
128
- return cookies.flatMap((cookie) => splitCookiesString(cookie));
129
- const header = headers.get("set-cookie");
130
- return header ? splitCookiesString(header) : [];
116
+ function getRequestSessionMutation(context) {
117
+ return context[requestSessionMutationKey] ?? 0;
131
118
  }
132
- function appendSetCookieHeaders(event, headers) {
133
- for (const header of getSetCookieHeaders(headers))
134
- appendCookieHeader(event, header);
119
+ function markRequestSessionMutation(context) {
120
+ context[requestSessionMutationKey] = getRequestSessionMutation(context) + 1;
135
121
  }
136
122
  function parseRequestCookies(cookieHeader) {
137
123
  const cookies = /* @__PURE__ */ new Map();
@@ -199,7 +185,11 @@ export async function getRequestSession(event) {
199
185
  return inFlight;
200
186
  if (context.requestSession !== void 0)
201
187
  return context.requestSession;
202
- const load = loadSession(event);
188
+ const load = loadSession(event).then(({ headers, response }) => {
189
+ if (context[requestSessionLoadKey] === load)
190
+ appendSetCookieHeaders(event, headers);
191
+ return response;
192
+ });
203
193
  context[requestSessionLoadKey] = load;
204
194
  try {
205
195
  const session = await load;
@@ -218,10 +208,15 @@ export async function getUserSession(event) {
218
208
  return inFlight;
219
209
  if (context.requestSession !== void 0)
220
210
  return context.requestSession;
221
- return loadSession(event);
211
+ const mutation = getRequestSessionMutation(context);
212
+ const { headers, response } = await loadSession(event);
213
+ if (getRequestSessionMutation(context) === mutation)
214
+ appendSetCookieHeaders(event, headers);
215
+ return response;
222
216
  }
223
217
  export function setRequestSession(event, session) {
224
218
  const context = getRequestSessionContext(event);
219
+ markRequestSessionMutation(context);
225
220
  context.requestSession = session;
226
221
  delete context[requestSessionLoadKey];
227
222
  }
@@ -239,6 +234,7 @@ export async function refreshSessionCookieCache(event) {
239
234
  context.requestSession = response;
240
235
  return response;
241
236
  });
237
+ markRequestSessionMutation(context);
242
238
  context[requestSessionLoadKey] = load;
243
239
  try {
244
240
  return await load;
@@ -262,6 +258,7 @@ export async function setSessionCookie(event, token) {
262
258
  expireCookies(event, context.authCookies.sessionData);
263
259
  expireCookies(event, context.authCookies.dontRememberToken);
264
260
  const requestContext = getRequestSessionContext(event);
261
+ markRequestSessionMutation(requestContext);
265
262
  delete requestContext.requestSession;
266
263
  delete requestContext[requestSessionLoadKey];
267
264
  updateRequestHeaders(event, sessionCookie, [
@@ -271,7 +268,12 @@ export async function setSessionCookie(event, token) {
271
268
  }
272
269
  export async function createSession(event, userId) {
273
270
  const context = await getServerAuthContext(event);
274
- return context.internalAdapter.createSession?.(userId, false);
271
+ if (typeof context.internalAdapter.createSession !== "function") {
272
+ throw new TypeError(
273
+ "[@nuxtjs/better-auth] Cannot create a session: the installed Better Auth version does not expose internalAdapter.createSession()."
274
+ );
275
+ }
276
+ return context.internalAdapter.createSession(userId, false);
275
277
  }
276
278
  export async function requireUserSession(event, options) {
277
279
  const session = await getRequestSession(event);
@@ -0,0 +1,18 @@
1
+ import type { TestOptions } from '@nuxt/test-utils/e2e';
2
+ import type { AuthSession, AuthUser } from '#nuxt-better-auth';
3
+ import type { LoginResult, TestHelpers } from 'better-auth/plugins';
4
+ export type TestLoginOptions = Parameters<TestHelpers['login']>[0];
5
+ export type TestLoginResult = Omit<LoginResult, 'user' | 'session'> & {
6
+ user: AuthUser;
7
+ session: AuthSession;
8
+ };
9
+ /** Create isolated auth fixtures in the Nuxt server started by @nuxt/test-utils. */
10
+ export declare function createAuthTestContext(options?: Partial<TestOptions>): Promise<{
11
+ setupOptions: Partial<TestOptions>;
12
+ /** Create a user with Better Auth's factory and track it for cleanup. */
13
+ createUser: (overrides?: Partial<AuthUser> & Record<string, unknown>) => Promise<AuthUser>;
14
+ /** Create a real session for a user created by this context. */
15
+ login(options: TestLoginOptions): Promise<TestLoginResult>;
16
+ /** Delete users created by this context, including their sessions. */
17
+ clear(): Promise<void>;
18
+ }>;
@@ -0,0 +1,48 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { fileURLToPath } from "node:url";
3
+ import { url } from "@nuxt/test-utils/e2e";
4
+ import { parseJSON } from "better-auth/client";
5
+ import { getRandomPort } from "get-port-please";
6
+ import { defu } from "defu";
7
+ export async function createAuthTestContext(options = {}) {
8
+ if (options.host || options.dev || options.build === false || options.server === false)
9
+ throw new Error("[nuxt-better-auth] Auth E2E helpers require a local test build. Use setup() with build and server enabled, without dev or host.");
10
+ const port = options.port || await getRandomPort("127.0.0.1");
11
+ const siteUrl = `http://127.0.0.1:${port}`;
12
+ const token = randomUUID();
13
+ const endpoint = "/api/auth/__test__";
14
+ const setupOptions = defu({
15
+ port,
16
+ dev: false,
17
+ env: { NUXT_PUBLIC_SITE_URL: siteUrl },
18
+ nuxtConfig: {
19
+ test: true,
20
+ runtimeConfig: { public: { siteUrl } },
21
+ modules: [[fileURLToPath(new URL("./module", import.meta.url)), { token }]]
22
+ }
23
+ }, options);
24
+ async function call(action, data = {}) {
25
+ const response = await fetch(url(endpoint), {
26
+ method: "POST",
27
+ headers: { "content-type": "application/json", "x-nuxt-auth-test": token },
28
+ body: JSON.stringify({ action, data })
29
+ });
30
+ if (!response.ok)
31
+ throw new Error(`[nuxt-better-auth] Test helper ${action} failed (${response.status}): ${await response.text()}`);
32
+ return parseJSON(await response.text());
33
+ }
34
+ return {
35
+ setupOptions,
36
+ /** Create a user with Better Auth's factory and track it for cleanup. */
37
+ createUser: (overrides = {}) => call("createUser", overrides),
38
+ /** Create a real session for a user created by this context. */
39
+ async login(options2) {
40
+ const result = await call("login", options2);
41
+ return { ...result, headers: new Headers(result.headers) };
42
+ },
43
+ /** Delete users created by this context, including their sessions. */
44
+ async clear() {
45
+ await call("clear");
46
+ }
47
+ };
48
+ }
@@ -0,0 +1,6 @@
1
+ declare const _default: import("@nuxt/schema").NuxtModule<{
2
+ token: string;
3
+ }, {
4
+ token: string;
5
+ }, false>;
6
+ export default _default;
@@ -0,0 +1,18 @@
1
+ import { addServerHandler, createResolver, defineNuxtModule } from "@nuxt/kit";
2
+ export default defineNuxtModule({
3
+ meta: { name: "@nuxtjs/better-auth/test-utils" },
4
+ setup(options, nuxt) {
5
+ if (!nuxt.options.test || !options.token)
6
+ throw new Error("[nuxt-better-auth] Auth test helpers must be installed through createAuthTestContext() in a test build.");
7
+ nuxt.hook("ready", () => {
8
+ if (!nuxt.options.alias["#auth/server"])
9
+ throw new Error("[nuxt-better-auth] Auth E2E helpers require a local Better Auth server.");
10
+ });
11
+ const resolver = createResolver(import.meta.url);
12
+ nuxt.hook("better-auth:plugins:extend", (sources) => {
13
+ sources.server = [...sources.server || [], resolver.resolve("./server/plugin")];
14
+ });
15
+ nuxt.options.runtimeConfig.betterAuthTestToken = options.token;
16
+ addServerHandler({ route: "/api/auth/__test__", method: "post", handler: resolver.resolve("./server/handler") });
17
+ }
18
+ });
@@ -0,0 +1,25 @@
1
+ import type { AuthUser, AuthUserUpdateInput, ClientAuthSession } from '#nuxt-better-auth';
2
+ export interface MockUserSession {
3
+ user: AuthUser;
4
+ session: ClientAuthSession;
5
+ }
6
+ /** Reactive replacement for useUserSession in Nuxt runtime tests. */
7
+ export declare function createUserSessionMock(initial?: MockUserSession | null): {
8
+ setSession: (value: MockUserSession | null, options?: {
9
+ ready?: boolean;
10
+ }) => void;
11
+ reset: () => void;
12
+ user: import("vue").Ref<AuthUser | null>;
13
+ session: import("vue").Ref<ClientAuthSession | null>;
14
+ loggedIn: import("vue").ComputedRef<boolean>;
15
+ ready: import("vue").ComputedRef<boolean>;
16
+ fetchSession: (options?: {
17
+ headers?: HeadersInit;
18
+ force?: boolean;
19
+ }) => Promise<void>;
20
+ waitForSession: () => Promise<void>;
21
+ signOut: (options?: {
22
+ onSuccess?: () => void | Promise<void>;
23
+ }) => Promise<void>;
24
+ updateUser: (updates: AuthUserUpdateInput) => Promise<void>;
25
+ };
@@ -0,0 +1,56 @@
1
+ import { computed, ref, shallowRef, toRaw, watch } from "vue";
2
+ export function createUserSessionMock(initial = null) {
3
+ function cloneSession(value) {
4
+ return value && structuredClone({ user: toRaw(value.user), session: toRaw(value.session) });
5
+ }
6
+ const initialSession = cloneSession(initial);
7
+ const user = ref(null);
8
+ const session = ref(null);
9
+ const resolved = shallowRef(true);
10
+ const loggedIn = computed(() => Boolean(user.value && session.value));
11
+ function setSession(value, options = {}) {
12
+ const snapshot = cloneSession(value);
13
+ user.value = snapshot?.user ?? null;
14
+ session.value = snapshot?.session ?? null;
15
+ resolved.value = options.ready ?? true;
16
+ }
17
+ function reset() {
18
+ setSession(initialSession);
19
+ }
20
+ const auth = {
21
+ user,
22
+ session,
23
+ loggedIn,
24
+ ready: computed(() => resolved.value),
25
+ async fetchSession() {
26
+ },
27
+ async waitForSession() {
28
+ if (loggedIn.value)
29
+ return;
30
+ await new Promise((resolve) => {
31
+ let timeout;
32
+ const stop = watch(loggedIn, (authenticated) => {
33
+ if (authenticated) {
34
+ clearTimeout(timeout);
35
+ stop();
36
+ resolve();
37
+ }
38
+ });
39
+ timeout = setTimeout(() => {
40
+ stop();
41
+ resolve();
42
+ }, 5e3);
43
+ });
44
+ },
45
+ async signOut(options) {
46
+ setSession(null);
47
+ await options?.onSuccess?.();
48
+ },
49
+ async updateUser(updates) {
50
+ if (user.value)
51
+ user.value = { ...user.value, ...updates };
52
+ }
53
+ };
54
+ reset();
55
+ return { ...auth, setSession, reset };
56
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,34 @@
1
+ import { parseJSON } from "better-auth/client";
2
+ import { z } from "zod";
3
+ import { createAuthError, defineEventHandler, toWebRequest, useRuntimeConfig } from "../../server/internal/nitro-compat.js";
4
+ import { serverAuth } from "../../server/utils/auth.js";
5
+ const requestSchema = z.discriminatedUnion("action", [
6
+ z.object({ action: z.literal("createUser"), data: z.record(z.string(), z.unknown()) }),
7
+ z.object({ action: z.literal("login"), data: z.object({ userId: z.string() }).passthrough() }),
8
+ z.object({ action: z.literal("clear") })
9
+ ]);
10
+ const ownedUsers = /* @__PURE__ */ new Set();
11
+ export default defineEventHandler(async (event) => {
12
+ const token = useRuntimeConfig(event).betterAuthTestToken;
13
+ if (!token || toWebRequest(event).headers.get("x-nuxt-auth-test") !== token)
14
+ throw createAuthError(404, "Not found");
15
+ const body = requestSchema.parse(parseJSON(await toWebRequest(event).text()));
16
+ const context = await serverAuth(event).$context;
17
+ const test = context.test;
18
+ if (body.action === "createUser") {
19
+ const user = await test.saveUser(test.createUser(body.data));
20
+ ownedUsers.add(user.id);
21
+ return user;
22
+ }
23
+ if (body.action === "login") {
24
+ if (!ownedUsers.has(body.data.userId))
25
+ throw createAuthError(403, "Create the user through this test context before logging in.");
26
+ const result = await test.login(body.data);
27
+ return { ...result, headers: Array.from(result.headers.entries()) };
28
+ }
29
+ for (const id of ownedUsers) {
30
+ await test.deleteUser(id);
31
+ ownedUsers.delete(id);
32
+ }
33
+ return { ok: true };
34
+ });
@@ -0,0 +1,23 @@
1
+ declare const _default: {
2
+ id: "test-utils";
3
+ version: string;
4
+ init(ctx: import("better-auth").AuthContext): {
5
+ context: {
6
+ test: import("better-auth/plugins").TestHelpers;
7
+ };
8
+ options: {
9
+ databaseHooks: {
10
+ verification: {
11
+ create: {
12
+ after(verification: {
13
+ identifier: string;
14
+ value: string;
15
+ } | null): Promise<void>;
16
+ };
17
+ };
18
+ };
19
+ } | undefined;
20
+ };
21
+ options: import("better-auth/plugins").TestUtilsOptions;
22
+ };
23
+ export default _default;
@@ -0,0 +1,2 @@
1
+ import { testUtils } from "better-auth/plugins";
2
+ export default testUtils();
@@ -2,7 +2,7 @@ import type { AuthSocialProviderRegistry, AuthUser, UserMatch } from '#nuxt-bett
2
2
  export type { AppSession, AuthSession, AuthSocialProviderRegistry, AuthUser, AuthUserUpdateInput, ClientAuthSession, RequireSessionOptions, ServerAuthContext, UserMatch, UserSessionComposable } from './types/augment.js';
3
3
  export type AuthSocialProviderId = AuthSocialProviderRegistry extends {
4
4
  ids: infer T;
5
- } ? Extract<T, string> : never;
5
+ } ? Extract<T, string> : string;
6
6
  export type { Auth, InferPluginTypes, InferSessionFromClient as InferSession, InferUserFromClient as InferUser } from 'better-auth';
7
7
  export interface AuthActionError {
8
8
  message: string;
package/dist/types.d.mts CHANGED
@@ -1,11 +1,5 @@
1
- import type { NuxtModule } from '@nuxt/schema'
1
+ export { type BetterAuthModuleOptions, type ModuleOptions, type defineClientAuth, type defineServerAuth } from '../dist/runtime/config.js'
2
2
 
3
- import type { default as Module } from './module.mjs'
4
-
5
- export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
6
-
7
- export { type BetterAuthModuleOptions, type defineClientAuth, type defineServerAuth } from '../dist/runtime/config.js'
8
-
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'
3
+ export { type AppSession, type Auth, type AuthActionError, type AuthMeta, type AuthMode, type AuthRouteRules, type AuthSession, type AuthSocialProviderId, type AuthUser, type ClientAuthSession, type InferSession, type InferUser, type RequireSessionOptions, type ServerAuthContext, type UserMatch } from '../dist/runtime/types.js'
10
4
 
11
5
  export { default } from './module.mjs'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nuxtjs/better-auth",
3
3
  "type": "module",
4
- "version": "0.3.1",
4
+ "version": "0.3.2",
5
5
  "description": "Nuxt module for Better Auth integration with NuxtHub, route protection, session management, and role-based access",
6
6
  "author": "onmax",
7
7
  "license": "MIT",
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "exports": {
14
14
  ".": {
15
- "types": "./dist/types.d.mts",
15
+ "types": "./dist/module.d.mts",
16
16
  "import": "./dist/module.mjs"
17
17
  },
18
18
  "./composables": {
@@ -22,19 +22,33 @@
22
22
  "./config": {
23
23
  "types": "./dist/runtime/config.d.ts",
24
24
  "import": "./dist/runtime/config.js"
25
+ },
26
+ "./test-utils/runtime": {
27
+ "types": "./dist/runtime/test-utils/runtime.d.ts",
28
+ "import": "./dist/runtime/test-utils/runtime.js"
29
+ },
30
+ "./test-utils/e2e": {
31
+ "types": "./dist/runtime/test-utils/e2e.d.ts",
32
+ "import": "./dist/runtime/test-utils/e2e.js"
25
33
  }
26
34
  },
27
35
  "main": "./dist/module.mjs",
28
36
  "typesVersions": {
29
37
  "*": {
30
38
  ".": [
31
- "./dist/types.d.mts"
39
+ "./dist/module.d.mts"
32
40
  ],
33
41
  "composables": [
34
42
  "./dist/runtime/composables.d.ts"
35
43
  ],
36
44
  "config": [
37
45
  "./dist/runtime/config.d.ts"
46
+ ],
47
+ "test-utils/runtime": [
48
+ "./dist/runtime/test-utils/runtime.d.ts"
49
+ ],
50
+ "test-utils/e2e": [
51
+ "./dist/runtime/test-utils/e2e.d.ts"
38
52
  ]
39
53
  }
40
54
  },
@@ -45,10 +59,14 @@
45
59
  "node": "^22.19.0 || ^24.11.0 || >=26.0.0"
46
60
  },
47
61
  "peerDependencies": {
62
+ "@nuxt/test-utils": "^4.1.0",
48
63
  "@nuxthub/core": ">=0.10.5",
49
64
  "better-auth": ">=1.7.3 <2"
50
65
  },
51
66
  "peerDependenciesMeta": {
67
+ "@nuxt/test-utils": {
68
+ "optional": true
69
+ },
52
70
  "@nuxthub/core": {
53
71
  "optional": true
54
72
  }
@@ -58,9 +76,12 @@
58
76
  "@nuxt/kit": "^4.5.2",
59
77
  "auth": "1.7.3",
60
78
  "consola": "^3.4.2",
79
+ "cookie-es": "^3.1.1",
61
80
  "defu": "^6.1.7",
81
+ "get-port-please": "^3.2.0",
62
82
  "h3": "^1.15.11",
63
83
  "jiti": "^2.7.0",
84
+ "nostics": "^1.2.0",
64
85
  "pathe": "^2.0.3",
65
86
  "radix3": "^1.1.2",
66
87
  "std-env": "^4.2.0",
@@ -79,16 +100,19 @@
79
100
  "@pinia/nuxt": "^1.0.2",
80
101
  "@types/better-sqlite3": "^9.6.0",
81
102
  "@types/node": "^24.13.3",
103
+ "@vue/test-utils": "^2.4.6",
82
104
  "better-auth": "1.7.3",
83
105
  "better-call": "1.4.0",
84
106
  "better-sqlite3": "^12.11.1",
85
107
  "drizzle-kit": "^0.31.10",
86
108
  "drizzle-orm": "^0.45.2",
87
109
  "eslint": "^10.8.1",
110
+ "happy-dom": "^20.8.9",
88
111
  "nitropack": "2.13.4",
89
112
  "nuxt": "^4.5.2",
90
113
  "pinia": "^4.0.3",
91
114
  "pkg-pr-new": "0.0.88",
115
+ "playwright-core": "1.58.2",
92
116
  "postgres": "^3.4.9",
93
117
  "typescript": "~5.9.3",
94
118
  "unstorage": "^1.17.5",
@@ -112,6 +136,7 @@
112
136
  "typecheck:runtime-server": "cd test/cases/plugins-type-inference && nuxi prepare && vue-tsc --noEmit --pretty false -p .nuxt/tsconfig.server.json",
113
137
  "typecheck:playground": "pnpm -C playground exec nuxi prepare && pnpm -C playground exec vue-tsc --noEmit -p .nuxt/tsconfig.app.json",
114
138
  "test": "vitest run",
115
- "test:watch": "vitest watch"
139
+ "test:watch": "vitest watch",
140
+ "test:runtime": "vitest run --config vitest.runtime.config.ts"
116
141
  }
117
142
  }