@nylorun/runtime 0.13.0-beta → 0.15.0-beta
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 +434 -0
- package/README.md +137 -41
- package/dist/adapters/execution/restate.d.ts +7 -2
- package/dist/adapters/execution/restate.js +40 -10
- package/dist/adapters/replication/pgoutput.d.ts +21 -0
- package/dist/adapters/replication/pgoutput.js +170 -0
- package/dist/adapters/streams/s2.js +37 -20
- package/dist/admin-openapi.json +570 -0
- package/dist/api/a2a/card.d.ts +15 -0
- package/dist/api/a2a/card.js +24 -0
- package/dist/api/a2a/endpoint.d.ts +8 -0
- package/dist/api/a2a/endpoint.js +81 -0
- package/dist/api/a2a/protocol.d.ts +144 -0
- package/dist/api/a2a/protocol.js +188 -0
- package/dist/api/a2a/routes.d.ts +19 -0
- package/dist/api/a2a/routes.js +289 -0
- package/dist/api/a2a/tasks.d.ts +50 -0
- package/dist/api/a2a/tasks.js +186 -0
- package/dist/api/ag-ui/endpoint.d.ts +8 -0
- package/dist/api/ag-ui/endpoint.js +126 -0
- package/dist/api/ag-ui/history.d.ts +7 -0
- package/dist/api/ag-ui/history.js +60 -0
- package/dist/api/ag-ui/routes.d.ts +32 -0
- package/dist/api/ag-ui/routes.js +305 -0
- package/dist/api/ag-ui/session-id.d.ts +1 -0
- package/dist/api/ag-ui/session-id.js +12 -0
- package/dist/api/ag-ui/sse.d.ts +9 -0
- package/dist/api/ag-ui/sse.js +7 -0
- package/dist/api/ag-ui/translate.d.ts +38 -0
- package/dist/api/ag-ui/translate.js +222 -0
- package/dist/api/components.d.ts +8065 -0
- package/dist/api/components.js +82 -0
- package/dist/api/gate/keys.d.ts +14 -0
- package/dist/api/gate/keys.js +59 -0
- package/dist/api/gate/routes.d.ts +34 -0
- package/dist/api/gate/routes.js +235 -0
- package/dist/api/http/app.d.ts +18 -0
- package/dist/api/http/app.js +58 -0
- package/dist/api/http/body.d.ts +4 -0
- package/dist/api/http/body.js +37 -0
- package/dist/api/http/define.d.ts +39 -0
- package/dist/api/http/define.js +122 -0
- package/dist/api/http/respond.d.ts +9 -0
- package/dist/api/http/respond.js +44 -0
- package/dist/api/http/routes/access.d.ts +24 -0
- package/dist/api/http/routes/access.js +266 -0
- package/dist/api/http/routes/actions.d.ts +8 -0
- package/dist/api/http/routes/actions.js +76 -0
- package/dist/api/http/routes/endpoints.d.ts +7 -0
- package/dist/api/http/routes/endpoints.js +100 -0
- package/dist/api/http/routes/sessions.d.ts +3 -0
- package/dist/api/http/routes/sessions.js +205 -0
- package/dist/api/http/routes/tenant.d.ts +11 -0
- package/dist/api/http/routes/tenant.js +244 -0
- package/dist/api/http/routes/vaults.d.ts +8 -0
- package/dist/api/http/routes/vaults.js +167 -0
- package/dist/api/openapi.d.ts +19 -0
- package/dist/api/openapi.js +137 -0
- package/dist/api/route.d.ts +12 -0
- package/dist/api/route.js +4 -0
- package/dist/core/bearer.d.ts +8 -0
- package/dist/core/bearer.js +11 -0
- package/dist/core/flow-host.d.ts +7 -15
- package/dist/core/flow-host.js +16 -41
- package/dist/core/sandbox-routes.d.ts +12 -7
- package/dist/core/sandbox-routes.js +24 -25
- package/dist/execution/memory.d.ts +8 -5
- package/dist/execution/memory.js +33 -13
- package/dist/execution/types.d.ts +38 -6
- package/dist/execution/types.js +12 -3
- package/dist/gates/contract.d.ts +51 -0
- package/dist/gates/contract.js +37 -0
- package/dist/gates/handler.d.ts +21 -0
- package/dist/gates/handler.js +55 -0
- package/dist/gates/http-client.d.ts +12 -0
- package/dist/gates/http-client.js +160 -0
- package/dist/gates/in-process.d.ts +32 -0
- package/dist/gates/in-process.js +42 -0
- package/dist/gates/inflight.d.ts +39 -0
- package/dist/gates/inflight.js +70 -0
- package/dist/gates/mcp-handler.d.ts +35 -0
- package/dist/gates/mcp-handler.js +142 -0
- package/dist/gates/meter.d.ts +24 -0
- package/dist/gates/meter.js +165 -0
- package/dist/gates/model-gate.d.ts +45 -0
- package/dist/gates/model-gate.js +1 -0
- package/dist/gates/tenant-vaults.d.ts +64 -0
- package/dist/gates/tenant-vaults.js +94 -0
- package/dist/gates/tool-calls.d.ts +51 -0
- package/dist/gates/tool-calls.js +64 -0
- package/dist/gates/tool-client.d.ts +12 -0
- package/dist/gates/tool-client.js +201 -0
- package/dist/gates/tool-contract.d.ts +116 -0
- package/dist/gates/tool-contract.js +64 -0
- package/dist/gates/tool-gate.d.ts +45 -0
- package/dist/gates/tool-gate.js +10 -0
- package/dist/host/admin-api.d.ts +23 -0
- package/dist/host/admin-api.js +74 -0
- package/dist/host/app.d.ts +34 -0
- package/dist/host/app.js +181 -0
- package/dist/host/config-for.d.ts +3 -1
- package/dist/host/config-for.js +3 -2
- package/dist/host/config.d.ts +11 -0
- package/dist/host/cors.d.ts +27 -0
- package/dist/host/cors.js +64 -0
- package/dist/host/create-host.d.ts +36 -8
- package/dist/host/create-host.js +161 -330
- package/dist/host/execution.d.ts +20 -18
- package/dist/host/execution.js +2 -2
- package/dist/host/gates.d.ts +58 -0
- package/dist/host/gates.js +127 -0
- package/dist/host/http.d.ts +20 -4
- package/dist/host/http.js +81 -23
- package/dist/host/index.d.ts +1 -1
- package/dist/host/main.js +189 -58
- package/dist/host/stack-config.d.ts +91 -19
- package/dist/host/stack-config.js +246 -17
- package/dist/infra/database.d.ts +2 -2
- package/dist/infra/execution.d.ts +5 -5
- package/dist/infra/execution.js +8 -6
- package/dist/infra/index.d.ts +1 -1
- package/dist/infra/workers.d.ts +17 -17
- package/dist/infra/workers.js +9 -9
- package/dist/keys/client.d.ts +9 -0
- package/dist/keys/client.js +70 -0
- package/dist/keys/contract.d.ts +24 -0
- package/dist/keys/contract.js +12 -0
- package/dist/keys/keys.d.ts +41 -0
- package/dist/keys/keys.js +50 -0
- package/dist/mcp/connect.d.ts +43 -3
- package/dist/mcp/connect.js +12 -5
- package/dist/mcp/pool.d.ts +39 -3
- package/dist/mcp/pool.js +74 -11
- package/dist/model/catalog.d.ts +2 -10
- package/dist/model/classify.d.ts +13 -0
- package/dist/model/classify.js +61 -0
- package/dist/model/models.d.ts +10 -1
- package/dist/model/models.js +14 -6
- package/dist/model/pi-model.d.ts +17 -2
- package/dist/model/pi-model.js +366 -222
- package/dist/openapi.json +25889 -0
- package/dist/record/append.d.ts +51 -0
- package/dist/record/append.js +20 -0
- package/dist/record/envelope.d.ts +19 -0
- package/dist/record/envelope.js +49 -0
- package/dist/record/index.d.ts +11 -0
- package/dist/record/index.js +11 -0
- package/dist/sandbox/manager.d.ts +13 -1
- package/dist/sandbox/manager.js +8 -11
- package/dist/sandbox/resolve.d.ts +33 -0
- package/dist/sandbox/resolve.js +81 -0
- package/dist/sandbox/session-sandbox.d.ts +11 -0
- package/dist/sandbox/session-sandbox.js +51 -0
- package/dist/sandbox/share.d.ts +14 -2
- package/dist/sandbox/share.js +33 -3
- package/dist/sandbox/tenant-config.d.ts +37 -0
- package/dist/sandbox/tenant-config.js +51 -0
- package/dist/sandbox/tools.d.ts +7 -9
- package/dist/sandbox/tools.js +11 -3
- package/dist/sandbox/types.d.ts +8 -2
- package/dist/store/postgres/connect.d.ts +25 -9
- package/dist/store/postgres/connect.js +27 -10
- package/dist/store/postgres/db.d.ts +16 -0
- package/dist/store/postgres/db.js +28 -0
- package/dist/store/postgres/drizzle/0000_foundation.sql +22 -0
- package/dist/store/postgres/drizzle/0001_baseline.sql +255 -0
- package/dist/store/postgres/drizzle/0002_stream_relay.sql +4 -0
- package/dist/store/postgres/drizzle/0003_tool_crossings.sql +9 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +34 -0
- package/dist/store/postgres/migrate.d.ts +68 -0
- package/dist/store/postgres/migrate.js +183 -0
- package/dist/store/postgres/record-writer.d.ts +4 -0
- package/dist/store/postgres/record-writer.js +34 -0
- package/dist/store/postgres/record.d.ts +5 -0
- package/dist/store/postgres/record.js +60 -0
- package/dist/store/postgres/schema.d.ts +3096 -0
- package/dist/store/postgres/schema.js +363 -0
- package/dist/store/postgres/store.d.ts +2 -4
- package/dist/store/postgres/store.js +590 -434
- package/dist/store/postgres/tenant.d.ts +56 -0
- package/dist/store/postgres/tenant.js +154 -0
- package/dist/store/types.d.ts +183 -132
- package/dist/store/types.js +0 -1
- package/dist/streams/basin.d.ts +18 -1
- package/dist/streams/basin.js +34 -2
- package/dist/streams/control.d.ts +18 -0
- package/dist/streams/control.js +33 -0
- package/dist/streams/memory.d.ts +3 -1
- package/dist/streams/memory.js +14 -8
- package/dist/streams/relay/core.d.ts +35 -0
- package/dist/streams/relay/core.js +366 -0
- package/dist/streams/relay/types.d.ts +78 -0
- package/dist/streams/relay/types.js +8 -0
- package/dist/streams/types.d.ts +71 -36
- package/dist/streams/types.js +18 -53
- package/dist/tenant/access-policy.d.ts +30 -0
- package/dist/tenant/access-policy.js +52 -0
- package/dist/tenant/actions.d.ts +10 -149
- package/dist/tenant/actions.js +5 -167
- package/dist/tenant/advance.d.ts +7 -2
- package/dist/tenant/advance.js +125 -14
- package/dist/tenant/auth.d.ts +19 -17
- package/dist/tenant/auth.js +90 -93
- package/dist/tenant/browser.d.ts +15 -0
- package/dist/tenant/browser.js +39 -0
- package/dist/tenant/cause.d.ts +25 -0
- package/dist/tenant/cause.js +45 -0
- package/dist/tenant/commands.d.ts +18 -2
- package/dist/tenant/commands.js +111 -115
- package/dist/tenant/context.d.ts +101 -21
- package/dist/tenant/context.js +14 -10
- package/dist/tenant/delivery-token.d.ts +41 -0
- package/dist/tenant/delivery-token.js +104 -0
- package/dist/tenant/delivery.d.ts +62 -0
- package/dist/tenant/delivery.js +481 -0
- package/dist/tenant/effects.d.ts +20 -1
- package/dist/tenant/effects.js +159 -42
- package/dist/tenant/endpoints.d.ts +67 -0
- package/dist/tenant/endpoints.js +90 -0
- package/dist/tenant/ephemeral.d.ts +22 -7
- package/dist/tenant/ephemeral.js +83 -125
- package/dist/tenant/history.d.ts +64 -0
- package/dist/tenant/history.js +120 -0
- package/dist/tenant/http.d.ts +8 -9
- package/dist/tenant/http.js +13 -27
- package/dist/tenant/jwt.d.ts +16 -0
- package/dist/tenant/jwt.js +50 -0
- package/dist/tenant/model-setting.d.ts +2 -2
- package/dist/tenant/module.d.ts +17 -28
- package/dist/tenant/module.js +133 -279
- package/dist/tenant/outbound.d.ts +44 -0
- package/dist/tenant/outbound.js +127 -0
- package/dist/tenant/paths.d.ts +11 -16
- package/dist/tenant/paths.js +24 -68
- package/dist/tenant/pool.d.ts +1 -3
- package/dist/tenant/pool.js +1 -19
- package/dist/tenant/principals.d.ts +23 -11
- package/dist/tenant/principals.js +61 -49
- package/dist/tenant/reset.d.ts +0 -4
- package/dist/tenant/reset.js +0 -5
- package/dist/tenant/runtime.d.ts +28 -20
- package/dist/tenant/runtime.js +95 -64
- package/dist/tenant/scheduler.d.ts +10 -3
- package/dist/tenant/scheduler.js +9 -5
- package/dist/tenant/session-streams.d.ts +127 -0
- package/dist/tenant/session-streams.js +404 -0
- package/dist/tenant/sessions.d.ts +28 -4
- package/dist/tenant/sessions.js +118 -24
- package/dist/tenant/signing-keys.d.ts +55 -0
- package/dist/tenant/signing-keys.js +172 -0
- package/dist/tenant/slim.d.ts +8 -0
- package/dist/tenant/slim.js +21 -0
- package/dist/tenant/status.d.ts +3 -3
- package/dist/tenant/status.js +20 -13
- package/dist/tenant/store-pg.d.ts +9 -6
- package/dist/tenant/store-pg.js +60 -125
- package/dist/tenant/streams.d.ts +62 -85
- package/dist/tenant/streams.js +143 -226
- package/dist/tenant/subject-limits.d.ts +16 -0
- package/dist/tenant/subject-limits.js +45 -0
- package/dist/tenant/sweep.d.ts +1 -10
- package/dist/tenant/sweep.js +29 -69
- package/dist/tenant/tokens.d.ts +14 -0
- package/dist/tenant/tokens.js +180 -0
- package/dist/tenant/transcript.d.ts +48 -5
- package/dist/tenant/transcript.js +58 -1
- package/dist/tenant/types.d.ts +69 -98
- package/dist/tenant/types.js +4 -15
- package/dist/tenant/worker.d.ts +3 -1
- package/dist/tenant/worker.js +13 -7
- package/dist/vault/host-model.d.ts +31 -0
- package/dist/vault/host-model.js +57 -0
- package/dist/vault/service.d.ts +44 -17
- package/dist/vault/service.js +126 -121
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +25 -9
- package/dist/core/executors.d.ts +0 -44
- package/dist/core/executors.js +0 -95
- package/dist/store/memory.d.ts +0 -57
- package/dist/store/memory.js +0 -645
- package/dist/store/postgres/migrations/001_initial.d.ts +0 -27
- package/dist/store/postgres/migrations/001_initial.js +0 -196
- package/dist/store/postgres/migrations/002_session_owner.d.ts +0 -6
- package/dist/store/postgres/migrations/002_session_owner.js +0 -13
- package/dist/store/postgres/migrations/index.d.ts +0 -49
- package/dist/store/postgres/migrations/index.js +0 -76
- package/dist/store/postgres/names.d.ts +0 -11
- package/dist/store/postgres/names.js +0 -42
- package/dist/store/postgres/tenants.d.ts +0 -90
- package/dist/store/postgres/tenants.js +0 -214
- package/dist/streams/relay.d.ts +0 -37
- package/dist/streams/relay.js +0 -254
- package/dist/tenant/envelope.d.ts +0 -7
- package/dist/tenant/envelope.js +0 -22
- package/dist/tenant/live.d.ts +0 -92
- package/dist/tenant/live.js +0 -290
- package/dist/tenant/quarantine-error.d.ts +0 -6
- package/dist/tenant/quarantine-error.js +0 -9
- package/dist/tenant/quarantine.d.ts +0 -27
- package/dist/tenant/quarantine.js +0 -72
- package/dist/tenant/routes-tenant.d.ts +0 -12
- package/dist/tenant/routes-tenant.js +0 -137
- package/dist/tenant/routes.d.ts +0 -9
- package/dist/tenant/routes.js +0 -151
- package/dist/tenant/store-memory.d.ts +0 -16
- package/dist/tenant/store-memory.js +0 -111
- /package/dist/{store → record}/cursor.d.ts +0 -0
- /package/dist/{store → record}/cursor.js +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Sql } from "postgres";
|
|
2
|
+
import { type TenantEnvelope } from "@nylorun/core/contracts";
|
|
3
|
+
import type { SessionStore } from "../types.js";
|
|
4
|
+
import { type Queryable } from "./db.js";
|
|
5
|
+
import { type Migration } from "./migrate.js";
|
|
6
|
+
/** An application principal the Tenant is created with (or given later). */
|
|
7
|
+
export interface InitialPrincipal {
|
|
8
|
+
id: string;
|
|
9
|
+
/** SHA-256 hex of the principal's key. */
|
|
10
|
+
credentialHash: string;
|
|
11
|
+
}
|
|
12
|
+
/** Who the Tenant is when the database holds none yet. */
|
|
13
|
+
export interface TenantCreation {
|
|
14
|
+
/** Default: a new id (`newTenantId()`). Ignored when the Tenant exists. */
|
|
15
|
+
tenantId?: string;
|
|
16
|
+
/** Ignored when the Tenant exists. */
|
|
17
|
+
name: string;
|
|
18
|
+
/**
|
|
19
|
+
* The principals the Tenant must have, given its id (derived keys depend on it). Created
|
|
20
|
+
* with the Tenant; on later opens, the missing ones are added.
|
|
21
|
+
*/
|
|
22
|
+
principals?(tenantId: string): readonly InitialPrincipal[];
|
|
23
|
+
}
|
|
24
|
+
export interface OpenTenantDatabaseOptions {
|
|
25
|
+
/** The pool on the Tenant's database. The store never ends it. */
|
|
26
|
+
sql: Sql;
|
|
27
|
+
create: TenantCreation;
|
|
28
|
+
/** Clock for the envelope and the principals' `createdAt`, and the store's. */
|
|
29
|
+
now?: () => Date;
|
|
30
|
+
/** Passed to the store (post-commit failures). */
|
|
31
|
+
onError?: (error: unknown) => void;
|
|
32
|
+
/** Tests only: the migrations this Runtime knows. Default: the shipped ones. */
|
|
33
|
+
migrations?: readonly Migration[];
|
|
34
|
+
}
|
|
35
|
+
export interface OpenedTenantDatabase {
|
|
36
|
+
store: SessionStore;
|
|
37
|
+
envelope: TenantEnvelope;
|
|
38
|
+
/** This call created the Tenant. */
|
|
39
|
+
created: boolean;
|
|
40
|
+
/** The schema versions (applied migrations) before and after. */
|
|
41
|
+
migrated: {
|
|
42
|
+
from: number;
|
|
43
|
+
to: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Migrates the database, creates its Tenant when it has none, and opens its Session Store.
|
|
48
|
+
* Throws a `TenantOpenError` with the cause when the Tenant cannot be opened (see above).
|
|
49
|
+
*/
|
|
50
|
+
export declare function openTenantDatabase(options: OpenTenantDatabaseOptions): Promise<OpenedTenantDatabase>;
|
|
51
|
+
/**
|
|
52
|
+
* The Tenant's envelope, or undefined when the database holds no Tenant yet (no `nylorun`
|
|
53
|
+
* schema, or an empty `tenant` table). Throws `envelope-invalid` when the row does not parse.
|
|
54
|
+
* Takes the pool or a Drizzle database or transaction on it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function readTenantEnvelope(q: Sql | Queryable): Promise<TenantEnvelope | undefined>;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Tenant a database holds (tenancy.md §1, §4; session-store.md §2). One database is one
|
|
3
|
+
* Tenant: its state in the schema `nylorun`, its record in `nylorun_streams`, and its
|
|
4
|
+
* envelope in the one row of `nylorun.tenant`. There is no catalog.
|
|
5
|
+
*
|
|
6
|
+
* `openTenantDatabase` runs in one transaction, under the database's migration lock
|
|
7
|
+
* (`migrate.ts`), so several processes starting at once migrate and create once:
|
|
8
|
+
*
|
|
9
|
+
* 1. Refuse an old layout (`database-layout-old`): `tenant_<id>` schemas or a record keyed by
|
|
10
|
+
* Tenant (a Runtime from before one Tenant per installation), or the `schema_version`
|
|
11
|
+
* tables of a pre-release build of it. It is never touched: this release starts fresh.
|
|
12
|
+
* 2. Apply the missing migrations (`migrate.ts`). A database with migrations this Runtime
|
|
13
|
+
* does not know is `schema-too-new`; a migration Postgres rejects is `migration-failed`.
|
|
14
|
+
* 3. When `nylorun.tenant` is empty, create the Tenant: its row (id, name, created time) and
|
|
15
|
+
* its first principals. A database whose row is gone but that holds a Tenant's data
|
|
16
|
+
* (principals, sessions, agents, vaults, keys) is `envelope-invalid`, never given a new
|
|
17
|
+
* Tenant. Principals given later that the Tenant does not have yet are added (a derived
|
|
18
|
+
* principal configured after the first start); existing ones are kept.
|
|
19
|
+
* 4. Read the envelope back (`envelope-invalid` when it does not parse), and open the store.
|
|
20
|
+
*
|
|
21
|
+
* A lost connection or an unavailable server says nothing about the Tenant: it is thrown as
|
|
22
|
+
* it is, never as a cause.
|
|
23
|
+
*/
|
|
24
|
+
import { sql } from "drizzle-orm";
|
|
25
|
+
import { isTenantId, newTenantId } from "@nylorun/core/compatibility";
|
|
26
|
+
import { TenantEnvelopeSchema, } from "@nylorun/core/contracts";
|
|
27
|
+
import { openError, TenantOpenError } from "../../tenant/cause.js";
|
|
28
|
+
import { database, driverError } from "./db.js";
|
|
29
|
+
import { applyMigrations, assertCurrentLayout, isStatementError, lockMigrations, shippedMigrations, } from "./migrate.js";
|
|
30
|
+
import { definitions, principals, sessions, signingKeys, TENANT_SCHEMA, tenant, vaults, } from "./schema.js";
|
|
31
|
+
import { createPostgresSessionStore } from "./store.js";
|
|
32
|
+
/**
|
|
33
|
+
* Migrates the database, creates its Tenant when it has none, and opens its Session Store.
|
|
34
|
+
* Throws a `TenantOpenError` with the cause when the Tenant cannot be opened (see above).
|
|
35
|
+
*/
|
|
36
|
+
export async function openTenantDatabase(options) {
|
|
37
|
+
const { sql: pool } = options;
|
|
38
|
+
const db = database(pool);
|
|
39
|
+
const now = options.now ?? (() => new Date());
|
|
40
|
+
const migrations = options.migrations ?? shippedMigrations();
|
|
41
|
+
let outcome;
|
|
42
|
+
try {
|
|
43
|
+
outcome = await db.transaction(async (tx) => {
|
|
44
|
+
await lockMigrations(tx);
|
|
45
|
+
await assertCurrentLayout(tx);
|
|
46
|
+
const migrated = await applyMigrations(tx, migrations);
|
|
47
|
+
const created = await ensureTenant(tx, options.create, migrated, now);
|
|
48
|
+
return { created, migrated };
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (thrown) {
|
|
52
|
+
const error = driverError(thrown);
|
|
53
|
+
if (!(error instanceof TenantOpenError) && !isStatementError(error))
|
|
54
|
+
throw error;
|
|
55
|
+
// A statement of the bootstrap itself (the layout check, the Tenant row) was rejected.
|
|
56
|
+
const failure = error instanceof TenantOpenError
|
|
57
|
+
? error
|
|
58
|
+
: openError("open-failed", `Opening the Tenant database failed: ${error.message}`);
|
|
59
|
+
// Name the Tenant when its row reads (a database newer than this Runtime, say).
|
|
60
|
+
if (failure.code !== "database-layout-old")
|
|
61
|
+
failure.envelope ??= await readTenantEnvelope(db).catch(() => undefined);
|
|
62
|
+
throw failure;
|
|
63
|
+
}
|
|
64
|
+
const envelope = await readTenantEnvelope(db);
|
|
65
|
+
if (!envelope)
|
|
66
|
+
throw openError("envelope-invalid", "The Tenant row is missing");
|
|
67
|
+
const store = createPostgresSessionStore({
|
|
68
|
+
sql: pool,
|
|
69
|
+
tenantId: envelope.id,
|
|
70
|
+
schemaVersion: migrations.length,
|
|
71
|
+
...(options.now ? { now: options.now } : {}),
|
|
72
|
+
...(options.onError ? { onError: options.onError } : {}),
|
|
73
|
+
});
|
|
74
|
+
return { store, envelope, ...outcome };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The Tenant's envelope, or undefined when the database holds no Tenant yet (no `nylorun`
|
|
78
|
+
* schema, or an empty `tenant` table). Throws `envelope-invalid` when the row does not parse.
|
|
79
|
+
* Takes the pool or a Drizzle database or transaction on it.
|
|
80
|
+
*/
|
|
81
|
+
export async function readTenantEnvelope(q) {
|
|
82
|
+
const db = typeof q === "function" ? database(q) : q;
|
|
83
|
+
try {
|
|
84
|
+
const [table] = await db.execute(sql `
|
|
85
|
+
SELECT to_regclass(${`${TENANT_SCHEMA}.tenant`}) IS NOT NULL AS exists`);
|
|
86
|
+
if (!table?.exists)
|
|
87
|
+
return undefined;
|
|
88
|
+
const [row] = await db
|
|
89
|
+
.select({
|
|
90
|
+
id: tenant.id,
|
|
91
|
+
name: tenant.name,
|
|
92
|
+
createdAt: tenant.createdAt,
|
|
93
|
+
updatedAt: tenant.updatedAt,
|
|
94
|
+
schemaVersion: tenant.schemaVersion,
|
|
95
|
+
})
|
|
96
|
+
.from(tenant);
|
|
97
|
+
if (!row)
|
|
98
|
+
return undefined;
|
|
99
|
+
const parsed = TenantEnvelopeSchema.safeParse(row);
|
|
100
|
+
if (!parsed.success || !isTenantId(parsed.data.id))
|
|
101
|
+
throw openError("envelope-invalid", "The Tenant row is not valid");
|
|
102
|
+
return parsed.data;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
throw driverError(error);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Creates the Tenant when there is none, and adds the principals it is missing. Records the
|
|
110
|
+
* schema version on the Tenant row when this transaction migrated.
|
|
111
|
+
*/
|
|
112
|
+
async function ensureTenant(tx, create, migrated, now) {
|
|
113
|
+
const [existing] = await tx.select({ id: tenant.id }).from(tenant);
|
|
114
|
+
const createdAt = now().toISOString();
|
|
115
|
+
let tenantId = existing?.id;
|
|
116
|
+
if (tenantId === undefined) {
|
|
117
|
+
const [data] = await tx.execute(sql `
|
|
118
|
+
SELECT EXISTS (SELECT 1 FROM ${principals})
|
|
119
|
+
OR EXISTS (SELECT 1 FROM ${sessions})
|
|
120
|
+
OR EXISTS (SELECT 1 FROM ${definitions})
|
|
121
|
+
OR EXISTS (SELECT 1 FROM ${vaults})
|
|
122
|
+
OR EXISTS (SELECT 1 FROM ${signingKeys}) AS held`);
|
|
123
|
+
if (data?.held)
|
|
124
|
+
throw openError("envelope-invalid", "The Tenant row is missing from a database that holds a Tenant's data: restore it from a backup");
|
|
125
|
+
tenantId = create.tenantId ?? newTenantId();
|
|
126
|
+
if (!isTenantId(tenantId))
|
|
127
|
+
throw new Error(`Invalid Tenant id: ${tenantId}`);
|
|
128
|
+
if (!create.name)
|
|
129
|
+
throw new Error("A Tenant needs a name");
|
|
130
|
+
await tx.insert(tenant).values({
|
|
131
|
+
id: tenantId,
|
|
132
|
+
name: create.name,
|
|
133
|
+
createdAt,
|
|
134
|
+
updatedAt: createdAt,
|
|
135
|
+
schemaVersion: migrated.to,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
else if (migrated.from !== migrated.to) {
|
|
139
|
+
await tx.update(tenant).set({ schemaVersion: migrated.to });
|
|
140
|
+
}
|
|
141
|
+
for (const principal of create.principals?.(tenantId) ?? [])
|
|
142
|
+
// A principal with this id or this key already exists: it is kept as it is.
|
|
143
|
+
await tx
|
|
144
|
+
.insert(principals)
|
|
145
|
+
.values({
|
|
146
|
+
id: principal.id,
|
|
147
|
+
role: "application",
|
|
148
|
+
tokenHash: principal.credentialHash,
|
|
149
|
+
idempotencyKey: null,
|
|
150
|
+
createdAt,
|
|
151
|
+
})
|
|
152
|
+
.onConflictDoNothing();
|
|
153
|
+
return existing === undefined;
|
|
154
|
+
}
|