@oidcraft/drizzle 0.1.0 → 0.2.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/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
+ import { AccountStore, FullAdapter, KeyStore } from "@oidcraft/adapter";
1
2
  import { AnyRelations } from "drizzle-orm";
2
3
  import { SQLiteAsyncDatabase } from "drizzle-orm/sqlite-core";
3
4
  import { PgQueryResultHKT } from "drizzle-orm/pg-core";
4
- import { AccountStore, FullAdapter, KeyStore } from "@oidcraft/adapter";
5
5
  import { PgAsyncDatabase } from "drizzle-orm/pg-core/async";
6
6
  /**
7
7
  * The oidcraft tables for Postgres, in `schema` or in the search path when it is omitted. A factory,
@@ -168,6 +168,21 @@ export declare const postgresTables: (schema?: string) => {
168
168
  identity: undefined;
169
169
  generated: undefined;
170
170
  }>;
171
+ familyId: import("drizzle-orm/pg-core").PgBuildColumn<"oidc_artifacts", import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>, {
172
+ name: string;
173
+ tableName: "oidc_artifacts";
174
+ dataType: "string";
175
+ data: string;
176
+ driverParam: string;
177
+ notNull: false;
178
+ hasDefault: false;
179
+ isPrimaryKey: false;
180
+ isAutoincrement: false;
181
+ hasRuntimeDefault: false;
182
+ enumValues: undefined;
183
+ identity: undefined;
184
+ generated: undefined;
185
+ }>;
171
186
  userCode: import("drizzle-orm/pg-core").PgBuildColumn<"oidc_artifacts", import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>, {
172
187
  name: string;
173
188
  tableName: "oidc_artifacts";
@@ -1207,6 +1222,22 @@ export declare const artifacts: import("drizzle-orm/sqlite-core").SQLiteTableWit
1207
1222
  identity: undefined;
1208
1223
  generated: undefined;
1209
1224
  }, {}>;
1225
+ familyId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
1226
+ name: string;
1227
+ tableName: "oidc_artifacts";
1228
+ dataType: "string";
1229
+ data: string;
1230
+ driverParam: string;
1231
+ notNull: false;
1232
+ hasDefault: false;
1233
+ isPrimaryKey: false;
1234
+ isAutoincrement: false;
1235
+ hasRuntimeDefault: false;
1236
+ enumValues: [string, ...string[]];
1237
+ baseColumn: never;
1238
+ identity: undefined;
1239
+ generated: undefined;
1240
+ }, {}>;
1210
1241
  userCode: import("drizzle-orm/sqlite-core").SQLiteColumn<{
1211
1242
  name: string;
1212
1243
  tableName: "oidc_artifacts";
@@ -2168,6 +2199,22 @@ export declare const schema: {
2168
2199
  identity: undefined;
2169
2200
  generated: undefined;
2170
2201
  }, {}>;
2202
+ familyId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
2203
+ name: string;
2204
+ tableName: "oidc_artifacts";
2205
+ dataType: "string";
2206
+ data: string;
2207
+ driverParam: string;
2208
+ notNull: false;
2209
+ hasDefault: false;
2210
+ isPrimaryKey: false;
2211
+ isAutoincrement: false;
2212
+ hasRuntimeDefault: false;
2213
+ enumValues: [string, ...string[]];
2214
+ baseColumn: never;
2215
+ identity: undefined;
2216
+ generated: undefined;
2217
+ }, {}>;
2171
2218
  userCode: import("drizzle-orm/sqlite-core").SQLiteColumn<{
2172
2219
  name: string;
2173
2220
  tableName: "oidc_artifacts";
package/dist/index.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { noAccounts } from "@oidcraft/adapter";
1
2
  import { and, eq, gt, isNull, lte } from "drizzle-orm";
2
3
  import { index, integer, primaryKey, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
3
4
  import { customType, index as index$1, integer as integer$1, pgSchema, pgTable, primaryKey as primaryKey$1, text as text$1, uniqueIndex as uniqueIndex$1 } from "drizzle-orm/pg-core";
@@ -21,6 +22,7 @@ const artifacts = sqliteTable("oidc_artifacts", {
21
22
  clientId: text("client_id").notNull(),
22
23
  accountId: text("account_id"),
23
24
  grantId: text("grant_id"),
25
+ familyId: text("family_id"),
24
26
  userCode: text("user_code"),
25
27
  payload: text("payload", { mode: "json" }).notNull(),
26
28
  consumedAt: integer("consumed_at", { mode: "timestamp_ms" }),
@@ -29,7 +31,9 @@ const artifacts = sqliteTable("oidc_artifacts", {
29
31
  primaryKey({ columns: [table.kind, table.id] }),
30
32
  index("oidc_artifacts_grant_idx").on(table.grantId),
31
33
  index("oidc_artifacts_user_code_idx").on(table.userCode),
32
- index("oidc_artifacts_expiry_idx").on(table.expiresAt)
34
+ index("oidc_artifacts_expiry_idx").on(table.expiresAt),
35
+ index("oidc_artifacts_client_idx").on(table.clientId),
36
+ index("oidc_artifacts_family_idx").on(table.familyId)
33
37
  ]);
34
38
  const sessions = sqliteTable("oidc_sessions", {
35
39
  id: text("id").primaryKey(),
@@ -55,7 +59,7 @@ const grants = sqliteTable("oidc_grants", {
55
59
  resources: text("resources", { mode: "json" }).notNull(),
56
60
  createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(),
57
61
  expiresAt: integer("expires_at", { mode: "timestamp_ms" })
58
- }, (table) => [uniqueIndex("oidc_grants_account_client_idx").on(table.accountId, table.clientId)]);
62
+ }, (table) => [uniqueIndex("oidc_grants_account_client_idx").on(table.accountId, table.clientId), index("oidc_grants_client_idx").on(table.clientId)]);
59
63
  const identities = sqliteTable("oidc_identities", {
60
64
  provider: text("provider").notNull(),
61
65
  subject: text("subject").notNull(),
@@ -137,6 +141,18 @@ const POSTGRES_MIGRATIONS = [
137
141
  {
138
142
  id: "0003_realms",
139
143
  statements: ["create table oidc_realms (id text primary key, display_name text, enabled integer not null, settings text not null, created_at bigint not null, updated_at bigint not null)"]
144
+ },
145
+ {
146
+ id: "0004_indexes",
147
+ statements: [
148
+ "create index oidc_artifacts_client_idx on oidc_artifacts (client_id)",
149
+ "create index oidc_grants_client_idx on oidc_grants (client_id)",
150
+ "create index oidc_sessions_expiry_idx on oidc_sessions (expires_at)"
151
+ ]
152
+ },
153
+ {
154
+ id: "0005_families",
155
+ statements: ["alter table oidc_artifacts add column family_id text", "create index oidc_artifacts_family_idx on oidc_artifacts (family_id)"]
140
156
  }
141
157
  ];
142
158
  // ../sql/dist/sqlite.mjs
@@ -175,6 +191,18 @@ const SQLITE_MIGRATIONS = [
175
191
  {
176
192
  id: "0003_realms",
177
193
  statements: ["create table oidc_realms (id text primary key, display_name text, enabled integer not null, settings text not null, created_at integer not null, updated_at integer not null)"]
194
+ },
195
+ {
196
+ id: "0004_indexes",
197
+ statements: [
198
+ "create index oidc_artifacts_client_idx on oidc_artifacts (client_id)",
199
+ "create index oidc_grants_client_idx on oidc_grants (client_id)",
200
+ "create index oidc_sessions_expiry_idx on oidc_sessions (expires_at)"
201
+ ]
202
+ },
203
+ {
204
+ id: "0005_families",
205
+ statements: ["alter table oidc_artifacts add column family_id text", "create index oidc_artifacts_family_idx on oidc_artifacts (family_id)"]
178
206
  }
179
207
  ];
180
208
  // src/postgres-schema.ts
@@ -213,6 +241,7 @@ const postgresTables = (schema) => {
213
241
  clientId: text$1("client_id").notNull(),
214
242
  accountId: text$1("account_id"),
215
243
  grantId: text$1("grant_id"),
244
+ familyId: text$1("family_id"),
216
245
  userCode: text$1("user_code"),
217
246
  payload: json("payload").notNull(),
218
247
  consumedAt: millis("consumed_at"),
@@ -221,7 +250,9 @@ const postgresTables = (schema) => {
221
250
  primaryKey$1({ columns: [t.kind, t.id] }),
222
251
  index$1("oidc_artifacts_grant_idx").on(t.grantId),
223
252
  index$1("oidc_artifacts_user_code_idx").on(t.userCode),
224
- index$1("oidc_artifacts_expiry_idx").on(t.expiresAt)
253
+ index$1("oidc_artifacts_expiry_idx").on(t.expiresAt),
254
+ index$1("oidc_artifacts_client_idx").on(t.clientId),
255
+ index$1("oidc_artifacts_family_idx").on(t.familyId)
225
256
  ]),
226
257
  sessions: table("oidc_sessions", {
227
258
  id: text$1("id").primaryKey(),
@@ -233,7 +264,11 @@ const postgresTables = (schema) => {
233
264
  upstreamSessionId: text$1("upstream_session_id"),
234
265
  clients: json("clients").notNull(),
235
266
  expiresAt: millis("expires_at").notNull()
236
- }, (t) => [index$1("oidc_sessions_account_idx").on(t.accountId), index$1("oidc_sessions_upstream_idx").on(t.idp, t.upstreamSessionId)]),
267
+ }, (t) => [
268
+ index$1("oidc_sessions_account_idx").on(t.accountId),
269
+ index$1("oidc_sessions_upstream_idx").on(t.idp, t.upstreamSessionId),
270
+ index$1("oidc_sessions_expiry_idx").on(t.expiresAt)
271
+ ]),
237
272
  grants: table("oidc_grants", {
238
273
  id: text$1("id").primaryKey(),
239
274
  accountId: text$1("account_id").notNull(),
@@ -243,7 +278,7 @@ const postgresTables = (schema) => {
243
278
  resources: json("resources").notNull(),
244
279
  createdAt: millis("created_at").notNull(),
245
280
  expiresAt: millis("expires_at")
246
- }, (t) => [uniqueIndex$1("oidc_grants_account_client_idx").on(t.accountId, t.clientId)]),
281
+ }, (t) => [uniqueIndex$1("oidc_grants_account_client_idx").on(t.accountId, t.clientId), index$1("oidc_grants_client_idx").on(t.clientId)]),
247
282
  identities: table("oidc_identities", {
248
283
  provider: text$1("provider").notNull(),
249
284
  subject: text$1("subject").notNull(),
@@ -293,6 +328,7 @@ const drizzleAdapter = (options) => {
293
328
  clientId: row.clientId,
294
329
  ...row.accountId && { accountId: row.accountId },
295
330
  ...row.grantId && { grantId: row.grantId },
331
+ ...row.familyId && { familyId: row.familyId },
296
332
  payload: row.payload,
297
333
  ...row.consumedAt && { consumedAt: row.consumedAt },
298
334
  expiresAt: row.expiresAt
@@ -345,12 +381,19 @@ const drizzleAdapter = (options) => {
345
381
  async destroy(clientId) {
346
382
  await db.delete(clients).where(eq(clients.clientId, clientId));
347
383
  },
348
- async list() {
349
- return { clients: (await db.select().from(clients)).map((row) => ({
350
- ...row.data,
351
- createdAt: row.createdAt,
352
- updatedAt: row.updatedAt
353
- })) };
384
+ async list(cursor, limit) {
385
+ const ordered = db.select().from(clients).where(cursor === void 0 ? void 0 : gt(clients.clientId, cursor)).orderBy(clients.clientId);
386
+ const rows = await (limit === void 0 ? ordered : ordered.limit(limit + 1));
387
+ const more = limit !== void 0 && rows.length > limit;
388
+ const shown = more ? rows.slice(0, limit) : rows;
389
+ return {
390
+ clients: shown.map((row) => ({
391
+ ...row.data,
392
+ createdAt: row.createdAt,
393
+ updatedAt: row.updatedAt
394
+ })),
395
+ ...more && { cursor: shown.at(-1)?.clientId }
396
+ };
354
397
  }
355
398
  },
356
399
  artifacts: {
@@ -361,6 +404,7 @@ const drizzleAdapter = (options) => {
361
404
  clientId: artifact.clientId,
362
405
  accountId: artifact.accountId ?? null,
363
406
  grantId: artifact.grantId ?? null,
407
+ familyId: artifact.familyId ?? null,
364
408
  userCode: artifact.payload.userCode ?? null,
365
409
  payload: artifact.payload,
366
410
  consumedAt: artifact.consumedAt ?? null,
@@ -391,6 +435,12 @@ const drizzleAdapter = (options) => {
391
435
  async revokeByGrantId(grantId) {
392
436
  await db.delete(artifacts).where(eq(artifacts.grantId, grantId));
393
437
  },
438
+ async revokeByFamilyId(familyId) {
439
+ await db.delete(artifacts).where(eq(artifacts.familyId, familyId));
440
+ },
441
+ async revokeByClientId(clientId) {
442
+ await db.delete(artifacts).where(eq(artifacts.clientId, clientId));
443
+ },
394
444
  async prune(before, limit) {
395
445
  const doomed = await db.select({
396
446
  kind: artifacts.kind,
@@ -409,7 +459,7 @@ const drizzleAdapter = (options) => {
409
459
  return (await db.select().from(sessions).where(and(eq(sessions.accountId, accountId), gt(sessions.expiresAt, now())))).map(toSession);
410
460
  },
411
461
  async findByUpstreamSession(provider, upstreamSessionId) {
412
- return (await db.select().from(sessions).where(and(eq(sessions.idp, provider), eq(sessions.upstreamSessionId, upstreamSessionId)))).map(toSession);
462
+ return (await db.select().from(sessions).where(and(eq(sessions.idp, provider), eq(sessions.upstreamSessionId, upstreamSessionId), gt(sessions.expiresAt, now())))).map(toSession);
413
463
  },
414
464
  async upsert(session) {
415
465
  const row = {
@@ -440,6 +490,11 @@ const drizzleAdapter = (options) => {
440
490
  },
441
491
  async destroy(id) {
442
492
  await db.delete(sessions).where(eq(sessions.id, id));
493
+ },
494
+ async prune(before, limit) {
495
+ const doomed = await db.select({ id: sessions.id }).from(sessions).where(lte(sessions.expiresAt, before)).limit(limit);
496
+ for (const row of doomed) await db.delete(sessions).where(and(eq(sessions.id, row.id), lte(sessions.expiresAt, before)));
497
+ return doomed.length;
443
498
  }
444
499
  },
445
500
  grants: {
@@ -465,29 +520,43 @@ const drizzleAdapter = (options) => {
465
520
  createdAt: grant.createdAt,
466
521
  expiresAt: grant.expiresAt ?? null
467
522
  };
523
+ const { id: _id, createdAt: _createdAt, ...changed } = row;
468
524
  await db.insert(grants).values(row).onConflictDoUpdate({
469
- target: grants.id,
470
- set: row
525
+ target: [grants.accountId, grants.clientId],
526
+ set: changed
471
527
  });
472
528
  },
473
529
  async destroy(id) {
474
530
  await db.delete(grants).where(eq(grants.id, id));
531
+ },
532
+ async destroyByClientId(clientId) {
533
+ await db.delete(grants).where(eq(grants.clientId, clientId));
475
534
  }
476
535
  },
477
536
  accounts: options.accounts ?? noAccounts,
478
537
  keys: options.keys,
479
- replay: { async claim(namespace, value, ttl) {
480
- const expiresAt = new Date(Date.now() + ttl * 1e3);
481
- return (await db.insert(replay).values({
482
- namespace,
483
- value,
484
- expiresAt
485
- }).onConflictDoUpdate({
486
- target: [replay.namespace, replay.value],
487
- set: { expiresAt },
488
- setWhere: lte(replay.expiresAt, now())
489
- }).returning({ value: replay.value })).length === 1;
490
- } },
538
+ replay: {
539
+ async claim(namespace, value, ttl) {
540
+ const expiresAt = new Date(Date.now() + ttl * 1e3);
541
+ return (await db.insert(replay).values({
542
+ namespace,
543
+ value,
544
+ expiresAt
545
+ }).onConflictDoUpdate({
546
+ target: [replay.namespace, replay.value],
547
+ set: { expiresAt },
548
+ setWhere: lte(replay.expiresAt, now())
549
+ }).returning({ value: replay.value })).length === 1;
550
+ },
551
+ async prune(before, limit) {
552
+ const doomed = await db.select({
553
+ namespace: replay.namespace,
554
+ value: replay.value
555
+ }).from(replay).where(lte(replay.expiresAt, before)).limit(limit);
556
+ for (const row of doomed) await db.delete(replay).where(and(eq(replay.namespace, row.namespace), eq(replay.value, row.value), lte(replay.expiresAt, before)));
557
+ return doomed.length;
558
+ }
559
+ },
491
560
  credentials: {
492
561
  async find(accountId) {
493
562
  const [row] = await db.select().from(credentials).where(eq(credentials.accountId, accountId)).limit(1);
@@ -561,10 +630,6 @@ const drizzleAdapter = (options) => {
561
630
  }
562
631
  };
563
632
  };
564
- const noAccounts = {
565
- async find() {},
566
- async claims() {}
567
- };
568
633
  const credentialRow = (credential) => ({
569
634
  accountId: credential.accountId,
570
635
  username: credential.username,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oidcraft/drizzle",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A Drizzle storage adapter for @oidcraft/provider, on Postgres or SQLite.",
5
5
  "license": "MIT",
6
6
  "author": "Fl0r14n <florian.chis@gmail.com>",
@@ -41,11 +41,11 @@
41
41
  "verify:entries": "bun run verify-entries.ts"
42
42
  },
43
43
  "peerDependencies": {
44
- "@oidcraft/adapter": "^0.1.0",
44
+ "@oidcraft/adapter": "^0.2.0",
45
45
  "drizzle-orm": ">=1.0.0-rc.5"
46
46
  },
47
47
  "devDependencies": {
48
- "@oidcraft/adapter": "^0.1.0",
48
+ "@oidcraft/adapter": "^0.2.0",
49
49
  "@oidcraft/sql": "0.0.0",
50
50
  "@types/pg": "^8.23.1",
51
51
  "drizzle-orm": "1.0.0-rc.5",