@intelligo-dev/audit 1.0.0-beta.1 → 1.0.0-beta.13

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/NOTICE ADDED
@@ -0,0 +1,6 @@
1
+ Intelligo
2
+ Copyright 2026 Turtuvshin Byambaa and the Intelligo contributors
3
+
4
+ This product is licensed under the Apache License, Version 2.0 (see
5
+ LICENSE). The Intelligo name and logo are trademarks; see TRADEMARK.md
6
+ in the source repository, https://github.com/intelligo-dev/intelligo.
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # @intelligo-dev/audit
2
+
3
+ Append-only audit events for multi-tenant apps, with a Postgres trigger that refuses every update and delete.
4
+
5
+ Part of [Intelligo](https://intelligo.dev), an application framework and
6
+ operational platform for vertical AI SaaS products. Every `@intelligo-dev/*`
7
+ package is released at one version and shares one database schema;
8
+ `pnpm dlx @intelligo-dev/cli@beta create my-app` installs the set an
9
+ application needs. Documentation:
10
+ [intelligo.dev/docs/packages/audit](https://intelligo.dev/docs/packages/audit).
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pnpm add @intelligo-dev/audit@beta drizzle-orm
16
+ ```
17
+
18
+ `drizzle-orm` is a peer. The `audit_events` table and its trigger are part of
19
+ the framework's schema, which `intelligo migrate` from
20
+ [`@intelligo-dev/cli`](https://www.npmjs.com/package/@intelligo-dev/cli)
21
+ applies.
22
+
23
+ ## Use
24
+
25
+ ```ts
26
+ import { recordAuditEvent } from "@intelligo-dev/audit";
27
+
28
+ await recordAuditEvent({
29
+ workspaceId,
30
+ actorId: user.id,
31
+ action: "member.removed",
32
+ resourceKind: "member",
33
+ resourceId: memberId,
34
+ metadata: { role: "admin" },
35
+ });
36
+ ```
37
+
38
+ An event with no `actorId` is a system actor's — a cron, a webhook, the job
39
+ runner; `actorKind: "support"` marks an operator acting on a tenant. `outcome`
40
+ is `"ok"` unless the caller says `"failed"`.
41
+
42
+ `recordAuditEvent` never throws — an audit failure must not fail the action it
43
+ records. `recordAuditEventOrThrow` exists for the callers where the record _is_
44
+ the action: impersonation, a destructive support operation.
45
+
46
+ `queryAuditEvents({ workspaceId, action, resourceKind, resourceId, before, limit })`
47
+ reads the trail most recent first, paginated by `before`.
48
+
49
+ ## Append-only, in the database
50
+
51
+ `audit_events` refuses `UPDATE` and `DELETE` at the database level, with one
52
+ exception: the `ON DELETE SET NULL` the foreign keys perform, so deleting a
53
+ workspace does not require deleting its trail.
54
+
55
+ ## Sinks
56
+
57
+ ```ts
58
+ import { registerAuditSink } from "@intelligo-dev/audit";
59
+
60
+ registerAuditSink("siem", async (event) => {
61
+ await ship(event);
62
+ });
63
+ ```
64
+
65
+ A sink registered from the composition root receives every event after it is
66
+ durably recorded, with failure isolation: an exporter with an expired
67
+ credential breaks neither the audited operation nor the other sinks. It is how
68
+ tamper-evidence, a retention policy or a SIEM export attaches without this
69
+ package knowing about it.
70
+
71
+ ## Licence
72
+
73
+ Apache-2.0
@@ -1,15 +1,11 @@
1
1
  /**
2
- * @intelligo-dev/audit database schema.
3
- *
4
2
  * One append-only table recording who did what to which resource.
5
- * Owned by this package per ADR-0004; scanned by drizzle-kit alongside
6
- * the core schema directory (see packages/core/drizzle.config.ts) so
7
- * the migration history stays unified in one database.
3
+ * Scanned by drizzle-kit alongside the core schema directory (see
4
+ * packages/core/drizzle.config.ts) so the migration history stays
5
+ * unified in one database.
8
6
  *
9
7
  * Distinct from `user_memory_audit` in core/identity, which records
10
- * mutations to a user's memory graph and predates this table. That one
11
- * folds in here once the memory subsystem's ownership is settled
12
- * (see docs/inventory/export-classification.md).
8
+ * mutations to a user's memory graph.
13
9
  */
14
10
  export declare const auditEvents: import("drizzle-orm/pg-core").PgTableWithColumns<{
15
11
  name: "audit_events";
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCvB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC;AACzD,MAAM,MAAM,gBAAgB,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCvB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC;AACzD,MAAM,MAAM,gBAAgB,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC"}
package/dist/db/schema.js CHANGED
@@ -1,23 +1,23 @@
1
1
  /**
2
- * @intelligo-dev/audit database schema.
3
- *
4
2
  * One append-only table recording who did what to which resource.
5
- * Owned by this package per ADR-0004; scanned by drizzle-kit alongside
6
- * the core schema directory (see packages/core/drizzle.config.ts) so
7
- * the migration history stays unified in one database.
3
+ * Scanned by drizzle-kit alongside the core schema directory (see
4
+ * packages/core/drizzle.config.ts) so the migration history stays
5
+ * unified in one database.
8
6
  *
9
7
  * Distinct from `user_memory_audit` in core/identity, which records
10
- * mutations to a user's memory graph and predates this table. That one
11
- * folds in here once the memory subsystem's ownership is settled
12
- * (see docs/inventory/export-classification.md).
8
+ * mutations to a user's memory graph.
13
9
  */
14
10
  import { pgTable, text, timestamp, jsonb, index } from "drizzle-orm/pg-core";
15
11
  import { organization, users } from "@intelligo-dev/core/db/schema";
16
12
  export const auditEvents = pgTable("audit_events", {
17
13
  id: text("id").primaryKey(),
18
- /** Null for platform-level events with no tenant. */
14
+ /**
15
+ * Null for platform-level events with no tenant — and for events
16
+ * whose workspace was since deleted: the trail outlives the tenant
17
+ * (set null, not cascade).
18
+ */
19
19
  workspaceId: text("workspace_id").references(() => organization.id, {
20
- onDelete: "cascade",
20
+ onDelete: "set null",
21
21
  }),
22
22
  /** Null for system actors (cron, webhook, job runner). */
23
23
  actorId: text("actor_id").references(() => users.id, {
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAEpE,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAChC,cAAc,EACd;IACE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;IAC3B,qDAAqD;IACrD,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE;QAClE,QAAQ,EAAE,SAAS;KACpB,CAAC;IACF,0DAA0D;IAC1D,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE;QACnD,QAAQ,EAAE,UAAU;KACrB,CAAC;IACF,gEAAgE;IAChE,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACvD,gEAAgE;IAChE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE;IAChC,uEAAuE;IACvE,YAAY,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE;IAC7C,kEAAkE;IAClE,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC;IAC/B,uDAAuD;IACvD,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAChD,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,EAA2B;IAC5D,SAAS,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE;CAC1D,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;IACT,KAAK,CAAC,oCAAoC,CAAC,CAAC,EAAE,CAC5C,KAAK,CAAC,WAAW,EACjB,KAAK,CAAC,SAAS,CAChB;IACD,KAAK,CAAC,yBAAyB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC;IAClE,KAAK,CAAC,2BAA2B,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC;CAC5E,CACF,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAEpE,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAChC,cAAc,EACd;IACE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;IAC3B;;;;OAIG;IACH,WAAW,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE;QAClE,QAAQ,EAAE,UAAU;KACrB,CAAC;IACF,0DAA0D;IAC1D,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE;QACnD,QAAQ,EAAE,UAAU;KACrB,CAAC;IACF,gEAAgE;IAChE,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACvD,gEAAgE;IAChE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE;IAChC,uEAAuE;IACvE,YAAY,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE;IAC7C,kEAAkE;IAClE,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC;IAC/B,uDAAuD;IACvD,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAChD,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,EAA2B;IAC5D,SAAS,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE;CAC1D,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;IACT,KAAK,CAAC,oCAAoC,CAAC,CAAC,EAAE,CAC5C,KAAK,CAAC,WAAW,EACjB,KAAK,CAAC,SAAS,CAChB;IACD,KAAK,CAAC,yBAAyB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC;IAClE,KAAK,CAAC,2BAA2B,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC;CAC5E,CACF,CAAC"}
package/dist/index.d.ts CHANGED
@@ -4,18 +4,13 @@
4
4
  * Emitting is deliberately failure-tolerant: an audit write must never
5
5
  * break the operation being audited. `recordAuditEvent` swallows and
6
6
  * logs; callers that need the guarantee (impersonation, destructive
7
- * support actions — Phase 5) use `recordAuditEventOrThrow`.
7
+ * support actions) use `recordAuditEventOrThrow`.
8
8
  */
9
9
  /**
10
- * Called after an event is durably recorded.
11
- *
12
- * This is an extension point, not a plugin system: sinks are
13
- * registered by the composition root, never by being imported
14
- * (ADR-0005). What it exists for is the governance work that does not
15
- * belong in a permissively-licensed package — tamper-evidence,
16
- * retention policy, shipping the trail to a customer's SIEM — so that
17
- * a closed module can add it without this package knowing it exists,
18
- * and without anyone forking this file.
10
+ * Called after an event is durably recorded. Sinks are registered by
11
+ * the composition root, never by being imported; they exist for
12
+ * governance work outside this package — tamper-evidence, retention
13
+ * policy, shipping the trail to a SIEM.
19
14
  *
20
15
  * A sink runs after the write, so it cannot corrupt or delay the audit
21
16
  * row itself, and its failures are isolated: an exporter with an
@@ -83,7 +78,7 @@ export type QueryAuditEventsOptions = {
83
78
  before?: Date;
84
79
  limit?: number;
85
80
  };
86
- /** Most-recent-first query for the admin console (Phase 5). */
81
+ /** Most-recent-first query for the admin console. */
87
82
  export declare function queryAuditEvents(options?: QueryAuditEventsOptions): Promise<{
88
83
  id: string;
89
84
  workspaceId: string | null;
@@ -96,7 +91,7 @@ export declare function queryAuditEvents(options?: QueryAuditEventsOptions): Pro
96
91
  metadata: Record<string, unknown> | null;
97
92
  createdAt: Date;
98
93
  }[]>;
99
- export { auditEvents } from "./db/schema";
100
- export type { AuditEvent, InsertAuditEvent } from "./db/schema";
101
- export type { AuditTargetKind as MemoryAuditTargetKind, AuditAction as MemoryAuditAction, AuditActorKind as MemoryAuditActorKind, UserMemoryAuditRow, InsertUserMemoryAudit, RecordMemoryAuditInput, } from "./memory-audit";
94
+ export { auditEvents } from "./db/schema.js";
95
+ export type { AuditEvent, InsertAuditEvent } from "./db/schema.js";
96
+ export type { AuditTargetKind as MemoryAuditTargetKind, AuditAction as MemoryAuditAction, AuditActorKind as MemoryAuditActorKind, UserMemoryAuditRow, InsertUserMemoryAudit, RecordMemoryAuditInput, } from "./memory-audit.js";
102
97
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAcH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE5E;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC;AAIF,wDAAwD;AACxD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAErE;AAED,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAE/C;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAoBD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC3D,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,QAAQ,CAAC;AAE3C,MAAM,MAAM,eAAe,GAAG;IAC5B,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAgBF;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAY5E;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CASf;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,+DAA+D;AAC/D,wBAAsB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B;;;;;;;;;;;KAqB3E;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIhE,YAAY,EACV,eAAe,IAAI,qBAAqB,EACxC,WAAW,IAAI,iBAAiB,EAChC,cAAc,IAAI,oBAAoB,EACtC,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE5E;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC;AAIF,wDAAwD;AACxD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAErE;AAED,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAE/C;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAoBD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC3D,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,QAAQ,CAAC;AAE3C,MAAM,MAAM,eAAe,GAAG;IAC5B,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAgBF;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAY5E;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CASf;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qDAAqD;AACrD,wBAAsB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B;;;;;;;;;;;KAqB3E;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIhE,YAAY,EACV,eAAe,IAAI,qBAAqB,EACxC,WAAW,IAAI,iBAAiB,EAChC,cAAc,IAAI,oBAAoB,EACtC,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -4,14 +4,15 @@
4
4
  * Emitting is deliberately failure-tolerant: an audit write must never
5
5
  * break the operation being audited. `recordAuditEvent` swallows and
6
6
  * logs; callers that need the guarantee (impersonation, destructive
7
- * support actions — Phase 5) use `recordAuditEventOrThrow`.
7
+ * support actions) use `recordAuditEventOrThrow`.
8
8
  */
9
9
  import { db } from "@intelligo-dev/core/db";
10
10
  import { createLogger } from "@intelligo-dev/core/logger";
11
+ import { createRegistry } from "@intelligo-dev/core/registry";
11
12
  import { and, desc, eq, lt } from "drizzle-orm";
12
- import { auditEvents } from "./db/schema";
13
+ import { auditEvents } from "./db/schema.js";
13
14
  const log = createLogger("Audit");
14
- const sinks = new Map();
15
+ const sinks = createRegistry("audit/sinks");
15
16
  /** Register (or replace) a sink under a stable name. */
16
17
  export function registerAuditSink(name, sink) {
17
18
  sinks.set(name, sink);
@@ -84,7 +85,7 @@ export async function recordAuditEventOrThrow(event) {
84
85
  // and every destructive support action.
85
86
  await fanOut({ ...row, createdAt: new Date() });
86
87
  }
87
- /** Most-recent-first query for the admin console (Phase 5). */
88
+ /** Most-recent-first query for the admin console. */
88
89
  export async function queryAuditEvents(options = {}) {
89
90
  const filters = [
90
91
  options.workspaceId
@@ -106,5 +107,5 @@ export async function queryAuditEvents(options = {}) {
106
107
  .orderBy(desc(auditEvents.createdAt))
107
108
  .limit(Math.min(options.limit ?? 50, 500));
108
109
  }
109
- export { auditEvents } from "./db/schema";
110
+ export { auditEvents } from "./db/schema.js";
110
111
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,45 +1,18 @@
1
1
  /**
2
- * Memory-audit event contract (ADR-0008).
2
+ * Memory-audit event contract.
3
3
  *
4
- * ADR-0008 names `@intelligo-dev/audit` as `recordMemoryAudit`'s
5
- * destination ("`recordMemoryAudit` to `audit`"). The dependency
6
- * allowlist doesn't cooperate with a literal move, though
7
- * (tests/architecture/dependency-direction.test.ts): this package may
8
- * depend on `@intelligo-dev/core` (`audit: ["@intelligo-dev/core"]`), but
9
- * `@intelligo-dev/core` may depend on nothing (`core: []`) — the same
10
- * constraint `packages/core/src/documents/service.ts` and
11
- * `.../conversations/service.ts` already document for
12
- * `@intelligo-dev/auth`. `user_facts`/`user_memories`/
13
- * `user_profile_snapshots`/`user_memory_audit` are owned by
14
- * `packages/core/src/identity` (see that module's doc comment), and
15
- * that module cannot import this package to call a writer defined
16
- * here — the allowlist only grants the audit -> core edge, never
17
- * core -> audit.
18
- *
19
- * What actually lands here, then, is the event *contract*: the shape a
20
- * memory-audit write takes, re-exported from the schema module that
21
- * already owns it. The write itself is a faithful, in-package port at
22
- * `packages/core/src/identity/audit.ts`, used internally by the
23
- * identity service (`deleteFact`, `exportIdentity`) so it never
24
- * crosses the disallowed core -> audit edge. This module is the public
25
- * seam for anyone else who depends on `@intelligo-dev/audit` (executions,
26
- * admin, billing) and wants to describe a memory-audit event without
27
- * reaching into `@intelligo-dev/core/identity`'s internals.
28
- *
29
- * `packages/audit/src/db/schema.ts` already documents where this
30
- * settles: `user_memory_audit` folds into `audit_events` once the
31
- * memory subsystem's ownership question closes (see
32
- * docs/inventory/export-classification.md), and this contract
33
- * graduates to backing that table's writer directly.
4
+ * `@intelligo-dev/core` may depend on nothing, so the identity module
5
+ * that owns `user_memory_audit` cannot call a writer defined here; the
6
+ * write lives in `packages/core/src/identity/audit.ts`. This module is
7
+ * the public type for packages that depend on `@intelligo-dev/audit`
8
+ * and want to describe a memory-audit event without reaching into
9
+ * `@intelligo-dev/core/identity`'s internals.
34
10
  */
35
11
  import type { AuditTargetKind, AuditAction, AuditActorKind, UserMemoryAuditRow, InsertUserMemoryAudit } from "@intelligo-dev/core/db/schema";
36
12
  export type { AuditTargetKind, AuditAction, AuditActorKind, UserMemoryAuditRow, InsertUserMemoryAudit, };
37
13
  /**
38
- * The shape `recordMemoryAudit`
39
- * (`packages/core/src/identity/audit.ts`) accepts. Kept here — not in
40
- * `@intelligo-dev/core/identity` — so a package that depends on
41
- * `@intelligo-dev/audit` but not on the identity service directly has a
42
- * stable type to code against.
14
+ * The shape `recordMemoryAudit` (`packages/core/src/identity/audit.ts`)
15
+ * accepts.
43
16
  */
44
17
  export type RecordMemoryAuditInput = {
45
18
  userId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"memory-audit.d.ts","sourceRoot":"","sources":["../src/memory-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EACV,eAAe,EACf,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,qBAAqB,GACtB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,eAAe,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,cAAc,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC"}
1
+ {"version":3,"file":"memory-audit.d.ts","sourceRoot":"","sources":["../src/memory-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EACV,eAAe,EACf,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,qBAAqB,GACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,eAAe,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,cAAc,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC"}
@@ -1,36 +1,12 @@
1
1
  /**
2
- * Memory-audit event contract (ADR-0008).
2
+ * Memory-audit event contract.
3
3
  *
4
- * ADR-0008 names `@intelligo-dev/audit` as `recordMemoryAudit`'s
5
- * destination ("`recordMemoryAudit` to `audit`"). The dependency
6
- * allowlist doesn't cooperate with a literal move, though
7
- * (tests/architecture/dependency-direction.test.ts): this package may
8
- * depend on `@intelligo-dev/core` (`audit: ["@intelligo-dev/core"]`), but
9
- * `@intelligo-dev/core` may depend on nothing (`core: []`) — the same
10
- * constraint `packages/core/src/documents/service.ts` and
11
- * `.../conversations/service.ts` already document for
12
- * `@intelligo-dev/auth`. `user_facts`/`user_memories`/
13
- * `user_profile_snapshots`/`user_memory_audit` are owned by
14
- * `packages/core/src/identity` (see that module's doc comment), and
15
- * that module cannot import this package to call a writer defined
16
- * here — the allowlist only grants the audit -> core edge, never
17
- * core -> audit.
18
- *
19
- * What actually lands here, then, is the event *contract*: the shape a
20
- * memory-audit write takes, re-exported from the schema module that
21
- * already owns it. The write itself is a faithful, in-package port at
22
- * `packages/core/src/identity/audit.ts`, used internally by the
23
- * identity service (`deleteFact`, `exportIdentity`) so it never
24
- * crosses the disallowed core -> audit edge. This module is the public
25
- * seam for anyone else who depends on `@intelligo-dev/audit` (executions,
26
- * admin, billing) and wants to describe a memory-audit event without
27
- * reaching into `@intelligo-dev/core/identity`'s internals.
28
- *
29
- * `packages/audit/src/db/schema.ts` already documents where this
30
- * settles: `user_memory_audit` folds into `audit_events` once the
31
- * memory subsystem's ownership question closes (see
32
- * docs/inventory/export-classification.md), and this contract
33
- * graduates to backing that table's writer directly.
4
+ * `@intelligo-dev/core` may depend on nothing, so the identity module
5
+ * that owns `user_memory_audit` cannot call a writer defined here; the
6
+ * write lives in `packages/core/src/identity/audit.ts`. This module is
7
+ * the public type for packages that depend on `@intelligo-dev/audit`
8
+ * and want to describe a memory-audit event without reaching into
9
+ * `@intelligo-dev/core/identity`'s internals.
34
10
  */
35
11
  export {};
36
12
  //# sourceMappingURL=memory-audit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-audit.js","sourceRoot":"","sources":["../src/memory-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG"}
1
+ {"version":3,"file":"memory-audit.js","sourceRoot":"","sources":["../src/memory-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
package/package.json CHANGED
@@ -1,15 +1,26 @@
1
1
  {
2
2
  "name": "@intelligo-dev/audit",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.13",
4
+ "description": "Append-only audit events for multi-tenant apps, with a Postgres trigger that refuses every update and delete.",
5
+ "keywords": [
6
+ "intelligo",
7
+ "ai-saas",
8
+ "saas",
9
+ "typescript",
10
+ "audit-log",
11
+ "append-only",
12
+ "postgres"
13
+ ],
4
14
  "license": "Apache-2.0",
15
+ "author": "Turtuvshin Byambaa <toroo.byamba@gmail.com>",
5
16
  "repository": {
6
17
  "type": "git",
7
- "url": "git+https://github.com/intelligo-mn/framework.git",
18
+ "url": "git+https://github.com/intelligo-dev/intelligo.git",
8
19
  "directory": "packages/audit"
9
20
  },
10
- "homepage": "https://github.com/intelligo-mn/framework#readme",
21
+ "homepage": "https://intelligo.dev/docs/packages/audit",
11
22
  "bugs": {
12
- "url": "https://github.com/intelligo-mn/framework/issues"
23
+ "url": "https://github.com/intelligo-dev/intelligo/issues"
13
24
  },
14
25
  "type": "module",
15
26
  "exports": {
@@ -23,22 +34,37 @@
23
34
  }
24
35
  },
25
36
  "dependencies": {
26
- "drizzle-orm": "^0.45.1",
27
- "@intelligo-dev/core": "1.0.0-beta.1"
37
+ "@intelligo-dev/core": "1.0.0-beta.13"
38
+ },
39
+ "peerDependencies": {
40
+ "drizzle-orm": "^0.45.1"
28
41
  },
29
42
  "devDependencies": {
30
- "@types/node": "^22.0.0",
31
- "typescript": "^5.7.2"
43
+ "@types/node": "^26.6.1",
44
+ "drizzle-orm": "^0.45.2",
45
+ "typescript": "^5.9.3"
32
46
  },
33
47
  "files": [
34
- "dist"
48
+ "dist",
49
+ "src",
50
+ "!src/**/*.test.ts",
51
+ "!src/**/*.test.tsx",
52
+ "!src/**/__tests__/**",
53
+ "LICENSE",
54
+ "NOTICE",
55
+ "README.md",
56
+ "!dist/**/*.tsbuildinfo"
35
57
  ],
36
58
  "publishConfig": {
37
59
  "access": "public"
38
60
  },
61
+ "engines": {
62
+ "node": ">=22.14"
63
+ },
64
+ "sideEffects": false,
39
65
  "scripts": {
40
66
  "type-check": "tsc --noEmit",
41
67
  "lint": "eslint .",
42
- "build": "tsc -p tsconfig.build.json"
68
+ "build": "tsc -p tsconfig.build.json && node ../../scripts/fix-esm-extensions.mjs dist"
43
69
  }
44
70
  }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * One append-only table recording who did what to which resource.
3
+ * Scanned by drizzle-kit alongside the core schema directory (see
4
+ * packages/core/drizzle.config.ts) so the migration history stays
5
+ * unified in one database.
6
+ *
7
+ * Distinct from `user_memory_audit` in core/identity, which records
8
+ * mutations to a user's memory graph.
9
+ */
10
+
11
+ import { pgTable, text, timestamp, jsonb, index } from "drizzle-orm/pg-core";
12
+ import { organization, users } from "@intelligo-dev/core/db/schema";
13
+
14
+ export const auditEvents = pgTable(
15
+ "audit_events",
16
+ {
17
+ id: text("id").primaryKey(),
18
+ /**
19
+ * Null for platform-level events with no tenant — and for events
20
+ * whose workspace was since deleted: the trail outlives the tenant
21
+ * (set null, not cascade).
22
+ */
23
+ workspaceId: text("workspace_id").references(() => organization.id, {
24
+ onDelete: "set null",
25
+ }),
26
+ /** Null for system actors (cron, webhook, job runner). */
27
+ actorId: text("actor_id").references(() => users.id, {
28
+ onDelete: "set null",
29
+ }),
30
+ /** "user" | "system" | "support" — who initiated the action. */
31
+ actorKind: text("actor_kind").notNull().default("user"),
32
+ /** Dotted verb: "execution.completed", "credits.reserved", … */
33
+ action: text("action").notNull(),
34
+ /** Resource type the action applied to: "execution", "workspace", … */
35
+ resourceKind: text("resource_kind").notNull(),
36
+ /** Identifier of that resource; free-form (uuid, slug, email). */
37
+ resourceId: text("resource_id"),
38
+ /** "ok" | "failed" — outcome of the audited action. */
39
+ outcome: text("outcome").notNull().default("ok"),
40
+ metadata: jsonb("metadata").$type<Record<string, unknown>>(),
41
+ createdAt: timestamp("created_at").notNull().defaultNow(),
42
+ },
43
+ (table) => [
44
+ index("audit_events_workspace_created_idx").on(
45
+ table.workspaceId,
46
+ table.createdAt
47
+ ),
48
+ index("audit_events_action_idx").on(table.action, table.createdAt),
49
+ index("audit_events_resource_idx").on(table.resourceKind, table.resourceId),
50
+ ]
51
+ );
52
+
53
+ export type AuditEvent = typeof auditEvents.$inferSelect;
54
+ export type InsertAuditEvent = typeof auditEvents.$inferInsert;
package/src/index.ts ADDED
@@ -0,0 +1,204 @@
1
+ /**
2
+ * @intelligo-dev/audit — append-only record of who did what.
3
+ *
4
+ * Emitting is deliberately failure-tolerant: an audit write must never
5
+ * break the operation being audited. `recordAuditEvent` swallows and
6
+ * logs; callers that need the guarantee (impersonation, destructive
7
+ * support actions) use `recordAuditEventOrThrow`.
8
+ */
9
+
10
+ import { db } from "@intelligo-dev/core/db";
11
+ import { createLogger } from "@intelligo-dev/core/logger";
12
+ import { createRegistry } from "@intelligo-dev/core/registry";
13
+ import { and, desc, eq, lt } from "drizzle-orm";
14
+
15
+ import { auditEvents } from "./db/schema";
16
+
17
+ const log = createLogger("Audit");
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Sinks
21
+ // ---------------------------------------------------------------------------
22
+
23
+ /**
24
+ * Called after an event is durably recorded. Sinks are registered by
25
+ * the composition root, never by being imported; they exist for
26
+ * governance work outside this package — tamper-evidence, retention
27
+ * policy, shipping the trail to a SIEM.
28
+ *
29
+ * A sink runs after the write, so it cannot corrupt or delay the audit
30
+ * row itself, and its failures are isolated: an exporter with an
31
+ * expired credential must not break the operation being audited, nor
32
+ * the other sinks.
33
+ */
34
+ export type AuditSink = (event: RecordedAuditEvent) => Promise<void> | void;
35
+
36
+ /**
37
+ * The row as written, which is what a sink needs to act on.
38
+ *
39
+ * Spelled out rather than inferred from `toRow`: inference gives `id`
40
+ * the template-literal type of `crypto.randomUUID()`, which is not
41
+ * what comes back out of the database, so every consumer would have to
42
+ * widen it.
43
+ */
44
+ export type RecordedAuditEvent = {
45
+ id: string;
46
+ workspaceId: string | null;
47
+ actorId: string | null;
48
+ actorKind: string;
49
+ action: string;
50
+ resourceKind: string;
51
+ resourceId: string | null;
52
+ outcome: string;
53
+ metadata: Record<string, unknown> | null;
54
+ createdAt: Date;
55
+ };
56
+
57
+ const sinks = createRegistry<AuditSink>("audit/sinks");
58
+
59
+ /** Register (or replace) a sink under a stable name. */
60
+ export function registerAuditSink(name: string, sink: AuditSink): void {
61
+ sinks.set(name, sink);
62
+ }
63
+
64
+ export function registeredAuditSinks(): string[] {
65
+ return [...sinks.keys()];
66
+ }
67
+
68
+ export function clearAuditSinks(): void {
69
+ sinks.clear();
70
+ }
71
+
72
+ async function fanOut(event: RecordedAuditEvent): Promise<void> {
73
+ if (sinks.size === 0) return;
74
+
75
+ await Promise.all(
76
+ [...sinks.entries()].map(async ([name, sink]) => {
77
+ try {
78
+ await sink(event);
79
+ } catch (error) {
80
+ log.error("Audit sink failed", {
81
+ sink: name,
82
+ action: event.action,
83
+ error: error instanceof Error ? error.message : String(error),
84
+ });
85
+ }
86
+ })
87
+ );
88
+ }
89
+
90
+ export type AuditActorKind = "user" | "system" | "support";
91
+ export type AuditOutcome = "ok" | "failed";
92
+
93
+ export type AuditEventInput = {
94
+ /** Omit for platform-level events with no tenant. */
95
+ workspaceId?: string | null;
96
+ /** Omit for system actors (cron, webhook, job runner). */
97
+ actorId?: string | null;
98
+ actorKind?: AuditActorKind;
99
+ /** Dotted verb, e.g. "execution.completed". */
100
+ action: string;
101
+ /** Resource type, e.g. "execution". */
102
+ resourceKind: string;
103
+ resourceId?: string | null;
104
+ outcome?: AuditOutcome;
105
+ metadata?: Record<string, unknown>;
106
+ };
107
+
108
+ function toRow(event: AuditEventInput) {
109
+ return {
110
+ id: crypto.randomUUID(),
111
+ workspaceId: event.workspaceId ?? null,
112
+ actorId: event.actorId ?? null,
113
+ actorKind: event.actorKind ?? (event.actorId ? "user" : "system"),
114
+ action: event.action,
115
+ resourceKind: event.resourceKind,
116
+ resourceId: event.resourceId ?? null,
117
+ outcome: event.outcome ?? "ok",
118
+ metadata: event.metadata ?? null,
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Record an audit event. Never throws — a failed audit write is logged
124
+ * and swallowed so it cannot take down the audited operation.
125
+ */
126
+ export async function recordAuditEvent(event: AuditEventInput): Promise<void> {
127
+ try {
128
+ const row = toRow(event);
129
+ await db.insert(auditEvents).values(row);
130
+ await fanOut({ ...row, createdAt: new Date() });
131
+ } catch (error) {
132
+ log.error("Audit write failed", {
133
+ action: event.action,
134
+ resourceKind: event.resourceKind,
135
+ error: error instanceof Error ? error.message : String(error),
136
+ });
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Record an audit event, propagating failures. Use where the audit
142
+ * trail is part of the contract (impersonation, destructive support
143
+ * actions) and the operation must abort if it cannot be recorded.
144
+ */
145
+ export async function recordAuditEventOrThrow(
146
+ event: AuditEventInput
147
+ ): Promise<void> {
148
+ const row = toRow(event);
149
+ await db.insert(auditEvents).values(row);
150
+ // Sinks stay failure-isolated even here. The contract this function
151
+ // adds is that the *event was recorded*; a downstream exporter being
152
+ // unreachable does not make it unrecorded, and failing the caller
153
+ // over it would mean an expired SIEM token could block impersonation
154
+ // and every destructive support action.
155
+ await fanOut({ ...row, createdAt: new Date() });
156
+ }
157
+
158
+ export type QueryAuditEventsOptions = {
159
+ workspaceId?: string;
160
+ action?: string;
161
+ resourceKind?: string;
162
+ resourceId?: string;
163
+ /** Keyset pagination: return events created strictly before this. */
164
+ before?: Date;
165
+ limit?: number;
166
+ };
167
+
168
+ /** Most-recent-first query for the admin console. */
169
+ export async function queryAuditEvents(options: QueryAuditEventsOptions = {}) {
170
+ const filters = [
171
+ options.workspaceId
172
+ ? eq(auditEvents.workspaceId, options.workspaceId)
173
+ : undefined,
174
+ options.action ? eq(auditEvents.action, options.action) : undefined,
175
+ options.resourceKind
176
+ ? eq(auditEvents.resourceKind, options.resourceKind)
177
+ : undefined,
178
+ options.resourceId
179
+ ? eq(auditEvents.resourceId, options.resourceId)
180
+ : undefined,
181
+ options.before ? lt(auditEvents.createdAt, options.before) : undefined,
182
+ ].filter(Boolean);
183
+
184
+ return db
185
+ .select()
186
+ .from(auditEvents)
187
+ .where(filters.length > 0 ? and(...filters) : undefined)
188
+ .orderBy(desc(auditEvents.createdAt))
189
+ .limit(Math.min(options.limit ?? 50, 500));
190
+ }
191
+
192
+ export { auditEvents } from "./db/schema";
193
+ export type { AuditEvent, InsertAuditEvent } from "./db/schema";
194
+
195
+ // Memory-audit event contract — see ./memory-audit.ts for
196
+ // why this is a type-only re-export rather than a second writer.
197
+ export type {
198
+ AuditTargetKind as MemoryAuditTargetKind,
199
+ AuditAction as MemoryAuditAction,
200
+ AuditActorKind as MemoryAuditActorKind,
201
+ UserMemoryAuditRow,
202
+ InsertUserMemoryAudit,
203
+ RecordMemoryAuditInput,
204
+ } from "./memory-audit";
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Memory-audit event contract.
3
+ *
4
+ * `@intelligo-dev/core` may depend on nothing, so the identity module
5
+ * that owns `user_memory_audit` cannot call a writer defined here; the
6
+ * write lives in `packages/core/src/identity/audit.ts`. This module is
7
+ * the public type for packages that depend on `@intelligo-dev/audit`
8
+ * and want to describe a memory-audit event without reaching into
9
+ * `@intelligo-dev/core/identity`'s internals.
10
+ */
11
+
12
+ import type {
13
+ AuditTargetKind,
14
+ AuditAction,
15
+ AuditActorKind,
16
+ UserMemoryAuditRow,
17
+ InsertUserMemoryAudit,
18
+ } from "@intelligo-dev/core/db/schema";
19
+
20
+ export type {
21
+ AuditTargetKind,
22
+ AuditAction,
23
+ AuditActorKind,
24
+ UserMemoryAuditRow,
25
+ InsertUserMemoryAudit,
26
+ };
27
+
28
+ /**
29
+ * The shape `recordMemoryAudit` (`packages/core/src/identity/audit.ts`)
30
+ * accepts.
31
+ */
32
+ export type RecordMemoryAuditInput = {
33
+ userId: string;
34
+ workspaceId: string;
35
+ targetKind: AuditTargetKind;
36
+ targetId: string;
37
+ action: AuditAction;
38
+ actorKind: AuditActorKind;
39
+ actorId?: string;
40
+ beforeValue?: unknown;
41
+ afterValue?: unknown;
42
+ reason?: string;
43
+ };