@better-auth/kysely-adapter 1.5.0-beta.9 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/{bun-sqlite-dialect-deBGXcrd.mjs → bun-sqlite-dialect-C8OaCWSL.mjs} +4 -3
- package/dist/bun-sqlite-dialect-C8OaCWSL.mjs.map +1 -0
- package/dist/d1-sqlite-dialect-sYHNqBte.mjs +117 -0
- package/dist/d1-sqlite-dialect-sYHNqBte.mjs.map +1 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +44 -27
- package/dist/index.mjs.map +1 -0
- package/dist/node-sqlite-dialect.d.mts +2 -2
- package/dist/node-sqlite-dialect.mjs +4 -3
- package/dist/node-sqlite-dialect.mjs.map +1 -0
- package/package.json +26 -8
- package/.turbo/turbo-build.log +0 -16
- package/src/bun-sqlite-dialect.ts +0 -300
- package/src/dialect.ts +0 -148
- package/src/index.ts +0 -5
- package/src/kysely-adapter.test.ts +0 -24
- package/src/kysely-adapter.ts +0 -639
- package/src/node-sqlite-dialect.ts +0 -302
- package/src/types.ts +0 -1
- package/tsconfig.json +0 -9
- package/tsdown.config.ts +0 -7
- package/vitest.config.ts +0 -3
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Better Auth Kysely Adapter
|
|
2
|
+
|
|
3
|
+
Kysely adapter for [Better Auth](https://www.better-auth.com).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @better-auth/kysely-adapter
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
For full documentation, visit [better-auth.com/docs/adapters/kysely](https://www.better-auth.com/docs/adapters/kysely).
|
|
14
|
+
|
|
15
|
+
## License
|
|
16
|
+
|
|
17
|
+
MIT
|
|
@@ -56,8 +56,8 @@ var BunSqliteConnection = class {
|
|
|
56
56
|
this.#db = db;
|
|
57
57
|
}
|
|
58
58
|
executeQuery(compiledQuery) {
|
|
59
|
-
const { sql
|
|
60
|
-
const stmt = this.#db.prepare(sql
|
|
59
|
+
const { sql, parameters } = compiledQuery;
|
|
60
|
+
const stmt = this.#db.prepare(sql);
|
|
61
61
|
return Promise.resolve({ rows: stmt.all(parameters) });
|
|
62
62
|
}
|
|
63
63
|
async *streamQuery() {
|
|
@@ -152,4 +152,5 @@ var BunSqliteDialect = class {
|
|
|
152
152
|
};
|
|
153
153
|
|
|
154
154
|
//#endregion
|
|
155
|
-
export { BunSqliteDialect };
|
|
155
|
+
export { BunSqliteDialect };
|
|
156
|
+
//# sourceMappingURL=bun-sqlite-dialect-C8OaCWSL.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bun-sqlite-dialect-C8OaCWSL.mjs","names":["#config","#connectionMutex","#db","#connection","#promise","#resolve","#getTableMetadata"],"sources":["../src/bun-sqlite-dialect.ts"],"sourcesContent":["/**\n * @see {@link https://github.com/dylanblokhuis/kysely-bun-sqlite} - Fork of the original kysely-bun-sqlite package by @dylanblokhuis\n */\n\nimport type { Database } from \"bun:sqlite\";\nimport type {\n\tDatabaseConnection,\n\tDatabaseIntrospector,\n\tDatabaseMetadata,\n\tDatabaseMetadataOptions,\n\tDialect,\n\tDialectAdapter,\n\tDialectAdapterBase,\n\tDriver,\n\tKysely,\n\tQueryCompiler,\n\tQueryResult,\n\tSchemaMetadata,\n\tTableMetadata,\n} from \"kysely\";\nimport {\n\tCompiledQuery,\n\tDEFAULT_MIGRATION_LOCK_TABLE,\n\tDEFAULT_MIGRATION_TABLE,\n\tDefaultQueryCompiler,\n\tsql,\n} from \"kysely\";\n\nclass BunSqliteAdapter implements DialectAdapterBase {\n\tget supportsCreateIfNotExists(): boolean {\n\t\treturn true;\n\t}\n\n\tget supportsTransactionalDdl(): boolean {\n\t\treturn false;\n\t}\n\n\tget supportsReturning(): boolean {\n\t\treturn true;\n\t}\n\n\tasync acquireMigrationLock(): Promise<void> {\n\t\t// SQLite only has one connection that's reserved by the migration system\n\t\t// for the whole time between acquireMigrationLock and releaseMigrationLock.\n\t\t// We don't need to do anything here.\n\t}\n\n\tasync releaseMigrationLock(): Promise<void> {\n\t\t// SQLite only has one connection that's reserved by the migration system\n\t\t// for the whole time between acquireMigrationLock and releaseMigrationLock.\n\t\t// We don't need to do anything here.\n\t}\n\tget supportsOutput(): boolean {\n\t\treturn true;\n\t}\n}\n\n/**\n * Config for the SQLite dialect.\n */\nexport interface BunSqliteDialectConfig {\n\t/**\n\t * An sqlite Database instance or a function that returns one.\n\t */\n\tdatabase: Database;\n\n\t/**\n\t * Called once when the first query is executed.\n\t */\n\tonCreateConnection?:\n\t\t| ((connection: DatabaseConnection) => Promise<void>)\n\t\t| undefined;\n}\n\nclass BunSqliteDriver implements Driver {\n\treadonly #config: BunSqliteDialectConfig;\n\treadonly #connectionMutex = new ConnectionMutex();\n\n\t#db?: Database;\n\t#connection?: DatabaseConnection;\n\n\tconstructor(config: BunSqliteDialectConfig) {\n\t\tthis.#config = { ...config };\n\t}\n\n\tasync init(): Promise<void> {\n\t\tthis.#db = this.#config.database;\n\n\t\tthis.#connection = new BunSqliteConnection(this.#db);\n\n\t\tif (this.#config.onCreateConnection) {\n\t\t\tawait this.#config.onCreateConnection(this.#connection);\n\t\t}\n\t}\n\n\tasync acquireConnection(): Promise<DatabaseConnection> {\n\t\t// SQLite only has one single connection. We use a mutex here to wait\n\t\t// until the single connection has been released.\n\t\tawait this.#connectionMutex.lock();\n\t\treturn this.#connection!;\n\t}\n\n\tasync beginTransaction(connection: DatabaseConnection): Promise<void> {\n\t\tawait connection.executeQuery(CompiledQuery.raw(\"begin\"));\n\t}\n\n\tasync commitTransaction(connection: DatabaseConnection): Promise<void> {\n\t\tawait connection.executeQuery(CompiledQuery.raw(\"commit\"));\n\t}\n\n\tasync rollbackTransaction(connection: DatabaseConnection): Promise<void> {\n\t\tawait connection.executeQuery(CompiledQuery.raw(\"rollback\"));\n\t}\n\n\tasync releaseConnection(): Promise<void> {\n\t\tthis.#connectionMutex.unlock();\n\t}\n\n\tasync destroy(): Promise<void> {\n\t\tthis.#db?.close();\n\t}\n}\n\nclass BunSqliteConnection implements DatabaseConnection {\n\treadonly #db: Database;\n\n\tconstructor(db: Database) {\n\t\tthis.#db = db;\n\t}\n\n\texecuteQuery<O>(compiledQuery: CompiledQuery): Promise<QueryResult<O>> {\n\t\tconst { sql, parameters } = compiledQuery;\n\t\tconst stmt = this.#db.prepare(sql);\n\n\t\treturn Promise.resolve({\n\t\t\trows: stmt.all(parameters as any) as O[],\n\t\t});\n\t}\n\n\tasync *streamQuery() {\n\t\tthrow new Error(\"Streaming query is not supported by SQLite driver.\");\n\t}\n}\n\nclass ConnectionMutex {\n\t#promise?: Promise<void>;\n\t#resolve?: () => void;\n\n\tasync lock(): Promise<void> {\n\t\twhile (this.#promise !== undefined) {\n\t\t\tawait this.#promise;\n\t\t}\n\n\t\tthis.#promise = new Promise((resolve) => {\n\t\t\tthis.#resolve = resolve;\n\t\t});\n\t}\n\n\tunlock(): void {\n\t\tconst resolve = this.#resolve;\n\n\t\tthis.#promise = undefined;\n\t\tthis.#resolve = undefined;\n\n\t\tresolve?.();\n\t}\n}\n\nclass BunSqliteIntrospector implements DatabaseIntrospector {\n\treadonly #db: Kysely<unknown>;\n\n\tconstructor(db: Kysely<unknown>) {\n\t\tthis.#db = db;\n\t}\n\n\tasync getSchemas(): Promise<SchemaMetadata[]> {\n\t\t// Sqlite doesn't support schemas.\n\t\treturn [];\n\t}\n\n\tasync getTables(\n\t\toptions: DatabaseMetadataOptions = { withInternalKyselyTables: false },\n\t): Promise<TableMetadata[]> {\n\t\tlet query = this.#db\n\t\t\t// @ts-expect-error\n\t\t\t.selectFrom(\"sqlite_schema\")\n\t\t\t// @ts-expect-error\n\t\t\t.where(\"type\", \"=\", \"table\")\n\t\t\t// @ts-expect-error\n\t\t\t.where(\"name\", \"not like\", \"sqlite_%\")\n\t\t\t.select(\"name\")\n\t\t\t.$castTo<{ name: string }>();\n\n\t\tif (!options.withInternalKyselyTables) {\n\t\t\tquery = query\n\t\t\t\t// @ts-expect-error\n\t\t\t\t.where(\"name\", \"!=\", DEFAULT_MIGRATION_TABLE)\n\t\t\t\t// @ts-expect-error\n\t\t\t\t.where(\"name\", \"!=\", DEFAULT_MIGRATION_LOCK_TABLE);\n\t\t}\n\n\t\tconst tables = await query.execute();\n\t\treturn Promise.all(tables.map(({ name }) => this.#getTableMetadata(name)));\n\t}\n\n\tasync getMetadata(\n\t\toptions?: DatabaseMetadataOptions | undefined,\n\t): Promise<DatabaseMetadata> {\n\t\treturn {\n\t\t\ttables: await this.getTables(options),\n\t\t};\n\t}\n\n\tasync #getTableMetadata(table: string): Promise<TableMetadata> {\n\t\tconst db = this.#db;\n\n\t\t// Get the SQL that was used to create the table.\n\t\tconst createSql = await db\n\t\t\t// @ts-expect-error\n\t\t\t.selectFrom(\"sqlite_master\")\n\t\t\t// @ts-expect-error\n\t\t\t.where(\"name\", \"=\", table)\n\t\t\t.select(\"sql\")\n\t\t\t.$castTo<{ sql: string | undefined }>()\n\t\t\t.execute();\n\n\t\t// Try to find the name of the column that has `autoincrement` 🤦\n\t\tconst autoIncrementCol = createSql[0]?.sql\n\t\t\t?.split(/[\\(\\),]/)\n\t\t\t?.find((it) => it.toLowerCase().includes(\"autoincrement\"))\n\t\t\t?.split(/\\s+/)?.[0]\n\t\t\t?.replace(/[\"`]/g, \"\");\n\n\t\tconst columns = await db\n\t\t\t.selectFrom(\n\t\t\t\tsql<{\n\t\t\t\t\tname: string;\n\t\t\t\t\ttype: string;\n\t\t\t\t\tnotnull: 0 | 1;\n\t\t\t\t\tdflt_value: any;\n\t\t\t\t}>`pragma_table_info(${table})`.as(\"table_info\"),\n\t\t\t)\n\t\t\t.select([\"name\", \"type\", \"notnull\", \"dflt_value\"])\n\t\t\t.execute();\n\n\t\treturn {\n\t\t\tname: table,\n\t\t\tcolumns: columns.map((col) => ({\n\t\t\t\tname: col.name,\n\t\t\t\tdataType: col.type,\n\t\t\t\tisNullable: !col.notnull,\n\t\t\t\tisAutoIncrementing: col.name === autoIncrementCol,\n\t\t\t\thasDefaultValue: col.dflt_value != null,\n\t\t\t})),\n\t\t\tisView: true,\n\t\t};\n\t}\n}\n\nclass BunSqliteQueryCompiler extends DefaultQueryCompiler {\n\tprotected override getCurrentParameterPlaceholder() {\n\t\treturn \"?\";\n\t}\n\n\tprotected override getLeftIdentifierWrapper(): string {\n\t\treturn '\"';\n\t}\n\n\tprotected override getRightIdentifierWrapper(): string {\n\t\treturn '\"';\n\t}\n\n\tprotected override getAutoIncrement() {\n\t\treturn \"autoincrement\";\n\t}\n}\n\nexport class BunSqliteDialect implements Dialect {\n\treadonly #config: BunSqliteDialectConfig;\n\n\tconstructor(config: BunSqliteDialectConfig) {\n\t\tthis.#config = { ...config };\n\t}\n\n\tcreateDriver(): Driver {\n\t\treturn new BunSqliteDriver(this.#config);\n\t}\n\n\tcreateQueryCompiler(): QueryCompiler {\n\t\treturn new BunSqliteQueryCompiler();\n\t}\n\n\tcreateAdapter(): DialectAdapter {\n\t\treturn new BunSqliteAdapter();\n\t}\n\n\tcreateIntrospector(db: Kysely<any>): DatabaseIntrospector {\n\t\treturn new BunSqliteIntrospector(db);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { DEFAULT_MIGRATION_LOCK_TABLE, DEFAULT_MIGRATION_TABLE, SqliteAdapter, SqliteQueryCompiler } from "kysely";
|
|
2
|
+
|
|
3
|
+
//#region src/d1-sqlite-dialect.ts
|
|
4
|
+
var D1SqliteAdapter = class extends SqliteAdapter {};
|
|
5
|
+
var D1SqliteDriver = class {
|
|
6
|
+
#config;
|
|
7
|
+
#connection;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.#config = { ...config };
|
|
10
|
+
}
|
|
11
|
+
async init() {
|
|
12
|
+
this.#connection = new D1SqliteConnection(this.#config.database);
|
|
13
|
+
if (this.#config.onCreateConnection) await this.#config.onCreateConnection(this.#connection);
|
|
14
|
+
}
|
|
15
|
+
async acquireConnection() {
|
|
16
|
+
return this.#connection;
|
|
17
|
+
}
|
|
18
|
+
async beginTransaction() {
|
|
19
|
+
throw new Error("D1 does not support interactive transactions. Use the D1 batch() API instead.");
|
|
20
|
+
}
|
|
21
|
+
async commitTransaction() {
|
|
22
|
+
throw new Error("D1 does not support interactive transactions. Use the D1 batch() API instead.");
|
|
23
|
+
}
|
|
24
|
+
async rollbackTransaction() {
|
|
25
|
+
throw new Error("D1 does not support interactive transactions. Use the D1 batch() API instead.");
|
|
26
|
+
}
|
|
27
|
+
async releaseConnection() {}
|
|
28
|
+
async destroy() {}
|
|
29
|
+
};
|
|
30
|
+
var D1SqliteConnection = class {
|
|
31
|
+
#db;
|
|
32
|
+
constructor(db) {
|
|
33
|
+
this.#db = db;
|
|
34
|
+
}
|
|
35
|
+
async executeQuery(compiledQuery) {
|
|
36
|
+
const results = await this.#db.prepare(compiledQuery.sql).bind(...compiledQuery.parameters).all();
|
|
37
|
+
const numAffectedRows = results.meta.changes != null ? BigInt(results.meta.changes) : void 0;
|
|
38
|
+
return {
|
|
39
|
+
insertId: results.meta.last_row_id === void 0 || results.meta.last_row_id === null ? void 0 : BigInt(results.meta.last_row_id),
|
|
40
|
+
rows: results?.results || [],
|
|
41
|
+
numAffectedRows,
|
|
42
|
+
numUpdatedOrDeletedRows: numAffectedRows
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async *streamQuery() {
|
|
46
|
+
throw new Error("D1 does not support streaming queries.");
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var D1SqliteIntrospector = class {
|
|
50
|
+
#db;
|
|
51
|
+
#d1;
|
|
52
|
+
constructor(db, d1) {
|
|
53
|
+
this.#db = db;
|
|
54
|
+
this.#d1 = d1;
|
|
55
|
+
}
|
|
56
|
+
async getSchemas() {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
async getTables(options = { withInternalKyselyTables: false }) {
|
|
60
|
+
let query = this.#db.selectFrom("sqlite_master").where("type", "in", ["table", "view"]).where("name", "not like", "sqlite_%").where("name", "not like", "_cf_%").select([
|
|
61
|
+
"name",
|
|
62
|
+
"type",
|
|
63
|
+
"sql"
|
|
64
|
+
]).$castTo();
|
|
65
|
+
if (!options.withInternalKyselyTables) query = query.where("name", "!=", DEFAULT_MIGRATION_TABLE).where("name", "!=", DEFAULT_MIGRATION_LOCK_TABLE);
|
|
66
|
+
const tables = await query.execute();
|
|
67
|
+
if (tables.length === 0) return [];
|
|
68
|
+
const statements = tables.map((table) => this.#d1.prepare("SELECT * FROM pragma_table_info(?)").bind(table.name));
|
|
69
|
+
const batchResults = await this.#d1.batch(statements);
|
|
70
|
+
return tables.map((table, index) => {
|
|
71
|
+
const columnInfo = batchResults[index]?.results ?? [];
|
|
72
|
+
let autoIncrementCol = table.sql?.split(/[(),]/)?.find((it) => it.toLowerCase().includes("autoincrement"))?.split(/\s+/)?.filter(Boolean)?.[0]?.replace(/["`]/g, "");
|
|
73
|
+
if (!autoIncrementCol) {
|
|
74
|
+
const pkCols = columnInfo.filter((r) => r.pk > 0);
|
|
75
|
+
const singlePk = pkCols.length === 1 ? pkCols[0] : void 0;
|
|
76
|
+
if (singlePk && singlePk.type.toLowerCase() === "integer") autoIncrementCol = singlePk.name;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
name: table.name,
|
|
80
|
+
isView: table.type === "view",
|
|
81
|
+
columns: columnInfo.map((col) => ({
|
|
82
|
+
name: col.name,
|
|
83
|
+
dataType: col.type,
|
|
84
|
+
isNullable: !col.notnull,
|
|
85
|
+
isAutoIncrementing: col.name === autoIncrementCol,
|
|
86
|
+
hasDefaultValue: col.dflt_value != null
|
|
87
|
+
}))
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async getMetadata(options) {
|
|
92
|
+
return { tables: await this.getTables(options) };
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var D1SqliteQueryCompiler = class extends SqliteQueryCompiler {};
|
|
96
|
+
var D1SqliteDialect = class {
|
|
97
|
+
#config;
|
|
98
|
+
constructor(config) {
|
|
99
|
+
this.#config = { ...config };
|
|
100
|
+
}
|
|
101
|
+
createDriver() {
|
|
102
|
+
return new D1SqliteDriver(this.#config);
|
|
103
|
+
}
|
|
104
|
+
createQueryCompiler() {
|
|
105
|
+
return new D1SqliteQueryCompiler();
|
|
106
|
+
}
|
|
107
|
+
createAdapter() {
|
|
108
|
+
return new D1SqliteAdapter();
|
|
109
|
+
}
|
|
110
|
+
createIntrospector(db) {
|
|
111
|
+
return new D1SqliteIntrospector(db, this.#config.database);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
export { D1SqliteDialect };
|
|
117
|
+
//# sourceMappingURL=d1-sqlite-dialect-sYHNqBte.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"d1-sqlite-dialect-sYHNqBte.mjs","names":["#config","#connection","#db","#d1"],"sources":["../src/d1-sqlite-dialect.ts"],"sourcesContent":["import type { D1Database } from \"@cloudflare/workers-types\";\nimport type {\n\tCompiledQuery,\n\tDatabaseConnection,\n\tDatabaseIntrospector,\n\tDatabaseMetadata,\n\tDatabaseMetadataOptions,\n\tDialect,\n\tDialectAdapter,\n\tDriver,\n\tKysely,\n\tQueryCompiler,\n\tQueryResult,\n\tSchemaMetadata,\n\tTableMetadata,\n} from \"kysely\";\nimport {\n\tDEFAULT_MIGRATION_LOCK_TABLE,\n\tDEFAULT_MIGRATION_TABLE,\n\tSqliteAdapter,\n\tSqliteQueryCompiler,\n} from \"kysely\";\n\nclass D1SqliteAdapter extends SqliteAdapter {}\n\n/**\n * Config for the D1 SQLite dialect.\n */\nexport interface D1SqliteDialectConfig {\n\t/**\n\t * A Cloudflare D1 database instance.\n\t */\n\tdatabase: D1Database;\n\n\t/**\n\t * Called once when the first query is executed.\n\t */\n\tonCreateConnection?:\n\t\t| ((connection: DatabaseConnection) => Promise<void>)\n\t\t| undefined;\n}\n\nclass D1SqliteDriver implements Driver {\n\treadonly #config: D1SqliteDialectConfig;\n\t#connection?: DatabaseConnection;\n\n\tconstructor(config: D1SqliteDialectConfig) {\n\t\tthis.#config = { ...config };\n\t}\n\n\tasync init(): Promise<void> {\n\t\tthis.#connection = new D1SqliteConnection(this.#config.database);\n\n\t\tif (this.#config.onCreateConnection) {\n\t\t\tawait this.#config.onCreateConnection(this.#connection);\n\t\t}\n\t}\n\n\tasync acquireConnection(): Promise<DatabaseConnection> {\n\t\treturn this.#connection!;\n\t}\n\n\tasync beginTransaction(): Promise<void> {\n\t\tthrow new Error(\n\t\t\t\"D1 does not support interactive transactions. Use the D1 batch() API instead.\",\n\t\t);\n\t}\n\n\tasync commitTransaction(): Promise<void> {\n\t\tthrow new Error(\n\t\t\t\"D1 does not support interactive transactions. Use the D1 batch() API instead.\",\n\t\t);\n\t}\n\n\tasync rollbackTransaction(): Promise<void> {\n\t\tthrow new Error(\n\t\t\t\"D1 does not support interactive transactions. Use the D1 batch() API instead.\",\n\t\t);\n\t}\n\n\tasync releaseConnection(): Promise<void> {}\n\n\tasync destroy(): Promise<void> {}\n}\n\nclass D1SqliteConnection implements DatabaseConnection {\n\treadonly #db: D1Database;\n\n\tconstructor(db: D1Database) {\n\t\tthis.#db = db;\n\t}\n\n\tasync executeQuery<O>(compiledQuery: CompiledQuery): Promise<QueryResult<O>> {\n\t\tconst results = await this.#db\n\t\t\t.prepare(compiledQuery.sql)\n\t\t\t.bind(...compiledQuery.parameters)\n\t\t\t.all();\n\n\t\tconst numAffectedRows =\n\t\t\tresults.meta.changes != null ? BigInt(results.meta.changes) : undefined;\n\n\t\treturn {\n\t\t\tinsertId:\n\t\t\t\tresults.meta.last_row_id === undefined ||\n\t\t\t\tresults.meta.last_row_id === null\n\t\t\t\t\t? undefined\n\t\t\t\t\t: BigInt(results.meta.last_row_id),\n\t\t\trows: (results?.results as O[]) || [],\n\t\t\tnumAffectedRows,\n\t\t\t// @ts-expect-error - deprecated in kysely >= 0.23, keep for backward compatibility\n\t\t\tnumUpdatedOrDeletedRows: numAffectedRows,\n\t\t};\n\t}\n\n\tasync *streamQuery<O>(): AsyncIterableIterator<QueryResult<O>> {\n\t\tthrow new Error(\"D1 does not support streaming queries.\");\n\t}\n}\n\nclass D1SqliteIntrospector implements DatabaseIntrospector {\n\treadonly #db: Kysely<unknown>;\n\treadonly #d1: D1Database;\n\n\tconstructor(db: Kysely<unknown>, d1: D1Database) {\n\t\tthis.#db = db;\n\t\tthis.#d1 = d1;\n\t}\n\n\tasync getSchemas(): Promise<SchemaMetadata[]> {\n\t\t// SQLite doesn't support schemas.\n\t\treturn [];\n\t}\n\n\tasync getTables(\n\t\toptions: DatabaseMetadataOptions = { withInternalKyselyTables: false },\n\t): Promise<TableMetadata[]> {\n\t\tlet query = this.#db\n\t\t\t// @ts-expect-error - sqlite_master is not in the schema\n\t\t\t.selectFrom(\"sqlite_master\")\n\t\t\t// @ts-expect-error\n\t\t\t.where(\"type\", \"in\", [\"table\", \"view\"])\n\t\t\t// @ts-expect-error\n\t\t\t.where(\"name\", \"not like\", \"sqlite_%\")\n\t\t\t// @ts-expect-error - D1 internal tables\n\t\t\t.where(\"name\", \"not like\", \"_cf_%\")\n\t\t\t.select([\"name\", \"type\", \"sql\"])\n\t\t\t.$castTo<{ name: string; type: string; sql: string | null }>();\n\n\t\tif (!options.withInternalKyselyTables) {\n\t\t\tquery = query\n\t\t\t\t// @ts-expect-error\n\t\t\t\t.where(\"name\", \"!=\", DEFAULT_MIGRATION_TABLE)\n\t\t\t\t// @ts-expect-error\n\t\t\t\t.where(\"name\", \"!=\", DEFAULT_MIGRATION_LOCK_TABLE);\n\t\t}\n\n\t\tconst tables = await query.execute();\n\n\t\tif (tables.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst statements = tables.map((table) =>\n\t\t\tthis.#d1.prepare(\"SELECT * FROM pragma_table_info(?)\").bind(table.name),\n\t\t);\n\t\tconst batchResults = await this.#d1.batch(statements);\n\n\t\treturn tables.map((table, index) => {\n\t\t\tconst columnInfo = (batchResults[index]?.results ?? []) as Array<{\n\t\t\t\tcid: number;\n\t\t\t\tname: string;\n\t\t\t\ttype: string;\n\t\t\t\tnotnull: number;\n\t\t\t\tdflt_value: string | null;\n\t\t\t\tpk: number;\n\t\t\t}>;\n\n\t\t\t// Find the column that has `autoincrement` from CREATE SQL\n\t\t\tlet autoIncrementCol = table.sql\n\t\t\t\t?.split(/[(),]/)\n\t\t\t\t?.find((it) => it.toLowerCase().includes(\"autoincrement\"))\n\t\t\t\t?.split(/\\s+/)\n\t\t\t\t?.filter(Boolean)?.[0]\n\t\t\t\t?.replace(/[\"`]/g, \"\");\n\n\t\t\t// In SQLite, `INTEGER PRIMARY KEY` is always an alias for rowid\n\t\t\t// and auto-increments even without the explicit AUTOINCREMENT keyword.\n\t\t\tif (!autoIncrementCol) {\n\t\t\t\tconst pkCols = columnInfo.filter((r) => r.pk > 0);\n\t\t\t\tconst singlePk = pkCols.length === 1 ? pkCols[0] : undefined;\n\t\t\t\tif (singlePk && singlePk.type.toLowerCase() === \"integer\") {\n\t\t\t\t\tautoIncrementCol = singlePk.name;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tname: table.name,\n\t\t\t\tisView: table.type === \"view\",\n\t\t\t\tcolumns: columnInfo.map((col) => ({\n\t\t\t\t\tname: col.name,\n\t\t\t\t\tdataType: col.type,\n\t\t\t\t\tisNullable: !col.notnull,\n\t\t\t\t\tisAutoIncrementing: col.name === autoIncrementCol,\n\t\t\t\t\thasDefaultValue: col.dflt_value != null,\n\t\t\t\t})),\n\t\t\t};\n\t\t});\n\t}\n\n\tasync getMetadata(\n\t\toptions?: DatabaseMetadataOptions,\n\t): Promise<DatabaseMetadata> {\n\t\treturn {\n\t\t\ttables: await this.getTables(options),\n\t\t};\n\t}\n}\n\nclass D1SqliteQueryCompiler extends SqliteQueryCompiler {}\n\nexport class D1SqliteDialect implements Dialect {\n\treadonly #config: D1SqliteDialectConfig;\n\n\tconstructor(config: D1SqliteDialectConfig) {\n\t\tthis.#config = { ...config };\n\t}\n\n\tcreateDriver(): Driver {\n\t\treturn new D1SqliteDriver(this.#config);\n\t}\n\n\tcreateQueryCompiler(): QueryCompiler {\n\t\treturn new D1SqliteQueryCompiler();\n\t}\n\n\tcreateAdapter(): DialectAdapter {\n\t\treturn new D1SqliteAdapter();\n\t}\n\n\tcreateIntrospector(db: Kysely<unknown>): DatabaseIntrospector {\n\t\treturn new D1SqliteIntrospector(db, this.#config.database);\n\t}\n}\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -46,4 +46,5 @@ interface KyselyAdapterConfig {
|
|
|
46
46
|
}
|
|
47
47
|
declare const kyselyAdapter: (db: Kysely<any>, config?: KyselyAdapterConfig | undefined) => (options: BetterAuthOptions) => DBAdapter<BetterAuthOptions>;
|
|
48
48
|
//#endregion
|
|
49
|
-
export { KyselyDatabaseType, createKyselyAdapter, getKyselyDatabaseType, kyselyAdapter };
|
|
49
|
+
export { KyselyDatabaseType, createKyselyAdapter, getKyselyDatabaseType, kyselyAdapter };
|
|
50
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Kysely, MssqlDialect, MysqlDialect, PostgresDialect, SqliteDialect, sql } from "kysely";
|
|
2
2
|
import { createAdapterFactory } from "@better-auth/core/db/adapter";
|
|
3
|
+
import { capitalizeFirstLetter } from "@better-auth/core/utils/string";
|
|
3
4
|
|
|
4
5
|
//#region src/dialect.ts
|
|
5
6
|
function getKyselyDatabaseType(db) {
|
|
@@ -16,6 +17,7 @@ function getKyselyDatabaseType(db) {
|
|
|
16
17
|
if ("connect" in db) return "postgres";
|
|
17
18
|
if ("fileControl" in db) return "sqlite";
|
|
18
19
|
if ("open" in db && "close" in db && "prepare" in db) return "sqlite";
|
|
20
|
+
if ("batch" in db && "exec" in db && "prepare" in db) return "sqlite";
|
|
19
21
|
return null;
|
|
20
22
|
}
|
|
21
23
|
const createKyselyAdapter = async (config) => {
|
|
@@ -42,10 +44,10 @@ const createKyselyAdapter = async (config) => {
|
|
|
42
44
|
if ("getConnection" in db) dialect = new MysqlDialect(db);
|
|
43
45
|
if ("connect" in db) dialect = new PostgresDialect({ pool: db });
|
|
44
46
|
if ("fileControl" in db) {
|
|
45
|
-
const { BunSqliteDialect } = await import("./bun-sqlite-dialect-
|
|
47
|
+
const { BunSqliteDialect } = await import("./bun-sqlite-dialect-C8OaCWSL.mjs");
|
|
46
48
|
dialect = new BunSqliteDialect({ database: db });
|
|
47
49
|
}
|
|
48
|
-
if ("createSession" in db
|
|
50
|
+
if ("createSession" in db) {
|
|
49
51
|
let DatabaseSync = void 0;
|
|
50
52
|
try {
|
|
51
53
|
const nodeSqlite = "node:sqlite";
|
|
@@ -62,6 +64,10 @@ const createKyselyAdapter = async (config) => {
|
|
|
62
64
|
dialect = new NodeSqliteDialect({ database: db });
|
|
63
65
|
}
|
|
64
66
|
}
|
|
67
|
+
if ("batch" in db && "exec" in db && "prepare" in db) {
|
|
68
|
+
const { D1SqliteDialect } = await import("./d1-sqlite-dialect-sYHNqBte.mjs");
|
|
69
|
+
dialect = new D1SqliteDialect({ database: db });
|
|
70
|
+
}
|
|
65
71
|
return {
|
|
66
72
|
kysely: dialect ? new Kysely({ dialect }) : null,
|
|
67
73
|
databaseType,
|
|
@@ -73,7 +79,7 @@ const createKyselyAdapter = async (config) => {
|
|
|
73
79
|
//#region src/kysely-adapter.ts
|
|
74
80
|
const kyselyAdapter = (db, config) => {
|
|
75
81
|
let lazyOptions = null;
|
|
76
|
-
const createCustomAdapter = (db
|
|
82
|
+
const createCustomAdapter = (db) => {
|
|
77
83
|
return ({ getFieldName, schema, getDefaultFieldName, getDefaultModelName, getFieldAttributes, getModelName }) => {
|
|
78
84
|
const selectAllJoins = (join) => {
|
|
79
85
|
const allSelects = [];
|
|
@@ -103,14 +109,14 @@ const kyselyAdapter = (db, config) => {
|
|
|
103
109
|
await builder.execute();
|
|
104
110
|
const field = values.id ? "id" : where.length > 0 && where[0]?.field ? where[0].field : "id";
|
|
105
111
|
if (!values.id && where.length === 0) {
|
|
106
|
-
res = await db
|
|
112
|
+
res = await db.selectFrom(model).selectAll().orderBy(getFieldName({
|
|
107
113
|
model,
|
|
108
114
|
field
|
|
109
115
|
}), "desc").limit(1).executeTakeFirst();
|
|
110
116
|
return res;
|
|
111
117
|
}
|
|
112
118
|
const value = values[field] || where[0]?.value;
|
|
113
|
-
res = await db
|
|
119
|
+
res = await db.selectFrom(model).selectAll().orderBy(getFieldName({
|
|
114
120
|
model,
|
|
115
121
|
field
|
|
116
122
|
}), "desc").where(getFieldName({
|
|
@@ -175,7 +181,7 @@ const kyselyAdapter = (db, config) => {
|
|
|
175
181
|
for (const [key, value] of Object.entries(currentRow)) {
|
|
176
182
|
const keyStr = String(key);
|
|
177
183
|
let assigned = false;
|
|
178
|
-
for (const { joinModel, fieldName, joinModelRef } of allSelectsStr) if (keyStr === `_joined_${joinModelRef}_${fieldName}`) {
|
|
184
|
+
for (const { joinModel, fieldName, joinModelRef } of allSelectsStr) if (keyStr === `_joined_${joinModelRef}_${fieldName}` || keyStr === `_Joined${capitalizeFirstLetter(joinModelRef)}${capitalizeFirstLetter(fieldName)}`) {
|
|
179
185
|
joinedModelFields[getModelName(joinModel)][getFieldName({
|
|
180
186
|
model: joinModel,
|
|
181
187
|
field: fieldName
|
|
@@ -188,9 +194,9 @@ const kyselyAdapter = (db, config) => {
|
|
|
188
194
|
const mainId = mainModelFields.id;
|
|
189
195
|
if (!mainId) continue;
|
|
190
196
|
if (!groupedByMainId.has(mainId)) {
|
|
191
|
-
const entry
|
|
192
|
-
for (const [joinModel, joinAttr] of Object.entries(joinConfig)) entry
|
|
193
|
-
groupedByMainId.set(mainId, entry
|
|
197
|
+
const entry = { ...mainModelFields };
|
|
198
|
+
for (const [joinModel, joinAttr] of Object.entries(joinConfig)) entry[getModelName(joinModel)] = joinAttr.relation === "one-to-one" ? null : [];
|
|
199
|
+
groupedByMainId.set(mainId, entry);
|
|
194
200
|
}
|
|
195
201
|
const entry = groupedByMainId.get(mainId);
|
|
196
202
|
for (const [joinModel, joinAttr] of Object.entries(joinConfig)) {
|
|
@@ -227,19 +233,24 @@ const kyselyAdapter = (db, config) => {
|
|
|
227
233
|
}
|
|
228
234
|
return {
|
|
229
235
|
async create({ data, model }) {
|
|
230
|
-
return await withReturning(data, db
|
|
236
|
+
return await withReturning(data, db.insertInto(model).values(data), model, []);
|
|
231
237
|
},
|
|
232
238
|
async findOne({ model, where, select, join }) {
|
|
233
239
|
const { and, or } = convertWhereClause(model, where);
|
|
234
|
-
let query = db
|
|
240
|
+
let query = db.selectFrom((eb) => {
|
|
235
241
|
let b = eb.selectFrom(model);
|
|
236
|
-
if (and) b = b.where((eb
|
|
237
|
-
if (or) b = b.where((eb
|
|
238
|
-
|
|
242
|
+
if (and) b = b.where((eb) => eb.and(and.map((expr) => expr(eb))));
|
|
243
|
+
if (or) b = b.where((eb) => eb.or(or.map((expr) => expr(eb))));
|
|
244
|
+
if (select?.length && select.length > 0) b = b.select(select.map((field) => getFieldName({
|
|
245
|
+
model,
|
|
246
|
+
field
|
|
247
|
+
})));
|
|
248
|
+
else b = b.selectAll();
|
|
249
|
+
return b.as("primary");
|
|
239
250
|
}).selectAll("primary");
|
|
240
251
|
if (join) for (const [joinModel, joinAttr] of Object.entries(join)) {
|
|
241
252
|
const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel];
|
|
242
|
-
query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join
|
|
253
|
+
query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join) => join.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`));
|
|
243
254
|
}
|
|
244
255
|
const { allSelectsStr, allSelects } = selectAllJoins(join);
|
|
245
256
|
query = query.select(allSelects);
|
|
@@ -249,9 +260,9 @@ const kyselyAdapter = (db, config) => {
|
|
|
249
260
|
if (join) return processJoinedResults(res, join, allSelectsStr)[0];
|
|
250
261
|
return row;
|
|
251
262
|
},
|
|
252
|
-
async findMany({ model, where, limit, offset, sortBy, join }) {
|
|
263
|
+
async findMany({ model, where, limit, select, offset, sortBy, join }) {
|
|
253
264
|
const { and, or } = convertWhereClause(model, where);
|
|
254
|
-
let query = db
|
|
265
|
+
let query = db.selectFrom((eb) => {
|
|
255
266
|
let b = eb.selectFrom(model);
|
|
256
267
|
if (config?.type === "mssql") {
|
|
257
268
|
if (offset !== void 0) {
|
|
@@ -269,13 +280,18 @@ const kyselyAdapter = (db, config) => {
|
|
|
269
280
|
model,
|
|
270
281
|
field: sortBy.field
|
|
271
282
|
})}`, sortBy.direction);
|
|
272
|
-
if (and) b = b.where((eb
|
|
273
|
-
if (or) b = b.where((eb
|
|
274
|
-
|
|
283
|
+
if (and) b = b.where((eb) => eb.and(and.map((expr) => expr(eb))));
|
|
284
|
+
if (or) b = b.where((eb) => eb.or(or.map((expr) => expr(eb))));
|
|
285
|
+
if (select?.length && select.length > 0) b = b.select(select.map((field) => getFieldName({
|
|
286
|
+
model,
|
|
287
|
+
field
|
|
288
|
+
})));
|
|
289
|
+
else b = b.selectAll();
|
|
290
|
+
return b.as("primary");
|
|
275
291
|
}).selectAll("primary");
|
|
276
292
|
if (join) for (const [joinModel, joinAttr] of Object.entries(join)) {
|
|
277
293
|
const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel];
|
|
278
|
-
query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join
|
|
294
|
+
query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join) => join.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`));
|
|
279
295
|
}
|
|
280
296
|
const { allSelectsStr, allSelects } = selectAllJoins(join);
|
|
281
297
|
query = query.select(allSelects);
|
|
@@ -290,14 +306,14 @@ const kyselyAdapter = (db, config) => {
|
|
|
290
306
|
},
|
|
291
307
|
async update({ model, where, update: values }) {
|
|
292
308
|
const { and, or } = convertWhereClause(model, where);
|
|
293
|
-
let query = db
|
|
309
|
+
let query = db.updateTable(model).set(values);
|
|
294
310
|
if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb))));
|
|
295
311
|
if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb))));
|
|
296
312
|
return await withReturning(values, query, model, where);
|
|
297
313
|
},
|
|
298
314
|
async updateMany({ model, where, update: values }) {
|
|
299
315
|
const { and, or } = convertWhereClause(model, where);
|
|
300
|
-
let query = db
|
|
316
|
+
let query = db.updateTable(model).set(values);
|
|
301
317
|
if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb))));
|
|
302
318
|
if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb))));
|
|
303
319
|
const res = (await query.executeTakeFirst()).numUpdatedRows;
|
|
@@ -305,7 +321,7 @@ const kyselyAdapter = (db, config) => {
|
|
|
305
321
|
},
|
|
306
322
|
async count({ model, where }) {
|
|
307
323
|
const { and, or } = convertWhereClause(model, where);
|
|
308
|
-
let query = db
|
|
324
|
+
let query = db.selectFrom(model).select(db.fn.count("id").as("count"));
|
|
309
325
|
if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb))));
|
|
310
326
|
if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb))));
|
|
311
327
|
const res = await query.execute();
|
|
@@ -315,14 +331,14 @@ const kyselyAdapter = (db, config) => {
|
|
|
315
331
|
},
|
|
316
332
|
async delete({ model, where }) {
|
|
317
333
|
const { and, or } = convertWhereClause(model, where);
|
|
318
|
-
let query = db
|
|
334
|
+
let query = db.deleteFrom(model);
|
|
319
335
|
if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb))));
|
|
320
336
|
if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb))));
|
|
321
337
|
await query.execute();
|
|
322
338
|
},
|
|
323
339
|
async deleteMany({ model, where }) {
|
|
324
340
|
const { and, or } = convertWhereClause(model, where);
|
|
325
|
-
let query = db
|
|
341
|
+
let query = db.deleteFrom(model);
|
|
326
342
|
if (and) query = query.where((eb) => eb.and(and.map((expr) => expr(eb))));
|
|
327
343
|
if (or) query = query.where((eb) => eb.or(or.map((expr) => expr(eb))));
|
|
328
344
|
const res = (await query.executeTakeFirst()).numDeletedRows;
|
|
@@ -361,4 +377,5 @@ const kyselyAdapter = (db, config) => {
|
|
|
361
377
|
};
|
|
362
378
|
|
|
363
379
|
//#endregion
|
|
364
|
-
export { createKyselyAdapter, getKyselyDatabaseType, kyselyAdapter };
|
|
380
|
+
export { createKyselyAdapter, getKyselyDatabaseType, kyselyAdapter };
|
|
381
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/dialect.ts","../src/kysely-adapter.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport type { Dialect } from \"kysely\";\nimport {\n\tKysely,\n\tMssqlDialect,\n\tMysqlDialect,\n\tPostgresDialect,\n\tSqliteDialect,\n} from \"kysely\";\nimport type { KyselyDatabaseType } from \"./types\";\n\nexport function getKyselyDatabaseType(\n\tdb: BetterAuthOptions[\"database\"],\n): KyselyDatabaseType | null {\n\tif (!db) {\n\t\treturn null;\n\t}\n\tif (\"dialect\" in db) {\n\t\treturn getKyselyDatabaseType(db.dialect as Dialect);\n\t}\n\tif (\"createDriver\" in db) {\n\t\tif (db instanceof SqliteDialect) {\n\t\t\treturn \"sqlite\";\n\t\t}\n\t\tif (db instanceof MysqlDialect) {\n\t\t\treturn \"mysql\";\n\t\t}\n\t\tif (db instanceof PostgresDialect) {\n\t\t\treturn \"postgres\";\n\t\t}\n\t\tif (db instanceof MssqlDialect) {\n\t\t\treturn \"mssql\";\n\t\t}\n\t}\n\tif (\"aggregate\" in db) {\n\t\treturn \"sqlite\";\n\t}\n\n\tif (\"getConnection\" in db) {\n\t\treturn \"mysql\";\n\t}\n\tif (\"connect\" in db) {\n\t\treturn \"postgres\";\n\t}\n\tif (\"fileControl\" in db) {\n\t\treturn \"sqlite\";\n\t}\n\tif (\"open\" in db && \"close\" in db && \"prepare\" in db) {\n\t\treturn \"sqlite\";\n\t}\n\t// Cloudflare D1\n\tif (\"batch\" in db && \"exec\" in db && \"prepare\" in db) {\n\t\treturn \"sqlite\";\n\t}\n\treturn null;\n}\n\nexport const createKyselyAdapter = async (config: BetterAuthOptions) => {\n\tconst db = config.database;\n\n\tif (!db) {\n\t\treturn {\n\t\t\tkysely: null,\n\t\t\tdatabaseType: null,\n\t\t\ttransaction: undefined,\n\t\t};\n\t}\n\n\tif (\"db\" in db) {\n\t\treturn {\n\t\t\tkysely: db.db,\n\t\t\tdatabaseType: db.type,\n\t\t\ttransaction: db.transaction,\n\t\t};\n\t}\n\n\tif (\"dialect\" in db) {\n\t\treturn {\n\t\t\tkysely: new Kysely<any>({ dialect: db.dialect }),\n\t\t\tdatabaseType: db.type,\n\t\t\ttransaction: db.transaction,\n\t\t};\n\t}\n\n\tlet dialect: Dialect | undefined = undefined;\n\n\tconst databaseType = getKyselyDatabaseType(db);\n\n\tif (\"createDriver\" in db) {\n\t\tdialect = db;\n\t}\n\n\tif (\"aggregate\" in db && !(\"createSession\" in db)) {\n\t\tdialect = new SqliteDialect({\n\t\t\tdatabase: db,\n\t\t});\n\t}\n\n\tif (\"getConnection\" in db) {\n\t\t// @ts-expect-error - mysql2/promise\n\t\tdialect = new MysqlDialect(db);\n\t}\n\n\tif (\"connect\" in db) {\n\t\tdialect = new PostgresDialect({\n\t\t\tpool: db,\n\t\t});\n\t}\n\n\tif (\"fileControl\" in db) {\n\t\tconst { BunSqliteDialect } = await import(\"./bun-sqlite-dialect\");\n\t\tdialect = new BunSqliteDialect({\n\t\t\tdatabase: db,\n\t\t});\n\t}\n\n\tif (\"createSession\" in db) {\n\t\tlet DatabaseSync: typeof import(\"node:sqlite\").DatabaseSync | undefined =\n\t\t\tundefined;\n\t\ttry {\n\t\t\tconst nodeSqlite: string = \"node:sqlite\";\n\t\t\t// Ignore both Vite and Webpack for dynamic import as they both try to pre-bundle 'node:sqlite' which might fail\n\t\t\t// It's okay because we are in a try-catch block\n\t\t\t({ DatabaseSync } = await import(\n\t\t\t\t/* @vite-ignore */\n\t\t\t\t/* webpackIgnore: true */\n\t\t\t\tnodeSqlite\n\t\t\t));\n\t\t} catch (error: unknown) {\n\t\t\tif (\n\t\t\t\terror !== null &&\n\t\t\t\ttypeof error === \"object\" &&\n\t\t\t\t\"code\" in error &&\n\t\t\t\terror.code !== \"ERR_UNKNOWN_BUILTIN_MODULE\"\n\t\t\t) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\tif (DatabaseSync && db instanceof DatabaseSync) {\n\t\t\tconst { NodeSqliteDialect } = await import(\"./node-sqlite-dialect\");\n\t\t\tdialect = new NodeSqliteDialect({\n\t\t\t\tdatabase: db,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Cloudflare D1\n\tif (\"batch\" in db && \"exec\" in db && \"prepare\" in db) {\n\t\tconst { D1SqliteDialect } = await import(\"./d1-sqlite-dialect\");\n\t\tdialect = new D1SqliteDialect({\n\t\t\tdatabase: db,\n\t\t});\n\t}\n\n\treturn {\n\t\tkysely: dialect ? new Kysely<any>({ dialect }) : null,\n\t\tdatabaseType,\n\t\ttransaction: undefined,\n\t};\n};\n","import type { BetterAuthOptions } from \"@better-auth/core\";\nimport type {\n\tAdapterFactoryCustomizeAdapterCreator,\n\tAdapterFactoryOptions,\n\tDBAdapter,\n\tDBAdapterDebugLogOption,\n\tJoinConfig,\n\tWhere,\n} from \"@better-auth/core/db/adapter\";\nimport { createAdapterFactory } from \"@better-auth/core/db/adapter\";\nimport { capitalizeFirstLetter } from \"@better-auth/core/utils/string\";\nimport type {\n\tInsertQueryBuilder,\n\tKysely,\n\tRawBuilder,\n\tUpdateQueryBuilder,\n} from \"kysely\";\nimport { sql } from \"kysely\";\nimport type { KyselyDatabaseType } from \"./types\";\n\ninterface KyselyAdapterConfig {\n\t/**\n\t * Database type.\n\t */\n\ttype?: KyselyDatabaseType | undefined;\n\t/**\n\t * Enable debug logs for the adapter\n\t *\n\t * @default false\n\t */\n\tdebugLogs?: DBAdapterDebugLogOption | undefined;\n\t/**\n\t * Use plural for table names.\n\t *\n\t * @default false\n\t */\n\tusePlural?: boolean | undefined;\n\t/**\n\t * Whether to execute multiple operations in a transaction.\n\t *\n\t * If the database doesn't support transactions,\n\t * set this to `false` and operations will be executed sequentially.\n\t * @default false\n\t */\n\ttransaction?: boolean | undefined;\n}\n\nexport const kyselyAdapter = (\n\tdb: Kysely<any>,\n\tconfig?: KyselyAdapterConfig | undefined,\n) => {\n\tlet lazyOptions: BetterAuthOptions | null = null;\n\tconst createCustomAdapter = (\n\t\tdb: Kysely<any>,\n\t): AdapterFactoryCustomizeAdapterCreator => {\n\t\treturn ({\n\t\t\tgetFieldName,\n\t\t\tschema,\n\t\t\tgetDefaultFieldName,\n\t\t\tgetDefaultModelName,\n\t\t\tgetFieldAttributes,\n\t\t\tgetModelName,\n\t\t}) => {\n\t\t\tconst selectAllJoins = (join: JoinConfig | undefined) => {\n\t\t\t\t// Use selectAll which will handle column naming appropriately\n\t\t\t\tconst allSelects: RawBuilder<unknown>[] = [];\n\t\t\t\tconst allSelectsStr: {\n\t\t\t\t\tjoinModel: string;\n\t\t\t\t\tjoinModelRef: string;\n\t\t\t\t\tfieldName: string;\n\t\t\t\t}[] = [];\n\t\t\t\tif (join) {\n\t\t\t\t\tfor (const [joinModel, _] of Object.entries(join)) {\n\t\t\t\t\t\tconst fields = schema[getDefaultModelName(joinModel)]?.fields;\n\t\t\t\t\t\tconst [_joinModelSchema, joinModelName] = joinModel.includes(\".\")\n\t\t\t\t\t\t\t? joinModel.split(\".\")\n\t\t\t\t\t\t\t: [undefined, joinModel];\n\n\t\t\t\t\t\tif (!fields) continue;\n\t\t\t\t\t\tfields.id = { type: \"string\" }; // make sure there is at least an id field\n\t\t\t\t\t\tfor (const [field, fieldAttr] of Object.entries(fields)) {\n\t\t\t\t\t\t\tallSelects.push(\n\t\t\t\t\t\t\t\tsql`${sql.ref(`join_${joinModelName}`)}.${sql.ref(fieldAttr.fieldName || field)} as ${sql.ref(`_joined_${joinModelName}_${fieldAttr.fieldName || field}`)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tallSelectsStr.push({\n\t\t\t\t\t\t\t\tjoinModel: joinModel,\n\t\t\t\t\t\t\t\tjoinModelRef: joinModelName,\n\t\t\t\t\t\t\t\tfieldName: fieldAttr.fieldName || field,\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}\n\t\t\t\treturn { allSelectsStr, allSelects };\n\t\t\t};\n\n\t\t\tconst withReturning = async (\n\t\t\t\tvalues: Record<string, any>,\n\t\t\t\tbuilder:\n\t\t\t\t\t| InsertQueryBuilder<any, any, any>\n\t\t\t\t\t| UpdateQueryBuilder<any, string, string, any>,\n\t\t\t\tmodel: string,\n\t\t\t\twhere: Where[],\n\t\t\t) => {\n\t\t\t\tlet res: any;\n\t\t\t\tif (config?.type === \"mysql\") {\n\t\t\t\t\t// This isn't good, but kysely doesn't support returning in mysql and it doesn't return the inserted id.\n\t\t\t\t\t// Change this if there is a better way.\n\t\t\t\t\tawait builder.execute();\n\t\t\t\t\tconst field = values.id\n\t\t\t\t\t\t? \"id\"\n\t\t\t\t\t\t: where.length > 0 && where[0]?.field\n\t\t\t\t\t\t\t? where[0].field\n\t\t\t\t\t\t\t: \"id\";\n\n\t\t\t\t\tif (!values.id && where.length === 0) {\n\t\t\t\t\t\tres = await db\n\t\t\t\t\t\t\t.selectFrom(model)\n\t\t\t\t\t\t\t.selectAll()\n\t\t\t\t\t\t\t.orderBy(getFieldName({ model, field }), \"desc\")\n\t\t\t\t\t\t\t.limit(1)\n\t\t\t\t\t\t\t.executeTakeFirst();\n\t\t\t\t\t\treturn res;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst value = values[field] || where[0]?.value;\n\t\t\t\t\tres = await db\n\t\t\t\t\t\t.selectFrom(model)\n\t\t\t\t\t\t.selectAll()\n\t\t\t\t\t\t.orderBy(getFieldName({ model, field }), \"desc\")\n\t\t\t\t\t\t.where(getFieldName({ model, field }), \"=\", value)\n\t\t\t\t\t\t.limit(1)\n\t\t\t\t\t\t.executeTakeFirst();\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\t\t\t\tif (config?.type === \"mssql\") {\n\t\t\t\t\tres = await builder.outputAll(\"inserted\").executeTakeFirst();\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\t\t\t\tres = await builder.returningAll().executeTakeFirst();\n\t\t\t\treturn res;\n\t\t\t};\n\t\t\tfunction convertWhereClause(model: string, w?: Where[] | undefined) {\n\t\t\t\tif (!w)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tand: null,\n\t\t\t\t\t\tor: null,\n\t\t\t\t\t};\n\n\t\t\t\tconst conditions = {\n\t\t\t\t\tand: [] as any[],\n\t\t\t\t\tor: [] as any[],\n\t\t\t\t};\n\n\t\t\t\tw.forEach((condition) => {\n\t\t\t\t\tconst {\n\t\t\t\t\t\tfield: _field,\n\t\t\t\t\t\tvalue: _value,\n\t\t\t\t\t\toperator = \"=\",\n\t\t\t\t\t\tconnector = \"AND\",\n\t\t\t\t\t} = condition;\n\t\t\t\t\tconst value: any = _value;\n\t\t\t\t\tconst field: string | any = getFieldName({\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tfield: _field,\n\t\t\t\t\t});\n\n\t\t\t\t\tconst expr = (eb: any) => {\n\t\t\t\t\t\tconst f = `${model}.${field}`;\n\t\t\t\t\t\tif (operator.toLowerCase() === \"in\") {\n\t\t\t\t\t\t\treturn eb(f, \"in\", Array.isArray(value) ? value : [value]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator.toLowerCase() === \"not_in\") {\n\t\t\t\t\t\t\treturn eb(f, \"not in\", Array.isArray(value) ? value : [value]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator === \"contains\") {\n\t\t\t\t\t\t\treturn eb(f, \"like\", `%${value}%`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator === \"starts_with\") {\n\t\t\t\t\t\t\treturn eb(f, \"like\", `${value}%`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator === \"ends_with\") {\n\t\t\t\t\t\t\treturn eb(f, \"like\", `%${value}`);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator === \"eq\") {\n\t\t\t\t\t\t\treturn eb(f, \"=\", value);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator === \"ne\") {\n\t\t\t\t\t\t\treturn eb(f, \"<>\", value);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator === \"gt\") {\n\t\t\t\t\t\t\treturn eb(f, \">\", value);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator === \"gte\") {\n\t\t\t\t\t\t\treturn eb(f, \">=\", value);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator === \"lt\") {\n\t\t\t\t\t\t\treturn eb(f, \"<\", value);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (operator === \"lte\") {\n\t\t\t\t\t\t\treturn eb(f, \"<=\", value);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn eb(f, operator, value);\n\t\t\t\t\t};\n\n\t\t\t\t\tif (connector === \"OR\") {\n\t\t\t\t\t\tconditions.or.push(expr);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconditions.and.push(expr);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\tand: conditions.and.length ? conditions.and : null,\n\t\t\t\t\tor: conditions.or.length ? conditions.or : null,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tfunction processJoinedResults(\n\t\t\t\trows: any[],\n\t\t\t\tjoinConfig: JoinConfig | undefined,\n\t\t\t\tallSelectsStr: {\n\t\t\t\t\tjoinModel: string;\n\t\t\t\t\tjoinModelRef: string;\n\t\t\t\t\tfieldName: string;\n\t\t\t\t}[],\n\t\t\t) {\n\t\t\t\tif (!joinConfig || !rows.length) {\n\t\t\t\t\treturn rows;\n\t\t\t\t}\n\n\t\t\t\t// Group rows by main model ID\n\t\t\t\tconst groupedByMainId = new Map<string, any>();\n\n\t\t\t\tfor (const currentRow of rows) {\n\t\t\t\t\t// Separate main model columns from joined columns\n\t\t\t\t\tconst mainModelFields: Record<string, any> = {};\n\t\t\t\t\tconst joinedModelFields: Record<string, Record<string, any>> = {};\n\n\t\t\t\t\t// Initialize joined model fields map\n\t\t\t\t\tfor (const [joinModel] of Object.entries(joinConfig)) {\n\t\t\t\t\t\tjoinedModelFields[getModelName(joinModel)] = {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Distribute all columns - collect complete objects per model\n\t\t\t\t\tfor (const [key, value] of Object.entries(currentRow)) {\n\t\t\t\t\t\tconst keyStr = String(key);\n\t\t\t\t\t\tlet assigned = false;\n\n\t\t\t\t\t\t// Check if this is a joined column\n\t\t\t\t\t\tfor (const {\n\t\t\t\t\t\t\tjoinModel,\n\t\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\t\tjoinModelRef,\n\t\t\t\t\t\t} of allSelectsStr) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tkeyStr === `_joined_${joinModelRef}_${fieldName}` ||\n\t\t\t\t\t\t\t\t// Edge case to catch capitalized results that derive from snake_case table names\n\t\t\t\t\t\t\t\t// If anyone can identify the cause behind this, please note it here.\n\t\t\t\t\t\t\t\tkeyStr ===\n\t\t\t\t\t\t\t\t\t`_Joined${capitalizeFirstLetter(joinModelRef)}${capitalizeFirstLetter(fieldName)}`\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tjoinedModelFields[getModelName(joinModel)]![\n\t\t\t\t\t\t\t\t\tgetFieldName({\n\t\t\t\t\t\t\t\t\t\tmodel: joinModel,\n\t\t\t\t\t\t\t\t\t\tfield: fieldName,\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t] = value;\n\t\t\t\t\t\t\t\tassigned = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!assigned) {\n\t\t\t\t\t\t\tmainModelFields[key] = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst mainId = mainModelFields.id;\n\t\t\t\t\tif (!mainId) continue;\n\n\t\t\t\t\t// Initialize or get existing entry for this main model\n\t\t\t\t\tif (!groupedByMainId.has(mainId)) {\n\t\t\t\t\t\tconst entry: Record<string, any> = { ...mainModelFields };\n\n\t\t\t\t\t\t// Initialize joined models based on uniqueness\n\t\t\t\t\t\tfor (const [joinModel, joinAttr] of Object.entries(joinConfig)) {\n\t\t\t\t\t\t\tentry[getModelName(joinModel)] =\n\t\t\t\t\t\t\t\tjoinAttr.relation === \"one-to-one\" ? null : [];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgroupedByMainId.set(mainId, entry);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst entry = groupedByMainId.get(mainId)!;\n\n\t\t\t\t\t// Add joined records to the entry\n\t\t\t\t\tfor (const [joinModel, joinAttr] of Object.entries(joinConfig)) {\n\t\t\t\t\t\tconst isUnique = joinAttr.relation === \"one-to-one\";\n\t\t\t\t\t\tconst limit = joinAttr.limit ?? 100;\n\n\t\t\t\t\t\tconst joinedObj = joinedModelFields[getModelName(joinModel)];\n\n\t\t\t\t\t\tconst hasData =\n\t\t\t\t\t\t\tjoinedObj &&\n\t\t\t\t\t\t\tObject.keys(joinedObj).length > 0 &&\n\t\t\t\t\t\t\tObject.values(joinedObj).some(\n\t\t\t\t\t\t\t\t(value) => value !== null && value !== undefined,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (isUnique) {\n\t\t\t\t\t\t\tentry[getModelName(joinModel)] = hasData ? joinedObj : null;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// For arrays, append if not already there (deduplicate by id) and respect limit\n\t\t\t\t\t\t\tconst joinModelName = getModelName(joinModel);\n\t\t\t\t\t\t\tif (Array.isArray(entry[joinModelName]) && hasData) {\n\t\t\t\t\t\t\t\t// Check if we've reached the limit before processing\n\t\t\t\t\t\t\t\tif (entry[joinModelName].length >= limit) {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Get the id field name using getFieldName to ensure correct transformation\n\t\t\t\t\t\t\t\tconst idFieldName = getFieldName({\n\t\t\t\t\t\t\t\t\tmodel: joinModel,\n\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tconst joinedId = joinedObj[idFieldName];\n\n\t\t\t\t\t\t\t\t// Only deduplicate if we have an id field\n\t\t\t\t\t\t\t\tif (joinedId) {\n\t\t\t\t\t\t\t\t\tconst exists = entry[joinModelName].some(\n\t\t\t\t\t\t\t\t\t\t(item: any) => item[idFieldName] === joinedId,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tif (!exists && entry[joinModelName].length < limit) {\n\t\t\t\t\t\t\t\t\t\tentry[joinModelName].push(joinedObj);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// If no id field, still add the object if it has data and limit not reached\n\t\t\t\t\t\t\t\t\tif (entry[joinModelName].length < limit) {\n\t\t\t\t\t\t\t\t\t\tentry[joinModelName].push(joinedObj);\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}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst result = Array.from(groupedByMainId.values());\n\n\t\t\t\t// Apply final limit to non-unique join arrays as a safety measure\n\t\t\t\tfor (const entry of result) {\n\t\t\t\t\tfor (const [joinModel, joinAttr] of Object.entries(joinConfig)) {\n\t\t\t\t\t\tif (joinAttr.relation !== \"one-to-one\") {\n\t\t\t\t\t\t\tconst joinModelName = getModelName(joinModel);\n\t\t\t\t\t\t\tif (Array.isArray(entry[joinModelName])) {\n\t\t\t\t\t\t\t\tconst limit = joinAttr.limit ?? 100;\n\t\t\t\t\t\t\t\tif (entry[joinModelName].length > limit) {\n\t\t\t\t\t\t\t\t\tentry[joinModelName] = entry[joinModelName].slice(0, limit);\n\t\t\t\t\t\t\t\t}\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}\n\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tasync create({ data, model }) {\n\t\t\t\t\tconst builder = db.insertInto(model).values(data);\n\t\t\t\t\tconst returned = await withReturning(data, builder, model, []);\n\t\t\t\t\treturn returned;\n\t\t\t\t},\n\t\t\t\tasync findOne({ model, where, select, join }) {\n\t\t\t\t\tconst { and, or } = convertWhereClause(model, where);\n\t\t\t\t\tlet query: any = db\n\t\t\t\t\t\t.selectFrom((eb) => {\n\t\t\t\t\t\t\tlet b = eb.selectFrom(model);\n\t\t\t\t\t\t\tif (and) {\n\t\t\t\t\t\t\t\tb = b.where((eb: any) =>\n\t\t\t\t\t\t\t\t\teb.and(and.map((expr: any) => expr(eb))),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (or) {\n\t\t\t\t\t\t\t\tb = b.where((eb: any) =>\n\t\t\t\t\t\t\t\t\teb.or(or.map((expr: any) => expr(eb))),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (select?.length && select.length > 0) {\n\t\t\t\t\t\t\t\tb = b.select(\n\t\t\t\t\t\t\t\t\tselect.map((field) => getFieldName({ model, field })),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tb = b.selectAll();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn b.as(\"primary\");\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.selectAll(\"primary\");\n\n\t\t\t\t\tif (join) {\n\t\t\t\t\t\tfor (const [joinModel, joinAttr] of Object.entries(join)) {\n\t\t\t\t\t\t\tconst [_joinModelSchema, joinModelName] = joinModel.includes(\".\")\n\t\t\t\t\t\t\t\t? joinModel.split(\".\")\n\t\t\t\t\t\t\t\t: [undefined, joinModel];\n\n\t\t\t\t\t\t\tquery = query.leftJoin(\n\t\t\t\t\t\t\t\t`${joinModel} as join_${joinModelName}`,\n\t\t\t\t\t\t\t\t(join: any) =>\n\t\t\t\t\t\t\t\t\tjoin.onRef(\n\t\t\t\t\t\t\t\t\t\t`join_${joinModelName}.${joinAttr.on.to}`,\n\t\t\t\t\t\t\t\t\t\t\"=\",\n\t\t\t\t\t\t\t\t\t\t`primary.${joinAttr.on.from}`,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst { allSelectsStr, allSelects } = selectAllJoins(join);\n\t\t\t\t\tquery = query.select(allSelects);\n\n\t\t\t\t\tconst res = await query.execute();\n\t\t\t\t\tif (!res || !Array.isArray(res) || res.length === 0) return null;\n\n\t\t\t\t\t// Get the first row from the result array\n\t\t\t\t\tconst row = res[0];\n\n\t\t\t\t\tif (join) {\n\t\t\t\t\t\tconst processedRows = processJoinedResults(\n\t\t\t\t\t\t\tres,\n\t\t\t\t\t\t\tjoin,\n\t\t\t\t\t\t\tallSelectsStr,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn processedRows[0] as any;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn row as any;\n\t\t\t\t},\n\t\t\t\tasync findMany({ model, where, limit, select, offset, sortBy, join }) {\n\t\t\t\t\tconst { and, or } = convertWhereClause(model, where);\n\t\t\t\t\tlet query: any = db\n\t\t\t\t\t\t.selectFrom((eb) => {\n\t\t\t\t\t\t\tlet b = eb.selectFrom(model);\n\n\t\t\t\t\t\t\tif (config?.type === \"mssql\") {\n\t\t\t\t\t\t\t\tif (offset !== undefined) {\n\t\t\t\t\t\t\t\t\tif (!sortBy) {\n\t\t\t\t\t\t\t\t\t\tb = b.orderBy(getFieldName({ model, field: \"id\" }));\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tb = b.offset(offset).fetch(limit || 100);\n\t\t\t\t\t\t\t\t} else if (limit !== undefined) {\n\t\t\t\t\t\t\t\t\tb = b.top(limit);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tif (limit !== undefined) {\n\t\t\t\t\t\t\t\t\tb = b.limit(limit);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (offset !== undefined) {\n\t\t\t\t\t\t\t\t\tb = b.offset(offset);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (sortBy?.field) {\n\t\t\t\t\t\t\t\tb = b.orderBy(\n\t\t\t\t\t\t\t\t\t`${getFieldName({ model, field: sortBy.field })}`,\n\t\t\t\t\t\t\t\t\tsortBy.direction,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (and) {\n\t\t\t\t\t\t\t\tb = b.where((eb: any) =>\n\t\t\t\t\t\t\t\t\teb.and(and.map((expr: any) => expr(eb))),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (or) {\n\t\t\t\t\t\t\t\tb = b.where((eb: any) =>\n\t\t\t\t\t\t\t\t\teb.or(or.map((expr: any) => expr(eb))),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (select?.length && select.length > 0) {\n\t\t\t\t\t\t\t\tb = b.select(\n\t\t\t\t\t\t\t\t\tselect.map((field) => getFieldName({ model, field })),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tb = b.selectAll();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn b.as(\"primary\");\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.selectAll(\"primary\");\n\n\t\t\t\t\tif (join) {\n\t\t\t\t\t\tfor (const [joinModel, joinAttr] of Object.entries(join)) {\n\t\t\t\t\t\t\t// it's possible users provide a schema name in the model name (`<schema>.<model>`)\n\t\t\t\t\t\t\tconst [_joinModelSchema, joinModelName] = joinModel.includes(\".\")\n\t\t\t\t\t\t\t\t? joinModel.split(\".\")\n\t\t\t\t\t\t\t\t: [undefined, joinModel];\n\n\t\t\t\t\t\t\tquery = query.leftJoin(\n\t\t\t\t\t\t\t\t`${joinModel} as join_${joinModelName}`,\n\t\t\t\t\t\t\t\t(join: any) =>\n\t\t\t\t\t\t\t\t\tjoin.onRef(\n\t\t\t\t\t\t\t\t\t\t`join_${joinModelName}.${joinAttr.on.to}`,\n\t\t\t\t\t\t\t\t\t\t\"=\",\n\t\t\t\t\t\t\t\t\t\t`primary.${joinAttr.on.from}`,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst { allSelectsStr, allSelects } = selectAllJoins(join);\n\n\t\t\t\t\tquery = query.select(allSelects);\n\n\t\t\t\t\tif (sortBy?.field) {\n\t\t\t\t\t\tquery = query.orderBy(\n\t\t\t\t\t\t\t`${getFieldName({ model, field: sortBy.field })}`,\n\t\t\t\t\t\t\tsortBy.direction,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst res = await query.execute();\n\n\t\t\t\t\tif (!res) return [];\n\t\t\t\t\tif (join) return processJoinedResults(res, join, allSelectsStr);\n\t\t\t\t\treturn res;\n\t\t\t\t},\n\t\t\t\tasync update({ model, where, update: values }) {\n\t\t\t\t\tconst { and, or } = convertWhereClause(model, where);\n\n\t\t\t\t\tlet query = db.updateTable(model).set(values as any);\n\t\t\t\t\tif (and) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.and(and.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\t\t\t\t\tif (or) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.or(or.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\t\t\t\t\treturn await withReturning(values as any, query, model, where);\n\t\t\t\t},\n\t\t\t\tasync updateMany({ model, where, update: values }) {\n\t\t\t\t\tconst { and, or } = convertWhereClause(model, where);\n\t\t\t\t\tlet query = db.updateTable(model).set(values as any);\n\t\t\t\t\tif (and) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.and(and.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\t\t\t\t\tif (or) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.or(or.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\t\t\t\t\tconst res = (await query.executeTakeFirst()).numUpdatedRows;\n\t\t\t\t\treturn res > Number.MAX_SAFE_INTEGER\n\t\t\t\t\t\t? Number.MAX_SAFE_INTEGER\n\t\t\t\t\t\t: Number(res);\n\t\t\t\t},\n\t\t\t\tasync count({ model, where }) {\n\t\t\t\t\tconst { and, or } = convertWhereClause(model, where);\n\t\t\t\t\tlet query = db\n\t\t\t\t\t\t.selectFrom(model)\n\t\t\t\t\t\t// a temporal solution for counting other than \"*\" - see more - https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted\n\t\t\t\t\t\t.select(db.fn.count(\"id\").as(\"count\"));\n\t\t\t\t\tif (and) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.and(and.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\t\t\t\t\tif (or) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.or(or.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\t\t\t\t\tconst res = await query.execute();\n\t\t\t\t\tif (typeof res[0]!.count === \"number\") {\n\t\t\t\t\t\treturn res[0]!.count;\n\t\t\t\t\t}\n\t\t\t\t\tif (typeof res[0]!.count === \"bigint\") {\n\t\t\t\t\t\treturn Number(res[0]!.count);\n\t\t\t\t\t}\n\t\t\t\t\treturn parseInt(res[0]!.count);\n\t\t\t\t},\n\t\t\t\tasync delete({ model, where }) {\n\t\t\t\t\tconst { and, or } = convertWhereClause(model, where);\n\t\t\t\t\tlet query = db.deleteFrom(model);\n\t\t\t\t\tif (and) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.and(and.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (or) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.or(or.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\t\t\t\t\tawait query.execute();\n\t\t\t\t},\n\t\t\t\tasync deleteMany({ model, where }) {\n\t\t\t\t\tconst { and, or } = convertWhereClause(model, where);\n\t\t\t\t\tlet query = db.deleteFrom(model);\n\t\t\t\t\tif (and) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.and(and.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\t\t\t\t\tif (or) {\n\t\t\t\t\t\tquery = query.where((eb) => eb.or(or.map((expr) => expr(eb))));\n\t\t\t\t\t}\n\t\t\t\t\tconst res = (await query.executeTakeFirst()).numDeletedRows;\n\t\t\t\t\treturn res > Number.MAX_SAFE_INTEGER\n\t\t\t\t\t\t? Number.MAX_SAFE_INTEGER\n\t\t\t\t\t\t: Number(res);\n\t\t\t\t},\n\t\t\t\toptions: config,\n\t\t\t};\n\t\t};\n\t};\n\tlet adapterOptions: AdapterFactoryOptions | null = null;\n\tadapterOptions = {\n\t\tconfig: {\n\t\t\tadapterId: \"kysely\",\n\t\t\tadapterName: \"Kysely Adapter\",\n\t\t\tusePlural: config?.usePlural,\n\t\t\tdebugLogs: config?.debugLogs,\n\t\t\tsupportsBooleans:\n\t\t\t\tconfig?.type === \"sqlite\" ||\n\t\t\t\tconfig?.type === \"mssql\" ||\n\t\t\t\tconfig?.type === \"mysql\" ||\n\t\t\t\t!config?.type\n\t\t\t\t\t? false\n\t\t\t\t\t: true,\n\t\t\tsupportsDates:\n\t\t\t\tconfig?.type === \"sqlite\" || config?.type === \"mssql\" || !config?.type\n\t\t\t\t\t? false\n\t\t\t\t\t: true,\n\t\t\tsupportsJSON:\n\t\t\t\tconfig?.type === \"postgres\"\n\t\t\t\t\t? true // even if there is JSON support, only pg supports passing direct json, all others must stringify\n\t\t\t\t\t: false,\n\t\t\tsupportsArrays: false, // Even if field supports JSON, we must pass stringified arrays to the database.\n\t\t\tsupportsUUIDs: config?.type === \"postgres\" ? true : false,\n\t\t\ttransaction: config?.transaction\n\t\t\t\t? (cb) =>\n\t\t\t\t\t\tdb.transaction().execute((trx) => {\n\t\t\t\t\t\t\tconst adapter = createAdapterFactory({\n\t\t\t\t\t\t\t\tconfig: adapterOptions!.config,\n\t\t\t\t\t\t\t\tadapter: createCustomAdapter(trx),\n\t\t\t\t\t\t\t})(lazyOptions!);\n\t\t\t\t\t\t\treturn cb(adapter);\n\t\t\t\t\t\t})\n\t\t\t\t: false,\n\t\t},\n\t\tadapter: createCustomAdapter(db),\n\t};\n\n\tconst adapter = createAdapterFactory(adapterOptions);\n\n\treturn (options: BetterAuthOptions): DBAdapter<BetterAuthOptions> => {\n\t\tlazyOptions = options;\n\t\treturn adapter(options);\n\t};\n};\n"],"mappings":"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"}
|
|
@@ -2,7 +2,6 @@ import { DatabaseConnection, DatabaseIntrospector, Dialect, DialectAdapter, Driv
|
|
|
2
2
|
import { DatabaseSync } from "node:sqlite";
|
|
3
3
|
|
|
4
4
|
//#region src/node-sqlite-dialect.d.ts
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
6
|
* Config for the SQLite dialect.
|
|
8
7
|
*/
|
|
@@ -25,4 +24,5 @@ declare class NodeSqliteDialect implements Dialect {
|
|
|
25
24
|
createIntrospector(db: Kysely<any>): DatabaseIntrospector;
|
|
26
25
|
}
|
|
27
26
|
//#endregion
|
|
28
|
-
export { NodeSqliteDialect, NodeSqliteDialectConfig };
|
|
27
|
+
export { NodeSqliteDialect, NodeSqliteDialectConfig };
|
|
28
|
+
//# sourceMappingURL=node-sqlite-dialect.d.mts.map
|
|
@@ -56,8 +56,8 @@ var NodeSqliteConnection = class {
|
|
|
56
56
|
this.#db = db;
|
|
57
57
|
}
|
|
58
58
|
executeQuery(compiledQuery) {
|
|
59
|
-
const { sql
|
|
60
|
-
const rows = this.#db.prepare(sql
|
|
59
|
+
const { sql, parameters } = compiledQuery;
|
|
60
|
+
const rows = this.#db.prepare(sql).all(...parameters);
|
|
61
61
|
return Promise.resolve({ rows });
|
|
62
62
|
}
|
|
63
63
|
async *streamQuery() {
|
|
@@ -152,4 +152,5 @@ var NodeSqliteDialect = class {
|
|
|
152
152
|
};
|
|
153
153
|
|
|
154
154
|
//#endregion
|
|
155
|
-
export { NodeSqliteDialect };
|
|
155
|
+
export { NodeSqliteDialect };
|
|
156
|
+
//# sourceMappingURL=node-sqlite-dialect.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-sqlite-dialect.mjs","names":["#config","#connectionMutex","#db","#connection","#promise","#resolve","#getTableMetadata"],"sources":["../src/node-sqlite-dialect.ts"],"sourcesContent":["/**\n * @see {@link https://nodejs.org/api/sqlite.html} - Node.js SQLite API documentation\n */\n\nimport type { DatabaseSync } from \"node:sqlite\";\nimport type {\n\tDatabaseConnection,\n\tDatabaseIntrospector,\n\tDatabaseMetadata,\n\tDatabaseMetadataOptions,\n\tDialect,\n\tDialectAdapter,\n\tDialectAdapterBase,\n\tDriver,\n\tKysely,\n\tQueryCompiler,\n\tQueryResult,\n\tSchemaMetadata,\n\tTableMetadata,\n} from \"kysely\";\nimport {\n\tCompiledQuery,\n\tDEFAULT_MIGRATION_LOCK_TABLE,\n\tDEFAULT_MIGRATION_TABLE,\n\tDefaultQueryCompiler,\n\tsql,\n} from \"kysely\";\n\nclass NodeSqliteAdapter implements DialectAdapterBase {\n\tget supportsCreateIfNotExists(): boolean {\n\t\treturn true;\n\t}\n\n\tget supportsTransactionalDdl(): boolean {\n\t\treturn false;\n\t}\n\n\tget supportsReturning(): boolean {\n\t\treturn true;\n\t}\n\n\tasync acquireMigrationLock(): Promise<void> {\n\t\t// SQLite only has one connection that's reserved by the migration system\n\t\t// for the whole time between acquireMigrationLock and releaseMigrationLock.\n\t\t// We don't need to do anything here.\n\t}\n\n\tasync releaseMigrationLock(): Promise<void> {\n\t\t// SQLite only has one connection that's reserved by the migration system\n\t\t// for the whole time between acquireMigrationLock and releaseMigrationLock.\n\t\t// We don't need to do anything here.\n\t}\n\tget supportsOutput(): boolean {\n\t\treturn true;\n\t}\n}\n\n/**\n * Config for the SQLite dialect.\n */\nexport interface NodeSqliteDialectConfig {\n\t/**\n\t * A sqlite DatabaseSync instance or a function that returns one.\n\t */\n\tdatabase: DatabaseSync;\n\n\t/**\n\t * Called once when the first query is executed.\n\t */\n\tonCreateConnection?:\n\t\t| ((connection: DatabaseConnection) => Promise<void>)\n\t\t| undefined;\n}\n\nclass NodeSqliteDriver implements Driver {\n\treadonly #config: NodeSqliteDialectConfig;\n\treadonly #connectionMutex = new ConnectionMutex();\n\n\t#db?: DatabaseSync;\n\t#connection?: DatabaseConnection;\n\n\tconstructor(config: NodeSqliteDialectConfig) {\n\t\tthis.#config = { ...config };\n\t}\n\n\tasync init(): Promise<void> {\n\t\tthis.#db = this.#config.database;\n\n\t\tthis.#connection = new NodeSqliteConnection(this.#db);\n\n\t\tif (this.#config.onCreateConnection) {\n\t\t\tawait this.#config.onCreateConnection(this.#connection);\n\t\t}\n\t}\n\n\tasync acquireConnection(): Promise<DatabaseConnection> {\n\t\t// SQLite only has one single connection. We use a mutex here to wait\n\t\t// until the single connection has been released.\n\t\tawait this.#connectionMutex.lock();\n\t\treturn this.#connection!;\n\t}\n\n\tasync beginTransaction(connection: DatabaseConnection): Promise<void> {\n\t\tawait connection.executeQuery(CompiledQuery.raw(\"begin\"));\n\t}\n\n\tasync commitTransaction(connection: DatabaseConnection): Promise<void> {\n\t\tawait connection.executeQuery(CompiledQuery.raw(\"commit\"));\n\t}\n\n\tasync rollbackTransaction(connection: DatabaseConnection): Promise<void> {\n\t\tawait connection.executeQuery(CompiledQuery.raw(\"rollback\"));\n\t}\n\n\tasync releaseConnection(): Promise<void> {\n\t\tthis.#connectionMutex.unlock();\n\t}\n\n\tasync destroy(): Promise<void> {\n\t\tthis.#db?.close();\n\t}\n}\n\nclass NodeSqliteConnection implements DatabaseConnection {\n\treadonly #db: DatabaseSync;\n\n\tconstructor(db: DatabaseSync) {\n\t\tthis.#db = db;\n\t}\n\n\texecuteQuery<O>(compiledQuery: CompiledQuery): Promise<QueryResult<O>> {\n\t\tconst { sql, parameters } = compiledQuery;\n\t\tconst stmt = this.#db.prepare(sql);\n\n\t\tconst rows = stmt.all(...(parameters as any[])) as O[];\n\n\t\treturn Promise.resolve({\n\t\t\trows,\n\t\t});\n\t}\n\n\tasync *streamQuery() {\n\t\tthrow new Error(\"Streaming query is not supported by SQLite driver.\");\n\t}\n}\n\nclass ConnectionMutex {\n\t#promise?: Promise<void>;\n\t#resolve?: () => void;\n\n\tasync lock(): Promise<void> {\n\t\twhile (this.#promise !== undefined) {\n\t\t\tawait this.#promise;\n\t\t}\n\n\t\tthis.#promise = new Promise((resolve) => {\n\t\t\tthis.#resolve = resolve;\n\t\t});\n\t}\n\n\tunlock(): void {\n\t\tconst resolve = this.#resolve;\n\n\t\tthis.#promise = undefined;\n\t\tthis.#resolve = undefined;\n\n\t\tresolve?.();\n\t}\n}\n\nclass NodeSqliteIntrospector implements DatabaseIntrospector {\n\treadonly #db: Kysely<unknown>;\n\n\tconstructor(db: Kysely<unknown>) {\n\t\tthis.#db = db;\n\t}\n\n\tasync getSchemas(): Promise<SchemaMetadata[]> {\n\t\t// Sqlite doesn't support schemas.\n\t\treturn [];\n\t}\n\n\tasync getTables(\n\t\toptions: DatabaseMetadataOptions = { withInternalKyselyTables: false },\n\t): Promise<TableMetadata[]> {\n\t\tlet query = this.#db\n\t\t\t// @ts-expect-error\n\t\t\t.selectFrom(\"sqlite_schema\")\n\t\t\t// @ts-expect-error\n\t\t\t.where(\"type\", \"=\", \"table\")\n\t\t\t// @ts-expect-error\n\t\t\t.where(\"name\", \"not like\", \"sqlite_%\")\n\t\t\t.select(\"name\")\n\t\t\t.$castTo<{ name: string }>();\n\n\t\tif (!options.withInternalKyselyTables) {\n\t\t\tquery = query\n\t\t\t\t// @ts-expect-error\n\t\t\t\t.where(\"name\", \"!=\", DEFAULT_MIGRATION_TABLE)\n\t\t\t\t// @ts-expect-error\n\t\t\t\t.where(\"name\", \"!=\", DEFAULT_MIGRATION_LOCK_TABLE);\n\t\t}\n\n\t\tconst tables = await query.execute();\n\t\treturn Promise.all(tables.map(({ name }) => this.#getTableMetadata(name)));\n\t}\n\n\tasync getMetadata(\n\t\toptions?: DatabaseMetadataOptions | undefined,\n\t): Promise<DatabaseMetadata> {\n\t\treturn {\n\t\t\ttables: await this.getTables(options),\n\t\t};\n\t}\n\n\tasync #getTableMetadata(table: string): Promise<TableMetadata> {\n\t\tconst db = this.#db;\n\n\t\t// Get the SQL that was used to create the table.\n\t\tconst createSql = await db\n\t\t\t// @ts-expect-error\n\t\t\t.selectFrom(\"sqlite_master\")\n\t\t\t// @ts-expect-error\n\t\t\t.where(\"name\", \"=\", table)\n\t\t\t.select(\"sql\")\n\t\t\t.$castTo<{ sql: string | undefined }>()\n\t\t\t.execute();\n\n\t\t// Try to find the name of the column that has `autoincrement` >&\n\t\tconst autoIncrementCol = createSql[0]?.sql\n\t\t\t?.split(/[\\(\\),]/)\n\t\t\t?.find((it) => it.toLowerCase().includes(\"autoincrement\"))\n\t\t\t?.split(/\\s+/)?.[0]\n\t\t\t?.replace(/[\"`]/g, \"\");\n\n\t\tconst columns = await db\n\t\t\t.selectFrom(\n\t\t\t\tsql<{\n\t\t\t\t\tname: string;\n\t\t\t\t\ttype: string;\n\t\t\t\t\tnotnull: 0 | 1;\n\t\t\t\t\tdflt_value: any;\n\t\t\t\t}>`pragma_table_info(${table})`.as(\"table_info\"),\n\t\t\t)\n\t\t\t.select([\"name\", \"type\", \"notnull\", \"dflt_value\"])\n\t\t\t.execute();\n\n\t\treturn {\n\t\t\tname: table,\n\t\t\tcolumns: columns.map((col) => ({\n\t\t\t\tname: col.name,\n\t\t\t\tdataType: col.type,\n\t\t\t\tisNullable: !col.notnull,\n\t\t\t\tisAutoIncrementing: col.name === autoIncrementCol,\n\t\t\t\thasDefaultValue: col.dflt_value != null,\n\t\t\t})),\n\t\t\tisView: true,\n\t\t};\n\t}\n}\n\nclass NodeSqliteQueryCompiler extends DefaultQueryCompiler {\n\tprotected override getCurrentParameterPlaceholder() {\n\t\treturn \"?\";\n\t}\n\n\tprotected override getLeftIdentifierWrapper(): string {\n\t\treturn '\"';\n\t}\n\n\tprotected override getRightIdentifierWrapper(): string {\n\t\treturn '\"';\n\t}\n\n\tprotected override getAutoIncrement() {\n\t\treturn \"autoincrement\";\n\t}\n}\n\nexport class NodeSqliteDialect implements Dialect {\n\treadonly #config: NodeSqliteDialectConfig;\n\n\tconstructor(config: NodeSqliteDialectConfig) {\n\t\tthis.#config = { ...config };\n\t}\n\n\tcreateDriver(): Driver {\n\t\treturn new NodeSqliteDriver(this.#config);\n\t}\n\n\tcreateQueryCompiler(): QueryCompiler {\n\t\treturn new NodeSqliteQueryCompiler();\n\t}\n\n\tcreateAdapter(): DialectAdapter {\n\t\treturn new NodeSqliteAdapter();\n\t}\n\n\tcreateIntrospector(db: Kysely<any>): DatabaseIntrospector {\n\t\treturn new NodeSqliteIntrospector(db);\n\t}\n}\n"],"mappings":";;;AA4BA,IAAM,oBAAN,MAAsD;CACrD,IAAI,4BAAqC;AACxC,SAAO;;CAGR,IAAI,2BAAoC;AACvC,SAAO;;CAGR,IAAI,oBAA6B;AAChC,SAAO;;CAGR,MAAM,uBAAsC;CAM5C,MAAM,uBAAsC;CAK5C,IAAI,iBAA0B;AAC7B,SAAO;;;AAqBT,IAAM,mBAAN,MAAyC;CACxC,CAASA;CACT,CAASC,kBAAmB,IAAI,iBAAiB;CAEjD;CACA;CAEA,YAAY,QAAiC;AAC5C,QAAKD,SAAU,EAAE,GAAG,QAAQ;;CAG7B,MAAM,OAAsB;AAC3B,QAAKE,KAAM,MAAKF,OAAQ;AAExB,QAAKG,aAAc,IAAI,qBAAqB,MAAKD,GAAI;AAErD,MAAI,MAAKF,OAAQ,mBAChB,OAAM,MAAKA,OAAQ,mBAAmB,MAAKG,WAAY;;CAIzD,MAAM,oBAAiD;AAGtD,QAAM,MAAKF,gBAAiB,MAAM;AAClC,SAAO,MAAKE;;CAGb,MAAM,iBAAiB,YAA+C;AACrE,QAAM,WAAW,aAAa,cAAc,IAAI,QAAQ,CAAC;;CAG1D,MAAM,kBAAkB,YAA+C;AACtE,QAAM,WAAW,aAAa,cAAc,IAAI,SAAS,CAAC;;CAG3D,MAAM,oBAAoB,YAA+C;AACxE,QAAM,WAAW,aAAa,cAAc,IAAI,WAAW,CAAC;;CAG7D,MAAM,oBAAmC;AACxC,QAAKF,gBAAiB,QAAQ;;CAG/B,MAAM,UAAyB;AAC9B,QAAKC,IAAK,OAAO;;;AAInB,IAAM,uBAAN,MAAyD;CACxD,CAASA;CAET,YAAY,IAAkB;AAC7B,QAAKA,KAAM;;CAGZ,aAAgB,eAAuD;EACtE,MAAM,EAAE,KAAK,eAAe;EAG5B,MAAM,OAFO,MAAKA,GAAI,QAAQ,IAAI,CAEhB,IAAI,GAAI,WAAqB;AAE/C,SAAO,QAAQ,QAAQ,EACtB,MACA,CAAC;;CAGH,OAAO,cAAc;AACpB,QAAM,IAAI,MAAM,qDAAqD;;;AAIvE,IAAM,kBAAN,MAAsB;CACrB;CACA;CAEA,MAAM,OAAsB;AAC3B,SAAO,MAAKE,YAAa,OACxB,OAAM,MAAKA;AAGZ,QAAKA,UAAW,IAAI,SAAS,YAAY;AACxC,SAAKC,UAAW;IACf;;CAGH,SAAe;EACd,MAAM,UAAU,MAAKA;AAErB,QAAKD,UAAW;AAChB,QAAKC,UAAW;AAEhB,aAAW;;;AAIb,IAAM,yBAAN,MAA6D;CAC5D,CAASH;CAET,YAAY,IAAqB;AAChC,QAAKA,KAAM;;CAGZ,MAAM,aAAwC;AAE7C,SAAO,EAAE;;CAGV,MAAM,UACL,UAAmC,EAAE,0BAA0B,OAAO,EAC3C;EAC3B,IAAI,QAAQ,MAAKA,GAEf,WAAW,gBAAgB,CAE3B,MAAM,QAAQ,KAAK,QAAQ,CAE3B,MAAM,QAAQ,YAAY,WAAW,CACrC,OAAO,OAAO,CACd,SAA2B;AAE7B,MAAI,CAAC,QAAQ,yBACZ,SAAQ,MAEN,MAAM,QAAQ,MAAM,wBAAwB,CAE5C,MAAM,QAAQ,MAAM,6BAA6B;EAGpD,MAAM,SAAS,MAAM,MAAM,SAAS;AACpC,SAAO,QAAQ,IAAI,OAAO,KAAK,EAAE,WAAW,MAAKI,iBAAkB,KAAK,CAAC,CAAC;;CAG3E,MAAM,YACL,SAC4B;AAC5B,SAAO,EACN,QAAQ,MAAM,KAAK,UAAU,QAAQ,EACrC;;CAGF,OAAMA,iBAAkB,OAAuC;EAC9D,MAAM,KAAK,MAAKJ;EAahB,MAAM,oBAVY,MAAM,GAEtB,WAAW,gBAAgB,CAE3B,MAAM,QAAQ,KAAK,MAAM,CACzB,OAAO,MAAM,CACb,SAAsC,CACtC,SAAS,EAGwB,IAAI,KACpC,MAAM,UAAU,EAChB,MAAM,OAAO,GAAG,aAAa,CAAC,SAAS,gBAAgB,CAAC,EACxD,MAAM,MAAM,GAAG,IACf,QAAQ,SAAS,GAAG;AAcvB,SAAO;GACN,MAAM;GACN,UAde,MAAM,GACpB,WACA,GAKE,qBAAqB,MAAM,GAAG,GAAG,aAAa,CAChD,CACA,OAAO;IAAC;IAAQ;IAAQ;IAAW;IAAa,CAAC,CACjD,SAAS,EAIO,KAAK,SAAS;IAC9B,MAAM,IAAI;IACV,UAAU,IAAI;IACd,YAAY,CAAC,IAAI;IACjB,oBAAoB,IAAI,SAAS;IACjC,iBAAiB,IAAI,cAAc;IACnC,EAAE;GACH,QAAQ;GACR;;;AAIH,IAAM,0BAAN,cAAsC,qBAAqB;CAC1D,AAAmB,iCAAiC;AACnD,SAAO;;CAGR,AAAmB,2BAAmC;AACrD,SAAO;;CAGR,AAAmB,4BAAoC;AACtD,SAAO;;CAGR,AAAmB,mBAAmB;AACrC,SAAO;;;AAIT,IAAa,oBAAb,MAAkD;CACjD,CAASF;CAET,YAAY,QAAiC;AAC5C,QAAKA,SAAU,EAAE,GAAG,QAAQ;;CAG7B,eAAuB;AACtB,SAAO,IAAI,iBAAiB,MAAKA,OAAQ;;CAG1C,sBAAqC;AACpC,SAAO,IAAI,yBAAyB;;CAGrC,gBAAgC;AAC/B,SAAO,IAAI,mBAAmB;;CAG/B,mBAAmB,IAAuC;AACzD,SAAO,IAAI,uBAAuB,GAAG"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/kysely-adapter",
|
|
3
|
-
"version": "1.5.0
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Kysely adapter for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://www.better-auth.com/docs/adapters/kysely",
|
|
6
8
|
"repository": {
|
|
7
9
|
"type": "git",
|
|
8
10
|
"url": "git+https://github.com/better-auth/better-auth.git",
|
|
9
11
|
"directory": "packages/kysely-adapter"
|
|
10
12
|
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"auth",
|
|
15
|
+
"kysely",
|
|
16
|
+
"adapter",
|
|
17
|
+
"typescript",
|
|
18
|
+
"better-auth"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
11
26
|
"main": "./dist/index.mjs",
|
|
12
27
|
"module": "./dist/index.mjs",
|
|
13
28
|
"types": "./dist/index.d.mts",
|
|
@@ -26,19 +41,22 @@
|
|
|
26
41
|
"peerDependencies": {
|
|
27
42
|
"@better-auth/utils": "^0.3.0",
|
|
28
43
|
"kysely": "^0.27.0 || ^0.28.0",
|
|
29
|
-
"@better-auth/core": "1.5.0
|
|
44
|
+
"@better-auth/core": "1.5.0"
|
|
30
45
|
},
|
|
31
46
|
"devDependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"
|
|
34
|
-
"
|
|
47
|
+
"@cloudflare/workers-types": "^4.20250121.0",
|
|
48
|
+
"@better-auth/utils": "^0.3.1",
|
|
49
|
+
"kysely": "^0.28.11",
|
|
50
|
+
"tsdown": "^0.20.3",
|
|
35
51
|
"typescript": "^5.9.3",
|
|
36
|
-
"@better-auth/core": "1.5.0
|
|
52
|
+
"@better-auth/core": "1.5.0"
|
|
37
53
|
},
|
|
38
54
|
"scripts": {
|
|
39
55
|
"build": "tsdown",
|
|
40
56
|
"dev": "tsdown --watch",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
57
|
+
"lint:package": "publint run --strict",
|
|
58
|
+
"lint:types": "attw --profile esm-only --pack .",
|
|
59
|
+
"typecheck": "tsc --noEmit",
|
|
60
|
+
"test": "vitest"
|
|
43
61
|
}
|
|
44
62
|
}
|