pipework 0.59.0 → 0.61.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/CHANGELOG.md +12 -0
- package/REFERENCE.md +12 -2
- package/dist/audit/chain/install.d.ts +4 -2
- package/dist/audit/chain/install.d.ts.map +1 -1
- package/dist/audit/chain/install.js +5 -3
- package/dist/audit/chain/install.js.map +1 -1
- package/dist/audit/query/query.d.ts +4 -0
- package/dist/audit/query/query.d.ts.map +1 -1
- package/dist/audit/query/query.js +6 -0
- package/dist/audit/query/query.js.map +1 -1
- package/dist/audit/schema/audit-record-fields.d.ts +5 -0
- package/dist/audit/schema/audit-record-fields.d.ts.map +1 -1
- package/dist/audit/schema/audit-record-fields.js +5 -0
- package/dist/audit/schema/audit-record-fields.js.map +1 -1
- package/dist/audit/schema/audit-record.d.ts +8 -0
- package/dist/audit/schema/audit-record.d.ts.map +1 -1
- package/dist/audit/schema/audit-record.js +7 -0
- package/dist/audit/schema/audit-record.js.map +1 -1
- package/dist/auth/auth/multi-org.d.ts +8 -1
- package/dist/auth/auth/multi-org.d.ts.map +1 -1
- package/dist/auth/auth/multi-org.js +9 -1
- package/dist/auth/auth/multi-org.js.map +1 -1
- package/dist/auth/auth/schema.d.ts +77 -0
- package/dist/auth/auth/schema.d.ts.map +1 -0
- package/dist/auth/auth/schema.js +57 -0
- package/dist/auth/auth/schema.js.map +1 -0
- package/dist/auth/auth/sessions.d.ts +4 -1
- package/dist/auth/auth/sessions.d.ts.map +1 -1
- package/dist/auth/auth/sessions.js +6 -1
- package/dist/auth/auth/sessions.js.map +1 -1
- package/dist/auth/auth/uuid.d.ts +3 -0
- package/dist/auth/auth/uuid.d.ts.map +1 -0
- package/dist/auth/auth/uuid.js +9 -0
- package/dist/auth/auth/uuid.js.map +1 -0
- package/dist/core/config/namespace.d.ts +2 -0
- package/dist/core/config/namespace.d.ts.map +1 -1
- package/dist/core/config/schema.d.ts +2 -0
- package/dist/core/config/schema.d.ts.map +1 -1
- package/dist/core/config/schema.js +4 -0
- package/dist/core/config/schema.js.map +1 -1
- package/dist/data/migrate/generate.d.ts +1 -0
- package/dist/data/migrate/generate.d.ts.map +1 -1
- package/dist/data/migrate/generate.js +15 -1
- package/dist/data/migrate/generate.js.map +1 -1
- package/dist/data/migrate/internal-definitions.d.ts.map +1 -1
- package/dist/data/migrate/internal-definitions.js +9 -0
- package/dist/data/migrate/internal-definitions.js.map +1 -1
- package/dist/data/migrate/provision-framework.d.ts.map +1 -1
- package/dist/data/migrate/provision-framework.js +3 -0
- package/dist/data/migrate/provision-framework.js.map +1 -1
- package/dist/data/write/audit/audit-columns.d.ts +1 -1
- package/dist/data/write/audit/audit-columns.d.ts.map +1 -1
- package/dist/data/write/audit/audit-select.d.ts +9 -2
- package/dist/data/write/audit/audit-select.d.ts.map +1 -1
- package/dist/data/write/audit/audit-select.js +22 -2
- package/dist/data/write/audit/audit-select.js.map +1 -1
- package/dist/data/write/audit/primary-key.d.ts +8 -0
- package/dist/data/write/audit/primary-key.d.ts.map +1 -1
- package/dist/data/write/audit/primary-key.js +32 -7
- package/dist/data/write/audit/primary-key.js.map +1 -1
- package/dist/data/write/audit/verb-delete.d.ts.map +1 -1
- package/dist/data/write/audit/verb-delete.js +2 -2
- package/dist/data/write/audit/verb-delete.js.map +1 -1
- package/dist/data/write/audit/verb-insert.d.ts.map +1 -1
- package/dist/data/write/audit/verb-insert.js +2 -2
- package/dist/data/write/audit/verb-insert.js.map +1 -1
- package/dist/data/write/audit/verb-update.d.ts.map +1 -1
- package/dist/data/write/audit/verb-update.js +2 -2
- package/dist/data/write/audit/verb-update.js.map +1 -1
- package/dist/data/write/audit/verb-upsert.d.ts.map +1 -1
- package/dist/data/write/audit/verb-upsert.js +2 -2
- package/dist/data/write/audit/verb-upsert.js.map +1 -1
- package/dist/infra/access-links/handle.js +6 -6
- package/dist/infra/access-links/handle.js.map +1 -1
- package/dist/infra/audit/namespace.d.ts +6 -1
- package/dist/infra/audit/namespace.d.ts.map +1 -1
- package/dist/infra/audit/namespace.js +6 -1
- package/dist/infra/audit/namespace.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.61.0
|
|
4
|
+
|
|
5
|
+
**Schema note: apps using `auth.createSessions` / `auth.createMultiOrg` can now get their tables from `pipework generate`. Existing tables from the hand-copied SQL keep working (the statements are `IF NOT EXISTS`); to type their ids uuid, run `ALTER TABLE pipework_refresh_tokens ALTER COLUMN tenant_id TYPE uuid USING tenant_id::uuid` and `ALTER TABLE pipework_user_orgs ALTER COLUMN org_id TYPE uuid USING org_id::uuid` once.**
|
|
6
|
+
|
|
7
|
+
- **New: blueprint `sessions: {}` and `orgs: {}` put the session and multi-org tables in generated migrations.** `sessions` adds `pipework_refresh_tokens` and `pipework_auth_versions`; `orgs` adds `pipework_user_orgs`. `tenant_id` and `org_id` are uuid, so an org id can be the tenant id; a `tenantId` or `orgId` that is not a uuid now throws a `ValidationError` instead of a Postgres cast error. The tables are not tenant-scoped (refresh lookup and sign-in read across tenants). A custom `createMultiOrg({ table })` stays the app's own DDL.
|
|
8
|
+
|
|
9
|
+
## 0.60.0
|
|
10
|
+
|
|
11
|
+
**Schema note: `audit_record` gains a nullable `entity_id` column and an index on `(tenant_id, entity, entity_id, occurred_at, id)`. `pipework migrate` adds both.**
|
|
12
|
+
|
|
13
|
+
- **New: `audit.query({ entity, entityId })` returns one row's history.** Every audited write records the written row's primary key in `entity_id` (the value as text; a composite key as a JSON array of the values in key order, built with `audit.entityId(table, row)`), and the filter is served by an index instead of scanning the tenant's records for that entity. `entityId` requires `entity`. Access-link audit rows carry the link id. Rows written earlier have no `entity_id` and are not found by it. With `audit.chain` on, new rows' hashes cover `entity_id`; existing rows hash as before and `audit.verify` stays ok across both.
|
|
14
|
+
|
|
3
15
|
## 0.59.0
|
|
4
16
|
|
|
5
17
|
**Schema note: `access_link_use` gains two nullable columns, `detail` (jsonb) and `claimed_at` (timestamptz). Run `pipework generate` and `pipework migrate` in apps that use access links.**
|
package/REFERENCE.md
CHANGED
|
@@ -284,10 +284,14 @@ Authentication namespace — session management, multi-org support, auth chain r
|
|
|
284
284
|
|
|
285
285
|
Creates a Sessions manager with JWT access/refresh tokens, rotation, and reuse detection.
|
|
286
286
|
|
|
287
|
+
Opt in with blueprint `sessions: {}`. The generated migration then includes `pipework_refresh_tokens` and `pipework_auth_versions`. `user_id` is text (the app's id format); `tenant_id` is uuid, and `tenantId` passed to `issueTokens` must be a uuid or it throws a `ValidationError`. `pipework_refresh_tokens` is deliberately not tenant-scoped: a refresh is looked up by its token hash before any tenant is known. The statements are `IF NOT EXISTS`, so apps that created these tables by hand keep working; if yours has `tenant_id text` holding uuids, run once: `ALTER TABLE pipework_refresh_tokens ALTER COLUMN tenant_id TYPE uuid USING tenant_id::uuid`.
|
|
288
|
+
|
|
287
289
|
### `auth.createMultiOrg`
|
|
288
290
|
|
|
289
291
|
Creates multi-org session management — org selection, switching, membership CRUD.
|
|
290
292
|
|
|
293
|
+
Opt in with blueprint `orgs: {}` (plus `sessions: {}`). The generated migration then includes `pipework_user_orgs` (`user_id` text, `org_id` uuid, `role`, `joined_at`, `added_by`, unique on `(user_id, org_id)`). It is deliberately not tenant-scoped: a user's orgs are read across orgs at sign-in. An `orgId` that is not a uuid throws a `ValidationError`. The statements are `IF NOT EXISTS`; if your existing table has `org_id text` holding uuids, run once: `ALTER TABLE pipework_user_orgs ALTER COLUMN org_id TYPE uuid USING org_id::uuid`. The definition is for the default table name only: with a custom `table`, the app owns that table's DDL.
|
|
294
|
+
|
|
291
295
|
### `auth.runChain`
|
|
292
296
|
|
|
293
297
|
Executes an auth chain (strategy pipeline) to resolve auth + tenant from a request.
|
|
@@ -1035,7 +1039,13 @@ Creates an Audit instance that writes audit records to a Postgres table.
|
|
|
1035
1039
|
|
|
1036
1040
|
### `audit.query`
|
|
1037
1041
|
|
|
1038
|
-
Queries the framework-managed `audit_record` table. Tenant-scoped via the active Flow.
|
|
1042
|
+
Queries the framework-managed `audit_record` table. Tenant-scoped via the active Flow. `{ entity, entityId }` returns one row's history from an index; build a composite key's `entityId` with `audit.entityId`.
|
|
1043
|
+
|
|
1044
|
+
Every audited write records the written row's primary key in `audit_record.entity_id`: the key's value as text, or for a composite key a compact JSON array of the key values as strings in key order. `entityId` filters on it, requires `entity` (else a `ValidationError`), and is served by the index `audit_record_entity_idx` on `(tenant_id, entity, entity_id, occurred_at, id)`. Delete rows carry the deleted row's key. Access-link rows (`AccessLink` create, revoke, use) carry the link id. Read-touches rows, and rows written before the column existed, have no `entity_id` and never match.
|
|
1045
|
+
|
|
1046
|
+
### `audit.entityId`
|
|
1047
|
+
|
|
1048
|
+
The `entityId` filter text for a written table's row: `audit.entityId(table, row)`. The primary key's value as text, or for a composite key a compact JSON array of the key values as strings in key order (`["a","7"]`). Dates become ISO strings.
|
|
1039
1049
|
|
|
1040
1050
|
### `audit.chainHead`
|
|
1041
1051
|
|
|
@@ -1051,7 +1061,7 @@ Opt in with blueprint `audit: { chain: true }`. Every `audit_record` row then ca
|
|
|
1051
1061
|
|
|
1052
1062
|
**Lock cost.** The trigger locks the tenant's chain-head row, so one tenant's audited writes serialize from their first audit row until their transaction commits. Different tenants do not block each other. Keep transactions that write audit rows short.
|
|
1053
1063
|
|
|
1054
|
-
**Canonical form.** A row's hash is `sha256(prev_hash_bytes || utf8(canonical))`, where `prev_hash_bytes` is the previous row's hash (32 zero bytes for `chain_seq` 1) and `canonical` is the text of this JSON array, as Postgres renders it: `[chain_seq, id, trace_day (YYYY-MM-DD), trace_id, trace_step_id, tenant_id, actor_id, entity, verb, before, after, captured_inputs, occurred_at]
|
|
1064
|
+
**Canonical form.** A row's hash is `sha256(prev_hash_bytes || utf8(canonical))`, where `prev_hash_bytes` is the previous row's hash (32 zero bytes for `chain_seq` 1) and `canonical` is the text of this JSON array, as Postgres renders it: `[chain_seq, id, trace_day (YYYY-MM-DD), trace_id, trace_step_id, tenant_id, actor_id, entity, verb, before, after, captured_inputs, occurred_at]`, followed by `entity_id` only when it is not null (so a row without one, such as a row written before the column existed, hashes as it always did). `occurred_at` is UTC, formatted `YYYY-MM-DDTHH:MI:SS.UUUUUUZ` (microseconds), so the result does not depend on the session TimeZone. `before`, `after` and `captured_inputs` are jsonb (keys in jsonb order). The SQL function `pipework_audit_record_canonical(audit_record)` returns this text.
|
|
1055
1065
|
|
|
1056
1066
|
**`audit.verify(options?)`** checks every seq in the range. Options: `fromSeq`, `toSeq`, `from` / `to` (`occurredAt >= from`, `< to`), and `anchor: { seq, hash }` (a pair saved from `audit.chainHead()`). Without an upper bound, the range ends at the chain head and its last record must equal the head, which catches deletion of the newest rows (reported as `missing`); rows committed after the head was read are not checked. Breaks, always the first in seq order: `hash-mismatch` (row edited), `prev-mismatch` (link to the previous row broken), `missing` (a seq has no row), `head-mismatch` (the chain head disagrees with the newest record, or is gone while records remain), `anchor-mismatch`. A tenant-scoped Flow verifies that tenant's chain; outside one, the chain of tenant-less rows. `seq` values are returned as numbers.
|
|
1057
1067
|
|
|
@@ -9,9 +9,11 @@ export declare const CHAIN_KEY_SQL = "coalesce(tenant_id, '00000000-0000-0000-00
|
|
|
9
9
|
* The text hashed for one row. `jsonb_build_array(...)::text` of, in order:
|
|
10
10
|
* chain_seq, id, trace_day (YYYY-MM-DD), trace_id, trace_step_id, tenant_id,
|
|
11
11
|
* actor_id, entity, verb, before, after, captured_inputs, occurred_at (UTC,
|
|
12
|
-
* `YYYY-MM-DD"T"HH24:MI:SS.US"Z"`)
|
|
12
|
+
* `YYYY-MM-DD"T"HH24:MI:SS.US"Z"`), then entity_id only when it is not null.
|
|
13
|
+
* A row without an entity_id (read-touches, rows written before the column
|
|
14
|
+
* existed) hashes exactly as it always did. Independent of the session TimeZone.
|
|
13
15
|
*/
|
|
14
|
-
export declare const CANONICAL_FUNCTION_SQL = "\nCREATE OR REPLACE FUNCTION pipework_audit_record_canonical(r audit_record) RETURNS text\nLANGUAGE sql IMMUTABLE SET search_path = pg_catalog AS $$\n SELECT jsonb_build_array(\n r.chain_seq, r.id, to_char(r.trace_day, 'YYYY-MM-DD'), r.trace_id, r.trace_step_id,\n r.tenant_id, r.actor_id, r.entity, r.verb, r.before, r.after, r.captured_inputs,\n to_char(r.occurred_at AT TIME ZONE 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS.US\"Z\"')\n )::text\n$$";
|
|
16
|
+
export declare const CANONICAL_FUNCTION_SQL = "\nCREATE OR REPLACE FUNCTION pipework_audit_record_canonical(r audit_record) RETURNS text\nLANGUAGE sql IMMUTABLE SET search_path = pg_catalog AS $$\n SELECT (jsonb_build_array(\n r.chain_seq, r.id, to_char(r.trace_day, 'YYYY-MM-DD'), r.trace_id, r.trace_step_id,\n r.tenant_id, r.actor_id, r.entity, r.verb, r.before, r.after, r.captured_inputs,\n to_char(r.occurred_at AT TIME ZONE 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS.US\"Z\"')\n ) || CASE WHEN r.entity_id IS NULL THEN '[]'::jsonb ELSE jsonb_build_array(r.entity_id) END)::text\n$$";
|
|
15
17
|
/**
|
|
16
18
|
* Install the audit hash chain on `audit_record`. The table must exist.
|
|
17
19
|
* Idempotent.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/audit/chain/install.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;AAGhD,oEAAoE;AACpE,eAAO,MAAM,qBAAqB,yCAAyC,CAAA;AAE3E,eAAO,MAAM,gBAAgB,8BAA8B,CAAA;AAC3D,eAAO,MAAM,mBAAmB,iCAAiC,CAAA;AAEjE,sFAAsF;AACtF,eAAO,MAAM,aAAa,sEAA0D,CAAA;AAIpF
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/audit/chain/install.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;AAGhD,oEAAoE;AACpE,eAAO,MAAM,qBAAqB,yCAAyC,CAAA;AAE3E,eAAO,MAAM,gBAAgB,8BAA8B,CAAA;AAC3D,eAAO,MAAM,mBAAmB,iCAAiC,CAAA;AAEjE,sFAAsF;AACtF,eAAO,MAAM,aAAa,sEAA0D,CAAA;AAIpF;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,oiBAQhC,CAAA;AAgCH;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B7D"}
|
|
@@ -20,16 +20,18 @@ const GENESIS_HASH_HEX = '00'.repeat(32);
|
|
|
20
20
|
* The text hashed for one row. `jsonb_build_array(...)::text` of, in order:
|
|
21
21
|
* chain_seq, id, trace_day (YYYY-MM-DD), trace_id, trace_step_id, tenant_id,
|
|
22
22
|
* actor_id, entity, verb, before, after, captured_inputs, occurred_at (UTC,
|
|
23
|
-
* `YYYY-MM-DD"T"HH24:MI:SS.US"Z"`)
|
|
23
|
+
* `YYYY-MM-DD"T"HH24:MI:SS.US"Z"`), then entity_id only when it is not null.
|
|
24
|
+
* A row without an entity_id (read-touches, rows written before the column
|
|
25
|
+
* existed) hashes exactly as it always did. Independent of the session TimeZone.
|
|
24
26
|
*/
|
|
25
27
|
export const CANONICAL_FUNCTION_SQL = `
|
|
26
28
|
CREATE OR REPLACE FUNCTION pipework_audit_record_canonical(r audit_record) RETURNS text
|
|
27
29
|
LANGUAGE sql IMMUTABLE SET search_path = pg_catalog AS $$
|
|
28
|
-
SELECT jsonb_build_array(
|
|
30
|
+
SELECT (jsonb_build_array(
|
|
29
31
|
r.chain_seq, r.id, to_char(r.trace_day, 'YYYY-MM-DD'), r.trace_id, r.trace_step_id,
|
|
30
32
|
r.tenant_id, r.actor_id, r.entity, r.verb, r.before, r.after, r.captured_inputs,
|
|
31
33
|
to_char(r.occurred_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US"Z"')
|
|
32
|
-
)::text
|
|
34
|
+
) || CASE WHEN r.entity_id IS NULL THEN '[]'::jsonb ELSE jsonb_build_array(r.entity_id) END)::text
|
|
33
35
|
$$`;
|
|
34
36
|
function insertTriggerFunctionSql(schema) {
|
|
35
37
|
return `
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/audit/chain/install.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,6EAA6E;AAC7E,qEAAqE;AACrE,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,8EAA8E;AAC9E,6EAA6E;AAC7E,sDAAsD;AAEtD,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAE1C,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAE9D,oEAAoE;AACpE,MAAM,CAAC,MAAM,qBAAqB,GAAG,sCAAsC,CAAA;AAE3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAA;AAC3D,MAAM,CAAC,MAAM,mBAAmB,GAAG,8BAA8B,CAAA;AAEjE,sFAAsF;AACtF,MAAM,CAAC,MAAM,aAAa,GAAG,wBAAwB,qBAAqB,UAAU,CAAA;AAEpF,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAExC
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/audit/chain/install.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,6EAA6E;AAC7E,qEAAqE;AACrE,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,8EAA8E;AAC9E,6EAA6E;AAC7E,sDAAsD;AAEtD,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAE1C,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAE9D,oEAAoE;AACpE,MAAM,CAAC,MAAM,qBAAqB,GAAG,sCAAsC,CAAA;AAE3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAA;AAC3D,MAAM,CAAC,MAAM,mBAAmB,GAAG,8BAA8B,CAAA;AAEjE,sFAAsF;AACtF,MAAM,CAAC,MAAM,aAAa,GAAG,wBAAwB,qBAAqB,UAAU,CAAA;AAEpF,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;AAExC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;GAQnC,CAAA;AAEH,SAAS,wBAAwB,CAAC,MAAc;IAC9C,OAAO;;kEAEyD,MAAM;;uCAEjC,qBAAqB;;;gBAG5C,gBAAgB;4BACJ,gBAAgB;;iCAEX,gBAAgB;;;;WAItC,gBAAgB;;;GAGxB,CAAA;AACH,CAAC;AAED,MAAM,wBAAwB,GAAG;;;;;;;GAO9B,CAAA;AAEH;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAM;IAC5C,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA,mCAAmC,CAAC,CAAA;IAC3E,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;IAE1E,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CACtB,8BAA8B,gBAAgB,IAAI;QAClD,uEAAuE,CACxE,CAAC,CAAA;IACF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CACtB,8BAA8B,mBAAmB,IAAI;QACrD,kGAAkG,CACnG,CAAC,CAAA;IACF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAA;IACjD,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAC3D,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAA;IACnD,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CACtB,sFAAsF;QACtF,oEAAoE,CACrE,CAAC,CAAA;IACF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CACtB,qGAAqG;QACrG,kEAAkE,CACnE,CAAC,CAAA;IACF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CACtB,uEAAuE,aAAa,eAAe,CACpG,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -8,6 +8,10 @@ export type AuditRecordRow = typeof auditRecord.Select;
|
|
|
8
8
|
export interface AuditQueryFilters {
|
|
9
9
|
/** Match audit rows whose `entity` is in this set. Single string accepted as shorthand. */
|
|
10
10
|
readonly entity?: string | readonly string[];
|
|
11
|
+
/**
|
|
12
|
+
* Match audit rows written for the row with this primary key — one row's history, served by an index on `(tenantId, entity, entityId, occurredAt, id)`. Requires `entity`. The text is the key's value, or for a composite key `audit.entityId(table, row)`; access-link rows carry the link id. Rows written before `entityId` existed, and read-touches rows, have none and never match.
|
|
13
|
+
*/
|
|
14
|
+
readonly entityId?: string;
|
|
11
15
|
/** Match audit rows whose `verb` is in this set. Single string accepted as shorthand. */
|
|
12
16
|
readonly verb?: string | readonly string[];
|
|
13
17
|
/** Match audit rows whose `actorId` equals this. `null` matches system-actor rows. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/audit/query/query.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAuBvD;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,WAAW,CAAC,MAAM,CAAA;AAEtD,MAAM,WAAW,iBAAiB;IAChC,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IAC5C,yFAAyF;IACzF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IAC1C,sFAAsF;IACtF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,iDAAiD;IACjD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,mHAAmH;IACnH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,2CAA2C;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,IAAI,CAAA;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,CAAA;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,CAAA;IACxC,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAKD;;;;GAIG;AACH,wBAAsB,KAAK,CACzB,OAAO,GAAE,iBAAsB,EAC/B,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/audit/query/query.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAuBvD;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,WAAW,CAAC,MAAM,CAAA;AAEtD,MAAM,WAAW,iBAAiB;IAChC,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IAC5C;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,yFAAyF;IACzF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IAC1C,sFAAsF;IACtF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,iDAAiD;IACjD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,mHAAmH;IACnH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,2CAA2C;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,IAAI,CAAA;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,CAAA;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,CAAA;IACxC,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAKD;;;;GAIG;AACH,wBAAsB,KAAK,CACzB,OAAO,GAAE,iBAAsB,EAC/B,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAsD3B"}
|
|
@@ -28,9 +28,15 @@ export async function query(filters = {}, options = {}) {
|
|
|
28
28
|
const ascending = options.asc === true;
|
|
29
29
|
const table = auditRecord.table();
|
|
30
30
|
const cols = table;
|
|
31
|
+
if (filters.entityId !== undefined && (filters.entity === undefined || (Array.isArray(filters.entity) && filters.entity.length === 0))) {
|
|
32
|
+
throw new ValidationError('audit.query: entityId requires entity. A row id is only meaningful within one entity — ' +
|
|
33
|
+
'pass { entity: "Item", entityId } (use audit.entityId(table, row) for a composite key).');
|
|
34
|
+
}
|
|
31
35
|
const conditions = [];
|
|
32
36
|
appendFilter(conditions, filters.entity, v => buildInOrEq(cols['entity'], v));
|
|
33
37
|
appendFilter(conditions, filters.verb, v => buildInOrEq(cols['verb'], v));
|
|
38
|
+
if (filters.entityId !== undefined)
|
|
39
|
+
conditions.push(eq(cols['entityId'], filters.entityId));
|
|
34
40
|
if (filters.actorId !== undefined) {
|
|
35
41
|
conditions.push(eq(cols['actorId'], filters.actorId));
|
|
36
42
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/audit/query/query.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wEAAwE;AACxE,0EAA0E;AAC1E,mDAAmD;AACnD,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,yDAAyD;AACzD,EAAE;AACF,wEAAwE;AACxE,yEAAyE;AACzE,uDAAuD;AAEvD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAC3D,OAAO,EACL,GAAG,EACH,EAAE,EACF,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,OAAO,EACP,IAAI,EACJ,GAAG,EACH,EAAE,GACH,MAAM,2BAA2B,CAAA;AAElC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,GAElB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/audit/query/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,11 @@ export declare const auditRecordFields: {
|
|
|
21
21
|
}>;
|
|
22
22
|
entity: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
23
23
|
verb: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
24
|
+
entityId: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
25
|
+
nullable: true;
|
|
26
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
27
|
+
nullable: true;
|
|
28
|
+
}>;
|
|
24
29
|
before: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType, {
|
|
25
30
|
nullable: true;
|
|
26
31
|
}> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-record-fields.d.ts","sourceRoot":"","sources":["../../../src/audit/schema/audit-record-fields.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"audit-record-fields.d.ts","sourceRoot":"","sources":["../../../src/audit/schema/audit-record-fields.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4C7B,CAAA;AAED,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAA6C,CAAA"}
|
|
@@ -38,6 +38,11 @@ export const auditRecordFields = {
|
|
|
38
38
|
// non-null — a `@touches` annotation requires both halves.
|
|
39
39
|
entity: field.text(),
|
|
40
40
|
verb: field.text(),
|
|
41
|
+
// The audited row's primary key as text: the single key's value, or for a
|
|
42
|
+
// composite key a JSON array of the key values (as text, in key order). Null
|
|
43
|
+
// on read-touches rows and on rows written before the column existed.
|
|
44
|
+
// Indexed with the tenant and entity so one row's history is an index range.
|
|
45
|
+
entityId: field.text().nullable(),
|
|
41
46
|
// Server-side `.traceSafe()` projection of the row before/after the write.
|
|
42
47
|
// Both nullable: create-verb has no `before`, delete-verb has no `after`,
|
|
43
48
|
// read-touches has neither.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-record-fields.js","sourceRoot":"","sources":["../../../src/audit/schema/audit-record-fields.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,0EAA0E;AAC1E,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,wBAAwB;AACxB,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,oEAAoE;AACpE,0EAA0E;AAC1E,2EAA2E;AAC3E,8DAA8D;AAE9D,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAA;AAE5D,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,aAAa,EAAE;IACvD,4EAA4E;IAC5E,uEAAuE;IACvE,qEAAqE;IACrE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE;IACtB,0EAA0E;IAC1E,yEAAyE;IACzE,kEAAkE;IAClE,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClE,2EAA2E;IAC3E,6DAA6D;IAC7D,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC1E,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1C,yEAAyE;IACzE,4EAA4E;IAC5E,0EAA0E;IAC1E,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAChC,0EAA0E;IAC1E,2DAA2D;IAC3D,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE;IACpB,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;IAClB,2EAA2E;IAC3E,0EAA0E;IAC1E,4BAA4B;IAC5B,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;IACnD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;IAClD,4EAA4E;IAC5E,4EAA4E;IAC5E,0EAA0E;IAC1E,8BAA8B;IAC9B,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC3D,UAAU,EAAE,KAAK,CAAC,SAAS,EAAE;IAC7B,oEAAoE;IACpE,0EAA0E;IAC1E,0DAA0D;IAC1D,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACjC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CAC9B,CAAA;AAED,yFAAyF;AACzF,MAAM,CAAC,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA"}
|
|
1
|
+
{"version":3,"file":"audit-record-fields.js","sourceRoot":"","sources":["../../../src/audit/schema/audit-record-fields.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,0EAA0E;AAC1E,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,wBAAwB;AACxB,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,oEAAoE;AACpE,0EAA0E;AAC1E,2EAA2E;AAC3E,8DAA8D;AAE9D,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAA;AACvD,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAA;AAE5D,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,aAAa,EAAE;IACvD,4EAA4E;IAC5E,uEAAuE;IACvE,qEAAqE;IACrE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE;IACtB,0EAA0E;IAC1E,yEAAyE;IACzE,kEAAkE;IAClE,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClE,2EAA2E;IAC3E,6DAA6D;IAC7D,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC1E,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1C,yEAAyE;IACzE,4EAA4E;IAC5E,0EAA0E;IAC1E,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAChC,0EAA0E;IAC1E,2DAA2D;IAC3D,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE;IACpB,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;IAClB,0EAA0E;IAC1E,6EAA6E;IAC7E,sEAAsE;IACtE,6EAA6E;IAC7E,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACjC,2EAA2E;IAC3E,0EAA0E;IAC1E,4BAA4B;IAC5B,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;IACnD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;IAClD,4EAA4E;IAC5E,4EAA4E;IAC5E,0EAA0E;IAC1E,8BAA8B;IAC9B,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC3D,UAAU,EAAE,KAAK,CAAC,SAAS,EAAE;IAC7B,oEAAoE;IACpE,0EAA0E;IAC1E,0DAA0D;IAC1D,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACjC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CAC9B,CAAA;AAED,yFAAyF;AACzF,MAAM,CAAC,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/** One row's history: `audit.query({ entity, entityId })` is a range scan of this index. */
|
|
2
|
+
export declare const AUDIT_ENTITY_INDEX = "audit_record_entity_idx";
|
|
3
|
+
export declare const AUDIT_ENTITY_INDEX_SQL = "CREATE INDEX IF NOT EXISTS audit_record_entity_idx ON audit_record (tenant_id, entity, entity_id, occurred_at, id)";
|
|
1
4
|
export declare const auditRecord: import("../../data/domain/types.js").DefinedTable<{
|
|
2
5
|
id: import("../../data/domain/types.js").FieldDescriptor<import("../../data/domain/brand.js").Branded<string, "AuditRecordId">, {
|
|
3
6
|
defaultRandom: true;
|
|
@@ -21,6 +24,11 @@ export declare const auditRecord: import("../../data/domain/types.js").DefinedTa
|
|
|
21
24
|
}>;
|
|
22
25
|
entity: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
23
26
|
verb: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
27
|
+
entityId: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
28
|
+
nullable: true;
|
|
29
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
30
|
+
nullable: true;
|
|
31
|
+
}>;
|
|
24
32
|
before: import("../../data/domain/types.js").FieldDescriptor<import("zod/v4").JSONType, {
|
|
25
33
|
nullable: true;
|
|
26
34
|
}> & import("../../data/domain/field.js").FieldModifiers<import("zod/v4").JSONType, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-record.d.ts","sourceRoot":"","sources":["../../../src/audit/schema/audit-record.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"audit-record.d.ts","sourceRoot":"","sources":["../../../src/audit/schema/audit-record.ts"],"names":[],"mappings":"AAWA,4FAA4F;AAC5F,eAAO,MAAM,kBAAkB,4BAA4B,CAAA;AAC3D,eAAO,MAAM,sBAAsB,uHACiF,CAAA;AAEpH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAMtB,CAAA"}
|
|
@@ -5,9 +5,16 @@
|
|
|
5
5
|
// to inherit the TraceId/TraceStepId brands without emitting an FK — the
|
|
6
6
|
// audit partition is free to outlive its source trace partition.
|
|
7
7
|
import { define } from '../../data/domain/index.js';
|
|
8
|
+
import { index } from '../../data/db/idx/index.js';
|
|
8
9
|
import { auditRecordFields } from './audit-record-fields.js';
|
|
10
|
+
/** One row's history: `audit.query({ entity, entityId })` is a range scan of this index. */
|
|
11
|
+
export const AUDIT_ENTITY_INDEX = 'audit_record_entity_idx';
|
|
12
|
+
export const AUDIT_ENTITY_INDEX_SQL = `CREATE INDEX IF NOT EXISTS ${AUDIT_ENTITY_INDEX} ON audit_record (tenant_id, entity, entity_id, occurred_at, id)`;
|
|
9
13
|
export const auditRecord = define('audit_record', auditRecordFields, {
|
|
10
14
|
primaryKey: ['id', 'traceDay'],
|
|
11
15
|
partitionBy: { strategy: 'range', column: 'traceDay' },
|
|
16
|
+
indexes: (t) => ({
|
|
17
|
+
entity: index(AUDIT_ENTITY_INDEX).on(t['tenantId'], t['entity'], t['entityId'], t['occurredAt'], t['id']),
|
|
18
|
+
}),
|
|
12
19
|
});
|
|
13
20
|
//# sourceMappingURL=audit-record.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-record.js","sourceRoot":"","sources":["../../../src/audit/schema/audit-record.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,2EAA2E;AAC3E,6EAA6E;AAC7E,4EAA4E;AAC5E,yEAAyE;AACzE,iEAAiE;AAEjE,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAE5D,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,EAAE,iBAAiB,EAAE;IACnE,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC;IAC9B,WAAW,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE;
|
|
1
|
+
{"version":3,"file":"audit-record.js","sourceRoot":"","sources":["../../../src/audit/schema/audit-record.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,2EAA2E;AAC3E,6EAA6E;AAC7E,4EAA4E;AAC5E,yEAAyE;AACzE,iEAAiE;AAEjE,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAE5D,4FAA4F;AAC5F,MAAM,CAAC,MAAM,kBAAkB,GAAG,yBAAyB,CAAA;AAC3D,MAAM,CAAC,MAAM,sBAAsB,GACjC,8BAA8B,kBAAkB,kEAAkE,CAAA;AAEpH,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,EAAE,iBAAiB,EAAE;IACnE,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC;IAC9B,WAAW,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE;IACtD,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACf,MAAM,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;KAC1G,CAAC;CACH,CAAC,CAAA"}
|
|
@@ -13,6 +13,10 @@ export interface MultiOrgConfig {
|
|
|
13
13
|
readonly orgSelectToken?: {
|
|
14
14
|
readonly expiresIn?: string;
|
|
15
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* Membership table name. Default `pipework_user_orgs`, whose definition ships with the `orgs: {}`
|
|
18
|
+
* blueprint flag. A custom name means the app owns that table's DDL (org_id uuid, same columns).
|
|
19
|
+
*/
|
|
16
20
|
readonly table?: string;
|
|
17
21
|
readonly resolveOrgNames?: (db: DB, orgIds: string[]) => Promise<Map<string, string>>;
|
|
18
22
|
}
|
|
@@ -72,6 +76,9 @@ export interface MultiOrgSessions {
|
|
|
72
76
|
}): Promise<void>;
|
|
73
77
|
checkMembership(db: DB, userId: string, orgId: string): Promise<OrgMembership | null>;
|
|
74
78
|
}
|
|
75
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* Creates a multi-org session manager with org selection flow and membership management.
|
|
81
|
+
* The default table comes from blueprint `orgs: {}`; org ids must be uuids.
|
|
82
|
+
*/
|
|
76
83
|
export declare function createMultiOrgSessions(config: MultiOrgConfig): MultiOrgSessions;
|
|
77
84
|
//# sourceMappingURL=multi-org.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multi-org.d.ts","sourceRoot":"","sources":["../../../src/auth/auth/multi-org.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"multi-org.d.ts","sourceRoot":"","sources":["../../../src/auth/auth/multi-org.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,11 @@ import { parseExpiry } from './parse-expiry.js';
|
|
|
3
3
|
import { sql } from '../../data/db/sql.js';
|
|
4
4
|
import { ForbiddenError, UnauthorizedError, ConflictError, NotFoundError } from '../../core/errors/index.js';
|
|
5
5
|
import { assertValidIdentifier } from '../../data/db/identifiers.js';
|
|
6
|
-
|
|
6
|
+
import { assertUuid } from './uuid.js';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a multi-org session manager with org selection flow and membership management.
|
|
9
|
+
* The default table comes from blueprint `orgs: {}`; org ids must be uuids.
|
|
10
|
+
*/
|
|
7
11
|
export function createMultiOrgSessions(config) {
|
|
8
12
|
const tableName = config.table ?? 'pipework_user_orgs';
|
|
9
13
|
assertValidIdentifier(tableName, 'multi-org membership table');
|
|
@@ -54,6 +58,7 @@ export function createMultiOrgSessions(config) {
|
|
|
54
58
|
}
|
|
55
59
|
}
|
|
56
60
|
async function requireMembership(db, userId, orgId) {
|
|
61
|
+
assertUuid(orgId, 'orgId');
|
|
57
62
|
const rows = await db.execute(sql `SELECT 1 FROM ${t} WHERE user_id = ${userId} AND org_id = ${orgId}`);
|
|
58
63
|
if (rows.length === 0) {
|
|
59
64
|
throw new ForbiddenError('You are not a member of this organization.');
|
|
@@ -108,6 +113,7 @@ export function createMultiOrgSessions(config) {
|
|
|
108
113
|
return { orgs };
|
|
109
114
|
}
|
|
110
115
|
async function addMember(db, params) {
|
|
116
|
+
assertUuid(params.orgId, 'orgId');
|
|
111
117
|
const role = params.role ?? null;
|
|
112
118
|
const addedBy = params.addedBy ?? null;
|
|
113
119
|
const rows = await db.execute(sql `INSERT INTO ${t} (user_id, org_id, role, added_by)
|
|
@@ -120,6 +126,7 @@ export function createMultiOrgSessions(config) {
|
|
|
120
126
|
return { id: rows[0]['id'] };
|
|
121
127
|
}
|
|
122
128
|
async function removeMember(db, params) {
|
|
129
|
+
assertUuid(params.orgId, 'orgId');
|
|
123
130
|
const rows = await db.execute(sql `DELETE FROM ${t} WHERE user_id = ${params.userId} AND org_id = ${params.orgId} RETURNING id`);
|
|
124
131
|
if (rows.length === 0) {
|
|
125
132
|
throw new NotFoundError('Membership');
|
|
@@ -127,6 +134,7 @@ export function createMultiOrgSessions(config) {
|
|
|
127
134
|
await config.sessions.bumpVersion(db, params.userId);
|
|
128
135
|
}
|
|
129
136
|
async function checkMembershipFn(db, userId, orgId) {
|
|
137
|
+
assertUuid(orgId, 'orgId');
|
|
130
138
|
const rows = await db.execute(sql `SELECT id, org_id, role, joined_at FROM ${t} WHERE user_id = ${userId} AND org_id = ${orgId}`);
|
|
131
139
|
if (rows.length === 0)
|
|
132
140
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multi-org.js","sourceRoot":"","sources":["../../../src/auth/auth/multi-org.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAE1C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAC5G,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;
|
|
1
|
+
{"version":3,"file":"multi-org.js","sourceRoot":"","sources":["../../../src/auth/auth/multi-org.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export declare const AUTH_TABLE_NAMES: ReadonlySet<string>;
|
|
2
|
+
export declare const refreshTokens: import("../../data/domain/types.js").DefinedTable<{
|
|
3
|
+
id: import("../../data/domain/types.js").FieldDescriptor<string, {
|
|
4
|
+
defaultRandom: true;
|
|
5
|
+
hasDefault: true;
|
|
6
|
+
} & {
|
|
7
|
+
primaryKey: true;
|
|
8
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string, {
|
|
9
|
+
defaultRandom: true;
|
|
10
|
+
hasDefault: true;
|
|
11
|
+
} & {
|
|
12
|
+
primaryKey: true;
|
|
13
|
+
}>;
|
|
14
|
+
userId: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
15
|
+
tenantId: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
16
|
+
tokenHash: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
17
|
+
familyId: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
18
|
+
revokedAt: import("../../data/domain/types.js").FieldDescriptor<Date | null, {
|
|
19
|
+
nullable: true;
|
|
20
|
+
}> & import("../../data/domain/field.js").FieldModifiers<Date | null, {
|
|
21
|
+
nullable: true;
|
|
22
|
+
}>;
|
|
23
|
+
createdAt: import("../../data/domain/types.js").FieldDescriptor<Date, {
|
|
24
|
+
hasDefault: true;
|
|
25
|
+
}> & import("../../data/domain/field.js").FieldModifiers<Date, {
|
|
26
|
+
hasDefault: true;
|
|
27
|
+
}>;
|
|
28
|
+
expiresAt: import("../../data/domain/types.js").FieldDescriptor<Date, {}> & import("../../data/domain/field.js").FieldModifiers<Date, {}>;
|
|
29
|
+
}, "pipework_refresh_tokens">;
|
|
30
|
+
export declare const authVersions: import("../../data/domain/types.js").DefinedTable<{
|
|
31
|
+
userId: import("../../data/domain/types.js").FieldDescriptor<string, {
|
|
32
|
+
primaryKey: true;
|
|
33
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string, {
|
|
34
|
+
primaryKey: true;
|
|
35
|
+
}>;
|
|
36
|
+
version: import("../../data/domain/types.js").FieldDescriptor<number, {
|
|
37
|
+
hasDefault: true;
|
|
38
|
+
}> & import("../../data/domain/field.js").FieldModifiers<number, {
|
|
39
|
+
hasDefault: true;
|
|
40
|
+
}>;
|
|
41
|
+
updatedAt: import("../../data/domain/types.js").FieldDescriptor<Date, {
|
|
42
|
+
hasDefault: true;
|
|
43
|
+
}> & import("../../data/domain/field.js").FieldModifiers<Date, {
|
|
44
|
+
hasDefault: true;
|
|
45
|
+
}>;
|
|
46
|
+
}, "pipework_auth_versions">;
|
|
47
|
+
export declare const userOrgs: import("../../data/domain/types.js").DefinedTable<{
|
|
48
|
+
id: import("../../data/domain/types.js").FieldDescriptor<string, {
|
|
49
|
+
defaultRandom: true;
|
|
50
|
+
hasDefault: true;
|
|
51
|
+
} & {
|
|
52
|
+
primaryKey: true;
|
|
53
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string, {
|
|
54
|
+
defaultRandom: true;
|
|
55
|
+
hasDefault: true;
|
|
56
|
+
} & {
|
|
57
|
+
primaryKey: true;
|
|
58
|
+
}>;
|
|
59
|
+
userId: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
60
|
+
orgId: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
|
|
61
|
+
role: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
62
|
+
nullable: true;
|
|
63
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
64
|
+
nullable: true;
|
|
65
|
+
}>;
|
|
66
|
+
joinedAt: import("../../data/domain/types.js").FieldDescriptor<Date, {
|
|
67
|
+
hasDefault: true;
|
|
68
|
+
}> & import("../../data/domain/field.js").FieldModifiers<Date, {
|
|
69
|
+
hasDefault: true;
|
|
70
|
+
}>;
|
|
71
|
+
addedBy: import("../../data/domain/types.js").FieldDescriptor<string | null, {
|
|
72
|
+
nullable: true;
|
|
73
|
+
}> & import("../../data/domain/field.js").FieldModifiers<string | null, {
|
|
74
|
+
nullable: true;
|
|
75
|
+
}>;
|
|
76
|
+
}, "pipework_user_orgs">;
|
|
77
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/auth/auth/schema.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAE/C,CAAA;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAexB,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;4BAIvB,CAAA;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAanB,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Definitions for the tables behind `auth.createSessions` and
|
|
2
|
+
// `auth.createMultiOrg`. Enabled with `sessions: {}` / `orgs: {}` in the
|
|
3
|
+
// blueprint; `pipework generate` then emits them into the default database's
|
|
4
|
+
// migrations. Emitted as IF NOT EXISTS so apps that created these tables by
|
|
5
|
+
// hand from the former .sql files migrate cleanly.
|
|
6
|
+
//
|
|
7
|
+
// `user_id` is text everywhere: its format is the app's. `tenant_id` and
|
|
8
|
+
// `org_id` are uuid so they can be the tenant id, but deliberately NOT
|
|
9
|
+
// `.tenant()`: a refresh token is looked up by its hash before any tenant is
|
|
10
|
+
// known, and a user's org list is read across orgs at sign-in, so tenant RLS on
|
|
11
|
+
// either table would hide the rows the lookup needs.
|
|
12
|
+
//
|
|
13
|
+
// A custom `createMultiOrg({ table })` name is outside these definitions: the
|
|
14
|
+
// app owns that table's DDL.
|
|
15
|
+
import { define } from '../../data/domain/index.js';
|
|
16
|
+
import { field } from '../../data/domain/field.js';
|
|
17
|
+
import { sql } from '../../data/db/sql.js';
|
|
18
|
+
import { index, unique } from '../../data/db/idx/index.js';
|
|
19
|
+
export const AUTH_TABLE_NAMES = new Set([
|
|
20
|
+
'pipework_refresh_tokens', 'pipework_auth_versions', 'pipework_user_orgs',
|
|
21
|
+
]);
|
|
22
|
+
export const refreshTokens = define('pipework_refresh_tokens', {
|
|
23
|
+
id: field.uuid().defaultRandom().primaryKey(),
|
|
24
|
+
userId: field.text(),
|
|
25
|
+
tenantId: field.uuid(),
|
|
26
|
+
tokenHash: field.text(),
|
|
27
|
+
familyId: field.uuid(),
|
|
28
|
+
revokedAt: field.timestamp().nullable(),
|
|
29
|
+
createdAt: field.timestamp().default('now'),
|
|
30
|
+
expiresAt: field.timestamp(),
|
|
31
|
+
}, {
|
|
32
|
+
indexes: (t) => ({
|
|
33
|
+
byHash: index('idx_pipework_refresh_tokens_hash').on(t['tokenHash']),
|
|
34
|
+
byUser: index('idx_pipework_refresh_tokens_user').on(t['userId']).where(sql `revoked_at IS NULL`),
|
|
35
|
+
byFamily: index('idx_pipework_refresh_tokens_family').on(t['familyId']),
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
export const authVersions = define('pipework_auth_versions', {
|
|
39
|
+
userId: field.text().primaryKey(),
|
|
40
|
+
version: field.integer().default(1),
|
|
41
|
+
updatedAt: field.timestamp().default('now'),
|
|
42
|
+
});
|
|
43
|
+
export const userOrgs = define('pipework_user_orgs', {
|
|
44
|
+
id: field.uuid().defaultRandom().primaryKey(),
|
|
45
|
+
userId: field.text(),
|
|
46
|
+
orgId: field.uuid(),
|
|
47
|
+
role: field.text().nullable(),
|
|
48
|
+
joinedAt: field.timestamp().default('now'),
|
|
49
|
+
addedBy: field.text().nullable(),
|
|
50
|
+
}, {
|
|
51
|
+
indexes: (t) => ({
|
|
52
|
+
membership: unique('pipework_user_orgs_user_id_org_id_key').on(t['userId'], t['orgId']),
|
|
53
|
+
byUser: index('idx_pipework_user_orgs_user').on(t['userId']),
|
|
54
|
+
byOrg: index('idx_pipework_user_orgs_org').on(t['orgId']),
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/auth/auth/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -65,6 +65,9 @@ export interface Sessions {
|
|
|
65
65
|
revokeHttp(response: HttpResponse, db: DB, request: Pick<HttpRequest, 'headers'>): Promise<void>;
|
|
66
66
|
revokeAllHttp(response: HttpResponse, db: DB, userId: string): Promise<void>;
|
|
67
67
|
}
|
|
68
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* Creates a Sessions manager with JWT access/refresh tokens, rotation, reuse detection, and cookie helpers.
|
|
70
|
+
* Its tables come from blueprint `sessions: {}`; `tenantId` must be a uuid.
|
|
71
|
+
*/
|
|
69
72
|
export declare function createSessions(config: SessionConfig): Sessions;
|
|
70
73
|
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../src/auth/auth/sessions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../src/auth/auth/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,8 +2,12 @@ import { SignJWT, jwtVerify, importPKCS8, importSPKI } from 'jose';
|
|
|
2
2
|
import { parseExpiry } from './parse-expiry.js';
|
|
3
3
|
import { sql } from '../../data/db/sql.js';
|
|
4
4
|
import { UnauthorizedError } from '../../core/errors/index.js';
|
|
5
|
+
import { assertUuid } from './uuid.js';
|
|
5
6
|
import { resolveCookieConfig, buildSetCookieHeader, buildClearCookieHeader, parseCookieHeader } from './cookie.js';
|
|
6
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Creates a Sessions manager with JWT access/refresh tokens, rotation, reuse detection, and cookie helpers.
|
|
9
|
+
* Its tables come from blueprint `sessions: {}`; `tenantId` must be a uuid.
|
|
10
|
+
*/
|
|
7
11
|
export function createSessions(config) {
|
|
8
12
|
const environment = config.environment ?? 'production';
|
|
9
13
|
if (environment === 'production') {
|
|
@@ -36,6 +40,7 @@ export function createSessions(config) {
|
|
|
36
40
|
return row['version'];
|
|
37
41
|
}
|
|
38
42
|
async function issueTokens(db, user, familyId = crypto.randomUUID()) {
|
|
43
|
+
assertUuid(user.tenantId, 'tenantId');
|
|
39
44
|
const key = await getPrivateKey();
|
|
40
45
|
const version = config.versionCheck ? await getOrCreateVersion(db, user.id) : 1;
|
|
41
46
|
const expiresInSeconds = parseExpiry(config.accessToken.expiresIn);
|