@holeauth/adapter-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.
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/mysql/index.cjs +285 -0
- package/dist/mysql/index.cjs.map +1 -0
- package/dist/mysql/index.d.cts +602 -0
- package/dist/mysql/index.d.ts +602 -0
- package/dist/mysql/index.js +282 -0
- package/dist/mysql/index.js.map +1 -0
- package/dist/pg/index.cjs +289 -0
- package/dist/pg/index.cjs.map +1 -0
- package/dist/pg/index.d.cts +609 -0
- package/dist/pg/index.d.ts +609 -0
- package/dist/pg/index.js +286 -0
- package/dist/pg/index.js.map +1 -0
- package/dist/sqlite/index.cjs +271 -0
- package/dist/sqlite/index.cjs.map +1 -0
- package/dist/sqlite/index.d.cts +602 -0
- package/dist/sqlite/index.d.ts +602 -0
- package/dist/sqlite/index.js +268 -0
- package/dist/sqlite/index.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { sqliteTable, text, integer, index, uniqueIndex, primaryKey } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
import { relations, eq, and, sql } from 'drizzle-orm';
|
|
3
|
+
|
|
4
|
+
// src/sqlite/index.ts
|
|
5
|
+
function createHoleauthTables(opts) {
|
|
6
|
+
const { usersTable, prefix = "holeauth_" } = opts;
|
|
7
|
+
const p = (s) => `${prefix}${s}`;
|
|
8
|
+
const sessions = sqliteTable(
|
|
9
|
+
p("session"),
|
|
10
|
+
{
|
|
11
|
+
id: text("id").primaryKey(),
|
|
12
|
+
userId: text("user_id").notNull().references(() => usersTable.id, { onDelete: "cascade" }),
|
|
13
|
+
familyId: text("family_id").notNull(),
|
|
14
|
+
refreshTokenHash: text("refresh_token_hash").notNull(),
|
|
15
|
+
expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull(),
|
|
16
|
+
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date()),
|
|
17
|
+
revokedAt: integer("revoked_at", { mode: "timestamp_ms" }),
|
|
18
|
+
userAgent: text("user_agent"),
|
|
19
|
+
ip: text("ip")
|
|
20
|
+
},
|
|
21
|
+
(t) => ({
|
|
22
|
+
familyIdx: index(`${p("session")}_family_idx`).on(t.familyId),
|
|
23
|
+
hashIdx: uniqueIndex(`${p("session")}_hash_idx`).on(t.refreshTokenHash),
|
|
24
|
+
userIdx: index(`${p("session")}_user_idx`).on(t.userId)
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
const accounts = sqliteTable(
|
|
28
|
+
p("account"),
|
|
29
|
+
{
|
|
30
|
+
id: text("id").primaryKey(),
|
|
31
|
+
userId: text("user_id").notNull().references(() => usersTable.id, { onDelete: "cascade" }),
|
|
32
|
+
provider: text("provider").notNull(),
|
|
33
|
+
providerAccountId: text("provider_account_id").notNull(),
|
|
34
|
+
email: text("email"),
|
|
35
|
+
accessToken: text("access_token"),
|
|
36
|
+
refreshToken: text("refresh_token"),
|
|
37
|
+
expiresAt: integer("expires_at", { mode: "timestamp_ms" }),
|
|
38
|
+
tokenType: text("token_type"),
|
|
39
|
+
scope: text("scope"),
|
|
40
|
+
idToken: text("id_token")
|
|
41
|
+
},
|
|
42
|
+
(t) => ({
|
|
43
|
+
providerIdx: uniqueIndex(`${p("account")}_provider_idx`).on(t.provider, t.providerAccountId),
|
|
44
|
+
userIdx: index(`${p("account")}_user_idx`).on(t.userId)
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
const verificationTokens = sqliteTable(
|
|
48
|
+
p("verification_token"),
|
|
49
|
+
{
|
|
50
|
+
identifier: text("identifier").notNull(),
|
|
51
|
+
token: text("token").notNull(),
|
|
52
|
+
expiresAt: integer("expires_at", { mode: "timestamp_ms" }).notNull()
|
|
53
|
+
},
|
|
54
|
+
(t) => ({ pk: primaryKey({ columns: [t.identifier, t.token] }) })
|
|
55
|
+
);
|
|
56
|
+
const auditLog = sqliteTable(
|
|
57
|
+
p("audit_log"),
|
|
58
|
+
{
|
|
59
|
+
id: text("id").primaryKey(),
|
|
60
|
+
type: text("type").notNull(),
|
|
61
|
+
userId: text("user_id").references(() => usersTable.id, { onDelete: "set null" }),
|
|
62
|
+
sessionId: text("session_id"),
|
|
63
|
+
at: integer("at", { mode: "timestamp_ms" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date()),
|
|
64
|
+
ip: text("ip"),
|
|
65
|
+
userAgent: text("user_agent"),
|
|
66
|
+
data: text("data", { mode: "json" })
|
|
67
|
+
},
|
|
68
|
+
(t) => ({
|
|
69
|
+
typeIdx: index(`${p("audit_log")}_type_idx`).on(t.type),
|
|
70
|
+
userIdx: index(`${p("audit_log")}_user_idx`).on(t.userId)
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
const sessionsRelations = relations(sessions, ({ one }) => ({
|
|
74
|
+
user: one(usersTable, { fields: [sessions.userId], references: [usersTable.id] })
|
|
75
|
+
}));
|
|
76
|
+
const accountsRelations = relations(accounts, ({ one }) => ({
|
|
77
|
+
user: one(usersTable, { fields: [accounts.userId], references: [usersTable.id] })
|
|
78
|
+
}));
|
|
79
|
+
const auditLogRelations = relations(auditLog, ({ one }) => ({
|
|
80
|
+
user: one(usersTable, { fields: [auditLog.userId], references: [usersTable.id] })
|
|
81
|
+
}));
|
|
82
|
+
return {
|
|
83
|
+
tables: { users: usersTable, sessions, accounts, verificationTokens, auditLog },
|
|
84
|
+
relations: { sessionsRelations, accountsRelations, auditLogRelations }
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function createHoleauthAdapters(opts) {
|
|
88
|
+
const { db, tables, userEmailColumn = "email", generateId = () => crypto.randomUUID() } = opts;
|
|
89
|
+
const { users, sessions, accounts, verificationTokens, auditLog } = tables;
|
|
90
|
+
const emailCol = users[userEmailColumn];
|
|
91
|
+
if (!emailCol) {
|
|
92
|
+
throw new Error(`[holeauth] usersTable missing "${userEmailColumn}" column.`);
|
|
93
|
+
}
|
|
94
|
+
const userRowToAdapter = (r) => ({
|
|
95
|
+
id: String(r.id),
|
|
96
|
+
email: String(r[userEmailColumn] ?? ""),
|
|
97
|
+
emailVerified: r.emailVerified ?? null,
|
|
98
|
+
name: r.name ?? null,
|
|
99
|
+
image: r.image ?? null,
|
|
100
|
+
passwordHash: r.passwordHash ?? null
|
|
101
|
+
});
|
|
102
|
+
const user = {
|
|
103
|
+
async getUserById(id) {
|
|
104
|
+
const rows = await db.select().from(users).where(eq(users.id, id)).limit(1);
|
|
105
|
+
return rows[0] ? userRowToAdapter(rows[0]) : null;
|
|
106
|
+
},
|
|
107
|
+
async getUserByEmail(email) {
|
|
108
|
+
const rows = await db.select().from(users).where(eq(emailCol, email)).limit(1);
|
|
109
|
+
return rows[0] ? userRowToAdapter(rows[0]) : null;
|
|
110
|
+
},
|
|
111
|
+
async createUser(data) {
|
|
112
|
+
const id = generateId();
|
|
113
|
+
const [row] = await db.insert(users).values({
|
|
114
|
+
id,
|
|
115
|
+
[userEmailColumn]: data.email,
|
|
116
|
+
emailVerified: data.emailVerified ?? null,
|
|
117
|
+
name: data.name ?? null,
|
|
118
|
+
image: data.image ?? null,
|
|
119
|
+
passwordHash: data.passwordHash ?? null
|
|
120
|
+
}).returning();
|
|
121
|
+
return userRowToAdapter(row);
|
|
122
|
+
},
|
|
123
|
+
async updateUser(id, patch) {
|
|
124
|
+
const toSet = { ...patch };
|
|
125
|
+
if ("email" in toSet) {
|
|
126
|
+
toSet[userEmailColumn] = toSet.email;
|
|
127
|
+
if (userEmailColumn !== "email") delete toSet.email;
|
|
128
|
+
}
|
|
129
|
+
const [row] = await db.update(users).set(toSet).where(eq(users.id, id)).returning();
|
|
130
|
+
if (!row) throw new Error(`User ${id} not found`);
|
|
131
|
+
return userRowToAdapter(row);
|
|
132
|
+
},
|
|
133
|
+
async deleteUser(id) {
|
|
134
|
+
await db.delete(users).where(eq(users.id, id));
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const sessionRowToAdapter = (r) => ({
|
|
138
|
+
id: String(r.id),
|
|
139
|
+
userId: String(r.userId),
|
|
140
|
+
familyId: String(r.familyId),
|
|
141
|
+
refreshTokenHash: String(r.refreshTokenHash),
|
|
142
|
+
expiresAt: r.expiresAt,
|
|
143
|
+
createdAt: r.createdAt,
|
|
144
|
+
revokedAt: r.revokedAt ?? null,
|
|
145
|
+
userAgent: r.userAgent ?? null,
|
|
146
|
+
ip: r.ip ?? null
|
|
147
|
+
});
|
|
148
|
+
const session = {
|
|
149
|
+
async createSession(data) {
|
|
150
|
+
const [row] = await db.insert(sessions).values(data).returning();
|
|
151
|
+
return sessionRowToAdapter(row);
|
|
152
|
+
},
|
|
153
|
+
async getSession(id) {
|
|
154
|
+
const rows = await db.select().from(sessions).where(eq(sessions.id, id)).limit(1);
|
|
155
|
+
return rows[0] ? sessionRowToAdapter(rows[0]) : null;
|
|
156
|
+
},
|
|
157
|
+
async getByRefreshHash(hash) {
|
|
158
|
+
const rows = await db.select().from(sessions).where(eq(sessions.refreshTokenHash, hash)).limit(1);
|
|
159
|
+
return rows[0] ? sessionRowToAdapter(rows[0]) : null;
|
|
160
|
+
},
|
|
161
|
+
async findByFamily(familyId) {
|
|
162
|
+
const rows = await db.select().from(sessions).where(eq(sessions.familyId, familyId));
|
|
163
|
+
return rows.map(sessionRowToAdapter);
|
|
164
|
+
},
|
|
165
|
+
async deleteSession(id) {
|
|
166
|
+
await db.delete(sessions).where(eq(sessions.id, id));
|
|
167
|
+
},
|
|
168
|
+
async rotateRefresh(id, newHash, expiresAt) {
|
|
169
|
+
const [row] = await db.update(sessions).set({ refreshTokenHash: newHash, expiresAt }).where(eq(sessions.id, id)).returning();
|
|
170
|
+
if (!row) throw new Error(`Session ${id} not found`);
|
|
171
|
+
return sessionRowToAdapter(row);
|
|
172
|
+
},
|
|
173
|
+
async revokeFamily(familyId) {
|
|
174
|
+
await db.update(sessions).set({ revokedAt: /* @__PURE__ */ new Date() }).where(and(eq(sessions.familyId, familyId), sql`${sessions.revokedAt} IS NULL`));
|
|
175
|
+
},
|
|
176
|
+
async revokeUser(userId) {
|
|
177
|
+
await db.update(sessions).set({ revokedAt: /* @__PURE__ */ new Date() }).where(and(eq(sessions.userId, userId), sql`${sessions.revokedAt} IS NULL`));
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
const accountRowToAdapter = (r) => ({
|
|
181
|
+
id: String(r.id),
|
|
182
|
+
userId: String(r.userId),
|
|
183
|
+
provider: String(r.provider),
|
|
184
|
+
providerAccountId: String(r.providerAccountId),
|
|
185
|
+
email: r.email ?? null,
|
|
186
|
+
accessToken: r.accessToken ?? null,
|
|
187
|
+
refreshToken: r.refreshToken ?? null,
|
|
188
|
+
expiresAt: r.expiresAt ?? null,
|
|
189
|
+
tokenType: r.tokenType ?? null,
|
|
190
|
+
scope: r.scope ?? null,
|
|
191
|
+
idToken: r.idToken ?? null
|
|
192
|
+
});
|
|
193
|
+
const account = {
|
|
194
|
+
async linkAccount(data) {
|
|
195
|
+
const [row] = await db.insert(accounts).values({ id: generateId(), ...data }).returning();
|
|
196
|
+
return accountRowToAdapter(row);
|
|
197
|
+
},
|
|
198
|
+
async getAccountByProvider(provider, providerAccountId) {
|
|
199
|
+
const rows = await db.select().from(accounts).where(and(eq(accounts.provider, provider), eq(accounts.providerAccountId, providerAccountId))).limit(1);
|
|
200
|
+
return rows[0] ? accountRowToAdapter(rows[0]) : null;
|
|
201
|
+
},
|
|
202
|
+
async getByProviderEmail(provider, email) {
|
|
203
|
+
const rows = await db.select().from(accounts).where(and(eq(accounts.provider, provider), eq(accounts.email, email))).limit(1);
|
|
204
|
+
return rows[0] ? accountRowToAdapter(rows[0]) : null;
|
|
205
|
+
},
|
|
206
|
+
async listByUser(userId) {
|
|
207
|
+
const rows = await db.select().from(accounts).where(eq(accounts.userId, userId));
|
|
208
|
+
return rows.map(accountRowToAdapter);
|
|
209
|
+
},
|
|
210
|
+
async unlinkAccount(id) {
|
|
211
|
+
await db.delete(accounts).where(eq(accounts.id, id));
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
const vtRowToAdapter = (r) => ({
|
|
215
|
+
identifier: String(r.identifier),
|
|
216
|
+
token: String(r.token),
|
|
217
|
+
expiresAt: r.expiresAt
|
|
218
|
+
});
|
|
219
|
+
const verificationToken = {
|
|
220
|
+
async create(data) {
|
|
221
|
+
const [row] = await db.insert(verificationTokens).values(data).returning();
|
|
222
|
+
return vtRowToAdapter(row);
|
|
223
|
+
},
|
|
224
|
+
async consume(identifier, token) {
|
|
225
|
+
const [row] = await db.delete(verificationTokens).where(and(eq(verificationTokens.identifier, identifier), eq(verificationTokens.token, token))).returning();
|
|
226
|
+
if (!row) return null;
|
|
227
|
+
const rec = vtRowToAdapter(row);
|
|
228
|
+
return rec.expiresAt.getTime() < Date.now() ? null : rec;
|
|
229
|
+
},
|
|
230
|
+
async purgeExpired() {
|
|
231
|
+
const res = await db.delete(verificationTokens).where(sql`${verificationTokens.expiresAt} < ${Date.now()}`).returning({ identifier: verificationTokens.identifier });
|
|
232
|
+
return res.length;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
const auditRowToAdapter = (r) => ({
|
|
236
|
+
id: String(r.id),
|
|
237
|
+
type: String(r.type),
|
|
238
|
+
userId: r.userId ?? null,
|
|
239
|
+
sessionId: r.sessionId ?? null,
|
|
240
|
+
at: r.at,
|
|
241
|
+
ip: r.ip ?? null,
|
|
242
|
+
userAgent: r.userAgent ?? null,
|
|
243
|
+
data: r.data ?? null
|
|
244
|
+
});
|
|
245
|
+
const auditLogAdapter = {
|
|
246
|
+
async record(event) {
|
|
247
|
+
await db.insert(auditLog).values({ id: event.id ?? generateId(), ...event });
|
|
248
|
+
},
|
|
249
|
+
async list(filter) {
|
|
250
|
+
const conds = [];
|
|
251
|
+
if (filter.userId) conds.push(eq(auditLog.userId, filter.userId));
|
|
252
|
+
if (filter.type) conds.push(eq(auditLog.type, filter.type));
|
|
253
|
+
const q = db.select().from(auditLog);
|
|
254
|
+
const rows = conds.length ? await q.where(and(...conds)).limit(filter.limit ?? 100) : await q.limit(filter.limit ?? 100);
|
|
255
|
+
return rows.map(auditRowToAdapter);
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
const transaction = {
|
|
259
|
+
async run(fn) {
|
|
260
|
+
return db.transaction(async () => fn());
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
return { user, session, account, verificationToken, auditLog: auditLogAdapter, transaction };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export { createHoleauthAdapters, createHoleauthTables };
|
|
267
|
+
//# sourceMappingURL=index.js.map
|
|
268
|
+
//# 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 {\n sqliteTable,\n text,\n integer,\n index,\n uniqueIndex,\n primaryKey,\n type SQLiteTableWithColumns,\n} from 'drizzle-orm/sqlite-core';\nimport { relations, eq, and, sql } from 'drizzle-orm';\nimport type {\n AdapterUser,\n AdapterSession,\n AdapterAccount,\n AdapterVerificationToken,\n AdapterAuditEvent,\n UserAdapter,\n SessionAdapter,\n AccountAdapter,\n VerificationTokenAdapter,\n AuditLogAdapter,\n TransactionAdapter,\n} from '@holeauth/core/adapters';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type SqliteUsersTable = SQLiteTableWithColumns<any> & { id: any };\n\nexport interface CreateHoleauthTablesOptions<U extends SqliteUsersTable> {\n usersTable: U;\n prefix?: string;\n}\n\nexport function createHoleauthTables<U extends SqliteUsersTable>(\n opts: CreateHoleauthTablesOptions<U>,\n) {\n const { usersTable, prefix = 'holeauth_' } = opts;\n const p = (s: string) => `${prefix}${s}`;\n\n const sessions = sqliteTable(\n p('session'),\n {\n id: text('id').primaryKey(),\n userId: text('user_id')\n .notNull()\n .references(() => usersTable.id, { onDelete: 'cascade' }),\n familyId: text('family_id').notNull(),\n refreshTokenHash: text('refresh_token_hash').notNull(),\n expiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(),\n createdAt: integer('created_at', { mode: 'timestamp_ms' })\n .notNull()\n .$defaultFn(() => new Date()),\n revokedAt: integer('revoked_at', { mode: 'timestamp_ms' }),\n userAgent: text('user_agent'),\n ip: text('ip'),\n },\n (t) => ({\n familyIdx: index(`${p('session')}_family_idx`).on(t.familyId),\n hashIdx: uniqueIndex(`${p('session')}_hash_idx`).on(t.refreshTokenHash),\n userIdx: index(`${p('session')}_user_idx`).on(t.userId),\n }),\n );\n\n const accounts = sqliteTable(\n p('account'),\n {\n id: text('id').primaryKey(),\n userId: text('user_id')\n .notNull()\n .references(() => usersTable.id, { onDelete: 'cascade' }),\n provider: text('provider').notNull(),\n providerAccountId: text('provider_account_id').notNull(),\n email: text('email'),\n accessToken: text('access_token'),\n refreshToken: text('refresh_token'),\n expiresAt: integer('expires_at', { mode: 'timestamp_ms' }),\n tokenType: text('token_type'),\n scope: text('scope'),\n idToken: text('id_token'),\n },\n (t) => ({\n providerIdx: uniqueIndex(`${p('account')}_provider_idx`).on(t.provider, t.providerAccountId),\n userIdx: index(`${p('account')}_user_idx`).on(t.userId),\n }),\n );\n\n const verificationTokens = sqliteTable(\n p('verification_token'),\n {\n identifier: text('identifier').notNull(),\n token: text('token').notNull(),\n expiresAt: integer('expires_at', { mode: 'timestamp_ms' }).notNull(),\n },\n (t) => ({ pk: primaryKey({ columns: [t.identifier, t.token] }) }),\n );\n\n const auditLog = sqliteTable(\n p('audit_log'),\n {\n id: text('id').primaryKey(),\n type: text('type').notNull(),\n userId: text('user_id').references(() => usersTable.id, { onDelete: 'set null' }),\n sessionId: text('session_id'),\n at: integer('at', { mode: 'timestamp_ms' })\n .notNull()\n .$defaultFn(() => new Date()),\n ip: text('ip'),\n userAgent: text('user_agent'),\n data: text('data', { mode: 'json' }),\n },\n (t) => ({\n typeIdx: index(`${p('audit_log')}_type_idx`).on(t.type),\n userIdx: index(`${p('audit_log')}_user_idx`).on(t.userId),\n }),\n );\n\n const sessionsRelations = relations(sessions, ({ one }) => ({\n user: one(usersTable, { fields: [sessions.userId], references: [usersTable.id] }),\n }));\n const accountsRelations = relations(accounts, ({ one }) => ({\n user: one(usersTable, { fields: [accounts.userId], references: [usersTable.id] }),\n }));\n const auditLogRelations = relations(auditLog, ({ one }) => ({\n user: one(usersTable, { fields: [auditLog.userId], references: [usersTable.id] }),\n }));\n\n return {\n tables: { users: usersTable, sessions, accounts, verificationTokens, auditLog },\n relations: { sessionsRelations, accountsRelations, auditLogRelations },\n };\n}\n\ntype HoleauthTables<U extends SqliteUsersTable> = ReturnType<\n typeof createHoleauthTables<U>\n>['tables'];\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type SqliteDb = any;\n\nexport interface CreateHoleauthAdaptersOptions<U extends SqliteUsersTable> {\n db: SqliteDb;\n tables: HoleauthTables<U>;\n userEmailColumn?: string;\n generateId?: () => string;\n}\n\nexport interface HoleauthAdapterBundle {\n user: UserAdapter;\n session: SessionAdapter;\n account: AccountAdapter;\n verificationToken: VerificationTokenAdapter;\n auditLog: AuditLogAdapter;\n transaction: TransactionAdapter;\n}\n\nexport function createHoleauthAdapters<U extends SqliteUsersTable>(\n opts: CreateHoleauthAdaptersOptions<U>,\n): HoleauthAdapterBundle {\n const { db, tables, userEmailColumn = 'email', generateId = () => crypto.randomUUID() } = opts;\n const { users, sessions, accounts, verificationTokens, auditLog } = tables;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const emailCol = (users as any)[userEmailColumn];\n if (!emailCol) {\n throw new Error(`[holeauth] usersTable missing \"${userEmailColumn}\" column.`);\n }\n\n const userRowToAdapter = (r: Record<string, unknown>): AdapterUser => ({\n id: String(r.id),\n email: String(r[userEmailColumn] ?? ''),\n emailVerified: (r.emailVerified as Date | null | undefined) ?? null,\n name: (r.name as string | null | undefined) ?? null,\n image: (r.image as string | null | undefined) ?? null,\n passwordHash: (r.passwordHash as string | null | undefined) ?? null,\n });\n\n const user: UserAdapter = {\n async getUserById(id) {\n const rows = await db.select().from(users).where(eq(users.id, id)).limit(1);\n return rows[0] ? userRowToAdapter(rows[0]) : null;\n },\n async getUserByEmail(email) {\n const rows = await db.select().from(users).where(eq(emailCol, email)).limit(1);\n return rows[0] ? userRowToAdapter(rows[0]) : null;\n },\n async createUser(data) {\n const id = generateId();\n const [row] = await db\n .insert(users)\n .values({\n id,\n [userEmailColumn]: data.email,\n emailVerified: data.emailVerified ?? null,\n name: data.name ?? null,\n image: data.image ?? null,\n passwordHash: data.passwordHash ?? null,\n })\n .returning();\n return userRowToAdapter(row);\n },\n async updateUser(id, patch) {\n const toSet: Record<string, unknown> = { ...patch };\n if ('email' in toSet) {\n toSet[userEmailColumn] = toSet.email;\n if (userEmailColumn !== 'email') delete toSet.email;\n }\n const [row] = await db.update(users).set(toSet).where(eq(users.id, id)).returning();\n if (!row) throw new Error(`User ${id} not found`);\n return userRowToAdapter(row);\n },\n async deleteUser(id) {\n await db.delete(users).where(eq(users.id, id));\n },\n };\n\n const sessionRowToAdapter = (r: Record<string, unknown>): AdapterSession => ({\n id: String(r.id),\n userId: String(r.userId),\n familyId: String(r.familyId),\n refreshTokenHash: String(r.refreshTokenHash),\n expiresAt: r.expiresAt as Date,\n createdAt: r.createdAt as Date | undefined,\n revokedAt: (r.revokedAt as Date | null | undefined) ?? null,\n userAgent: (r.userAgent as string | null | undefined) ?? null,\n ip: (r.ip as string | null | undefined) ?? null,\n });\n\n const session: SessionAdapter = {\n async createSession(data) {\n const [row] = await db.insert(sessions).values(data).returning();\n return sessionRowToAdapter(row);\n },\n async getSession(id) {\n const rows = await db.select().from(sessions).where(eq(sessions.id, id)).limit(1);\n return rows[0] ? sessionRowToAdapter(rows[0]) : null;\n },\n async getByRefreshHash(hash) {\n const rows = await db.select().from(sessions).where(eq(sessions.refreshTokenHash, hash)).limit(1);\n return rows[0] ? sessionRowToAdapter(rows[0]) : null;\n },\n async findByFamily(familyId) {\n const rows = await db.select().from(sessions).where(eq(sessions.familyId, familyId));\n return rows.map(sessionRowToAdapter);\n },\n async deleteSession(id) {\n await db.delete(sessions).where(eq(sessions.id, id));\n },\n async rotateRefresh(id, newHash, expiresAt) {\n const [row] = await db\n .update(sessions)\n .set({ refreshTokenHash: newHash, expiresAt })\n .where(eq(sessions.id, id))\n .returning();\n if (!row) throw new Error(`Session ${id} not found`);\n return sessionRowToAdapter(row);\n },\n async revokeFamily(familyId) {\n await db\n .update(sessions)\n .set({ revokedAt: new Date() })\n .where(and(eq(sessions.familyId, familyId), sql`${sessions.revokedAt} IS NULL`));\n },\n async revokeUser(userId) {\n await db\n .update(sessions)\n .set({ revokedAt: new Date() })\n .where(and(eq(sessions.userId, userId), sql`${sessions.revokedAt} IS NULL`));\n },\n };\n\n const accountRowToAdapter = (r: Record<string, unknown>): AdapterAccount => ({\n id: String(r.id),\n userId: String(r.userId),\n provider: String(r.provider),\n providerAccountId: String(r.providerAccountId),\n email: (r.email as string | null | undefined) ?? null,\n accessToken: (r.accessToken as string | null | undefined) ?? null,\n refreshToken: (r.refreshToken as string | null | undefined) ?? null,\n expiresAt: (r.expiresAt as Date | null | undefined) ?? null,\n tokenType: (r.tokenType as string | null | undefined) ?? null,\n scope: (r.scope as string | null | undefined) ?? null,\n idToken: (r.idToken as string | null | undefined) ?? null,\n });\n\n const account: AccountAdapter = {\n async linkAccount(data) {\n const [row] = await db.insert(accounts).values({ id: generateId(), ...data }).returning();\n return accountRowToAdapter(row);\n },\n async getAccountByProvider(provider, providerAccountId) {\n const rows = await db\n .select()\n .from(accounts)\n .where(and(eq(accounts.provider, provider), eq(accounts.providerAccountId, providerAccountId)))\n .limit(1);\n return rows[0] ? accountRowToAdapter(rows[0]) : null;\n },\n async getByProviderEmail(provider, email) {\n const rows = await db\n .select()\n .from(accounts)\n .where(and(eq(accounts.provider, provider), eq(accounts.email, email)))\n .limit(1);\n return rows[0] ? accountRowToAdapter(rows[0]) : null;\n },\n async listByUser(userId) {\n const rows = await db.select().from(accounts).where(eq(accounts.userId, userId));\n return rows.map(accountRowToAdapter);\n },\n async unlinkAccount(id) {\n await db.delete(accounts).where(eq(accounts.id, id));\n },\n };\n\n const vtRowToAdapter = (r: Record<string, unknown>): AdapterVerificationToken => ({\n identifier: String(r.identifier),\n token: String(r.token),\n expiresAt: r.expiresAt as Date,\n });\n\n const verificationToken: VerificationTokenAdapter = {\n async create(data) {\n const [row] = await db.insert(verificationTokens).values(data).returning();\n return vtRowToAdapter(row);\n },\n async consume(identifier, token) {\n const [row] = await db\n .delete(verificationTokens)\n .where(and(eq(verificationTokens.identifier, identifier), eq(verificationTokens.token, token)))\n .returning();\n if (!row) return null;\n const rec = vtRowToAdapter(row);\n return rec.expiresAt.getTime() < Date.now() ? null : rec;\n },\n async purgeExpired() {\n const res = await db\n .delete(verificationTokens)\n .where(sql`${verificationTokens.expiresAt} < ${Date.now()}`)\n .returning({ identifier: verificationTokens.identifier });\n return res.length;\n },\n };\n\n const auditRowToAdapter = (r: Record<string, unknown>): AdapterAuditEvent => ({\n id: String(r.id),\n type: String(r.type),\n userId: (r.userId as string | null | undefined) ?? null,\n sessionId: (r.sessionId as string | null | undefined) ?? null,\n at: r.at as Date | undefined,\n ip: (r.ip as string | null | undefined) ?? null,\n userAgent: (r.userAgent as string | null | undefined) ?? null,\n data: (r.data as Record<string, unknown> | null | undefined) ?? null,\n });\n\n const auditLogAdapter: AuditLogAdapter = {\n async record(event) {\n await db.insert(auditLog).values({ id: event.id ?? generateId(), ...event });\n },\n async list(filter) {\n const conds = [];\n if (filter.userId) conds.push(eq(auditLog.userId, filter.userId));\n if (filter.type) conds.push(eq(auditLog.type, filter.type));\n const q = db.select().from(auditLog);\n const rows = conds.length\n ? await q.where(and(...conds)).limit(filter.limit ?? 100)\n : await q.limit(filter.limit ?? 100);\n return rows.map(auditRowToAdapter);\n },\n };\n\n const transaction: TransactionAdapter = {\n async run(fn) {\n return db.transaction(async () => fn());\n },\n };\n\n return { user, session, account, verificationToken, auditLog: auditLogAdapter, transaction };\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@holeauth/adapter-drizzle",
|
|
3
|
+
"version": "0.0.1-alpha.0",
|
|
4
|
+
"description": "Drizzle factory-based adapters for holeauth core (users, sessions, accounts, verification, audit). Supports Postgres, MySQL, SQLite.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Robert Kratz",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/robert-kratz/holeauth.git",
|
|
10
|
+
"directory": "packages/adapter-drizzle"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://robert-kratz.github.io/holeauth",
|
|
13
|
+
"bugs": "https://github.com/robert-kratz/holeauth/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"auth",
|
|
16
|
+
"holeauth",
|
|
17
|
+
"drizzle",
|
|
18
|
+
"postgres",
|
|
19
|
+
"mysql",
|
|
20
|
+
"sqlite"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"type": "module",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"require": "./dist/index.cjs"
|
|
30
|
+
},
|
|
31
|
+
"./pg": {
|
|
32
|
+
"types": "./dist/pg/index.d.ts",
|
|
33
|
+
"import": "./dist/pg/index.js",
|
|
34
|
+
"require": "./dist/pg/index.cjs"
|
|
35
|
+
},
|
|
36
|
+
"./mysql": {
|
|
37
|
+
"types": "./dist/mysql/index.d.ts",
|
|
38
|
+
"import": "./dist/mysql/index.js",
|
|
39
|
+
"require": "./dist/mysql/index.cjs"
|
|
40
|
+
},
|
|
41
|
+
"./sqlite": {
|
|
42
|
+
"types": "./dist/sqlite/index.d.ts",
|
|
43
|
+
"import": "./dist/sqlite/index.js",
|
|
44
|
+
"require": "./dist/sqlite/index.cjs"
|
|
45
|
+
},
|
|
46
|
+
"./package.json": "./package.json"
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"dist",
|
|
50
|
+
"README.md",
|
|
51
|
+
"LICENSE"
|
|
52
|
+
],
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public",
|
|
55
|
+
"provenance": true
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"drizzle-orm": ">=0.33.0",
|
|
59
|
+
"@holeauth/core": "0.0.1-alpha.0"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@types/node": "^20.16.10",
|
|
63
|
+
"drizzle-orm": "^0.36.0",
|
|
64
|
+
"tsup": "^8.3.0",
|
|
65
|
+
"typescript": "^5.6.2",
|
|
66
|
+
"vitest": "^2.1.2",
|
|
67
|
+
"@holeauth/core": "0.0.1-alpha.0",
|
|
68
|
+
"@holeauth/eslint-config": "0.0.0",
|
|
69
|
+
"@holeauth/tsconfig": "0.0.0"
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "tsup",
|
|
73
|
+
"dev": "tsup --watch",
|
|
74
|
+
"clean": "rm -rf dist .turbo",
|
|
75
|
+
"lint": "echo 'lint skipped'",
|
|
76
|
+
"typecheck": "tsc --noEmit",
|
|
77
|
+
"test": "vitest run --passWithNoTests"
|
|
78
|
+
}
|
|
79
|
+
}
|