@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,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Runtime's requests to Action endpoints (design: Action endpoints §8.3): one POST, no
|
|
3
|
+
* redirects, a bounded answer, and the Host's address policy checked on the address actually
|
|
4
|
+
* connected to, so a DNS answer cannot steer a delivery somewhere the Host forbids.
|
|
5
|
+
*
|
|
6
|
+
* The result says whether anything reached the endpoint. A request that failed before its body
|
|
7
|
+
* was flushed (refused connection, unknown host, TLS failure, a refused address) was `not_sent`
|
|
8
|
+
* and is safe to send again, even for a tool; one that failed after (reset, timeout) is `lost`.
|
|
9
|
+
*/
|
|
10
|
+
import { lookup as dnsLookup } from "node:dns";
|
|
11
|
+
import { request as httpRequest } from "node:http";
|
|
12
|
+
import { request as httpsRequest } from "node:https";
|
|
13
|
+
import { BlockList, isIP } from "node:net";
|
|
14
|
+
/** The largest answer read from an endpoint. */
|
|
15
|
+
export const MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
16
|
+
const PRIVATE = new BlockList();
|
|
17
|
+
for (const [network, prefix] of [
|
|
18
|
+
["0.0.0.0", 8],
|
|
19
|
+
["10.0.0.0", 8],
|
|
20
|
+
["100.64.0.0", 10],
|
|
21
|
+
["127.0.0.0", 8],
|
|
22
|
+
["169.254.0.0", 16],
|
|
23
|
+
["172.16.0.0", 12],
|
|
24
|
+
["192.168.0.0", 16],
|
|
25
|
+
])
|
|
26
|
+
PRIVATE.addSubnet(network, prefix, "ipv4");
|
|
27
|
+
for (const [network, prefix] of [
|
|
28
|
+
["::", 128],
|
|
29
|
+
["::1", 128],
|
|
30
|
+
["fc00::", 7],
|
|
31
|
+
["fe80::", 10],
|
|
32
|
+
])
|
|
33
|
+
PRIVATE.addSubnet(network, prefix, "ipv6");
|
|
34
|
+
/** True when `address` is private, loopback, link-local or unspecified (IPv4-mapped included). */
|
|
35
|
+
export function isPrivateAddress(address) {
|
|
36
|
+
const mapped = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i.exec(address);
|
|
37
|
+
if (mapped)
|
|
38
|
+
return PRIVATE.check(mapped[1], "ipv4");
|
|
39
|
+
const family = isIP(address);
|
|
40
|
+
if (family === 0)
|
|
41
|
+
return false;
|
|
42
|
+
return PRIVATE.check(address, family === 4 ? "ipv4" : "ipv6");
|
|
43
|
+
}
|
|
44
|
+
class RefusedAddress extends Error {
|
|
45
|
+
code = "ENDPOINT_ADDRESS_REFUSED";
|
|
46
|
+
}
|
|
47
|
+
/** Why the Host refuses `url`, or `undefined` when it may be called. */
|
|
48
|
+
export function refusal(url, policy) {
|
|
49
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && policy.allowHttp !== false))
|
|
50
|
+
return `This Runtime calls only ${policy.allowHttp === false ? "https" : "http and https"} endpoints`;
|
|
51
|
+
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
52
|
+
if (policy.privateAddresses === "refuse" && isIP(host) && isPrivateAddress(host))
|
|
53
|
+
return "This Runtime does not call private addresses; expose the endpoint through a public URL (a tunnel, for a local app)";
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
/** POSTs `body` to `url` under `policy`. Never throws; `signal` aborts the request. */
|
|
57
|
+
export async function post(target, body, headers, options) {
|
|
58
|
+
const { policy, signal } = options;
|
|
59
|
+
const limit = options.maxResponseBytes ?? MAX_RESPONSE_BYTES;
|
|
60
|
+
const url = new URL(target);
|
|
61
|
+
const refused = refusal(url, policy);
|
|
62
|
+
if (refused)
|
|
63
|
+
return { kind: "not_sent", code: "ENDPOINT_ADDRESS_REFUSED", message: refused };
|
|
64
|
+
const originalHost = url.host;
|
|
65
|
+
if (policy.loopback === "docker-host" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))
|
|
66
|
+
url.hostname = "host.docker.internal";
|
|
67
|
+
const lookup = (hostname, lookupOptions, callback) => dnsLookup(hostname, { ...lookupOptions, all: true }, (error, addresses) => {
|
|
68
|
+
if (error)
|
|
69
|
+
return callback(error, []);
|
|
70
|
+
const allowed = policy.privateAddresses === "refuse"
|
|
71
|
+
? addresses.filter((a) => !isPrivateAddress(a.address))
|
|
72
|
+
: addresses;
|
|
73
|
+
if (allowed.length === 0)
|
|
74
|
+
return callback(new RefusedAddress(`${hostname} resolves only to private addresses, which this Runtime does not call`), []);
|
|
75
|
+
if (lookupOptions.all)
|
|
76
|
+
return callback(null, allowed);
|
|
77
|
+
return callback(null, allowed[0].address, allowed[0].family);
|
|
78
|
+
});
|
|
79
|
+
return new Promise((resolve) => {
|
|
80
|
+
let sent = false;
|
|
81
|
+
let settled = false;
|
|
82
|
+
const finish = (result) => {
|
|
83
|
+
if (settled)
|
|
84
|
+
return;
|
|
85
|
+
settled = true;
|
|
86
|
+
resolve(result);
|
|
87
|
+
};
|
|
88
|
+
const failed = (error) => finish({
|
|
89
|
+
kind: sent ? "lost" : "not_sent",
|
|
90
|
+
code: signal.aborted ? "ABORTED" : (error.code ?? error.name),
|
|
91
|
+
message: signal.aborted ? "The delivery was aborted" : error.message,
|
|
92
|
+
});
|
|
93
|
+
const request = (url.protocol === "https:" ? httpsRequest : httpRequest)(url, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: {
|
|
96
|
+
...headers,
|
|
97
|
+
host: originalHost,
|
|
98
|
+
"content-type": "application/json",
|
|
99
|
+
"content-length": String(Buffer.byteLength(body)),
|
|
100
|
+
},
|
|
101
|
+
lookup: lookup,
|
|
102
|
+
signal,
|
|
103
|
+
}, (response) => {
|
|
104
|
+
const status = response.statusCode ?? 0;
|
|
105
|
+
const chunks = [];
|
|
106
|
+
let size = 0;
|
|
107
|
+
response.on("data", (chunk) => {
|
|
108
|
+
size += chunk.length;
|
|
109
|
+
if (size > limit) {
|
|
110
|
+
// Settle first: destroying the answer reports an error of its own.
|
|
111
|
+
finish({ kind: "too_large", status });
|
|
112
|
+
response.destroy();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
chunks.push(chunk);
|
|
116
|
+
});
|
|
117
|
+
response.on("end", () => finish({ kind: "response", status, headers: response.headers, body: Buffer.concat(chunks) }));
|
|
118
|
+
response.on("error", failed);
|
|
119
|
+
response.on("aborted", () => failed(Object.assign(new Error("The answer was cut off"), { code: "ECONNRESET" })));
|
|
120
|
+
});
|
|
121
|
+
request.on("finish", () => {
|
|
122
|
+
sent = true;
|
|
123
|
+
});
|
|
124
|
+
request.on("error", failed);
|
|
125
|
+
request.end(body);
|
|
126
|
+
});
|
|
127
|
+
}
|
package/dist/tenant/paths.d.ts
CHANGED
|
@@ -1,28 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TenantPaths } from "./types.js";
|
|
2
2
|
export interface HostPaths {
|
|
3
3
|
root: string;
|
|
4
4
|
config: string;
|
|
5
5
|
credentials: string;
|
|
6
6
|
home: string;
|
|
7
7
|
tmp: string;
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
/** The Tenant directory (`tenantPaths`). */
|
|
9
|
+
tenant: string;
|
|
10
10
|
}
|
|
11
11
|
/** Host layout under NYLORUN_HOME / ~/.nylorun. */
|
|
12
12
|
export declare function hostPaths(hostRoot: string): HostPaths;
|
|
13
13
|
/**
|
|
14
|
-
* Absolute Tenant directory
|
|
15
|
-
*
|
|
14
|
+
* Absolute paths of the Tenant directory, `<hostRoot>/tenant/`: a Host serves one Tenant
|
|
15
|
+
* (tenancy.md §1), so the directory has no id segment. Asserts that it stays inside the Host
|
|
16
|
+
* root after realpath.
|
|
16
17
|
*
|
|
17
|
-
* The directory holds what stays on the Host (the Tenant's data is its
|
|
18
|
-
* `
|
|
18
|
+
* The directory holds what stays on the Host (the Tenant's data is its database): `home/`,
|
|
19
|
+
* `tmp/`, `sandboxes/`, `plugin-data/`, `logs/tenant.log`. The vault key is the one exception:
|
|
20
|
+
* it lives beside the Tenant directory, in `<hostRoot>/keys/vault-kek`, which the local stack
|
|
21
|
+
* mounts only into the gateway (F4.2), never into the runtime container.
|
|
19
22
|
*/
|
|
20
|
-
export declare function tenantPaths(hostRoot: string
|
|
21
|
-
/**
|
|
22
|
-
* Moves every Tenant directory that holds a `tenant.sqlite` to `trash/`, logging each.
|
|
23
|
-
*
|
|
24
|
-
* Those are beta Tenants from the SQLite Runtime. They are not migrated (recreate them); a
|
|
25
|
-
* Postgres Tenant's directory never holds that file. Moving them at Host start keeps a new
|
|
26
|
-
* Postgres Tenant with the same id from sharing the old directory. Returns the moved ids.
|
|
27
|
-
*/
|
|
28
|
-
export declare function trashSqliteTenants(hostRoot: string, logger: Logger): string[];
|
|
23
|
+
export declare function tenantPaths(hostRoot: string): TenantPaths;
|
package/dist/tenant/paths.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import { existsSync, mkdirSync,
|
|
1
|
+
import { existsSync, mkdirSync, realpathSync } from "node:fs";
|
|
2
2
|
import { join, resolve, sep } from "node:path";
|
|
3
|
-
import { isTenantId } from "@nylorun/core/compatibility";
|
|
4
|
-
function ensureDir(path) {
|
|
5
|
-
mkdirSync(path, { recursive: true });
|
|
6
|
-
return realpathSync(path);
|
|
7
|
-
}
|
|
8
3
|
function assertContained(parent, child) {
|
|
9
4
|
const root = parent.endsWith(sep) ? parent : parent + sep;
|
|
10
5
|
if (child !== parent && !child.startsWith(root)) {
|
|
11
|
-
throw new Error(`Path ${child} escapes
|
|
6
|
+
throw new Error(`Path ${child} escapes the Host root ${parent}`);
|
|
12
7
|
}
|
|
13
8
|
}
|
|
14
9
|
/** Host layout under NYLORUN_HOME / ~/.nylorun. */
|
|
@@ -20,72 +15,33 @@ export function hostPaths(hostRoot) {
|
|
|
20
15
|
credentials: join(root, "host-credentials.json"),
|
|
21
16
|
home: join(root, "home"),
|
|
22
17
|
tmp: join(root, "tmp"),
|
|
23
|
-
|
|
24
|
-
trash: join(root, "trash"),
|
|
18
|
+
tenant: join(root, "tenant"),
|
|
25
19
|
};
|
|
26
20
|
}
|
|
27
21
|
/**
|
|
28
|
-
* Absolute Tenant directory
|
|
29
|
-
*
|
|
22
|
+
* Absolute paths of the Tenant directory, `<hostRoot>/tenant/`: a Host serves one Tenant
|
|
23
|
+
* (tenancy.md §1), so the directory has no id segment. Asserts that it stays inside the Host
|
|
24
|
+
* root after realpath.
|
|
30
25
|
*
|
|
31
|
-
* The directory holds what stays on the Host (the Tenant's data is its
|
|
32
|
-
* `
|
|
26
|
+
* The directory holds what stays on the Host (the Tenant's data is its database): `home/`,
|
|
27
|
+
* `tmp/`, `sandboxes/`, `plugin-data/`, `logs/tenant.log`. The vault key is the one exception:
|
|
28
|
+
* it lives beside the Tenant directory, in `<hostRoot>/keys/vault-kek`, which the local stack
|
|
29
|
+
* mounts only into the gateway (F4.2), never into the runtime container.
|
|
33
30
|
*/
|
|
34
|
-
export function tenantPaths(hostRoot
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const root = join(tenantsRoot, tenantId);
|
|
41
|
-
// Containment before the Tenant directory exists: resolve under real tenants root.
|
|
42
|
-
const resolvedRoot = resolve(tenantsRoot, tenantId);
|
|
43
|
-
assertContained(tenantsRoot, resolvedRoot);
|
|
44
|
-
if (existsSync(root)) {
|
|
45
|
-
assertContained(tenantsRoot, realpathSync(root));
|
|
46
|
-
}
|
|
31
|
+
export function tenantPaths(hostRoot) {
|
|
32
|
+
mkdirSync(hostRoot, { recursive: true });
|
|
33
|
+
const host = realpathSync(hostRoot);
|
|
34
|
+
const root = join(host, "tenant");
|
|
35
|
+
if (existsSync(root))
|
|
36
|
+
assertContained(host, realpathSync(root));
|
|
47
37
|
return {
|
|
48
|
-
root
|
|
49
|
-
kek: join(
|
|
50
|
-
home: join(
|
|
51
|
-
tmp: join(
|
|
52
|
-
sandboxes: join(
|
|
53
|
-
pluginData: join(
|
|
54
|
-
logs: join(
|
|
55
|
-
log: join(
|
|
38
|
+
root,
|
|
39
|
+
kek: join(host, "keys", "vault-kek"),
|
|
40
|
+
home: join(root, "home"),
|
|
41
|
+
tmp: join(root, "tmp"),
|
|
42
|
+
sandboxes: join(root, "sandboxes"),
|
|
43
|
+
pluginData: join(root, "plugin-data"),
|
|
44
|
+
logs: join(root, "logs"),
|
|
45
|
+
log: join(root, "logs", "tenant.log"),
|
|
56
46
|
};
|
|
57
47
|
}
|
|
58
|
-
/** The database file of a Tenant from before the Postgres Session Store. */
|
|
59
|
-
const SQLITE_DATABASE = "tenant.sqlite";
|
|
60
|
-
/**
|
|
61
|
-
* Moves every Tenant directory that holds a `tenant.sqlite` to `trash/`, logging each.
|
|
62
|
-
*
|
|
63
|
-
* Those are beta Tenants from the SQLite Runtime. They are not migrated (recreate them); a
|
|
64
|
-
* Postgres Tenant's directory never holds that file. Moving them at Host start keeps a new
|
|
65
|
-
* Postgres Tenant with the same id from sharing the old directory. Returns the moved ids.
|
|
66
|
-
*/
|
|
67
|
-
export function trashSqliteTenants(hostRoot, logger) {
|
|
68
|
-
const host = hostPaths(hostRoot);
|
|
69
|
-
if (!existsSync(host.tenants))
|
|
70
|
-
return [];
|
|
71
|
-
const moved = [];
|
|
72
|
-
const stamp = new Date().toISOString().replaceAll(":", "-");
|
|
73
|
-
for (const entry of readdirSync(host.tenants, { withFileTypes: true })) {
|
|
74
|
-
if (!entry.isDirectory())
|
|
75
|
-
continue;
|
|
76
|
-
const directory = join(host.tenants, entry.name);
|
|
77
|
-
if (!existsSync(join(directory, SQLITE_DATABASE)))
|
|
78
|
-
continue;
|
|
79
|
-
mkdirSync(host.trash, { recursive: true });
|
|
80
|
-
const destination = join(host.trash, `${entry.name}-sqlite-${stamp}`);
|
|
81
|
-
renameSync(directory, destination);
|
|
82
|
-
moved.push(entry.name);
|
|
83
|
-
logger.warn("sqlite_tenant_moved_to_trash", {
|
|
84
|
-
tenant: entry.name,
|
|
85
|
-
from: directory,
|
|
86
|
-
to: destination,
|
|
87
|
-
reason: "SQLite Tenants are not migrated to the Postgres Session Store; recreate the Tenant",
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
return moved;
|
|
91
|
-
}
|
package/dist/tenant/pool.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
/** Run async work over items with a fixed concurrency limit. */
|
|
2
|
-
export declare function mapPool<T, R>(items: readonly T[], concurrency: number, worker: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
3
1
|
export declare class TimeoutError extends Error {
|
|
4
2
|
constructor(message?: string);
|
|
5
3
|
}
|
|
6
4
|
/**
|
|
7
5
|
* Race a promise against a timeout. On timeout the late result is handed to
|
|
8
|
-
* `onLate` (Risk R6:
|
|
6
|
+
* `onLate` (Risk R6: the module closes a handle that opened too late).
|
|
9
7
|
*/
|
|
10
8
|
export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, onLate?: (late: Promise<T>) => void): Promise<T>;
|
package/dist/tenant/pool.js
CHANGED
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
/** Run async work over items with a fixed concurrency limit. */
|
|
2
|
-
export async function mapPool(items, concurrency, worker) {
|
|
3
|
-
if (items.length === 0)
|
|
4
|
-
return [];
|
|
5
|
-
const limit = Math.max(1, Math.min(concurrency, items.length));
|
|
6
|
-
const results = new Array(items.length);
|
|
7
|
-
let next = 0;
|
|
8
|
-
async function run() {
|
|
9
|
-
for (;;) {
|
|
10
|
-
const index = next++;
|
|
11
|
-
if (index >= items.length)
|
|
12
|
-
return;
|
|
13
|
-
results[index] = await worker(items[index], index);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
await Promise.all(Array.from({ length: limit }, () => run()));
|
|
17
|
-
return results;
|
|
18
|
-
}
|
|
19
1
|
export class TimeoutError extends Error {
|
|
20
2
|
constructor(message = "operation timed out") {
|
|
21
3
|
super(message);
|
|
@@ -24,7 +6,7 @@ export class TimeoutError extends Error {
|
|
|
24
6
|
}
|
|
25
7
|
/**
|
|
26
8
|
* Race a promise against a timeout. On timeout the late result is handed to
|
|
27
|
-
* `onLate` (Risk R6:
|
|
9
|
+
* `onLate` (Risk R6: the module closes a handle that opened too late).
|
|
28
10
|
*/
|
|
29
11
|
export async function withTimeout(promise, timeoutMs, onLate) {
|
|
30
12
|
let timer;
|
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { BootstrapPrincipal } from "./types.js";
|
|
1
|
+
import type { InitialPrincipal } from "../store/postgres/tenant.js";
|
|
3
2
|
export type { PrincipalRow } from "../store/types.js";
|
|
4
3
|
/** Principal id of the Studio key derived from the admin key. */
|
|
5
4
|
export declare const STUDIO_PRINCIPAL_ID = "studio";
|
|
5
|
+
/** The derived principal Projects use (`PROJECT_PRINCIPAL_ID` in `@nylorun/admin`). */
|
|
6
|
+
export declare const PROJECT_PRINCIPAL_ID = "project";
|
|
7
|
+
/** The derived principals a Host registers when not told otherwise. */
|
|
8
|
+
export declare const DEFAULT_DERIVED_PRINCIPALS: readonly string[];
|
|
9
|
+
/** The Studio key of `tenantId`: HMAC-SHA256 of the admin key. */
|
|
10
|
+
export declare function deriveStudioKey(adminKey: string, tenantId: string): string;
|
|
11
|
+
/** The key of derived principal `principalId` on `tenantId`: HMAC-SHA256 of the admin key. */
|
|
12
|
+
export declare function deriveTenantKey(adminKey: string, tenantId: string, principalId: string): string;
|
|
13
|
+
/** Whether `id` may name a derived principal: the client's name, never `studio`. */
|
|
14
|
+
export declare function isDerivedPrincipalId(id: string): boolean;
|
|
6
15
|
/**
|
|
7
|
-
*
|
|
8
|
-
* principal
|
|
9
|
-
* Exported for WS-B's `TenantStore.create` (A3).
|
|
16
|
+
* The principals a Host's Tenant is created with: `studio`, each derived principal, and an
|
|
17
|
+
* application principal when a key is given (the ephemeral Runtime). Keys are hashed here.
|
|
10
18
|
*/
|
|
11
|
-
export declare function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
export declare function hostPrincipals(options: {
|
|
20
|
+
adminKey: string;
|
|
21
|
+
derived?: readonly string[];
|
|
22
|
+
application?: {
|
|
23
|
+
principalId: string;
|
|
24
|
+
key: string;
|
|
25
|
+
};
|
|
26
|
+
/** Registers `studio` with this hash instead of the admin key's derivation. */
|
|
27
|
+
studioCredentialHash?: string;
|
|
28
|
+
}): (tenantId: string) => InitialPrincipal[];
|
|
@@ -1,56 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The principals the Host gives its Tenant when it creates it (tenancy.md §4, plan P9): the
|
|
3
|
+
* Studio principal and the derived principals, whose keys the admin key derives, so the
|
|
4
|
+
* clients holding the admin key (Studio, `nylorun start`, Babai) store none. The Tenant keeps
|
|
5
|
+
* only their hashes.
|
|
6
|
+
*
|
|
7
|
+
* The derivations are the ones `@nylorun/admin` computes on the client side
|
|
8
|
+
* (`admin/src/derived-credentials.ts`: `deriveStudioToken`, `deriveTenantKey`); both sides
|
|
9
|
+
* must stay byte for byte the same.
|
|
10
|
+
*/
|
|
11
|
+
import { createHmac } from "node:crypto";
|
|
12
|
+
import { DERIVED_PRINCIPAL_ID_PATTERN } from "@nylorun/core/compatibility";
|
|
13
|
+
import { hashToken } from "../core/bearer.js";
|
|
1
14
|
/** Principal id of the Studio key derived from the admin key. */
|
|
2
15
|
export const STUDIO_PRINCIPAL_ID = "studio";
|
|
16
|
+
/** The derived principal Projects use (`PROJECT_PRINCIPAL_ID` in `@nylorun/admin`). */
|
|
17
|
+
export const PROJECT_PRINCIPAL_ID = "project";
|
|
18
|
+
/** The derived principals a Host registers when not told otherwise. */
|
|
19
|
+
export const DEFAULT_DERIVED_PRINCIPALS = [PROJECT_PRINCIPAL_ID];
|
|
20
|
+
/** The Studio key of `tenantId`: HMAC-SHA256 of the admin key. */
|
|
21
|
+
export function deriveStudioKey(adminKey, tenantId) {
|
|
22
|
+
return hmac(adminKey, ["nylorun/studio/v1", tenantId]);
|
|
23
|
+
}
|
|
24
|
+
/** The key of derived principal `principalId` on `tenantId`: HMAC-SHA256 of the admin key. */
|
|
25
|
+
export function deriveTenantKey(adminKey, tenantId, principalId) {
|
|
26
|
+
return hmac(adminKey, ["nylorun/principal/v1", principalId, tenantId]);
|
|
27
|
+
}
|
|
28
|
+
/** Whether `id` may name a derived principal: the client's name, never `studio`. */
|
|
29
|
+
export function isDerivedPrincipalId(id) {
|
|
30
|
+
return DERIVED_PRINCIPAL_ID_PATTERN.test(id) && id !== STUDIO_PRINCIPAL_ID;
|
|
31
|
+
}
|
|
3
32
|
/**
|
|
4
|
-
*
|
|
5
|
-
* principal
|
|
6
|
-
* Exported for WS-B's `TenantStore.create` (A3).
|
|
33
|
+
* The principals a Host's Tenant is created with: `studio`, each derived principal, and an
|
|
34
|
+
* application principal when a key is given (the ephemeral Runtime). Keys are hashed here.
|
|
7
35
|
*/
|
|
8
|
-
export
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
id
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
36
|
+
export function hostPrincipals(options) {
|
|
37
|
+
const derived = options.derived ?? DEFAULT_DERIVED_PRINCIPALS;
|
|
38
|
+
for (const id of derived)
|
|
39
|
+
if (!isDerivedPrincipalId(id))
|
|
40
|
+
throw new Error(`Derived principal id '${id}' must match ${DERIVED_PRINCIPAL_ID_PATTERN} and not be '${STUDIO_PRINCIPAL_ID}'`);
|
|
41
|
+
return (tenantId) => [
|
|
42
|
+
...(options.application
|
|
43
|
+
? [
|
|
44
|
+
{
|
|
45
|
+
id: options.application.principalId,
|
|
46
|
+
credentialHash: hashToken(options.application.key),
|
|
47
|
+
},
|
|
48
|
+
]
|
|
49
|
+
: []),
|
|
50
|
+
{
|
|
19
51
|
id: STUDIO_PRINCIPAL_ID,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
role: "application",
|
|
29
|
-
tokenHash: principal.credentialHash,
|
|
30
|
-
idempotencyKey: null,
|
|
31
|
-
createdAt,
|
|
32
|
-
});
|
|
52
|
+
credentialHash: options.studioCredentialHash ??
|
|
53
|
+
hashToken(deriveStudioKey(options.adminKey, tenantId)),
|
|
54
|
+
},
|
|
55
|
+
...[...new Set(derived)].map((id) => ({
|
|
56
|
+
id,
|
|
57
|
+
credentialHash: hashToken(deriveTenantKey(options.adminKey, tenantId, id)),
|
|
58
|
+
})),
|
|
59
|
+
];
|
|
33
60
|
}
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
row.role !== "application" ||
|
|
42
|
-
row.tokenHash !== bootstrap.credentialHash ||
|
|
43
|
-
row.idempotencyKey !== bootstrap.idempotencyKey)
|
|
44
|
-
return false;
|
|
45
|
-
const studio = await t.principalById(STUDIO_PRINCIPAL_ID);
|
|
46
|
-
if ((studio?.role === "application" ? studio.tokenHash : undefined) !==
|
|
47
|
-
bootstrap.studioCredentialHash)
|
|
48
|
-
return false;
|
|
49
|
-
for (const principal of bootstrap.derivedPrincipals ?? []) {
|
|
50
|
-
const stored = await t.principalById(principal.id);
|
|
51
|
-
if (stored?.role !== "application" ||
|
|
52
|
-
stored.tokenHash !== principal.credentialHash)
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
return true;
|
|
61
|
+
/** HMAC-SHA256 (hex) of `parts` joined by NUL bytes, keyed with the admin key. */
|
|
62
|
+
function hmac(adminKey, parts) {
|
|
63
|
+
const message = Buffer.concat(parts.flatMap((part, index) => [
|
|
64
|
+
...(index > 0 ? [Buffer.from([0])] : []),
|
|
65
|
+
Buffer.from(part, "utf8"),
|
|
66
|
+
]));
|
|
67
|
+
return createHmac("sha256", Buffer.from(adminKey, "utf8")).update(message).digest("hex");
|
|
56
68
|
}
|
package/dist/tenant/reset.d.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import type { ResetScope, SessionStore } from "../store/types.js";
|
|
2
|
-
import type { ExecutorRegistry } from "../core/executors.js";
|
|
3
2
|
import type { SandboxManager } from "../sandbox/manager.js";
|
|
4
3
|
import type { TenantPaths } from "./types.js";
|
|
5
4
|
export type { ResetScope } from "../store/types.js";
|
|
6
5
|
export interface ResetTenantContext {
|
|
7
6
|
store: SessionStore;
|
|
8
|
-
registry: ExecutorRegistry;
|
|
9
7
|
sandbox: SandboxManager;
|
|
10
8
|
paths: TenantPaths;
|
|
11
9
|
/** Clear in-memory session observers after the store wipe. */
|
|
12
10
|
clearSessionState: () => void;
|
|
13
|
-
/** Clear executor SSE streams when registrations are removed. */
|
|
14
|
-
clearExecutorStreams: () => void;
|
|
15
11
|
}
|
|
16
12
|
/**
|
|
17
13
|
* Reset Tenant durable state for `scope` (A17).
|
package/dist/tenant/reset.js
CHANGED
|
@@ -42,13 +42,8 @@ export async function resetTenant(ctx, scope) {
|
|
|
42
42
|
await ctx.sandbox.reconcile(() => false);
|
|
43
43
|
}
|
|
44
44
|
await ctx.store.tx((t) => t.reset(scope));
|
|
45
|
-
if (clearAll)
|
|
46
|
-
for (const row of ctx.registry.list())
|
|
47
|
-
ctx.registry.remove(row.agentId);
|
|
48
45
|
if (clearSessions)
|
|
49
46
|
ctx.clearSessionState();
|
|
50
|
-
if (clearAll)
|
|
51
|
-
ctx.clearExecutorStreams();
|
|
52
47
|
if (clearSandboxes)
|
|
53
48
|
replaceDirectory(ctx.paths.sandboxes);
|
|
54
49
|
if (clearAll) {
|
package/dist/tenant/runtime.d.ts
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Composition root of an open Tenant: validates the config, opens the Session Store and the
|
|
3
|
-
* vault key, builds the services and the `TenantContext`, wires the seams, registers the
|
|
4
|
-
* Tenant's Worker handlers and arms its sweep, and implements `TenantHandle` (handle,
|
|
5
|
-
* summary, drain, close) by delegating to the Tenant modules.
|
|
6
|
-
*
|
|
7
|
-
* Seams wired here: `wireStreams()` connects the store's commits to Durable Streams (the
|
|
8
|
-
* relay, and the history, SSE, work and control readers); `wake` goes to the
|
|
9
|
-
* `DurableExecution`, whose handlers (`worker.ts`) call `advance` and `sweep`; `abortLocal`
|
|
10
|
-
* aborts an advance running on this process. The sweep also drains the outbox.
|
|
11
|
-
*
|
|
12
|
-
* Execution: the Host passes one `TenantExecution` for every Tenant it opens
|
|
13
|
-
* (`TenantOpenHooks.execution`); without one, the Tenant runs its own in-process
|
|
14
|
-
* `MemoryExecution`. No lock file: several processes may open a Tenant, and ownership of each
|
|
15
|
-
* session (§10.6) keeps its advances apart.
|
|
16
|
-
*/
|
|
17
|
-
import type { ServerResponse, IncomingMessage } from "node:http";
|
|
18
1
|
import type { TenantEnvelope } from "@nylorun/core/contracts";
|
|
19
2
|
import { type ModelProvider } from "../core/provider.js";
|
|
3
|
+
import type { ModelGate } from "../gates/model-gate.js";
|
|
20
4
|
import { type AuthorizeResult } from "../vault/service.js";
|
|
21
5
|
import type { DurableStreams } from "../streams/types.js";
|
|
22
|
-
import type { OpenedTenant, TenantConfig, TenantHandle, TenantSummary } from "./types.js";
|
|
6
|
+
import type { NodeBindings, OpenedTenant, TenantConfig, TenantHandle, TenantSummary } from "./types.js";
|
|
23
7
|
import { type StreamsStatus } from "./streams.js";
|
|
24
8
|
import { type TenantExecution, type TenantWorker } from "./worker.js";
|
|
9
|
+
import { type ToolGate } from "../gates/tool-gate.js";
|
|
10
|
+
import { type Keys } from "../keys/keys.js";
|
|
25
11
|
/** TENANTS-CCR: test/injection hooks until TenantConfig gains them. */
|
|
26
12
|
export type TenantOpenHooks = {
|
|
27
13
|
modelProvider?: ModelProvider;
|
|
14
|
+
/**
|
|
15
|
+
* Serves the Tenant's vault-backed model calls (the gates service's client). Without one,
|
|
16
|
+
* the Tenant calls the model in this process.
|
|
17
|
+
*/
|
|
18
|
+
modelGate?: ModelGate;
|
|
19
|
+
/**
|
|
20
|
+
* Serves the Tenant's remote MCP servers and Action deliveries (the gates service's client).
|
|
21
|
+
* Without one, the Tenant opens them and POSTs deliveries in this process.
|
|
22
|
+
*/
|
|
23
|
+
toolGate?: ToolGate;
|
|
24
|
+
/**
|
|
25
|
+
* Runs vault writes and token signing (the `keys` service's client, F4.2). With one, this
|
|
26
|
+
* process never reads, creates or holds the vault key. Without one, it does them here.
|
|
27
|
+
*/
|
|
28
|
+
keys?: Keys;
|
|
28
29
|
vaultKek?: Buffer | string | null;
|
|
29
30
|
/** When true, create the KEK file on first vault write (tests / new Tenants). */
|
|
30
31
|
createKekIfMissing?: boolean;
|
|
@@ -42,6 +43,13 @@ export type TenantOpenHooks = {
|
|
|
42
43
|
* survive a restart (tests, and a Host without S2).
|
|
43
44
|
*/
|
|
44
45
|
streams?: DurableStreams;
|
|
46
|
+
/**
|
|
47
|
+
* The Host's stream relay feeds `streams` from the record. Without it the
|
|
48
|
+
* Tenant relays its own commits.
|
|
49
|
+
*/
|
|
50
|
+
hostRelay?: boolean;
|
|
51
|
+
/** How long a retired stream basin is kept after a reset (tests). Default 60 s. */
|
|
52
|
+
retireGraceMs?: number;
|
|
45
53
|
} & OpenedTenant;
|
|
46
54
|
export declare class TenantRuntime implements TenantHandle {
|
|
47
55
|
private readonly ctx;
|
|
@@ -53,7 +61,7 @@ export declare class TenantRuntime implements TenantHandle {
|
|
|
53
61
|
private readonly closeGraceMs;
|
|
54
62
|
private constructor();
|
|
55
63
|
static open(config: TenantConfig, hooks: TenantOpenHooks): Promise<TenantRuntime>;
|
|
56
|
-
|
|
64
|
+
fetch(request: Request, node: NodeBindings): Promise<Response>;
|
|
57
65
|
authorize(sessionId: string, request: {
|
|
58
66
|
url: string;
|
|
59
67
|
serverName?: string;
|
|
@@ -67,7 +75,7 @@ export declare class TenantRuntime implements TenantHandle {
|
|
|
67
75
|
abortLocal(sessionId: string): void;
|
|
68
76
|
/**
|
|
69
77
|
* The Durable Streams seam's status for Tenant status and readiness: S2 reachability, the
|
|
70
|
-
* basin,
|
|
78
|
+
* basin, its generation and the Tenant's relay (`streamsStatus` in `tenant/streams.ts`).
|
|
71
79
|
*/
|
|
72
80
|
streamsStatus(): Promise<StreamsStatus>;
|
|
73
81
|
/** Adds a callback to the Tenant sweep. Returns a function that removes it. */
|