@holeauth/2fa-drizzle 0.0.1-alpha.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.
@@ -0,0 +1,138 @@
1
+ import * as drizzle_orm from 'drizzle-orm';
2
+ import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
3
+ import { SQLiteTableWithColumns } from 'drizzle-orm/sqlite-core';
4
+ import { TwoFactorAdapter } from '@holeauth/plugin-2fa';
5
+
6
+ type SqliteUsersTable = SQLiteTableWithColumns<any> & {
7
+ id: any;
8
+ };
9
+ interface CreateTwoFactorTablesOptions<U extends SqliteUsersTable> {
10
+ usersTable: U;
11
+ prefix?: string;
12
+ }
13
+ declare function createTwoFactorTables<U extends SqliteUsersTable>(opts: CreateTwoFactorTablesOptions<U>): {
14
+ tables: {
15
+ twoFactor: SQLiteTableWithColumns<{
16
+ name: string;
17
+ schema: undefined;
18
+ columns: {
19
+ userId: drizzle_orm_sqlite_core.SQLiteColumn<{
20
+ name: "user_id";
21
+ tableName: string;
22
+ dataType: "string";
23
+ columnType: "SQLiteText";
24
+ data: string;
25
+ driverParam: string;
26
+ notNull: true;
27
+ hasDefault: false;
28
+ isPrimaryKey: true;
29
+ isAutoincrement: false;
30
+ hasRuntimeDefault: false;
31
+ enumValues: [string, ...string[]];
32
+ baseColumn: never;
33
+ identity: undefined;
34
+ generated: undefined;
35
+ }, object>;
36
+ secret: drizzle_orm_sqlite_core.SQLiteColumn<{
37
+ name: "secret";
38
+ tableName: string;
39
+ dataType: "string";
40
+ columnType: "SQLiteText";
41
+ data: string;
42
+ driverParam: string;
43
+ notNull: true;
44
+ hasDefault: false;
45
+ isPrimaryKey: false;
46
+ isAutoincrement: false;
47
+ hasRuntimeDefault: false;
48
+ enumValues: [string, ...string[]];
49
+ baseColumn: never;
50
+ identity: undefined;
51
+ generated: undefined;
52
+ }, object>;
53
+ enabled: drizzle_orm_sqlite_core.SQLiteColumn<{
54
+ name: "enabled";
55
+ tableName: string;
56
+ dataType: "boolean";
57
+ columnType: "SQLiteBoolean";
58
+ data: boolean;
59
+ driverParam: number;
60
+ notNull: true;
61
+ hasDefault: true;
62
+ isPrimaryKey: false;
63
+ isAutoincrement: false;
64
+ hasRuntimeDefault: false;
65
+ enumValues: undefined;
66
+ baseColumn: never;
67
+ identity: undefined;
68
+ generated: undefined;
69
+ }, object>;
70
+ recoveryCodes: drizzle_orm_sqlite_core.SQLiteColumn<{
71
+ name: "recovery_codes";
72
+ tableName: string;
73
+ dataType: "json";
74
+ columnType: "SQLiteTextJson";
75
+ data: string[];
76
+ driverParam: string;
77
+ notNull: true;
78
+ hasDefault: true;
79
+ isPrimaryKey: false;
80
+ isAutoincrement: false;
81
+ hasRuntimeDefault: false;
82
+ enumValues: undefined;
83
+ baseColumn: never;
84
+ identity: undefined;
85
+ generated: undefined;
86
+ }, object>;
87
+ createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
88
+ name: "created_at";
89
+ tableName: string;
90
+ dataType: "date";
91
+ columnType: "SQLiteTimestamp";
92
+ data: Date;
93
+ driverParam: number;
94
+ notNull: true;
95
+ hasDefault: true;
96
+ isPrimaryKey: false;
97
+ isAutoincrement: false;
98
+ hasRuntimeDefault: true;
99
+ enumValues: undefined;
100
+ baseColumn: never;
101
+ identity: undefined;
102
+ generated: undefined;
103
+ }, object>;
104
+ updatedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
105
+ name: "updated_at";
106
+ tableName: string;
107
+ dataType: "date";
108
+ columnType: "SQLiteTimestamp";
109
+ data: Date;
110
+ driverParam: number;
111
+ notNull: true;
112
+ hasDefault: true;
113
+ isPrimaryKey: false;
114
+ isAutoincrement: false;
115
+ hasRuntimeDefault: true;
116
+ enumValues: undefined;
117
+ baseColumn: never;
118
+ identity: undefined;
119
+ generated: undefined;
120
+ }, object>;
121
+ };
122
+ dialect: "sqlite";
123
+ }>;
124
+ };
125
+ relations: {
126
+ twoFactorRelations: drizzle_orm.Relations<string, {
127
+ user: drizzle_orm.One<U["_"]["name"], true>;
128
+ }>;
129
+ };
130
+ };
131
+ type Tables = ReturnType<typeof createTwoFactorTables>['tables'];
132
+ interface CreateTwoFactorAdapterOptions {
133
+ db: any;
134
+ tables: Tables;
135
+ }
136
+ declare function createTwoFactorAdapter(opts: CreateTwoFactorAdapterOptions): TwoFactorAdapter;
137
+
138
+ export { type CreateTwoFactorAdapterOptions, type CreateTwoFactorTablesOptions, type SqliteUsersTable, createTwoFactorAdapter, createTwoFactorTables };
@@ -0,0 +1,68 @@
1
+ import { sqliteTable, integer, text } from 'drizzle-orm/sqlite-core';
2
+ import { relations, eq } from 'drizzle-orm';
3
+
4
+ // src/sqlite/index.ts
5
+ function createTwoFactorTables(opts) {
6
+ const { usersTable, prefix = "holeauth_2fa_" } = opts;
7
+ const p = (s) => `${prefix}${s}`;
8
+ const twoFactor = sqliteTable(p("credential"), {
9
+ userId: text("user_id").primaryKey().references(() => usersTable.id, { onDelete: "cascade" }),
10
+ secret: text("secret").notNull(),
11
+ enabled: integer("enabled", { mode: "boolean" }).notNull().default(false),
12
+ recoveryCodes: text("recovery_codes", { mode: "json" }).$type().notNull().default([]),
13
+ createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date()),
14
+ updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date())
15
+ });
16
+ const twoFactorRelations = relations(twoFactor, ({ one }) => ({
17
+ user: one(usersTable, { fields: [twoFactor.userId], references: [usersTable.id] })
18
+ }));
19
+ return { tables: { twoFactor }, relations: { twoFactorRelations } };
20
+ }
21
+ var rowToRecord = (r) => ({
22
+ userId: String(r.userId),
23
+ secret: String(r.secret),
24
+ enabled: Boolean(r.enabled),
25
+ recoveryCodes: r.recoveryCodes ?? [],
26
+ createdAt: r.createdAt,
27
+ updatedAt: r.updatedAt
28
+ });
29
+ function createTwoFactorAdapter(opts) {
30
+ const { db, tables } = opts;
31
+ const { twoFactor } = tables;
32
+ return {
33
+ async getByUserId(userId) {
34
+ const rows = await db.select().from(twoFactor).where(eq(twoFactor.userId, userId)).limit(1);
35
+ return rows[0] ? rowToRecord(rows[0]) : null;
36
+ },
37
+ async upsert(record) {
38
+ const [row] = await db.insert(twoFactor).values({
39
+ userId: record.userId,
40
+ secret: record.secret,
41
+ enabled: record.enabled,
42
+ recoveryCodes: record.recoveryCodes
43
+ }).onConflictDoUpdate({
44
+ target: twoFactor.userId,
45
+ set: {
46
+ secret: record.secret,
47
+ enabled: record.enabled,
48
+ recoveryCodes: record.recoveryCodes,
49
+ updatedAt: /* @__PURE__ */ new Date()
50
+ }
51
+ }).returning();
52
+ return rowToRecord(row);
53
+ },
54
+ async update(userId, patch) {
55
+ const toSet = { ...patch, updatedAt: /* @__PURE__ */ new Date() };
56
+ delete toSet.userId;
57
+ const [row] = await db.update(twoFactor).set(toSet).where(eq(twoFactor.userId, userId)).returning();
58
+ return row ? rowToRecord(row) : null;
59
+ },
60
+ async delete(userId) {
61
+ await db.delete(twoFactor).where(eq(twoFactor.userId, userId));
62
+ }
63
+ };
64
+ }
65
+
66
+ export { createTwoFactorAdapter, createTwoFactorTables };
67
+ //# sourceMappingURL=index.js.map
68
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { sqliteTable, text, integer, type SQLiteTableWithColumns } from 'drizzle-orm/sqlite-core';\nimport { relations, eq } from 'drizzle-orm';\nimport type { TwoFactorAdapter, TwoFactorRecord } from '@holeauth/plugin-2fa';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type SqliteUsersTable = SQLiteTableWithColumns<any> & { id: any };\n\nexport interface CreateTwoFactorTablesOptions<U extends SqliteUsersTable> {\n usersTable: U;\n prefix?: string;\n}\n\nexport function createTwoFactorTables<U extends SqliteUsersTable>(opts: CreateTwoFactorTablesOptions<U>) {\n const { usersTable, prefix = 'holeauth_2fa_' } = opts;\n const p = (s: string) => `${prefix}${s}`;\n const twoFactor = sqliteTable(p('credential'), {\n userId: text('user_id')\n .primaryKey()\n .references(() => usersTable.id, { onDelete: 'cascade' }),\n secret: text('secret').notNull(),\n enabled: integer('enabled', { mode: 'boolean' }).notNull().default(false),\n recoveryCodes: text('recovery_codes', { mode: 'json' }).$type<string[]>().notNull().default([]),\n createdAt: integer('created_at', { mode: 'timestamp_ms' })\n .notNull()\n .$defaultFn(() => new Date()),\n updatedAt: integer('updated_at', { mode: 'timestamp_ms' })\n .notNull()\n .$defaultFn(() => new Date()),\n });\n const twoFactorRelations = relations(twoFactor, ({ one }) => ({\n user: one(usersTable, { fields: [twoFactor.userId], references: [usersTable.id] }),\n }));\n return { tables: { twoFactor }, relations: { twoFactorRelations } };\n}\n\ntype Tables = ReturnType<typeof createTwoFactorTables>['tables'];\n\nexport interface CreateTwoFactorAdapterOptions {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n db: any;\n tables: Tables;\n}\n\nconst rowToRecord = (r: Record<string, unknown>): TwoFactorRecord => ({\n userId: String(r.userId),\n secret: String(r.secret),\n enabled: Boolean(r.enabled),\n recoveryCodes: (r.recoveryCodes as string[] | null | undefined) ?? [],\n createdAt: r.createdAt as Date | undefined,\n updatedAt: r.updatedAt as Date | undefined,\n});\n\nexport function createTwoFactorAdapter(opts: CreateTwoFactorAdapterOptions): TwoFactorAdapter {\n const { db, tables } = opts;\n const { twoFactor } = tables;\n return {\n async getByUserId(userId) {\n const rows = await db.select().from(twoFactor).where(eq(twoFactor.userId, userId)).limit(1);\n return rows[0] ? rowToRecord(rows[0]) : null;\n },\n async upsert(record) {\n const [row] = await db\n .insert(twoFactor)\n .values({\n userId: record.userId,\n secret: record.secret,\n enabled: record.enabled,\n recoveryCodes: record.recoveryCodes,\n })\n .onConflictDoUpdate({\n target: twoFactor.userId,\n set: {\n secret: record.secret,\n enabled: record.enabled,\n recoveryCodes: record.recoveryCodes,\n updatedAt: new Date(),\n },\n })\n .returning();\n return rowToRecord(row);\n },\n async update(userId, patch) {\n const toSet: Record<string, unknown> = { ...patch, updatedAt: new Date() };\n delete toSet.userId;\n const [row] = await db.update(twoFactor).set(toSet).where(eq(twoFactor.userId, userId)).returning();\n return row ? rowToRecord(row) : null;\n },\n async delete(userId) {\n await db.delete(twoFactor).where(eq(twoFactor.userId, userId));\n },\n };\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "@holeauth/2fa-drizzle",
3
+ "version": "0.0.1-alpha.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/robert-kratz/holeauth.git",
7
+ "directory": "packages/2fa-drizzle"
8
+ },
9
+ "description": "Drizzle adapter for @holeauth/plugin-2fa (TOTP + recovery codes).",
10
+ "license": "MIT",
11
+ "author": "Robert Kratz",
12
+ "type": "module",
13
+ "sideEffects": false,
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js",
19
+ "require": "./dist/index.cjs"
20
+ },
21
+ "./pg": {
22
+ "types": "./dist/pg/index.d.ts",
23
+ "import": "./dist/pg/index.js",
24
+ "require": "./dist/pg/index.cjs"
25
+ },
26
+ "./mysql": {
27
+ "types": "./dist/mysql/index.d.ts",
28
+ "import": "./dist/mysql/index.js",
29
+ "require": "./dist/mysql/index.cjs"
30
+ },
31
+ "./sqlite": {
32
+ "types": "./dist/sqlite/index.d.ts",
33
+ "import": "./dist/sqlite/index.js",
34
+ "require": "./dist/sqlite/index.cjs"
35
+ },
36
+ "./package.json": "./package.json"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md",
41
+ "LICENSE"
42
+ ],
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "provenance": true
46
+ },
47
+ "peerDependencies": {
48
+ "drizzle-orm": ">=0.33.0",
49
+ "@holeauth/plugin-2fa": "0.0.1-alpha.0"
50
+ },
51
+ "devDependencies": {
52
+ "@testcontainers/mysql": "^11.14.0",
53
+ "@testcontainers/postgresql": "^11.14.0",
54
+ "@types/better-sqlite3": "^7.6.13",
55
+ "@types/node": "^20.16.10",
56
+ "@types/pg": "^8.11.10",
57
+ "@vitest/coverage-v8": "^2.1.9",
58
+ "better-sqlite3": "^12.9.0",
59
+ "drizzle-orm": "^0.36.0",
60
+ "mysql2": "^3.22.2",
61
+ "pg": "^8.13.0",
62
+ "testcontainers": "^11.14.0",
63
+ "tsup": "^8.3.0",
64
+ "typescript": "^5.6.2",
65
+ "vitest": "^2.1.2",
66
+ "@holeauth/eslint-config": "0.0.0",
67
+ "@holeauth/plugin-2fa": "0.0.1-alpha.0",
68
+ "@holeauth/tsconfig": "0.0.0"
69
+ },
70
+ "scripts": {
71
+ "build": "tsup",
72
+ "dev": "tsup --watch",
73
+ "clean": "rm -rf dist .turbo",
74
+ "lint": "echo 'lint skipped'",
75
+ "typecheck": "tsc --noEmit",
76
+ "test": "vitest run --passWithNoTests",
77
+ "test:coverage": "vitest run --coverage"
78
+ }
79
+ }