@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.
Files changed (309) hide show
  1. package/CHANGELOG.md +434 -0
  2. package/README.md +137 -41
  3. package/dist/adapters/execution/restate.d.ts +7 -2
  4. package/dist/adapters/execution/restate.js +40 -10
  5. package/dist/adapters/replication/pgoutput.d.ts +21 -0
  6. package/dist/adapters/replication/pgoutput.js +170 -0
  7. package/dist/adapters/streams/s2.js +37 -20
  8. package/dist/admin-openapi.json +570 -0
  9. package/dist/api/a2a/card.d.ts +15 -0
  10. package/dist/api/a2a/card.js +24 -0
  11. package/dist/api/a2a/endpoint.d.ts +8 -0
  12. package/dist/api/a2a/endpoint.js +81 -0
  13. package/dist/api/a2a/protocol.d.ts +144 -0
  14. package/dist/api/a2a/protocol.js +188 -0
  15. package/dist/api/a2a/routes.d.ts +19 -0
  16. package/dist/api/a2a/routes.js +289 -0
  17. package/dist/api/a2a/tasks.d.ts +50 -0
  18. package/dist/api/a2a/tasks.js +186 -0
  19. package/dist/api/ag-ui/endpoint.d.ts +8 -0
  20. package/dist/api/ag-ui/endpoint.js +126 -0
  21. package/dist/api/ag-ui/history.d.ts +7 -0
  22. package/dist/api/ag-ui/history.js +60 -0
  23. package/dist/api/ag-ui/routes.d.ts +32 -0
  24. package/dist/api/ag-ui/routes.js +305 -0
  25. package/dist/api/ag-ui/session-id.d.ts +1 -0
  26. package/dist/api/ag-ui/session-id.js +12 -0
  27. package/dist/api/ag-ui/sse.d.ts +9 -0
  28. package/dist/api/ag-ui/sse.js +7 -0
  29. package/dist/api/ag-ui/translate.d.ts +38 -0
  30. package/dist/api/ag-ui/translate.js +222 -0
  31. package/dist/api/components.d.ts +8065 -0
  32. package/dist/api/components.js +82 -0
  33. package/dist/api/gate/keys.d.ts +14 -0
  34. package/dist/api/gate/keys.js +59 -0
  35. package/dist/api/gate/routes.d.ts +34 -0
  36. package/dist/api/gate/routes.js +235 -0
  37. package/dist/api/http/app.d.ts +18 -0
  38. package/dist/api/http/app.js +58 -0
  39. package/dist/api/http/body.d.ts +4 -0
  40. package/dist/api/http/body.js +37 -0
  41. package/dist/api/http/define.d.ts +39 -0
  42. package/dist/api/http/define.js +122 -0
  43. package/dist/api/http/respond.d.ts +9 -0
  44. package/dist/api/http/respond.js +44 -0
  45. package/dist/api/http/routes/access.d.ts +24 -0
  46. package/dist/api/http/routes/access.js +266 -0
  47. package/dist/api/http/routes/actions.d.ts +8 -0
  48. package/dist/api/http/routes/actions.js +76 -0
  49. package/dist/api/http/routes/endpoints.d.ts +7 -0
  50. package/dist/api/http/routes/endpoints.js +100 -0
  51. package/dist/api/http/routes/sessions.d.ts +3 -0
  52. package/dist/api/http/routes/sessions.js +205 -0
  53. package/dist/api/http/routes/tenant.d.ts +11 -0
  54. package/dist/api/http/routes/tenant.js +244 -0
  55. package/dist/api/http/routes/vaults.d.ts +8 -0
  56. package/dist/api/http/routes/vaults.js +167 -0
  57. package/dist/api/openapi.d.ts +19 -0
  58. package/dist/api/openapi.js +137 -0
  59. package/dist/api/route.d.ts +12 -0
  60. package/dist/api/route.js +4 -0
  61. package/dist/core/bearer.d.ts +8 -0
  62. package/dist/core/bearer.js +11 -0
  63. package/dist/core/flow-host.d.ts +7 -15
  64. package/dist/core/flow-host.js +16 -41
  65. package/dist/core/sandbox-routes.d.ts +12 -7
  66. package/dist/core/sandbox-routes.js +24 -25
  67. package/dist/execution/memory.d.ts +8 -5
  68. package/dist/execution/memory.js +33 -13
  69. package/dist/execution/types.d.ts +38 -6
  70. package/dist/execution/types.js +12 -3
  71. package/dist/gates/contract.d.ts +51 -0
  72. package/dist/gates/contract.js +37 -0
  73. package/dist/gates/handler.d.ts +21 -0
  74. package/dist/gates/handler.js +55 -0
  75. package/dist/gates/http-client.d.ts +12 -0
  76. package/dist/gates/http-client.js +160 -0
  77. package/dist/gates/in-process.d.ts +32 -0
  78. package/dist/gates/in-process.js +42 -0
  79. package/dist/gates/inflight.d.ts +39 -0
  80. package/dist/gates/inflight.js +70 -0
  81. package/dist/gates/mcp-handler.d.ts +35 -0
  82. package/dist/gates/mcp-handler.js +142 -0
  83. package/dist/gates/meter.d.ts +24 -0
  84. package/dist/gates/meter.js +165 -0
  85. package/dist/gates/model-gate.d.ts +45 -0
  86. package/dist/gates/model-gate.js +1 -0
  87. package/dist/gates/tenant-vaults.d.ts +64 -0
  88. package/dist/gates/tenant-vaults.js +94 -0
  89. package/dist/gates/tool-calls.d.ts +51 -0
  90. package/dist/gates/tool-calls.js +64 -0
  91. package/dist/gates/tool-client.d.ts +12 -0
  92. package/dist/gates/tool-client.js +201 -0
  93. package/dist/gates/tool-contract.d.ts +116 -0
  94. package/dist/gates/tool-contract.js +64 -0
  95. package/dist/gates/tool-gate.d.ts +45 -0
  96. package/dist/gates/tool-gate.js +10 -0
  97. package/dist/host/admin-api.d.ts +23 -0
  98. package/dist/host/admin-api.js +74 -0
  99. package/dist/host/app.d.ts +34 -0
  100. package/dist/host/app.js +181 -0
  101. package/dist/host/config-for.d.ts +3 -1
  102. package/dist/host/config-for.js +3 -2
  103. package/dist/host/config.d.ts +11 -0
  104. package/dist/host/cors.d.ts +27 -0
  105. package/dist/host/cors.js +64 -0
  106. package/dist/host/create-host.d.ts +36 -8
  107. package/dist/host/create-host.js +161 -330
  108. package/dist/host/execution.d.ts +20 -18
  109. package/dist/host/execution.js +2 -2
  110. package/dist/host/gates.d.ts +58 -0
  111. package/dist/host/gates.js +127 -0
  112. package/dist/host/http.d.ts +20 -4
  113. package/dist/host/http.js +81 -23
  114. package/dist/host/index.d.ts +1 -1
  115. package/dist/host/main.js +189 -58
  116. package/dist/host/stack-config.d.ts +91 -19
  117. package/dist/host/stack-config.js +246 -17
  118. package/dist/infra/database.d.ts +2 -2
  119. package/dist/infra/execution.d.ts +5 -5
  120. package/dist/infra/execution.js +8 -6
  121. package/dist/infra/index.d.ts +1 -1
  122. package/dist/infra/workers.d.ts +17 -17
  123. package/dist/infra/workers.js +9 -9
  124. package/dist/keys/client.d.ts +9 -0
  125. package/dist/keys/client.js +70 -0
  126. package/dist/keys/contract.d.ts +24 -0
  127. package/dist/keys/contract.js +12 -0
  128. package/dist/keys/keys.d.ts +41 -0
  129. package/dist/keys/keys.js +50 -0
  130. package/dist/mcp/connect.d.ts +43 -3
  131. package/dist/mcp/connect.js +12 -5
  132. package/dist/mcp/pool.d.ts +39 -3
  133. package/dist/mcp/pool.js +74 -11
  134. package/dist/model/catalog.d.ts +2 -10
  135. package/dist/model/classify.d.ts +13 -0
  136. package/dist/model/classify.js +61 -0
  137. package/dist/model/models.d.ts +10 -1
  138. package/dist/model/models.js +14 -6
  139. package/dist/model/pi-model.d.ts +17 -2
  140. package/dist/model/pi-model.js +366 -222
  141. package/dist/openapi.json +25889 -0
  142. package/dist/record/append.d.ts +51 -0
  143. package/dist/record/append.js +20 -0
  144. package/dist/record/envelope.d.ts +19 -0
  145. package/dist/record/envelope.js +49 -0
  146. package/dist/record/index.d.ts +11 -0
  147. package/dist/record/index.js +11 -0
  148. package/dist/sandbox/manager.d.ts +13 -1
  149. package/dist/sandbox/manager.js +8 -11
  150. package/dist/sandbox/resolve.d.ts +33 -0
  151. package/dist/sandbox/resolve.js +81 -0
  152. package/dist/sandbox/session-sandbox.d.ts +11 -0
  153. package/dist/sandbox/session-sandbox.js +51 -0
  154. package/dist/sandbox/share.d.ts +14 -2
  155. package/dist/sandbox/share.js +33 -3
  156. package/dist/sandbox/tenant-config.d.ts +37 -0
  157. package/dist/sandbox/tenant-config.js +51 -0
  158. package/dist/sandbox/tools.d.ts +7 -9
  159. package/dist/sandbox/tools.js +11 -3
  160. package/dist/sandbox/types.d.ts +8 -2
  161. package/dist/store/postgres/connect.d.ts +25 -9
  162. package/dist/store/postgres/connect.js +27 -10
  163. package/dist/store/postgres/db.d.ts +16 -0
  164. package/dist/store/postgres/db.js +28 -0
  165. package/dist/store/postgres/drizzle/0000_foundation.sql +22 -0
  166. package/dist/store/postgres/drizzle/0001_baseline.sql +255 -0
  167. package/dist/store/postgres/drizzle/0002_stream_relay.sql +4 -0
  168. package/dist/store/postgres/drizzle/0003_tool_crossings.sql +9 -0
  169. package/dist/store/postgres/drizzle/meta/_journal.json +34 -0
  170. package/dist/store/postgres/migrate.d.ts +68 -0
  171. package/dist/store/postgres/migrate.js +183 -0
  172. package/dist/store/postgres/record-writer.d.ts +4 -0
  173. package/dist/store/postgres/record-writer.js +34 -0
  174. package/dist/store/postgres/record.d.ts +5 -0
  175. package/dist/store/postgres/record.js +60 -0
  176. package/dist/store/postgres/schema.d.ts +3096 -0
  177. package/dist/store/postgres/schema.js +363 -0
  178. package/dist/store/postgres/store.d.ts +2 -4
  179. package/dist/store/postgres/store.js +590 -434
  180. package/dist/store/postgres/tenant.d.ts +56 -0
  181. package/dist/store/postgres/tenant.js +154 -0
  182. package/dist/store/types.d.ts +183 -132
  183. package/dist/store/types.js +0 -1
  184. package/dist/streams/basin.d.ts +18 -1
  185. package/dist/streams/basin.js +34 -2
  186. package/dist/streams/control.d.ts +18 -0
  187. package/dist/streams/control.js +33 -0
  188. package/dist/streams/memory.d.ts +3 -1
  189. package/dist/streams/memory.js +14 -8
  190. package/dist/streams/relay/core.d.ts +35 -0
  191. package/dist/streams/relay/core.js +366 -0
  192. package/dist/streams/relay/types.d.ts +78 -0
  193. package/dist/streams/relay/types.js +8 -0
  194. package/dist/streams/types.d.ts +71 -36
  195. package/dist/streams/types.js +18 -53
  196. package/dist/tenant/access-policy.d.ts +30 -0
  197. package/dist/tenant/access-policy.js +52 -0
  198. package/dist/tenant/actions.d.ts +10 -149
  199. package/dist/tenant/actions.js +5 -167
  200. package/dist/tenant/advance.d.ts +7 -2
  201. package/dist/tenant/advance.js +125 -14
  202. package/dist/tenant/auth.d.ts +19 -17
  203. package/dist/tenant/auth.js +90 -93
  204. package/dist/tenant/browser.d.ts +15 -0
  205. package/dist/tenant/browser.js +39 -0
  206. package/dist/tenant/cause.d.ts +25 -0
  207. package/dist/tenant/cause.js +45 -0
  208. package/dist/tenant/commands.d.ts +18 -2
  209. package/dist/tenant/commands.js +111 -115
  210. package/dist/tenant/context.d.ts +101 -21
  211. package/dist/tenant/context.js +14 -10
  212. package/dist/tenant/delivery-token.d.ts +41 -0
  213. package/dist/tenant/delivery-token.js +104 -0
  214. package/dist/tenant/delivery.d.ts +62 -0
  215. package/dist/tenant/delivery.js +481 -0
  216. package/dist/tenant/effects.d.ts +20 -1
  217. package/dist/tenant/effects.js +159 -42
  218. package/dist/tenant/endpoints.d.ts +67 -0
  219. package/dist/tenant/endpoints.js +90 -0
  220. package/dist/tenant/ephemeral.d.ts +22 -7
  221. package/dist/tenant/ephemeral.js +83 -125
  222. package/dist/tenant/history.d.ts +64 -0
  223. package/dist/tenant/history.js +120 -0
  224. package/dist/tenant/http.d.ts +8 -9
  225. package/dist/tenant/http.js +13 -27
  226. package/dist/tenant/jwt.d.ts +16 -0
  227. package/dist/tenant/jwt.js +50 -0
  228. package/dist/tenant/model-setting.d.ts +2 -2
  229. package/dist/tenant/module.d.ts +17 -28
  230. package/dist/tenant/module.js +133 -279
  231. package/dist/tenant/outbound.d.ts +44 -0
  232. package/dist/tenant/outbound.js +127 -0
  233. package/dist/tenant/paths.d.ts +11 -16
  234. package/dist/tenant/paths.js +24 -68
  235. package/dist/tenant/pool.d.ts +1 -3
  236. package/dist/tenant/pool.js +1 -19
  237. package/dist/tenant/principals.d.ts +23 -11
  238. package/dist/tenant/principals.js +61 -49
  239. package/dist/tenant/reset.d.ts +0 -4
  240. package/dist/tenant/reset.js +0 -5
  241. package/dist/tenant/runtime.d.ts +28 -20
  242. package/dist/tenant/runtime.js +95 -64
  243. package/dist/tenant/scheduler.d.ts +10 -3
  244. package/dist/tenant/scheduler.js +9 -5
  245. package/dist/tenant/session-streams.d.ts +127 -0
  246. package/dist/tenant/session-streams.js +404 -0
  247. package/dist/tenant/sessions.d.ts +28 -4
  248. package/dist/tenant/sessions.js +118 -24
  249. package/dist/tenant/signing-keys.d.ts +55 -0
  250. package/dist/tenant/signing-keys.js +172 -0
  251. package/dist/tenant/slim.d.ts +8 -0
  252. package/dist/tenant/slim.js +21 -0
  253. package/dist/tenant/status.d.ts +3 -3
  254. package/dist/tenant/status.js +20 -13
  255. package/dist/tenant/store-pg.d.ts +9 -6
  256. package/dist/tenant/store-pg.js +60 -125
  257. package/dist/tenant/streams.d.ts +62 -85
  258. package/dist/tenant/streams.js +143 -226
  259. package/dist/tenant/subject-limits.d.ts +16 -0
  260. package/dist/tenant/subject-limits.js +45 -0
  261. package/dist/tenant/sweep.d.ts +1 -10
  262. package/dist/tenant/sweep.js +29 -69
  263. package/dist/tenant/tokens.d.ts +14 -0
  264. package/dist/tenant/tokens.js +180 -0
  265. package/dist/tenant/transcript.d.ts +48 -5
  266. package/dist/tenant/transcript.js +58 -1
  267. package/dist/tenant/types.d.ts +69 -98
  268. package/dist/tenant/types.js +4 -15
  269. package/dist/tenant/worker.d.ts +3 -1
  270. package/dist/tenant/worker.js +13 -7
  271. package/dist/vault/host-model.d.ts +31 -0
  272. package/dist/vault/host-model.js +57 -0
  273. package/dist/vault/service.d.ts +44 -17
  274. package/dist/vault/service.js +126 -121
  275. package/dist/version.d.ts +1 -1
  276. package/dist/version.js +1 -1
  277. package/package.json +25 -9
  278. package/dist/core/executors.d.ts +0 -44
  279. package/dist/core/executors.js +0 -95
  280. package/dist/store/memory.d.ts +0 -57
  281. package/dist/store/memory.js +0 -645
  282. package/dist/store/postgres/migrations/001_initial.d.ts +0 -27
  283. package/dist/store/postgres/migrations/001_initial.js +0 -196
  284. package/dist/store/postgres/migrations/002_session_owner.d.ts +0 -6
  285. package/dist/store/postgres/migrations/002_session_owner.js +0 -13
  286. package/dist/store/postgres/migrations/index.d.ts +0 -49
  287. package/dist/store/postgres/migrations/index.js +0 -76
  288. package/dist/store/postgres/names.d.ts +0 -11
  289. package/dist/store/postgres/names.js +0 -42
  290. package/dist/store/postgres/tenants.d.ts +0 -90
  291. package/dist/store/postgres/tenants.js +0 -214
  292. package/dist/streams/relay.d.ts +0 -37
  293. package/dist/streams/relay.js +0 -254
  294. package/dist/tenant/envelope.d.ts +0 -7
  295. package/dist/tenant/envelope.js +0 -22
  296. package/dist/tenant/live.d.ts +0 -92
  297. package/dist/tenant/live.js +0 -290
  298. package/dist/tenant/quarantine-error.d.ts +0 -6
  299. package/dist/tenant/quarantine-error.js +0 -9
  300. package/dist/tenant/quarantine.d.ts +0 -27
  301. package/dist/tenant/quarantine.js +0 -72
  302. package/dist/tenant/routes-tenant.d.ts +0 -12
  303. package/dist/tenant/routes-tenant.js +0 -137
  304. package/dist/tenant/routes.d.ts +0 -9
  305. package/dist/tenant/routes.js +0 -151
  306. package/dist/tenant/store-memory.d.ts +0 -16
  307. package/dist/tenant/store-memory.js +0 -111
  308. /package/dist/{store → record}/cursor.d.ts +0 -0
  309. /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
+ }