@lenso/audit 0.0.0-stage → 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.
@@ -0,0 +1,361 @@
1
+ import type { BunSQLDatabase } from "drizzle-orm/bun-sql";
2
+ import type { AuditRepository } from "./contracts";
3
+ export declare const auditEvents: import("drizzle-orm/pg-core").PgTableWithColumns<{
4
+ name: "lenso_audit_events";
5
+ schema: undefined;
6
+ columns: {
7
+ tenantKey: import("drizzle-orm/pg-core").PgColumn<{
8
+ name: "tenant_key";
9
+ tableName: "lenso_audit_events";
10
+ dataType: "string";
11
+ columnType: "PgText";
12
+ data: string;
13
+ driverParam: string;
14
+ notNull: true;
15
+ hasDefault: false;
16
+ isPrimaryKey: false;
17
+ isAutoincrement: false;
18
+ hasRuntimeDefault: false;
19
+ enumValues: [string, ...string[]];
20
+ baseColumn: never;
21
+ identity: undefined;
22
+ generated: undefined;
23
+ }, {}, {}>;
24
+ scopeId: import("drizzle-orm/pg-core").PgColumn<{
25
+ name: "scope_id";
26
+ tableName: "lenso_audit_events";
27
+ dataType: "string";
28
+ columnType: "PgText";
29
+ data: string;
30
+ driverParam: string;
31
+ notNull: true;
32
+ hasDefault: false;
33
+ isPrimaryKey: false;
34
+ isAutoincrement: false;
35
+ hasRuntimeDefault: false;
36
+ enumValues: [string, ...string[]];
37
+ baseColumn: never;
38
+ identity: undefined;
39
+ generated: undefined;
40
+ }, {}, {}>;
41
+ id: import("drizzle-orm/pg-core").PgColumn<{
42
+ name: "id";
43
+ tableName: "lenso_audit_events";
44
+ dataType: "string";
45
+ columnType: "PgText";
46
+ data: string;
47
+ driverParam: string;
48
+ notNull: true;
49
+ hasDefault: false;
50
+ isPrimaryKey: false;
51
+ isAutoincrement: false;
52
+ hasRuntimeDefault: false;
53
+ enumValues: [string, ...string[]];
54
+ baseColumn: never;
55
+ identity: undefined;
56
+ generated: undefined;
57
+ }, {}, {}>;
58
+ recordedAt: import("drizzle-orm/pg-core").PgColumn<{
59
+ name: "recorded_at";
60
+ tableName: "lenso_audit_events";
61
+ dataType: "number";
62
+ columnType: "PgBigInt53";
63
+ data: number;
64
+ driverParam: string | number;
65
+ notNull: true;
66
+ hasDefault: false;
67
+ isPrimaryKey: false;
68
+ isAutoincrement: false;
69
+ hasRuntimeDefault: false;
70
+ enumValues: undefined;
71
+ baseColumn: never;
72
+ identity: undefined;
73
+ generated: undefined;
74
+ }, {}, {}>;
75
+ action: import("drizzle-orm/pg-core").PgColumn<{
76
+ name: "action";
77
+ tableName: "lenso_audit_events";
78
+ dataType: "string";
79
+ columnType: "PgText";
80
+ data: string;
81
+ driverParam: string;
82
+ notNull: true;
83
+ hasDefault: false;
84
+ isPrimaryKey: false;
85
+ isAutoincrement: false;
86
+ hasRuntimeDefault: false;
87
+ enumValues: [string, ...string[]];
88
+ baseColumn: never;
89
+ identity: undefined;
90
+ generated: undefined;
91
+ }, {}, {}>;
92
+ targetType: import("drizzle-orm/pg-core").PgColumn<{
93
+ name: "target_type";
94
+ tableName: "lenso_audit_events";
95
+ dataType: "string";
96
+ columnType: "PgText";
97
+ data: string;
98
+ driverParam: string;
99
+ notNull: true;
100
+ hasDefault: false;
101
+ isPrimaryKey: false;
102
+ isAutoincrement: false;
103
+ hasRuntimeDefault: false;
104
+ enumValues: [string, ...string[]];
105
+ baseColumn: never;
106
+ identity: undefined;
107
+ generated: undefined;
108
+ }, {}, {}>;
109
+ targetId: import("drizzle-orm/pg-core").PgColumn<{
110
+ name: "target_id";
111
+ tableName: "lenso_audit_events";
112
+ dataType: "string";
113
+ columnType: "PgText";
114
+ data: string;
115
+ driverParam: string;
116
+ notNull: true;
117
+ hasDefault: false;
118
+ isPrimaryKey: false;
119
+ isAutoincrement: false;
120
+ hasRuntimeDefault: false;
121
+ enumValues: [string, ...string[]];
122
+ baseColumn: never;
123
+ identity: undefined;
124
+ generated: undefined;
125
+ }, {}, {}>;
126
+ result: import("drizzle-orm/pg-core").PgColumn<{
127
+ name: "result";
128
+ tableName: "lenso_audit_events";
129
+ dataType: "string";
130
+ columnType: "PgText";
131
+ data: string;
132
+ driverParam: string;
133
+ notNull: true;
134
+ hasDefault: false;
135
+ isPrimaryKey: false;
136
+ isAutoincrement: false;
137
+ hasRuntimeDefault: false;
138
+ enumValues: [string, ...string[]];
139
+ baseColumn: never;
140
+ identity: undefined;
141
+ generated: undefined;
142
+ }, {}, {}>;
143
+ correlationId: import("drizzle-orm/pg-core").PgColumn<{
144
+ name: "correlation_id";
145
+ tableName: "lenso_audit_events";
146
+ dataType: "string";
147
+ columnType: "PgText";
148
+ data: string;
149
+ driverParam: string;
150
+ notNull: false;
151
+ hasDefault: false;
152
+ isPrimaryKey: false;
153
+ isAutoincrement: false;
154
+ hasRuntimeDefault: false;
155
+ enumValues: [string, ...string[]];
156
+ baseColumn: never;
157
+ identity: undefined;
158
+ generated: undefined;
159
+ }, {}, {}>;
160
+ eventJson: import("drizzle-orm/pg-core").PgColumn<{
161
+ name: "event_json";
162
+ tableName: "lenso_audit_events";
163
+ dataType: "string";
164
+ columnType: "PgText";
165
+ data: string;
166
+ driverParam: string;
167
+ notNull: true;
168
+ hasDefault: false;
169
+ isPrimaryKey: false;
170
+ isAutoincrement: false;
171
+ hasRuntimeDefault: false;
172
+ enumValues: [string, ...string[]];
173
+ baseColumn: never;
174
+ identity: undefined;
175
+ generated: undefined;
176
+ }, {}, {}>;
177
+ };
178
+ dialect: 'pg';
179
+ }>;
180
+ export declare const auditPostgresSchema: {
181
+ auditEvents: import("drizzle-orm/pg-core").PgTableWithColumns<{
182
+ name: "lenso_audit_events";
183
+ schema: undefined;
184
+ columns: {
185
+ tenantKey: import("drizzle-orm/pg-core").PgColumn<{
186
+ name: "tenant_key";
187
+ tableName: "lenso_audit_events";
188
+ dataType: "string";
189
+ columnType: "PgText";
190
+ data: string;
191
+ driverParam: string;
192
+ notNull: true;
193
+ hasDefault: false;
194
+ isPrimaryKey: false;
195
+ isAutoincrement: false;
196
+ hasRuntimeDefault: false;
197
+ enumValues: [string, ...string[]];
198
+ baseColumn: never;
199
+ identity: undefined;
200
+ generated: undefined;
201
+ }, {}, {}>;
202
+ scopeId: import("drizzle-orm/pg-core").PgColumn<{
203
+ name: "scope_id";
204
+ tableName: "lenso_audit_events";
205
+ dataType: "string";
206
+ columnType: "PgText";
207
+ data: string;
208
+ driverParam: string;
209
+ notNull: true;
210
+ hasDefault: false;
211
+ isPrimaryKey: false;
212
+ isAutoincrement: false;
213
+ hasRuntimeDefault: false;
214
+ enumValues: [string, ...string[]];
215
+ baseColumn: never;
216
+ identity: undefined;
217
+ generated: undefined;
218
+ }, {}, {}>;
219
+ id: import("drizzle-orm/pg-core").PgColumn<{
220
+ name: "id";
221
+ tableName: "lenso_audit_events";
222
+ dataType: "string";
223
+ columnType: "PgText";
224
+ data: string;
225
+ driverParam: string;
226
+ notNull: true;
227
+ hasDefault: false;
228
+ isPrimaryKey: false;
229
+ isAutoincrement: false;
230
+ hasRuntimeDefault: false;
231
+ enumValues: [string, ...string[]];
232
+ baseColumn: never;
233
+ identity: undefined;
234
+ generated: undefined;
235
+ }, {}, {}>;
236
+ recordedAt: import("drizzle-orm/pg-core").PgColumn<{
237
+ name: "recorded_at";
238
+ tableName: "lenso_audit_events";
239
+ dataType: "number";
240
+ columnType: "PgBigInt53";
241
+ data: number;
242
+ driverParam: string | number;
243
+ notNull: true;
244
+ hasDefault: false;
245
+ isPrimaryKey: false;
246
+ isAutoincrement: false;
247
+ hasRuntimeDefault: false;
248
+ enumValues: undefined;
249
+ baseColumn: never;
250
+ identity: undefined;
251
+ generated: undefined;
252
+ }, {}, {}>;
253
+ action: import("drizzle-orm/pg-core").PgColumn<{
254
+ name: "action";
255
+ tableName: "lenso_audit_events";
256
+ dataType: "string";
257
+ columnType: "PgText";
258
+ data: string;
259
+ driverParam: string;
260
+ notNull: true;
261
+ hasDefault: false;
262
+ isPrimaryKey: false;
263
+ isAutoincrement: false;
264
+ hasRuntimeDefault: false;
265
+ enumValues: [string, ...string[]];
266
+ baseColumn: never;
267
+ identity: undefined;
268
+ generated: undefined;
269
+ }, {}, {}>;
270
+ targetType: import("drizzle-orm/pg-core").PgColumn<{
271
+ name: "target_type";
272
+ tableName: "lenso_audit_events";
273
+ dataType: "string";
274
+ columnType: "PgText";
275
+ data: string;
276
+ driverParam: string;
277
+ notNull: true;
278
+ hasDefault: false;
279
+ isPrimaryKey: false;
280
+ isAutoincrement: false;
281
+ hasRuntimeDefault: false;
282
+ enumValues: [string, ...string[]];
283
+ baseColumn: never;
284
+ identity: undefined;
285
+ generated: undefined;
286
+ }, {}, {}>;
287
+ targetId: import("drizzle-orm/pg-core").PgColumn<{
288
+ name: "target_id";
289
+ tableName: "lenso_audit_events";
290
+ dataType: "string";
291
+ columnType: "PgText";
292
+ data: string;
293
+ driverParam: string;
294
+ notNull: true;
295
+ hasDefault: false;
296
+ isPrimaryKey: false;
297
+ isAutoincrement: false;
298
+ hasRuntimeDefault: false;
299
+ enumValues: [string, ...string[]];
300
+ baseColumn: never;
301
+ identity: undefined;
302
+ generated: undefined;
303
+ }, {}, {}>;
304
+ result: import("drizzle-orm/pg-core").PgColumn<{
305
+ name: "result";
306
+ tableName: "lenso_audit_events";
307
+ dataType: "string";
308
+ columnType: "PgText";
309
+ data: string;
310
+ driverParam: string;
311
+ notNull: true;
312
+ hasDefault: false;
313
+ isPrimaryKey: false;
314
+ isAutoincrement: false;
315
+ hasRuntimeDefault: false;
316
+ enumValues: [string, ...string[]];
317
+ baseColumn: never;
318
+ identity: undefined;
319
+ generated: undefined;
320
+ }, {}, {}>;
321
+ correlationId: import("drizzle-orm/pg-core").PgColumn<{
322
+ name: "correlation_id";
323
+ tableName: "lenso_audit_events";
324
+ dataType: "string";
325
+ columnType: "PgText";
326
+ data: string;
327
+ driverParam: string;
328
+ notNull: false;
329
+ hasDefault: false;
330
+ isPrimaryKey: false;
331
+ isAutoincrement: false;
332
+ hasRuntimeDefault: false;
333
+ enumValues: [string, ...string[]];
334
+ baseColumn: never;
335
+ identity: undefined;
336
+ generated: undefined;
337
+ }, {}, {}>;
338
+ eventJson: import("drizzle-orm/pg-core").PgColumn<{
339
+ name: "event_json";
340
+ tableName: "lenso_audit_events";
341
+ dataType: "string";
342
+ columnType: "PgText";
343
+ data: string;
344
+ driverParam: string;
345
+ notNull: true;
346
+ hasDefault: false;
347
+ isPrimaryKey: false;
348
+ isAutoincrement: false;
349
+ hasRuntimeDefault: false;
350
+ enumValues: [string, ...string[]];
351
+ baseColumn: never;
352
+ identity: undefined;
353
+ generated: undefined;
354
+ }, {}, {}>;
355
+ };
356
+ dialect: 'pg';
357
+ }>;
358
+ };
359
+ export declare function createPostgresAuditRepository<TSchema extends Record<string, unknown>>(db: BunSQLDatabase<TSchema>, options?: {
360
+ durableIntents?: boolean;
361
+ }): AuditRepository;
@@ -0,0 +1,80 @@
1
+ import {
2
+ tenantKey,
3
+ decodeEvent,
4
+ insertionResult
5
+ } from "./index-9cajwcjn.js";
6
+
7
+ // src/postgres.ts
8
+ import { and, desc, eq, gte, lte, lt, or } from "drizzle-orm";
9
+ import { bigint, index, pgTable, primaryKey, text } from "drizzle-orm/pg-core";
10
+ var auditEvents = pgTable("lenso_audit_events", {
11
+ tenantKey: text("tenant_key").notNull(),
12
+ scopeId: text("scope_id").notNull(),
13
+ id: text("id").notNull(),
14
+ recordedAt: bigint("recorded_at", { mode: "number" }).notNull(),
15
+ action: text("action").notNull(),
16
+ targetType: text("target_type").notNull(),
17
+ targetId: text("target_id").notNull(),
18
+ result: text("result").notNull(),
19
+ correlationId: text("correlation_id"),
20
+ eventJson: text("event_json").notNull()
21
+ }, (table) => [
22
+ primaryKey({ columns: [table.tenantKey, table.scopeId, table.id] }),
23
+ index("lenso_audit_events_scope_order").on(table.tenantKey, table.scopeId, table.recordedAt.desc(), table.id.desc())
24
+ ]);
25
+ var auditPostgresSchema = { auditEvents };
26
+ function createPostgresAuditRepository(db, options = {}) {
27
+ return {
28
+ durableIntents: options.durableIntents ?? false,
29
+ async insert(event) {
30
+ const rows = await db.insert(auditEvents).values({
31
+ tenantKey: tenantKey(event.scope),
32
+ scopeId: event.scope.scopeId,
33
+ id: event.id,
34
+ recordedAt: event.recordedAt,
35
+ action: event.action,
36
+ targetType: event.target.type,
37
+ targetId: event.target.id,
38
+ result: event.result,
39
+ correlationId: event.correlationId ?? null,
40
+ eventJson: JSON.stringify(event)
41
+ }).onConflictDoNothing({
42
+ target: [auditEvents.tenantKey, auditEvents.scopeId, auditEvents.id]
43
+ }).returning({ id: auditEvents.id });
44
+ if (rows.length)
45
+ return "inserted";
46
+ return insertionResult(event, await this.get(event.scope, event.id) ?? undefined);
47
+ },
48
+ async get(scope, id) {
49
+ const rows = await db.select({ eventJson: auditEvents.eventJson }).from(auditEvents).where(and(eq(auditEvents.tenantKey, tenantKey(scope)), eq(auditEvents.scopeId, scope.scopeId), eq(auditEvents.id, id))).limit(1);
50
+ return rows[0] ? decodeEvent(rows[0].eventJson) : null;
51
+ },
52
+ async list(query) {
53
+ const terms = [
54
+ eq(auditEvents.tenantKey, tenantKey(query.scope)),
55
+ eq(auditEvents.scopeId, query.scope.scopeId)
56
+ ];
57
+ if (query.action !== undefined)
58
+ terms.push(eq(auditEvents.action, query.action));
59
+ if (query.target)
60
+ terms.push(eq(auditEvents.targetType, query.target.type), eq(auditEvents.targetId, query.target.id));
61
+ if (query.result !== undefined)
62
+ terms.push(eq(auditEvents.result, query.result));
63
+ if (query.correlationId !== undefined)
64
+ terms.push(eq(auditEvents.correlationId, query.correlationId));
65
+ if (query.recordedFrom !== undefined)
66
+ terms.push(gte(auditEvents.recordedAt, query.recordedFrom));
67
+ if (query.recordedTo !== undefined)
68
+ terms.push(lte(auditEvents.recordedAt, query.recordedTo));
69
+ if (query.cursor)
70
+ terms.push(or(lt(auditEvents.recordedAt, query.cursor.recordedAt), and(eq(auditEvents.recordedAt, query.cursor.recordedAt), lt(auditEvents.id, query.cursor.id))));
71
+ const rows = await db.select({ eventJson: auditEvents.eventJson }).from(auditEvents).where(and(...terms)).orderBy(desc(auditEvents.recordedAt), desc(auditEvents.id)).limit(query.limit);
72
+ return rows.map((row) => decodeEvent(row.eventJson));
73
+ }
74
+ };
75
+ }
76
+ export {
77
+ auditEvents,
78
+ auditPostgresSchema,
79
+ createPostgresAuditRepository
80
+ };
@@ -0,0 +1,4 @@
1
+ import type { AuditEvent, AuditScope } from "./contracts";
2
+ export declare function tenantKey(scope: AuditScope): string;
3
+ export declare function decodeEvent(value: string): AuditEvent;
4
+ export declare function insertionResult(event: AuditEvent, existing: AuditEvent | undefined): "conflict" | "duplicate";
@@ -0,0 +1,49 @@
1
+ import { type AuditAuthority, type AuditEvent, type AuditInput, type AuditPage, type AuditQuery, type AuditReporter, type AuditRepository, type AuditScope, type SummaryPolicy } from "./contracts";
2
+ declare const receiptBrand: unique symbol;
3
+ export interface AuditIntentReceipt {
4
+ readonly intentId: string;
5
+ readonly [receiptBrand]: true;
6
+ }
7
+ export interface AuditOutcome {
8
+ readonly id: string;
9
+ readonly occurredAt: number;
10
+ readonly result: "success" | "failure" | "denied" | "unknown";
11
+ readonly reasonCode: string;
12
+ readonly summary?: AuditInput["summary"];
13
+ }
14
+ export interface AuditService<P> {
15
+ append(input: AuditInput, principal: P): Promise<{
16
+ status: "inserted" | "duplicate";
17
+ event: AuditEvent;
18
+ }>;
19
+ appendBestEffort(input: AuditInput, principal: P): Promise<{
20
+ status: "inserted" | "duplicate";
21
+ event: AuditEvent;
22
+ } | {
23
+ status: "unconfirmed";
24
+ code: "storage-failed";
25
+ }>;
26
+ get(input: {
27
+ scope: AuditScope;
28
+ id: string;
29
+ }, principal: P): Promise<AuditEvent | null>;
30
+ query(input: AuditQuery, principal: P): Promise<AuditPage>;
31
+ prepare(input: AuditInput, principal: P): Promise<{
32
+ status: "ready";
33
+ receipt: AuditIntentReceipt;
34
+ } | {
35
+ status: "already-recorded";
36
+ intentId: string;
37
+ }>;
38
+ complete(receipt: AuditIntentReceipt, outcome: AuditOutcome): Promise<AuditEvent>;
39
+ }
40
+ export interface AuditServiceOptions<P> {
41
+ repository: AuditRepository;
42
+ authority: AuditAuthority<P>;
43
+ summaryPolicy?: SummaryPolicy;
44
+ maxPageSize?: number;
45
+ report?: AuditReporter;
46
+ clock?: () => number;
47
+ }
48
+ export declare function createAuditService<P>(options: AuditServiceOptions<P>): AuditService<P>;
49
+ export {};