@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/host/create-host.js
CHANGED
|
@@ -1,42 +1,13 @@
|
|
|
1
1
|
import { createServer, } from "node:http";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { AdminStatusSchema
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { getRequestListener, RequestError } from "@hono/node-server";
|
|
3
|
+
import { HOST_PROTOCOL } from "@nylorun/core/compatibility";
|
|
4
|
+
import { AdminStatusSchema } from "@nylorun/core/contracts";
|
|
5
|
+
import { adminDocument } from "../api/openapi.js";
|
|
6
|
+
import { createAdminApi } from "./admin-api.js";
|
|
7
|
+
import { createHostApp } from "./app.js";
|
|
8
|
+
import { bindListener as bind, EXIT_NON_LOOPBACK, headerValue, HostListenError, isAllowedRequestHost, isLoopbackHost, pathnameIsLogged, redactRoutePath, rejectedResponse, sendRejected, } from "./http.js";
|
|
8
9
|
import { RUNTIME_VERSION } from "../version.js";
|
|
9
|
-
|
|
10
|
-
return createHash("sha256").update(value, "utf8").digest();
|
|
11
|
-
}
|
|
12
|
-
/** Constant-time comparison of SHA-256 digests of the presented and stored admin keys. */
|
|
13
|
-
export function adminKeyMatches(presented, adminKey) {
|
|
14
|
-
if (presented === undefined)
|
|
15
|
-
return false;
|
|
16
|
-
const a = hashUtf8(presented);
|
|
17
|
-
const b = hashUtf8(adminKey);
|
|
18
|
-
return a.length === b.length && timingSafeEqual(a, b);
|
|
19
|
-
}
|
|
20
|
-
function headerValue(headers, name) {
|
|
21
|
-
const raw = headers[name.toLowerCase()];
|
|
22
|
-
if (Array.isArray(raw))
|
|
23
|
-
return raw[0];
|
|
24
|
-
return raw;
|
|
25
|
-
}
|
|
26
|
-
function parseProtocolVersion(raw) {
|
|
27
|
-
if (raw === undefined)
|
|
28
|
-
return undefined;
|
|
29
|
-
const trimmed = raw.trim();
|
|
30
|
-
if (!/^\d+$/.test(trimmed))
|
|
31
|
-
return undefined;
|
|
32
|
-
return Number(trimmed);
|
|
33
|
-
}
|
|
34
|
-
function protocolAccepted(raw) {
|
|
35
|
-
const version = parseProtocolVersion(raw);
|
|
36
|
-
if (version === undefined)
|
|
37
|
-
return false;
|
|
38
|
-
return checkCompatibility({ version, required: [] }, HOST_PROTOCOL).ok;
|
|
39
|
-
}
|
|
10
|
+
export { adminKeyMatches } from "./http.js";
|
|
40
11
|
export function createHost(options) {
|
|
41
12
|
const { hostRoot, module, config, credentials, logger, coreVersion, } = options;
|
|
42
13
|
const pid = options.pid ?? process.pid;
|
|
@@ -46,10 +17,14 @@ export function createHost(options) {
|
|
|
46
17
|
let server;
|
|
47
18
|
let url = "";
|
|
48
19
|
let listenPort = bindPort;
|
|
20
|
+
const operator = options.operator;
|
|
21
|
+
let operatorServer;
|
|
22
|
+
let operatorPort = operator?.port ?? 0;
|
|
23
|
+
let adminUrl = "";
|
|
24
|
+
const mainRole = operator ? "public" : "combined";
|
|
49
25
|
let closing = false;
|
|
50
26
|
let closePromise;
|
|
51
27
|
const adminStatusBody = async () => {
|
|
52
|
-
const tenants = await module.list();
|
|
53
28
|
const aggregate = await module.summarize();
|
|
54
29
|
return AdminStatusSchema.parse({
|
|
55
30
|
service: "nylorun-runtime",
|
|
@@ -59,7 +34,7 @@ export function createHost(options) {
|
|
|
59
34
|
max: HOST_PROTOCOL.max,
|
|
60
35
|
features: [...HOST_PROTOCOL.features],
|
|
61
36
|
},
|
|
62
|
-
|
|
37
|
+
tenant: module.tenant(),
|
|
63
38
|
aggregate,
|
|
64
39
|
host: {
|
|
65
40
|
hostId: config.hostId,
|
|
@@ -68,276 +43,76 @@ export function createHost(options) {
|
|
|
68
43
|
},
|
|
69
44
|
});
|
|
70
45
|
};
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
code: "invalid_request",
|
|
132
|
-
message: "activeWork must be refuse, drain, or cancel",
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
try {
|
|
136
|
-
await module.delete(id, activeWork);
|
|
137
|
-
response.writeHead(204);
|
|
138
|
-
response.end();
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
catch (error) {
|
|
142
|
-
if (error instanceof TenantNotFoundError)
|
|
143
|
-
return sendOpaqueNotFound(response);
|
|
144
|
-
const code = error.code;
|
|
145
|
-
if (error instanceof TenantBusyError ||
|
|
146
|
-
error.name === "TenantBusyError" ||
|
|
147
|
-
code === "active_work" ||
|
|
148
|
-
code === "conflict") {
|
|
149
|
-
return sendRejected(response, 409, "active_work", error instanceof Error ? error.message : "Active work");
|
|
150
|
-
}
|
|
151
|
-
throw error;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// D12: /v1/admin/status and /v1/admin/host share one handler.
|
|
157
|
-
if ((segments[2] === "host" || segments[2] === "status") &&
|
|
158
|
-
segments.length === 3 &&
|
|
159
|
-
method === "GET") {
|
|
160
|
-
return sendJson(response, 200, await adminStatusBody());
|
|
161
|
-
}
|
|
162
|
-
if (segments[2] === "host" &&
|
|
163
|
-
segments.length === 4 &&
|
|
164
|
-
segments[3] === "shutdown" &&
|
|
165
|
-
method === "POST") {
|
|
166
|
-
sendJson(response, 200, { status: "shutting_down" });
|
|
167
|
-
void close();
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
return sendRejected(response, 404, "not_found", "Route not found");
|
|
171
|
-
};
|
|
172
|
-
const handle = async (request, response) => {
|
|
173
|
-
const started = Date.now();
|
|
174
|
-
let tenantId;
|
|
175
|
-
let statusCode = 500;
|
|
176
|
-
try {
|
|
177
|
-
const urlObj = new URL(request.url ?? "/", "http://runtime.local");
|
|
178
|
-
const pathname = urlObj.pathname;
|
|
179
|
-
// D§11: Host, Origin, then Content-Type — before any other processing.
|
|
180
|
-
const hostHeader = headerValue(request.headers, "host");
|
|
181
|
-
if (!isAllowedRequestHost(hostHeader, {
|
|
182
|
-
port: listenPort,
|
|
183
|
-
host: config.host,
|
|
184
|
-
allowNonLoopback: config.allowNonLoopback,
|
|
185
|
-
...(containerListen
|
|
186
|
-
? { allowedHosts: containerListen.allowedHosts }
|
|
187
|
-
: {}),
|
|
188
|
-
})) {
|
|
189
|
-
sendRejected(response, 421, "host_rejected", "Host header is not an allowed loopback or configured address");
|
|
190
|
-
statusCode = 421;
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
if (headerValue(request.headers, "origin") !== undefined) {
|
|
194
|
-
sendRejected(response, 403, "origin_rejected", "Browser Origin headers are not accepted");
|
|
195
|
-
statusCode = 403;
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
if (requestHasBody(request) &&
|
|
199
|
-
!isJsonContentType(headerValue(request.headers, "content-type"))) {
|
|
200
|
-
sendRejected(response, 415, "unsupported_media_type", "Request bodies must use application/json");
|
|
201
|
-
statusCode = 415;
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
if (pathname === "/health") {
|
|
205
|
-
sendJson(response, 200, {
|
|
206
|
-
status: "ok",
|
|
207
|
-
service: "nylorun-runtime",
|
|
208
|
-
version: RUNTIME_VERSION,
|
|
209
|
-
protocol: {
|
|
210
|
-
min: HOST_PROTOCOL.min,
|
|
211
|
-
max: HOST_PROTOCOL.max,
|
|
212
|
-
features: [...HOST_PROTOCOL.features],
|
|
213
|
-
},
|
|
214
|
-
coreVersion,
|
|
215
|
-
hostId: config.hostId,
|
|
216
|
-
pid,
|
|
217
|
-
});
|
|
218
|
-
statusCode = 200;
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
if (pathname === "/ready") {
|
|
222
|
-
const listener = Boolean(server?.listening);
|
|
223
|
-
const discovery = module.started;
|
|
224
|
-
const infra = await options.readiness?.();
|
|
225
|
-
const ready = listener && discovery && !closing && (infra?.ok ?? true);
|
|
226
|
-
sendJson(response, ready ? 200 : 503, {
|
|
227
|
-
status: ready ? "ready" : "not_ready",
|
|
228
|
-
service: "nylorun-runtime",
|
|
229
|
-
checks: { listener, discovery, ...infra?.checks },
|
|
230
|
-
});
|
|
231
|
-
statusCode = ready ? 200 : 503;
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
const segments = pathname.split("/").filter(Boolean);
|
|
235
|
-
const isAdmin = segments[0] === "v1" && segments[1] === "admin";
|
|
236
|
-
if (isAdmin) {
|
|
237
|
-
const protocolHeader = headerValue(request.headers, PROTOCOL_HEADER);
|
|
238
|
-
if (!protocolAccepted(protocolHeader)) {
|
|
239
|
-
sendProtocolRejected(response);
|
|
240
|
-
statusCode = 426;
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
if (!requireAdmin(request, response)) {
|
|
244
|
-
statusCode = 404;
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
await handleAdmin(request, response, urlObj, segments);
|
|
248
|
-
statusCode = response.statusCode || 200;
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
// Tenant-scoped routes: header pattern → protocol → resolve → Tenant handle.
|
|
252
|
-
const tenantHeader = headerValue(request.headers, TENANT_HEADER);
|
|
253
|
-
if (tenantHeader === undefined || tenantHeader.trim() === "") {
|
|
254
|
-
sendJson(response, 400, {
|
|
255
|
-
status: "rejected",
|
|
256
|
-
code: "invalid_request",
|
|
257
|
-
message: `${TENANT_HEADER} header is required`,
|
|
258
|
-
});
|
|
259
|
-
statusCode = 400;
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
if (!isTenantId(tenantHeader)) {
|
|
263
|
-
sendJson(response, 400, {
|
|
264
|
-
status: "rejected",
|
|
265
|
-
code: "invalid_request",
|
|
266
|
-
message: `${TENANT_HEADER} header is malformed`,
|
|
267
|
-
});
|
|
268
|
-
statusCode = 400;
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
tenantId = tenantHeader;
|
|
272
|
-
const protocolHeader = headerValue(request.headers, PROTOCOL_HEADER);
|
|
273
|
-
if (!protocolAccepted(protocolHeader)) {
|
|
274
|
-
sendProtocolRejected(response);
|
|
275
|
-
statusCode = 426;
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
const resolution = await module.resolve(tenantId);
|
|
279
|
-
if (resolution.kind !== "open") {
|
|
280
|
-
if (resolution.kind === "quarantined") {
|
|
281
|
-
logger.warn("tenant_quarantined", {
|
|
282
|
-
tenantId,
|
|
283
|
-
code: resolution.quarantine.code,
|
|
284
|
-
repair: resolution.quarantine.repair,
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
sendOpaqueNotFound(response);
|
|
288
|
-
statusCode = 404;
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
await resolution.handle.handle(request, response, urlObj);
|
|
292
|
-
statusCode = response.statusCode || 200;
|
|
293
|
-
}
|
|
294
|
-
catch (error) {
|
|
295
|
-
const status = error.status;
|
|
296
|
-
if (typeof status === "number" && status >= 400 && status < 600) {
|
|
297
|
-
sendJson(response, status, {
|
|
298
|
-
status: "rejected",
|
|
299
|
-
code: status === 400 ? "invalid_request" : "request_rejected",
|
|
300
|
-
message: error instanceof Error ? error.message : "Request rejected",
|
|
301
|
-
});
|
|
302
|
-
statusCode = status;
|
|
303
|
-
}
|
|
304
|
-
else if (error &&
|
|
305
|
-
typeof error === "object" &&
|
|
306
|
-
"name" in error &&
|
|
307
|
-
error.name === "ZodError") {
|
|
308
|
-
sendJson(response, 400, {
|
|
309
|
-
status: "rejected",
|
|
310
|
-
code: "invalid_request",
|
|
311
|
-
message: "Invalid request body",
|
|
312
|
-
});
|
|
313
|
-
statusCode = 400;
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
logger.error("request_failed", {
|
|
317
|
-
error: error instanceof Error ? error.message : String(error),
|
|
318
|
-
});
|
|
319
|
-
if (!response.headersSent) {
|
|
320
|
-
sendJson(response, 500, {
|
|
321
|
-
status: "rejected",
|
|
322
|
-
code: "internal_error",
|
|
323
|
-
message: "Internal error",
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
statusCode = 500;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
finally {
|
|
330
|
-
if (pathnameIsLogged(request.url)) {
|
|
46
|
+
const adminApi = createAdminApi({
|
|
47
|
+
status: adminStatusBody,
|
|
48
|
+
shutdown: () => void close(),
|
|
49
|
+
document: adminDocument,
|
|
50
|
+
});
|
|
51
|
+
const app = createHostApp({
|
|
52
|
+
module,
|
|
53
|
+
logger,
|
|
54
|
+
hostId: config.hostId,
|
|
55
|
+
adminKey: credentials.adminKey,
|
|
56
|
+
coreVersion,
|
|
57
|
+
pid,
|
|
58
|
+
browserAccess: options.browserAccess === true,
|
|
59
|
+
...(options.readiness ? { readiness: options.readiness } : {}),
|
|
60
|
+
listening: () => Boolean(server?.listening) && (!operator || Boolean(operatorServer?.listening)),
|
|
61
|
+
closing: () => closing,
|
|
62
|
+
admin: async (request, node) => await adminApi.fetch(request, node),
|
|
63
|
+
});
|
|
64
|
+
/** Where a listener's requests go once their `Host` header checks out. */
|
|
65
|
+
const pipeline = (role) => getRequestListener(async (request, node) => alreadySent(await app.fetch(request, { ...node, role })), {
|
|
66
|
+
// The Runtime runs inside other processes (`startEphemeralRuntime`): leave their
|
|
67
|
+
// `Request` and `Response` alone.
|
|
68
|
+
overrideGlobalObjects: false,
|
|
69
|
+
// A request target `@hono/node-server` cannot make a URL of, such as `*`.
|
|
70
|
+
errorHandler: (error) => {
|
|
71
|
+
if (error instanceof RequestError)
|
|
72
|
+
return rejectedResponse(400, "invalid_request", "Invalid request target");
|
|
73
|
+
logger.error("request_failed", {
|
|
74
|
+
error: error instanceof Error ? error.message : String(error),
|
|
75
|
+
});
|
|
76
|
+
return rejectedResponse(500, "internal_error", "Internal error");
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
/** The `Host` values a listener accepts. */
|
|
80
|
+
const hostAllowed = (role, hostHeader) => role === "operator"
|
|
81
|
+
? isAllowedRequestHost(hostHeader, {
|
|
82
|
+
port: operatorPort,
|
|
83
|
+
host: operator.host,
|
|
84
|
+
allowNonLoopback: false,
|
|
85
|
+
...(operator.allowedHosts ? { allowedHosts: operator.allowedHosts } : {}),
|
|
86
|
+
})
|
|
87
|
+
: isAllowedRequestHost(hostHeader, {
|
|
88
|
+
port: listenPort,
|
|
89
|
+
host: config.host,
|
|
90
|
+
allowNonLoopback: config.allowNonLoopback,
|
|
91
|
+
...(containerListen ? { allowedHosts: containerListen.allowedHosts } : {}),
|
|
92
|
+
});
|
|
93
|
+
/** Responses not yet finished; shutdown ends the streams among them. */
|
|
94
|
+
const inFlight = new Set();
|
|
95
|
+
const serve = (role) => {
|
|
96
|
+
const next = pipeline(role);
|
|
97
|
+
return (req, res) => {
|
|
98
|
+
const started = Date.now();
|
|
99
|
+
inFlight.add(res);
|
|
100
|
+
res.once("close", () => inFlight.delete(res));
|
|
101
|
+
// D§11: `Host` first, before anything reads the request.
|
|
102
|
+
if (hostAllowed(role, headerValue(req, "host")))
|
|
103
|
+
return void next(req, res);
|
|
104
|
+
sendRejected(res, 421, "host_rejected", "Host header is not an allowed loopback or configured address");
|
|
105
|
+
if (pathnameIsLogged(req.url))
|
|
331
106
|
logger.info("request", {
|
|
332
|
-
status:
|
|
333
|
-
tenantId,
|
|
107
|
+
status: 421,
|
|
334
108
|
durationMs: Date.now() - started,
|
|
335
|
-
path: redactRoutePath(new URL(
|
|
336
|
-
method:
|
|
109
|
+
path: redactRoutePath(new URL(req.url ?? "/", "http://runtime.local").pathname),
|
|
110
|
+
method: req.method,
|
|
337
111
|
});
|
|
338
|
-
|
|
339
|
-
}
|
|
112
|
+
};
|
|
340
113
|
};
|
|
114
|
+
/** Binds `listening`; once bound, a listener error is logged rather than lost. */
|
|
115
|
+
const bindListener = (listening, port, host) => bind(listening, port, host, (error) => logger.error("listener_error", { error: error.message }));
|
|
341
116
|
async function listen() {
|
|
342
117
|
if (server)
|
|
343
118
|
throw new Error("Already listening");
|
|
@@ -348,27 +123,37 @@ export function createHost(options) {
|
|
|
348
123
|
!isLoopbackHost(config.host)) {
|
|
349
124
|
throw new HostListenError(`Refusing to bind non-loopback host ${config.host} without allowNonLoopback`, EXIT_NON_LOOPBACK);
|
|
350
125
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
await
|
|
355
|
-
server.once("error", (error) => {
|
|
356
|
-
if (error.code === "EADDRINUSE") {
|
|
357
|
-
reject(new HostListenError(`Port ${bindPort} on ${bindHost} is already in use`, EXIT_PORT_IN_USE, error));
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
reject(error);
|
|
361
|
-
});
|
|
362
|
-
server.listen(bindPort, bindHost, resolve);
|
|
363
|
-
});
|
|
126
|
+
if (operator && !containerListen && !isLoopbackHost(operator.host))
|
|
127
|
+
throw new HostListenError(`Refusing to bind the operator listener on non-loopback host ${operator.host}`, EXIT_NON_LOOPBACK);
|
|
128
|
+
server = createServer(serve(mainRole));
|
|
129
|
+
await bindListener(server, bindPort, bindHost);
|
|
364
130
|
const address = server.address();
|
|
365
131
|
listenPort =
|
|
366
132
|
typeof address === "object" && address ? address.port : bindPort;
|
|
367
133
|
url = `http://${bindHost}:${listenPort}`;
|
|
134
|
+
adminUrl = url;
|
|
135
|
+
if (operator) {
|
|
136
|
+
operatorServer = createServer(serve("operator"));
|
|
137
|
+
await bindListener(operatorServer, operator.port, operator.host).catch(async (error) => {
|
|
138
|
+
// Leave nothing half-open: the main listener closes too.
|
|
139
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
140
|
+
server = undefined;
|
|
141
|
+
throw error;
|
|
142
|
+
});
|
|
143
|
+
const operatorAddress = operatorServer.address();
|
|
144
|
+
operatorPort =
|
|
145
|
+
typeof operatorAddress === "object" && operatorAddress
|
|
146
|
+
? operatorAddress.port
|
|
147
|
+
: operator.port;
|
|
148
|
+
adminUrl = `http://${operator.host}:${operatorPort}`;
|
|
149
|
+
}
|
|
150
|
+
// The Tenant opens once the listener is bound: `/ready` and `/v1/admin/status` answer
|
|
151
|
+
// while it opens, and say why when it cannot.
|
|
368
152
|
await module.start();
|
|
369
153
|
logger.info("host_listening", {
|
|
370
154
|
hostId: config.hostId,
|
|
371
155
|
url,
|
|
156
|
+
...(operator ? { adminUrl } : {}),
|
|
372
157
|
pid,
|
|
373
158
|
});
|
|
374
159
|
}
|
|
@@ -393,13 +178,40 @@ export function createHost(options) {
|
|
|
393
178
|
closePromise = (async () => {
|
|
394
179
|
closing = true;
|
|
395
180
|
logger.info("host_shutdown", { hostId: config.hostId });
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
181
|
+
const listeners = [server, operatorServer].filter((listening) => listening !== undefined);
|
|
182
|
+
const stopped = Promise.all(listeners.map((listening) => new Promise((resolve) => {
|
|
183
|
+
listening.close(() => resolve());
|
|
184
|
+
listening.closeIdleConnections();
|
|
185
|
+
})));
|
|
186
|
+
// A stream never finishes by itself, and a listener closes only once every connection
|
|
187
|
+
// has: end the streams, close their connections once idle, let other requests finish,
|
|
188
|
+
// then cut what is left.
|
|
189
|
+
const streams = [...inFlight].filter(isStreaming);
|
|
190
|
+
void Promise.all(streams.map((response) => {
|
|
191
|
+
const done = new Promise((resolve) => response.once("close", resolve));
|
|
192
|
+
response.end();
|
|
193
|
+
return done;
|
|
194
|
+
})).then(() => {
|
|
195
|
+
for (const listening of listeners)
|
|
196
|
+
listening.closeIdleConnections();
|
|
197
|
+
});
|
|
198
|
+
let grace;
|
|
199
|
+
const graceful = await Promise.race([
|
|
200
|
+
stopped.then(() => true),
|
|
201
|
+
new Promise((resolve) => {
|
|
202
|
+
grace = setTimeout(() => resolve(false), SHUTDOWN_GRACE_MS);
|
|
203
|
+
grace.unref();
|
|
204
|
+
}),
|
|
205
|
+
]);
|
|
206
|
+
clearTimeout(grace);
|
|
207
|
+
if (!graceful) {
|
|
208
|
+
logger.warn("host_shutdown_forced", { openResponses: inFlight.size });
|
|
209
|
+
for (const listening of listeners)
|
|
210
|
+
listening.closeAllConnections();
|
|
211
|
+
await stopped;
|
|
212
|
+
}
|
|
213
|
+
server = undefined;
|
|
214
|
+
operatorServer = undefined;
|
|
403
215
|
await step("beforeTenants", options.shutdown?.beforeTenants);
|
|
404
216
|
await step("tenants", () => module.close());
|
|
405
217
|
await step("afterTenants", options.shutdown?.afterTenants);
|
|
@@ -413,11 +225,30 @@ export function createHost(options) {
|
|
|
413
225
|
get url() {
|
|
414
226
|
return url;
|
|
415
227
|
},
|
|
228
|
+
get adminUrl() {
|
|
229
|
+
return adminUrl;
|
|
230
|
+
},
|
|
416
231
|
};
|
|
417
232
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
233
|
+
/**
|
|
234
|
+
* An answer already written to the Node response. `@hono/node-server` skips writing one that
|
|
235
|
+
* says so in its headers, unless it is its own `Response` class, which a process that ran its
|
|
236
|
+
* `serve()` has as the global one: it writes those again. This is never that class.
|
|
237
|
+
*/
|
|
238
|
+
const SENT = {
|
|
239
|
+
status: 200,
|
|
240
|
+
headers: new Headers({ "x-hono-already-sent": "true" }),
|
|
241
|
+
body: null,
|
|
242
|
+
};
|
|
243
|
+
function alreadySent(response) {
|
|
244
|
+
return response.headers.has("x-hono-already-sent") ? SENT : response;
|
|
245
|
+
}
|
|
246
|
+
/** How long shutdown waits for requests in progress before closing their connections. */
|
|
247
|
+
const SHUTDOWN_GRACE_MS = 10_000;
|
|
248
|
+
/**
|
|
249
|
+
* A response that has started and not ended is a stream: JSON answers are written and ended
|
|
250
|
+
* at once. (`getHeader` cannot tell, since streams pass their headers to `writeHead`.)
|
|
251
|
+
*/
|
|
252
|
+
function isStreaming(response) {
|
|
253
|
+
return response.headersSent && !response.writableEnded;
|
|
423
254
|
}
|
package/dist/host/execution.d.ts
CHANGED
|
@@ -1,37 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Host's Durable Session Execution (architecture §6, §12.3, §14.8): one per process,
|
|
3
|
-
*
|
|
3
|
+
* for the Tenant the Host serves.
|
|
4
4
|
*
|
|
5
|
-
* - `tenantExecution` is what the Host passes to
|
|
5
|
+
* - `tenantExecution` is what the Host passes to its Tenant when it opens it
|
|
6
6
|
* (`TenantOpenHooks.execution`): the execution, the `TenantWorkers` registry its handlers
|
|
7
|
-
* dispatch through (with `resolve`
|
|
8
|
-
*
|
|
9
|
-
* - `start` serves the Worker endpoint
|
|
10
|
-
* nothing for
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* - `
|
|
7
|
+
* dispatch through (with `resolve` waiting for the Tenant when an invocation arrives while
|
|
8
|
+
* it opens), and the Tenant status hook for stuck invocations.
|
|
9
|
+
* - `start` serves the Worker endpoint when the process runs loop (`infra/workers.ts`), and does
|
|
10
|
+
* nothing for a core-only process, whose wakes, timers and sweep arming go through Restate's
|
|
11
|
+
* ingress.
|
|
12
|
+
* - `armAll` arms the listed Tenants' sweeps (tests, recovery). Arming is idempotent; opening
|
|
13
|
+
* the Tenant arms its own at every start, which is what recovers from lost Restate state:
|
|
14
|
+
* the sweep re-wakes `runnable` sessions without a live owner (§14.8).
|
|
15
|
+
* - `disarm` stops a Tenant's sweep.
|
|
15
16
|
*
|
|
16
|
-
* **Order at startup.** Call `start` before opening
|
|
17
|
+
* **Order at startup.** Call `start` before opening the Tenant. Opening the Tenant arms its
|
|
17
18
|
* sweep through Restate's ingress, which answers 404 until a Worker has registered the
|
|
18
|
-
* services, so the open would fail.
|
|
19
|
+
* services, so the open would fail. A core-only process relies on a Worker having registered
|
|
19
20
|
* them first.
|
|
20
21
|
*
|
|
21
22
|
* **One Worker URL.** `start` registers the Worker endpoint (`NYLORUN_WORKER_URL`) with
|
|
22
23
|
* Restate once. Restate sends new invocations to the latest registered deployment, so
|
|
23
24
|
* several Workers that each register their own URL do not share load: the last one to start
|
|
24
|
-
* takes every new invocation. The
|
|
25
|
-
* `--
|
|
25
|
+
* takes every new invocation. The local stack runs a single `runtime` container with
|
|
26
|
+
* `--service core,loop`. A deployment with several Worker processes (Helm, Cloud) must advertise one
|
|
26
27
|
* load-balanced `NYLORUN_WORKER_URL` shared by all of them.
|
|
27
28
|
*/
|
|
28
29
|
import type { DurableExecution } from "../execution/types.js";
|
|
29
30
|
import type { Logger } from "../tenant/types.js";
|
|
30
31
|
import { type TenantExecution, type TenantWorker } from "../tenant/worker.js";
|
|
31
|
-
import type {
|
|
32
|
+
import type { RuntimeServices } from "./stack-config.js";
|
|
32
33
|
export interface CreateHostExecutionOptions {
|
|
33
34
|
execution: DurableExecution;
|
|
34
|
-
|
|
35
|
+
/** The services this process runs: it serves the Worker endpoint when they include loop. */
|
|
36
|
+
services: RuntimeServices;
|
|
35
37
|
/** Finds or opens a Tenant an invocation arrived for that is not open on this process. */
|
|
36
38
|
resolve: (tenantId: string) => Promise<TenantWorker | undefined>;
|
|
37
39
|
logger?: Logger;
|
|
@@ -44,9 +46,9 @@ export interface CreateHostExecutionOptions {
|
|
|
44
46
|
advanceGraceMs?: number;
|
|
45
47
|
}
|
|
46
48
|
export interface HostExecution {
|
|
47
|
-
/** Pass to
|
|
49
|
+
/** Pass to the Tenant the Host opens (`TenantOpenHooks.execution`). */
|
|
48
50
|
readonly tenantExecution: TenantExecution;
|
|
49
|
-
/** Serves the Worker endpoint
|
|
51
|
+
/** Serves the Worker endpoint when the process runs loop. Idempotent. */
|
|
50
52
|
start(): Promise<void>;
|
|
51
53
|
/** Stops serving: aborts running advances and waits for them. Idempotent. */
|
|
52
54
|
stop(): Promise<void>;
|
package/dist/host/execution.js
CHANGED
|
@@ -3,7 +3,7 @@ import { TenantWorkers, } from "../tenant/worker.js";
|
|
|
3
3
|
/** How many sweep arms `armAll` sends at once. */
|
|
4
4
|
const ARM_CONCURRENCY = 16;
|
|
5
5
|
export function createHostExecution(options) {
|
|
6
|
-
const { execution,
|
|
6
|
+
const { execution, services, logger } = options;
|
|
7
7
|
const workers = new TenantWorkers({
|
|
8
8
|
resolve: options.resolve,
|
|
9
9
|
...(options.advanceDeadlineMs !== undefined
|
|
@@ -27,7 +27,7 @@ export function createHostExecution(options) {
|
|
|
27
27
|
return {
|
|
28
28
|
tenantExecution,
|
|
29
29
|
async start() {
|
|
30
|
-
started ??= startWorker({
|
|
30
|
+
started ??= startWorker({ services, execution, handlers: workers.handlers });
|
|
31
31
|
try {
|
|
32
32
|
await started;
|
|
33
33
|
}
|