better-auth 1.5.4 → 1.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/index.d.mts +25 -1
- package/dist/adapters/index.mjs +9 -1
- package/dist/adapters/index.mjs.map +1 -0
- package/dist/api/index.d.mts +36 -10
- package/dist/api/index.mjs +19 -4
- package/dist/api/index.mjs.map +1 -1
- package/dist/api/middlewares/origin-check.mjs +17 -8
- package/dist/api/middlewares/origin-check.mjs.map +1 -1
- package/dist/api/routes/account.d.mts +1 -1
- package/dist/api/routes/email-verification.d.mts +0 -1
- package/dist/api/routes/password.d.mts +1 -0
- package/dist/api/routes/password.mjs +2 -1
- package/dist/api/routes/password.mjs.map +1 -1
- package/dist/api/routes/session.d.mts +0 -1
- package/dist/api/routes/sign-in.d.mts +16 -2
- package/dist/api/routes/sign-in.mjs +10 -2
- package/dist/api/routes/sign-in.mjs.map +1 -1
- package/dist/api/routes/sign-up.d.mts +0 -1
- package/dist/api/routes/sign-up.mjs +3 -2
- package/dist/api/routes/sign-up.mjs.map +1 -1
- package/dist/api/routes/update-session.d.mts +0 -1
- package/dist/api/routes/update-user.d.mts +0 -1
- package/dist/api/to-auth-endpoints.mjs +49 -12
- package/dist/api/to-auth-endpoints.mjs.map +1 -1
- package/dist/auth/full.d.mts +0 -1
- package/dist/auth/minimal.d.mts +0 -1
- package/dist/client/index.d.mts +3 -4
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/path-to-object.d.mts +9 -2
- package/dist/client/query.mjs +3 -2
- package/dist/client/query.mjs.map +1 -1
- package/dist/client/session-refresh.d.mts +11 -3
- package/dist/client/session-refresh.mjs +13 -8
- package/dist/client/session-refresh.mjs.map +1 -1
- package/dist/client/types.d.mts +0 -1
- package/dist/context/create-context.mjs +4 -1
- package/dist/context/create-context.mjs.map +1 -1
- package/dist/context/helpers.mjs +10 -4
- package/dist/context/helpers.mjs.map +1 -1
- package/dist/cookies/index.d.mts +0 -1
- package/dist/cookies/session-store.d.mts +0 -2
- package/dist/db/get-migration.mjs +3 -2
- package/dist/db/get-migration.mjs.map +1 -1
- package/dist/db/index.d.mts +2 -2
- package/dist/db/internal-adapter.d.mts +2 -1
- package/dist/db/internal-adapter.mjs +1 -1
- package/dist/db/internal-adapter.mjs.map +1 -1
- package/dist/db/schema.d.mts +0 -1
- package/dist/db/with-hooks.d.mts +6 -2
- package/dist/db/with-hooks.mjs +72 -31
- package/dist/db/with-hooks.mjs.map +1 -1
- package/dist/index.d.mts +0 -2
- package/dist/integrations/node.d.mts +0 -1
- package/dist/oauth2/link-account.d.mts +0 -1
- package/dist/plugins/admin/access/statement.d.mts +0 -2
- package/dist/plugins/admin/admin.d.mts +0 -1
- package/dist/plugins/admin/client.d.mts +0 -2
- package/dist/plugins/admin/types.d.mts +0 -2
- package/dist/plugins/anonymous/types.d.mts +0 -1
- package/dist/plugins/email-otp/index.mjs +2 -1
- package/dist/plugins/email-otp/index.mjs.map +1 -1
- package/dist/plugins/email-otp/otp-token.mjs +31 -2
- package/dist/plugins/email-otp/otp-token.mjs.map +1 -1
- package/dist/plugins/email-otp/routes.mjs +60 -59
- package/dist/plugins/email-otp/routes.mjs.map +1 -1
- package/dist/plugins/email-otp/types.d.mts +12 -0
- package/dist/plugins/email-otp/utils.mjs +4 -1
- package/dist/plugins/email-otp/utils.mjs.map +1 -1
- package/dist/plugins/generic-oauth/client.d.mts +0 -1
- package/dist/plugins/generic-oauth/index.d.mts +0 -1
- package/dist/plugins/index.d.mts +0 -3
- package/dist/plugins/jwt/types.d.mts +0 -1
- package/dist/plugins/magic-link/index.d.mts +2 -0
- package/dist/plugins/magic-link/index.mjs +5 -3
- package/dist/plugins/magic-link/index.mjs.map +1 -1
- package/dist/plugins/mcp/index.d.mts +0 -1
- package/dist/plugins/oidc-provider/authorize.mjs +13 -4
- package/dist/plugins/oidc-provider/authorize.mjs.map +1 -1
- package/dist/plugins/oidc-provider/error.mjs +12 -2
- package/dist/plugins/oidc-provider/error.mjs.map +1 -1
- package/dist/plugins/oidc-provider/index.d.mts +0 -1
- package/dist/plugins/oidc-provider/types.d.mts +0 -1
- package/dist/plugins/one-time-token/index.d.mts +0 -1
- package/dist/plugins/organization/access/statement.d.mts +0 -2
- package/dist/plugins/organization/adapter.d.mts +0 -2
- package/dist/plugins/organization/adapter.mjs +2 -2
- package/dist/plugins/organization/adapter.mjs.map +1 -1
- package/dist/plugins/organization/client.d.mts +0 -5
- package/dist/plugins/organization/organization.d.mts +0 -2
- package/dist/plugins/organization/permission.d.mts +0 -1
- package/dist/plugins/organization/routes/crud-access-control.d.mts +0 -2
- package/dist/plugins/organization/routes/crud-invites.d.mts +0 -3
- package/dist/plugins/organization/routes/crud-invites.mjs +1 -1
- package/dist/plugins/organization/routes/crud-invites.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-members.d.mts +0 -3
- package/dist/plugins/organization/routes/crud-members.mjs +1 -1
- package/dist/plugins/organization/routes/crud-members.mjs.map +1 -1
- package/dist/plugins/organization/routes/crud-org.d.mts +0 -3
- package/dist/plugins/organization/routes/crud-team.d.mts +2 -3
- package/dist/plugins/organization/routes/crud-team.mjs +18 -14
- package/dist/plugins/organization/routes/crud-team.mjs.map +1 -1
- package/dist/plugins/organization/schema.d.mts +0 -1
- package/dist/plugins/organization/types.d.mts +0 -2
- package/dist/plugins/phone-number/types.d.mts +0 -1
- package/dist/plugins/siwe/index.d.mts +0 -1
- package/dist/plugins/test-utils/types.d.mts +0 -2
- package/dist/plugins/two-factor/client.d.mts +7 -0
- package/dist/plugins/two-factor/client.mjs +5 -1
- package/dist/plugins/two-factor/client.mjs.map +1 -1
- package/dist/plugins/two-factor/index.mjs +7 -1
- package/dist/plugins/two-factor/index.mjs.map +1 -1
- package/dist/plugins/two-factor/otp/index.d.mts +2 -2
- package/dist/plugins/two-factor/otp/index.mjs.map +1 -1
- package/dist/plugins/two-factor/types.d.mts +7 -1
- package/dist/test-utils/test-instance.d.mts +108 -21
- package/dist/types/index.d.mts +0 -1
- package/package.json +13 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-migration.mjs","names":[],"sources":["../../src/db/get-migration.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport type { DBFieldAttribute, DBFieldType } from \"@better-auth/core/db\";\nimport { getAuthTables } from \"@better-auth/core/db\";\nimport {\n\tinitGetFieldName,\n\tinitGetModelName,\n} from \"@better-auth/core/db/adapter\";\nimport { createLogger } from \"@better-auth/core/env\";\nimport type { KyselyDatabaseType } from \"@better-auth/kysely-adapter\";\nimport { createKyselyAdapter } from \"@better-auth/kysely-adapter\";\nimport type {\n\tAlterTableBuilder,\n\tAlterTableColumnAlteringBuilder,\n\tColumnDataType,\n\tCreateIndexBuilder,\n\tCreateTableBuilder,\n\tKysely,\n\tRawBuilder,\n} from \"kysely\";\nimport { sql } from \"kysely\";\nimport { getSchema } from \"./get-schema\";\n\nconst postgresMap = {\n\tstring: [\"character varying\", \"varchar\", \"text\", \"uuid\"],\n\tnumber: [\n\t\t\"int4\",\n\t\t\"integer\",\n\t\t\"bigint\",\n\t\t\"smallint\",\n\t\t\"numeric\",\n\t\t\"real\",\n\t\t\"double precision\",\n\t],\n\tboolean: [\"bool\", \"boolean\"],\n\tdate: [\"timestamptz\", \"timestamp\", \"date\"],\n\tjson: [\"json\", \"jsonb\"],\n};\nconst mysqlMap = {\n\tstring: [\"varchar\", \"text\", \"uuid\"],\n\tnumber: [\n\t\t\"integer\",\n\t\t\"int\",\n\t\t\"bigint\",\n\t\t\"smallint\",\n\t\t\"decimal\",\n\t\t\"float\",\n\t\t\"double\",\n\t],\n\tboolean: [\"boolean\", \"tinyint\"],\n\tdate: [\"timestamp\", \"datetime\", \"date\"],\n\tjson: [\"json\"],\n};\n\nconst sqliteMap = {\n\tstring: [\"TEXT\"],\n\tnumber: [\"INTEGER\", \"REAL\"],\n\tboolean: [\"INTEGER\", \"BOOLEAN\"], // 0 or 1\n\tdate: [\"DATE\", \"INTEGER\"],\n\tjson: [\"TEXT\"],\n};\n\nconst mssqlMap = {\n\tstring: [\"varchar\", \"nvarchar\", \"uniqueidentifier\"],\n\tnumber: [\"int\", \"bigint\", \"smallint\", \"decimal\", \"float\", \"double\"],\n\tboolean: [\"bit\", \"smallint\"],\n\tdate: [\"datetime2\", \"date\", \"datetime\"],\n\tjson: [\"varchar\", \"nvarchar\"],\n};\n\nconst map = {\n\tpostgres: postgresMap,\n\tmysql: mysqlMap,\n\tsqlite: sqliteMap,\n\tmssql: mssqlMap,\n};\n\nexport function matchType(\n\tcolumnDataType: string,\n\tfieldType: DBFieldType,\n\tdbType: KyselyDatabaseType,\n) {\n\tfunction normalize(type: string) {\n\t\treturn type.toLowerCase().split(\"(\")[0]!.trim();\n\t}\n\tif (fieldType === \"string[]\" || fieldType === \"number[]\") {\n\t\treturn columnDataType.toLowerCase().includes(\"json\");\n\t}\n\tconst types = map[dbType]!;\n\tconst expected = Array.isArray(fieldType)\n\t\t? types[\"string\"].map((t) => t.toLowerCase())\n\t\t: types[fieldType]!.map((t) => t.toLowerCase());\n\treturn expected.includes(normalize(columnDataType));\n}\n\n/**\n * Get the current PostgreSQL schema (search_path) for the database connection\n * Returns the first schema in the search_path, defaulting to 'public' if not found\n */\nasync function getPostgresSchema(db: Kysely<unknown>): Promise<string> {\n\ttry {\n\t\tconst result = await sql<{\n\t\t\tsearch_path?: string;\n\t\t\tsearchPath?: string;\n\t\t}>`SHOW search_path`.execute(db);\n\t\tconst searchPath =\n\t\t\tresult.rows[0]?.search_path ?? result.rows[0]?.searchPath;\n\t\tif (searchPath) {\n\t\t\t// search_path can be a comma-separated list like \"$user, public\" or '\"$user\", public'\n\t\t\t// Supabase may return escaped format like '\"\\$user\", public'\n\t\t\t// We want the first non-variable schema\n\t\t\tconst schemas = searchPath\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((s) => s.trim())\n\t\t\t\t// Remove quotes and filter out variables like $user\n\t\t\t\t.map((s) => s.replace(/^[\"']|[\"']$/g, \"\"))\n\t\t\t\t// Filter out variable references like $user, \\$user (escaped)\n\t\t\t\t.filter((s) => !s.startsWith(\"$\") && !s.startsWith(\"\\\\$\"));\n\t\t\treturn schemas[0] || \"public\";\n\t\t}\n\t} catch {\n\t\t// If query fails, fall back to public schema\n\t}\n\treturn \"public\";\n}\n\nexport async function getMigrations(config: BetterAuthOptions) {\n\tconst betterAuthSchema = getSchema(config);\n\tconst logger = createLogger(config.logger);\n\n\tlet { kysely: db, databaseType: dbType } = await createKyselyAdapter(config);\n\n\tif (!dbType) {\n\t\tlogger.warn(\n\t\t\t\"Could not determine database type, defaulting to sqlite. Please provide a type in the database options to avoid this.\",\n\t\t);\n\t\tdbType = \"sqlite\";\n\t}\n\n\tif (!db) {\n\t\tlogger.error(\n\t\t\t\"Only kysely adapter is supported for migrations. You can use `generate` command to generate the schema, if you're using a different adapter.\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// For PostgreSQL, detect and log the current schema being used\n\tlet currentSchema = \"public\";\n\tif (dbType === \"postgres\") {\n\t\tcurrentSchema = await getPostgresSchema(db);\n\t\tlogger.debug(\n\t\t\t`PostgreSQL migration: Using schema '${currentSchema}' (from search_path)`,\n\t\t);\n\n\t\t// Verify the schema exists\n\t\ttry {\n\t\t\tconst schemaCheck = await sql<{\n\t\t\t\tschema_name?: string;\n\t\t\t\tschemaName?: string;\n\t\t\t}>`\n\t\t\t\tSELECT schema_name\n\t\t\t\tFROM information_schema.schemata\n\t\t\t\tWHERE schema_name = ${currentSchema}\n\t\t\t`.execute(db);\n\n\t\t\tconst schemaExists =\n\t\t\t\tschemaCheck.rows[0]?.schema_name ?? schemaCheck.rows[0]?.schemaName;\n\t\t\tif (!schemaExists) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Schema '${currentSchema}' does not exist. Tables will be inspected from available schemas. Consider creating the schema first or checking your database configuration.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.debug(\n\t\t\t\t`Could not verify schema existence: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst allTableMetadata = await db.introspection.getTables();\n\n\t// For PostgreSQL, filter tables to only those in the target schema\n\tlet tableMetadata = allTableMetadata;\n\tif (dbType === \"postgres\") {\n\t\t// Get tables with their schema information\n\t\ttry {\n\t\t\tconst tablesInSchema = await sql<{\n\t\t\t\ttable_name?: string;\n\t\t\t\ttableName?: string;\n\t\t\t}>`\n\t\t\t\tSELECT table_name\n\t\t\t\tFROM information_schema.tables\n\t\t\t\tWHERE table_schema = ${currentSchema}\n\t\t\t\tAND table_type = 'BASE TABLE'\n\t\t\t`.execute(db);\n\n\t\t\tconst tableNamesInSchema = new Set(\n\t\t\t\ttablesInSchema.rows.map((row) => row.table_name ?? row.tableName),\n\t\t\t);\n\n\t\t\t// Filter to only tables that exist in the target schema\n\t\t\ttableMetadata = allTableMetadata.filter(\n\t\t\t\t(table) =>\n\t\t\t\t\ttable.schema === currentSchema && tableNamesInSchema.has(table.name),\n\t\t\t);\n\n\t\t\tlogger.debug(\n\t\t\t\t`Found ${tableMetadata.length} table(s) in schema '${currentSchema}': ${tableMetadata.map((t) => t.name).join(\", \") || \"(none)\"}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlogger.warn(\n\t\t\t\t`Could not filter tables by schema. Using all discovered tables. Error: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\t// Fall back to using all tables if schema filtering fails\n\t\t}\n\t}\n\tconst toBeCreated: {\n\t\ttable: string;\n\t\tfields: Record<string, DBFieldAttribute>;\n\t\torder: number;\n\t}[] = [];\n\tconst toBeAdded: {\n\t\ttable: string;\n\t\tfields: Record<string, DBFieldAttribute>;\n\t\torder: number;\n\t}[] = [];\n\n\tfor (const [key, value] of Object.entries(betterAuthSchema)) {\n\t\tconst table = tableMetadata.find((t) => t.name === key);\n\t\tif (!table) {\n\t\t\tconst tIndex = toBeCreated.findIndex((t) => t.table === key);\n\t\t\tconst tableData = {\n\t\t\t\ttable: key,\n\t\t\t\tfields: value.fields,\n\t\t\t\torder: value.order || Infinity,\n\t\t\t};\n\n\t\t\tconst insertIndex = toBeCreated.findIndex(\n\t\t\t\t(t) => (t.order || Infinity) > tableData.order,\n\t\t\t);\n\n\t\t\tif (insertIndex === -1) {\n\t\t\t\tif (tIndex === -1) {\n\t\t\t\t\ttoBeCreated.push(tableData);\n\t\t\t\t} else {\n\t\t\t\t\ttoBeCreated[tIndex]!.fields = {\n\t\t\t\t\t\t...toBeCreated[tIndex]!.fields,\n\t\t\t\t\t\t...value.fields,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttoBeCreated.splice(insertIndex, 0, tableData);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst toBeAddedFields: Record<string, DBFieldAttribute> = {};\n\t\tfor (const [fieldName, field] of Object.entries(value.fields)) {\n\t\t\tconst column = table.columns.find((c) => c.name === fieldName);\n\t\t\tif (!column) {\n\t\t\t\ttoBeAddedFields[fieldName] = field;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (matchType(column.dataType, field.type, dbType)) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Field ${fieldName} in table ${key} has a different type in the database. Expected ${field.type} but got ${column.dataType}.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (Object.keys(toBeAddedFields).length > 0) {\n\t\t\ttoBeAdded.push({\n\t\t\t\ttable: key,\n\t\t\t\tfields: toBeAddedFields,\n\t\t\t\torder: value.order || Infinity,\n\t\t\t});\n\t\t}\n\t}\n\n\tconst migrations: (\n\t\t| AlterTableColumnAlteringBuilder\n\t\t| ReturnType<AlterTableBuilder[\"addIndex\"]>\n\t\t| CreateTableBuilder<string, string>\n\t\t| CreateIndexBuilder\n\t)[] = [];\n\n\tconst useUUIDs = config.advanced?.database?.generateId === \"uuid\";\n\tconst useNumberId = config.advanced?.database?.generateId === \"serial\";\n\n\tfunction getType(field: DBFieldAttribute, fieldName: string) {\n\t\tconst type = field.type;\n\t\tconst provider = dbType || \"sqlite\";\n\t\ttype StringOnlyUnion<T> = T extends string ? T : never;\n\t\tconst typeMap: Record<\n\t\t\tStringOnlyUnion<DBFieldType> | \"id\" | \"foreignKeyId\",\n\t\t\tRecord<KyselyDatabaseType, ColumnDataType | RawBuilder<unknown>>\n\t\t> = {\n\t\t\tstring: {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"text\",\n\t\t\t\tmysql: field.unique\n\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t: field.references\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: field.sortable\n\t\t\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t\t\t: field.index\n\t\t\t\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t\t\t\t: \"text\",\n\t\t\t\tmssql:\n\t\t\t\t\tfield.unique || field.sortable\n\t\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t\t: field.references\n\t\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t\t: // mssql deprecated `text`, and the alternative is `varchar(max)`.\n\t\t\t\t\t\t\t\t// Kysely type interface doesn't support `text`, so we set this to `varchar(8000)` as\n\t\t\t\t\t\t\t\t// that's the max length for `varchar`\n\t\t\t\t\t\t\t\t\"varchar(8000)\",\n\t\t\t},\n\t\t\tboolean: {\n\t\t\t\tsqlite: \"integer\",\n\t\t\t\tpostgres: \"boolean\",\n\t\t\t\tmysql: \"boolean\",\n\t\t\t\tmssql: \"smallint\",\n\t\t\t},\n\t\t\tnumber: {\n\t\t\t\tsqlite: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t\tpostgres: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t\tmysql: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t\tmssql: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t},\n\t\t\tdate: {\n\t\t\t\tsqlite: \"date\",\n\t\t\t\tpostgres: \"timestamptz\",\n\t\t\t\tmysql: \"timestamp(3)\",\n\t\t\t\tmssql: sql`datetime2(3)`,\n\t\t\t},\n\t\t\tjson: {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"jsonb\",\n\t\t\t\tmysql: \"json\",\n\t\t\t\tmssql: \"varchar(8000)\",\n\t\t\t},\n\t\t\tid: {\n\t\t\t\tpostgres: useNumberId\n\t\t\t\t\t? sql`integer GENERATED BY DEFAULT AS IDENTITY`\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"uuid\"\n\t\t\t\t\t\t: \"text\",\n\t\t\t\tmysql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tmssql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tsqlite: useNumberId ? \"integer\" : \"text\",\n\t\t\t},\n\t\t\tforeignKeyId: {\n\t\t\t\tpostgres: useNumberId ? \"integer\" : useUUIDs ? \"uuid\" : \"text\",\n\t\t\t\tmysql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tmssql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\" /* Should be using `UNIQUEIDENTIFIER` but Kysely doesn't support it */\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tsqlite: useNumberId ? \"integer\" : \"text\",\n\t\t\t},\n\t\t\t\"string[]\": {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"jsonb\",\n\t\t\t\tmysql: \"json\",\n\t\t\t\tmssql: \"varchar(8000)\",\n\t\t\t},\n\t\t\t\"number[]\": {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"jsonb\",\n\t\t\t\tmysql: \"json\",\n\t\t\t\tmssql: \"varchar(8000)\",\n\t\t\t},\n\t\t} as const;\n\t\tif (fieldName === \"id\" || field.references?.field === \"id\") {\n\t\t\tif (fieldName === \"id\") {\n\t\t\t\treturn typeMap.id[provider];\n\t\t\t}\n\t\t\treturn typeMap.foreignKeyId[provider];\n\t\t}\n\t\tif (Array.isArray(type)) {\n\t\t\treturn \"text\";\n\t\t}\n\t\tif (!(type in typeMap)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unsupported field type '${String(type)}' for field '${fieldName}'. Allowed types are: string, number, boolean, date, string[], number[]. If you need to store structured data, store it as a JSON string (type: \"string\") or split it into primitive fields. See https://better-auth.com/docs/advanced/schema#additional-fields`,\n\t\t\t);\n\t\t}\n\t\treturn typeMap[type][provider];\n\t}\n\tconst getModelName = initGetModelName({\n\t\tschema: getAuthTables(config),\n\t\tusePlural: false,\n\t});\n\tconst getFieldName = initGetFieldName({\n\t\tschema: getAuthTables(config),\n\t\tusePlural: false,\n\t});\n\n\t// Helper function to safely resolve model and field names, falling back to\n\t// user-supplied strings for external tables not in the BetterAuth schema\n\tfunction getReferencePath(model: string, field: string): string {\n\t\ttry {\n\t\t\tconst modelName = getModelName(model);\n\t\t\tconst fieldName = getFieldName({ model, field });\n\t\t\treturn `${modelName}.${fieldName}`;\n\t\t} catch {\n\t\t\t// If resolution fails (external table), fall back to user-supplied references\n\t\t\treturn `${model}.${field}`;\n\t\t}\n\t}\n\n\tif (toBeAdded.length) {\n\t\tfor (const table of toBeAdded) {\n\t\t\tfor (const [fieldName, field] of Object.entries(table.fields)) {\n\t\t\t\tconst type = getType(field, fieldName);\n\t\t\t\tconst builder = db.schema.alterTable(table.table);\n\n\t\t\t\tif (field.index) {\n\t\t\t\t\tconst index = db.schema\n\t\t\t\t\t\t.alterTable(table.table)\n\t\t\t\t\t\t.addIndex(`${table.table}_${fieldName}_idx`);\n\t\t\t\t\tmigrations.push(index);\n\t\t\t\t}\n\n\t\t\t\tconst built = builder.addColumn(fieldName, type, (col) => {\n\t\t\t\t\tcol = field.required !== false ? col.notNull() : col;\n\t\t\t\t\tif (field.references) {\n\t\t\t\t\t\tcol = col\n\t\t\t\t\t\t\t.references(\n\t\t\t\t\t\t\t\tgetReferencePath(\n\t\t\t\t\t\t\t\t\tfield.references.model,\n\t\t\t\t\t\t\t\t\tfield.references.field,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.onDelete(field.references.onDelete || \"cascade\");\n\t\t\t\t\t}\n\t\t\t\t\tif (field.unique) {\n\t\t\t\t\t\tcol = col.unique();\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tfield.type === \"date\" &&\n\t\t\t\t\t\ttypeof field.defaultValue === \"function\" &&\n\t\t\t\t\t\t(dbType === \"postgres\" || dbType === \"mysql\" || dbType === \"mssql\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (dbType === \"mysql\") {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn col;\n\t\t\t\t});\n\t\t\t\tmigrations.push(built);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst toBeIndexed: CreateIndexBuilder[] = [];\n\n\tif (toBeCreated.length) {\n\t\tfor (const table of toBeCreated) {\n\t\t\tconst idType = getType({ type: useNumberId ? \"number\" : \"string\" }, \"id\");\n\t\t\tlet dbT = db.schema\n\t\t\t\t.createTable(table.table)\n\t\t\t\t.addColumn(\"id\", idType, (col) => {\n\t\t\t\t\tif (useNumberId) {\n\t\t\t\t\t\tif (dbType === \"postgres\") {\n\t\t\t\t\t\t\t// Identity column is already specified in the type via sql template tag\n\t\t\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t\t\t} else if (dbType === \"sqlite\") {\n\t\t\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t\t\t} else if (dbType === \"mssql\") {\n\t\t\t\t\t\t\treturn col.identity().primaryKey().notNull();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn col.autoIncrement().primaryKey().notNull();\n\t\t\t\t\t}\n\t\t\t\t\tif (useUUIDs) {\n\t\t\t\t\t\tif (dbType === \"postgres\") {\n\t\t\t\t\t\t\treturn col\n\t\t\t\t\t\t\t\t.primaryKey()\n\t\t\t\t\t\t\t\t.defaultTo(sql`pg_catalog.gen_random_uuid()`)\n\t\t\t\t\t\t\t\t.notNull();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t\t}\n\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t});\n\n\t\t\tfor (const [fieldName, field] of Object.entries(table.fields)) {\n\t\t\t\tconst type = getType(field, fieldName);\n\t\t\t\tdbT = dbT.addColumn(fieldName, type, (col) => {\n\t\t\t\t\tcol = field.required !== false ? col.notNull() : col;\n\t\t\t\t\tif (field.references) {\n\t\t\t\t\t\tcol = col\n\t\t\t\t\t\t\t.references(\n\t\t\t\t\t\t\t\tgetReferencePath(\n\t\t\t\t\t\t\t\t\tfield.references.model,\n\t\t\t\t\t\t\t\t\tfield.references.field,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.onDelete(field.references.onDelete || \"cascade\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (field.unique) {\n\t\t\t\t\t\tcol = col.unique();\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tfield.type === \"date\" &&\n\t\t\t\t\t\ttypeof field.defaultValue === \"function\" &&\n\t\t\t\t\t\t(dbType === \"postgres\" || dbType === \"mysql\" || dbType === \"mssql\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (dbType === \"mysql\") {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn col;\n\t\t\t\t});\n\n\t\t\t\tif (field.index) {\n\t\t\t\t\tconst builder = db.schema\n\t\t\t\t\t\t.createIndex(\n\t\t\t\t\t\t\t`${table.table}_${fieldName}_${field.unique ? \"uidx\" : \"idx\"}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.on(table.table)\n\t\t\t\t\t\t.columns([fieldName]);\n\t\t\t\t\ttoBeIndexed.push(field.unique ? builder.unique() : builder);\n\t\t\t\t}\n\t\t\t}\n\t\t\tmigrations.push(dbT);\n\t\t}\n\t}\n\n\t// instead of adding the index straight to `migrations`,\n\t// we do this at the end so that indexes are created after the table is created\n\tif (toBeIndexed.length) {\n\t\tfor (const index of toBeIndexed) {\n\t\t\tmigrations.push(index);\n\t\t}\n\t}\n\n\tasync function runMigrations() {\n\t\tfor (const migration of migrations) {\n\t\t\tawait migration.execute();\n\t\t}\n\t}\n\tasync function compileMigrations() {\n\t\tconst compiled = migrations.map((m) => m.compile().sql);\n\t\treturn compiled.join(\";\\n\\n\") + \";\";\n\t}\n\treturn { toBeCreated, toBeAdded, runMigrations, compileMigrations };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"get-migration.mjs","names":[],"sources":["../../src/db/get-migration.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport type { DBFieldAttribute, DBFieldType } from \"@better-auth/core/db\";\nimport { getAuthTables } from \"@better-auth/core/db\";\nimport {\n\tinitGetFieldName,\n\tinitGetModelName,\n} from \"@better-auth/core/db/adapter\";\nimport { createLogger } from \"@better-auth/core/env\";\nimport type { KyselyDatabaseType } from \"@better-auth/kysely-adapter\";\nimport { createKyselyAdapter } from \"@better-auth/kysely-adapter\";\nimport type {\n\tAlterTableColumnAlteringBuilder,\n\tColumnDataType,\n\tCreateIndexBuilder,\n\tCreateTableBuilder,\n\tKysely,\n\tRawBuilder,\n} from \"kysely\";\nimport { sql } from \"kysely\";\nimport { getSchema } from \"./get-schema\";\n\nconst postgresMap = {\n\tstring: [\"character varying\", \"varchar\", \"text\", \"uuid\"],\n\tnumber: [\n\t\t\"int4\",\n\t\t\"integer\",\n\t\t\"bigint\",\n\t\t\"smallint\",\n\t\t\"numeric\",\n\t\t\"real\",\n\t\t\"double precision\",\n\t],\n\tboolean: [\"bool\", \"boolean\"],\n\tdate: [\"timestamptz\", \"timestamp\", \"date\"],\n\tjson: [\"json\", \"jsonb\"],\n};\nconst mysqlMap = {\n\tstring: [\"varchar\", \"text\", \"uuid\"],\n\tnumber: [\n\t\t\"integer\",\n\t\t\"int\",\n\t\t\"bigint\",\n\t\t\"smallint\",\n\t\t\"decimal\",\n\t\t\"float\",\n\t\t\"double\",\n\t],\n\tboolean: [\"boolean\", \"tinyint\"],\n\tdate: [\"timestamp\", \"datetime\", \"date\"],\n\tjson: [\"json\"],\n};\n\nconst sqliteMap = {\n\tstring: [\"TEXT\"],\n\tnumber: [\"INTEGER\", \"REAL\"],\n\tboolean: [\"INTEGER\", \"BOOLEAN\"], // 0 or 1\n\tdate: [\"DATE\", \"INTEGER\"],\n\tjson: [\"TEXT\"],\n};\n\nconst mssqlMap = {\n\tstring: [\"varchar\", \"nvarchar\", \"uniqueidentifier\"],\n\tnumber: [\"int\", \"bigint\", \"smallint\", \"decimal\", \"float\", \"double\"],\n\tboolean: [\"bit\", \"smallint\"],\n\tdate: [\"datetime2\", \"date\", \"datetime\"],\n\tjson: [\"varchar\", \"nvarchar\"],\n};\n\nconst map = {\n\tpostgres: postgresMap,\n\tmysql: mysqlMap,\n\tsqlite: sqliteMap,\n\tmssql: mssqlMap,\n};\n\nexport function matchType(\n\tcolumnDataType: string,\n\tfieldType: DBFieldType,\n\tdbType: KyselyDatabaseType,\n) {\n\tfunction normalize(type: string) {\n\t\treturn type.toLowerCase().split(\"(\")[0]!.trim();\n\t}\n\tif (fieldType === \"string[]\" || fieldType === \"number[]\") {\n\t\treturn columnDataType.toLowerCase().includes(\"json\");\n\t}\n\tconst types = map[dbType]!;\n\tconst expected = Array.isArray(fieldType)\n\t\t? types[\"string\"].map((t) => t.toLowerCase())\n\t\t: types[fieldType]!.map((t) => t.toLowerCase());\n\treturn expected.includes(normalize(columnDataType));\n}\n\n/**\n * Get the current PostgreSQL schema (search_path) for the database connection\n * Returns the first schema in the search_path, defaulting to 'public' if not found\n */\nasync function getPostgresSchema(db: Kysely<unknown>): Promise<string> {\n\ttry {\n\t\tconst result = await sql<{\n\t\t\tsearch_path?: string;\n\t\t\tsearchPath?: string;\n\t\t}>`SHOW search_path`.execute(db);\n\t\tconst searchPath =\n\t\t\tresult.rows[0]?.search_path ?? result.rows[0]?.searchPath;\n\t\tif (searchPath) {\n\t\t\t// search_path can be a comma-separated list like \"$user, public\" or '\"$user\", public'\n\t\t\t// Supabase may return escaped format like '\"\\$user\", public'\n\t\t\t// We want the first non-variable schema\n\t\t\tconst schemas = searchPath\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((s) => s.trim())\n\t\t\t\t// Remove quotes and filter out variables like $user\n\t\t\t\t.map((s) => s.replace(/^[\"']|[\"']$/g, \"\"))\n\t\t\t\t// Filter out variable references like $user, \\$user (escaped)\n\t\t\t\t.filter((s) => !s.startsWith(\"$\") && !s.startsWith(\"\\\\$\"));\n\t\t\treturn schemas[0] || \"public\";\n\t\t}\n\t} catch {\n\t\t// If query fails, fall back to public schema\n\t}\n\treturn \"public\";\n}\n\nexport async function getMigrations(config: BetterAuthOptions) {\n\tconst betterAuthSchema = getSchema(config);\n\tconst logger = createLogger(config.logger);\n\n\tlet { kysely: db, databaseType: dbType } = await createKyselyAdapter(config);\n\n\tif (!dbType) {\n\t\tlogger.warn(\n\t\t\t\"Could not determine database type, defaulting to sqlite. Please provide a type in the database options to avoid this.\",\n\t\t);\n\t\tdbType = \"sqlite\";\n\t}\n\n\tif (!db) {\n\t\tlogger.error(\n\t\t\t\"Only kysely adapter is supported for migrations. You can use `generate` command to generate the schema, if you're using a different adapter.\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\t// For PostgreSQL, detect and log the current schema being used\n\tlet currentSchema = \"public\";\n\tif (dbType === \"postgres\") {\n\t\tcurrentSchema = await getPostgresSchema(db);\n\t\tlogger.debug(\n\t\t\t`PostgreSQL migration: Using schema '${currentSchema}' (from search_path)`,\n\t\t);\n\n\t\t// Verify the schema exists\n\t\ttry {\n\t\t\tconst schemaCheck = await sql<{\n\t\t\t\tschema_name?: string;\n\t\t\t\tschemaName?: string;\n\t\t\t}>`\n\t\t\t\tSELECT schema_name\n\t\t\t\tFROM information_schema.schemata\n\t\t\t\tWHERE schema_name = ${currentSchema}\n\t\t\t`.execute(db);\n\n\t\t\tconst schemaExists =\n\t\t\t\tschemaCheck.rows[0]?.schema_name ?? schemaCheck.rows[0]?.schemaName;\n\t\t\tif (!schemaExists) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Schema '${currentSchema}' does not exist. Tables will be inspected from available schemas. Consider creating the schema first or checking your database configuration.`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.debug(\n\t\t\t\t`Could not verify schema existence: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst allTableMetadata = await db.introspection.getTables();\n\n\t// For PostgreSQL, filter tables to only those in the target schema\n\tlet tableMetadata = allTableMetadata;\n\tif (dbType === \"postgres\") {\n\t\t// Get tables with their schema information\n\t\ttry {\n\t\t\tconst tablesInSchema = await sql<{\n\t\t\t\ttable_name?: string;\n\t\t\t\ttableName?: string;\n\t\t\t}>`\n\t\t\t\tSELECT table_name\n\t\t\t\tFROM information_schema.tables\n\t\t\t\tWHERE table_schema = ${currentSchema}\n\t\t\t\tAND table_type = 'BASE TABLE'\n\t\t\t`.execute(db);\n\n\t\t\tconst tableNamesInSchema = new Set(\n\t\t\t\ttablesInSchema.rows.map((row) => row.table_name ?? row.tableName),\n\t\t\t);\n\n\t\t\t// Filter to only tables that exist in the target schema\n\t\t\ttableMetadata = allTableMetadata.filter(\n\t\t\t\t(table) =>\n\t\t\t\t\ttable.schema === currentSchema && tableNamesInSchema.has(table.name),\n\t\t\t);\n\n\t\t\tlogger.debug(\n\t\t\t\t`Found ${tableMetadata.length} table(s) in schema '${currentSchema}': ${tableMetadata.map((t) => t.name).join(\", \") || \"(none)\"}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlogger.warn(\n\t\t\t\t`Could not filter tables by schema. Using all discovered tables. Error: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\t// Fall back to using all tables if schema filtering fails\n\t\t}\n\t}\n\tconst toBeCreated: {\n\t\ttable: string;\n\t\tfields: Record<string, DBFieldAttribute>;\n\t\torder: number;\n\t}[] = [];\n\tconst toBeAdded: {\n\t\ttable: string;\n\t\tfields: Record<string, DBFieldAttribute>;\n\t\torder: number;\n\t}[] = [];\n\n\tfor (const [key, value] of Object.entries(betterAuthSchema)) {\n\t\tconst table = tableMetadata.find((t) => t.name === key);\n\t\tif (!table) {\n\t\t\tconst tIndex = toBeCreated.findIndex((t) => t.table === key);\n\t\t\tconst tableData = {\n\t\t\t\ttable: key,\n\t\t\t\tfields: value.fields,\n\t\t\t\torder: value.order || Infinity,\n\t\t\t};\n\n\t\t\tconst insertIndex = toBeCreated.findIndex(\n\t\t\t\t(t) => (t.order || Infinity) > tableData.order,\n\t\t\t);\n\n\t\t\tif (insertIndex === -1) {\n\t\t\t\tif (tIndex === -1) {\n\t\t\t\t\ttoBeCreated.push(tableData);\n\t\t\t\t} else {\n\t\t\t\t\ttoBeCreated[tIndex]!.fields = {\n\t\t\t\t\t\t...toBeCreated[tIndex]!.fields,\n\t\t\t\t\t\t...value.fields,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttoBeCreated.splice(insertIndex, 0, tableData);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst toBeAddedFields: Record<string, DBFieldAttribute> = {};\n\t\tfor (const [fieldName, field] of Object.entries(value.fields)) {\n\t\t\tconst column = table.columns.find((c) => c.name === fieldName);\n\t\t\tif (!column) {\n\t\t\t\ttoBeAddedFields[fieldName] = field;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (matchType(column.dataType, field.type, dbType)) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Field ${fieldName} in table ${key} has a different type in the database. Expected ${field.type} but got ${column.dataType}.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (Object.keys(toBeAddedFields).length > 0) {\n\t\t\ttoBeAdded.push({\n\t\t\t\ttable: key,\n\t\t\t\tfields: toBeAddedFields,\n\t\t\t\torder: value.order || Infinity,\n\t\t\t});\n\t\t}\n\t}\n\n\tconst migrations: (\n\t\t| AlterTableColumnAlteringBuilder\n\t\t| CreateTableBuilder<string, string>\n\t\t| CreateIndexBuilder\n\t)[] = [];\n\n\tconst useUUIDs = config.advanced?.database?.generateId === \"uuid\";\n\tconst useNumberId = config.advanced?.database?.generateId === \"serial\";\n\n\tfunction getType(field: DBFieldAttribute, fieldName: string) {\n\t\tconst type = field.type;\n\t\tconst provider = dbType || \"sqlite\";\n\t\ttype StringOnlyUnion<T> = T extends string ? T : never;\n\t\tconst typeMap: Record<\n\t\t\tStringOnlyUnion<DBFieldType> | \"id\" | \"foreignKeyId\",\n\t\t\tRecord<KyselyDatabaseType, ColumnDataType | RawBuilder<unknown>>\n\t\t> = {\n\t\t\tstring: {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"text\",\n\t\t\t\tmysql: field.unique\n\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t: field.references\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: field.sortable\n\t\t\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t\t\t: field.index\n\t\t\t\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t\t\t\t: \"text\",\n\t\t\t\tmssql:\n\t\t\t\t\tfield.unique || field.sortable\n\t\t\t\t\t\t? \"varchar(255)\"\n\t\t\t\t\t\t: field.references\n\t\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t\t: // mssql deprecated `text`, and the alternative is `varchar(max)`.\n\t\t\t\t\t\t\t\t// Kysely type interface doesn't support `text`, so we set this to `varchar(8000)` as\n\t\t\t\t\t\t\t\t// that's the max length for `varchar`\n\t\t\t\t\t\t\t\t\"varchar(8000)\",\n\t\t\t},\n\t\t\tboolean: {\n\t\t\t\tsqlite: \"integer\",\n\t\t\t\tpostgres: \"boolean\",\n\t\t\t\tmysql: \"boolean\",\n\t\t\t\tmssql: \"smallint\",\n\t\t\t},\n\t\t\tnumber: {\n\t\t\t\tsqlite: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t\tpostgres: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t\tmysql: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t\tmssql: field.bigint ? \"bigint\" : \"integer\",\n\t\t\t},\n\t\t\tdate: {\n\t\t\t\tsqlite: \"date\",\n\t\t\t\tpostgres: \"timestamptz\",\n\t\t\t\tmysql: \"timestamp(3)\",\n\t\t\t\tmssql: sql`datetime2(3)`,\n\t\t\t},\n\t\t\tjson: {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"jsonb\",\n\t\t\t\tmysql: \"json\",\n\t\t\t\tmssql: \"varchar(8000)\",\n\t\t\t},\n\t\t\tid: {\n\t\t\t\tpostgres: useNumberId\n\t\t\t\t\t? sql`integer GENERATED BY DEFAULT AS IDENTITY`\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"uuid\"\n\t\t\t\t\t\t: \"text\",\n\t\t\t\tmysql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tmssql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tsqlite: useNumberId ? \"integer\" : \"text\",\n\t\t\t},\n\t\t\tforeignKeyId: {\n\t\t\t\tpostgres: useNumberId ? \"integer\" : useUUIDs ? \"uuid\" : \"text\",\n\t\t\t\tmysql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\"\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tmssql: useNumberId\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: useUUIDs\n\t\t\t\t\t\t? \"varchar(36)\" /* Should be using `UNIQUEIDENTIFIER` but Kysely doesn't support it */\n\t\t\t\t\t\t: \"varchar(36)\",\n\t\t\t\tsqlite: useNumberId ? \"integer\" : \"text\",\n\t\t\t},\n\t\t\t\"string[]\": {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"jsonb\",\n\t\t\t\tmysql: \"json\",\n\t\t\t\tmssql: \"varchar(8000)\",\n\t\t\t},\n\t\t\t\"number[]\": {\n\t\t\t\tsqlite: \"text\",\n\t\t\t\tpostgres: \"jsonb\",\n\t\t\t\tmysql: \"json\",\n\t\t\t\tmssql: \"varchar(8000)\",\n\t\t\t},\n\t\t} as const;\n\t\tif (fieldName === \"id\" || field.references?.field === \"id\") {\n\t\t\tif (fieldName === \"id\") {\n\t\t\t\treturn typeMap.id[provider];\n\t\t\t}\n\t\t\treturn typeMap.foreignKeyId[provider];\n\t\t}\n\t\tif (Array.isArray(type)) {\n\t\t\treturn \"text\";\n\t\t}\n\t\tif (!(type in typeMap)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Unsupported field type '${String(type)}' for field '${fieldName}'. Allowed types are: string, number, boolean, date, string[], number[]. If you need to store structured data, store it as a JSON string (type: \"string\") or split it into primitive fields. See https://better-auth.com/docs/advanced/schema#additional-fields`,\n\t\t\t);\n\t\t}\n\t\treturn typeMap[type][provider];\n\t}\n\tconst getModelName = initGetModelName({\n\t\tschema: getAuthTables(config),\n\t\tusePlural: false,\n\t});\n\tconst getFieldName = initGetFieldName({\n\t\tschema: getAuthTables(config),\n\t\tusePlural: false,\n\t});\n\n\t// Helper function to safely resolve model and field names, falling back to\n\t// user-supplied strings for external tables not in the BetterAuth schema\n\tfunction getReferencePath(model: string, field: string): string {\n\t\ttry {\n\t\t\tconst modelName = getModelName(model);\n\t\t\tconst fieldName = getFieldName({ model, field });\n\t\t\treturn `${modelName}.${fieldName}`;\n\t\t} catch {\n\t\t\t// If resolution fails (external table), fall back to user-supplied references\n\t\t\treturn `${model}.${field}`;\n\t\t}\n\t}\n\n\tif (toBeAdded.length) {\n\t\tfor (const table of toBeAdded) {\n\t\t\tfor (const [fieldName, field] of Object.entries(table.fields)) {\n\t\t\t\tconst type = getType(field, fieldName);\n\t\t\t\tconst builder = db.schema.alterTable(table.table);\n\n\t\t\t\tif (field.index) {\n\t\t\t\t\tconst indexName = `${table.table}_${fieldName}_${field.unique ? \"uidx\" : \"idx\"}`;\n\t\t\t\t\tconst indexBuilder = db.schema\n\t\t\t\t\t\t.createIndex(indexName)\n\t\t\t\t\t\t.on(table.table)\n\t\t\t\t\t\t.columns([fieldName]);\n\t\t\t\t\tmigrations.push(field.unique ? indexBuilder.unique() : indexBuilder);\n\t\t\t\t}\n\n\t\t\t\tconst built = builder.addColumn(fieldName, type, (col) => {\n\t\t\t\t\tcol = field.required !== false ? col.notNull() : col;\n\t\t\t\t\tif (field.references) {\n\t\t\t\t\t\tcol = col\n\t\t\t\t\t\t\t.references(\n\t\t\t\t\t\t\t\tgetReferencePath(\n\t\t\t\t\t\t\t\t\tfield.references.model,\n\t\t\t\t\t\t\t\t\tfield.references.field,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.onDelete(field.references.onDelete || \"cascade\");\n\t\t\t\t\t}\n\t\t\t\t\tif (field.unique) {\n\t\t\t\t\t\tcol = col.unique();\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tfield.type === \"date\" &&\n\t\t\t\t\t\ttypeof field.defaultValue === \"function\" &&\n\t\t\t\t\t\t(dbType === \"postgres\" || dbType === \"mysql\" || dbType === \"mssql\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (dbType === \"mysql\") {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn col;\n\t\t\t\t});\n\t\t\t\tmigrations.push(built);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst toBeIndexed: CreateIndexBuilder[] = [];\n\n\tif (toBeCreated.length) {\n\t\tfor (const table of toBeCreated) {\n\t\t\tconst idType = getType({ type: useNumberId ? \"number\" : \"string\" }, \"id\");\n\t\t\tlet dbT = db.schema\n\t\t\t\t.createTable(table.table)\n\t\t\t\t.addColumn(\"id\", idType, (col) => {\n\t\t\t\t\tif (useNumberId) {\n\t\t\t\t\t\tif (dbType === \"postgres\") {\n\t\t\t\t\t\t\t// Identity column is already specified in the type via sql template tag\n\t\t\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t\t\t} else if (dbType === \"sqlite\") {\n\t\t\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t\t\t} else if (dbType === \"mssql\") {\n\t\t\t\t\t\t\treturn col.identity().primaryKey().notNull();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn col.autoIncrement().primaryKey().notNull();\n\t\t\t\t\t}\n\t\t\t\t\tif (useUUIDs) {\n\t\t\t\t\t\tif (dbType === \"postgres\") {\n\t\t\t\t\t\t\treturn col\n\t\t\t\t\t\t\t\t.primaryKey()\n\t\t\t\t\t\t\t\t.defaultTo(sql`pg_catalog.gen_random_uuid()`)\n\t\t\t\t\t\t\t\t.notNull();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t\t}\n\t\t\t\t\treturn col.primaryKey().notNull();\n\t\t\t\t});\n\n\t\t\tfor (const [fieldName, field] of Object.entries(table.fields)) {\n\t\t\t\tconst type = getType(field, fieldName);\n\t\t\t\tdbT = dbT.addColumn(fieldName, type, (col) => {\n\t\t\t\t\tcol = field.required !== false ? col.notNull() : col;\n\t\t\t\t\tif (field.references) {\n\t\t\t\t\t\tcol = col\n\t\t\t\t\t\t\t.references(\n\t\t\t\t\t\t\t\tgetReferencePath(\n\t\t\t\t\t\t\t\t\tfield.references.model,\n\t\t\t\t\t\t\t\t\tfield.references.field,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.onDelete(field.references.onDelete || \"cascade\");\n\t\t\t\t\t}\n\n\t\t\t\t\tif (field.unique) {\n\t\t\t\t\t\tcol = col.unique();\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tfield.type === \"date\" &&\n\t\t\t\t\t\ttypeof field.defaultValue === \"function\" &&\n\t\t\t\t\t\t(dbType === \"postgres\" || dbType === \"mysql\" || dbType === \"mssql\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (dbType === \"mysql\") {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP(3)`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcol = col.defaultTo(sql`CURRENT_TIMESTAMP`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn col;\n\t\t\t\t});\n\n\t\t\t\tif (field.index) {\n\t\t\t\t\tconst builder = db.schema\n\t\t\t\t\t\t.createIndex(\n\t\t\t\t\t\t\t`${table.table}_${fieldName}_${field.unique ? \"uidx\" : \"idx\"}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.on(table.table)\n\t\t\t\t\t\t.columns([fieldName]);\n\t\t\t\t\ttoBeIndexed.push(field.unique ? builder.unique() : builder);\n\t\t\t\t}\n\t\t\t}\n\t\t\tmigrations.push(dbT);\n\t\t}\n\t}\n\n\t// instead of adding the index straight to `migrations`,\n\t// we do this at the end so that indexes are created after the table is created\n\tif (toBeIndexed.length) {\n\t\tfor (const index of toBeIndexed) {\n\t\t\tmigrations.push(index);\n\t\t}\n\t}\n\n\tasync function runMigrations() {\n\t\tfor (const migration of migrations) {\n\t\t\tawait migration.execute();\n\t\t}\n\t}\n\tasync function compileMigrations() {\n\t\tconst compiled = migrations.map((m) => m.compile().sql);\n\t\treturn compiled.join(\";\\n\\n\") + \";\";\n\t}\n\treturn { toBeCreated, toBeAdded, runMigrations, compileMigrations };\n}\n"],"mappings":"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"}
|
package/dist/db/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { FieldAttributeToObject, InferAdditionalFieldsFromPluginOptions, InferFieldsInputClient, InferFieldsOutput, RemoveFieldsWithReturnedFalse } from "./field.mjs";
|
|
2
2
|
import { convertFromDB, convertToDB } from "./field-converter.mjs";
|
|
3
3
|
import { getSchema } from "./get-schema.mjs";
|
|
4
|
+
import { DatabaseHooksEntry, getWithHooks } from "./with-hooks.mjs";
|
|
4
5
|
import { createInternalAdapter } from "./internal-adapter.mjs";
|
|
5
6
|
import { getSessionDefaultFields, mergeSchema, parseAccountInput, parseAccountOutput, parseAdditionalUserInput, parseInputData, parseSessionInput, parseSessionOutput, parseUserInput, parseUserOutput } from "./schema.mjs";
|
|
6
7
|
import { FieldAttributeToSchema, toZodSchema } from "./to-zod.mjs";
|
|
7
|
-
import { getWithHooks } from "./with-hooks.mjs";
|
|
8
8
|
export * from "@better-auth/core/db";
|
|
9
|
-
export { FieldAttributeToObject, FieldAttributeToSchema, InferAdditionalFieldsFromPluginOptions, InferFieldsInputClient, InferFieldsOutput, RemoveFieldsWithReturnedFalse, convertFromDB, convertToDB, createInternalAdapter, getSchema, getSessionDefaultFields, getWithHooks, mergeSchema, parseAccountInput, parseAccountOutput, parseAdditionalUserInput, parseInputData, parseSessionInput, parseSessionOutput, parseUserInput, parseUserOutput, toZodSchema };
|
|
9
|
+
export { DatabaseHooksEntry, FieldAttributeToObject, FieldAttributeToSchema, InferAdditionalFieldsFromPluginOptions, InferFieldsInputClient, InferFieldsOutput, RemoveFieldsWithReturnedFalse, convertFromDB, convertToDB, createInternalAdapter, getSchema, getSessionDefaultFields, getWithHooks, mergeSchema, parseAccountInput, parseAccountOutput, parseAdditionalUserInput, parseInputData, parseSessionInput, parseSessionOutput, parseUserInput, parseUserOutput, toZodSchema };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DatabaseHooksEntry } from "./with-hooks.mjs";
|
|
1
2
|
import { AuthContext, BetterAuthOptions, InternalAdapter } from "@better-auth/core";
|
|
2
3
|
import { InternalLogger } from "@better-auth/core/env";
|
|
3
4
|
import { DBAdapter } from "@better-auth/core/db/adapter";
|
|
@@ -6,7 +7,7 @@ import { DBAdapter } from "@better-auth/core/db/adapter";
|
|
|
6
7
|
declare const createInternalAdapter: (adapter: DBAdapter<BetterAuthOptions>, ctx: {
|
|
7
8
|
options: Omit<BetterAuthOptions, "logger">;
|
|
8
9
|
logger: InternalLogger;
|
|
9
|
-
hooks:
|
|
10
|
+
hooks: DatabaseHooksEntry[];
|
|
10
11
|
generateId: AuthContext["generateId"];
|
|
11
12
|
}) => InternalAdapter;
|
|
12
13
|
//#endregion
|
|
@@ -198,7 +198,7 @@ const createInternalAdapter = (adapter, ctx) => {
|
|
|
198
198
|
findSession: async (token) => {
|
|
199
199
|
if (secondaryStorage) {
|
|
200
200
|
const sessionStringified = await secondaryStorage.get(token);
|
|
201
|
-
if (!sessionStringified && !options.session?.storeSessionInDatabase) return null;
|
|
201
|
+
if (!sessionStringified && (!options.session?.storeSessionInDatabase || ctx.options.session?.preserveSessionInDatabase)) return null;
|
|
202
202
|
if (sessionStringified) {
|
|
203
203
|
const s = safeJSONParse(sessionStringified);
|
|
204
204
|
if (!s) return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal-adapter.mjs","names":[],"sources":["../../src/db/internal-adapter.ts"],"sourcesContent":["import type {\n\tAuthContext,\n\tBetterAuthOptions,\n\tInternalAdapter,\n} from \"@better-auth/core\";\nimport {\n\tgetCurrentAdapter,\n\tgetCurrentAuthContext,\n\trunWithTransaction,\n} from \"@better-auth/core/context\";\nimport type { DBAdapter, Where } from \"@better-auth/core/db/adapter\";\nimport type { InternalLogger } from \"@better-auth/core/env\";\nimport { generateId } from \"@better-auth/core/utils/id\";\nimport { safeJSONParse } from \"@better-auth/core/utils/json\";\nimport type { Account, Session, User, Verification } from \"../types\";\nimport { getDate } from \"../utils/date\";\nimport { getIp } from \"../utils/get-request-ip\";\nimport {\n\tgetSessionDefaultFields,\n\tparseSessionOutput,\n\tparseUserOutput,\n} from \"./schema\";\nimport {\n\tgetStorageOption,\n\tprocessIdentifier,\n} from \"./verification-token-storage\";\nimport { getWithHooks } from \"./with-hooks\";\n\nfunction getTTLSeconds(expiresAt: Date | number, now = Date.now()): number {\n\tconst expiresMs =\n\t\ttypeof expiresAt === \"number\" ? expiresAt : expiresAt.getTime();\n\treturn Math.max(Math.floor((expiresMs - now) / 1000), 0);\n}\n\nexport const createInternalAdapter = (\n\tadapter: DBAdapter<BetterAuthOptions>,\n\tctx: {\n\t\toptions: Omit<BetterAuthOptions, \"logger\">;\n\t\tlogger: InternalLogger;\n\t\thooks: Exclude<BetterAuthOptions[\"databaseHooks\"], undefined>[];\n\t\tgenerateId: AuthContext[\"generateId\"];\n\t},\n): InternalAdapter => {\n\tconst logger = ctx.logger;\n\tconst options = ctx.options;\n\tconst secondaryStorage = options.secondaryStorage;\n\tconst sessionExpiration = options.session?.expiresIn || 60 * 60 * 24 * 7; // 7 days\n\tconst {\n\t\tcreateWithHooks,\n\t\tupdateWithHooks,\n\t\tupdateManyWithHooks,\n\t\tdeleteWithHooks,\n\t\tdeleteManyWithHooks,\n\t} = getWithHooks(adapter, ctx);\n\n\tasync function refreshUserSessions(user: User) {\n\t\tif (!secondaryStorage) return;\n\n\t\tconst listRaw = await secondaryStorage.get(`active-sessions-${user.id}`);\n\t\tif (!listRaw) return;\n\n\t\tconst now = Date.now();\n\t\tconst list =\n\t\t\tsafeJSONParse<{ token: string; expiresAt: number }[]>(listRaw) || [];\n\t\tconst validSessions = list.filter((s) => s.expiresAt > now);\n\n\t\tawait Promise.all(\n\t\t\tvalidSessions.map(async ({ token }) => {\n\t\t\t\tconst cached = await secondaryStorage.get(token);\n\t\t\t\tif (!cached) return;\n\t\t\t\tconst parsed = safeJSONParse<{ session: Session; user: User }>(cached);\n\t\t\t\tif (!parsed) return;\n\n\t\t\t\tconst sessionTTL = getTTLSeconds(parsed.session.expiresAt, now);\n\n\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\ttoken,\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\tsession: parsed.session,\n\t\t\t\t\t\tuser,\n\t\t\t\t\t}),\n\t\t\t\t\tMath.floor(sessionTTL),\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn {\n\t\tcreateOAuthUser: async (\n\t\t\tuser: Omit<User, \"id\" | \"createdAt\" | \"updatedAt\">,\n\t\t\taccount: Omit<Account, \"userId\" | \"id\" | \"createdAt\" | \"updatedAt\"> &\n\t\t\t\tPartial<Account>,\n\t\t) => {\n\t\t\treturn runWithTransaction(adapter, async () => {\n\t\t\t\tconst createdUser = await createWithHooks(\n\t\t\t\t\t{\n\t\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t...user,\n\t\t\t\t\t},\n\t\t\t\t\t\"user\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\tconst createdAccount = await createWithHooks(\n\t\t\t\t\t{\n\t\t\t\t\t\t...account,\n\t\t\t\t\t\tuserId: createdUser!.id,\n\t\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t},\n\t\t\t\t\t\"account\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tuser: createdUser,\n\t\t\t\t\taccount: createdAccount,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\tcreateUser: async <T>(\n\t\t\tuser: Omit<User, \"id\" | \"createdAt\" | \"updatedAt\" | \"emailVerified\"> &\n\t\t\t\tPartial<User> &\n\t\t\t\tRecord<string, any>,\n\t\t) => {\n\t\t\tconst createdUser = await createWithHooks(\n\t\t\t\t{\n\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t...user,\n\t\t\t\t\temail: user.email?.toLowerCase(),\n\t\t\t\t},\n\t\t\t\t\"user\",\n\t\t\t\tundefined,\n\t\t\t);\n\n\t\t\treturn createdUser as T & User;\n\t\t},\n\t\tcreateAccount: async <T extends Record<string, any>>(\n\t\t\taccount: Omit<Account, \"id\" | \"createdAt\" | \"updatedAt\"> &\n\t\t\t\tPartial<Account> &\n\t\t\t\tT,\n\t\t) => {\n\t\t\tconst createdAccount = await createWithHooks(\n\t\t\t\t{\n\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t...account,\n\t\t\t\t},\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\treturn createdAccount as T & Account;\n\t\t},\n\t\tlistSessions: async (\n\t\t\tuserId: string,\n\t\t\toptions?: { onlyActiveSessions?: boolean | undefined } | undefined,\n\t\t) => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst currentList = await secondaryStorage.get(\n\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t);\n\t\t\t\tif (!currentList) return [];\n\n\t\t\t\tconst list: { token: string; expiresAt: number }[] =\n\t\t\t\t\tsafeJSONParse(currentList) || [];\n\t\t\t\tconst now = Date.now();\n\n\t\t\t\tconst seenTokens = new Set<string>();\n\t\t\t\tconst sessions: Session[] = [];\n\n\t\t\t\tfor (const { token, expiresAt } of list) {\n\t\t\t\t\tif (expiresAt <= now || seenTokens.has(token)) continue;\n\t\t\t\t\tseenTokens.add(token);\n\n\t\t\t\t\tconst data = await secondaryStorage.get(token);\n\t\t\t\t\tif (!data) continue;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst parsed = (\n\t\t\t\t\t\t\ttypeof data === \"string\" ? JSON.parse(data) : data\n\t\t\t\t\t\t) as {\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (!parsed?.session) continue;\n\n\t\t\t\t\t\tsessions.push(\n\t\t\t\t\t\t\tparseSessionOutput(ctx.options, {\n\t\t\t\t\t\t\t\t...parsed.session,\n\t\t\t\t\t\t\t\texpiresAt: new Date(parsed.session.expiresAt),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn sessions;\n\t\t\t}\n\n\t\t\tconst sessions = await (\n\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t).findMany<Session>({\n\t\t\t\tmodel: \"session\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t\t...(options?.onlyActiveSessions\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"expiresAt\",\n\t\t\t\t\t\t\t\t\tvalue: new Date(),\n\t\t\t\t\t\t\t\t\toperator: \"gt\",\n\t\t\t\t\t\t\t\t} satisfies Where,\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn sessions;\n\t\t},\n\t\tlistUsers: async (\n\t\t\tlimit?: number | undefined,\n\t\t\toffset?: number | undefined,\n\t\t\tsortBy?:\n\t\t\t\t| {\n\t\t\t\t\t\tfield: string;\n\t\t\t\t\t\tdirection: \"asc\" | \"desc\";\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\twhere?: Where[] | undefined,\n\t\t) => {\n\t\t\tconst users = await (await getCurrentAdapter(adapter)).findMany<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\tlimit,\n\t\t\t\toffset,\n\t\t\t\tsortBy,\n\t\t\t\twhere,\n\t\t\t});\n\t\t\treturn users;\n\t\t},\n\t\tcountTotalUsers: async (where?: Where[] | undefined) => {\n\t\t\tconst total = await (await getCurrentAdapter(adapter)).count({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere,\n\t\t\t});\n\t\t\tif (typeof total === \"string\") {\n\t\t\t\treturn parseInt(total);\n\t\t\t}\n\t\t\treturn total;\n\t\t},\n\t\tdeleteUser: async (userId: string) => {\n\t\t\tif (!secondaryStorage || options.session?.storeSessionInDatabase) {\n\t\t\t\tawait deleteManyWithHooks(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t\"session\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait deleteManyWithHooks(\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\n\t\t\tawait deleteWithHooks(\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"user\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tcreateSession: async (\n\t\t\tuserId: string,\n\t\t\tdontRememberMe?: boolean | undefined,\n\t\t\toverride?: (Partial<Session> & Record<string, any>) | undefined,\n\t\t\toverrideAll?: boolean | undefined,\n\t\t) => {\n\t\t\tconst headers: Headers | undefined = await (async () => {\n\t\t\t\tconst ctx = await getCurrentAuthContext().catch(() => null);\n\t\t\t\treturn ctx?.headers || ctx?.request?.headers;\n\t\t\t})();\n\t\t\tconst storeInDb = options.session?.storeSessionInDatabase;\n\t\t\tconst {\n\t\t\t\t// always ignore override id - new sessions must have new ids\n\t\t\t\tid: _,\n\t\t\t\t...rest\n\t\t\t} = override || {};\n\n\t\t\t// we're parsing default values for session additional fields\n\t\t\tconst defaultAdditionalFields = getSessionDefaultFields(options);\n\t\t\tconst data = {\n\t\t\t\tipAddress: headers ? getIp(headers, options) || \"\" : \"\",\n\t\t\t\tuserAgent: headers?.get(\"user-agent\") || \"\",\n\t\t\t\t...rest,\n\t\t\t\t/**\n\t\t\t\t * If the user doesn't want to be remembered\n\t\t\t\t * set the session to expire in 1 day.\n\t\t\t\t * The cookie will be set to expire at the end of the session\n\t\t\t\t */\n\t\t\t\texpiresAt: dontRememberMe\n\t\t\t\t\t? getDate(60 * 60 * 24, \"sec\") // 1 day\n\t\t\t\t\t: getDate(sessionExpiration, \"sec\"),\n\t\t\t\tuserId,\n\t\t\t\ttoken: generateId(32),\n\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\tcreatedAt: new Date(),\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t...defaultAdditionalFields,\n\t\t\t\t...(overrideAll ? rest : {}),\n\t\t\t} satisfies Partial<Session>;\n\t\t\tconst res = await createWithHooks(\n\t\t\t\tdata,\n\t\t\t\t\"session\",\n\t\t\t\tsecondaryStorage\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tfn: async (sessionData) => {\n\t\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t\t * store the session token for the user\n\t\t\t\t\t\t\t\t * so we can retrieve it later for listing sessions\n\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\tconst currentList = await secondaryStorage.get(\n\t\t\t\t\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tlet list: { token: string; expiresAt: number }[] = [];\n\t\t\t\t\t\t\t\tconst now = Date.now();\n\n\t\t\t\t\t\t\t\tif (currentList) {\n\t\t\t\t\t\t\t\t\tlist = safeJSONParse(currentList) || [];\n\t\t\t\t\t\t\t\t\tlist = list.filter(\n\t\t\t\t\t\t\t\t\t\t(session) =>\n\t\t\t\t\t\t\t\t\t\t\tsession.expiresAt > now && session.token !== data.token,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst sorted = [\n\t\t\t\t\t\t\t\t\t...list,\n\t\t\t\t\t\t\t\t\t{ token: data.token, expiresAt: data.expiresAt.getTime() },\n\t\t\t\t\t\t\t\t].sort((a, b) => a.expiresAt - b.expiresAt);\n\t\t\t\t\t\t\t\tconst furthestSessionExp =\n\t\t\t\t\t\t\t\t\tsorted.at(-1)?.expiresAt ?? data.expiresAt.getTime();\n\t\t\t\t\t\t\t\tconst furthestSessionTTL = getTTLSeconds(\n\t\t\t\t\t\t\t\t\tfurthestSessionExp,\n\t\t\t\t\t\t\t\t\tnow,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (furthestSessionTTL > 0) {\n\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t\t\t\t\t\t\tJSON.stringify(sorted),\n\t\t\t\t\t\t\t\t\t\tfurthestSessionTTL,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst user = await (\n\t\t\t\t\t\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t\t\t\t\t\t).findOne<User>({\n\t\t\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tconst sessionTTL = getTTLSeconds(data.expiresAt, now);\n\t\t\t\t\t\t\t\tif (sessionTTL > 0) {\n\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\tdata.token,\n\t\t\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t\t\tsession: sessionData,\n\t\t\t\t\t\t\t\t\t\t\tuser,\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\tsessionTTL,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn sessionData;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\texecuteMainFn: storeInDb,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t\treturn res as Session;\n\t\t},\n\t\tfindSession: async (\n\t\t\ttoken: string,\n\t\t): Promise<{\n\t\t\tsession: Session & Record<string, any>;\n\t\t\tuser: User & Record<string, any>;\n\t\t} | null> => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst sessionStringified = await secondaryStorage.get(token);\n\t\t\t\tif (!sessionStringified && !options.session?.storeSessionInDatabase) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (sessionStringified) {\n\t\t\t\t\tconst s = safeJSONParse<{\n\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\tuser: User;\n\t\t\t\t\t}>(sessionStringified);\n\t\t\t\t\tif (!s) return null;\n\t\t\t\t\tconst parsedSession = parseSessionOutput(ctx.options, {\n\t\t\t\t\t\t...s.session,\n\t\t\t\t\t\texpiresAt: new Date(s.session.expiresAt),\n\t\t\t\t\t\tcreatedAt: new Date(s.session.createdAt),\n\t\t\t\t\t\tupdatedAt: new Date(s.session.updatedAt),\n\t\t\t\t\t});\n\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.options, {\n\t\t\t\t\t\t...s.user,\n\t\t\t\t\t\tcreatedAt: new Date(s.user.createdAt),\n\t\t\t\t\t\tupdatedAt: new Date(s.user.updatedAt),\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst currentAdapter = await getCurrentAdapter(adapter);\n\t\t\tconst result = await currentAdapter.findOne<\n\t\t\t\tSession & { user: User | null }\n\t\t\t>({\n\t\t\t\tmodel: \"session\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: token,\n\t\t\t\t\t\tfield: \"token\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tjoin: {\n\t\t\t\t\tuser: true,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (!result) return null;\n\n\t\t\tconst { user, ...session } = result;\n\t\t\tif (!user) return null;\n\t\t\tconst parsedSession = parseSessionOutput(ctx.options, session);\n\t\t\tconst parsedUser = parseUserOutput(ctx.options, user);\n\t\t\treturn {\n\t\t\t\tsession: parsedSession,\n\t\t\t\tuser: parsedUser,\n\t\t\t};\n\t\t},\n\t\tfindSessions: async (\n\t\t\tsessionTokens: string[],\n\t\t\toptions?:\n\t\t\t\t| {\n\t\t\t\t\t\tonlyActiveSessions?: boolean | undefined;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t) => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst sessions: {\n\t\t\t\t\tsession: Session;\n\t\t\t\t\tuser: User;\n\t\t\t\t}[] = [];\n\t\t\t\tfor (const sessionToken of sessionTokens) {\n\t\t\t\t\tconst sessionStringified = await secondaryStorage.get(sessionToken);\n\t\t\t\t\tif (sessionStringified) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst s = (\n\t\t\t\t\t\t\t\ttypeof sessionStringified === \"string\"\n\t\t\t\t\t\t\t\t\t? JSON.parse(sessionStringified)\n\t\t\t\t\t\t\t\t\t: sessionStringified\n\t\t\t\t\t\t\t) as {\n\t\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tif (!s) return [];\n\t\t\t\t\t\t\tconst expiresAt = new Date(s.session.expiresAt);\n\t\t\t\t\t\t\tif (options?.onlyActiveSessions && expiresAt <= new Date()) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst session = {\n\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t...s.session,\n\t\t\t\t\t\t\t\t\texpiresAt: new Date(s.session.expiresAt),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t...s.user,\n\t\t\t\t\t\t\t\t\tcreatedAt: new Date(s.user.createdAt),\n\t\t\t\t\t\t\t\t\tupdatedAt: new Date(s.user.updatedAt),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tsessions.push(session);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Skip invalid/corrupt session data\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn sessions;\n\t\t\t}\n\n\t\t\tconst sessions = await (await getCurrentAdapter(adapter)).findMany<\n\t\t\t\tSession & { user: User | null }\n\t\t\t>({\n\t\t\t\tmodel: \"session\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"token\",\n\t\t\t\t\t\tvalue: sessionTokens,\n\t\t\t\t\t\toperator: \"in\",\n\t\t\t\t\t},\n\t\t\t\t\t...(options?.onlyActiveSessions\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"expiresAt\",\n\t\t\t\t\t\t\t\t\tvalue: new Date(),\n\t\t\t\t\t\t\t\t\toperator: \"gt\",\n\t\t\t\t\t\t\t\t} satisfies Where,\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t\tjoin: {\n\t\t\t\t\tuser: true,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (!sessions.length) return [];\n\t\t\tif (sessions.some((session) => !session.user)) return [];\n\n\t\t\treturn sessions.map((_session) => {\n\t\t\t\tconst { user, ...session } = _session;\n\t\t\t\treturn {\n\t\t\t\t\tsession,\n\t\t\t\t\tuser: user!,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\tupdateSession: async (\n\t\t\tsessionToken: string,\n\t\t\tsession: Partial<Session> & Record<string, any>,\n\t\t) => {\n\t\t\tconst updatedSession = await updateWithHooks<Session>(\n\t\t\t\tsession,\n\t\t\t\t[{ field: \"token\", value: sessionToken }],\n\t\t\t\t\"session\",\n\t\t\t\tsecondaryStorage\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tasync fn(data) {\n\t\t\t\t\t\t\t\tconst currentSession = await secondaryStorage.get(sessionToken);\n\t\t\t\t\t\t\t\tif (!currentSession) {\n\t\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst parsedSession = safeJSONParse<{\n\t\t\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\t\t}>(currentSession);\n\t\t\t\t\t\t\t\tif (!parsedSession) return null;\n\n\t\t\t\t\t\t\t\tconst mergedSession = {\n\t\t\t\t\t\t\t\t\t...parsedSession.session,\n\t\t\t\t\t\t\t\t\t...data,\n\t\t\t\t\t\t\t\t\texpiresAt: new Date(\n\t\t\t\t\t\t\t\t\t\tdata.expiresAt ?? parsedSession.session.expiresAt,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tcreatedAt: new Date(parsedSession.session.createdAt),\n\t\t\t\t\t\t\t\t\tupdatedAt: new Date(\n\t\t\t\t\t\t\t\t\t\tdata.updatedAt ?? parsedSession.session.updatedAt,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tconst updatedSession = parseSessionOutput(\n\t\t\t\t\t\t\t\t\tctx.options,\n\t\t\t\t\t\t\t\t\tmergedSession,\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tconst now = Date.now();\n\t\t\t\t\t\t\t\tconst expiresMs = new Date(updatedSession.expiresAt).getTime();\n\t\t\t\t\t\t\t\tconst sessionTTL = getTTLSeconds(expiresMs, now);\n\n\t\t\t\t\t\t\t\tif (sessionTTL > 0) {\n\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\tsessionToken,\n\t\t\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t\t\tsession: updatedSession,\n\t\t\t\t\t\t\t\t\t\t\tuser: parsedSession.user,\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\tsessionTTL,\n\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\tconst listKey = `active-sessions-${updatedSession.userId}`;\n\t\t\t\t\t\t\t\t\tconst listRaw = await secondaryStorage.get(listKey);\n\t\t\t\t\t\t\t\t\tconst list: { token: string; expiresAt: number }[] = listRaw\n\t\t\t\t\t\t\t\t\t\t? safeJSONParse(listRaw) || []\n\t\t\t\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\t\t\t\t\tconst filtered = list\n\t\t\t\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t\t\t\t(s) => s.token !== sessionToken && s.expiresAt > now,\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t.concat([{ token: sessionToken, expiresAt: expiresMs }]);\n\n\t\t\t\t\t\t\t\t\tconst sorted = filtered.sort(\n\t\t\t\t\t\t\t\t\t\t(a, b) => a.expiresAt - b.expiresAt,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tconst furthestSessionExp = sorted.at(-1)?.expiresAt;\n\n\t\t\t\t\t\t\t\t\tif (furthestSessionExp && furthestSessionExp > now) {\n\t\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\t\tlistKey,\n\t\t\t\t\t\t\t\t\t\t\tJSON.stringify(sorted),\n\t\t\t\t\t\t\t\t\t\t\tgetTTLSeconds(furthestSessionExp, now),\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tawait secondaryStorage.delete(listKey);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn updatedSession;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\texecuteMainFn: options.session?.storeSessionInDatabase,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t\treturn updatedSession;\n\t\t},\n\t\tdeleteSession: async (token: string) => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\t// remove the session from the active sessions list\n\t\t\t\tconst data = await secondaryStorage.get(token);\n\t\t\t\tif (data) {\n\t\t\t\t\tconst { session } =\n\t\t\t\t\t\tsafeJSONParse<{\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t}>(data) ?? {};\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\tlogger.error(\"Session not found in secondary storage\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst userId = session.userId;\n\n\t\t\t\t\tconst currentList = await secondaryStorage.get(\n\t\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t\t);\n\t\t\t\t\tif (currentList) {\n\t\t\t\t\t\tconst list: { token: string; expiresAt: number }[] =\n\t\t\t\t\t\t\tsafeJSONParse(currentList) || [];\n\t\t\t\t\t\tconst now = Date.now();\n\n\t\t\t\t\t\tconst filtered = list.filter(\n\t\t\t\t\t\t\t(session) => session.expiresAt > now && session.token !== token,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst sorted = filtered.sort((a, b) => a.expiresAt - b.expiresAt);\n\t\t\t\t\t\tconst furthestSessionExp = sorted.at(-1)?.expiresAt;\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tfiltered.length > 0 &&\n\t\t\t\t\t\t\tfurthestSessionExp &&\n\t\t\t\t\t\t\tfurthestSessionExp > Date.now()\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t\t\t\t\tJSON.stringify(filtered),\n\t\t\t\t\t\t\t\tgetTTLSeconds(furthestSessionExp, now),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait secondaryStorage.delete(`active-sessions-${userId}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.error(\"Active sessions list not found in secondary storage\");\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tawait secondaryStorage.delete(token);\n\n\t\t\t\tif (\n\t\t\t\t\t!options.session?.storeSessionInDatabase ||\n\t\t\t\t\tctx.options.session?.preserveSessionInDatabase\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait deleteWithHooks(\n\t\t\t\t[{ field: \"token\", value: token }],\n\t\t\t\t\"session\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tdeleteAccounts: async (userId: string) => {\n\t\t\tawait deleteManyWithHooks(\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tdeleteAccount: async (accountId: string) => {\n\t\t\tawait deleteWithHooks(\n\t\t\t\t[{ field: \"id\", value: accountId }],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tdeleteSessions: async (userIdOrSessionTokens: string | string[]) => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\tif (typeof userIdOrSessionTokens === \"string\") {\n\t\t\t\t\tconst activeSession = await secondaryStorage.get(\n\t\t\t\t\t\t`active-sessions-${userIdOrSessionTokens}`,\n\t\t\t\t\t);\n\t\t\t\t\tconst sessions = activeSession\n\t\t\t\t\t\t? safeJSONParse<{ token: string }[]>(activeSession)\n\t\t\t\t\t\t: [];\n\t\t\t\t\tif (!sessions) return;\n\t\t\t\t\tfor (const session of sessions) {\n\t\t\t\t\t\tawait secondaryStorage.delete(session.token);\n\t\t\t\t\t}\n\t\t\t\t\tawait secondaryStorage.delete(\n\t\t\t\t\t\t`active-sessions-${userIdOrSessionTokens}`,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tfor (const sessionToken of userIdOrSessionTokens) {\n\t\t\t\t\t\tconst session = await secondaryStorage.get(sessionToken);\n\t\t\t\t\t\tif (session) {\n\t\t\t\t\t\t\tawait secondaryStorage.delete(sessionToken);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t!options.session?.storeSessionInDatabase ||\n\t\t\t\t\tctx.options.session?.preserveSessionInDatabase\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait deleteManyWithHooks(\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: Array.isArray(userIdOrSessionTokens) ? \"token\" : \"userId\",\n\t\t\t\t\t\tvalue: userIdOrSessionTokens,\n\t\t\t\t\t\toperator: Array.isArray(userIdOrSessionTokens) ? \"in\" : undefined,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"session\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tfindOAuthUser: async (\n\t\t\temail: string,\n\t\t\taccountId: string,\n\t\t\tproviderId: string,\n\t\t) => {\n\t\t\t// we need to find account first to avoid missing user if the email changed with the provider for the same account\n\t\t\tconst account = await (await getCurrentAdapter(adapter)).findOne<\n\t\t\t\tAccount & { user: User | null }\n\t\t\t>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: accountId,\n\t\t\t\t\t\tfield: \"accountId\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: providerId,\n\t\t\t\t\t\tfield: \"providerId\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tjoin: {\n\t\t\t\t\tuser: true,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (account) {\n\t\t\t\tif (account.user) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tuser: account.user,\n\t\t\t\t\t\tlinkedAccount: account,\n\t\t\t\t\t\taccounts: [account],\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tconst user = await (await getCurrentAdapter(adapter)).findOne<User>({\n\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: email.toLowerCase(),\n\t\t\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\tif (user) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tuser,\n\t\t\t\t\t\t\tlinkedAccount: account,\n\t\t\t\t\t\t\taccounts: [account],\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst user = await (await getCurrentAdapter(adapter)).findOne<User>({\n\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: email.toLowerCase(),\n\t\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tif (user) {\n\t\t\t\t\tconst accounts = await (\n\t\t\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t\t\t).findMany<Account>({\n\t\t\t\t\t\tmodel: \"account\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\tuser,\n\t\t\t\t\t\tlinkedAccount: null,\n\t\t\t\t\t\taccounts: accounts || [],\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tfindUserByEmail: async (\n\t\t\temail: string,\n\t\t\toptions?: { includeAccounts: boolean } | undefined,\n\t\t) => {\n\t\t\tconst currentAdapter = await getCurrentAdapter(adapter);\n\t\t\tconst result = await currentAdapter.findOne<\n\t\t\t\tUser & { account: Account[] | undefined }\n\t\t\t>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: email.toLowerCase(),\n\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tjoin: {\n\t\t\t\t\t...(options?.includeAccounts ? { account: true } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (!result) return null;\n\t\t\tconst { account: accounts, ...user } = result;\n\t\t\treturn {\n\t\t\t\tuser,\n\t\t\t\taccounts: accounts ?? [],\n\t\t\t};\n\t\t},\n\t\tfindUserById: async (userId: string) => {\n\t\t\tif (!userId) return null;\n\t\t\tconst user = await (await getCurrentAdapter(adapter)).findOne<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn user;\n\t\t},\n\t\tlinkAccount: async (\n\t\t\taccount: Omit<Account, \"id\" | \"createdAt\" | \"updatedAt\"> &\n\t\t\t\tPartial<Account>,\n\t\t) => {\n\t\t\tconst _account = await createWithHooks(\n\t\t\t\t{\n\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t...account,\n\t\t\t\t},\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\treturn _account;\n\t\t},\n\t\tupdateUser: async (\n\t\t\tuserId: string,\n\t\t\tdata: Partial<User> & Record<string, any>,\n\t\t) => {\n\t\t\tconst user = await updateWithHooks<User>(\n\t\t\t\tdata,\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"user\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tawait refreshUserSessions(user);\n\t\t\treturn user;\n\t\t},\n\t\tupdateUserByEmail: async (\n\t\t\temail: string,\n\t\t\tdata: Partial<User & Record<string, any>>,\n\t\t) => {\n\t\t\tconst user = await updateWithHooks<User>(\n\t\t\t\tdata,\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t\tvalue: email.toLowerCase(),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"user\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tawait refreshUserSessions(user);\n\t\t\treturn user;\n\t\t},\n\t\tupdatePassword: async (userId: string, password: string) => {\n\t\t\tawait updateManyWithHooks(\n\t\t\t\t{\n\t\t\t\t\tpassword,\n\t\t\t\t},\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"providerId\",\n\t\t\t\t\t\tvalue: \"credential\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tfindAccounts: async (userId: string) => {\n\t\t\tconst accounts = await (\n\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t).findMany<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn accounts;\n\t\t},\n\t\tfindAccount: async (accountId: string) => {\n\t\t\tconst account = await (await getCurrentAdapter(adapter)).findOne<Account>(\n\t\t\t\t{\n\t\t\t\t\tmodel: \"account\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"accountId\",\n\t\t\t\t\t\t\tvalue: accountId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn account;\n\t\t},\n\t\tfindAccountByProviderId: async (accountId: string, providerId: string) => {\n\t\t\tconst account = await (await getCurrentAdapter(adapter)).findOne<Account>(\n\t\t\t\t{\n\t\t\t\t\tmodel: \"account\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"accountId\",\n\t\t\t\t\t\t\tvalue: accountId,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"providerId\",\n\t\t\t\t\t\t\tvalue: providerId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn account;\n\t\t},\n\t\tfindAccountByUserId: async (userId: string) => {\n\t\t\tconst account = await (\n\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t).findMany<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn account;\n\t\t},\n\t\tupdateAccount: async (id: string, data: Partial<Account>) => {\n\t\t\tconst account = await updateWithHooks<Account>(\n\t\t\t\tdata,\n\t\t\t\t[{ field: \"id\", value: id }],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\treturn account;\n\t\t},\n\t\tcreateVerificationValue: async (\n\t\t\tdata: Omit<Verification, \"createdAt\" | \"id\" | \"updatedAt\"> &\n\t\t\t\tPartial<Verification>,\n\t\t) => {\n\t\t\tconst storageOption = getStorageOption(\n\t\t\t\tdata.identifier,\n\t\t\t\toptions.verification?.storeIdentifier,\n\t\t\t);\n\t\t\tconst storedIdentifier = await processIdentifier(\n\t\t\t\tdata.identifier,\n\t\t\t\tstorageOption,\n\t\t\t);\n\n\t\t\tconst verification = await createWithHooks(\n\t\t\t\t{\n\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t...data,\n\t\t\t\t\tidentifier: storedIdentifier,\n\t\t\t\t},\n\t\t\t\t\"verification\",\n\t\t\t\tsecondaryStorage\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tasync fn(verificationData) {\n\t\t\t\t\t\t\t\tconst ttl = getTTLSeconds(verificationData.expiresAt);\n\t\t\t\t\t\t\t\tif (ttl > 0) {\n\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\t`verification:${storedIdentifier}`,\n\t\t\t\t\t\t\t\t\t\tJSON.stringify(verificationData),\n\t\t\t\t\t\t\t\t\t\tttl,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn verificationData;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\texecuteMainFn: options.verification?.storeInDatabase,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t\treturn verification as Verification;\n\t\t},\n\t\tfindVerificationValue: async (identifier: string) => {\n\t\t\tconst storageOption = getStorageOption(\n\t\t\t\tidentifier,\n\t\t\t\toptions.verification?.storeIdentifier,\n\t\t\t);\n\t\t\tconst storedIdentifier = await processIdentifier(\n\t\t\t\tidentifier,\n\t\t\t\tstorageOption,\n\t\t\t);\n\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst cached = await secondaryStorage.get(\n\t\t\t\t\t`verification:${storedIdentifier}`,\n\t\t\t\t);\n\t\t\t\tif (cached) {\n\t\t\t\t\tconst parsed = safeJSONParse<Verification>(cached);\n\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\treturn parsed;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (storageOption && storageOption !== \"plain\") {\n\t\t\t\t\tconst plainCached = await secondaryStorage.get(\n\t\t\t\t\t\t`verification:${identifier}`,\n\t\t\t\t\t);\n\t\t\t\t\tif (plainCached) {\n\t\t\t\t\t\tconst parsed = safeJSONParse<Verification>(plainCached);\n\t\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\t\treturn parsed;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!options.verification?.storeInDatabase) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst currentAdapter = await getCurrentAdapter(adapter);\n\n\t\t\tasync function findByIdentifier(id: string) {\n\t\t\t\treturn currentAdapter.findMany<Verification>({\n\t\t\t\t\tmodel: \"verification\",\n\t\t\t\t\twhere: [{ field: \"identifier\", value: id }],\n\t\t\t\t\tsortBy: { field: \"createdAt\", direction: \"desc\" },\n\t\t\t\t\tlimit: 1,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet verification = await findByIdentifier(storedIdentifier);\n\n\t\t\tif (!verification.length && storageOption && storageOption !== \"plain\") {\n\t\t\t\tverification = await findByIdentifier(identifier);\n\t\t\t}\n\n\t\t\tif (!options.verification?.disableCleanup) {\n\t\t\t\tawait deleteManyWithHooks(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"expiresAt\",\n\t\t\t\t\t\t\tvalue: new Date(),\n\t\t\t\t\t\t\toperator: \"lt\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t\"verification\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn (verification[0] as Verification) || null;\n\t\t},\n\t\tdeleteVerificationByIdentifier: async (identifier: string) => {\n\t\t\tconst storageOption = getStorageOption(\n\t\t\t\tidentifier,\n\t\t\t\toptions.verification?.storeIdentifier,\n\t\t\t);\n\t\t\tconst storedIdentifier = await processIdentifier(\n\t\t\t\tidentifier,\n\t\t\t\tstorageOption,\n\t\t\t);\n\n\t\t\tif (secondaryStorage) {\n\t\t\t\tawait secondaryStorage.delete(`verification:${storedIdentifier}`);\n\t\t\t}\n\n\t\t\tif (!secondaryStorage || options.verification?.storeInDatabase) {\n\t\t\t\tawait deleteWithHooks(\n\t\t\t\t\t[{ field: \"identifier\", value: storedIdentifier }],\n\t\t\t\t\t\"verification\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t\tupdateVerificationByIdentifier: async (\n\t\t\tidentifier: string,\n\t\t\tdata: Partial<Verification>,\n\t\t) => {\n\t\t\tconst storageOption = getStorageOption(\n\t\t\t\tidentifier,\n\t\t\t\toptions.verification?.storeIdentifier,\n\t\t\t);\n\t\t\tconst storedIdentifier = await processIdentifier(\n\t\t\t\tidentifier,\n\t\t\t\tstorageOption,\n\t\t\t);\n\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst cached = await secondaryStorage.get(\n\t\t\t\t\t`verification:${storedIdentifier}`,\n\t\t\t\t);\n\t\t\t\tif (cached) {\n\t\t\t\t\tconst parsed = safeJSONParse<Verification>(cached);\n\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\tconst updated = { ...parsed, ...data };\n\t\t\t\t\t\tconst expiresAt = updated.expiresAt ?? parsed.expiresAt;\n\t\t\t\t\t\tconst ttl = getTTLSeconds(\n\t\t\t\t\t\t\texpiresAt instanceof Date ? expiresAt : new Date(expiresAt),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (ttl > 0) {\n\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t`verification:${storedIdentifier}`,\n\t\t\t\t\t\t\t\tJSON.stringify(updated),\n\t\t\t\t\t\t\t\tttl,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!options.verification?.storeInDatabase) {\n\t\t\t\t\t\t\treturn updated;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!secondaryStorage || options.verification?.storeInDatabase) {\n\t\t\t\tconst verification = await updateWithHooks<Verification>(\n\t\t\t\t\tdata,\n\t\t\t\t\t[{ field: \"identifier\", value: storedIdentifier }],\n\t\t\t\t\t\"verification\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\treturn verification;\n\t\t\t}\n\t\t\treturn data as Verification;\n\t\t},\n\t};\n};\n"],"mappings":";;;;;;;;;;AA4BA,SAAS,cAAc,WAA0B,MAAM,KAAK,KAAK,EAAU;CAC1E,MAAM,YACL,OAAO,cAAc,WAAW,YAAY,UAAU,SAAS;AAChE,QAAO,KAAK,IAAI,KAAK,OAAO,YAAY,OAAO,IAAK,EAAE,EAAE;;AAGzD,MAAa,yBACZ,SACA,QAMqB;CACrB,MAAM,SAAS,IAAI;CACnB,MAAM,UAAU,IAAI;CACpB,MAAM,mBAAmB,QAAQ;CACjC,MAAM,oBAAoB,QAAQ,SAAS,aAAa,OAAU,KAAK;CACvE,MAAM,EACL,iBACA,iBACA,qBACA,iBACA,wBACG,aAAa,SAAS,IAAI;CAE9B,eAAe,oBAAoB,MAAY;AAC9C,MAAI,CAAC,iBAAkB;EAEvB,MAAM,UAAU,MAAM,iBAAiB,IAAI,mBAAmB,KAAK,KAAK;AACxE,MAAI,CAAC,QAAS;EAEd,MAAM,MAAM,KAAK,KAAK;EAGtB,MAAM,iBADL,cAAsD,QAAQ,IAAI,EAAE,EAC1C,QAAQ,MAAM,EAAE,YAAY,IAAI;AAE3D,QAAM,QAAQ,IACb,cAAc,IAAI,OAAO,EAAE,YAAY;GACtC,MAAM,SAAS,MAAM,iBAAiB,IAAI,MAAM;AAChD,OAAI,CAAC,OAAQ;GACb,MAAM,SAAS,cAAgD,OAAO;AACtE,OAAI,CAAC,OAAQ;GAEb,MAAM,aAAa,cAAc,OAAO,QAAQ,WAAW,IAAI;AAE/D,SAAM,iBAAiB,IACtB,OACA,KAAK,UAAU;IACd,SAAS,OAAO;IAChB;IACA,CAAC,EACF,KAAK,MAAM,WAAW,CACtB;IACA,CACF;;AAGF,QAAO;EACN,iBAAiB,OAChB,MACA,YAEI;AACJ,UAAO,mBAAmB,SAAS,YAAY;IAC9C,MAAM,cAAc,MAAM,gBACzB;KAEC,2BAAW,IAAI,MAAM;KACrB,2BAAW,IAAI,MAAM;KACrB,GAAG;KACH,EACD,QACA,OACA;AAYD,WAAO;KACN,MAAM;KACN,SAbsB,MAAM,gBAC5B;MACC,GAAG;MACH,QAAQ,YAAa;MAErB,2BAAW,IAAI,MAAM;MACrB,2BAAW,IAAI,MAAM;MACrB,EACD,WACA,OACA;KAIA;KACA;;EAEH,YAAY,OACX,SAGI;AAaJ,UAZoB,MAAM,gBACzB;IAEC,2BAAW,IAAI,MAAM;IACrB,2BAAW,IAAI,MAAM;IACrB,GAAG;IACH,OAAO,KAAK,OAAO,aAAa;IAChC,EACD,QACA,OACA;;EAIF,eAAe,OACd,YAGI;AAWJ,UAVuB,MAAM,gBAC5B;IAEC,2BAAW,IAAI,MAAM;IACrB,2BAAW,IAAI,MAAM;IACrB,GAAG;IACH,EACD,WACA,OACA;;EAGF,cAAc,OACb,QACA,YACI;AACJ,OAAI,kBAAkB;IACrB,MAAM,cAAc,MAAM,iBAAiB,IAC1C,mBAAmB,SACnB;AACD,QAAI,CAAC,YAAa,QAAO,EAAE;IAE3B,MAAM,OACL,cAAc,YAAY,IAAI,EAAE;IACjC,MAAM,MAAM,KAAK,KAAK;IAEtB,MAAM,6BAAa,IAAI,KAAa;IACpC,MAAM,WAAsB,EAAE;AAE9B,SAAK,MAAM,EAAE,OAAO,eAAe,MAAM;AACxC,SAAI,aAAa,OAAO,WAAW,IAAI,MAAM,CAAE;AAC/C,gBAAW,IAAI,MAAM;KAErB,MAAM,OAAO,MAAM,iBAAiB,IAAI,MAAM;AAC9C,SAAI,CAAC,KAAM;AAEX,SAAI;MACH,MAAM,SACL,OAAO,SAAS,WAAW,KAAK,MAAM,KAAK,GAAG;AAK/C,UAAI,CAAC,QAAQ,QAAS;AAEtB,eAAS,KACR,mBAAmB,IAAI,SAAS;OAC/B,GAAG,OAAO;OACV,WAAW,IAAI,KAAK,OAAO,QAAQ,UAAU;OAC7C,CAAC,CACF;aACM;AACP;;;AAGF,WAAO;;AAuBR,UApBiB,OAChB,MAAM,kBAAkB,QAAQ,EAC/B,SAAkB;IACnB,OAAO;IACP,OAAO,CACN;KACC,OAAO;KACP,OAAO;KACP,EACD,GAAI,SAAS,qBACV,CACA;KACC,OAAO;KACP,uBAAO,IAAI,MAAM;KACjB,UAAU;KACV,CACD,GACA,EAAE,CACL;IACD,CAAC;;EAGH,WAAW,OACV,OACA,QACA,QAMA,UACI;AAQJ,UAPc,OAAO,MAAM,kBAAkB,QAAQ,EAAE,SAAe;IACrE,OAAO;IACP;IACA;IACA;IACA;IACA,CAAC;;EAGH,iBAAiB,OAAO,UAAgC;GACvD,MAAM,QAAQ,OAAO,MAAM,kBAAkB,QAAQ,EAAE,MAAM;IAC5D,OAAO;IACP;IACA,CAAC;AACF,OAAI,OAAO,UAAU,SACpB,QAAO,SAAS,MAAM;AAEvB,UAAO;;EAER,YAAY,OAAO,WAAmB;AACrC,OAAI,CAAC,oBAAoB,QAAQ,SAAS,uBACzC,OAAM,oBACL,CACC;IACC,OAAO;IACP,OAAO;IACP,CACD,EACD,WACA,OACA;AAEF,SAAM,oBACL,CACC;IACC,OAAO;IACP,OAAO;IACP,CACD,EACD,WACA,OACA;AAED,SAAM,gBACL,CACC;IACC,OAAO;IACP,OAAO;IACP,CACD,EACD,QACA,OACA;;EAEF,eAAe,OACd,QACA,gBACA,UACA,gBACI;GACJ,MAAM,UAA+B,OAAO,YAAY;IACvD,MAAM,MAAM,MAAM,uBAAuB,CAAC,YAAY,KAAK;AAC3D,WAAO,KAAK,WAAW,KAAK,SAAS;OAClC;GACJ,MAAM,YAAY,QAAQ,SAAS;GACnC,MAAM,EAEL,IAAI,GACJ,GAAG,SACA,YAAY,EAAE;GAGlB,MAAM,0BAA0B,wBAAwB,QAAQ;GAChE,MAAM,OAAO;IACZ,WAAW,UAAU,MAAM,SAAS,QAAQ,IAAI,KAAK;IACrD,WAAW,SAAS,IAAI,aAAa,IAAI;IACzC,GAAG;IAMH,WAAW,iBACR,QAAQ,OAAU,IAAI,MAAM,GAC5B,QAAQ,mBAAmB,MAAM;IACpC;IACA,OAAO,WAAW,GAAG;IAErB,2BAAW,IAAI,MAAM;IACrB,2BAAW,IAAI,MAAM;IACrB,GAAG;IACH,GAAI,cAAc,OAAO,EAAE;IAC3B;AAyED,UAxEY,MAAM,gBACjB,MACA,WACA,mBACG;IACA,IAAI,OAAO,gBAAgB;;;;;KAK1B,MAAM,cAAc,MAAM,iBAAiB,IAC1C,mBAAmB,SACnB;KAED,IAAI,OAA+C,EAAE;KACrD,MAAM,MAAM,KAAK,KAAK;AAEtB,SAAI,aAAa;AAChB,aAAO,cAAc,YAAY,IAAI,EAAE;AACvC,aAAO,KAAK,QACV,YACA,QAAQ,YAAY,OAAO,QAAQ,UAAU,KAAK,MACnD;;KAGF,MAAM,SAAS,CACd,GAAG,MACH;MAAE,OAAO,KAAK;MAAO,WAAW,KAAK,UAAU,SAAS;MAAE,CAC1D,CAAC,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,UAAU;KAG3C,MAAM,qBAAqB,cAD1B,OAAO,GAAG,GAAG,EAAE,aAAa,KAAK,UAAU,SAAS,EAGpD,IACA;AACD,SAAI,qBAAqB,EACxB,OAAM,iBAAiB,IACtB,mBAAmB,UACnB,KAAK,UAAU,OAAO,EACtB,mBACA;KAGF,MAAM,OAAO,OACZ,MAAM,kBAAkB,QAAQ,EAC/B,QAAc;MACf,OAAO;MACP,OAAO,CACN;OACC,OAAO;OACP,OAAO;OACP,CACD;MACD,CAAC;KACF,MAAM,aAAa,cAAc,KAAK,WAAW,IAAI;AACrD,SAAI,aAAa,EAChB,OAAM,iBAAiB,IACtB,KAAK,OACL,KAAK,UAAU;MACd,SAAS;MACT;MACA,CAAC,EACF,WACA;AAGF,YAAO;;IAER,eAAe;IACf,GACA,OACH;;EAGF,aAAa,OACZ,UAIY;AACZ,OAAI,kBAAkB;IACrB,MAAM,qBAAqB,MAAM,iBAAiB,IAAI,MAAM;AAC5D,QAAI,CAAC,sBAAsB,CAAC,QAAQ,SAAS,uBAC5C,QAAO;AAER,QAAI,oBAAoB;KACvB,MAAM,IAAI,cAGP,mBAAmB;AACtB,SAAI,CAAC,EAAG,QAAO;AAYf,YAAO;MACN,SAZqB,mBAAmB,IAAI,SAAS;OACrD,GAAG,EAAE;OACL,WAAW,IAAI,KAAK,EAAE,QAAQ,UAAU;OACxC,WAAW,IAAI,KAAK,EAAE,QAAQ,UAAU;OACxC,WAAW,IAAI,KAAK,EAAE,QAAQ,UAAU;OACxC,CAAC;MAQD,MAPkB,gBAAgB,IAAI,SAAS;OAC/C,GAAG,EAAE;OACL,WAAW,IAAI,KAAK,EAAE,KAAK,UAAU;OACrC,WAAW,IAAI,KAAK,EAAE,KAAK,UAAU;OACrC,CAAC;MAID;;;GAKH,MAAM,SAAS,OADQ,MAAM,kBAAkB,QAAQ,EACnB,QAElC;IACD,OAAO;IACP,OAAO,CACN;KACC,OAAO;KACP,OAAO;KACP,CACD;IACD,MAAM,EACL,MAAM,MACN;IACD,CAAC;AACF,OAAI,CAAC,OAAQ,QAAO;GAEpB,MAAM,EAAE,MAAM,GAAG,YAAY;AAC7B,OAAI,CAAC,KAAM,QAAO;AAGlB,UAAO;IACN,SAHqB,mBAAmB,IAAI,SAAS,QAAQ;IAI7D,MAHkB,gBAAgB,IAAI,SAAS,KAAK;IAIpD;;EAEF,cAAc,OACb,eACA,YAKI;AACJ,OAAI,kBAAkB;IACrB,MAAM,WAGA,EAAE;AACR,SAAK,MAAM,gBAAgB,eAAe;KACzC,MAAM,qBAAqB,MAAM,iBAAiB,IAAI,aAAa;AACnE,SAAI,mBACH,KAAI;MACH,MAAM,IACL,OAAO,uBAAuB,WAC3B,KAAK,MAAM,mBAAmB,GAC9B;AAKJ,UAAI,CAAC,EAAG,QAAO,EAAE;MACjB,MAAM,YAAY,IAAI,KAAK,EAAE,QAAQ,UAAU;AAC/C,UAAI,SAAS,sBAAsB,6BAAa,IAAI,MAAM,CACzD;MAED,MAAM,UAAU;OACf,SAAS;QACR,GAAG,EAAE;QACL,WAAW,IAAI,KAAK,EAAE,QAAQ,UAAU;QACxC;OACD,MAAM;QACL,GAAG,EAAE;QACL,WAAW,IAAI,KAAK,EAAE,KAAK,UAAU;QACrC,WAAW,IAAI,KAAK,EAAE,KAAK,UAAU;QACrC;OACD;AAID,eAAS,KAAK,QAAQ;aACf;AAEP;;;AAIH,WAAO;;GAGR,MAAM,WAAW,OAAO,MAAM,kBAAkB,QAAQ,EAAE,SAExD;IACD,OAAO;IACP,OAAO,CACN;KACC,OAAO;KACP,OAAO;KACP,UAAU;KACV,EACD,GAAI,SAAS,qBACV,CACA;KACC,OAAO;KACP,uBAAO,IAAI,MAAM;KACjB,UAAU;KACV,CACD,GACA,EAAE,CACL;IACD,MAAM,EACL,MAAM,MACN;IACD,CAAC;AAEF,OAAI,CAAC,SAAS,OAAQ,QAAO,EAAE;AAC/B,OAAI,SAAS,MAAM,YAAY,CAAC,QAAQ,KAAK,CAAE,QAAO,EAAE;AAExD,UAAO,SAAS,KAAK,aAAa;IACjC,MAAM,EAAE,MAAM,GAAG,YAAY;AAC7B,WAAO;KACN;KACM;KACN;KACA;;EAEH,eAAe,OACd,cACA,YACI;AAoFJ,UAnFuB,MAAM,gBAC5B,SACA,CAAC;IAAE,OAAO;IAAS,OAAO;IAAc,CAAC,EACzC,WACA,mBACG;IACA,MAAM,GAAG,MAAM;KACd,MAAM,iBAAiB,MAAM,iBAAiB,IAAI,aAAa;AAC/D,SAAI,CAAC,eACJ,QAAO;KAGR,MAAM,gBAAgB,cAGnB,eAAe;AAClB,SAAI,CAAC,cAAe,QAAO;KAE3B,MAAM,gBAAgB;MACrB,GAAG,cAAc;MACjB,GAAG;MACH,WAAW,IAAI,KACd,KAAK,aAAa,cAAc,QAAQ,UACxC;MACD,WAAW,IAAI,KAAK,cAAc,QAAQ,UAAU;MACpD,WAAW,IAAI,KACd,KAAK,aAAa,cAAc,QAAQ,UACxC;MACD;KAED,MAAM,iBAAiB,mBACtB,IAAI,SACJ,cACA;KAED,MAAM,MAAM,KAAK,KAAK;KACtB,MAAM,YAAY,IAAI,KAAK,eAAe,UAAU,CAAC,SAAS;KAC9D,MAAM,aAAa,cAAc,WAAW,IAAI;AAEhD,SAAI,aAAa,GAAG;AACnB,YAAM,iBAAiB,IACtB,cACA,KAAK,UAAU;OACd,SAAS;OACT,MAAM,cAAc;OACpB,CAAC,EACF,WACA;MAED,MAAM,UAAU,mBAAmB,eAAe;MAClD,MAAM,UAAU,MAAM,iBAAiB,IAAI,QAAQ;MAWnD,MAAM,UAV+C,UAClD,cAAc,QAAQ,IAAI,EAAE,GAC5B,EAAE,EAGH,QACC,MAAM,EAAE,UAAU,gBAAgB,EAAE,YAAY,IACjD,CACA,OAAO,CAAC;OAAE,OAAO;OAAc,WAAW;OAAW,CAAC,CAAC,CAEjC,MACtB,GAAG,MAAM,EAAE,YAAY,EAAE,UAC1B;MACD,MAAM,qBAAqB,OAAO,GAAG,GAAG,EAAE;AAE1C,UAAI,sBAAsB,qBAAqB,IAC9C,OAAM,iBAAiB,IACtB,SACA,KAAK,UAAU,OAAO,EACtB,cAAc,oBAAoB,IAAI,CACtC;UAED,OAAM,iBAAiB,OAAO,QAAQ;;AAIxC,YAAO;;IAER,eAAe,QAAQ,SAAS;IAChC,GACA,OACH;;EAGF,eAAe,OAAO,UAAkB;AACvC,OAAI,kBAAkB;IAErB,MAAM,OAAO,MAAM,iBAAiB,IAAI,MAAM;AAC9C,QAAI,MAAM;KACT,MAAM,EAAE,YACP,cAGG,KAAK,IAAI,EAAE;AACf,SAAI,CAAC,SAAS;AACb,aAAO,MAAM,yCAAyC;AACtD;;KAED,MAAM,SAAS,QAAQ;KAEvB,MAAM,cAAc,MAAM,iBAAiB,IAC1C,mBAAmB,SACnB;AACD,SAAI,aAAa;MAChB,MAAM,OACL,cAAc,YAAY,IAAI,EAAE;MACjC,MAAM,MAAM,KAAK,KAAK;MAEtB,MAAM,WAAW,KAAK,QACpB,YAAY,QAAQ,YAAY,OAAO,QAAQ,UAAU,MAC1D;MAED,MAAM,qBADS,SAAS,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,UAAU,CAC/B,GAAG,GAAG,EAAE;AAE1C,UACC,SAAS,SAAS,KAClB,sBACA,qBAAqB,KAAK,KAAK,CAE/B,OAAM,iBAAiB,IACtB,mBAAmB,UACnB,KAAK,UAAU,SAAS,EACxB,cAAc,oBAAoB,IAAI,CACtC;UAED,OAAM,iBAAiB,OAAO,mBAAmB,SAAS;WAG3D,QAAO,MAAM,sDAAsD;;AAIrE,UAAM,iBAAiB,OAAO,MAAM;AAEpC,QACC,CAAC,QAAQ,SAAS,0BAClB,IAAI,QAAQ,SAAS,0BAErB;;AAIF,SAAM,gBACL,CAAC;IAAE,OAAO;IAAS,OAAO;IAAO,CAAC,EAClC,WACA,OACA;;EAEF,gBAAgB,OAAO,WAAmB;AACzC,SAAM,oBACL,CACC;IACC,OAAO;IACP,OAAO;IACP,CACD,EACD,WACA,OACA;;EAEF,eAAe,OAAO,cAAsB;AAC3C,SAAM,gBACL,CAAC;IAAE,OAAO;IAAM,OAAO;IAAW,CAAC,EACnC,WACA,OACA;;EAEF,gBAAgB,OAAO,0BAA6C;AACnE,OAAI,kBAAkB;AACrB,QAAI,OAAO,0BAA0B,UAAU;KAC9C,MAAM,gBAAgB,MAAM,iBAAiB,IAC5C,mBAAmB,wBACnB;KACD,MAAM,WAAW,gBACd,cAAmC,cAAc,GACjD,EAAE;AACL,SAAI,CAAC,SAAU;AACf,UAAK,MAAM,WAAW,SACrB,OAAM,iBAAiB,OAAO,QAAQ,MAAM;AAE7C,WAAM,iBAAiB,OACtB,mBAAmB,wBACnB;UAED,MAAK,MAAM,gBAAgB,sBAE1B,KADgB,MAAM,iBAAiB,IAAI,aAAa,CAEvD,OAAM,iBAAiB,OAAO,aAAa;AAK9C,QACC,CAAC,QAAQ,SAAS,0BAClB,IAAI,QAAQ,SAAS,0BAErB;;AAGF,SAAM,oBACL,CACC;IACC,OAAO,MAAM,QAAQ,sBAAsB,GAAG,UAAU;IACxD,OAAO;IACP,UAAU,MAAM,QAAQ,sBAAsB,GAAG,OAAO;IACxD,CACD,EACD,WACA,OACA;;EAEF,eAAe,OACd,OACA,WACA,eACI;GAEJ,MAAM,UAAU,OAAO,MAAM,kBAAkB,QAAQ,EAAE,QAEvD;IACD,OAAO;IACP,OAAO,CACN;KACC,OAAO;KACP,OAAO;KACP,EACD;KACC,OAAO;KACP,OAAO;KACP,CACD;IACD,MAAM,EACL,MAAM,MACN;IACD,CAAC;AACF,OAAI,QACH,KAAI,QAAQ,KACX,QAAO;IACN,MAAM,QAAQ;IACd,eAAe;IACf,UAAU,CAAC,QAAQ;IACnB;QACK;IACN,MAAM,OAAO,OAAO,MAAM,kBAAkB,QAAQ,EAAE,QAAc;KACnE,OAAO;KACP,OAAO,CACN;MACC,OAAO,MAAM,aAAa;MAC1B,OAAO;MACP,CACD;KACD,CAAC;AACF,QAAI,KACH,QAAO;KACN;KACA,eAAe;KACf,UAAU,CAAC,QAAQ;KACnB;AAEF,WAAO;;QAEF;IACN,MAAM,OAAO,OAAO,MAAM,kBAAkB,QAAQ,EAAE,QAAc;KACnE,OAAO;KACP,OAAO,CACN;MACC,OAAO,MAAM,aAAa;MAC1B,OAAO;MACP,CACD;KACD,CAAC;AACF,QAAI,KAYH,QAAO;KACN;KACA,eAAe;KACf,UAdgB,OAChB,MAAM,kBAAkB,QAAQ,EAC/B,SAAkB;MACnB,OAAO;MACP,OAAO,CACN;OACC,OAAO,KAAK;OACZ,OAAO;OACP,CACD;MACD,CAAC,IAIqB,EAAE;KACxB;QAED,QAAO;;;EAIV,iBAAiB,OAChB,OACA,YACI;GAEJ,MAAM,SAAS,OADQ,MAAM,kBAAkB,QAAQ,EACnB,QAElC;IACD,OAAO;IACP,OAAO,CACN;KACC,OAAO,MAAM,aAAa;KAC1B,OAAO;KACP,CACD;IACD,MAAM,EACL,GAAI,SAAS,kBAAkB,EAAE,SAAS,MAAM,GAAG,EAAE,EACrD;IACD,CAAC;AACF,OAAI,CAAC,OAAQ,QAAO;GACpB,MAAM,EAAE,SAAS,UAAU,GAAG,SAAS;AACvC,UAAO;IACN;IACA,UAAU,YAAY,EAAE;IACxB;;EAEF,cAAc,OAAO,WAAmB;AACvC,OAAI,CAAC,OAAQ,QAAO;AAUpB,UATa,OAAO,MAAM,kBAAkB,QAAQ,EAAE,QAAc;IACnE,OAAO;IACP,OAAO,CACN;KACC,OAAO;KACP,OAAO;KACP,CACD;IACD,CAAC;;EAGH,aAAa,OACZ,YAEI;AAWJ,UAViB,MAAM,gBACtB;IAEC,2BAAW,IAAI,MAAM;IACrB,2BAAW,IAAI,MAAM;IACrB,GAAG;IACH,EACD,WACA,OACA;;EAGF,YAAY,OACX,QACA,SACI;GACJ,MAAM,OAAO,MAAM,gBAClB,MACA,CACC;IACC,OAAO;IACP,OAAO;IACP,CACD,EACD,QACA,OACA;AACD,SAAM,oBAAoB,KAAK;AAC/B,UAAO;;EAER,mBAAmB,OAClB,OACA,SACI;GACJ,MAAM,OAAO,MAAM,gBAClB,MACA,CACC;IACC,OAAO;IACP,OAAO,MAAM,aAAa;IAC1B,CACD,EACD,QACA,OACA;AACD,SAAM,oBAAoB,KAAK;AAC/B,UAAO;;EAER,gBAAgB,OAAO,QAAgB,aAAqB;AAC3D,SAAM,oBACL,EACC,UACA,EACD,CACC;IACC,OAAO;IACP,OAAO;IACP,EACD;IACC,OAAO;IACP,OAAO;IACP,CACD,EACD,WACA,OACA;;EAEF,cAAc,OAAO,WAAmB;AAYvC,UAXiB,OAChB,MAAM,kBAAkB,QAAQ,EAC/B,SAAkB;IACnB,OAAO;IACP,OAAO,CACN;KACC,OAAO;KACP,OAAO;KACP,CACD;IACD,CAAC;;EAGH,aAAa,OAAO,cAAsB;AAYzC,UAXgB,OAAO,MAAM,kBAAkB,QAAQ,EAAE,QACxD;IACC,OAAO;IACP,OAAO,CACN;KACC,OAAO;KACP,OAAO;KACP,CACD;IACD,CACD;;EAGF,yBAAyB,OAAO,WAAmB,eAAuB;AAgBzE,UAfgB,OAAO,MAAM,kBAAkB,QAAQ,EAAE,QACxD;IACC,OAAO;IACP,OAAO,CACN;KACC,OAAO;KACP,OAAO;KACP,EACD;KACC,OAAO;KACP,OAAO;KACP,CACD;IACD,CACD;;EAGF,qBAAqB,OAAO,WAAmB;AAY9C,UAXgB,OACf,MAAM,kBAAkB,QAAQ,EAC/B,SAAkB;IACnB,OAAO;IACP,OAAO,CACN;KACC,OAAO;KACP,OAAO;KACP,CACD;IACD,CAAC;;EAGH,eAAe,OAAO,IAAY,SAA2B;AAO5D,UANgB,MAAM,gBACrB,MACA,CAAC;IAAE,OAAO;IAAM,OAAO;IAAI,CAAC,EAC5B,WACA,OACA;;EAGF,yBAAyB,OACxB,SAEI;GACJ,MAAM,gBAAgB,iBACrB,KAAK,YACL,QAAQ,cAAc,gBACtB;GACD,MAAM,mBAAmB,MAAM,kBAC9B,KAAK,YACL,cACA;AA4BD,UA1BqB,MAAM,gBAC1B;IAEC,2BAAW,IAAI,MAAM;IACrB,2BAAW,IAAI,MAAM;IACrB,GAAG;IACH,YAAY;IACZ,EACD,gBACA,mBACG;IACA,MAAM,GAAG,kBAAkB;KAC1B,MAAM,MAAM,cAAc,iBAAiB,UAAU;AACrD,SAAI,MAAM,EACT,OAAM,iBAAiB,IACtB,gBAAgB,oBAChB,KAAK,UAAU,iBAAiB,EAChC,IACA;AAEF,YAAO;;IAER,eAAe,QAAQ,cAAc;IACrC,GACA,OACH;;EAGF,uBAAuB,OAAO,eAAuB;GACpD,MAAM,gBAAgB,iBACrB,YACA,QAAQ,cAAc,gBACtB;GACD,MAAM,mBAAmB,MAAM,kBAC9B,YACA,cACA;AAED,OAAI,kBAAkB;IACrB,MAAM,SAAS,MAAM,iBAAiB,IACrC,gBAAgB,mBAChB;AACD,QAAI,QAAQ;KACX,MAAM,SAAS,cAA4B,OAAO;AAClD,SAAI,OACH,QAAO;;AAGT,QAAI,iBAAiB,kBAAkB,SAAS;KAC/C,MAAM,cAAc,MAAM,iBAAiB,IAC1C,gBAAgB,aAChB;AACD,SAAI,aAAa;MAChB,MAAM,SAAS,cAA4B,YAAY;AACvD,UAAI,OACH,QAAO;;;AAIV,QAAI,CAAC,QAAQ,cAAc,gBAC1B,QAAO;;GAIT,MAAM,iBAAiB,MAAM,kBAAkB,QAAQ;GAEvD,eAAe,iBAAiB,IAAY;AAC3C,WAAO,eAAe,SAAuB;KAC5C,OAAO;KACP,OAAO,CAAC;MAAE,OAAO;MAAc,OAAO;MAAI,CAAC;KAC3C,QAAQ;MAAE,OAAO;MAAa,WAAW;MAAQ;KACjD,OAAO;KACP,CAAC;;GAGH,IAAI,eAAe,MAAM,iBAAiB,iBAAiB;AAE3D,OAAI,CAAC,aAAa,UAAU,iBAAiB,kBAAkB,QAC9D,gBAAe,MAAM,iBAAiB,WAAW;AAGlD,OAAI,CAAC,QAAQ,cAAc,eAC1B,OAAM,oBACL,CACC;IACC,OAAO;IACP,uBAAO,IAAI,MAAM;IACjB,UAAU;IACV,CACD,EACD,gBACA,OACA;AAGF,UAAQ,aAAa,MAAuB;;EAE7C,gCAAgC,OAAO,eAAuB;GAK7D,MAAM,mBAAmB,MAAM,kBAC9B,YALqB,iBACrB,YACA,QAAQ,cAAc,gBACtB,CAIA;AAED,OAAI,iBACH,OAAM,iBAAiB,OAAO,gBAAgB,mBAAmB;AAGlE,OAAI,CAAC,oBAAoB,QAAQ,cAAc,gBAC9C,OAAM,gBACL,CAAC;IAAE,OAAO;IAAc,OAAO;IAAkB,CAAC,EAClD,gBACA,OACA;;EAGH,gCAAgC,OAC/B,YACA,SACI;GAKJ,MAAM,mBAAmB,MAAM,kBAC9B,YALqB,iBACrB,YACA,QAAQ,cAAc,gBACtB,CAIA;AAED,OAAI,kBAAkB;IACrB,MAAM,SAAS,MAAM,iBAAiB,IACrC,gBAAgB,mBAChB;AACD,QAAI,QAAQ;KACX,MAAM,SAAS,cAA4B,OAAO;AAClD,SAAI,QAAQ;MACX,MAAM,UAAU;OAAE,GAAG;OAAQ,GAAG;OAAM;MACtC,MAAM,YAAY,QAAQ,aAAa,OAAO;MAC9C,MAAM,MAAM,cACX,qBAAqB,OAAO,YAAY,IAAI,KAAK,UAAU,CAC3D;AACD,UAAI,MAAM,EACT,OAAM,iBAAiB,IACtB,gBAAgB,oBAChB,KAAK,UAAU,QAAQ,EACvB,IACA;AAEF,UAAI,CAAC,QAAQ,cAAc,gBAC1B,QAAO;;;;AAMX,OAAI,CAAC,oBAAoB,QAAQ,cAAc,gBAO9C,QANqB,MAAM,gBAC1B,MACA,CAAC;IAAE,OAAO;IAAc,OAAO;IAAkB,CAAC,EAClD,gBACA,OACA;AAGF,UAAO;;EAER"}
|
|
1
|
+
{"version":3,"file":"internal-adapter.mjs","names":[],"sources":["../../src/db/internal-adapter.ts"],"sourcesContent":["import type {\n\tAuthContext,\n\tBetterAuthOptions,\n\tInternalAdapter,\n} from \"@better-auth/core\";\nimport {\n\tgetCurrentAdapter,\n\tgetCurrentAuthContext,\n\trunWithTransaction,\n} from \"@better-auth/core/context\";\nimport type { DBAdapter, Where } from \"@better-auth/core/db/adapter\";\nimport type { InternalLogger } from \"@better-auth/core/env\";\nimport { generateId } from \"@better-auth/core/utils/id\";\nimport { safeJSONParse } from \"@better-auth/core/utils/json\";\nimport type { Account, Session, User, Verification } from \"../types\";\nimport { getDate } from \"../utils/date\";\nimport { getIp } from \"../utils/get-request-ip\";\nimport {\n\tgetSessionDefaultFields,\n\tparseSessionOutput,\n\tparseUserOutput,\n} from \"./schema\";\nimport {\n\tgetStorageOption,\n\tprocessIdentifier,\n} from \"./verification-token-storage\";\nimport type { DatabaseHooksEntry } from \"./with-hooks\";\nimport { getWithHooks } from \"./with-hooks\";\n\nfunction getTTLSeconds(expiresAt: Date | number, now = Date.now()): number {\n\tconst expiresMs =\n\t\ttypeof expiresAt === \"number\" ? expiresAt : expiresAt.getTime();\n\treturn Math.max(Math.floor((expiresMs - now) / 1000), 0);\n}\n\nexport const createInternalAdapter = (\n\tadapter: DBAdapter<BetterAuthOptions>,\n\tctx: {\n\t\toptions: Omit<BetterAuthOptions, \"logger\">;\n\t\tlogger: InternalLogger;\n\t\thooks: DatabaseHooksEntry[];\n\t\tgenerateId: AuthContext[\"generateId\"];\n\t},\n): InternalAdapter => {\n\tconst logger = ctx.logger;\n\tconst options = ctx.options;\n\tconst secondaryStorage = options.secondaryStorage;\n\tconst sessionExpiration = options.session?.expiresIn || 60 * 60 * 24 * 7; // 7 days\n\tconst {\n\t\tcreateWithHooks,\n\t\tupdateWithHooks,\n\t\tupdateManyWithHooks,\n\t\tdeleteWithHooks,\n\t\tdeleteManyWithHooks,\n\t} = getWithHooks(adapter, ctx);\n\n\tasync function refreshUserSessions(user: User) {\n\t\tif (!secondaryStorage) return;\n\n\t\tconst listRaw = await secondaryStorage.get(`active-sessions-${user.id}`);\n\t\tif (!listRaw) return;\n\n\t\tconst now = Date.now();\n\t\tconst list =\n\t\t\tsafeJSONParse<{ token: string; expiresAt: number }[]>(listRaw) || [];\n\t\tconst validSessions = list.filter((s) => s.expiresAt > now);\n\n\t\tawait Promise.all(\n\t\t\tvalidSessions.map(async ({ token }) => {\n\t\t\t\tconst cached = await secondaryStorage.get(token);\n\t\t\t\tif (!cached) return;\n\t\t\t\tconst parsed = safeJSONParse<{ session: Session; user: User }>(cached);\n\t\t\t\tif (!parsed) return;\n\n\t\t\t\tconst sessionTTL = getTTLSeconds(parsed.session.expiresAt, now);\n\n\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\ttoken,\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\tsession: parsed.session,\n\t\t\t\t\t\tuser,\n\t\t\t\t\t}),\n\t\t\t\t\tMath.floor(sessionTTL),\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn {\n\t\tcreateOAuthUser: async (\n\t\t\tuser: Omit<User, \"id\" | \"createdAt\" | \"updatedAt\">,\n\t\t\taccount: Omit<Account, \"userId\" | \"id\" | \"createdAt\" | \"updatedAt\"> &\n\t\t\t\tPartial<Account>,\n\t\t) => {\n\t\t\treturn runWithTransaction(adapter, async () => {\n\t\t\t\tconst createdUser = await createWithHooks(\n\t\t\t\t\t{\n\t\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t...user,\n\t\t\t\t\t},\n\t\t\t\t\t\"user\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\tconst createdAccount = await createWithHooks(\n\t\t\t\t\t{\n\t\t\t\t\t\t...account,\n\t\t\t\t\t\tuserId: createdUser!.id,\n\t\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t},\n\t\t\t\t\t\"account\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tuser: createdUser,\n\t\t\t\t\taccount: createdAccount,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\tcreateUser: async <T>(\n\t\t\tuser: Omit<User, \"id\" | \"createdAt\" | \"updatedAt\" | \"emailVerified\"> &\n\t\t\t\tPartial<User> &\n\t\t\t\tRecord<string, any>,\n\t\t) => {\n\t\t\tconst createdUser = await createWithHooks(\n\t\t\t\t{\n\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t...user,\n\t\t\t\t\temail: user.email?.toLowerCase(),\n\t\t\t\t},\n\t\t\t\t\"user\",\n\t\t\t\tundefined,\n\t\t\t);\n\n\t\t\treturn createdUser as T & User;\n\t\t},\n\t\tcreateAccount: async <T extends Record<string, any>>(\n\t\t\taccount: Omit<Account, \"id\" | \"createdAt\" | \"updatedAt\"> &\n\t\t\t\tPartial<Account> &\n\t\t\t\tT,\n\t\t) => {\n\t\t\tconst createdAccount = await createWithHooks(\n\t\t\t\t{\n\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t...account,\n\t\t\t\t},\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\treturn createdAccount as T & Account;\n\t\t},\n\t\tlistSessions: async (\n\t\t\tuserId: string,\n\t\t\toptions?: { onlyActiveSessions?: boolean | undefined } | undefined,\n\t\t) => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst currentList = await secondaryStorage.get(\n\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t);\n\t\t\t\tif (!currentList) return [];\n\n\t\t\t\tconst list: { token: string; expiresAt: number }[] =\n\t\t\t\t\tsafeJSONParse(currentList) || [];\n\t\t\t\tconst now = Date.now();\n\n\t\t\t\tconst seenTokens = new Set<string>();\n\t\t\t\tconst sessions: Session[] = [];\n\n\t\t\t\tfor (const { token, expiresAt } of list) {\n\t\t\t\t\tif (expiresAt <= now || seenTokens.has(token)) continue;\n\t\t\t\t\tseenTokens.add(token);\n\n\t\t\t\t\tconst data = await secondaryStorage.get(token);\n\t\t\t\t\tif (!data) continue;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst parsed = (\n\t\t\t\t\t\t\ttypeof data === \"string\" ? JSON.parse(data) : data\n\t\t\t\t\t\t) as {\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (!parsed?.session) continue;\n\n\t\t\t\t\t\tsessions.push(\n\t\t\t\t\t\t\tparseSessionOutput(ctx.options, {\n\t\t\t\t\t\t\t\t...parsed.session,\n\t\t\t\t\t\t\t\texpiresAt: new Date(parsed.session.expiresAt),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn sessions;\n\t\t\t}\n\n\t\t\tconst sessions = await (\n\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t).findMany<Session>({\n\t\t\t\tmodel: \"session\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t\t...(options?.onlyActiveSessions\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"expiresAt\",\n\t\t\t\t\t\t\t\t\tvalue: new Date(),\n\t\t\t\t\t\t\t\t\toperator: \"gt\",\n\t\t\t\t\t\t\t\t} satisfies Where,\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn sessions;\n\t\t},\n\t\tlistUsers: async (\n\t\t\tlimit?: number | undefined,\n\t\t\toffset?: number | undefined,\n\t\t\tsortBy?:\n\t\t\t\t| {\n\t\t\t\t\t\tfield: string;\n\t\t\t\t\t\tdirection: \"asc\" | \"desc\";\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t\twhere?: Where[] | undefined,\n\t\t) => {\n\t\t\tconst users = await (await getCurrentAdapter(adapter)).findMany<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\tlimit,\n\t\t\t\toffset,\n\t\t\t\tsortBy,\n\t\t\t\twhere,\n\t\t\t});\n\t\t\treturn users;\n\t\t},\n\t\tcountTotalUsers: async (where?: Where[] | undefined) => {\n\t\t\tconst total = await (await getCurrentAdapter(adapter)).count({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere,\n\t\t\t});\n\t\t\tif (typeof total === \"string\") {\n\t\t\t\treturn parseInt(total);\n\t\t\t}\n\t\t\treturn total;\n\t\t},\n\t\tdeleteUser: async (userId: string) => {\n\t\t\tif (!secondaryStorage || options.session?.storeSessionInDatabase) {\n\t\t\t\tawait deleteManyWithHooks(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t\"session\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait deleteManyWithHooks(\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\n\t\t\tawait deleteWithHooks(\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"user\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tcreateSession: async (\n\t\t\tuserId: string,\n\t\t\tdontRememberMe?: boolean | undefined,\n\t\t\toverride?: (Partial<Session> & Record<string, any>) | undefined,\n\t\t\toverrideAll?: boolean | undefined,\n\t\t) => {\n\t\t\tconst headers: Headers | undefined = await (async () => {\n\t\t\t\tconst ctx = await getCurrentAuthContext().catch(() => null);\n\t\t\t\treturn ctx?.headers || ctx?.request?.headers;\n\t\t\t})();\n\t\t\tconst storeInDb = options.session?.storeSessionInDatabase;\n\t\t\tconst {\n\t\t\t\t// always ignore override id - new sessions must have new ids\n\t\t\t\tid: _,\n\t\t\t\t...rest\n\t\t\t} = override || {};\n\n\t\t\t// we're parsing default values for session additional fields\n\t\t\tconst defaultAdditionalFields = getSessionDefaultFields(options);\n\t\t\tconst data = {\n\t\t\t\tipAddress: headers ? getIp(headers, options) || \"\" : \"\",\n\t\t\t\tuserAgent: headers?.get(\"user-agent\") || \"\",\n\t\t\t\t...rest,\n\t\t\t\t/**\n\t\t\t\t * If the user doesn't want to be remembered\n\t\t\t\t * set the session to expire in 1 day.\n\t\t\t\t * The cookie will be set to expire at the end of the session\n\t\t\t\t */\n\t\t\t\texpiresAt: dontRememberMe\n\t\t\t\t\t? getDate(60 * 60 * 24, \"sec\") // 1 day\n\t\t\t\t\t: getDate(sessionExpiration, \"sec\"),\n\t\t\t\tuserId,\n\t\t\t\ttoken: generateId(32),\n\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\tcreatedAt: new Date(),\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t...defaultAdditionalFields,\n\t\t\t\t...(overrideAll ? rest : {}),\n\t\t\t} satisfies Partial<Session>;\n\t\t\tconst res = await createWithHooks(\n\t\t\t\tdata,\n\t\t\t\t\"session\",\n\t\t\t\tsecondaryStorage\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tfn: async (sessionData) => {\n\t\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t\t * store the session token for the user\n\t\t\t\t\t\t\t\t * so we can retrieve it later for listing sessions\n\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\tconst currentList = await secondaryStorage.get(\n\t\t\t\t\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tlet list: { token: string; expiresAt: number }[] = [];\n\t\t\t\t\t\t\t\tconst now = Date.now();\n\n\t\t\t\t\t\t\t\tif (currentList) {\n\t\t\t\t\t\t\t\t\tlist = safeJSONParse(currentList) || [];\n\t\t\t\t\t\t\t\t\tlist = list.filter(\n\t\t\t\t\t\t\t\t\t\t(session) =>\n\t\t\t\t\t\t\t\t\t\t\tsession.expiresAt > now && session.token !== data.token,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst sorted = [\n\t\t\t\t\t\t\t\t\t...list,\n\t\t\t\t\t\t\t\t\t{ token: data.token, expiresAt: data.expiresAt.getTime() },\n\t\t\t\t\t\t\t\t].sort((a, b) => a.expiresAt - b.expiresAt);\n\t\t\t\t\t\t\t\tconst furthestSessionExp =\n\t\t\t\t\t\t\t\t\tsorted.at(-1)?.expiresAt ?? data.expiresAt.getTime();\n\t\t\t\t\t\t\t\tconst furthestSessionTTL = getTTLSeconds(\n\t\t\t\t\t\t\t\t\tfurthestSessionExp,\n\t\t\t\t\t\t\t\t\tnow,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (furthestSessionTTL > 0) {\n\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t\t\t\t\t\t\tJSON.stringify(sorted),\n\t\t\t\t\t\t\t\t\t\tfurthestSessionTTL,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst user = await (\n\t\t\t\t\t\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t\t\t\t\t\t).findOne<User>({\n\t\t\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tconst sessionTTL = getTTLSeconds(data.expiresAt, now);\n\t\t\t\t\t\t\t\tif (sessionTTL > 0) {\n\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\tdata.token,\n\t\t\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t\t\tsession: sessionData,\n\t\t\t\t\t\t\t\t\t\t\tuser,\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\tsessionTTL,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn sessionData;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\texecuteMainFn: storeInDb,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t\treturn res as Session;\n\t\t},\n\t\tfindSession: async (\n\t\t\ttoken: string,\n\t\t): Promise<{\n\t\t\tsession: Session & Record<string, any>;\n\t\t\tuser: User & Record<string, any>;\n\t\t} | null> => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst sessionStringified = await secondaryStorage.get(token);\n\t\t\t\t// When preserveSessionInDatabase is enabled, revoked sessions\n\t\t\t\t// remain in the database for audit purposes. Skip the database\n\t\t\t\t// fallback to prevent those revoked sessions from being restored.\n\t\t\t\tif (\n\t\t\t\t\t!sessionStringified &&\n\t\t\t\t\t(!options.session?.storeSessionInDatabase ||\n\t\t\t\t\t\tctx.options.session?.preserveSessionInDatabase)\n\t\t\t\t) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (sessionStringified) {\n\t\t\t\t\tconst s = safeJSONParse<{\n\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\tuser: User;\n\t\t\t\t\t}>(sessionStringified);\n\t\t\t\t\tif (!s) return null;\n\t\t\t\t\tconst parsedSession = parseSessionOutput(ctx.options, {\n\t\t\t\t\t\t...s.session,\n\t\t\t\t\t\texpiresAt: new Date(s.session.expiresAt),\n\t\t\t\t\t\tcreatedAt: new Date(s.session.createdAt),\n\t\t\t\t\t\tupdatedAt: new Date(s.session.updatedAt),\n\t\t\t\t\t});\n\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.options, {\n\t\t\t\t\t\t...s.user,\n\t\t\t\t\t\tcreatedAt: new Date(s.user.createdAt),\n\t\t\t\t\t\tupdatedAt: new Date(s.user.updatedAt),\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst currentAdapter = await getCurrentAdapter(adapter);\n\t\t\tconst result = await currentAdapter.findOne<\n\t\t\t\tSession & { user: User | null }\n\t\t\t>({\n\t\t\t\tmodel: \"session\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: token,\n\t\t\t\t\t\tfield: \"token\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tjoin: {\n\t\t\t\t\tuser: true,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (!result) return null;\n\n\t\t\tconst { user, ...session } = result;\n\t\t\tif (!user) return null;\n\t\t\tconst parsedSession = parseSessionOutput(ctx.options, session);\n\t\t\tconst parsedUser = parseUserOutput(ctx.options, user);\n\t\t\treturn {\n\t\t\t\tsession: parsedSession,\n\t\t\t\tuser: parsedUser,\n\t\t\t};\n\t\t},\n\t\tfindSessions: async (\n\t\t\tsessionTokens: string[],\n\t\t\toptions?:\n\t\t\t\t| {\n\t\t\t\t\t\tonlyActiveSessions?: boolean | undefined;\n\t\t\t\t }\n\t\t\t\t| undefined,\n\t\t) => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst sessions: {\n\t\t\t\t\tsession: Session;\n\t\t\t\t\tuser: User;\n\t\t\t\t}[] = [];\n\t\t\t\tfor (const sessionToken of sessionTokens) {\n\t\t\t\t\tconst sessionStringified = await secondaryStorage.get(sessionToken);\n\t\t\t\t\tif (sessionStringified) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst s = (\n\t\t\t\t\t\t\t\ttypeof sessionStringified === \"string\"\n\t\t\t\t\t\t\t\t\t? JSON.parse(sessionStringified)\n\t\t\t\t\t\t\t\t\t: sessionStringified\n\t\t\t\t\t\t\t) as {\n\t\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tif (!s) return [];\n\t\t\t\t\t\t\tconst expiresAt = new Date(s.session.expiresAt);\n\t\t\t\t\t\t\tif (options?.onlyActiveSessions && expiresAt <= new Date()) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst session = {\n\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t...s.session,\n\t\t\t\t\t\t\t\t\texpiresAt: new Date(s.session.expiresAt),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t...s.user,\n\t\t\t\t\t\t\t\t\tcreatedAt: new Date(s.user.createdAt),\n\t\t\t\t\t\t\t\t\tupdatedAt: new Date(s.user.updatedAt),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tsessions.push(session);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Skip invalid/corrupt session data\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn sessions;\n\t\t\t}\n\n\t\t\tconst sessions = await (await getCurrentAdapter(adapter)).findMany<\n\t\t\t\tSession & { user: User | null }\n\t\t\t>({\n\t\t\t\tmodel: \"session\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"token\",\n\t\t\t\t\t\tvalue: sessionTokens,\n\t\t\t\t\t\toperator: \"in\",\n\t\t\t\t\t},\n\t\t\t\t\t...(options?.onlyActiveSessions\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"expiresAt\",\n\t\t\t\t\t\t\t\t\tvalue: new Date(),\n\t\t\t\t\t\t\t\t\toperator: \"gt\",\n\t\t\t\t\t\t\t\t} satisfies Where,\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t\tjoin: {\n\t\t\t\t\tuser: true,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (!sessions.length) return [];\n\t\t\tif (sessions.some((session) => !session.user)) return [];\n\n\t\t\treturn sessions.map((_session) => {\n\t\t\t\tconst { user, ...session } = _session;\n\t\t\t\treturn {\n\t\t\t\t\tsession,\n\t\t\t\t\tuser: user!,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\tupdateSession: async (\n\t\t\tsessionToken: string,\n\t\t\tsession: Partial<Session> & Record<string, any>,\n\t\t) => {\n\t\t\tconst updatedSession = await updateWithHooks<Session>(\n\t\t\t\tsession,\n\t\t\t\t[{ field: \"token\", value: sessionToken }],\n\t\t\t\t\"session\",\n\t\t\t\tsecondaryStorage\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tasync fn(data) {\n\t\t\t\t\t\t\t\tconst currentSession = await secondaryStorage.get(sessionToken);\n\t\t\t\t\t\t\t\tif (!currentSession) {\n\t\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst parsedSession = safeJSONParse<{\n\t\t\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\t\t}>(currentSession);\n\t\t\t\t\t\t\t\tif (!parsedSession) return null;\n\n\t\t\t\t\t\t\t\tconst mergedSession = {\n\t\t\t\t\t\t\t\t\t...parsedSession.session,\n\t\t\t\t\t\t\t\t\t...data,\n\t\t\t\t\t\t\t\t\texpiresAt: new Date(\n\t\t\t\t\t\t\t\t\t\tdata.expiresAt ?? parsedSession.session.expiresAt,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tcreatedAt: new Date(parsedSession.session.createdAt),\n\t\t\t\t\t\t\t\t\tupdatedAt: new Date(\n\t\t\t\t\t\t\t\t\t\tdata.updatedAt ?? parsedSession.session.updatedAt,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tconst updatedSession = parseSessionOutput(\n\t\t\t\t\t\t\t\t\tctx.options,\n\t\t\t\t\t\t\t\t\tmergedSession,\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tconst now = Date.now();\n\t\t\t\t\t\t\t\tconst expiresMs = new Date(updatedSession.expiresAt).getTime();\n\t\t\t\t\t\t\t\tconst sessionTTL = getTTLSeconds(expiresMs, now);\n\n\t\t\t\t\t\t\t\tif (sessionTTL > 0) {\n\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\tsessionToken,\n\t\t\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t\t\tsession: updatedSession,\n\t\t\t\t\t\t\t\t\t\t\tuser: parsedSession.user,\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\tsessionTTL,\n\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\tconst listKey = `active-sessions-${updatedSession.userId}`;\n\t\t\t\t\t\t\t\t\tconst listRaw = await secondaryStorage.get(listKey);\n\t\t\t\t\t\t\t\t\tconst list: { token: string; expiresAt: number }[] = listRaw\n\t\t\t\t\t\t\t\t\t\t? safeJSONParse(listRaw) || []\n\t\t\t\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\t\t\t\t\tconst filtered = list\n\t\t\t\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t\t\t\t(s) => s.token !== sessionToken && s.expiresAt > now,\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t.concat([{ token: sessionToken, expiresAt: expiresMs }]);\n\n\t\t\t\t\t\t\t\t\tconst sorted = filtered.sort(\n\t\t\t\t\t\t\t\t\t\t(a, b) => a.expiresAt - b.expiresAt,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tconst furthestSessionExp = sorted.at(-1)?.expiresAt;\n\n\t\t\t\t\t\t\t\t\tif (furthestSessionExp && furthestSessionExp > now) {\n\t\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\t\tlistKey,\n\t\t\t\t\t\t\t\t\t\t\tJSON.stringify(sorted),\n\t\t\t\t\t\t\t\t\t\t\tgetTTLSeconds(furthestSessionExp, now),\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tawait secondaryStorage.delete(listKey);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn updatedSession;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\texecuteMainFn: options.session?.storeSessionInDatabase,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t\treturn updatedSession;\n\t\t},\n\t\tdeleteSession: async (token: string) => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\t// remove the session from the active sessions list\n\t\t\t\tconst data = await secondaryStorage.get(token);\n\t\t\t\tif (data) {\n\t\t\t\t\tconst { session } =\n\t\t\t\t\t\tsafeJSONParse<{\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t}>(data) ?? {};\n\t\t\t\t\tif (!session) {\n\t\t\t\t\t\tlogger.error(\"Session not found in secondary storage\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst userId = session.userId;\n\n\t\t\t\t\tconst currentList = await secondaryStorage.get(\n\t\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t\t);\n\t\t\t\t\tif (currentList) {\n\t\t\t\t\t\tconst list: { token: string; expiresAt: number }[] =\n\t\t\t\t\t\t\tsafeJSONParse(currentList) || [];\n\t\t\t\t\t\tconst now = Date.now();\n\n\t\t\t\t\t\tconst filtered = list.filter(\n\t\t\t\t\t\t\t(session) => session.expiresAt > now && session.token !== token,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst sorted = filtered.sort((a, b) => a.expiresAt - b.expiresAt);\n\t\t\t\t\t\tconst furthestSessionExp = sorted.at(-1)?.expiresAt;\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tfiltered.length > 0 &&\n\t\t\t\t\t\t\tfurthestSessionExp &&\n\t\t\t\t\t\t\tfurthestSessionExp > Date.now()\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t`active-sessions-${userId}`,\n\t\t\t\t\t\t\t\tJSON.stringify(filtered),\n\t\t\t\t\t\t\t\tgetTTLSeconds(furthestSessionExp, now),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait secondaryStorage.delete(`active-sessions-${userId}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.error(\"Active sessions list not found in secondary storage\");\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tawait secondaryStorage.delete(token);\n\n\t\t\t\tif (\n\t\t\t\t\t!options.session?.storeSessionInDatabase ||\n\t\t\t\t\tctx.options.session?.preserveSessionInDatabase\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait deleteWithHooks(\n\t\t\t\t[{ field: \"token\", value: token }],\n\t\t\t\t\"session\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tdeleteAccounts: async (userId: string) => {\n\t\t\tawait deleteManyWithHooks(\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tdeleteAccount: async (accountId: string) => {\n\t\t\tawait deleteWithHooks(\n\t\t\t\t[{ field: \"id\", value: accountId }],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tdeleteSessions: async (userIdOrSessionTokens: string | string[]) => {\n\t\t\tif (secondaryStorage) {\n\t\t\t\tif (typeof userIdOrSessionTokens === \"string\") {\n\t\t\t\t\tconst activeSession = await secondaryStorage.get(\n\t\t\t\t\t\t`active-sessions-${userIdOrSessionTokens}`,\n\t\t\t\t\t);\n\t\t\t\t\tconst sessions = activeSession\n\t\t\t\t\t\t? safeJSONParse<{ token: string }[]>(activeSession)\n\t\t\t\t\t\t: [];\n\t\t\t\t\tif (!sessions) return;\n\t\t\t\t\tfor (const session of sessions) {\n\t\t\t\t\t\tawait secondaryStorage.delete(session.token);\n\t\t\t\t\t}\n\t\t\t\t\tawait secondaryStorage.delete(\n\t\t\t\t\t\t`active-sessions-${userIdOrSessionTokens}`,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tfor (const sessionToken of userIdOrSessionTokens) {\n\t\t\t\t\t\tconst session = await secondaryStorage.get(sessionToken);\n\t\t\t\t\t\tif (session) {\n\t\t\t\t\t\t\tawait secondaryStorage.delete(sessionToken);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t!options.session?.storeSessionInDatabase ||\n\t\t\t\t\tctx.options.session?.preserveSessionInDatabase\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait deleteManyWithHooks(\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: Array.isArray(userIdOrSessionTokens) ? \"token\" : \"userId\",\n\t\t\t\t\t\tvalue: userIdOrSessionTokens,\n\t\t\t\t\t\toperator: Array.isArray(userIdOrSessionTokens) ? \"in\" : undefined,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"session\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tfindOAuthUser: async (\n\t\t\temail: string,\n\t\t\taccountId: string,\n\t\t\tproviderId: string,\n\t\t) => {\n\t\t\t// we need to find account first to avoid missing user if the email changed with the provider for the same account\n\t\t\tconst account = await (await getCurrentAdapter(adapter)).findOne<\n\t\t\t\tAccount & { user: User | null }\n\t\t\t>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: accountId,\n\t\t\t\t\t\tfield: \"accountId\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: providerId,\n\t\t\t\t\t\tfield: \"providerId\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tjoin: {\n\t\t\t\t\tuser: true,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (account) {\n\t\t\t\tif (account.user) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tuser: account.user,\n\t\t\t\t\t\tlinkedAccount: account,\n\t\t\t\t\t\taccounts: [account],\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tconst user = await (await getCurrentAdapter(adapter)).findOne<User>({\n\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: email.toLowerCase(),\n\t\t\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\tif (user) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tuser,\n\t\t\t\t\t\t\tlinkedAccount: account,\n\t\t\t\t\t\t\taccounts: [account],\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst user = await (await getCurrentAdapter(adapter)).findOne<User>({\n\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: email.toLowerCase(),\n\t\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tif (user) {\n\t\t\t\t\tconst accounts = await (\n\t\t\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t\t\t).findMany<Account>({\n\t\t\t\t\t\tmodel: \"account\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\tuser,\n\t\t\t\t\t\tlinkedAccount: null,\n\t\t\t\t\t\taccounts: accounts || [],\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tfindUserByEmail: async (\n\t\t\temail: string,\n\t\t\toptions?: { includeAccounts: boolean } | undefined,\n\t\t) => {\n\t\t\tconst currentAdapter = await getCurrentAdapter(adapter);\n\t\t\tconst result = await currentAdapter.findOne<\n\t\t\t\tUser & { account: Account[] | undefined }\n\t\t\t>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: email.toLowerCase(),\n\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tjoin: {\n\t\t\t\t\t...(options?.includeAccounts ? { account: true } : {}),\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (!result) return null;\n\t\t\tconst { account: accounts, ...user } = result;\n\t\t\treturn {\n\t\t\t\tuser,\n\t\t\t\taccounts: accounts ?? [],\n\t\t\t};\n\t\t},\n\t\tfindUserById: async (userId: string) => {\n\t\t\tif (!userId) return null;\n\t\t\tconst user = await (await getCurrentAdapter(adapter)).findOne<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn user;\n\t\t},\n\t\tlinkAccount: async (\n\t\t\taccount: Omit<Account, \"id\" | \"createdAt\" | \"updatedAt\"> &\n\t\t\t\tPartial<Account>,\n\t\t) => {\n\t\t\tconst _account = await createWithHooks(\n\t\t\t\t{\n\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t...account,\n\t\t\t\t},\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\treturn _account;\n\t\t},\n\t\tupdateUser: async (\n\t\t\tuserId: string,\n\t\t\tdata: Partial<User> & Record<string, any>,\n\t\t) => {\n\t\t\tconst user = await updateWithHooks<User>(\n\t\t\t\tdata,\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"user\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tawait refreshUserSessions(user);\n\t\t\treturn user;\n\t\t},\n\t\tupdateUserByEmail: async (\n\t\t\temail: string,\n\t\t\tdata: Partial<User & Record<string, any>>,\n\t\t) => {\n\t\t\tconst user = await updateWithHooks<User>(\n\t\t\t\tdata,\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"email\",\n\t\t\t\t\t\tvalue: email.toLowerCase(),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"user\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tawait refreshUserSessions(user);\n\t\t\treturn user;\n\t\t},\n\t\tupdatePassword: async (userId: string, password: string) => {\n\t\t\tawait updateManyWithHooks(\n\t\t\t\t{\n\t\t\t\t\tpassword,\n\t\t\t\t},\n\t\t\t\t[\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"providerId\",\n\t\t\t\t\t\tvalue: \"credential\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t},\n\t\tfindAccounts: async (userId: string) => {\n\t\t\tconst accounts = await (\n\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t).findMany<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn accounts;\n\t\t},\n\t\tfindAccount: async (accountId: string) => {\n\t\t\tconst account = await (await getCurrentAdapter(adapter)).findOne<Account>(\n\t\t\t\t{\n\t\t\t\t\tmodel: \"account\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"accountId\",\n\t\t\t\t\t\t\tvalue: accountId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn account;\n\t\t},\n\t\tfindAccountByProviderId: async (accountId: string, providerId: string) => {\n\t\t\tconst account = await (await getCurrentAdapter(adapter)).findOne<Account>(\n\t\t\t\t{\n\t\t\t\t\tmodel: \"account\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"accountId\",\n\t\t\t\t\t\t\tvalue: accountId,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"providerId\",\n\t\t\t\t\t\t\tvalue: providerId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn account;\n\t\t},\n\t\tfindAccountByUserId: async (userId: string) => {\n\t\t\tconst account = await (\n\t\t\t\tawait getCurrentAdapter(adapter)\n\t\t\t).findMany<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\tvalue: userId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\treturn account;\n\t\t},\n\t\tupdateAccount: async (id: string, data: Partial<Account>) => {\n\t\t\tconst account = await updateWithHooks<Account>(\n\t\t\t\tdata,\n\t\t\t\t[{ field: \"id\", value: id }],\n\t\t\t\t\"account\",\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\treturn account;\n\t\t},\n\t\tcreateVerificationValue: async (\n\t\t\tdata: Omit<Verification, \"createdAt\" | \"id\" | \"updatedAt\"> &\n\t\t\t\tPartial<Verification>,\n\t\t) => {\n\t\t\tconst storageOption = getStorageOption(\n\t\t\t\tdata.identifier,\n\t\t\t\toptions.verification?.storeIdentifier,\n\t\t\t);\n\t\t\tconst storedIdentifier = await processIdentifier(\n\t\t\t\tdata.identifier,\n\t\t\t\tstorageOption,\n\t\t\t);\n\n\t\t\tconst verification = await createWithHooks(\n\t\t\t\t{\n\t\t\t\t\t// todo: we should remove auto setting createdAt and updatedAt in the next major release, since the db generators already handle that\n\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t...data,\n\t\t\t\t\tidentifier: storedIdentifier,\n\t\t\t\t},\n\t\t\t\t\"verification\",\n\t\t\t\tsecondaryStorage\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tasync fn(verificationData) {\n\t\t\t\t\t\t\t\tconst ttl = getTTLSeconds(verificationData.expiresAt);\n\t\t\t\t\t\t\t\tif (ttl > 0) {\n\t\t\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t\t\t`verification:${storedIdentifier}`,\n\t\t\t\t\t\t\t\t\t\tJSON.stringify(verificationData),\n\t\t\t\t\t\t\t\t\t\tttl,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn verificationData;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\texecuteMainFn: options.verification?.storeInDatabase,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t\treturn verification as Verification;\n\t\t},\n\t\tfindVerificationValue: async (identifier: string) => {\n\t\t\tconst storageOption = getStorageOption(\n\t\t\t\tidentifier,\n\t\t\t\toptions.verification?.storeIdentifier,\n\t\t\t);\n\t\t\tconst storedIdentifier = await processIdentifier(\n\t\t\t\tidentifier,\n\t\t\t\tstorageOption,\n\t\t\t);\n\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst cached = await secondaryStorage.get(\n\t\t\t\t\t`verification:${storedIdentifier}`,\n\t\t\t\t);\n\t\t\t\tif (cached) {\n\t\t\t\t\tconst parsed = safeJSONParse<Verification>(cached);\n\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\treturn parsed;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (storageOption && storageOption !== \"plain\") {\n\t\t\t\t\tconst plainCached = await secondaryStorage.get(\n\t\t\t\t\t\t`verification:${identifier}`,\n\t\t\t\t\t);\n\t\t\t\t\tif (plainCached) {\n\t\t\t\t\t\tconst parsed = safeJSONParse<Verification>(plainCached);\n\t\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\t\treturn parsed;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!options.verification?.storeInDatabase) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst currentAdapter = await getCurrentAdapter(adapter);\n\n\t\t\tasync function findByIdentifier(id: string) {\n\t\t\t\treturn currentAdapter.findMany<Verification>({\n\t\t\t\t\tmodel: \"verification\",\n\t\t\t\t\twhere: [{ field: \"identifier\", value: id }],\n\t\t\t\t\tsortBy: { field: \"createdAt\", direction: \"desc\" },\n\t\t\t\t\tlimit: 1,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet verification = await findByIdentifier(storedIdentifier);\n\n\t\t\tif (!verification.length && storageOption && storageOption !== \"plain\") {\n\t\t\t\tverification = await findByIdentifier(identifier);\n\t\t\t}\n\n\t\t\tif (!options.verification?.disableCleanup) {\n\t\t\t\tawait deleteManyWithHooks(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"expiresAt\",\n\t\t\t\t\t\t\tvalue: new Date(),\n\t\t\t\t\t\t\toperator: \"lt\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t\"verification\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn (verification[0] as Verification) || null;\n\t\t},\n\t\tdeleteVerificationByIdentifier: async (identifier: string) => {\n\t\t\tconst storageOption = getStorageOption(\n\t\t\t\tidentifier,\n\t\t\t\toptions.verification?.storeIdentifier,\n\t\t\t);\n\t\t\tconst storedIdentifier = await processIdentifier(\n\t\t\t\tidentifier,\n\t\t\t\tstorageOption,\n\t\t\t);\n\n\t\t\tif (secondaryStorage) {\n\t\t\t\tawait secondaryStorage.delete(`verification:${storedIdentifier}`);\n\t\t\t}\n\n\t\t\tif (!secondaryStorage || options.verification?.storeInDatabase) {\n\t\t\t\tawait deleteWithHooks(\n\t\t\t\t\t[{ field: \"identifier\", value: storedIdentifier }],\n\t\t\t\t\t\"verification\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t\tupdateVerificationByIdentifier: async (\n\t\t\tidentifier: string,\n\t\t\tdata: Partial<Verification>,\n\t\t) => {\n\t\t\tconst storageOption = getStorageOption(\n\t\t\t\tidentifier,\n\t\t\t\toptions.verification?.storeIdentifier,\n\t\t\t);\n\t\t\tconst storedIdentifier = await processIdentifier(\n\t\t\t\tidentifier,\n\t\t\t\tstorageOption,\n\t\t\t);\n\n\t\t\tif (secondaryStorage) {\n\t\t\t\tconst cached = await secondaryStorage.get(\n\t\t\t\t\t`verification:${storedIdentifier}`,\n\t\t\t\t);\n\t\t\t\tif (cached) {\n\t\t\t\t\tconst parsed = safeJSONParse<Verification>(cached);\n\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\tconst updated = { ...parsed, ...data };\n\t\t\t\t\t\tconst expiresAt = updated.expiresAt ?? parsed.expiresAt;\n\t\t\t\t\t\tconst ttl = getTTLSeconds(\n\t\t\t\t\t\t\texpiresAt instanceof Date ? expiresAt : new Date(expiresAt),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (ttl > 0) {\n\t\t\t\t\t\t\tawait secondaryStorage.set(\n\t\t\t\t\t\t\t\t`verification:${storedIdentifier}`,\n\t\t\t\t\t\t\t\tJSON.stringify(updated),\n\t\t\t\t\t\t\t\tttl,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!options.verification?.storeInDatabase) {\n\t\t\t\t\t\t\treturn updated;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!secondaryStorage || options.verification?.storeInDatabase) {\n\t\t\t\tconst verification = await updateWithHooks<Verification>(\n\t\t\t\t\tdata,\n\t\t\t\t\t[{ field: \"identifier\", value: storedIdentifier }],\n\t\t\t\t\t\"verification\",\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\treturn verification;\n\t\t\t}\n\t\t\treturn data as Verification;\n\t\t},\n\t};\n};\n"],"mappings":"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"}
|
package/dist/db/schema.d.mts
CHANGED
package/dist/db/with-hooks.d.mts
CHANGED
|
@@ -3,9 +3,13 @@ import { BaseModelNames } from "@better-auth/core/db";
|
|
|
3
3
|
import { DBAdapter, Where } from "@better-auth/core/db/adapter";
|
|
4
4
|
|
|
5
5
|
//#region src/db/with-hooks.d.ts
|
|
6
|
+
type DatabaseHooksEntry = {
|
|
7
|
+
source: string;
|
|
8
|
+
hooks: Exclude<BetterAuthOptions["databaseHooks"], undefined>;
|
|
9
|
+
};
|
|
6
10
|
declare function getWithHooks(adapter: DBAdapter<BetterAuthOptions>, ctx: {
|
|
7
11
|
options: BetterAuthOptions;
|
|
8
|
-
hooks:
|
|
12
|
+
hooks: DatabaseHooksEntry[];
|
|
9
13
|
}): {
|
|
10
14
|
createWithHooks: <T extends Record<string, any>>(data: T, model: BaseModelNames, customCreateFn?: {
|
|
11
15
|
fn: (data: Record<string, any>) => void | Promise<any>;
|
|
@@ -29,5 +33,5 @@ declare function getWithHooks(adapter: DBAdapter<BetterAuthOptions>, ctx: {
|
|
|
29
33
|
} | undefined) => Promise<any>;
|
|
30
34
|
};
|
|
31
35
|
//#endregion
|
|
32
|
-
export { getWithHooks };
|
|
36
|
+
export { DatabaseHooksEntry, getWithHooks };
|
|
33
37
|
//# sourceMappingURL=with-hooks.d.mts.map
|