@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
package/dist/vault/service.js
CHANGED
|
@@ -34,13 +34,12 @@
|
|
|
34
34
|
* listHostProviders(): Promise<{ providers: HostModelProviderInfo[] }>
|
|
35
35
|
* putHostModel(body: PutHostModelRequest): Promise<HostModelView>
|
|
36
36
|
* selectHostModel(body: SelectHostModelRequest): Promise<HostModelView>
|
|
37
|
-
* readHostModel(): Promise<HostModelSecret | undefined>
|
|
38
|
-
* updateHostCredential(credential): Promise<void>
|
|
39
|
-
*
|
|
40
|
-
* // Rejected caller audit: opens its own transaction.
|
|
41
|
-
* reject(route: string): Promise<void>
|
|
42
37
|
* ```
|
|
43
38
|
*
|
|
39
|
+
* Reading the host model's secret and writing back a refreshed one are `HostModelVault`'s
|
|
40
|
+
* (`vault/host-model.ts`), which only the Model Gate uses: this service seals the host model's
|
|
41
|
+
* credential but never reads it back.
|
|
42
|
+
*
|
|
44
43
|
* ## Transactions and I/O
|
|
45
44
|
*
|
|
46
45
|
* - No network I/O runs inside a transaction. The KEK getter may touch the
|
|
@@ -67,16 +66,21 @@ import { VaultError } from "./error.js";
|
|
|
67
66
|
import { hostModelCatalog } from "../model/catalog.js";
|
|
68
67
|
import { normalizeVaultUrl } from "./url.js";
|
|
69
68
|
const REFRESH_SKEW_MS = 60_000;
|
|
70
|
-
const
|
|
69
|
+
const REFRESH_TIMEOUT_MS = 30_000;
|
|
70
|
+
export const HOST_VAULT_ID = "host";
|
|
71
71
|
const HOST_MODEL_ID = "host-model";
|
|
72
72
|
export class VaultService {
|
|
73
73
|
store;
|
|
74
74
|
kek;
|
|
75
75
|
fetchImpl;
|
|
76
|
+
refreshTimeoutMs;
|
|
77
|
+
/** Refreshes in progress by credential id: concurrent uses share one. */
|
|
78
|
+
refreshing = new Map();
|
|
76
79
|
constructor(options) {
|
|
77
80
|
this.store = options.store;
|
|
78
81
|
this.kek = options.kek;
|
|
79
82
|
this.fetchImpl = options.fetch;
|
|
83
|
+
this.refreshTimeoutMs = options.refreshTimeoutMs ?? REFRESH_TIMEOUT_MS;
|
|
80
84
|
}
|
|
81
85
|
// --- administration --------------------------------------------------------
|
|
82
86
|
async createVault(body) {
|
|
@@ -338,7 +342,7 @@ export class VaultService {
|
|
|
338
342
|
};
|
|
339
343
|
}
|
|
340
344
|
if (row.type === "oauth" && dueForRefresh(row.expiresAt)) {
|
|
341
|
-
const refreshed = await this.
|
|
345
|
+
const refreshed = await this.refreshShared(kek, row, payload, input.sessionId, url);
|
|
342
346
|
if (refreshed.status === "refused")
|
|
343
347
|
return refreshed;
|
|
344
348
|
payload = refreshed.payload;
|
|
@@ -373,9 +377,9 @@ export class VaultService {
|
|
|
373
377
|
}
|
|
374
378
|
async listHostProviders() {
|
|
375
379
|
return this.store.tx(async (t) => {
|
|
376
|
-
const active = await
|
|
380
|
+
const active = await activeProviderId(t);
|
|
377
381
|
const catalog = new Map(hostModelCatalog().providers.map((provider) => [provider.id, provider.name]));
|
|
378
|
-
const providers = (await
|
|
382
|
+
const providers = (await hostModelRows(t)).map((row) => {
|
|
379
383
|
const binding = modelBinding(row);
|
|
380
384
|
return {
|
|
381
385
|
id: binding.provider,
|
|
@@ -386,6 +390,7 @@ export class VaultService {
|
|
|
386
390
|
model: binding.model,
|
|
387
391
|
authType: binding.authType,
|
|
388
392
|
...(binding.baseUrl ? { baseUrl: binding.baseUrl } : {}),
|
|
393
|
+
...(binding.settings ? { settings: binding.settings } : {}),
|
|
389
394
|
lastUpdated: row.rotatedAt ?? row.createdAt,
|
|
390
395
|
active: binding.provider === active,
|
|
391
396
|
};
|
|
@@ -412,6 +417,7 @@ export class VaultService {
|
|
|
412
417
|
provider: body.provider,
|
|
413
418
|
model: body.model,
|
|
414
419
|
baseUrl: body.baseUrl,
|
|
420
|
+
settings: body.settings,
|
|
415
421
|
authType: body.auth.type,
|
|
416
422
|
payload,
|
|
417
423
|
});
|
|
@@ -430,7 +436,7 @@ export class VaultService {
|
|
|
430
436
|
const kek = this.kek();
|
|
431
437
|
return this.store.tx((t) => this.replay(t, `host-model-select:${body.idempotencyKey}`, body, async () => {
|
|
432
438
|
this.validateHostModel(body);
|
|
433
|
-
const row = await
|
|
439
|
+
const row = await hostCredentialRowFor(t, body.provider);
|
|
434
440
|
if (!row)
|
|
435
441
|
throw new VaultError(404, "Model provider is not configured");
|
|
436
442
|
const binding = modelBinding(row);
|
|
@@ -442,6 +448,8 @@ export class VaultService {
|
|
|
442
448
|
provider: body.provider,
|
|
443
449
|
model: body.model,
|
|
444
450
|
baseUrl: body.baseUrl,
|
|
451
|
+
// Selecting a model keeps the endpoint's settings.
|
|
452
|
+
settings: binding.settings,
|
|
445
453
|
authType: binding.authType,
|
|
446
454
|
payload,
|
|
447
455
|
});
|
|
@@ -456,61 +464,47 @@ export class VaultService {
|
|
|
456
464
|
return this.hostModelView(t);
|
|
457
465
|
}));
|
|
458
466
|
}
|
|
459
|
-
/** Reads the active host model secret. Decrypts after the read commits. */
|
|
460
|
-
async readHostModel() {
|
|
461
|
-
const row = await this.store.tx((t) => this.activeHostCredentialRow(t));
|
|
462
|
-
if (!row)
|
|
463
|
-
return undefined;
|
|
464
|
-
const binding = modelBinding(row);
|
|
465
|
-
const payload = readHostPayload(this.kek(), row, binding);
|
|
466
|
-
const credential = binding.authType === "oauth"
|
|
467
|
-
? { type: "oauth", ...payload.oauth }
|
|
468
|
-
: {
|
|
469
|
-
type: "api_key",
|
|
470
|
-
key: payload.apiKey,
|
|
471
|
-
...(payload.env ? { env: payload.env } : {}),
|
|
472
|
-
};
|
|
473
|
-
return {
|
|
474
|
-
provider: binding.provider,
|
|
475
|
-
model: binding.model,
|
|
476
|
-
...(binding.baseUrl ? { baseUrl: binding.baseUrl } : {}),
|
|
477
|
-
authType: binding.authType,
|
|
478
|
-
credential,
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
async updateHostCredential(credential) {
|
|
482
|
-
const kek = this.kek();
|
|
483
|
-
await this.store.tx(async (t) => {
|
|
484
|
-
const row = await this.activeHostCredentialRow(t);
|
|
485
|
-
if (!row)
|
|
486
|
-
throw new VaultError(404, "Model provider is not configured");
|
|
487
|
-
const binding = modelBinding(row);
|
|
488
|
-
const payload = credential.type === "oauth"
|
|
489
|
-
? { oauth: credential }
|
|
490
|
-
: {
|
|
491
|
-
apiKey: credential.key,
|
|
492
|
-
...(credential.env ? { env: credential.env } : {}),
|
|
493
|
-
};
|
|
494
|
-
const sealed = encryptSecret(kek, hostModelAad(binding.provider, binding.model), Buffer.from(JSON.stringify(payload), "utf8"));
|
|
495
|
-
await t.updateCredential(HOST_VAULT_ID, row.id, {
|
|
496
|
-
type: "model",
|
|
497
|
-
bindingJson: JSON.stringify({ ...binding, authType: credential.type }),
|
|
498
|
-
...sealed,
|
|
499
|
-
rotatedAt: new Date().toISOString(),
|
|
500
|
-
});
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
// --- rejected callers ---------------------------------------------------------
|
|
504
|
-
async reject(route) {
|
|
505
|
-
await this.store.tx((t) => this.audit(t, {
|
|
506
|
-
actor: "executor",
|
|
507
|
-
action: "reject",
|
|
508
|
-
target: route,
|
|
509
|
-
outcome: "rejected",
|
|
510
|
-
}));
|
|
511
|
-
}
|
|
512
467
|
// --- internals -----------------------------------------------------------------
|
|
513
468
|
/** Calls the token endpoint outside any transaction, then stores the result. */
|
|
469
|
+
/**
|
|
470
|
+
* Refreshes an OAuth grant once for every concurrent use in this process. A rotating refresh
|
|
471
|
+
* token is valid once, so two refreshes with it would fail the second, or make the provider
|
|
472
|
+
* revoke the grant.
|
|
473
|
+
*/
|
|
474
|
+
refreshShared(kek, row, payload, sessionId, url) {
|
|
475
|
+
let pending = this.refreshing.get(row.id);
|
|
476
|
+
if (!pending) {
|
|
477
|
+
pending = this.refreshLatest(kek, row, payload, sessionId, url).finally(() => this.refreshing.delete(row.id));
|
|
478
|
+
this.refreshing.set(row.id, pending);
|
|
479
|
+
}
|
|
480
|
+
return pending;
|
|
481
|
+
}
|
|
482
|
+
/** Uses a token another process refreshed instead of refreshing again, before and after. */
|
|
483
|
+
async refreshLatest(kek, row, payload, sessionId, url) {
|
|
484
|
+
const before = await this.rotatedSince(kek, row);
|
|
485
|
+
if (before)
|
|
486
|
+
return { status: "ok", payload: before };
|
|
487
|
+
const refreshed = await this.refresh(kek, row, payload, sessionId, url);
|
|
488
|
+
if (refreshed.status === "ok")
|
|
489
|
+
return refreshed;
|
|
490
|
+
// The loser of a race with another process fails with the spent refresh token.
|
|
491
|
+
const after = await this.rotatedSince(kek, row);
|
|
492
|
+
return after ? { status: "ok", payload: after } : refreshed;
|
|
493
|
+
}
|
|
494
|
+
/** The credential's payload when it was rotated after `row` was read and is not due. */
|
|
495
|
+
async rotatedSince(kek, row) {
|
|
496
|
+
const current = await this.store.tx((t) => t.getCredential(row.id));
|
|
497
|
+
if (!current || current.vaultId !== row.vaultId || !isUserCredential(current))
|
|
498
|
+
return undefined;
|
|
499
|
+
if (current.rotatedAt === row.rotatedAt || dueForRefresh(current.expiresAt))
|
|
500
|
+
return undefined;
|
|
501
|
+
try {
|
|
502
|
+
return readPayload(kek, current);
|
|
503
|
+
}
|
|
504
|
+
catch {
|
|
505
|
+
return undefined;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
514
508
|
async refresh(kek, row, payload, sessionId, url) {
|
|
515
509
|
const failRefresh = async () => {
|
|
516
510
|
await this.store.tx((t) => this.audit(t, {
|
|
@@ -557,6 +551,7 @@ export class VaultService {
|
|
|
557
551
|
headers,
|
|
558
552
|
body: body.toString(),
|
|
559
553
|
redirect: "error",
|
|
554
|
+
signal: AbortSignal.timeout(this.refreshTimeoutMs),
|
|
560
555
|
});
|
|
561
556
|
if (!response.ok)
|
|
562
557
|
return failRefresh();
|
|
@@ -640,6 +635,8 @@ export class VaultService {
|
|
|
640
635
|
});
|
|
641
636
|
}
|
|
642
637
|
validateHostModel(body) {
|
|
638
|
+
if (body.settings && body.provider !== "custom")
|
|
639
|
+
throw new VaultError(400, "Model settings (context window, output limit, reasoning, compat) apply only to a custom provider.");
|
|
643
640
|
if (body.provider === "custom") {
|
|
644
641
|
if (!body.baseUrl)
|
|
645
642
|
throw new VaultError(400, "A base URL is required for a custom provider.");
|
|
@@ -673,6 +670,9 @@ export class VaultService {
|
|
|
673
670
|
provider: input.provider,
|
|
674
671
|
model: input.model,
|
|
675
672
|
...(input.baseUrl ? { baseUrl: input.baseUrl } : {}),
|
|
673
|
+
...(input.settings && Object.keys(input.settings).length
|
|
674
|
+
? { settings: input.settings }
|
|
675
|
+
: {}),
|
|
676
676
|
authType: input.authType,
|
|
677
677
|
}),
|
|
678
678
|
expiresAt: null,
|
|
@@ -682,7 +682,7 @@ export class VaultService {
|
|
|
682
682
|
});
|
|
683
683
|
}
|
|
684
684
|
async hostModelView(t) {
|
|
685
|
-
const row = await
|
|
685
|
+
const row = await activeHostCredentialRow(t);
|
|
686
686
|
if (!row)
|
|
687
687
|
return { configured: false };
|
|
688
688
|
const binding = modelBinding(row);
|
|
@@ -692,67 +692,15 @@ export class VaultService {
|
|
|
692
692
|
model: binding.model,
|
|
693
693
|
authType: binding.authType,
|
|
694
694
|
...(binding.baseUrl ? { baseUrl: binding.baseUrl } : {}),
|
|
695
|
+
...(binding.settings ? { settings: binding.settings } : {}),
|
|
695
696
|
};
|
|
696
697
|
}
|
|
697
|
-
async hostModelRows(t) {
|
|
698
|
-
return (await t.credentialsForVault(HOST_VAULT_ID, { type: "model" })).filter((row) => {
|
|
699
|
-
try {
|
|
700
|
-
modelBinding(row);
|
|
701
|
-
return true;
|
|
702
|
-
}
|
|
703
|
-
catch {
|
|
704
|
-
return false;
|
|
705
|
-
}
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
async hostCredentialRowFor(t, provider) {
|
|
709
|
-
const preferred = hostModelCredentialId(provider);
|
|
710
|
-
const rows = await this.hostModelRows(t);
|
|
711
|
-
return (rows.find((row) => row.id === preferred) ??
|
|
712
|
-
rows.find((row) => modelBinding(row).provider === provider));
|
|
713
|
-
}
|
|
714
|
-
async activeHostCredentialRow(t) {
|
|
715
|
-
const active = await this.activeProviderId(t);
|
|
716
|
-
if (!active)
|
|
717
|
-
return undefined;
|
|
718
|
-
return this.hostCredentialRowFor(t, active);
|
|
719
|
-
}
|
|
720
|
-
async activeProviderId(t) {
|
|
721
|
-
const vault = await t.getVault(HOST_VAULT_ID);
|
|
722
|
-
if (vault?.metadataJson) {
|
|
723
|
-
let activeProvider;
|
|
724
|
-
try {
|
|
725
|
-
activeProvider = JSON.parse(vault.metadataJson).activeProvider;
|
|
726
|
-
}
|
|
727
|
-
catch {
|
|
728
|
-
/* Fall through to the only configured provider. */
|
|
729
|
-
}
|
|
730
|
-
if (typeof activeProvider === "string" && activeProvider) {
|
|
731
|
-
try {
|
|
732
|
-
if (await this.hostCredentialRowFor(t, activeProvider))
|
|
733
|
-
return activeProvider;
|
|
734
|
-
}
|
|
735
|
-
catch {
|
|
736
|
-
/* An invalid provider id falls through, as before. */
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
const rows = await this.hostModelRows(t);
|
|
741
|
-
if (rows.length === 0)
|
|
742
|
-
return undefined;
|
|
743
|
-
if (rows.length === 1)
|
|
744
|
-
return modelBinding(rows[0]).provider;
|
|
745
|
-
const legacy = rows.find((row) => row.id === HOST_MODEL_ID);
|
|
746
|
-
if (legacy)
|
|
747
|
-
return modelBinding(legacy).provider;
|
|
748
|
-
return modelBinding(rows[0]).provider;
|
|
749
|
-
}
|
|
750
698
|
async setActiveProvider(t, provider) {
|
|
751
699
|
await this.ensureHostVault(t);
|
|
752
700
|
await t.updateVaultMetadata(HOST_VAULT_ID, JSON.stringify({ activeProvider: provider }));
|
|
753
701
|
}
|
|
754
702
|
async deleteHostProviderRows(t, provider) {
|
|
755
|
-
const ids = (await
|
|
703
|
+
const ids = (await hostModelRows(t))
|
|
756
704
|
.filter((row) => modelBinding(row).provider === provider)
|
|
757
705
|
.map((row) => row.id);
|
|
758
706
|
ids.push(hostModelCredentialId(provider));
|
|
@@ -818,7 +766,64 @@ function readPayload(kek, row) {
|
|
|
818
766
|
plaintext.fill(0);
|
|
819
767
|
}
|
|
820
768
|
}
|
|
821
|
-
|
|
769
|
+
/** The host vault's model credential rows that parse. */
|
|
770
|
+
export async function hostModelRows(t) {
|
|
771
|
+
return (await t.credentialsForVault(HOST_VAULT_ID, { type: "model" })).filter((row) => {
|
|
772
|
+
try {
|
|
773
|
+
modelBinding(row);
|
|
774
|
+
return true;
|
|
775
|
+
}
|
|
776
|
+
catch {
|
|
777
|
+
return false;
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
/** The host model credential of `provider`. */
|
|
782
|
+
export async function hostCredentialRowFor(t, provider) {
|
|
783
|
+
const preferred = hostModelCredentialId(provider);
|
|
784
|
+
const rows = await hostModelRows(t);
|
|
785
|
+
return (rows.find((row) => row.id === preferred) ??
|
|
786
|
+
rows.find((row) => modelBinding(row).provider === provider));
|
|
787
|
+
}
|
|
788
|
+
/** The provider the host model selection names, or the only (or legacy) one configured. */
|
|
789
|
+
export async function activeProviderId(t) {
|
|
790
|
+
const vault = await t.getVault(HOST_VAULT_ID);
|
|
791
|
+
if (vault?.metadataJson) {
|
|
792
|
+
let activeProvider;
|
|
793
|
+
try {
|
|
794
|
+
activeProvider = JSON.parse(vault.metadataJson).activeProvider;
|
|
795
|
+
}
|
|
796
|
+
catch {
|
|
797
|
+
/* Fall through to the only configured provider. */
|
|
798
|
+
}
|
|
799
|
+
if (typeof activeProvider === "string" && activeProvider) {
|
|
800
|
+
try {
|
|
801
|
+
if (await hostCredentialRowFor(t, activeProvider))
|
|
802
|
+
return activeProvider;
|
|
803
|
+
}
|
|
804
|
+
catch {
|
|
805
|
+
/* An invalid provider id falls through, as before. */
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
const rows = await hostModelRows(t);
|
|
810
|
+
if (rows.length === 0)
|
|
811
|
+
return undefined;
|
|
812
|
+
if (rows.length === 1)
|
|
813
|
+
return modelBinding(rows[0]).provider;
|
|
814
|
+
const legacy = rows.find((row) => row.id === HOST_MODEL_ID);
|
|
815
|
+
if (legacy)
|
|
816
|
+
return modelBinding(legacy).provider;
|
|
817
|
+
return modelBinding(rows[0]).provider;
|
|
818
|
+
}
|
|
819
|
+
/** The active host model credential row (ciphertext), in `t`. */
|
|
820
|
+
export async function activeHostCredentialRow(t) {
|
|
821
|
+
const active = await activeProviderId(t);
|
|
822
|
+
if (!active)
|
|
823
|
+
return undefined;
|
|
824
|
+
return hostCredentialRowFor(t, active);
|
|
825
|
+
}
|
|
826
|
+
export function readHostPayload(kek, row, binding) {
|
|
822
827
|
const plaintext = decryptSecret(kek, hostModelAad(binding.provider, binding.model), Buffer.from(row.nonce), Buffer.from(row.ciphertext), Buffer.from(row.wrappedDek), row.kekId);
|
|
823
828
|
try {
|
|
824
829
|
return JSON.parse(plaintext.toString("utf8"));
|
|
@@ -889,7 +894,7 @@ function requireTimestamp(value) {
|
|
|
889
894
|
throw new VaultError(400, "Credential expiry is invalid");
|
|
890
895
|
return new Date(Date.parse(value)).toISOString();
|
|
891
896
|
}
|
|
892
|
-
function modelBinding(row) {
|
|
897
|
+
export function modelBinding(row) {
|
|
893
898
|
const binding = JSON.parse(row.bindingJson);
|
|
894
899
|
if (!binding.provider || !binding.model || !binding.authType)
|
|
895
900
|
throw new VaultError(500, "Host model credential is unreadable");
|
|
@@ -900,7 +905,7 @@ function hostModelCredentialId(provider) {
|
|
|
900
905
|
throw new VaultError(400, "Invalid provider id");
|
|
901
906
|
return `${HOST_MODEL_ID}:${provider}`;
|
|
902
907
|
}
|
|
903
|
-
function hostModelAad(provider, model) {
|
|
908
|
+
export function hostModelAad(provider, model) {
|
|
904
909
|
return Buffer.from(canonical({
|
|
905
910
|
scope: "host",
|
|
906
911
|
vaultId: HOST_VAULT_ID,
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const RUNTIME_VERSION = "0.
|
|
1
|
+
export declare const RUNTIME_VERSION = "0.15.0-beta";
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nylorun/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0-beta",
|
|
4
4
|
"description": "Nylorun Runtime: the agent execution Host on Postgres, Restate and S2, and model providers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
"types": "./dist/configuration.d.ts",
|
|
31
31
|
"import": "./dist/configuration.js"
|
|
32
32
|
},
|
|
33
|
+
"./openapi.json": "./dist/openapi.json",
|
|
34
|
+
"./admin-openapi.json": "./dist/admin-openapi.json",
|
|
33
35
|
"./package.json": "./package.json"
|
|
34
36
|
},
|
|
35
37
|
"files": [
|
|
@@ -43,7 +45,7 @@
|
|
|
43
45
|
"provenance": true
|
|
44
46
|
},
|
|
45
47
|
"scripts": {
|
|
46
|
-
"build": "npm run clean && node ../scripts/check-typescript-version.mjs && tsc -p tsconfig.json",
|
|
48
|
+
"build": "npm run clean && node ../scripts/check-typescript-version.mjs && tsc -p tsconfig.json && node scripts/copy-migrations.mjs && node scripts/build-openapi.mjs",
|
|
47
49
|
"check": "npm run build && npm test && node scripts/check-package.mjs",
|
|
48
50
|
"typecheck": "node ../scripts/check-typescript-version.mjs && tsc -p tsconfig.json --noEmit",
|
|
49
51
|
"test": "vitest run",
|
|
@@ -52,24 +54,38 @@
|
|
|
52
54
|
"test:stack:down": "node test/stack/up.mjs down",
|
|
53
55
|
"prepack": "npm run build",
|
|
54
56
|
"clean": "node -e \"import('node:fs').then(({rmSync})=>rmSync('dist',{recursive:true,force:true}))\"",
|
|
55
|
-
"start": "node dist/host/main.js"
|
|
57
|
+
"start": "node dist/host/main.js",
|
|
58
|
+
"db:generate": "drizzle-kit generate",
|
|
59
|
+
"db:studio": "drizzle-kit studio"
|
|
56
60
|
},
|
|
57
61
|
"dependencies": {
|
|
58
|
-
"@
|
|
59
|
-
"@
|
|
62
|
+
"@ag-ui/core": "~1.0.0",
|
|
63
|
+
"@asteasolutions/zod-to-openapi": "^9.1.0",
|
|
64
|
+
"@earendil-works/pi-ai": "0.99.1",
|
|
60
65
|
"@hono/node-server": "^2.1.1",
|
|
61
|
-
"@
|
|
62
|
-
"@
|
|
66
|
+
"@hono/zod-openapi": "^1.6.3",
|
|
67
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
68
|
+
"@nylorun/core": "0.10.0-beta",
|
|
69
|
+
"@nylorun/harness": "0.21.1-beta",
|
|
63
70
|
"@restatedev/restate-sdk": "1.16.9",
|
|
64
71
|
"@s2-dev/streamstore": "0.27.0",
|
|
72
|
+
"drizzle-orm": "^0.45.3",
|
|
73
|
+
"hono": "^4.13.12",
|
|
74
|
+
"jose": "^6.2.12",
|
|
65
75
|
"just-bash": "3.4.2",
|
|
66
|
-
"
|
|
76
|
+
"pg": "8.23.1",
|
|
77
|
+
"pg-logical-replication": "2.5.0",
|
|
78
|
+
"postgres": "^3.4.9",
|
|
79
|
+
"zod": "^4.6.5"
|
|
67
80
|
},
|
|
68
81
|
"devDependencies": {
|
|
82
|
+
"@a2a-js/sdk": "~1.3.0",
|
|
69
83
|
"@ag-ui/client": "1.0.0",
|
|
84
|
+
"@scalar/openapi-parser": "^0.29.9",
|
|
70
85
|
"@types/node": "^26.5.0",
|
|
86
|
+
"@types/pg": "^8.23.1",
|
|
71
87
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
72
|
-
"
|
|
88
|
+
"drizzle-kit": "^0.31.11",
|
|
73
89
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
74
90
|
"vitest": "^5.0.1"
|
|
75
91
|
}
|
package/dist/core/executors.d.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { ExecutorScope } from "@nylorun/core/contracts";
|
|
2
|
-
import type { SessionStore } from "../store/types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Executor bearer tokens are 256-bit CSPRNG values minted by the CLI and the wire schema
|
|
5
|
-
* requires at least 16 characters, so an unsalted digest is adequate to keep them out of
|
|
6
|
-
* the Session Store at rest. This is not a password KDF and must not be used for one.
|
|
7
|
-
*/
|
|
8
|
-
export declare const hashToken: (token: string) => string;
|
|
9
|
-
export interface ExecutorRecord extends ExecutorScope {
|
|
10
|
-
readonly tokenHash: string;
|
|
11
|
-
/** Always true under Runtime Tenants; startup env executors are removed (D8). */
|
|
12
|
-
readonly persisted: boolean;
|
|
13
|
-
readonly updatedAt: string;
|
|
14
|
-
/** Application principal that last registered this executor, when known. */
|
|
15
|
-
readonly principalId?: string;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Rejects tokens that are weak, empty of agent identity, or whose hash equals any
|
|
19
|
-
* application principal hash (A5). Replaces the old `serverToken` equality check.
|
|
20
|
-
*/
|
|
21
|
-
export declare function assertExecutorCredential(executor: {
|
|
22
|
-
agentId: string;
|
|
23
|
-
implementationVersion: string;
|
|
24
|
-
token: string;
|
|
25
|
-
}, applicationHashes: readonly string[]): void;
|
|
26
|
-
/** Mint a 32-byte hex application/executor key for tests and CLI bootstrap. */
|
|
27
|
-
export declare function mintBearerToken(): string;
|
|
28
|
-
export declare class ExecutorRegistry {
|
|
29
|
-
private readonly byHash;
|
|
30
|
-
private readonly byAgent;
|
|
31
|
-
seed(records: readonly ExecutorRecord[]): void;
|
|
32
|
-
find(tokenHash: string): ExecutorRecord | undefined;
|
|
33
|
-
get(agentId: string): ExecutorRecord | undefined;
|
|
34
|
-
list(): readonly ExecutorRecord[];
|
|
35
|
-
upsert(record: ExecutorRecord): {
|
|
36
|
-
rotated: boolean;
|
|
37
|
-
previousHash?: string;
|
|
38
|
-
previousPrincipalId?: string;
|
|
39
|
-
};
|
|
40
|
-
remove(agentId: string): ExecutorRecord | undefined;
|
|
41
|
-
private write;
|
|
42
|
-
}
|
|
43
|
-
/** A registry seeded from the executors the store persisted (at Tenant open). */
|
|
44
|
-
export declare function loadExecutorRegistry(store: SessionStore): Promise<ExecutorRegistry>;
|
package/dist/core/executors.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
|
-
const equals = (a, b) => {
|
|
3
|
-
const aa = Buffer.from(a), bb = Buffer.from(b);
|
|
4
|
-
return aa.length === bb.length && timingSafeEqual(aa, bb);
|
|
5
|
-
};
|
|
6
|
-
/**
|
|
7
|
-
* Executor bearer tokens are 256-bit CSPRNG values minted by the CLI and the wire schema
|
|
8
|
-
* requires at least 16 characters, so an unsalted digest is adequate to keep them out of
|
|
9
|
-
* the Session Store at rest. This is not a password KDF and must not be used for one.
|
|
10
|
-
*/
|
|
11
|
-
export const hashToken = (token) => createHash("sha256").update(token, "utf8").digest("hex");
|
|
12
|
-
/**
|
|
13
|
-
* Rejects tokens that are weak, empty of agent identity, or whose hash equals any
|
|
14
|
-
* application principal hash (A5). Replaces the old `serverToken` equality check.
|
|
15
|
-
*/
|
|
16
|
-
export function assertExecutorCredential(executor, applicationHashes) {
|
|
17
|
-
const tokenHash = hashToken(executor.token);
|
|
18
|
-
const matchesApplication = applicationHashes.some((hash) => equals(hash, tokenHash));
|
|
19
|
-
if (executor.token.length < 16 ||
|
|
20
|
-
matchesApplication ||
|
|
21
|
-
!executor.agentId ||
|
|
22
|
-
!executor.implementationVersion)
|
|
23
|
-
throw new Error("Executor tokens require independent credentials and an agent id");
|
|
24
|
-
}
|
|
25
|
-
/** Mint a 32-byte hex application/executor key for tests and CLI bootstrap. */
|
|
26
|
-
export function mintBearerToken() {
|
|
27
|
-
return randomBytes(32).toString("hex");
|
|
28
|
-
}
|
|
29
|
-
export class ExecutorRegistry {
|
|
30
|
-
byHash = new Map();
|
|
31
|
-
byAgent = new Map();
|
|
32
|
-
seed(records) {
|
|
33
|
-
for (const record of records)
|
|
34
|
-
this.write(record);
|
|
35
|
-
}
|
|
36
|
-
find(tokenHash) {
|
|
37
|
-
return this.byHash.get(tokenHash);
|
|
38
|
-
}
|
|
39
|
-
get(agentId) {
|
|
40
|
-
return this.byAgent.get(agentId);
|
|
41
|
-
}
|
|
42
|
-
list() {
|
|
43
|
-
return [...this.byAgent.values()];
|
|
44
|
-
}
|
|
45
|
-
upsert(record) {
|
|
46
|
-
const previous = this.byAgent.get(record.agentId);
|
|
47
|
-
const collision = this.byHash.get(record.tokenHash);
|
|
48
|
-
if (collision && collision.agentId !== record.agentId)
|
|
49
|
-
throw new Error("Executor tokens must be unique");
|
|
50
|
-
this.write(record);
|
|
51
|
-
if (!previous || previous.tokenHash === record.tokenHash)
|
|
52
|
-
return { rotated: false };
|
|
53
|
-
return {
|
|
54
|
-
rotated: true,
|
|
55
|
-
previousHash: previous.tokenHash,
|
|
56
|
-
...(previous.principalId === undefined
|
|
57
|
-
? {}
|
|
58
|
-
: { previousPrincipalId: previous.principalId }),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
remove(agentId) {
|
|
62
|
-
const record = this.byAgent.get(agentId);
|
|
63
|
-
if (!record)
|
|
64
|
-
return undefined;
|
|
65
|
-
this.byAgent.delete(agentId);
|
|
66
|
-
this.byHash.delete(record.tokenHash);
|
|
67
|
-
return record;
|
|
68
|
-
}
|
|
69
|
-
write(record) {
|
|
70
|
-
const previous = this.byAgent.get(record.agentId);
|
|
71
|
-
if (previous)
|
|
72
|
-
this.byHash.delete(previous.tokenHash);
|
|
73
|
-
this.byAgent.set(record.agentId, record);
|
|
74
|
-
this.byHash.set(record.tokenHash, record);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/** A registry seeded from the executors the store persisted (at Tenant open). */
|
|
78
|
-
export async function loadExecutorRegistry(store) {
|
|
79
|
-
const registry = new ExecutorRegistry();
|
|
80
|
-
const rows = await store.tx((t) => t.listExecutors());
|
|
81
|
-
registry.seed(rows.map((row) => ({
|
|
82
|
-
agentId: row.agentId,
|
|
83
|
-
implementationVersion: row.implementationVersion,
|
|
84
|
-
...(row.manifestHash === undefined
|
|
85
|
-
? {}
|
|
86
|
-
: { manifestHash: row.manifestHash }),
|
|
87
|
-
tokenHash: row.tokenHash,
|
|
88
|
-
persisted: true,
|
|
89
|
-
updatedAt: row.updatedAt,
|
|
90
|
-
...(row.principalId === undefined
|
|
91
|
-
? {}
|
|
92
|
-
: { principalId: row.principalId }),
|
|
93
|
-
})));
|
|
94
|
-
return registry;
|
|
95
|
-
}
|
package/dist/store/memory.d.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { type CommitListener, type DocTable, type ExecutorRow, type PrincipalRow, type SessionOwnership, type SessionStore, type SessionStoreOptions, type StoreHealth, type Tx, type VaultAuditRow, type VaultCredentialRow, type VaultIdempotencyRow, type VaultRow } from "./types.js";
|
|
2
|
-
/** Schema version the fake reports; it has no migrations. */
|
|
3
|
-
export declare const MEMORY_SCHEMA_VERSION = 1;
|
|
4
|
-
interface SessionMeta extends SessionOwnership {
|
|
5
|
-
nextSeq: number;
|
|
6
|
-
}
|
|
7
|
-
interface State {
|
|
8
|
-
/** JSON text per id, like a `body` column. */
|
|
9
|
-
docs: Record<DocTable, Map<string, string>>;
|
|
10
|
-
sessionMeta: Map<string, SessionMeta>;
|
|
11
|
-
/** sessionId → seq → event JSON. */
|
|
12
|
-
outbox: Map<string, Map<number, string>>;
|
|
13
|
-
executors: Map<string, ExecutorRow>;
|
|
14
|
-
principals: Map<string, PrincipalRow>;
|
|
15
|
-
vaults: Map<string, VaultRow>;
|
|
16
|
-
credentials: Map<string, VaultCredentialRow>;
|
|
17
|
-
audit: VaultAuditRow[];
|
|
18
|
-
idempotency: Map<string, VaultIdempotencyRow>;
|
|
19
|
-
settings: Map<string, string>;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* The data behind in-memory Session Stores: what a database is to its connections. Several
|
|
23
|
-
* `MemorySessionStore`s on one `MemoryStoreData` see each other's commits and serialize their
|
|
24
|
-
* transactions together, as several processes on one Tenant schema would; it outlives them,
|
|
25
|
-
* so a test can close a Tenant and open it again.
|
|
26
|
-
*/
|
|
27
|
-
export declare class MemoryStoreData {
|
|
28
|
-
/** @internal */ state: State;
|
|
29
|
-
/** @internal */ queue: Promise<void>;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* In-memory `SessionStore` for unit tests. Not a supported profile.
|
|
33
|
-
*
|
|
34
|
-
* Transactions are serialized (one at a time), each works on a copy of the
|
|
35
|
-
* state and replaces it on commit, so a throw rolls back everything: documents,
|
|
36
|
-
* sequences, outbox rows, `afterCommit` callbacks and `signalWork`. Commit listeners see
|
|
37
|
-
* only this store's commits, as with a Postgres connection.
|
|
38
|
-
*/
|
|
39
|
-
export declare class MemorySessionStore implements SessionStore {
|
|
40
|
-
/** Shared with other stores on the same data; a fresh, private one by default. */
|
|
41
|
-
private readonly data;
|
|
42
|
-
readonly tenantId: string;
|
|
43
|
-
private readonly active;
|
|
44
|
-
private readonly listeners;
|
|
45
|
-
private readonly now;
|
|
46
|
-
private readonly onError;
|
|
47
|
-
private closed;
|
|
48
|
-
constructor(options: SessionStoreOptions,
|
|
49
|
-
/** Shared with other stores on the same data; a fresh, private one by default. */
|
|
50
|
-
data?: MemoryStoreData);
|
|
51
|
-
tx<T>(fn: (t: Tx) => Promise<T>): Promise<T>;
|
|
52
|
-
onCommit(listener: CommitListener): () => void;
|
|
53
|
-
health(): Promise<StoreHealth>;
|
|
54
|
-
close(): Promise<void>;
|
|
55
|
-
private acquire;
|
|
56
|
-
}
|
|
57
|
-
export {};
|