@beignet/provider-db-drizzle 0.0.22 → 0.0.24

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.
@@ -32,6 +32,7 @@
32
32
  import type { IdempotencyPort } from "@beignet/core/idempotency";
33
33
  import type { OutboxPort } from "@beignet/core/outbox";
34
34
  import {
35
+ type AuditLogPort,
35
36
  type BufferedDomainEventRecorder,
36
37
  createDomainEventRecorder,
37
38
  type EventBusPort,
@@ -48,6 +49,11 @@ import { drizzle, type LibSQLDatabase } from "drizzle-orm/libsql";
48
49
  import type { LibSQLTransaction } from "drizzle-orm/libsql/session";
49
50
  import type { SQLiteTransactionConfig } from "drizzle-orm/sqlite-core";
50
51
  import { z } from "zod";
52
+ import {
53
+ createAuditLogInsertQuery,
54
+ createAuditLogSqlRow,
55
+ type DrizzleAuditLogCoreOptions,
56
+ } from "../shared/audit-core.js";
51
57
  import { type DbHealth, dbHealthError, dbHealthOk } from "../shared/health.js";
52
58
  import {
53
59
  createIdempotencyPortCore,
@@ -196,6 +202,91 @@ export function createDrizzleSqliteUnitOfWork<
196
202
  };
197
203
  }
198
204
 
205
+ /**
206
+ * Options for a Drizzle SQLite-backed audit log port.
207
+ */
208
+ export interface DrizzleSqliteAuditLogOptions
209
+ extends DrizzleAuditLogCoreOptions {
210
+ /**
211
+ * Table that stores audit log entries.
212
+ *
213
+ * Default: "audit_log".
214
+ */
215
+ tableName?: string;
216
+ }
217
+
218
+ /**
219
+ * Create idempotent SQL statements for the Drizzle SQLite audit log table.
220
+ *
221
+ * Run these during migrations or local setup before using
222
+ * `createDrizzleSqliteAuditLogPort(...)`.
223
+ */
224
+ export function createDrizzleSqliteAuditLogSetupStatements(
225
+ options: DrizzleSqliteAuditLogOptions = {},
226
+ ): readonly string[] {
227
+ const tableName = options.tableName ?? "audit_log";
228
+ const table = quoteIdentifier(tableName, '"');
229
+ const indexPrefix = tableName.replaceAll(/[^A-Za-z0-9_]/g, "_");
230
+
231
+ return [
232
+ `CREATE TABLE IF NOT EXISTS ${table} (
233
+ id text PRIMARY KEY NOT NULL,
234
+ action text NOT NULL,
235
+ actor_type text NOT NULL,
236
+ actor_id text,
237
+ actor_display_name text,
238
+ tenant_id text,
239
+ tenant_slug text,
240
+ resource_type text,
241
+ resource_id text,
242
+ resource_name text,
243
+ outcome text DEFAULT 'success' NOT NULL,
244
+ request_id text,
245
+ trace_id text,
246
+ message text,
247
+ metadata text,
248
+ actor_metadata text,
249
+ tenant_metadata text,
250
+ resource_metadata text,
251
+ occurred_at text NOT NULL
252
+ )`,
253
+ `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(`${indexPrefix}_action_idx`, '"')} ON ${table} (action)`,
254
+ `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(`${indexPrefix}_actor_idx`, '"')} ON ${table} (actor_type, actor_id)`,
255
+ `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(`${indexPrefix}_occurred_at_idx`, '"')} ON ${table} (occurred_at)`,
256
+ `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(`${indexPrefix}_request_idx`, '"')} ON ${table} (request_id)`,
257
+ `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(`${indexPrefix}_resource_idx`, '"')} ON ${table} (resource_type, resource_id)`,
258
+ `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(`${indexPrefix}_tenant_idx`, '"')} ON ${table} (tenant_id)`,
259
+ ];
260
+ }
261
+
262
+ /**
263
+ * Create a Beignet audit log port backed by a Drizzle SQLite database.
264
+ *
265
+ * The port accepts both the root Drizzle database and transaction clients, so
266
+ * applications can rebuild audit logging inside Unit of Work transaction ports.
267
+ */
268
+ export function createDrizzleSqliteAuditLogPort<
269
+ TSchema extends Record<string, unknown>,
270
+ >(
271
+ db: DrizzleSqliteDatabase<TSchema>,
272
+ adapterOptions: DrizzleSqliteAuditLogOptions = {},
273
+ ): AuditLogPort {
274
+ const table = sql.raw(
275
+ quoteIdentifier(adapterOptions.tableName ?? "audit_log", '"'),
276
+ );
277
+
278
+ return {
279
+ async record(input) {
280
+ await db.run(
281
+ createAuditLogInsertQuery(
282
+ table,
283
+ createAuditLogSqlRow(input, adapterOptions),
284
+ ),
285
+ );
286
+ },
287
+ };
288
+ }
289
+
199
290
  /**
200
291
  * Options for a Drizzle SQLite-backed outbox port.
201
292
  */