diff --git a/demo/nextjs/package.json b/demo/nextjs/package.json index 057d6cdeb3..e23bf5323d 100644 --- a/demo/nextjs/package.json +++ b/demo/nextjs/package.json @@ -19,8 +19,6 @@ "@libsql/client": "^0.8.1", "@libsql/kysely-libsql": "^0.4.1", "@number-flow/react": "^0.5.10", - "@prisma/adapter-libsql": "^5.22.0", - "@prisma/client": "^5.22.0", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-aspect-ratio": "^1.1.7", @@ -67,7 +65,7 @@ "lucide-react": "^0.542.0", "mini-svg-data-uri": "^1.4.4", "mysql2": "^3.14.4", - "next": "16.0.1", + "next": "16.0.7", "next-themes": "^0.4.6", "react": "catalog:react19", "react-day-picker": "9.9.0", @@ -92,7 +90,6 @@ "@types/react-dom": "catalog:react19", "@types/ua-parser-js": "^0.7.39", "postcss": "^8.5.6", - "prisma": "^5.22.0", "tailwindcss": "^4.1.13", "tw-animate-css": "^1.3.8" } diff --git a/demo/stateless/package.json b/demo/stateless/package.json index 61d3984bca..c12fd802d9 100644 --- a/demo/stateless/package.json +++ b/demo/stateless/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "better-auth": "workspace:*", - "next": "16.0.1", + "next": "16.0.7", "react": "catalog:react19", "react-dom": "catalog:react19" }, diff --git a/docs/components/sidebar-content.tsx b/docs/components/sidebar-content.tsx index 5029a0eb56..e1c08adcfa 100644 --- a/docs/components/sidebar-content.tsx +++ b/docs/components/sidebar-content.tsx @@ -999,7 +999,7 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2, ), }, { - title: "Tiktok", + title: "TikTok", href: "/docs/authentication/tiktok", icon: () => ( { }) } ``` + +### Middleware + +You can use TanStack Start's middleware to protect routes that require authentication. Create a middleware that checks for a valid session and redirects unauthenticated users to the login page. + +```ts title="src/middleware/auth.ts" +import { redirect } from "@tanstack/react-router"; +import { createMiddleware } from "@tanstack/react-start"; +import { auth } from "./auth"; + +export const authMiddleware = createMiddleware().server( + async ({ next, request }) => { + const session = await auth.api.getSession({ headers: request.headers }) + + if (!session) { + throw redirect({ to: "/login" }) + } + + return await next() + } +); +``` + +You can then use this middleware in your route definitions to protect specific routes: + +```tsx title="src/routes/dashboard.tsx" +import { createFileRoute } from '@tanstack/react-router' +import { authMiddleware } from '@/lib/middleware' + +export const Route = createFileRoute('/dashboard')({ + component: RouteComponent, + server: { + middleware: [authMiddleware], + }, +}) + +function RouteComponent() { + return
Hello "/dashboard"!
+} +``` + diff --git a/docs/content/docs/plugins/organization.mdx b/docs/content/docs/plugins/organization.mdx index ec60f7779c..09f0e91a54 100644 --- a/docs/content/docs/plugins/organization.mdx +++ b/docs/content/docs/plugins/organization.mdx @@ -612,7 +612,7 @@ You can set the active organization by calling the `organization.setActive` func set to `null`. - + ```ts type setActiveOrganization = { /** @@ -858,7 +858,7 @@ export const auth = betterAuth({ To invite users to an organization, you can use the `invite` function provided by the client. The `invite` function takes an object with the following properties: - + ```ts type createInvitation = { /** @@ -900,7 +900,7 @@ When a user receives an invitation email, they can click on the invitation link Make sure to call the `acceptInvitation` function after the user is logged in. - + ```ts type acceptInvitation = { /** @@ -937,7 +937,7 @@ If a user has sent out an invitation, you can use this method to cancel it. If you're looking for how a user can reject an invitation, you can find that [here](#reject-invitation). - + ```ts type cancelInvitation = { /** @@ -952,7 +952,7 @@ type cancelInvitation = { If this user has received an invitation, but wants to decline it, this method will allow you to do so by rejecting it. - + ```ts type rejectInvitation = { /** @@ -993,7 +993,7 @@ type getInvitation = { To list all invitations for a given organization you can use the `listInvitations` function provided by the client. - + ```ts type listInvitations = { /** @@ -1033,7 +1033,7 @@ const invitations = await auth.api.listUserInvitations({ To list all members of an organization you can use the `listMembers` function. - + ```ts type listMembers = { @@ -1077,7 +1077,7 @@ type listMembers = { To remove you can use `organization.removeMember` - + ```ts type removeMember = { /** @@ -1096,7 +1096,7 @@ type removeMember = { To update the role of a member in an organization, you can use the `organization.updateMemberRole`. If the user has the permission to update the role of the member, the role will be updated. - + ```ts type updateMemberRole = { /** @@ -1911,7 +1911,7 @@ type removeTeam = { Sets the given team as the current active team. If `teamId` is `null` the current active team is unset. - + ```ts type setActiveTeam = { /** @@ -1926,7 +1926,7 @@ type setActiveTeam = { List all teams that the current user is a part of. - + ```ts type listUserTeams = { } @@ -1937,7 +1937,7 @@ List all teams that the current user is a part of. List the members of the given team. - + ```ts type listTeamMembers = { /** @@ -1952,7 +1952,7 @@ type listTeamMembers = { Add a member to a team. - + ```ts type addTeamMember = { /** @@ -1971,7 +1971,7 @@ type addTeamMember = { Remove a member from a team. - + ```ts type removeTeamMember = { /** diff --git a/docs/package.json b/docs/package.json index 0d95d0f95a..f530880153 100644 --- a/docs/package.json +++ b/docs/package.json @@ -74,7 +74,7 @@ "lottie-react": "^2.4.1", "lucide-react": "^0.542.0", "motion": "^12.23.12", - "next": "16.0.1", + "next": "16.0.7", "next-themes": "^0.4.6", "prism-react-renderer": "^2.4.1", "react": "catalog:react19", diff --git a/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/package.json b/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/package.json index def734027a..03a0e0b8b8 100644 --- a/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/package.json +++ b/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/package.json @@ -6,6 +6,7 @@ "typecheck": "tsc --project tsconfig.json" }, "dependencies": { - "better-auth": "workspace:*" + "better-auth": "workspace:*", + "@better-auth/sso": "workspace:*" } } diff --git a/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/src/oidc-provider.ts b/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/src/oidc-provider.ts new file mode 100644 index 0000000000..fb57ceb638 --- /dev/null +++ b/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/src/oidc-provider.ts @@ -0,0 +1,10 @@ +import { betterAuth } from "better-auth"; +import { oidcProvider } from "better-auth/plugins"; + +export const auth = betterAuth({ + plugins: [ + oidcProvider({ + loginPage: "/login", + }), + ], +}); diff --git a/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/src/sso.ts b/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/src/sso.ts new file mode 100644 index 0000000000..1bba99de7e --- /dev/null +++ b/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/src/sso.ts @@ -0,0 +1,6 @@ +import { sso } from "@better-auth/sso"; +import { betterAuth } from "better-auth"; + +export const auth = betterAuth({ + plugins: [sso()], +}); diff --git a/packages/better-auth/package.json b/packages/better-auth/package.json index a81d7dd53f..912afd759d 100644 --- a/packages/better-auth/package.json +++ b/packages/better-auth/package.json @@ -449,10 +449,10 @@ "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "better-call": "catalog:", - "ms": "4.0.0-nightly.202508271359", "defu": "^6.1.4", "jose": "^6.1.0", "kysely": "^0.28.5", + "ms": "4.0.0-nightly.202508271359", "nanostores": "^1.0.1", "zod": "^4.1.12" }, @@ -471,7 +471,7 @@ "happy-dom": "^20.0.10", "listhen": "^1.9.0", "mongodb": "^6.18.0", - "msw": "^2.12.1", + "msw": "^2.12.4", "mysql2": "^3.14.4", "next": "^16.0.1", "oauth2-mock-server": "^7.2.1", diff --git a/packages/better-auth/src/adapters/create-test-suite.ts b/packages/better-auth/src/adapters/create-test-suite.ts index 0204a5468f..25c6312425 100644 --- a/packages/better-auth/src/adapters/create-test-suite.ts +++ b/packages/better-auth/src/adapters/create-test-suite.ts @@ -13,6 +13,83 @@ import { betterAuth } from "../auth"; import type { Account, Session, User, Verification } from "../types"; import type { Logger } from "./test-adapter"; +/** + * Test entry type that supports both callback and object formats. + * Object format allows specifying migration options that will be applied before the test runs. + */ +export type TestEntry = + | ((context: { + readonly skip: { + (note?: string | undefined): never; + (condition: boolean, note?: string | undefined): void; + }; + }) => Promise) + | { + migrateBetterAuth?: BetterAuthOptions; + test: (context: { + readonly skip: { + (note?: string | undefined): never; + (condition: boolean, note?: string | undefined): void; + }; + }) => Promise; + }; + +/** + * Deep equality comparison for BetterAuthOptions. + * Handles nested objects, arrays, and primitive values. + */ +function deepEqual(a: any, b: any): boolean { + if (a === b) return true; + if (a == null || b == null) return a === b; + if (typeof a !== typeof b) return false; + + if (typeof a === "object") { + if (Array.isArray(a) !== Array.isArray(b)) return false; + + if (Array.isArray(a)) { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i++) { + if (!deepEqual(a[i], b[i])) return false; + } + return true; + } + + const keysA = Object.keys(a); + const keysB = Object.keys(b); + + if (keysA.length !== keysB.length) return false; + + for (const key of keysA) { + if (!keysB.includes(key)) return false; + if (!deepEqual(a[key], b[key])) return false; + } + + return true; + } + + return false; +} + +/** + * Statistics tracking for test suites. + */ +export type TestSuiteStats = { + migrationCount: number; + totalMigrationTime: number; + testCount: number; + suiteStartTime: number; + suiteDuration: number; + suiteName: string; + groupingStats?: { + totalGroups: number; + averageTestsPerGroup: number; + largestGroupSize: number; + smallestGroupSize: number; + groupsWithMultipleTests: number; + totalTestsInGroups: number; + }; +}; + type GenerateFn = ( Model: M, ) => Promise< @@ -81,20 +158,7 @@ export type InsertRandomFn = < >; export const createTestSuite = < - Tests extends Record< - string, - (context: { - /** - * Mark tests as skipped. All execution after this call will be skipped. - * This function throws an error, so make sure you are not catching it accidentally. - * @see {@link https://vitest.dev/guide/test-context#skip} - */ - readonly skip: { - (note?: string | undefined): never; - (condition: boolean, note?: string | undefined): void; - }; - }) => Promise - >, + Tests extends Record, AdditionalOptions extends Record = {}, >( suiteName: string, @@ -177,7 +241,7 @@ export const createTestSuite = < cleanup: () => Promise; runMigrations: () => Promise; prefixTests?: string | undefined; - onTestFinish: () => Promise; + onTestFinish: (stats: TestSuiteStats) => Promise; customIdGenerator?: () => any | Promise | undefined; transformIdOutput?: (id: any) => string | undefined; }) => { @@ -310,18 +374,57 @@ export const createTestSuite = < } }; - let didMigrateOnOptionsModify = false; + // Track current applied BetterAuth options state + let currentAppliedOptions: BetterAuthOptions | null = null; - const resetBetterAuthOptions = async () => { - adapter = await helpers.adapter(); - await helpers.modifyBetterAuthOptions( - config.defaultBetterAuthOptions || {}, + // Statistics tracking + const stats: TestSuiteStats = { + migrationCount: 0, + totalMigrationTime: 0, + testCount: 0, + suiteStartTime: performance.now(), + suiteDuration: 0, + suiteName, + }; + + /** + * Apply BetterAuth options and run migrations if needed. + * Tracks migration statistics. + */ + const applyOptionsAndMigrate = async ( + options: BetterAuthOptions | Partial, + forceMigrate: boolean = false, + ): Promise => { + const finalOptions = deepmerge( + config?.defaultBetterAuthOptions || {}, + options || {}, ); - if (didMigrateOnOptionsModify) { - didMigrateOnOptionsModify = false; - await helpers.runMigrations(); + + // Check if options have changed + const optionsChanged = !deepEqual(currentAppliedOptions, finalOptions); + + if (optionsChanged || forceMigrate) { adapter = await helpers.adapter(); + await helpers.modifyBetterAuthOptions(finalOptions); + + if (config.alwaysMigrate || forceMigrate) { + const migrationStart = performance.now(); + await helpers.runMigrations(); + const migrationTime = performance.now() - migrationStart; + + stats.migrationCount++; + stats.totalMigrationTime += migrationTime; + + adapter = await helpers.adapter(); + } + + currentAppliedOptions = finalOptions; + } else { + // Options haven't changed, just update the reference + currentAppliedOptions = finalOptions; } + + return finalOptions; }; const transformGeneratedModel = (data: Record) => { @@ -493,14 +596,7 @@ export const createTestSuite = < opts: BetterAuthOptions, shouldRunMigrations: boolean, ) => { - const res = helpers.modifyBetterAuthOptions( - deepmerge(config?.defaultBetterAuthOptions || {}, opts), - ); - if (config.alwaysMigrate || shouldRunMigrations) { - didMigrateOnOptionsModify = true; - await helpers.runMigrations(); - } - return res; + return await applyOptionsAndMigrate(opts, shouldRunMigrations); }; const additionalOptions = { ...options }; @@ -558,55 +654,231 @@ export const createTestSuite = < await helpers.cleanup(); } catch {} if (config.defaultBetterAuthOptions && !allDisabled) { - await helpers.modifyBetterAuthOptions( + await applyOptionsAndMigrate( config.defaultBetterAuthOptions, + config.alwaysMigrate, ); - if (config.alwaysMigrate) { - await helpers.runMigrations(); - } } }); + /** + * Extract test function and migration options from a test entry. + */ + const extractTestEntry = ( + entry: TestEntry, + ): { + testFn: (context: { + readonly skip: { + (note?: string | undefined): never; + (condition: boolean, note?: string | undefined): void; + }; + }) => Promise; + migrateBetterAuth?: BetterAuthOptions; + } => { + if (typeof entry === "function") { + return { testFn: entry }; + } + return { + testFn: entry.test, + migrateBetterAuth: entry.migrateBetterAuth, + }; + }; + + // Convert test entries to array with migration info (moved before onFinish for access) + const testEntries = Object.entries(fullTests).map(([name, entry]) => { + const { testFn, migrateBetterAuth } = extractTestEntry( + entry as TestEntry, + ); + return { name, testFn, migrateBetterAuth }; + }); + + /** + * Group tests by their migrateBetterAuth options. + * Tests with equal migration options are grouped together. + */ + type TestGroup = { + migrationOptions: BetterAuthOptions | null | undefined; + testIndices: number[]; + }; + + const groupTestsByMigrationOptions = (): TestGroup[] => { + const groups: TestGroup[] = []; + let currentGroup: TestGroup | null = null; + + for (let i = 0; i < testEntries.length; i++) { + const { migrateBetterAuth } = testEntries[i]!; + const isSkipped = + (allDisabled && + options?.disableTests?.[testEntries[i]!.name] !== false) || + (options?.disableTests?.[testEntries[i]!.name] ?? false); + + // Skip grouping for skipped tests - they'll be handled individually + if (isSkipped) { + if (currentGroup) { + groups.push(currentGroup); + currentGroup = null; + } + groups.push({ + migrationOptions: migrateBetterAuth, + testIndices: [i], + }); + continue; + } + + // Check if this test belongs to the current group + if ( + currentGroup && + deepEqual(currentGroup.migrationOptions, migrateBetterAuth) + ) { + currentGroup.testIndices.push(i); + } else { + // Start a new group + if (currentGroup) { + groups.push(currentGroup); + } + currentGroup = { + migrationOptions: migrateBetterAuth, + testIndices: [i], + }; + } + } + + // Add the last group if it exists + if (currentGroup) { + groups.push(currentGroup); + } + + return groups; + }; + + const testGroups = groupTestsByMigrationOptions(); + + // Calculate grouping statistics + const calculateGroupingStats = () => { + const nonSkippedGroups = testGroups.filter( + (group) => group.testIndices.length > 0, + ); + const groupSizes = nonSkippedGroups.map( + (group) => group.testIndices.length, + ); + + if (groupSizes.length === 0) { + return { + totalGroups: 0, + averageTestsPerGroup: 0, + largestGroupSize: 0, + smallestGroupSize: 0, + groupsWithMultipleTests: 0, + totalTestsInGroups: 0, + }; + } + + const totalTestsInGroups = groupSizes.reduce( + (sum, size) => sum + size, + 0, + ); + const groupsWithMultipleTests = groupSizes.filter( + (size) => size > 1, + ).length; + + return { + totalGroups: nonSkippedGroups.length, + averageTestsPerGroup: totalTestsInGroups / nonSkippedGroups.length, + largestGroupSize: Math.max(...groupSizes), + smallestGroupSize: Math.min(...groupSizes), + groupsWithMultipleTests, + totalTestsInGroups, + }; + }; + const onFinish = async (testName: string) => { await cleanupCreatedRows(); - await resetBetterAuthOptions(); - // Check if this is the last test by comparing current test index with total tests - const testEntries = Object.entries(fullTests); + const currentTestIndex = testEntries.findIndex( - ([name]) => - name === testName.replace(/\[.*?\] /, "").replace(/ ─ /g, " - "), + ({ name }) => name === testName, ); const isLastTest = currentTestIndex === testEntries.length - 1; if (isLastTest) { - await helpers.onTestFinish(); + stats.suiteDuration = performance.now() - stats.suiteStartTime; + stats.groupingStats = calculateGroupingStats(); + await helpers.onTestFinish(stats); } }; - if (allDisabled) { - await resetBetterAuthOptions(); - } + // Track the current group's migration options + let currentGroupMigrationOptions: BetterAuthOptions | null | undefined = + null; + + for (let i = 0; i < testEntries.length; i++) { + const { name: testName, testFn, migrateBetterAuth } = testEntries[i]!; + + // Find which group this test belongs to + const testGroup = testGroups.find((group) => + group.testIndices.includes(i), + ); + const isFirstInGroup = testGroup && testGroup.testIndices[0] === i; - for (let [testName, testFn] of Object.entries(fullTests)) { let shouldSkip = (allDisabled && options?.disableTests?.[testName] !== false) || (options?.disableTests?.[testName] ?? false); - testName = testName.replace( + + let displayName = testName.replace( " - ", ` ${TTY_COLORS.dim}${dash}${TTY_COLORS.undim} `, ); if (config.prefixTests) { - testName = `${config.prefixTests} ${TTY_COLORS.dim}>${TTY_COLORS.undim} ${testName}`; + displayName = `${config.prefixTests} ${TTY_COLORS.dim}>${TTY_COLORS.undim} ${displayName}`; } if (helpers.prefixTests) { - testName = `[${TTY_COLORS.dim}${helpers.prefixTests}${TTY_COLORS.undim}] ${testName}`; + displayName = `[${TTY_COLORS.dim}${helpers.prefixTests}${TTY_COLORS.undim}] ${displayName}`; } test.skipIf(shouldSkip)( - testName, + displayName, { timeout: 30000 }, async ({ onTestFailed, skip }) => { resetDebugLogs(); + + // Apply migration options before test runs + await (async () => { + if (shouldSkip) return; + + const thisMigration = deepmerge( + config.defaultBetterAuthOptions || {}, + migrateBetterAuth || {}, + ); + + // If this is the first test in a group, migrate to the group's options + if (isFirstInGroup && testGroup) { + const groupMigrationOptions = testGroup.migrationOptions; + const groupFinalOptions = deepmerge( + config.defaultBetterAuthOptions || {}, + groupMigrationOptions || {}, + ); + + // Only migrate if the group's options are different from current state + if ( + !deepEqual( + currentGroupMigrationOptions, + groupMigrationOptions, + ) + ) { + await applyOptionsAndMigrate(groupFinalOptions, true); + currentGroupMigrationOptions = groupMigrationOptions; + } + } + // If this test is not in a group or not first in group, check if migration is needed + else if ( + !deepEqual(currentGroupMigrationOptions, migrateBetterAuth) + ) { + await applyOptionsAndMigrate(thisMigration, true); + currentGroupMigrationOptions = migrateBetterAuth; + } + })(); + + stats.testCount++; + onTestFailed(async () => { printDebugLogs(); await onFinish(testName); diff --git a/packages/better-auth/src/adapters/test-adapter.ts b/packages/better-auth/src/adapters/test-adapter.ts index 71521d9d25..4fe46dee2d 100644 --- a/packages/better-auth/src/adapters/test-adapter.ts +++ b/packages/better-auth/src/adapters/test-adapter.ts @@ -4,7 +4,7 @@ import { deepmerge, initGetModelName } from "@better-auth/core/db/adapter"; import { TTY_COLORS } from "@better-auth/core/env"; import { afterAll, beforeAll, describe } from "vitest"; import { getAuthTables } from "../db"; -import type { createTestSuite } from "./create-test-suite"; +import type { createTestSuite, TestSuiteStats } from "./create-test-suite"; export type Logger = { info: (...args: any[]) => void; @@ -197,12 +197,158 @@ export const testAdapter = async ({ return { execute: () => { describe(adapterDisplayName, async () => { + // Collect statistics from all test suites + const allSuiteStats: TestSuiteStats[] = []; + beforeAll(async () => { await migrate(); }, 60000); afterAll(async () => { await cleanup(); + + // Display statistics summary + if (allSuiteStats.length > 0) { + const totalMigrations = allSuiteStats.reduce( + (sum, stats) => sum + stats.migrationCount, + 0, + ); + const totalMigrationTime = allSuiteStats.reduce( + (sum, stats) => sum + stats.totalMigrationTime, + 0, + ); + const totalTests = allSuiteStats.reduce( + (sum, stats) => sum + stats.testCount, + 0, + ); + const totalDuration = allSuiteStats.reduce( + (sum, stats) => sum + stats.suiteDuration, + 0, + ); + + const dash = "─"; + const separator = `${dash.repeat(80)}`; + + console.log(`\n${TTY_COLORS.fg.cyan}${separator}`); + console.log( + `${TTY_COLORS.fg.cyan}${TTY_COLORS.bright}TEST SUITE STATISTICS SUMMARY${TTY_COLORS.reset}`, + ); + console.log( + `${TTY_COLORS.fg.cyan}${separator}${TTY_COLORS.reset}\n`, + ); + + // Per-suite breakdown + for (const stats of allSuiteStats) { + const avgMigrationTime = + stats.migrationCount > 0 + ? (stats.totalMigrationTime / stats.migrationCount).toFixed(2) + : "0.00"; + console.log( + `${TTY_COLORS.fg.magenta}${stats.suiteName}${TTY_COLORS.reset}:`, + ); + console.log( + ` Tests: ${TTY_COLORS.fg.green}${stats.testCount}${TTY_COLORS.reset}`, + ); + console.log( + ` Migrations: ${TTY_COLORS.fg.yellow}${stats.migrationCount}${TTY_COLORS.reset} (avg: ${avgMigrationTime}ms)`, + ); + console.log( + ` Total Migration Time: ${TTY_COLORS.fg.yellow}${stats.totalMigrationTime.toFixed(2)}ms${TTY_COLORS.reset}`, + ); + console.log( + ` Suite Duration: ${TTY_COLORS.fg.blue}${stats.suiteDuration.toFixed(2)}ms${TTY_COLORS.reset}`, + ); + + // Display grouping statistics if available + if (stats.groupingStats) { + const { + totalGroups, + averageTestsPerGroup, + largestGroupSize, + smallestGroupSize, + groupsWithMultipleTests, + } = stats.groupingStats; + console.log( + ` Test Groups: ${TTY_COLORS.fg.cyan}${totalGroups}${TTY_COLORS.reset}`, + ); + if (totalGroups > 0) { + console.log( + ` Avg Tests/Group: ${TTY_COLORS.fg.cyan}${averageTestsPerGroup.toFixed(2)}${TTY_COLORS.reset}`, + ); + console.log( + ` Largest Group: ${TTY_COLORS.fg.cyan}${largestGroupSize}${TTY_COLORS.reset}`, + ); + console.log( + ` Smallest Group: ${TTY_COLORS.fg.cyan}${smallestGroupSize}${TTY_COLORS.reset}`, + ); + console.log( + ` Groups w/ Multiple Tests: ${TTY_COLORS.fg.cyan}${groupsWithMultipleTests}${TTY_COLORS.reset}`, + ); + } + } + + console.log(""); + } + + // Totals + const avgMigrationTime = + totalMigrations > 0 + ? (totalMigrationTime / totalMigrations).toFixed(2) + : "0.00"; + + // Calculate total grouping statistics + const totalGroups = allSuiteStats.reduce( + (sum, stats) => sum + (stats.groupingStats?.totalGroups || 0), + 0, + ); + const totalGroupsWithMultipleTests = allSuiteStats.reduce( + (sum, stats) => + sum + (stats.groupingStats?.groupsWithMultipleTests || 0), + 0, + ); + const totalTestsInGroups = allSuiteStats.reduce( + (sum, stats) => + sum + (stats.groupingStats?.totalTestsInGroups || 0), + 0, + ); + const avgTestsPerGroup = + totalGroups > 0 ? totalTestsInGroups / totalGroups : 0; + + console.log(`${TTY_COLORS.fg.cyan}${separator}`); + console.log( + `${TTY_COLORS.fg.cyan}${TTY_COLORS.bright}TOTALS${TTY_COLORS.reset}`, + ); + console.log( + ` Total Tests: ${TTY_COLORS.fg.green}${totalTests}${TTY_COLORS.reset}`, + ); + console.log( + ` Total Migrations: ${TTY_COLORS.fg.yellow}${totalMigrations}${TTY_COLORS.reset} (avg: ${avgMigrationTime}ms)`, + ); + console.log( + ` Total Migration Time: ${TTY_COLORS.fg.yellow}${totalMigrationTime.toFixed(2)}ms${TTY_COLORS.reset}`, + ); + console.log( + ` Total Duration: ${TTY_COLORS.fg.blue}${totalDuration.toFixed(2)}ms${TTY_COLORS.reset}`, + ); + + // Display total grouping statistics + if (totalGroups > 0) { + console.log( + ` Total Test Groups: ${TTY_COLORS.fg.cyan}${totalGroups}${TTY_COLORS.reset}`, + ); + console.log( + ` Avg Tests/Group: ${TTY_COLORS.fg.cyan}${avgTestsPerGroup.toFixed(2)}${TTY_COLORS.reset}`, + ); + console.log( + ` Groups w/ Multiple Tests: ${TTY_COLORS.fg.cyan}${totalGroupsWithMultipleTests}${TTY_COLORS.reset}`, + ); + } + + console.log( + `${TTY_COLORS.fg.cyan}${separator}${TTY_COLORS.reset}\n`, + ); + } + await onFinish?.(); }, 60000); @@ -227,7 +373,9 @@ export const testAdapter = async ({ cleanup, prefixTests, runMigrations: migrate, - onTestFinish: async () => {}, + onTestFinish: async (stats: TestSuiteStats) => { + allSuiteStats.push(stats); + }, customIdGenerator, transformIdOutput, }); diff --git a/packages/better-auth/src/adapters/tests/basic.ts b/packages/better-auth/src/adapters/tests/basic.ts index 7fa314fd61..acb818f844 100644 --- a/packages/better-auth/src/adapters/tests/basic.ts +++ b/packages/better-auth/src/adapters/tests/basic.ts @@ -97,36 +97,35 @@ export const getNormalTestSuiteTests = ( }); expect(findResult).toEqual(res); }, - "create - should return null for nullable foreign keys": async () => { - await modifyBetterAuthOptions( - { - plugins: [ - { - id: "nullable-test", - schema: { - testModel: { - fields: { - nullableReference: { - type: "string", - references: { field: "id", model: "user" }, - required: false, - }, + "create - should return null for nullable foreign keys": { + migrateBetterAuth: { + plugins: [ + { + id: "nullable-test", + schema: { + testModel: { + fields: { + nullableReference: { + type: "string", + references: { field: "id", model: "user" }, + required: false, }, }, }, - } satisfies BetterAuthPlugin, - ], - }, - true, - ); - const { nullableReference } = await adapter.create<{ - nullableReference: string | null; - }>({ - model: "testModel", - data: { nullableReference: null }, - forceAllowId: true, - }); - expect(nullableReference).toBeNull(); + }, + } satisfies BetterAuthPlugin, + ], + }, + test: async () => { + const { nullableReference } = await adapter.create<{ + nullableReference: string | null; + }>({ + model: "testModel", + data: { nullableReference: null }, + forceAllowId: true, + }); + expect(nullableReference).toBeNull(); + }, }, "create - should apply default values to fields": async () => { diff --git a/packages/better-auth/src/client/index.ts b/packages/better-auth/src/client/index.ts index 29f9b7f163..a468140488 100644 --- a/packages/better-auth/src/client/index.ts +++ b/packages/better-auth/src/client/index.ts @@ -38,6 +38,7 @@ export type * from "@better-fetch/fetch"; // @ts-expect-error export type * from "nanostores"; export type * from "../plugins/access"; +export type * from "../plugins/organization"; export type * from "../types/helper"; export type { UnionToIntersection } from "../types/helper"; //#endregion diff --git a/packages/better-auth/src/client/lynx/index.ts b/packages/better-auth/src/client/lynx/index.ts index dc90c1e3f8..a6e70ff679 100644 --- a/packages/better-auth/src/client/lynx/index.ts +++ b/packages/better-auth/src/client/lynx/index.ts @@ -3,6 +3,7 @@ import type { BetterAuthClientPlugin, } from "@better-auth/core"; import type { BASE_ERROR_CODES } from "@better-auth/core/error"; +import { capitalizeFirstLetter } from "@better-auth/core/utils"; import type { BetterFetchError, BetterFetchResponse, @@ -23,10 +24,6 @@ function getAtomKey(str: string) { return `use${capitalizeFirstLetter(str)}`; } -export function capitalizeFirstLetter(str: string) { - return str.charAt(0).toUpperCase() + str.slice(1); -} - type InferResolvedHooks = O extends { plugins: Array; } diff --git a/packages/better-auth/src/client/react/index.ts b/packages/better-auth/src/client/react/index.ts index b64e68e681..80b0b76547 100644 --- a/packages/better-auth/src/client/react/index.ts +++ b/packages/better-auth/src/client/react/index.ts @@ -3,6 +3,7 @@ import type { BetterAuthClientPlugin, } from "@better-auth/core"; import type { BASE_ERROR_CODES } from "@better-auth/core/error"; +import { capitalizeFirstLetter } from "@better-auth/core/utils"; import type { BetterFetchError, BetterFetchResponse, @@ -23,10 +24,6 @@ function getAtomKey(str: string) { return `use${capitalizeFirstLetter(str)}`; } -export function capitalizeFirstLetter(str: string) { - return str.charAt(0).toUpperCase() + str.slice(1); -} - type InferResolvedHooks = O extends { plugins: Array; } diff --git a/packages/better-auth/src/client/solid/index.ts b/packages/better-auth/src/client/solid/index.ts index e9087f754a..b3655f0a81 100644 --- a/packages/better-auth/src/client/solid/index.ts +++ b/packages/better-auth/src/client/solid/index.ts @@ -3,13 +3,13 @@ import type { BetterAuthClientPlugin, } from "@better-auth/core"; import type { BASE_ERROR_CODES } from "@better-auth/core/error"; +import { capitalizeFirstLetter } from "@better-auth/core/utils"; import type { BetterFetchError, BetterFetchResponse, } from "@better-fetch/fetch"; import type { Accessor } from "solid-js"; import type { PrettifyDeep, UnionToIntersection } from "../../types/helper"; -import { capitalizeFirstLetter } from "../../utils/misc"; import { getClientConfig } from "../config"; import { createDynamicPathProxy } from "../proxy"; import type { diff --git a/packages/better-auth/src/client/svelte/index.ts b/packages/better-auth/src/client/svelte/index.ts index c5538a7aec..ea3cdc2ac3 100644 --- a/packages/better-auth/src/client/svelte/index.ts +++ b/packages/better-auth/src/client/svelte/index.ts @@ -3,13 +3,13 @@ import type { BetterAuthClientPlugin, } from "@better-auth/core"; import type { BASE_ERROR_CODES } from "@better-auth/core/error"; +import { capitalizeFirstLetter } from "@better-auth/core/utils"; import type { BetterFetchError, BetterFetchResponse, } from "@better-fetch/fetch"; import type { Atom } from "nanostores"; import type { PrettifyDeep, UnionToIntersection } from "../../types/helper"; -import { capitalizeFirstLetter } from "../../utils/misc"; import { getClientConfig } from "../config"; import { createDynamicPathProxy } from "../proxy"; import type { diff --git a/packages/better-auth/src/client/vanilla.ts b/packages/better-auth/src/client/vanilla.ts index f73ed83e59..e52000bbb8 100644 --- a/packages/better-auth/src/client/vanilla.ts +++ b/packages/better-auth/src/client/vanilla.ts @@ -3,13 +3,13 @@ import type { BetterAuthClientPlugin, } from "@better-auth/core"; import type { BASE_ERROR_CODES } from "@better-auth/core/error"; +import { capitalizeFirstLetter } from "@better-auth/core/utils"; import type { BetterFetchError, BetterFetchResponse, } from "@better-fetch/fetch"; import type { Atom } from "nanostores"; import type { PrettifyDeep, UnionToIntersection } from "../types/helper"; -import { capitalizeFirstLetter } from "../utils/misc"; import { getClientConfig } from "./config"; import { createDynamicPathProxy } from "./proxy"; import type { diff --git a/packages/better-auth/src/client/vue/index.ts b/packages/better-auth/src/client/vue/index.ts index 0dd115c7ed..f24ed0dc56 100644 --- a/packages/better-auth/src/client/vue/index.ts +++ b/packages/better-auth/src/client/vue/index.ts @@ -3,13 +3,13 @@ import type { BetterAuthClientPlugin, } from "@better-auth/core"; import type { BASE_ERROR_CODES } from "@better-auth/core/error"; +import { capitalizeFirstLetter } from "@better-auth/core/utils"; import type { BetterFetchError, BetterFetchResponse, } from "@better-fetch/fetch"; import type { DeepReadonly, Ref } from "vue"; import type { PrettifyDeep, UnionToIntersection } from "../../types/helper"; -import { capitalizeFirstLetter } from "../../utils/misc"; import { getClientConfig } from "../config"; import { createDynamicPathProxy } from "../proxy"; import type { diff --git a/packages/better-auth/src/cookies/cookies.test.ts b/packages/better-auth/src/cookies/cookies.test.ts index 6590f395c5..b4b2009441 100644 --- a/packages/better-auth/src/cookies/cookies.test.ts +++ b/packages/better-auth/src/cookies/cookies.test.ts @@ -1,6 +1,7 @@ import type { BetterAuthOptions } from "@better-auth/core"; import { describe, expect, it } from "vitest"; import { getCookieCache, getCookies, getSessionCookie } from "../cookies"; +import { parseUserOutput } from "../db/schema"; import { getTestInstance } from "../test-utils/test-instance"; import { parseSetCookieHeader } from "./cookie-utils"; @@ -481,36 +482,6 @@ describe("Cookie Cache Field Filtering", () => { expect(cache?.user?.internalNote).toBeUndefined(); }); - it("should always preserve the user.id in cookie cache", async () => { - const { client, testUser, cookieSetter } = await getTestInstance({ - secret: "better-auth.secret", - session: { - cookieCache: { - enabled: true, - }, - }, - }); - const headers = new Headers(); - await client.signIn.email( - { - email: testUser.email, - password: testUser.password, - }, - { - onSuccess: cookieSetter(headers), - }, - ); - const request = new Request("https://example.com/api/auth/session", { - headers, - }); - const cache = await getCookieCache(request, { - secret: "better-auth.secret", - }); - expect(cache).not.toBeNull(); - expect(cache?.user?.id).toBeDefined(); - expect(typeof cache?.user?.id).toBe("string"); - }); - it("should correctly filter multiple user fields based on returned config", async () => { const { client, testUser, cookieSetter } = await getTestInstance({ secret: "better-auth.secret", @@ -573,6 +544,26 @@ describe("Cookie Cache Field Filtering", () => { expect(cache?.user?.adminFlags).toBeUndefined(); }); + it("should always include id in parseUserOutput", () => { + const options = { + user: { + additionalFields: { + id: { type: "string", returned: false }, + }, + }, + } as any; + const user = { + id: "custom-oauth-id-123", + email: "test@example.com", + emailVerified: true, + createdAt: new Date(), + updatedAt: new Date(), + name: "Test User", + }; + const result = parseUserOutput(options, user); + expect(result.id).toBe("custom-oauth-id-123"); + }); + it("should reduce cookie size when large fields are excluded", async () => { const largeString = "x".repeat(2000); const { client, testUser, cookieSetter } = await getTestInstance({ diff --git a/packages/better-auth/src/db/schema.ts b/packages/better-auth/src/db/schema.ts index 637472861f..e4793a2d93 100644 --- a/packages/better-auth/src/db/schema.ts +++ b/packages/better-auth/src/db/schema.ts @@ -112,9 +112,20 @@ export function parseInputData>( continue; } if (fields[key]!.validator?.input && data[key] !== undefined) { - parsedData[key] = fields[key]!.validator.input["~standard"].validate( + const result = fields[key]!.validator.input["~standard"].validate( data[key], ); + if (result instanceof Promise) { + throw new APIError("INTERNAL_SERVER_ERROR", { + message: "Async validation is not supported for additional fields", + }); + } + if ("issues" in result && result.issues) { + throw new APIError("BAD_REQUEST", { + message: result.issues[0]?.message || "Validation Error", + }); + } + parsedData[key] = result.value; continue; } if (fields[key]!.transform?.input && data[key] !== undefined) { @@ -180,12 +191,16 @@ export function mergeSchema( schema: S, newSchema?: | { - [K in keyof S]?: { - modelName?: string; - fields?: { - [P: string]: string; - }; - }; + [K in keyof S]?: + | { + modelName?: string | undefined; + fields?: + | { + [P: string]: string; + } + | undefined; + } + | undefined; } | undefined, ) { diff --git a/packages/better-auth/src/plugins/api-key/api-key.test.ts b/packages/better-auth/src/plugins/api-key/api-key.test.ts index 1b1a3928e7..09541d5a8f 100644 --- a/packages/better-auth/src/plugins/api-key/api-key.test.ts +++ b/packages/better-auth/src/plugins/api-key/api-key.test.ts @@ -1681,37 +1681,98 @@ describe("api-key", async () => { // Sessions from API keys // ========================================================================= - it("should get session from an API key", async () => { - const { client, auth, signInWithTestUser } = await getTestInstance( - { - plugins: [ - apiKey({ - enableSessionForAPIKeys: true, - }), - ], - }, - { - clientOptions: { - plugins: [apiKeyClient()], + describe("enableSessionForAPIKeys", () => { + it("should get session from an API key", async () => { + const { client, auth, signInWithTestUser } = await getTestInstance( + { + plugins: [ + apiKey({ + enableSessionForAPIKeys: true, + }), + ], }, - }, - ); + { + clientOptions: { + plugins: [apiKeyClient()], + }, + }, + ); - const { headers: userHeaders } = await signInWithTestUser(); + const { headers: userHeaders } = await signInWithTestUser(); - const { data: apiKey2 } = await client.apiKey.create( - {}, - { headers: userHeaders }, - ); - if (!apiKey2) return; - const headers = new Headers(); - headers.set("x-api-key", apiKey2.key); + const { data: apiKey2 } = await client.apiKey.create( + {}, + { headers: userHeaders }, + ); + if (!apiKey2) return; + const headers = new Headers(); + headers.set("x-api-key", apiKey2.key); - const session = await auth.api.getSession({ - headers: headers, + const session = await auth.api.getSession({ + headers: headers, + }); + + expect(session?.session).toBeDefined(); }); - expect(session?.session).toBeDefined(); + it("should not get session from an API key if enableSessionForAPIKeys is false", async () => { + const { client, auth, signInWithTestUser } = await getTestInstance( + { + plugins: [ + apiKey({ + enableSessionForAPIKeys: false, + }), + ], + }, + { + clientOptions: { + plugins: [apiKeyClient()], + }, + }, + ); + const { headers: userHeaders } = await signInWithTestUser(); + const { data: apiKey2 } = await client.apiKey.create( + {}, + { headers: userHeaders }, + ); + if (!apiKey2) return; + const headers = new Headers(); + headers.set("x-api-key", apiKey2.key); + const session = await auth.api.getSession({ + headers: headers, + }); + expect(session).toBeNull(); + }); + + it("should get the Response object when asResponse is true", async () => { + const { client, auth, signInWithTestUser } = await getTestInstance( + { + plugins: [ + apiKey({ + enableSessionForAPIKeys: true, + }), + ], + }, + { + clientOptions: { + plugins: [apiKeyClient()], + }, + }, + ); + const { headers: userHeaders } = await signInWithTestUser(); + const { data: apiKey2 } = await client.apiKey.create( + {}, + { headers: userHeaders }, + ); + if (!apiKey2) return; + const headers = new Headers(); + headers.set("x-api-key", apiKey2.key); + const res = await auth.api.getSession({ + headers: headers, + asResponse: true, + }); + expect(res).toBeInstanceOf(Response); + }); }); // ========================================================================= diff --git a/packages/better-auth/src/plugins/jwt/sign.ts b/packages/better-auth/src/plugins/jwt/sign.ts index ab0b19b57d..8731488e0a 100644 --- a/packages/better-auth/src/plugins/jwt/sign.ts +++ b/packages/better-auth/src/plugins/jwt/sign.ts @@ -7,18 +7,73 @@ import { getJwksAdapter } from "./adapter"; import type { JwtOptions } from "./types"; import { createJwk, toExpJWT } from "./utils"; +type JWTPayloadWithOptional = { + /** + * JWT Issuer + * + * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.1 RFC7519#section-4.1.1} + */ + iss?: string | undefined; + + /** + * JWT Subject + * + * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.2 RFC7519#section-4.1.2} + */ + sub?: string | undefined; + + /** + * JWT Audience + * + * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3 RFC7519#section-4.1.3} + */ + aud?: string | string[] | undefined; + + /** + * JWT ID + * + * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.7 RFC7519#section-4.1.7} + */ + jti?: string | undefined; + + /** + * JWT Not Before + * + * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.5 RFC7519#section-4.1.5} + */ + nbf?: number | undefined; + + /** + * JWT Expiration Time + * + * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4 RFC7519#section-4.1.4} + */ + exp?: number | undefined; + + /** + * JWT Issued At + * + * @see {@link https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 RFC7519#section-4.1.6} + */ + iat?: number | undefined; + + /** Any other JWT Claim Set member. */ + [propName: string]: unknown | undefined; +}; + export async function signJWT( ctx: GenericEndpointContext, config: { options?: JwtOptions | undefined; - payload: JWTPayload; + payload: JWTPayloadWithOptional; }, ) { - const { options, payload } = config; + const { options } = config; + const payload = config.payload as JWTPayload; // Iat const nowSeconds = Math.floor(Date.now() / 1000); - const iat = payload.iat; + const iat = payload.iat!; // Exp let exp = payload.exp; @@ -29,7 +84,7 @@ export async function signJWT( exp = exp ?? defaultExp; // Nbf - const nbf = payload.nbf; + const nbf = payload.nbf!; // Iss const iss = payload.iss; @@ -94,7 +149,7 @@ export async function getJwtToken( ) { const payload = !options?.jwt?.definePayload ? ctx.context.session!.user - : await options?.jwt.definePayload(ctx.context.session!); + : await options.jwt.definePayload(ctx.context.session!); return await signJWT(ctx, { options, diff --git a/packages/better-auth/src/plugins/jwt/types.ts b/packages/better-auth/src/plugins/jwt/types.ts index 895938dbcf..662c29bbe2 100644 --- a/packages/better-auth/src/plugins/jwt/types.ts +++ b/packages/better-auth/src/plugins/jwt/types.ts @@ -13,7 +13,7 @@ export interface JwtOptions { * Useful if jwks are not managed at /jwks or * if your jwks are signed with a certificate and placed on your CDN. */ - remoteUrl?: string; + remoteUrl?: string | undefined; /** * Key pair configuration * @description A subset of the options available for the generateKeyPair function @@ -22,26 +22,26 @@ export interface JwtOptions { * * @default { alg: 'EdDSA', crv: 'Ed25519' } */ - keyPairConfig?: JWKOptions; + keyPairConfig?: JWKOptions | undefined; /** * Disable private key encryption * @description Disable the encryption of the private key in the database * * @default false */ - disablePrivateKeyEncryption?: boolean; + disablePrivateKeyEncryption?: boolean | undefined; /** * The key rotation interval in seconds. * * @default undefined (disabled) */ - rotationInterval?: number; + rotationInterval?: number | undefined; /** * The grace period in seconds. * * @default 2592000 (30 days) */ - gracePeriod?: number; + gracePeriod?: number | undefined; /** * The path of the endpoint exposing the JWKS. * When set, this replaces the default /jwks endpoint. @@ -50,7 +50,7 @@ export interface JwtOptions { * @default /jwks * @example "/.well-known/jwks.json" */ - jwksPath?: string; + jwksPath?: string | undefined; } | undefined; @@ -59,11 +59,11 @@ export interface JwtOptions { /** * The issuer of the JWT */ - issuer?: string; + issuer?: string | undefined; /** * The audience of the JWT */ - audience?: string; + audience?: string | undefined; /** * Set the "exp" (Expiration Time) Claim. * @@ -87,14 +87,14 @@ export interface JwtOptions { * * @default 15m */ - expirationTime?: number | string | Date; + expirationTime?: number | string | Date | undefined; /** * A function that is called to define the payload of the JWT */ definePayload?: (session: { user: User & Record; session: Session & Record; - }) => Promise> | Record; + }) => Promise> | Record | undefined; /** * A function that is called to get the subject of the JWT * @@ -103,7 +103,7 @@ export interface JwtOptions { getSubject?: (session: { user: User & Record; session: Session & Record; - }) => Promise | string; + }) => Promise | string | undefined; /** * A custom function to remote sign the jwt payload. * @@ -114,7 +114,7 @@ export interface JwtOptions { * @requires jwks.remoteUrl * @invalidates other jwt.* options */ - sign?: (payload: JWTPayload) => Awaitable; + sign?: ((payload: JWTPayload) => Awaitable) | undefined; } | undefined; diff --git a/packages/better-auth/src/plugins/oidc-provider/authorize.ts b/packages/better-auth/src/plugins/oidc-provider/authorize.ts index 7c8fae2ef5..a6b45373f0 100644 --- a/packages/better-auth/src/plugins/oidc-provider/authorize.ts +++ b/packages/better-auth/src/plugins/oidc-provider/authorize.ts @@ -148,7 +148,9 @@ export async function authorize( } const requestScope = - query.scope?.split(" ").filter((s) => s) || opts.defaultScope.split(" "); + query.scope?.split(" ").filter((s) => s) || + opts.defaultScope?.split(" ") || + []; const invalidScopes = requestScope.filter((scope) => { return !opts.scopes.includes(scope); }); @@ -191,7 +193,7 @@ export async function authorize( } const code = generateRandomString(32, "a-z", "A-Z", "0-9"); - const codeExpiresInMs = opts.codeExpiresIn * 1000; + const codeExpiresInMs = opts.codeExpiresIn! * 1000; const expiresAt = new Date(Date.now() + codeExpiresInMs); // Determine if consent is required diff --git a/packages/better-auth/src/plugins/oidc-provider/index.ts b/packages/better-auth/src/plugins/oidc-provider/index.ts index 20a9ff929a..b789d9e45e 100644 --- a/packages/better-auth/src/plugins/oidc-provider/index.ts +++ b/packages/better-auth/src/plugins/oidc-provider/index.ts @@ -9,6 +9,7 @@ import { import { getCurrentAuthContext } from "@better-auth/core/context"; import { base64 } from "@better-auth/utils/base64"; import { createHash } from "@better-auth/utils/hash"; +import type { OpenAPIParameter } from "better-call"; import { jwtVerify, SignJWT } from "jose"; import * as z from "zod"; import { APIError, getSessionFromCtx, sessionMiddleware } from "../../api"; @@ -132,6 +133,10 @@ export const getMetadata = ( }; }; +const DEFAULT_CODE_EXPIRES_IN = 600; +const DEFAULT_ACCESS_TOKEN_EXPIRES_IN = 3600; +const DEFAULT_REFRESH_TOKEN_EXPIRES_IN = 604800; + /** * OpenID Connect (OIDC) plugin for Better Auth. This plugin implements the * authorization code flow and the token exchange flow. It also implements the @@ -148,10 +153,10 @@ export const oidcProvider = (options: OIDCOptions) => { }; const opts = { - codeExpiresIn: 600, + codeExpiresIn: DEFAULT_CODE_EXPIRES_IN, defaultScope: "openid", - accessTokenExpiresIn: 3600, - refreshTokenExpiresIn: 604800, + accessTokenExpiresIn: DEFAULT_ACCESS_TOKEN_EXPIRES_IN, + refreshTokenExpiresIn: DEFAULT_REFRESH_TOKEN_EXPIRES_IN, allowPlainCodeChallengeMethod: true, storeClientSecret: "plain" as const, ...options, @@ -464,7 +469,8 @@ export const oidcProvider = (options: OIDCOptions) => { }); } const code = generateRandomString(32, "a-z", "A-Z", "0-9"); - const codeExpiresInMs = opts.codeExpiresIn * 1000; + const codeExpiresInMs = + (opts?.codeExpiresIn ?? DEFAULT_CODE_EXPIRES_IN) * 1000; const expiresAt = new Date(Date.now() + codeExpiresInMs); await ctx.context.internalAdapter.updateVerificationValue( verification.id, @@ -848,7 +854,8 @@ export const oidcProvider = (options: OIDCOptions) => { ...additionalUserClaims, }; const expirationTime = - Math.floor(Date.now() / 1000) + opts.accessTokenExpiresIn; + Math.floor(Date.now() / 1000) + + (opts?.accessTokenExpiresIn ?? DEFAULT_ACCESS_TOKEN_EXPIRES_IN); let idToken: string; @@ -1519,7 +1526,6 @@ export const oidcProvider = (options: OIDCOptions) => { "/oauth2/endsession", { method: ["GET", "POST"], - operationId: "oauth2EndSession", query: z .object({ id_token_hint: z.string().optional(), @@ -1584,7 +1590,7 @@ export const oidcProvider = (options: OIDCOptions) => { required: false, schema: { type: "string" }, }, - ], + ] as OpenAPIParameter[], responses: { "302": { description: diff --git a/packages/better-auth/src/plugins/oidc-provider/types.ts b/packages/better-auth/src/plugins/oidc-provider/types.ts index 51c675c037..6faefa693c 100644 --- a/packages/better-auth/src/plugins/oidc-provider/types.ts +++ b/packages/better-auth/src/plugins/oidc-provider/types.ts @@ -77,7 +77,7 @@ export interface OIDCOptions { | ((props: { clientId: string; clientName: string; - clientIcon?: string; + clientIcon?: string | undefined; clientMetadata: Record | null; code: string; scopes: string[]; diff --git a/packages/better-auth/src/utils/index.ts b/packages/better-auth/src/utils/index.ts index d479225ede..2c9b571e3d 100644 --- a/packages/better-auth/src/utils/index.ts +++ b/packages/better-auth/src/utils/index.ts @@ -1,4 +1,3 @@ export { generateId } from "@better-auth/core/utils"; export * from "../oauth2/state"; export * from "./hide-metadata"; -export * from "./misc"; diff --git a/packages/cli/package.json b/packages/cli/package.json index 6567b90723..1adb554e67 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -51,13 +51,14 @@ "@babel/core": "^7.28.4", "@babel/preset-react": "^7.27.1", "@babel/preset-typescript": "^7.27.1", + "@better-auth/core": "workspace:*", + "@better-auth/telemetry": "workspace:*", "@better-auth/utils": "0.3.0", "@clack/prompts": "^0.11.0", "@mrleebo/prisma-ast": "^0.13.0", "@prisma/client": "^5.22.0", "@types/pg": "^8.15.5", - "better-auth": "workspace:*", - "@better-auth/core": "workspace:*", + "better-auth": "workspace:^", "better-sqlite3": "^12.2.0", "c12": "^3.2.0", "chalk": "^5.6.2", @@ -67,7 +68,6 @@ "open": "^10.2.0", "pg": "^8.16.3", "prettier": "^3.6.2", - "prisma": "^5.22.0", "prompts": "^2.4.2", "semver": "^7.7.2", "yocto-spinner": "^0.2.3", diff --git a/packages/cli/src/commands/generate.ts b/packages/cli/src/commands/generate.ts index f9c62d2f78..f8e5f61d48 100644 --- a/packages/cli/src/commands/generate.ts +++ b/packages/cli/src/commands/generate.ts @@ -1,7 +1,10 @@ import { existsSync } from "node:fs"; import fs from "node:fs/promises"; import path from "node:path"; -import { createTelemetry, getTelemetryAuthConfig, logger } from "better-auth"; +import { + createTelemetry, + getTelemetryAuthConfig, +} from "@better-auth/telemetry"; import { getAdapter } from "better-auth/db"; import chalk from "chalk"; import { Command } from "commander"; @@ -24,7 +27,7 @@ export async function generateAction(opts: any) { const cwd = path.resolve(options.cwd); if (!existsSync(cwd)) { - logger.error(`The directory "${cwd}" does not exist.`); + console.error(`The directory "${cwd}" does not exist.`); process.exit(1); } const config = await getConfig({ @@ -32,14 +35,14 @@ export async function generateAction(opts: any) { configPath: options.config, }); if (!config) { - logger.error( + console.error( "No configuration file found. Add a `auth.ts` file to your project or pass the path to the configuration file using the `--config` flag.", ); return; } const adapter = await getAdapter(config).catch((e) => { - logger.error(e.message); + console.error(e.message); process.exit(1); }); @@ -53,7 +56,7 @@ export async function generateAction(opts: any) { spinner.stop(); if (!schema.code) { - logger.info("Your schema is already up to date."); + console.log("Your schema is already up to date."); // telemetry: track generate attempted, no changes try { const telemetry = await createTelemetry(config); @@ -98,7 +101,7 @@ export async function generateAction(opts: any) { } else { await fs.appendFile(path.join(cwd, schema.fileName), schema.code); } - logger.success( + console.log( `🚀 Schema was ${ schema.overwrite ? "overwritten" : "appended" } successfully!`, @@ -116,7 +119,7 @@ export async function generateAction(opts: any) { } catch {} process.exit(0); } else { - logger.error("Schema generation aborted."); + console.error("Schema generation aborted."); // telemetry: track generate aborted try { const telemetry = await createTelemetry(config); @@ -151,7 +154,7 @@ export async function generateAction(opts: any) { } if (!confirm) { - logger.error("Schema generation aborted."); + console.error("Schema generation aborted."); // telemetry: track generate aborted before write try { const telemetry = await createTelemetry(config); @@ -175,7 +178,7 @@ export async function generateAction(opts: any) { options.output || path.join(cwd, schema.fileName), schema.code, ); - logger.success(`🚀 Schema was generated successfully!`); + console.log(`🚀 Schema was generated successfully!`); // telemetry: track generate success try { const telemetry = await createTelemetry(config); diff --git a/packages/cli/src/commands/login.ts b/packages/cli/src/commands/login.ts index d06d20357a..3796531a1a 100644 --- a/packages/cli/src/commands/login.ts +++ b/packages/cli/src/commands/login.ts @@ -2,7 +2,6 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { cancel, confirm, intro, isCancel, outro } from "@clack/prompts"; -import { logger } from "better-auth"; import { createAuthClient } from "better-auth/client"; import { deviceAuthorizationClient } from "better-auth/client/plugins"; import chalk from "chalk"; @@ -73,7 +72,7 @@ export async function loginAction(opts: any) { spinner.stop(); if (error || !data) { - logger.error( + console.error( `Failed to request device authorization: ${error?.error_description || "Unknown error"}`, ); process.exit(1); @@ -154,7 +153,7 @@ export async function loginAction(opts: any) { } } catch (err) { spinner.stop(); - logger.error( + console.error( `Login failed: ${err instanceof Error ? err.message : "Unknown error"}`, ); process.exit(1); @@ -209,23 +208,23 @@ async function pollForToken( break; case "access_denied": spinner.stop(); - logger.error("Access was denied by the user"); + console.error("Access was denied by the user"); process.exit(1); break; case "expired_token": spinner.stop(); - logger.error("The device code has expired. Please try again."); + console.error("The device code has expired. Please try again."); process.exit(1); break; default: spinner.stop(); - logger.error(`Error: ${error.error_description}`); + console.error(`Error: ${error.error_description}`); process.exit(1); } } } catch (err) { spinner.stop(); - logger.error( + console.error( `Network error: ${err instanceof Error ? err.message : "Unknown error"}`, ); process.exit(1); @@ -254,7 +253,7 @@ async function storeToken(token: any): Promise { await fs.writeFile(TOKEN_FILE, JSON.stringify(tokenData, null, 2), "utf-8"); } catch (error) { - logger.warn("Failed to store authentication token locally"); + console.warn("Failed to store authentication token locally"); } } diff --git a/packages/cli/src/commands/migrate.ts b/packages/cli/src/commands/migrate.ts index a97b27c91e..4e82a37464 100644 --- a/packages/cli/src/commands/migrate.ts +++ b/packages/cli/src/commands/migrate.ts @@ -1,6 +1,9 @@ import { existsSync } from "node:fs"; import path from "node:path"; -import { createTelemetry, getTelemetryAuthConfig, logger } from "better-auth"; +import { + createTelemetry, + getTelemetryAuthConfig, +} from "@better-auth/telemetry"; import { getAdapter, getMigrations } from "better-auth/db"; import chalk from "chalk"; import { Command } from "commander"; @@ -21,7 +24,7 @@ export async function migrateAction(opts: any) { const cwd = path.resolve(options.cwd); if (!existsSync(cwd)) { - logger.error(`The directory "${cwd}" does not exist.`); + console.error(`The directory "${cwd}" does not exist.`); process.exit(1); } @@ -30,7 +33,7 @@ export async function migrateAction(opts: any) { configPath: options.config, }); if (!config) { - logger.error( + console.error( "No configuration file found. Add a `auth.ts` file to your project or pass the path to the configuration file using the `--config` flag.", ); return; @@ -39,7 +42,7 @@ export async function migrateAction(opts: any) { const db = await getAdapter(config); if (!db) { - logger.error( + console.error( "Invalid database configuration. Make sure you're not using adapters. Migrate command only works with built-in Kysely adapter.", ); process.exit(1); @@ -47,8 +50,8 @@ export async function migrateAction(opts: any) { if (db.id !== "kysely") { if (db.id === "prisma") { - logger.error( - "The migrate command only works with the built-in Kysely adapter. For Prisma, run `npx @better-auth/cli generate` to create the schema, then use Prisma’s migrate or push to apply it.", + console.error( + "The migrate command only works with the built-in Kysely adapter. For Prisma, run `npx @better-auth/cli generate` to create the schema, then use Prisma's migrate or push to apply it.", ); try { const telemetry = await createTelemetry(config); @@ -64,8 +67,8 @@ export async function migrateAction(opts: any) { process.exit(0); } if (db.id === "drizzle") { - logger.error( - "The migrate command only works with the built-in Kysely adapter. For Drizzle, run `npx @better-auth/cli generate` to create the schema, then use Drizzle’s migrate or push to apply it.", + console.error( + "The migrate command only works with the built-in Kysely adapter. For Drizzle, run `npx @better-auth/cli generate` to create the schema, then use Drizzle's migrate or push to apply it.", ); try { const telemetry = await createTelemetry(config); @@ -80,7 +83,7 @@ export async function migrateAction(opts: any) { } catch {} process.exit(0); } - logger.error("Migrate command isn't supported for this adapter."); + console.error("Migrate command isn't supported for this adapter."); try { const telemetry = await createTelemetry(config); await telemetry.publish({ @@ -101,7 +104,7 @@ export async function migrateAction(opts: any) { if (!toBeAdded.length && !toBeCreated.length) { spinner.stop(); - logger.info("🚀 No migrations needed."); + console.log("🚀 No migrations needed."); try { const telemetry = await createTelemetry(config); await telemetry.publish({ @@ -116,7 +119,7 @@ export async function migrateAction(opts: any) { } spinner.stop(); - logger.info(`🔑 The migration will affect the following:`); + console.log(`🔑 The migration will affect the following:`); for (const table of [...toBeCreated, ...toBeAdded]) { console.log( @@ -145,7 +148,7 @@ export async function migrateAction(opts: any) { } if (!migrate) { - logger.info("Migration cancelled."); + console.log("Migration cancelled."); try { const telemetry = await createTelemetry(config); await telemetry.publish({ @@ -159,7 +162,7 @@ export async function migrateAction(opts: any) { spinner?.start("migrating..."); await runMigrations(); spinner.stop(); - logger.info("🚀 migration was completed successfully!"); + console.log("🚀 migration was completed successfully!"); try { const telemetry = await createTelemetry(config); await telemetry.publish({ diff --git a/packages/cli/src/commands/secret.ts b/packages/cli/src/commands/secret.ts index e43bee93d3..103d8c7c06 100644 --- a/packages/cli/src/commands/secret.ts +++ b/packages/cli/src/commands/secret.ts @@ -1,11 +1,10 @@ import Crypto from "node:crypto"; -import { logger } from "better-auth"; import chalk from "chalk"; import { Command } from "commander"; export const generateSecret = new Command("secret").action(() => { const secret = generateSecretHash(); - logger.info(`\nAdd the following to your .env file: + console.log(`\nAdd the following to your .env file: ${ chalk.gray("# Auth Secret") + chalk.green(`\nBETTER_AUTH_SECRET=${secret}`) }`); diff --git a/packages/cli/src/generators/auth-config.ts b/packages/cli/src/generators/auth-config.ts index de850802ed..757fd792fb 100644 --- a/packages/cli/src/generators/auth-config.ts +++ b/packages/cli/src/generators/auth-config.ts @@ -1,5 +1,4 @@ import type { spinner as clackSpinner } from "@clack/prompts"; -import { logger } from "better-auth"; import type { SupportedDatabases, SupportedPlugin } from "../commands/init"; export type Import = { @@ -545,7 +544,7 @@ export async function generateAuthConfig({ `Something went wrong while generating/updating your new auth config file.`, 1, ); - logger.error(error.message); + console.error(error.message); process.exit(1); } } @@ -566,7 +565,7 @@ export async function generateAuthConfig({ `Something went wrong while generating/updating your new auth config file.`, 1, ); - logger.error(error.message); + console.error(error.message); process.exit(1); } } diff --git a/packages/cli/src/generators/index.ts b/packages/cli/src/generators/index.ts index a019872bbf..9d20bfd34e 100644 --- a/packages/cli/src/generators/index.ts +++ b/packages/cli/src/generators/index.ts @@ -1,6 +1,5 @@ +import type { BetterAuthOptions } from "@better-auth/core"; import type { DBAdapter } from "@better-auth/core/db/adapter"; -import type { BetterAuthOptions } from "better-auth"; -import { logger } from "better-auth"; import { generateDrizzleSchema } from "./drizzle"; import { generateMigrations } from "./kysely"; import { generatePrismaSchema } from "./prisma"; @@ -36,7 +35,7 @@ export const generateSchema = (opts: { })); } - logger.error( + console.error( `${adapter.id} is not supported. If it is a custom adapter, please request the maintainer to implement createSchema`, ); process.exit(1); diff --git a/packages/cli/src/generators/prisma.ts b/packages/cli/src/generators/prisma.ts index 21b343cf8f..a57c60d47f 100644 --- a/packages/cli/src/generators/prisma.ts +++ b/packages/cli/src/generators/prisma.ts @@ -1,8 +1,8 @@ import { existsSync } from "node:fs"; import fs from "node:fs/promises"; import path from "node:path"; +import { capitalizeFirstLetter } from "@better-auth/core/utils"; import { produceSchema } from "@mrleebo/prisma-ast"; -import { capitalizeFirstLetter } from "better-auth"; import { initGetFieldName, initGetModelName } from "better-auth/adapters"; import type { FieldType } from "better-auth/db"; import { getAuthTables } from "better-auth/db"; diff --git a/packages/cli/src/generators/types.ts b/packages/cli/src/generators/types.ts index f762b99a80..5bf0d3cd09 100644 --- a/packages/cli/src/generators/types.ts +++ b/packages/cli/src/generators/types.ts @@ -1,4 +1,5 @@ -import type { BetterAuthOptions, DBAdapter } from "better-auth"; +import type { BetterAuthOptions } from "@better-auth/core"; +import type { DBAdapter } from "@better-auth/core/db/adapter"; export interface SchemaGenerator { (opts: { diff --git a/packages/cli/src/utils/get-config.ts b/packages/cli/src/utils/get-config.ts index 4f4558cd32..73cb2e2474 100644 --- a/packages/cli/src/utils/get-config.ts +++ b/packages/cli/src/utils/get-config.ts @@ -4,8 +4,8 @@ import path from "node:path"; import babelPresetReact from "@babel/preset-react"; // @ts-expect-error import babelPresetTypeScript from "@babel/preset-typescript"; -import type { BetterAuthOptions } from "better-auth"; -import { BetterAuthError, logger } from "better-auth"; +import type { BetterAuthOptions } from "@better-auth/core"; +import { BetterAuthError } from "@better-auth/core/error"; import { loadConfig } from "c12"; import type { JitiOptions } from "jiti"; import { addCloudflareModules } from "./add-cloudflare-modules"; @@ -76,7 +76,7 @@ function getPathAliasesRecursive( visited.add(tsconfigPath); if (!fs.existsSync(tsconfigPath)) { - logger.warn(`Referenced tsconfig not found: ${tsconfigPath}`); + console.warn(`Referenced tsconfig not found: ${tsconfigPath}`); return {}; } @@ -114,7 +114,7 @@ function getPathAliasesRecursive( return result; } catch (error) { - logger.warn(`Error parsing tsconfig at ${tsconfigPath}: ${error}`); + console.warn(`Error parsing tsconfig at ${tsconfigPath}: ${error}`); return {}; } } @@ -204,7 +204,7 @@ export async function getConfig({ `Couldn't read your auth config in ${resolvedPath}. Make sure to default export your auth instance or to export as a variable named auth.`, ); } - logger.error( + console.error( `[#better-auth]: Couldn't read your auth config in ${resolvedPath}. Make sure to default export your auth instance or to export as a variable named auth.`, ); process.exit(1); @@ -236,9 +236,9 @@ export async function getConfig({ "Couldn't read your auth config. Make sure to default export your auth instance or to export as a variable named auth.", ); } - logger.error("[#better-auth]: Couldn't read your auth config."); + console.error("[#better-auth]: Couldn't read your auth config."); console.log(""); - logger.info( + console.log( "[#better-auth]: Make sure to default export your auth instance or to export as a variable named auth.", ); process.exit(1); @@ -260,7 +260,7 @@ export async function getConfig({ `Please remove import 'server-only' from your auth config file temporarily. The CLI cannot resolve the configuration with it included. You can re-add it after running the CLI.`, ); } - logger.error( + console.error( `Please remove import 'server-only' from your auth config file temporarily. The CLI cannot resolve the configuration with it included. You can re-add it after running the CLI.`, ); process.exit(1); @@ -268,7 +268,7 @@ export async function getConfig({ if (shouldThrowOnError) { throw e; } - logger.error("[#better-auth]: Couldn't read your auth config.", e); + console.error("[#better-auth]: Couldn't read your auth config.", e); process.exit(1); } } @@ -289,7 +289,7 @@ export async function getConfig({ `Please remove import 'server-only' from your auth config file temporarily. The CLI cannot resolve the configuration with it included. You can re-add it after running the CLI.`, ); } - logger.error( + console.error( `Please remove import 'server-only' from your auth config file temporarily. The CLI cannot resolve the configuration with it included. You can re-add it after running the CLI.`, ); process.exit(1); @@ -298,7 +298,7 @@ export async function getConfig({ throw e; } - logger.error("Couldn't read your auth config.", e); + console.error("Couldn't read your auth config.", e); process.exit(1); } } diff --git a/packages/cli/test/generate-all-db.test.ts b/packages/cli/test/generate-all-db.test.ts index b3078d995d..b47a5c39ee 100644 --- a/packages/cli/test/generate-all-db.test.ts +++ b/packages/cli/test/generate-all-db.test.ts @@ -1,5 +1,5 @@ +import type { BetterAuthOptions } from "@better-auth/core"; import { passkey } from "@better-auth/passkey"; -import type { BetterAuthOptions } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { twoFactor, username } from "better-auth/plugins"; import { describe, expect, it } from "vitest"; diff --git a/packages/cli/test/generate.test.ts b/packages/cli/test/generate.test.ts index 60a27b1bba..bf9a4a5afa 100644 --- a/packages/cli/test/generate.test.ts +++ b/packages/cli/test/generate.test.ts @@ -1,7 +1,7 @@ import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; -import type { BetterAuthOptions } from "better-auth"; +import type { BetterAuthOptions } from "@better-auth/core"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { prismaAdapter } from "better-auth/adapters/prisma"; import { organization, twoFactor, username } from "better-auth/plugins"; diff --git a/packages/cli/test/migrate.test.ts b/packages/cli/test/migrate.test.ts index 6988d5120a..f05f382da0 100644 --- a/packages/cli/test/migrate.test.ts +++ b/packages/cli/test/migrate.test.ts @@ -1,4 +1,4 @@ -import type { BetterAuthPlugin } from "better-auth"; +import type { BetterAuthPlugin } from "@better-auth/core"; import { betterAuth } from "better-auth"; import Database from "better-sqlite3"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; diff --git a/packages/core/src/async_hooks/index.ts b/packages/core/src/async_hooks/index.ts index 54e4b49c16..f6bbb7caac 100644 --- a/packages/core/src/async_hooks/index.ts +++ b/packages/core/src/async_hooks/index.ts @@ -6,30 +6,39 @@ import type { AsyncLocalStorage } from "node:async_hooks"; // We only export the type here to avoid issues in environments where AsyncLocalStorage is not available. export type { AsyncLocalStorage }; -const AsyncLocalStoragePromise: Promise = import( - /* @vite-ignore */ - /* webpackIgnore: true */ - "node:async_hooks" -) - .then((mod) => mod.AsyncLocalStorage) - .catch((err) => { - if ("AsyncLocalStorage" in globalThis) { - return (globalThis as any).AsyncLocalStorage; - } - console.warn( - "[better-auth] Warning: AsyncLocalStorage is not available in this environment. Some features may not work as expected.", - ); - console.warn( - "[better-auth] Please read more about this warning at https://better-auth.com/docs/installation#mount-handler", - ); - console.warn( - "[better-auth] If you are using Cloudflare Workers, please see: https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-compatibility-flag", - ); - throw err; - }); +const AsyncLocalStoragePromise: Promise = + import( + /* @vite-ignore */ + /* webpackIgnore: true */ + "node:async_hooks" + ) + .then((mod) => mod.AsyncLocalStorage) + .catch((err) => { + if ("AsyncLocalStorage" in globalThis) { + return (globalThis as any).AsyncLocalStorage; + } + if (typeof window !== "undefined") { + return null; + } + console.warn( + "[better-auth] Warning: AsyncLocalStorage is not available in this environment. Some features may not work as expected.", + ); + console.warn( + "[better-auth] Please read more about this warning at https://better-auth.com/docs/installation#mount-handler", + ); + console.warn( + "[better-auth] If you are using Cloudflare Workers, please see: https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-compatibility-flag", + ); + throw err; + }); export async function getAsyncLocalStorage(): Promise< typeof AsyncLocalStorage > { - return AsyncLocalStoragePromise; + const mod = await AsyncLocalStoragePromise; + if (mod === null) { + throw new Error("getAsyncLocalStorage is only available in server code"); + } else { + return mod; + } } diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index c3c9e97766..2e53a9582f 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -1,3 +1,4 @@ export { defineErrorCodes } from "./error-codes"; export { generateId } from "./id"; export { safeJSONParse } from "./json"; +export { capitalizeFirstLetter } from "./string"; diff --git a/packages/better-auth/src/utils/misc.ts b/packages/core/src/utils/string.ts similarity index 100% rename from packages/better-auth/src/utils/misc.ts rename to packages/core/src/utils/string.ts diff --git a/patches/msw.patch b/patches/msw.patch deleted file mode 100644 index 04497161e7..0000000000 --- a/patches/msw.patch +++ /dev/null @@ -1,85 +0,0 @@ -diff --git a/lib/core/utils/cookieStore.js b/lib/core/utils/cookieStore.js -index 5a0d429c9ae68555745aa2ebe0db3d1465636b1e..d2b39e96d13216626170ed9064f6e48d91abfeb3 100644 ---- a/lib/core/utils/cookieStore.js -+++ b/lib/core/utils/cookieStore.js -@@ -48,6 +48,9 @@ class CookieStore { - this.persist(); - } - getCookieStoreIndex() { -+ if ((0, import_is_node_process.isNodeProcess)()) { -+ return {}; -+ } - if (typeof localStorage === "undefined") { - return {}; - } -diff --git a/lib/core/utils/cookieStore.js.map b/lib/core/utils/cookieStore.js.map -index 41775029e081f898d74fe31e3c5216e9fe0bff18..08781bb89c50afe9a01f43d41bbb5e604ec1f5be 100644 ---- a/lib/core/utils/cookieStore.js.map -+++ b/lib/core/utils/cookieStore.js.map -@@ -1 +1 @@ --{"version":3,"sources":["../../../src/core/utils/cookieStore.ts"],"sourcesContent":["import { isNodeProcess } from 'is-node-process'\nimport { invariant } from 'outvariant'\nimport {\n Cookie,\n CookieJar,\n MemoryCookieStore,\n type MemoryCookieStoreIndex,\n} from 'tough-cookie'\nimport { jsonParse } from './internal/jsonParse'\n\nclass CookieStore {\n #storageKey = '__msw-cookie-store__'\n #jar: CookieJar\n #memoryStore: MemoryCookieStore\n\n constructor() {\n if (!isNodeProcess()) {\n invariant(\n typeof localStorage !== 'undefined',\n 'Failed to create a CookieStore: `localStorage` is not available in this environment. This is likely an issue with your environment, which has been detected as browser (or browser-like) environment and must implement global browser APIs correctly.',\n )\n }\n\n this.#memoryStore = new MemoryCookieStore()\n this.#memoryStore.idx = this.getCookieStoreIndex()\n this.#jar = new CookieJar(this.#memoryStore)\n }\n\n public getCookies(url: string): Array {\n return this.#jar.getCookiesSync(url)\n }\n\n public async setCookie(cookieName: string, url: string): Promise {\n await this.#jar.setCookie(cookieName, url)\n this.persist()\n }\n\n private getCookieStoreIndex(): MemoryCookieStoreIndex {\n if (typeof localStorage === 'undefined') {\n return {}\n }\n\n const cookiesString = localStorage.getItem(this.#storageKey)\n if (cookiesString == null) {\n return {}\n }\n\n const rawCookies = jsonParse>>(cookiesString)\n if (rawCookies == null) {\n return {}\n }\n\n const cookies: MemoryCookieStoreIndex = {}\n\n for (const rawCookie of rawCookies) {\n const cookie = Cookie.fromJSON(rawCookie)\n\n if (cookie != null && cookie.domain != null && cookie.path != null) {\n cookies[cookie.domain] ||= {}\n cookies[cookie.domain][cookie.path] ||= {}\n cookies[cookie.domain][cookie.path][cookie.key] = cookie\n }\n }\n\n return cookies\n }\n\n private persist(): void {\n if (typeof localStorage === 'undefined') {\n return\n }\n\n const data = []\n const { idx } = this.#memoryStore\n\n for (const domain in idx) {\n for (const path in idx[domain]) {\n for (const key in idx[domain][path]) {\n data.push(idx[domain][path][key].toJSON())\n }\n }\n }\n\n localStorage.setItem(this.#storageKey, JSON.stringify(data))\n }\n}\n\nexport const cookieStore = new CookieStore()\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAA8B;AAC9B,wBAA0B;AAC1B,0BAKO;AACP,uBAA0B;AAE1B,MAAM,YAAY;AAAA,EAChB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EAEA,cAAc;AACZ,QAAI,KAAC,sCAAc,GAAG;AACpB;AAAA,QACE,OAAO,iBAAiB;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,eAAe,IAAI,sCAAkB;AAC1C,SAAK,aAAa,MAAM,KAAK,oBAAoB;AACjD,SAAK,OAAO,IAAI,8BAAU,KAAK,YAAY;AAAA,EAC7C;AAAA,EAEO,WAAW,KAA4B;AAC5C,WAAO,KAAK,KAAK,eAAe,GAAG;AAAA,EACrC;AAAA,EAEA,MAAa,UAAU,YAAoB,KAA4B;AACrE,UAAM,KAAK,KAAK,UAAU,YAAY,GAAG;AACzC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,sBAA8C;AACpD,QAAI,OAAO,iBAAiB,aAAa;AACvC,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,gBAAgB,aAAa,QAAQ,KAAK,WAAW;AAC3D,QAAI,iBAAiB,MAAM;AACzB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,iBAAa,4BAA0C,aAAa;AAC1E,QAAI,cAAc,MAAM;AACtB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAAkC,CAAC;AAEzC,eAAW,aAAa,YAAY;AAClC,YAAM,SAAS,2BAAO,SAAS,SAAS;AAExC,UAAI,UAAU,QAAQ,OAAO,UAAU,QAAQ,OAAO,QAAQ,MAAM;AAClE,gBAAQ,OAAO,MAAM,MAAM,CAAC;AAC5B,gBAAQ,OAAO,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC;AACzC,gBAAQ,OAAO,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO,GAAG,IAAI;AAAA,MACpD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAgB;AACtB,QAAI,OAAO,iBAAiB,aAAa;AACvC;AAAA,IACF;AAEA,UAAM,OAAO,CAAC;AACd,UAAM,EAAE,IAAI,IAAI,KAAK;AAErB,eAAW,UAAU,KAAK;AACxB,iBAAW,QAAQ,IAAI,MAAM,GAAG;AAC9B,mBAAW,OAAO,IAAI,MAAM,EAAE,IAAI,GAAG;AACnC,eAAK,KAAK,IAAI,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAEA,iBAAa,QAAQ,KAAK,aAAa,KAAK,UAAU,IAAI,CAAC;AAAA,EAC7D;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","names":[]} -\ No newline at end of file -+{"version":3,"sources":["../../../src/core/utils/cookieStore.ts"],"sourcesContent":["import { isNodeProcess } from 'is-node-process'\nimport { invariant } from 'outvariant'\nimport {\n Cookie,\n CookieJar,\n MemoryCookieStore,\n type MemoryCookieStoreIndex,\n} from 'tough-cookie'\nimport { jsonParse } from './internal/jsonParse'\n\nclass CookieStore {\n #storageKey = '__msw-cookie-store__'\n #jar: CookieJar\n #memoryStore: MemoryCookieStore\n\n constructor() {\n if (!isNodeProcess()) {\n invariant(\n typeof localStorage !== 'undefined',\n 'Failed to create a CookieStore: `localStorage` is not available in this environment. This is likely an issue with your environment, which has been detected as browser (or browser-like) environment and must implement global browser APIs correctly.',\n )\n }\n\n this.#memoryStore = new MemoryCookieStore()\n this.#memoryStore.idx = this.getCookieStoreIndex()\n this.#jar = new CookieJar(this.#memoryStore)\n }\n\n public getCookies(url: string): Array {\n return this.#jar.getCookiesSync(url)\n }\n\n public async setCookie(cookieName: string, url: string): Promise {\n await this.#jar.setCookie(cookieName, url)\n this.persist()\n }\n\n private getCookieStoreIndex(): MemoryCookieStoreIndex {\n if (isNodeProcess()) {\n // In Node.js 25, localStorage is available but throws an error when accessed without argv.\n return {}\n }\n\n if (typeof localStorage === 'undefined') {\n return {}\n }\n\n const cookiesString = localStorage.getItem(this.#storageKey)\n if (cookiesString == null) {\n return {}\n }\n\n const rawCookies = jsonParse>>(cookiesString)\n if (rawCookies == null) {\n return {}\n }\n\n const cookies: MemoryCookieStoreIndex = {}\n\n for (const rawCookie of rawCookies) {\n const cookie = Cookie.fromJSON(rawCookie)\n\n if (cookie != null && cookie.domain != null && cookie.path != null) {\n cookies[cookie.domain] ||= {}\n cookies[cookie.domain][cookie.path] ||= {}\n cookies[cookie.domain][cookie.path][cookie.key] = cookie\n }\n }\n\n return cookies\n }\n\n private persist(): void {\n if (typeof localStorage === 'undefined') {\n return\n }\n\n const data = []\n const { idx } = this.#memoryStore\n\n for (const domain in idx) {\n for (const path in idx[domain]) {\n for (const key in idx[domain][path]) {\n data.push(idx[domain][path][key].toJSON())\n }\n }\n }\n\n localStorage.setItem(this.#storageKey, JSON.stringify(data))\n }\n}\n\nexport const cookieStore = new CookieStore()\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAA8B;AAC9B,wBAA0B;AAC1B,0BAKO;AACP,uBAA0B;AAE1B,MAAM,YAAY;AAAA,EAChB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EAEA,cAAc;AACZ,QAAI,KAAC,sCAAc,GAAG;AACpB;AAAA,QACE,OAAO,iBAAiB;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,eAAe,IAAI,sCAAkB;AAC1C,SAAK,aAAa,MAAM,KAAK,oBAAoB;AACjD,SAAK,OAAO,IAAI,8BAAU,KAAK,YAAY;AAAA,EAC7C;AAAA,EAEO,WAAW,KAA4B;AAC5C,WAAO,KAAK,KAAK,eAAe,GAAG;AAAA,EACrC;AAAA,EAEA,MAAa,UAAU,YAAoB,KAA4B;AACrE,UAAM,KAAK,KAAK,UAAU,YAAY,GAAG;AACzC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,sBAA8C;AACpD,YAAI,sCAAc,GAAG;AAEnB,aAAO,CAAC;AAAA,IACV;AAEA,QAAI,OAAO,iBAAiB,aAAa;AACvC,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,gBAAgB,aAAa,QAAQ,KAAK,WAAW;AAC3D,QAAI,iBAAiB,MAAM;AACzB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,iBAAa,4BAA0C,aAAa;AAC1E,QAAI,cAAc,MAAM;AACtB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAAkC,CAAC;AAEzC,eAAW,aAAa,YAAY;AAClC,YAAM,SAAS,2BAAO,SAAS,SAAS;AAExC,UAAI,UAAU,QAAQ,OAAO,UAAU,QAAQ,OAAO,QAAQ,MAAM;AAClE,gBAAQ,OAAO,MAAM,MAAM,CAAC;AAC5B,gBAAQ,OAAO,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC;AACzC,gBAAQ,OAAO,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO,GAAG,IAAI;AAAA,MACpD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAgB;AACtB,QAAI,OAAO,iBAAiB,aAAa;AACvC;AAAA,IACF;AAEA,UAAM,OAAO,CAAC;AACd,UAAM,EAAE,IAAI,IAAI,KAAK;AAErB,eAAW,UAAU,KAAK;AACxB,iBAAW,QAAQ,IAAI,MAAM,GAAG;AAC9B,mBAAW,OAAO,IAAI,MAAM,EAAE,IAAI,GAAG;AACnC,eAAK,KAAK,IAAI,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAEA,iBAAa,QAAQ,KAAK,aAAa,KAAK,UAAU,IAAI,CAAC;AAAA,EAC7D;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","names":[]} -\ No newline at end of file -diff --git a/lib/core/utils/cookieStore.mjs b/lib/core/utils/cookieStore.mjs -index 6eb83d156979cb69a373bbd543e744a8cb42c5d3..708a62c7ddc3749bd664bb237318cccbfec5e873 100644 ---- a/lib/core/utils/cookieStore.mjs -+++ b/lib/core/utils/cookieStore.mjs -@@ -29,6 +29,9 @@ class CookieStore { - this.persist(); - } - getCookieStoreIndex() { -+ if (isNodeProcess()) { -+ return {}; -+ } - if (typeof localStorage === "undefined") { - return {}; - } -diff --git a/lib/core/utils/cookieStore.mjs.map b/lib/core/utils/cookieStore.mjs.map -index e62cdfd43291f264956d212a09ebd0b37f3db30e..0fe4079184c134b74a1f3ece0c27a682a552dae6 100644 ---- a/lib/core/utils/cookieStore.mjs.map -+++ b/lib/core/utils/cookieStore.mjs.map -@@ -1 +1 @@ --{"version":3,"sources":["../../../src/core/utils/cookieStore.ts"],"sourcesContent":["import { isNodeProcess } from 'is-node-process'\nimport { invariant } from 'outvariant'\nimport {\n Cookie,\n CookieJar,\n MemoryCookieStore,\n type MemoryCookieStoreIndex,\n} from 'tough-cookie'\nimport { jsonParse } from './internal/jsonParse'\n\nclass CookieStore {\n #storageKey = '__msw-cookie-store__'\n #jar: CookieJar\n #memoryStore: MemoryCookieStore\n\n constructor() {\n if (!isNodeProcess()) {\n invariant(\n typeof localStorage !== 'undefined',\n 'Failed to create a CookieStore: `localStorage` is not available in this environment. This is likely an issue with your environment, which has been detected as browser (or browser-like) environment and must implement global browser APIs correctly.',\n )\n }\n\n this.#memoryStore = new MemoryCookieStore()\n this.#memoryStore.idx = this.getCookieStoreIndex()\n this.#jar = new CookieJar(this.#memoryStore)\n }\n\n public getCookies(url: string): Array {\n return this.#jar.getCookiesSync(url)\n }\n\n public async setCookie(cookieName: string, url: string): Promise {\n await this.#jar.setCookie(cookieName, url)\n this.persist()\n }\n\n private getCookieStoreIndex(): MemoryCookieStoreIndex {\n if (typeof localStorage === 'undefined') {\n return {}\n }\n\n const cookiesString = localStorage.getItem(this.#storageKey)\n if (cookiesString == null) {\n return {}\n }\n\n const rawCookies = jsonParse>>(cookiesString)\n if (rawCookies == null) {\n return {}\n }\n\n const cookies: MemoryCookieStoreIndex = {}\n\n for (const rawCookie of rawCookies) {\n const cookie = Cookie.fromJSON(rawCookie)\n\n if (cookie != null && cookie.domain != null && cookie.path != null) {\n cookies[cookie.domain] ||= {}\n cookies[cookie.domain][cookie.path] ||= {}\n cookies[cookie.domain][cookie.path][cookie.key] = cookie\n }\n }\n\n return cookies\n }\n\n private persist(): void {\n if (typeof localStorage === 'undefined') {\n return\n }\n\n const data = []\n const { idx } = this.#memoryStore\n\n for (const domain in idx) {\n for (const path in idx[domain]) {\n for (const key in idx[domain][path]) {\n data.push(idx[domain][path][key].toJSON())\n }\n }\n }\n\n localStorage.setItem(this.#storageKey, JSON.stringify(data))\n }\n}\n\nexport const cookieStore = new CookieStore()\n"],"mappings":"AAAA,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,iBAAiB;AAE1B,MAAM,YAAY;AAAA,EAChB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EAEA,cAAc;AACZ,QAAI,CAAC,cAAc,GAAG;AACpB;AAAA,QACE,OAAO,iBAAiB;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,eAAe,IAAI,kBAAkB;AAC1C,SAAK,aAAa,MAAM,KAAK,oBAAoB;AACjD,SAAK,OAAO,IAAI,UAAU,KAAK,YAAY;AAAA,EAC7C;AAAA,EAEO,WAAW,KAA4B;AAC5C,WAAO,KAAK,KAAK,eAAe,GAAG;AAAA,EACrC;AAAA,EAEA,MAAa,UAAU,YAAoB,KAA4B;AACrE,UAAM,KAAK,KAAK,UAAU,YAAY,GAAG;AACzC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,sBAA8C;AACpD,QAAI,OAAO,iBAAiB,aAAa;AACvC,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,gBAAgB,aAAa,QAAQ,KAAK,WAAW;AAC3D,QAAI,iBAAiB,MAAM;AACzB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,aAAa,UAA0C,aAAa;AAC1E,QAAI,cAAc,MAAM;AACtB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAAkC,CAAC;AAEzC,eAAW,aAAa,YAAY;AAClC,YAAM,SAAS,OAAO,SAAS,SAAS;AAExC,UAAI,UAAU,QAAQ,OAAO,UAAU,QAAQ,OAAO,QAAQ,MAAM;AAClE,gBAAQ,OAAO,MAAM,MAAM,CAAC;AAC5B,gBAAQ,OAAO,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC;AACzC,gBAAQ,OAAO,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO,GAAG,IAAI;AAAA,MACpD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAgB;AACtB,QAAI,OAAO,iBAAiB,aAAa;AACvC;AAAA,IACF;AAEA,UAAM,OAAO,CAAC;AACd,UAAM,EAAE,IAAI,IAAI,KAAK;AAErB,eAAW,UAAU,KAAK;AACxB,iBAAW,QAAQ,IAAI,MAAM,GAAG;AAC9B,mBAAW,OAAO,IAAI,MAAM,EAAE,IAAI,GAAG;AACnC,eAAK,KAAK,IAAI,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAEA,iBAAa,QAAQ,KAAK,aAAa,KAAK,UAAU,IAAI,CAAC;AAAA,EAC7D;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","names":[]} -\ No newline at end of file -+{"version":3,"sources":["../../../src/core/utils/cookieStore.ts"],"sourcesContent":["import { isNodeProcess } from 'is-node-process'\nimport { invariant } from 'outvariant'\nimport {\n Cookie,\n CookieJar,\n MemoryCookieStore,\n type MemoryCookieStoreIndex,\n} from 'tough-cookie'\nimport { jsonParse } from './internal/jsonParse'\n\nclass CookieStore {\n #storageKey = '__msw-cookie-store__'\n #jar: CookieJar\n #memoryStore: MemoryCookieStore\n\n constructor() {\n if (!isNodeProcess()) {\n invariant(\n typeof localStorage !== 'undefined',\n 'Failed to create a CookieStore: `localStorage` is not available in this environment. This is likely an issue with your environment, which has been detected as browser (or browser-like) environment and must implement global browser APIs correctly.',\n )\n }\n\n this.#memoryStore = new MemoryCookieStore()\n this.#memoryStore.idx = this.getCookieStoreIndex()\n this.#jar = new CookieJar(this.#memoryStore)\n }\n\n public getCookies(url: string): Array {\n return this.#jar.getCookiesSync(url)\n }\n\n public async setCookie(cookieName: string, url: string): Promise {\n await this.#jar.setCookie(cookieName, url)\n this.persist()\n }\n\n private getCookieStoreIndex(): MemoryCookieStoreIndex {\n if (isNodeProcess()) {\n // In Node.js 25, localStorage is available but throws an error when accessed without argv.\n return {}\n }\n\n if (typeof localStorage === 'undefined') {\n return {}\n }\n\n const cookiesString = localStorage.getItem(this.#storageKey)\n if (cookiesString == null) {\n return {}\n }\n\n const rawCookies = jsonParse>>(cookiesString)\n if (rawCookies == null) {\n return {}\n }\n\n const cookies: MemoryCookieStoreIndex = {}\n\n for (const rawCookie of rawCookies) {\n const cookie = Cookie.fromJSON(rawCookie)\n\n if (cookie != null && cookie.domain != null && cookie.path != null) {\n cookies[cookie.domain] ||= {}\n cookies[cookie.domain][cookie.path] ||= {}\n cookies[cookie.domain][cookie.path][cookie.key] = cookie\n }\n }\n\n return cookies\n }\n\n private persist(): void {\n if (typeof localStorage === 'undefined') {\n return\n }\n\n const data = []\n const { idx } = this.#memoryStore\n\n for (const domain in idx) {\n for (const path in idx[domain]) {\n for (const key in idx[domain][path]) {\n data.push(idx[domain][path][key].toJSON())\n }\n }\n }\n\n localStorage.setItem(this.#storageKey, JSON.stringify(data))\n }\n}\n\nexport const cookieStore = new CookieStore()\n"],"mappings":"AAAA,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,iBAAiB;AAE1B,MAAM,YAAY;AAAA,EAChB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EAEA,cAAc;AACZ,QAAI,CAAC,cAAc,GAAG;AACpB;AAAA,QACE,OAAO,iBAAiB;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,eAAe,IAAI,kBAAkB;AAC1C,SAAK,aAAa,MAAM,KAAK,oBAAoB;AACjD,SAAK,OAAO,IAAI,UAAU,KAAK,YAAY;AAAA,EAC7C;AAAA,EAEO,WAAW,KAA4B;AAC5C,WAAO,KAAK,KAAK,eAAe,GAAG;AAAA,EACrC;AAAA,EAEA,MAAa,UAAU,YAAoB,KAA4B;AACrE,UAAM,KAAK,KAAK,UAAU,YAAY,GAAG;AACzC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,sBAA8C;AACpD,QAAI,cAAc,GAAG;AAEnB,aAAO,CAAC;AAAA,IACV;AAEA,QAAI,OAAO,iBAAiB,aAAa;AACvC,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,gBAAgB,aAAa,QAAQ,KAAK,WAAW;AAC3D,QAAI,iBAAiB,MAAM;AACzB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,aAAa,UAA0C,aAAa;AAC1E,QAAI,cAAc,MAAM;AACtB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAAkC,CAAC;AAEzC,eAAW,aAAa,YAAY;AAClC,YAAM,SAAS,OAAO,SAAS,SAAS;AAExC,UAAI,UAAU,QAAQ,OAAO,UAAU,QAAQ,OAAO,QAAQ,MAAM;AAClE,gBAAQ,OAAO,MAAM,MAAM,CAAC;AAC5B,gBAAQ,OAAO,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC;AACzC,gBAAQ,OAAO,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO,GAAG,IAAI;AAAA,MACpD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAgB;AACtB,QAAI,OAAO,iBAAiB,aAAa;AACvC;AAAA,IACF;AAEA,UAAM,OAAO,CAAC;AACd,UAAM,EAAE,IAAI,IAAI,KAAK;AAErB,eAAW,UAAU,KAAK;AACxB,iBAAW,QAAQ,IAAI,MAAM,GAAG;AAC9B,mBAAW,OAAO,IAAI,MAAM,EAAE,IAAI,GAAG;AACnC,eAAK,KAAK,IAAI,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAEA,iBAAa,QAAQ,KAAK,aAAa,KAAK,UAAU,IAAI,CAAC;AAAA,EAC7D;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","names":[]} -\ No newline at end of file -diff --git a/lib/iife/index.js b/lib/iife/index.js -index c33a77221736478201b7d2aec9571f481de9c879..6b9305de50cf02c0bd040aaf1bc1a62fce422eb7 100644 ---- a/lib/iife/index.js -+++ b/lib/iife/index.js -@@ -17857,6 +17857,9 @@ ${operationTypes.join("\n")} - this.persist(); - } - getCookieStoreIndex() { -+ if (isNodeProcess()) { -+ return {}; -+ } - if (typeof localStorage === "undefined") { - return {}; - } -diff --git a/lib/iife/index.js.map b/lib/iife/index.js.map -index 3c84c9ec77601bd39efd40f9874f5b4df5230068..b47939231ccffe68608e397229aa50bbed38cb84 100644 ---- a/lib/iife/index.js.map -+++ b/lib/iife/index.js.map -@@ -1 +1 @@ --{"version":3,"sources":["../../node_modules/.pnpm/statuses@2.0.2/node_modules/statuses/codes.json","../../node_modules/.pnpm/statuses@2.0.2/node_modules/statuses/index.js","../../node_modules/.pnpm/cookie@1.0.2/node_modules/cookie/src/index.ts","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/version.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/devAssert.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/isPromise.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/isObjectLike.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/invariant.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/location.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/printLocation.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/error/GraphQLError.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/error/syntaxError.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/ast.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/directiveLocation.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/kinds.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/characterClasses.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/blockString.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/tokenKind.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/lexer.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/inspect.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/instanceOf.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/source.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/parser.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/didYouMean.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/identityFunc.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/keyMap.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/keyValMap.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/mapValue.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/naturalCompare.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/suggestionList.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/toObjMap.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/printString.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/visitor.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/printer.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/valueFromASTUntyped.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/type/assertName.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/type/definition.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/typeComparators.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/type/scalars.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/type/directives.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/isIterableObject.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/astFromValue.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/type/introspection.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/type/schema.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/type/validate.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/typeFromAST.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/TypeInfo.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/predicates.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/ExecutableDefinitionsRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/FieldsOnCorrectTypeRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/FragmentsOnCompositeTypesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/KnownArgumentNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/KnownDirectivesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/KnownFragmentNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/KnownTypeNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/LoneAnonymousOperationRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/LoneSchemaDefinitionRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/NoFragmentCyclesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/NoUndefinedVariablesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/NoUnusedFragmentsRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/NoUnusedVariablesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/sortValueNode.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/OverlappingFieldsCanBeMergedRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/PossibleFragmentSpreadsRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/PossibleTypeExtensionsRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/ProvidedRequiredArgumentsRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/ScalarLeafsRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/printPathArray.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/Path.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/coerceInputValue.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/valueFromAST.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/execution/values.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/execution/collectFields.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/SingleFieldSubscriptionsRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/groupBy.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueArgumentDefinitionNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueArgumentNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueDirectiveNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueDirectivesPerLocationRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueEnumValueNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueFieldDefinitionNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueFragmentNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueInputFieldNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueOperationNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueOperationTypesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueTypeNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/UniqueVariableNamesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/ValuesOfCorrectTypeRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/VariablesAreInputTypesRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/VariablesInAllowedPositionRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/specifiedRules.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/ValidationContext.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/validate.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/memoize3.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/promiseForObject.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/promiseReduce.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/toError.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/error/locatedError.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/execution/execute.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/graphql.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/type/index.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/language/index.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/jsutils/isAsyncIterable.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/execution/mapAsyncIterator.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/execution/subscribe.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/execution/index.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/custom/NoDeprecatedCustomRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/rules/custom/NoSchemaIntrospectionCustomRule.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/validation/index.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/error/index.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/getIntrospectionQuery.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/getOperationAST.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/getOperationRootType.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/introspectionFromSchema.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/buildClientSchema.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/extendSchema.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/buildASTSchema.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/lexicographicSortSchema.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/printSchema.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/concatAST.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/separateOperations.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/stripIgnoredCharacters.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/assertValidName.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/findBreakingChanges.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/utilities/index.mjs","../../node_modules/.pnpm/graphql@16.8.2/node_modules/graphql/index.mjs","../../src/iife/index.ts","../../node_modules/.pnpm/outvariant@1.4.3/node_modules/outvariant/src/format.ts","../../node_modules/.pnpm/outvariant@1.4.3/node_modules/outvariant/src/invariant.ts","../../src/core/utils/internal/devUtils.ts","../../src/core/utils/internal/checkGlobals.ts","../../node_modules/.pnpm/strict-event-emitter@0.5.1/node_modules/strict-event-emitter/src/MemoryLeakError.ts","../../node_modules/.pnpm/strict-event-emitter@0.5.1/node_modules/strict-event-emitter/src/Emitter.ts","../../src/core/utils/internal/pipeEvents.ts","../../src/core/utils/internal/toReadonlyArray.ts","../../src/core/utils/internal/Disposable.ts","../../src/core/SetupApi.ts","../../src/core/utils/internal/getCallFrame.ts","../../src/core/utils/internal/isIterable.ts","../../src/core/handlers/RequestHandler.ts","../../src/core/utils/internal/isStringEqual.ts","../../src/core/utils/logging/getStatusCodeColor.ts","../../src/core/utils/logging/getTimestamp.ts","../../src/core/utils/logging/serializeRequest.ts","../../src/shims/statuses.ts","../../src/core/utils/logging/serializeResponse.ts","../../node_modules/.pnpm/path-to-regexp@6.3.0/node_modules/path-to-regexp/src/index.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/bufferUtils.ts","../../node_modules/.pnpm/is-node-process@1.2.0/node_modules/is-node-process/src/index.ts","../../node_modules/.pnpm/@open-draft+logger@0.3.0/node_modules/@open-draft/logger/lib/index.mjs","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/Interceptor.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/createRequestId.ts","../../node_modules/.pnpm/@open-draft+deferred-promise@2.2.0/node_modules/@open-draft/deferred-promise/src/createDeferredExecutor.ts","../../node_modules/.pnpm/@open-draft+deferred-promise@2.2.0/node_modules/@open-draft/deferred-promise/src/DeferredPromise.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/glossary.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/RequestController.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/InterceptorError.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/canParseUrl.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/getValueBySymbol.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/fetchUtils.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/getRawRequest.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/BatchInterceptor.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/getCleanUrl.ts","../../src/core/utils/url/cleanUrl.ts","../../src/core/utils/url/isAbsoluteUrl.ts","../../src/core/utils/url/getAbsoluteUrl.ts","../../src/core/utils/matching/normalizePath.ts","../../src/core/utils/matching/matchRequestUrl.ts","../../src/core/utils/request/toPublicUrl.ts","../../src/shims/cookie.ts","../../node_modules/.pnpm/tldts-core@7.0.12/node_modules/tldts-core/src/domain.ts","../../node_modules/.pnpm/tldts-core@7.0.12/node_modules/tldts-core/src/domain-without-suffix.ts","../../node_modules/.pnpm/tldts-core@7.0.12/node_modules/tldts-core/src/extract-hostname.ts","../../node_modules/.pnpm/tldts-core@7.0.12/node_modules/tldts-core/src/is-ip.ts","../../node_modules/.pnpm/tldts-core@7.0.12/node_modules/tldts-core/src/is-valid.ts","../../node_modules/.pnpm/tldts-core@7.0.12/node_modules/tldts-core/src/options.ts","../../node_modules/.pnpm/tldts-core@7.0.12/node_modules/tldts-core/src/subdomain.ts","../../node_modules/.pnpm/tldts-core@7.0.12/node_modules/tldts-core/src/factory.ts","../../node_modules/.pnpm/tldts-core@7.0.12/node_modules/tldts-core/src/lookup/fast-path.ts","../../node_modules/.pnpm/tldts@7.0.12/node_modules/tldts/src/data/trie.ts","../../node_modules/.pnpm/tldts@7.0.12/node_modules/tldts/src/suffix-trie.ts","../../node_modules/.pnpm/tldts@7.0.12/node_modules/tldts/index.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/pathMatch.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/getPublicSuffix.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/permuteDomain.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/store.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/utils.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/memstore.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/validators.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/version.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/constants.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/canonicalDomain.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/formatDate.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/parseDate.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/cookie.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/cookieCompare.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/defaultPath.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/domainMatch.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/secureContext.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/cookieJar.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/permutePath.ts","../../node_modules/.pnpm/tough-cookie@6.0.0/node_modules/tough-cookie/lib/cookie/index.ts","../../src/core/utils/internal/jsonParse.ts","../../src/core/utils/cookieStore.ts","../../src/core/utils/request/getRequestCookies.ts","../../src/core/handlers/HttpHandler.ts","../../src/core/http.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/node_modules/set-cookie-parser/lib/set-cookie.js","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/Headers.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/utils/normalizeHeaderName.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/utils/normalizeHeaderValue.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/utils/isValidHeaderName.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/utils/isValidHeaderValue.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/getRawHeaders.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/transformers/headersToList.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/transformers/headersToString.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/transformers/headersToObject.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/transformers/stringToHeaders.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/transformers/listToHeaders.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/transformers/reduceHeadersObject.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/transformers/objectToHeaders.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/transformers/flattenHeadersList.ts","../../node_modules/.pnpm/headers-polyfill@4.0.3/node_modules/headers-polyfill/src/transformers/flattenHeadersObject.ts","../../src/core/utils/internal/parseMultipartData.ts","../../src/core/utils/internal/parseGraphQLRequest.ts","../../src/core/handlers/GraphQLHandler.ts","../../src/core/graphql.ts","../../src/core/handlers/WebSocketHandler.ts","../../src/core/ws/WebSocketMemoryClientStore.ts","../../src/core/ws/WebSocketIndexedDBClientStore.ts","../../src/core/ws/WebSocketClientManager.ts","../../src/core/ws.ts","../../src/core/delay.ts","../../src/core/utils/internal/isObject.ts","../../src/core/ws/utils/getMessageLength.ts","../../src/core/ws/utils/truncateMessage.ts","../../src/core/ws/utils/getPublicData.ts","../../src/core/ws/utils/attachWebSocketLogger.ts","../../src/core/sse.ts","../../node_modules/.pnpm/until-async@3.0.2/node_modules/until-async/src/index.ts","../../src/core/utils/executeHandlers.ts","../../src/core/isCommonAssetRequest.ts","../../src/core/utils/request/onUnhandledRequest.ts","../../src/core/utils/HttpResponse/decorators.ts","../../src/core/utils/request/storeResponseCookies.ts","../../src/core/utils/handleRequest.ts","../../src/core/getResponse.ts","../../src/core/HttpResponse.ts","../../src/core/bypass.ts","../../src/core/passthrough.ts","../../src/core/index.ts","../../src/core/utils/internal/mergeRight.ts","../../src/browser/setupWorker/start/utils/prepareStartHandler.ts","../../src/browser/utils/getAbsoluteWorkerUrl.ts","../../src/browser/setupWorker/start/utils/getWorkerByRegistration.ts","../../src/browser/setupWorker/start/utils/getWorkerInstance.ts","../../src/browser/setupWorker/start/utils/printStartMessage.ts","../../src/browser/setupWorker/start/utils/enableMocking.ts","../../src/browser/utils/pruneGetRequestBody.ts","../../src/browser/utils/deserializeRequest.ts","../../src/browser/utils/supports.ts","../../src/core/utils/toResponseInit.ts","../../src/core/utils/internal/isHandlerKind.ts","../../src/browser/setupWorker/start/createRequestListener.ts","../../src/browser/utils/checkWorkerIntegrity.ts","../../src/browser/setupWorker/start/createResponseListener.ts","../../src/browser/setupWorker/start/utils/validateWorkerScope.ts","../../src/browser/setupWorker/start/createStartHandler.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/emitAsync.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/hasConfigurableGlobal.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/bindEvent.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/utils/events.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketClientConnection.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketServerConnection.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketOverride.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/WebSocketClassTransport.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/WebSocket/index.ts","../../src/core/ws/webSocketInterceptor.ts","../../src/core/ws/handleWebSocketEvent.ts","../../node_modules/.pnpm/rettime@0.7.0/node_modules/rettime/src/index.ts","../../src/browser/utils/workerChannel.ts","../../node_modules/.pnpm/@open-draft+until@2.1.0/node_modules/@open-draft/until/src/until.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/isObject.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/isPropertyAccessible.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/responseUtils.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/handleRequest.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/isNodeLikeError.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/fetch/index.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/createNetworkError.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/followRedirect.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/brotli-decompress.browser.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/fetch/utils/decompression.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/index.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/concatArrayBuffer.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/polyfills/EventPolyfill.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/polyfills/ProgressEventPolyfill.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createEvent.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/findPropertySource.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/createProxy.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/isDomParserSupportedType.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/utils/parseJson.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/createResponse.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/utils/getBodyByteLength.ts","../../node_modules/.pnpm/@mswjs+interceptors@0.40.0/node_modules/@mswjs/interceptors/src/interceptors/XMLHttpRequest/XMLHttpRequestProxy.ts","../../src/browser/setupWorker/start/createFallbackRequestListener.ts","../../src/browser/setupWorker/stop/utils/printStopMessage.ts","../../src/browser/setupWorker/setupWorker.ts"],"sourcesContent":["{\n \"100\": \"Continue\",\n \"101\": \"Switching Protocols\",\n \"102\": \"Processing\",\n \"103\": \"Early Hints\",\n \"200\": \"OK\",\n \"201\": \"Created\",\n \"202\": \"Accepted\",\n \"203\": \"Non-Authoritative Information\",\n \"204\": \"No Content\",\n \"205\": \"Reset Content\",\n \"206\": \"Partial Content\",\n \"207\": \"Multi-Status\",\n \"208\": \"Already Reported\",\n \"226\": \"IM Used\",\n \"300\": \"Multiple Choices\",\n \"301\": \"Moved Permanently\",\n \"302\": \"Found\",\n \"303\": \"See Other\",\n \"304\": \"Not Modified\",\n \"305\": \"Use Proxy\",\n \"307\": \"Temporary Redirect\",\n \"308\": \"Permanent Redirect\",\n \"400\": \"Bad Request\",\n \"401\": \"Unauthorized\",\n \"402\": \"Payment Required\",\n \"403\": \"Forbidden\",\n \"404\": \"Not Found\",\n \"405\": \"Method Not Allowed\",\n \"406\": \"Not Acceptable\",\n \"407\": \"Proxy Authentication Required\",\n \"408\": \"Request Timeout\",\n \"409\": \"Conflict\",\n \"410\": \"Gone\",\n \"411\": \"Length Required\",\n \"412\": \"Precondition Failed\",\n \"413\": \"Payload Too Large\",\n \"414\": \"URI Too Long\",\n \"415\": \"Unsupported Media Type\",\n \"416\": \"Range Not Satisfiable\",\n \"417\": \"Expectation Failed\",\n \"418\": \"I'm a Teapot\",\n \"421\": \"Misdirected Request\",\n \"422\": \"Unprocessable Entity\",\n \"423\": \"Locked\",\n \"424\": \"Failed Dependency\",\n \"425\": \"Too Early\",\n \"426\": \"Upgrade Required\",\n \"428\": \"Precondition Required\",\n \"429\": \"Too Many Requests\",\n \"431\": \"Request Header Fields Too Large\",\n \"451\": \"Unavailable For Legal Reasons\",\n \"500\": \"Internal Server Error\",\n \"501\": \"Not Implemented\",\n \"502\": \"Bad Gateway\",\n \"503\": \"Service Unavailable\",\n \"504\": \"Gateway Timeout\",\n \"505\": \"HTTP Version Not Supported\",\n \"506\": \"Variant Also Negotiates\",\n \"507\": \"Insufficient Storage\",\n \"508\": \"Loop Detected\",\n \"509\": \"Bandwidth Limit Exceeded\",\n \"510\": \"Not Extended\",\n \"511\": \"Network Authentication Required\"\n}\n","/*!\n * statuses\n * Copyright(c) 2014 Jonathan Ong\n * Copyright(c) 2016 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n'use strict'\n\n/**\n * Module dependencies.\n * @private\n */\n\nvar codes = require('./codes.json')\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = status\n\n// status code to message map\nstatus.message = codes\n\n// status message (lower-case) to code map\nstatus.code = createMessageToStatusCodeMap(codes)\n\n// array of status codes\nstatus.codes = createStatusCodeList(codes)\n\n// status codes for redirects\nstatus.redirect = {\n 300: true,\n 301: true,\n 302: true,\n 303: true,\n 305: true,\n 307: true,\n 308: true\n}\n\n// status codes for empty bodies\nstatus.empty = {\n 204: true,\n 205: true,\n 304: true\n}\n\n// status codes for when you should retry the request\nstatus.retry = {\n 502: true,\n 503: true,\n 504: true\n}\n\n/**\n * Create a map of message to status code.\n * @private\n */\n\nfunction createMessageToStatusCodeMap (codes) {\n var map = {}\n\n Object.keys(codes).forEach(function forEachCode (code) {\n var message = codes[code]\n var status = Number(code)\n\n // populate map\n map[message.toLowerCase()] = status\n })\n\n return map\n}\n\n/**\n * Create a list of all status codes.\n * @private\n */\n\nfunction createStatusCodeList (codes) {\n return Object.keys(codes).map(function mapCode (code) {\n return Number(code)\n })\n}\n\n/**\n * Get the status code for given message.\n * @private\n */\n\nfunction getStatusCode (message) {\n var msg = message.toLowerCase()\n\n if (!Object.prototype.hasOwnProperty.call(status.code, msg)) {\n throw new Error('invalid status message: \"' + message + '\"')\n }\n\n return status.code[msg]\n}\n\n/**\n * Get the status message for given code.\n * @private\n */\n\nfunction getStatusMessage (code) {\n if (!Object.prototype.hasOwnProperty.call(status.message, code)) {\n throw new Error('invalid status code: ' + code)\n }\n\n return status.message[code]\n}\n\n/**\n * Get the status code.\n *\n * Given a number, this will throw if it is not a known status\n * code, otherwise the code will be returned. Given a string,\n * the string will be parsed for a number and return the code\n * if valid, otherwise will lookup the code assuming this is\n * the status message.\n *\n * @param {string|number} code\n * @returns {number}\n * @public\n */\n\nfunction status (code) {\n if (typeof code === 'number') {\n return getStatusMessage(code)\n }\n\n if (typeof code !== 'string') {\n throw new TypeError('code must be a number or string')\n }\n\n // '403'\n var n = parseInt(code, 10)\n if (!isNaN(n)) {\n return getStatusMessage(n)\n }\n\n return getStatusCode(code)\n}\n","/**\n * RegExp to match cookie-name in RFC 6265 sec 4.1.1\n * This refers out to the obsoleted definition of token in RFC 2616 sec 2.2\n * which has been replaced by the token definition in RFC 7230 appendix B.\n *\n * cookie-name = token\n * token = 1*tchar\n * tchar = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" /\n * \"*\" / \"+\" / \"-\" / \".\" / \"^\" / \"_\" /\n * \"`\" / \"|\" / \"~\" / DIGIT / ALPHA\n *\n * Note: Allowing more characters - https://github.com/jshttp/cookie/issues/191\n * Allow same range as cookie value, except `=`, which delimits end of name.\n */\nconst cookieNameRegExp = /^[\\u0021-\\u003A\\u003C\\u003E-\\u007E]+$/;\n\n/**\n * RegExp to match cookie-value in RFC 6265 sec 4.1.1\n *\n * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )\n * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E\n * ; US-ASCII characters excluding CTLs,\n * ; whitespace DQUOTE, comma, semicolon,\n * ; and backslash\n *\n * Allowing more characters: https://github.com/jshttp/cookie/issues/191\n * Comma, backslash, and DQUOTE are not part of the parsing algorithm.\n */\nconst cookieValueRegExp = /^[\\u0021-\\u003A\\u003C-\\u007E]*$/;\n\n/**\n * RegExp to match domain-value in RFC 6265 sec 4.1.1\n *\n * domain-value = \n * ; defined in [RFC1034], Section 3.5, as\n * ; enhanced by [RFC1123], Section 2.1\n * =