@smithers-orchestrator/server 0.17.0 → 0.18.0
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/package.json +14 -14
- package/src/GatewayOptions.ts +2 -0
- package/src/GatewayRegisterOptions.ts +8 -0
- package/src/GatewayUiConfig.ts +20 -0
- package/src/gateway.js +347 -2
- package/src/gatewayUi/createGatewayUiApp.js +47 -0
- package/src/index.d.ts +271 -47
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smithers-orchestrator/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "HTTP, WebSocket, gateway, cron, webhook, and metrics servers for Smithers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -26,28 +26,28 @@
|
|
|
26
26
|
"effect": "^3.21.1",
|
|
27
27
|
"hono": "^4.12.14",
|
|
28
28
|
"ws": "^8.20.0",
|
|
29
|
-
"@smithers-orchestrator/db": "0.
|
|
30
|
-
"@smithers-orchestrator/
|
|
31
|
-
"@smithers-orchestrator/
|
|
32
|
-
"@smithers-orchestrator/errors": "0.
|
|
33
|
-
"@smithers-orchestrator/components": "0.
|
|
34
|
-
"@smithers-orchestrator/
|
|
35
|
-
"@smithers-orchestrator/
|
|
36
|
-
"@smithers-orchestrator/
|
|
37
|
-
"@smithers-orchestrator/protocol": "0.
|
|
38
|
-
"@smithers-orchestrator/scheduler": "0.
|
|
39
|
-
"@smithers-orchestrator/time-travel": "0.
|
|
29
|
+
"@smithers-orchestrator/db": "0.18.0",
|
|
30
|
+
"@smithers-orchestrator/devtools": "0.18.0",
|
|
31
|
+
"@smithers-orchestrator/engine": "0.18.0",
|
|
32
|
+
"@smithers-orchestrator/errors": "0.18.0",
|
|
33
|
+
"@smithers-orchestrator/components": "0.18.0",
|
|
34
|
+
"@smithers-orchestrator/driver": "0.18.0",
|
|
35
|
+
"@smithers-orchestrator/observability": "0.18.0",
|
|
36
|
+
"@smithers-orchestrator/gateway": "0.18.0",
|
|
37
|
+
"@smithers-orchestrator/protocol": "0.18.0",
|
|
38
|
+
"@smithers-orchestrator/scheduler": "0.18.0",
|
|
39
|
+
"@smithers-orchestrator/time-travel": "0.18.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/bun": "latest",
|
|
43
43
|
"react": "^19.2.5",
|
|
44
44
|
"typescript": "~5.9.3",
|
|
45
45
|
"zod": "^4.3.6",
|
|
46
|
-
"@smithers-orchestrator/graph": "0.
|
|
46
|
+
"@smithers-orchestrator/graph": "0.18.0"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"test": "bun test tests",
|
|
50
50
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
51
|
-
"build": "tsup --dts-only"
|
|
51
|
+
"build": "rm -f src/index.d.ts && node ../../node_modules/tsup/dist/cli-default.js --dts-only"
|
|
52
52
|
}
|
|
53
53
|
}
|
package/src/GatewayOptions.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { GatewayAuthConfig } from "./GatewayAuthConfig.js";
|
|
2
2
|
import type { GatewayDefaults } from "./GatewayDefaults.js";
|
|
3
|
+
import type { GatewayUiConfig } from "./GatewayUiConfig.js";
|
|
3
4
|
|
|
4
5
|
export type GatewayOptions = {
|
|
5
6
|
protocol?: number;
|
|
6
7
|
features?: string[];
|
|
7
8
|
heartbeatMs?: number;
|
|
8
9
|
auth?: GatewayAuthConfig;
|
|
10
|
+
ui?: GatewayUiConfig;
|
|
9
11
|
defaults?: GatewayDefaults;
|
|
10
12
|
maxBodyBytes?: number;
|
|
11
13
|
maxPayload?: number;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type GatewayUiConfig = {
|
|
2
|
+
/**
|
|
3
|
+
* Browser entry module for the React app. Smithers bundles this with Bun and
|
|
4
|
+
* serves it from the Gateway origin.
|
|
5
|
+
*/
|
|
6
|
+
entry: string;
|
|
7
|
+
/**
|
|
8
|
+
* URL path where the UI is mounted. Gateway-level UI defaults to `/`;
|
|
9
|
+
* workflow-level UI defaults to `/workflows/<workflowKey>`.
|
|
10
|
+
*/
|
|
11
|
+
path?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Document title for the generated HTML shell.
|
|
14
|
+
*/
|
|
15
|
+
title?: string;
|
|
16
|
+
/**
|
|
17
|
+
* JSON-serializable boot data exposed to the browser.
|
|
18
|
+
*/
|
|
19
|
+
props?: Record<string, unknown>;
|
|
20
|
+
};
|
package/src/gateway.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
// @smithers-type-exports-begin
|
|
2
2
|
/** @typedef {import("./EventFrame.js").EventFrame} EventFrame */
|
|
3
3
|
/** @typedef {import("./GatewayDefaults.js").GatewayDefaults} GatewayDefaults */
|
|
4
|
+
/** @typedef {import("./GatewayRegisterOptions.js").GatewayRegisterOptions} GatewayRegisterOptions */
|
|
4
5
|
/** @typedef {import("./GatewayTokenGrant.js").GatewayTokenGrant} GatewayTokenGrant */
|
|
6
|
+
/** @typedef {import("./GatewayUiConfig.js").GatewayUiConfig} GatewayUiConfig */
|
|
5
7
|
/** @typedef {import("./HelloResponse.js").HelloResponse} HelloResponse */
|
|
6
8
|
// @smithers-type-exports-end
|
|
7
9
|
|
|
8
10
|
import { createServer } from "node:http";
|
|
9
11
|
import { createHash, createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
|
12
|
+
import { resolve } from "node:path";
|
|
10
13
|
import { CronExpressionParser } from "cron-parser";
|
|
11
14
|
import { Effect, Metric } from "effect";
|
|
12
15
|
import { WebSocketServer } from "ws";
|
|
@@ -36,6 +39,7 @@ import { writeRewindAuditRow } from "@smithers-orchestrator/time-travel/writeRew
|
|
|
36
39
|
import { recoverInProgressRewindAudits } from "@smithers-orchestrator/time-travel/recoverInProgressRewindAudits";
|
|
37
40
|
import { GATEWAY_EVENT_WINDOW_DEFAULT, SMITHERS_API_VERSION, getRequiredScopeForGatewayMethod, } from "@smithers-orchestrator/gateway/rpc";
|
|
38
41
|
import { hasGatewayScope } from "@smithers-orchestrator/gateway/auth/scopes";
|
|
42
|
+
import { createGatewayUiApp } from "./gatewayUi/createGatewayUiApp.js";
|
|
39
43
|
/** @typedef {import("./GatewayWebhookRunConfig.js").GatewayWebhookRunConfig} GatewayWebhookRunConfig */
|
|
40
44
|
/** @typedef {import("./GatewayWebhookSignalConfig.js").GatewayWebhookSignalConfig} GatewayWebhookSignalConfig */
|
|
41
45
|
/** @typedef {import("./ConnectRequest.js").ConnectRequest} ConnectRequest */
|
|
@@ -90,6 +94,7 @@ import { hasGatewayScope } from "@smithers-orchestrator/gateway/auth/scopes";
|
|
|
90
94
|
* key: string;
|
|
91
95
|
* schedule?: string;
|
|
92
96
|
* webhook?: GatewayWebhookConfig;
|
|
97
|
+
* ui?: ResolvedGatewayUiConfig | null;
|
|
93
98
|
* }} RegisteredWorkflow
|
|
94
99
|
*/
|
|
95
100
|
/**
|
|
@@ -100,6 +105,21 @@ import { hasGatewayScope } from "@smithers-orchestrator/gateway/auth/scopes";
|
|
|
100
105
|
* adapter: SmithersDb;
|
|
101
106
|
* }} ResolvedRun
|
|
102
107
|
*/
|
|
108
|
+
/**
|
|
109
|
+
* @typedef {{
|
|
110
|
+
* entry: string;
|
|
111
|
+
* path: string;
|
|
112
|
+
* title?: string;
|
|
113
|
+
* props?: Record<string, unknown>;
|
|
114
|
+
* }} ResolvedGatewayUiConfig
|
|
115
|
+
*/
|
|
116
|
+
/**
|
|
117
|
+
* @typedef {{
|
|
118
|
+
* kind: "gateway" | "workflow";
|
|
119
|
+
* workflowKey: string | null;
|
|
120
|
+
* config: ResolvedGatewayUiConfig;
|
|
121
|
+
* }} GatewayUiMount
|
|
122
|
+
*/
|
|
103
123
|
|
|
104
124
|
const DEFAULT_PROTOCOL = 1;
|
|
105
125
|
const DEFAULT_HEARTBEAT_MS = 15_000;
|
|
@@ -117,6 +137,115 @@ export const GATEWAY_FRAME_ID_MAX_LENGTH = 128;
|
|
|
117
137
|
export const GATEWAY_RPC_INPUT_MAX_BYTES = GATEWAY_RPC_MAX_PAYLOAD_BYTES;
|
|
118
138
|
export const GATEWAY_RPC_INPUT_MAX_DEPTH = GATEWAY_RPC_MAX_DEPTH;
|
|
119
139
|
const GATEWAY_METHOD_NAME_PATTERN = /^[a-z][a-zA-Z0-9]*(?:\.[a-z][a-zA-Z0-9]*)*$/;
|
|
140
|
+
const GATEWAY_UI_ASSET_PREFIX = "__smithers_ui";
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @param {string} value
|
|
144
|
+
* @returns {string}
|
|
145
|
+
*/
|
|
146
|
+
function escapeHtml(value) {
|
|
147
|
+
return value
|
|
148
|
+
.replaceAll("&", "&")
|
|
149
|
+
.replaceAll("<", "<")
|
|
150
|
+
.replaceAll(">", ">")
|
|
151
|
+
.replaceAll('"', """);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @param {unknown} value
|
|
156
|
+
* @returns {string}
|
|
157
|
+
*/
|
|
158
|
+
function safeJsonScript(value) {
|
|
159
|
+
return JSON.stringify(value).replaceAll("<", "\\u003c");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @param {string | undefined} rawPath
|
|
164
|
+
* @param {string} fallbackPath
|
|
165
|
+
* @returns {string}
|
|
166
|
+
*/
|
|
167
|
+
function normalizeUiMountPath(rawPath, fallbackPath) {
|
|
168
|
+
const candidate = (rawPath && rawPath.trim()) || fallbackPath;
|
|
169
|
+
const withSlash = candidate.startsWith("/") ? candidate : `/${candidate}`;
|
|
170
|
+
const withoutTrailing = withSlash.length > 1 ? withSlash.replace(/\/+$/, "") : withSlash;
|
|
171
|
+
if (!/^\/[A-Za-z0-9/_:.-]*$/.test(withoutTrailing)) {
|
|
172
|
+
throw new SmithersError("INVALID_INPUT", `Gateway UI path is invalid: ${candidate}`);
|
|
173
|
+
}
|
|
174
|
+
return withoutTrailing;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @param {string} mountPath
|
|
179
|
+
* @param {string} suffix
|
|
180
|
+
* @returns {string}
|
|
181
|
+
*/
|
|
182
|
+
function joinUiPath(mountPath, suffix) {
|
|
183
|
+
if (mountPath === "/") {
|
|
184
|
+
return `/${suffix.replace(/^\/+/, "")}`;
|
|
185
|
+
}
|
|
186
|
+
return `${mountPath}/${suffix.replace(/^\/+/, "")}`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @param {GatewayUiConfig | undefined} ui
|
|
191
|
+
* @param {string} fallbackPath
|
|
192
|
+
* @returns {ResolvedGatewayUiConfig | null}
|
|
193
|
+
*/
|
|
194
|
+
function resolveGatewayUiConfig(ui, fallbackPath) {
|
|
195
|
+
if (!ui) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
if (typeof ui.entry !== "string" || !ui.entry.trim()) {
|
|
199
|
+
throw new SmithersError("INVALID_INPUT", "Gateway UI config requires a non-empty entry path.");
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
entry: resolve(process.cwd(), ui.entry),
|
|
203
|
+
path: normalizeUiMountPath(ui.path, fallbackPath),
|
|
204
|
+
...(typeof ui.title === "string" ? { title: ui.title } : {}),
|
|
205
|
+
...(ui.props && typeof ui.props === "object" && !Array.isArray(ui.props)
|
|
206
|
+
? { props: ui.props }
|
|
207
|
+
: {}),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @param {import("node:http").IncomingHttpHeaders} headers
|
|
213
|
+
* @returns {Headers}
|
|
214
|
+
*/
|
|
215
|
+
function nodeHeadersToFetchHeaders(headers) {
|
|
216
|
+
const out = new Headers();
|
|
217
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
218
|
+
if (value === undefined) {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (Array.isArray(value)) {
|
|
222
|
+
for (const entry of value) {
|
|
223
|
+
out.append(key, entry);
|
|
224
|
+
}
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
out.set(key, value);
|
|
228
|
+
}
|
|
229
|
+
return out;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @param {ServerResponse} res
|
|
234
|
+
* @param {Response} response
|
|
235
|
+
* @param {boolean} headOnly
|
|
236
|
+
*/
|
|
237
|
+
async function writeFetchResponse(res, response, headOnly = false) {
|
|
238
|
+
res.statusCode = response.status;
|
|
239
|
+
response.headers.forEach((value, key) => {
|
|
240
|
+
res.setHeader(key, value);
|
|
241
|
+
});
|
|
242
|
+
if (headOnly) {
|
|
243
|
+
res.end();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const body = Buffer.from(await response.arrayBuffer());
|
|
247
|
+
res.end(body);
|
|
248
|
+
}
|
|
120
249
|
/**
|
|
121
250
|
* @template T
|
|
122
251
|
* @param {string | null | undefined} value
|
|
@@ -1054,6 +1183,8 @@ export class Gateway {
|
|
|
1054
1183
|
headersTimeout;
|
|
1055
1184
|
requestTimeout;
|
|
1056
1185
|
auth;
|
|
1186
|
+
ui;
|
|
1187
|
+
uiApp;
|
|
1057
1188
|
defaults;
|
|
1058
1189
|
workflows = new Map();
|
|
1059
1190
|
connections = new Set();
|
|
@@ -1066,6 +1197,7 @@ export class Gateway {
|
|
|
1066
1197
|
devtoolsSubscriberCounts = new Map();
|
|
1067
1198
|
/** Flagged subscriber IDs that should force a snapshot on their next emit. */
|
|
1068
1199
|
devtoolsInvalidateFlags = new Set();
|
|
1200
|
+
uiAssetCache = new Map();
|
|
1069
1201
|
server = null;
|
|
1070
1202
|
wsServer = null;
|
|
1071
1203
|
schedulerTimer = null;
|
|
@@ -1097,8 +1229,193 @@ export class Gateway {
|
|
|
1097
1229
|
? DEFAULT_REQUEST_TIMEOUT
|
|
1098
1230
|
: Math.floor(assertPositiveFiniteInteger("requestTimeout", Number(options.requestTimeout)));
|
|
1099
1231
|
this.auth = options.auth;
|
|
1232
|
+
this.ui = resolveGatewayUiConfig(options.ui, "/");
|
|
1233
|
+
this.uiApp = createGatewayUiApp({
|
|
1234
|
+
resolveMatch: (pathname) => this.resolveUiMatch(pathname),
|
|
1235
|
+
renderIndex: (match) => this.renderUiIndex(match),
|
|
1236
|
+
renderAsset: (match) => this.renderUiAsset(match),
|
|
1237
|
+
});
|
|
1100
1238
|
this.defaults = options.defaults;
|
|
1101
1239
|
}
|
|
1240
|
+
/**
|
|
1241
|
+
* @returns {GatewayUiMount[]}
|
|
1242
|
+
*/
|
|
1243
|
+
getUiMounts() {
|
|
1244
|
+
const mounts = [];
|
|
1245
|
+
if (this.ui) {
|
|
1246
|
+
mounts.push({ kind: "gateway", workflowKey: null, config: this.ui });
|
|
1247
|
+
}
|
|
1248
|
+
for (const [workflowKey, entry] of this.workflows.entries()) {
|
|
1249
|
+
if (entry.ui) {
|
|
1250
|
+
mounts.push({ kind: "workflow", workflowKey, config: entry.ui });
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
return mounts.sort((left, right) => right.config.path.length - left.config.path.length);
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* @param {string} pathname
|
|
1257
|
+
* @returns {GatewayUiMount | null}
|
|
1258
|
+
*/
|
|
1259
|
+
findUiMount(pathname) {
|
|
1260
|
+
for (const mount of this.getUiMounts()) {
|
|
1261
|
+
const mountPath = mount.config.path;
|
|
1262
|
+
if (mountPath === "/" || pathname === mountPath || pathname.startsWith(`${mountPath}/`)) {
|
|
1263
|
+
return mount;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
return null;
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* @param {string} pathname
|
|
1270
|
+
*/
|
|
1271
|
+
resolveUiMatch(pathname) {
|
|
1272
|
+
const mount = this.findUiMount(pathname);
|
|
1273
|
+
if (!mount) {
|
|
1274
|
+
return null;
|
|
1275
|
+
}
|
|
1276
|
+
const assetBase = joinUiPath(mount.config.path, `${GATEWAY_UI_ASSET_PREFIX}/`);
|
|
1277
|
+
const assetPath = pathname.startsWith(assetBase)
|
|
1278
|
+
? pathname.slice(assetBase.length)
|
|
1279
|
+
: null;
|
|
1280
|
+
return {
|
|
1281
|
+
pathname,
|
|
1282
|
+
mountPath: mount.config.path,
|
|
1283
|
+
assetPath,
|
|
1284
|
+
config: mount,
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* @param {GatewayUiMount} mount
|
|
1289
|
+
*/
|
|
1290
|
+
uiBootConfig(mount) {
|
|
1291
|
+
return {
|
|
1292
|
+
apiVersion: SMITHERS_API_VERSION,
|
|
1293
|
+
kind: mount.kind,
|
|
1294
|
+
workflowKey: mount.workflowKey,
|
|
1295
|
+
mountPath: mount.config.path,
|
|
1296
|
+
rpcPath: "/v1/rpc",
|
|
1297
|
+
wsPath: "/",
|
|
1298
|
+
assetBasePath: joinUiPath(mount.config.path, `${GATEWAY_UI_ASSET_PREFIX}/`),
|
|
1299
|
+
props: mount.config.props ?? {},
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* @param {{ config: GatewayUiMount }} match
|
|
1304
|
+
*/
|
|
1305
|
+
renderUiIndex(match) {
|
|
1306
|
+
const mount = match.config;
|
|
1307
|
+
const title = mount.config.title ?? (mount.workflowKey ? `${mount.workflowKey} | Smithers` : "Smithers");
|
|
1308
|
+
const boot = this.uiBootConfig(mount);
|
|
1309
|
+
const assetSrc = joinUiPath(mount.config.path, `${GATEWAY_UI_ASSET_PREFIX}/client.js`);
|
|
1310
|
+
return `<!doctype html>
|
|
1311
|
+
<html lang="en">
|
|
1312
|
+
<head>
|
|
1313
|
+
<meta charset="utf-8">
|
|
1314
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1315
|
+
<title>${escapeHtml(title)}</title>
|
|
1316
|
+
</head>
|
|
1317
|
+
<body>
|
|
1318
|
+
<div id="root"></div>
|
|
1319
|
+
<script>globalThis.__SMITHERS_GATEWAY_UI__=${safeJsonScript(boot)};</script>
|
|
1320
|
+
<script type="module" src="${escapeHtml(assetSrc)}"></script>
|
|
1321
|
+
</body>
|
|
1322
|
+
</html>`;
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* @param {{ config: GatewayUiMount; assetPath: string | null }} match
|
|
1326
|
+
*/
|
|
1327
|
+
async renderUiAsset(match) {
|
|
1328
|
+
if (match.assetPath !== "client.js") {
|
|
1329
|
+
return null;
|
|
1330
|
+
}
|
|
1331
|
+
const body = await this.bundleUiEntry(match.config.config);
|
|
1332
|
+
return {
|
|
1333
|
+
body,
|
|
1334
|
+
contentType: "text/javascript; charset=utf-8",
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* @param {ResolvedGatewayUiConfig} config
|
|
1339
|
+
* @returns {Promise<string>}
|
|
1340
|
+
*/
|
|
1341
|
+
async bundleUiEntry(config) {
|
|
1342
|
+
const cached = this.uiAssetCache.get(config.entry);
|
|
1343
|
+
if (cached) {
|
|
1344
|
+
return cached;
|
|
1345
|
+
}
|
|
1346
|
+
if (typeof Bun === "undefined" || typeof Bun.build !== "function") {
|
|
1347
|
+
throw new SmithersError("INVALID_INPUT", "Gateway UI bundling requires Bun.build.");
|
|
1348
|
+
}
|
|
1349
|
+
const result = await Bun.build({
|
|
1350
|
+
entrypoints: [config.entry],
|
|
1351
|
+
root: process.cwd(),
|
|
1352
|
+
target: "browser",
|
|
1353
|
+
format: "esm",
|
|
1354
|
+
sourcemap: "inline",
|
|
1355
|
+
minify: false,
|
|
1356
|
+
jsx: {
|
|
1357
|
+
runtime: "automatic",
|
|
1358
|
+
importSource: "react",
|
|
1359
|
+
},
|
|
1360
|
+
});
|
|
1361
|
+
if (!result.success) {
|
|
1362
|
+
const message = result.logs?.map((entry) => entry.message).filter(Boolean).join("\n")
|
|
1363
|
+
|| `Failed to build Gateway UI entry ${config.entry}`;
|
|
1364
|
+
throw new SmithersError("INVALID_INPUT", message);
|
|
1365
|
+
}
|
|
1366
|
+
const output = result.outputs.find((entry) => entry.path.endsWith(".js")) ?? result.outputs[0];
|
|
1367
|
+
const body = await output.text();
|
|
1368
|
+
this.uiAssetCache.set(config.entry, body);
|
|
1369
|
+
return body;
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* @param {IncomingMessage} req
|
|
1373
|
+
* @param {ServerResponse} res
|
|
1374
|
+
*/
|
|
1375
|
+
async handleUiHttp(req, res) {
|
|
1376
|
+
if ((req.method ?? "GET") !== "GET" && (req.method ?? "GET") !== "HEAD") {
|
|
1377
|
+
return false;
|
|
1378
|
+
}
|
|
1379
|
+
const host = headerValue(req, "host") ?? "127.0.0.1";
|
|
1380
|
+
const request = new Request(`http://${host}${req.url ?? "/"}`, {
|
|
1381
|
+
method: "GET",
|
|
1382
|
+
headers: nodeHeadersToFetchHeaders(req.headers),
|
|
1383
|
+
});
|
|
1384
|
+
const response = await this.uiApp.fetch(request);
|
|
1385
|
+
if (response.status === 404 && response.headers.get("x-smithers-ui-miss") === "1") {
|
|
1386
|
+
return false;
|
|
1387
|
+
}
|
|
1388
|
+
await writeFetchResponse(res, response, (req.method ?? "GET") === "HEAD");
|
|
1389
|
+
return true;
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* @param {string} key
|
|
1393
|
+
* @param {RegisteredWorkflow} entry
|
|
1394
|
+
*/
|
|
1395
|
+
workflowSummary(key, entry) {
|
|
1396
|
+
return {
|
|
1397
|
+
key,
|
|
1398
|
+
...(entry.workflow.readableName ? { readableName: entry.workflow.readableName } : {}),
|
|
1399
|
+
...(entry.workflow.description ? { description: entry.workflow.description } : {}),
|
|
1400
|
+
hasUi: Boolean(entry.ui),
|
|
1401
|
+
uiPath: entry.ui?.path ?? null,
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* @param {boolean | undefined} hasUi
|
|
1406
|
+
*/
|
|
1407
|
+
listWorkflowSummaries(hasUi) {
|
|
1408
|
+
const rows = [];
|
|
1409
|
+
for (const [key, entry] of this.workflows.entries()) {
|
|
1410
|
+
const summary = this.workflowSummary(key, entry);
|
|
1411
|
+
if (hasUi !== undefined && summary.hasUi !== hasUi) {
|
|
1412
|
+
continue;
|
|
1413
|
+
}
|
|
1414
|
+
rows.push(summary);
|
|
1415
|
+
}
|
|
1416
|
+
rows.sort((left, right) => left.key.localeCompare(right.key));
|
|
1417
|
+
return rows;
|
|
1418
|
+
}
|
|
1102
1419
|
authModeLabel() {
|
|
1103
1420
|
return gatewayAuthMode(this.auth);
|
|
1104
1421
|
}
|
|
@@ -1770,16 +2087,18 @@ export class Gateway {
|
|
|
1770
2087
|
/**
|
|
1771
2088
|
* @param {string} key
|
|
1772
2089
|
* @param {SmithersWorkflow} workflow
|
|
1773
|
-
* @param {
|
|
2090
|
+
* @param {GatewayRegisterOptions} [options]
|
|
1774
2091
|
* @returns {this}
|
|
1775
2092
|
*/
|
|
1776
2093
|
register(key, workflow, options) {
|
|
1777
2094
|
ensureSmithersTables(workflow.db);
|
|
2095
|
+
const ui = resolveGatewayUiConfig(options?.ui, `/workflows/${encodeURIComponent(key)}`);
|
|
1778
2096
|
this.workflows.set(key, {
|
|
1779
2097
|
key,
|
|
1780
2098
|
workflow,
|
|
1781
2099
|
schedule: options?.schedule,
|
|
1782
2100
|
webhook: options?.webhook,
|
|
2101
|
+
ui,
|
|
1783
2102
|
});
|
|
1784
2103
|
// Startup recovery: any audit row left in `in_progress` from a prior
|
|
1785
2104
|
// crash is flipped to `partial` and the associated run is flagged as
|
|
@@ -1832,6 +2151,9 @@ export class Gateway {
|
|
|
1832
2151
|
if ((req.method ?? "GET") === "POST" && (req.url ?? "/") === "/rpc") {
|
|
1833
2152
|
return this.handleHttpRpc(req, res);
|
|
1834
2153
|
}
|
|
2154
|
+
if (await this.handleUiHttp(req, res)) {
|
|
2155
|
+
return;
|
|
2156
|
+
}
|
|
1835
2157
|
return sendJson(res, 404, { error: { code: "NOT_FOUND", message: "Route not found" } });
|
|
1836
2158
|
});
|
|
1837
2159
|
server.headersTimeout = this.headersTimeout;
|
|
@@ -2698,6 +3020,7 @@ export class Gateway {
|
|
|
2698
3020
|
const request = parseApprovalRequest(parseJson(approval.requestJson), node?.label ?? approval.nodeId);
|
|
2699
3021
|
approvals.push({
|
|
2700
3022
|
runId: approval.runId,
|
|
3023
|
+
workflowKey: entry.key,
|
|
2701
3024
|
nodeId: approval.nodeId,
|
|
2702
3025
|
iteration: approval.iteration ?? 0,
|
|
2703
3026
|
requestTitle: request.title ?? node?.label ?? approval.nodeId,
|
|
@@ -2945,6 +3268,12 @@ export class Gateway {
|
|
|
2945
3268
|
const status = asString(params.status) ?? asString(filter.status);
|
|
2946
3269
|
return responseOk(frame.id, await this.listRunsAcrossWorkflows(limit, status));
|
|
2947
3270
|
}
|
|
3271
|
+
case "workflows.list":
|
|
3272
|
+
case "listWorkflows": {
|
|
3273
|
+
const filter = asObject(params.filter) ?? {};
|
|
3274
|
+
const hasUi = asBoolean(params.hasUi) ?? asBoolean(filter.hasUi);
|
|
3275
|
+
return responseOk(frame.id, this.listWorkflowSummaries(hasUi));
|
|
3276
|
+
}
|
|
2948
3277
|
case "runs.create":
|
|
2949
3278
|
case "launchRun": {
|
|
2950
3279
|
const workflowKey = asString(params.workflow);
|
|
@@ -3548,7 +3877,23 @@ export class Gateway {
|
|
|
3548
3877
|
return responseOk(frame.id, diffRawSnapshots(leftSnapshot, rightSnapshot));
|
|
3549
3878
|
}
|
|
3550
3879
|
case "approvals.list":
|
|
3551
|
-
|
|
3880
|
+
case "listApprovals": {
|
|
3881
|
+
const filter = asObject(params.filter) ?? {};
|
|
3882
|
+
const runId = asString(params.runId) ?? asString(filter.runId);
|
|
3883
|
+
const workflow = asString(params.workflow) ?? asString(filter.workflow);
|
|
3884
|
+
const limit = asOptionalPositiveInt(params.limit ?? filter.limit, "limit");
|
|
3885
|
+
let approvals = await this.listPendingApprovals();
|
|
3886
|
+
if (runId) {
|
|
3887
|
+
approvals = approvals.filter((approval) => approval.runId === runId);
|
|
3888
|
+
}
|
|
3889
|
+
if (workflow) {
|
|
3890
|
+
approvals = approvals.filter((approval) => approval.workflowKey === workflow);
|
|
3891
|
+
}
|
|
3892
|
+
if (limit !== undefined) {
|
|
3893
|
+
approvals = approvals.slice(0, limit);
|
|
3894
|
+
}
|
|
3895
|
+
return responseOk(frame.id, approvals);
|
|
3896
|
+
}
|
|
3552
3897
|
case "approvals.decide":
|
|
3553
3898
|
case "submitApproval": {
|
|
3554
3899
|
const runId = asString(params.runId);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {{
|
|
5
|
+
* pathname: string;
|
|
6
|
+
* mountPath: string;
|
|
7
|
+
* assetPath: string | null;
|
|
8
|
+
* config: Record<string, unknown>;
|
|
9
|
+
* }} GatewayUiMatch
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {{
|
|
14
|
+
* resolveMatch: (pathname: string) => GatewayUiMatch | null;
|
|
15
|
+
* renderIndex: (match: GatewayUiMatch) => string;
|
|
16
|
+
* renderAsset: (match: GatewayUiMatch) => Promise<{ body: string; contentType: string } | null>;
|
|
17
|
+
* }} options
|
|
18
|
+
*/
|
|
19
|
+
export function createGatewayUiApp(options) {
|
|
20
|
+
const app = new Hono();
|
|
21
|
+
app.get("*", async (c) => {
|
|
22
|
+
const url = new URL(c.req.url);
|
|
23
|
+
const match = options.resolveMatch(url.pathname);
|
|
24
|
+
if (!match) {
|
|
25
|
+
return new Response("Not Found", {
|
|
26
|
+
status: 404,
|
|
27
|
+
headers: { "x-smithers-ui-miss": "1" },
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (match.assetPath) {
|
|
31
|
+
const asset = await options.renderAsset(match);
|
|
32
|
+
if (!asset) {
|
|
33
|
+
return c.text("Not Found", 404);
|
|
34
|
+
}
|
|
35
|
+
return c.body(asset.body, 200, {
|
|
36
|
+
"Content-Type": asset.contentType,
|
|
37
|
+
"Cache-Control": "no-store",
|
|
38
|
+
"X-Content-Type-Options": "nosniff",
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return c.html(options.renderIndex(match), 200, {
|
|
42
|
+
"Cache-Control": "no-store",
|
|
43
|
+
"X-Content-Type-Options": "nosniff",
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
return app;
|
|
47
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _smithers_orchestrator_db_adapter_RunRow from '@smithers-orchestrator/db/adapter/RunRow';
|
|
2
2
|
import * as node_http from 'node:http';
|
|
3
|
-
import
|
|
4
|
-
import * as
|
|
5
|
-
import * as _smithers_components_SmithersWorkflow from '@smithers-orchestrator/components/SmithersWorkflow';
|
|
3
|
+
import * as _smithers_orchestrator_observability_SmithersEvent from '@smithers-orchestrator/observability/SmithersEvent';
|
|
4
|
+
import * as _smithers_orchestrator_components_SmithersWorkflow from '@smithers-orchestrator/components/SmithersWorkflow';
|
|
6
5
|
import { SmithersWorkflow as SmithersWorkflow$1 } from '@smithers-orchestrator/components/SmithersWorkflow';
|
|
6
|
+
import * as hono from 'hono';
|
|
7
|
+
import { Hono } from 'hono';
|
|
8
|
+
import * as hono_types from 'hono/types';
|
|
7
9
|
import { Effect } from 'effect';
|
|
8
|
-
import * as
|
|
10
|
+
import * as _smithers_orchestrator_db_adapter from '@smithers-orchestrator/db/adapter';
|
|
9
11
|
import { SmithersDb as SmithersDb$4 } from '@smithers-orchestrator/db/adapter';
|
|
10
|
-
import * as hono_types from 'hono/types';
|
|
11
|
-
import { Hono } from 'hono';
|
|
12
12
|
import * as effect_Fiber from 'effect/Fiber';
|
|
13
|
-
import * as
|
|
14
|
-
import * as
|
|
15
|
-
import * as
|
|
16
|
-
import * as
|
|
13
|
+
import * as _smithers_orchestrator_protocol_errors from '@smithers-orchestrator/protocol/errors';
|
|
14
|
+
import * as _smithers_orchestrator_devtools_snapshotSerializer from '@smithers-orchestrator/devtools/snapshotSerializer';
|
|
15
|
+
import * as _smithers_orchestrator_protocol_devtools from '@smithers-orchestrator/protocol/devtools';
|
|
16
|
+
import * as _smithers_orchestrator_engine_effect_DiffBundle from '@smithers-orchestrator/engine/effect/DiffBundle';
|
|
17
17
|
import { DiffBundle } from '@smithers-orchestrator/engine/effect/DiffBundle';
|
|
18
18
|
import { selectOutputRow } from '@smithers-orchestrator/db/output';
|
|
19
|
-
import * as
|
|
19
|
+
import * as _smithers_orchestrator_time_travel_jumpToFrame from '@smithers-orchestrator/time-travel/jumpToFrame';
|
|
20
20
|
export { JumpToFrameError } from '@smithers-orchestrator/time-travel/jumpToFrame';
|
|
21
21
|
|
|
22
22
|
type ServerOptions$1 = {
|
|
@@ -26,16 +26,33 @@ type ServerOptions$1 = {
|
|
|
26
26
|
maxBodyBytes?: number;
|
|
27
27
|
rootDir?: string;
|
|
28
28
|
allowNetwork?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Maximum time (in milliseconds) allowed for the HTTP parser to receive the
|
|
31
|
+
* complete headers of a single request. Helps mitigate slowloris attacks.
|
|
32
|
+
* @default 30000
|
|
33
|
+
*/
|
|
34
|
+
headersTimeout?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Maximum time (in milliseconds) allowed for a single request to be received
|
|
37
|
+
* and parsed, including the body. Helps mitigate slowloris attacks.
|
|
38
|
+
* @default 60000
|
|
39
|
+
*/
|
|
40
|
+
requestTimeout?: number;
|
|
29
41
|
};
|
|
30
42
|
|
|
31
43
|
type ResponseFrame$1 = {
|
|
32
44
|
type: "res";
|
|
33
45
|
id: string;
|
|
34
46
|
ok: boolean;
|
|
47
|
+
apiVersion?: "v1";
|
|
35
48
|
payload?: unknown;
|
|
36
49
|
error?: {
|
|
50
|
+
version?: "v1";
|
|
37
51
|
code: string;
|
|
38
52
|
message: string;
|
|
53
|
+
requiredScope?: string;
|
|
54
|
+
refresh?: string;
|
|
55
|
+
details?: unknown;
|
|
39
56
|
};
|
|
40
57
|
};
|
|
41
58
|
|
|
@@ -70,6 +87,10 @@ type GatewayTokenGrant$1 = {
|
|
|
70
87
|
role: string;
|
|
71
88
|
scopes: string[];
|
|
72
89
|
userId?: string;
|
|
90
|
+
tokenId?: string;
|
|
91
|
+
issuedAtMs?: number;
|
|
92
|
+
expiresAtMs?: number;
|
|
93
|
+
revokedAtMs?: number;
|
|
73
94
|
};
|
|
74
95
|
|
|
75
96
|
type GatewayAuthConfig$1 = {
|
|
@@ -98,15 +119,54 @@ type GatewayDefaults$1 = {
|
|
|
98
119
|
cliAgentTools?: "all" | "explicit-only";
|
|
99
120
|
};
|
|
100
121
|
|
|
122
|
+
type GatewayUiConfig$1 = {
|
|
123
|
+
/**
|
|
124
|
+
* Browser entry module for the React app. Smithers bundles this with Bun and
|
|
125
|
+
* serves it from the Gateway origin.
|
|
126
|
+
*/
|
|
127
|
+
entry: string;
|
|
128
|
+
/**
|
|
129
|
+
* URL path where the UI is mounted. Gateway-level UI defaults to `/`;
|
|
130
|
+
* workflow-level UI defaults to `/workflows/<workflowKey>`.
|
|
131
|
+
*/
|
|
132
|
+
path?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Document title for the generated HTML shell.
|
|
135
|
+
*/
|
|
136
|
+
title?: string;
|
|
137
|
+
/**
|
|
138
|
+
* JSON-serializable boot data exposed to the browser.
|
|
139
|
+
*/
|
|
140
|
+
props?: Record<string, unknown>;
|
|
141
|
+
};
|
|
142
|
+
|
|
101
143
|
type GatewayOptions$1 = {
|
|
102
144
|
protocol?: number;
|
|
103
145
|
features?: string[];
|
|
104
146
|
heartbeatMs?: number;
|
|
105
147
|
auth?: GatewayAuthConfig$1;
|
|
148
|
+
ui?: GatewayUiConfig$1;
|
|
106
149
|
defaults?: GatewayDefaults$1;
|
|
107
150
|
maxBodyBytes?: number;
|
|
108
151
|
maxPayload?: number;
|
|
109
152
|
maxConnections?: number;
|
|
153
|
+
/**
|
|
154
|
+
* Per-run replay window for Gateway run event streams.
|
|
155
|
+
* @default 10000
|
|
156
|
+
*/
|
|
157
|
+
eventWindowSize?: number;
|
|
158
|
+
/**
|
|
159
|
+
* Maximum time (in milliseconds) allowed for the HTTP parser to receive the
|
|
160
|
+
* complete headers of a single request. Helps mitigate slowloris attacks.
|
|
161
|
+
* @default 30000
|
|
162
|
+
*/
|
|
163
|
+
headersTimeout?: number;
|
|
164
|
+
/**
|
|
165
|
+
* Maximum time (in milliseconds) allowed for a single request to be received
|
|
166
|
+
* and parsed, including the body. Helps mitigate slowloris attacks.
|
|
167
|
+
* @default 60000
|
|
168
|
+
*/
|
|
169
|
+
requestTimeout?: number;
|
|
110
170
|
};
|
|
111
171
|
|
|
112
172
|
type ConnectRequest$1 = {
|
|
@@ -144,12 +204,19 @@ type HelloResponse$1 = {
|
|
|
144
204
|
};
|
|
145
205
|
};
|
|
146
206
|
|
|
207
|
+
type GatewayRegisterOptions$1 = {
|
|
208
|
+
schedule?: string;
|
|
209
|
+
webhook?: GatewayWebhookConfig$1;
|
|
210
|
+
ui?: GatewayUiConfig$1;
|
|
211
|
+
};
|
|
212
|
+
|
|
147
213
|
type EventFrame$1 = {
|
|
148
214
|
type: "event";
|
|
149
215
|
event: string;
|
|
150
216
|
payload?: unknown;
|
|
151
217
|
seq: number;
|
|
152
218
|
stateVersion: number;
|
|
219
|
+
apiVersion?: "v1";
|
|
153
220
|
};
|
|
154
221
|
|
|
155
222
|
/**
|
|
@@ -175,7 +242,7 @@ declare function assertGatewayInputDepthWithinBounds(value: unknown, maxDepth?:
|
|
|
175
242
|
/**
|
|
176
243
|
* @param {string | undefined} code
|
|
177
244
|
*/
|
|
178
|
-
declare function statusForRpcError(code: string | undefined): 401 | 403 | 404 |
|
|
245
|
+
declare function statusForRpcError(code: string | undefined): 400 | 401 | 403 | 404 | 409 | 429 | 413 | 501 | 500;
|
|
179
246
|
declare const GATEWAY_RPC_MAX_PAYLOAD_BYTES: 1048576;
|
|
180
247
|
declare const GATEWAY_RPC_MAX_DEPTH: 32;
|
|
181
248
|
declare const GATEWAY_RPC_MAX_ARRAY_LENGTH: 256;
|
|
@@ -195,7 +262,12 @@ declare class Gateway {
|
|
|
195
262
|
maxBodyBytes: number;
|
|
196
263
|
maxPayload: number;
|
|
197
264
|
maxConnections: number;
|
|
265
|
+
eventWindowSize: number;
|
|
266
|
+
headersTimeout: number;
|
|
267
|
+
requestTimeout: number;
|
|
198
268
|
auth: GatewayAuthConfig$1 | undefined;
|
|
269
|
+
ui: ResolvedGatewayUiConfig | null;
|
|
270
|
+
uiApp: hono.Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
|
|
199
271
|
defaults: GatewayDefaults$1 | undefined;
|
|
200
272
|
workflows: Map<any, any>;
|
|
201
273
|
connections: Set<any>;
|
|
@@ -203,15 +275,95 @@ declare class Gateway {
|
|
|
203
275
|
activeRuns: Map<any, any>;
|
|
204
276
|
inflightRuns: Map<any, any>;
|
|
205
277
|
devtoolsSubscribers: Map<any, any>;
|
|
278
|
+
runEventWindows: Map<any, any>;
|
|
206
279
|
/** Absolute active subscriber count per runId (gauge source of truth). */
|
|
207
280
|
devtoolsSubscriberCounts: Map<any, any>;
|
|
208
281
|
/** Flagged subscriber IDs that should force a snapshot on their next emit. */
|
|
209
282
|
devtoolsInvalidateFlags: Set<any>;
|
|
283
|
+
uiAssetCache: Map<any, any>;
|
|
210
284
|
server: null;
|
|
211
285
|
wsServer: null;
|
|
212
286
|
schedulerTimer: null;
|
|
213
287
|
stateVersion: number;
|
|
214
288
|
startedAtMs: number;
|
|
289
|
+
/**
|
|
290
|
+
* @returns {GatewayUiMount[]}
|
|
291
|
+
*/
|
|
292
|
+
getUiMounts(): GatewayUiMount[];
|
|
293
|
+
/**
|
|
294
|
+
* @param {string} pathname
|
|
295
|
+
* @returns {GatewayUiMount | null}
|
|
296
|
+
*/
|
|
297
|
+
findUiMount(pathname: string): GatewayUiMount | null;
|
|
298
|
+
/**
|
|
299
|
+
* @param {string} pathname
|
|
300
|
+
*/
|
|
301
|
+
resolveUiMatch(pathname: string): {
|
|
302
|
+
pathname: string;
|
|
303
|
+
mountPath: string;
|
|
304
|
+
assetPath: string | null;
|
|
305
|
+
config: GatewayUiMount;
|
|
306
|
+
} | null;
|
|
307
|
+
/**
|
|
308
|
+
* @param {GatewayUiMount} mount
|
|
309
|
+
*/
|
|
310
|
+
uiBootConfig(mount: GatewayUiMount): {
|
|
311
|
+
apiVersion: "v1";
|
|
312
|
+
kind: "workflow" | "gateway";
|
|
313
|
+
workflowKey: string | null;
|
|
314
|
+
mountPath: string;
|
|
315
|
+
rpcPath: string;
|
|
316
|
+
wsPath: string;
|
|
317
|
+
assetBasePath: string;
|
|
318
|
+
props: Record<string, unknown>;
|
|
319
|
+
};
|
|
320
|
+
/**
|
|
321
|
+
* @param {{ config: GatewayUiMount }} match
|
|
322
|
+
*/
|
|
323
|
+
renderUiIndex(match: {
|
|
324
|
+
config: GatewayUiMount;
|
|
325
|
+
}): string;
|
|
326
|
+
/**
|
|
327
|
+
* @param {{ config: GatewayUiMount; assetPath: string | null }} match
|
|
328
|
+
*/
|
|
329
|
+
renderUiAsset(match: {
|
|
330
|
+
config: GatewayUiMount;
|
|
331
|
+
assetPath: string | null;
|
|
332
|
+
}): Promise<{
|
|
333
|
+
body: string;
|
|
334
|
+
contentType: string;
|
|
335
|
+
} | null>;
|
|
336
|
+
/**
|
|
337
|
+
* @param {ResolvedGatewayUiConfig} config
|
|
338
|
+
* @returns {Promise<string>}
|
|
339
|
+
*/
|
|
340
|
+
bundleUiEntry(config: ResolvedGatewayUiConfig): Promise<string>;
|
|
341
|
+
/**
|
|
342
|
+
* @param {IncomingMessage} req
|
|
343
|
+
* @param {ServerResponse} res
|
|
344
|
+
*/
|
|
345
|
+
handleUiHttp(req: IncomingMessage, res: ServerResponse$1): Promise<boolean>;
|
|
346
|
+
/**
|
|
347
|
+
* @param {string} key
|
|
348
|
+
* @param {RegisteredWorkflow} entry
|
|
349
|
+
*/
|
|
350
|
+
workflowSummary(key: string, entry: RegisteredWorkflow): {
|
|
351
|
+
hasUi: boolean;
|
|
352
|
+
uiPath: string | null;
|
|
353
|
+
description?: string | undefined;
|
|
354
|
+
readableName?: string | undefined;
|
|
355
|
+
key: string;
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* @param {boolean | undefined} hasUi
|
|
359
|
+
*/
|
|
360
|
+
listWorkflowSummaries(hasUi: boolean | undefined): {
|
|
361
|
+
hasUi: boolean;
|
|
362
|
+
uiPath: string | null;
|
|
363
|
+
description?: string | undefined;
|
|
364
|
+
readableName?: string | undefined;
|
|
365
|
+
key: string;
|
|
366
|
+
}[];
|
|
215
367
|
authModeLabel(): string;
|
|
216
368
|
/**
|
|
217
369
|
* @param {string} [runId]
|
|
@@ -269,6 +421,61 @@ declare class Gateway {
|
|
|
269
421
|
*/
|
|
270
422
|
cleanupDevToolsSubscribers(connection: ConnectionState): void;
|
|
271
423
|
/**
|
|
424
|
+
* @param {string} runId
|
|
425
|
+
* @returns {{ nextSeq: number; window: Array<Record<string, unknown>> }}
|
|
426
|
+
*/
|
|
427
|
+
getRunEventWindow(runId: string): {
|
|
428
|
+
nextSeq: number;
|
|
429
|
+
window: Array<Record<string, unknown>>;
|
|
430
|
+
};
|
|
431
|
+
/**
|
|
432
|
+
* @param {string} event
|
|
433
|
+
* @param {unknown} payload
|
|
434
|
+
* @param {number} stateVersion
|
|
435
|
+
* @returns {Record<string, unknown> | null}
|
|
436
|
+
*/
|
|
437
|
+
appendRunEventWindow(event: string, payload: unknown, stateVersion: number): Record<string, unknown> | null;
|
|
438
|
+
/**
|
|
439
|
+
* @param {string} runId
|
|
440
|
+
* @returns {number}
|
|
441
|
+
*/
|
|
442
|
+
getRunEventCurrentSeq(runId: string): number;
|
|
443
|
+
/**
|
|
444
|
+
* @param {ConnectionState} connection
|
|
445
|
+
* @param {string} streamId
|
|
446
|
+
* @param {string} runId
|
|
447
|
+
* @returns {() => void}
|
|
448
|
+
*/
|
|
449
|
+
registerRunEventSubscriber(connection: ConnectionState, streamId: string, runId: string): () => void;
|
|
450
|
+
/**
|
|
451
|
+
* @param {ConnectionState} connection
|
|
452
|
+
* @param {string} streamId
|
|
453
|
+
*/
|
|
454
|
+
unregisterRunEventSubscriber(connection: ConnectionState, streamId: string): void;
|
|
455
|
+
/**
|
|
456
|
+
* @param {ConnectionState} connection
|
|
457
|
+
*/
|
|
458
|
+
cleanupRunEventSubscribers(connection: ConnectionState): void;
|
|
459
|
+
/**
|
|
460
|
+
* @param {ConnectionState} connection
|
|
461
|
+
* @param {string} streamId
|
|
462
|
+
* @param {Record<string, unknown>} frame
|
|
463
|
+
*/
|
|
464
|
+
sendRunEventStreamFrame(connection: ConnectionState, streamId: string, frame: Record<string, unknown>): void;
|
|
465
|
+
/**
|
|
466
|
+
* @param {ConnectionState} connection
|
|
467
|
+
* @param {string} streamId
|
|
468
|
+
* @param {string} runId
|
|
469
|
+
* @param {number} fromSeq
|
|
470
|
+
* @param {number} toSeq
|
|
471
|
+
* @param {unknown} snapshot
|
|
472
|
+
*/
|
|
473
|
+
sendRunGapResync(connection: ConnectionState, streamId: string, runId: string, fromSeq: number, toSeq: number, snapshot: unknown): void;
|
|
474
|
+
/**
|
|
475
|
+
* @param {string} runId
|
|
476
|
+
*/
|
|
477
|
+
buildRunSnapshot(runId: string): Promise<any>;
|
|
478
|
+
/**
|
|
272
479
|
* @param {GatewayTransport} transport
|
|
273
480
|
* @param {string} frameType
|
|
274
481
|
* @param {GatewayMetricLabels} [labels]
|
|
@@ -307,7 +514,7 @@ declare class Gateway {
|
|
|
307
514
|
* @param {number} status
|
|
308
515
|
* @param {ResponseFrame} response
|
|
309
516
|
*/
|
|
310
|
-
sendHttpRpcResponse(res: ServerResponse, status: number, response: ResponseFrame): void;
|
|
517
|
+
sendHttpRpcResponse(res: ServerResponse$1, status: number, response: ResponseFrame): void;
|
|
311
518
|
/**
|
|
312
519
|
* @param {SmithersDb} adapter
|
|
313
520
|
* @param {string} runId
|
|
@@ -327,17 +534,14 @@ declare class Gateway {
|
|
|
327
534
|
* @param {ServerResponse} res
|
|
328
535
|
* @param {string} workflowKey
|
|
329
536
|
*/
|
|
330
|
-
handleWebhook(req: IncomingMessage, res: ServerResponse, workflowKey: string): Promise<void>;
|
|
537
|
+
handleWebhook(req: IncomingMessage, res: ServerResponse$1, workflowKey: string): Promise<void>;
|
|
331
538
|
/**
|
|
332
539
|
* @param {string} key
|
|
333
540
|
* @param {SmithersWorkflow} workflow
|
|
334
|
-
* @param {
|
|
541
|
+
* @param {GatewayRegisterOptions} [options]
|
|
335
542
|
* @returns {this}
|
|
336
543
|
*/
|
|
337
|
-
register(key: string, workflow: SmithersWorkflow, options?:
|
|
338
|
-
schedule?: string;
|
|
339
|
-
webhook?: GatewayWebhookConfig;
|
|
340
|
-
}): this;
|
|
544
|
+
register(key: string, workflow: SmithersWorkflow, options?: GatewayRegisterOptions): this;
|
|
341
545
|
/**
|
|
342
546
|
* @param {{ port?: number; host?: string }} [options]
|
|
343
547
|
*/
|
|
@@ -419,8 +623,9 @@ declare class Gateway {
|
|
|
419
623
|
/**
|
|
420
624
|
* @param {IncomingMessage} req
|
|
421
625
|
* @param {ServerResponse} res
|
|
626
|
+
* @param {string} [forcedMethod]
|
|
422
627
|
*/
|
|
423
|
-
handleHttpRpc(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
628
|
+
handleHttpRpc(req: IncomingMessage, res: ServerResponse$1, forcedMethod?: string): Promise<void>;
|
|
424
629
|
/**
|
|
425
630
|
* @param {ConnectionState} connection
|
|
426
631
|
* @param {ResponseFrame} frame
|
|
@@ -441,6 +646,7 @@ declare class Gateway {
|
|
|
441
646
|
runs: any[];
|
|
442
647
|
approvals: {
|
|
443
648
|
runId: any;
|
|
649
|
+
workflowKey: any;
|
|
444
650
|
nodeId: any;
|
|
445
651
|
iteration: any;
|
|
446
652
|
requestTitle: any;
|
|
@@ -465,6 +671,7 @@ declare class Gateway {
|
|
|
465
671
|
listRunsAcrossWorkflows(limit?: number, status?: string): Promise<any[]>;
|
|
466
672
|
listPendingApprovals(): Promise<{
|
|
467
673
|
runId: any;
|
|
674
|
+
workflowKey: any;
|
|
468
675
|
nodeId: any;
|
|
469
676
|
iteration: any;
|
|
470
677
|
requestTitle: any;
|
|
@@ -511,7 +718,9 @@ declare class Gateway {
|
|
|
511
718
|
}
|
|
512
719
|
type EventFrame = EventFrame$1;
|
|
513
720
|
type GatewayDefaults = GatewayDefaults$1;
|
|
721
|
+
type GatewayRegisterOptions = GatewayRegisterOptions$1;
|
|
514
722
|
type GatewayTokenGrant = GatewayTokenGrant$1;
|
|
723
|
+
type GatewayUiConfig = GatewayUiConfig$1;
|
|
515
724
|
type HelloResponse = HelloResponse$1;
|
|
516
725
|
type GatewayWebhookRunConfig = GatewayWebhookRunConfig$1;
|
|
517
726
|
type GatewayWebhookSignalConfig = GatewayWebhookSignalConfig$1;
|
|
@@ -522,9 +731,9 @@ type GatewayWebhookConfig = GatewayWebhookConfig$1;
|
|
|
522
731
|
type IncomingMessage = node_http.IncomingMessage;
|
|
523
732
|
type RequestFrame = RequestFrame$1;
|
|
524
733
|
type ResponseFrame = ResponseFrame$1;
|
|
525
|
-
type ServerResponse = node_http.ServerResponse;
|
|
526
|
-
type SmithersWorkflow =
|
|
527
|
-
type SmithersEvent$1 =
|
|
734
|
+
type ServerResponse$1 = node_http.ServerResponse;
|
|
735
|
+
type SmithersWorkflow = _smithers_orchestrator_components_SmithersWorkflow.SmithersWorkflow<unknown>;
|
|
736
|
+
type SmithersEvent$1 = _smithers_orchestrator_observability_SmithersEvent.SmithersEvent;
|
|
528
737
|
type GatewayMetricLabels = Record<string, string | number | null | undefined>;
|
|
529
738
|
type GatewayTransport = "ws" | "http";
|
|
530
739
|
type GatewayRequestContext = {
|
|
@@ -532,6 +741,7 @@ type GatewayRequestContext = {
|
|
|
532
741
|
role?: string;
|
|
533
742
|
scopes?: string[];
|
|
534
743
|
userId?: string | null;
|
|
744
|
+
tokenId?: string | null;
|
|
535
745
|
origin?: string;
|
|
536
746
|
transport?: GatewayTransport;
|
|
537
747
|
};
|
|
@@ -550,6 +760,7 @@ type RunStartAuthContext = {
|
|
|
550
760
|
role: string;
|
|
551
761
|
scopes: string[];
|
|
552
762
|
userId?: string | null;
|
|
763
|
+
tokenId?: string | null;
|
|
553
764
|
connectionId?: string;
|
|
554
765
|
};
|
|
555
766
|
type RegisteredWorkflow = {
|
|
@@ -558,6 +769,7 @@ type RegisteredWorkflow = {
|
|
|
558
769
|
key: string;
|
|
559
770
|
schedule?: string;
|
|
560
771
|
webhook?: GatewayWebhookConfig;
|
|
772
|
+
ui?: ResolvedGatewayUiConfig | null;
|
|
561
773
|
};
|
|
562
774
|
type ResolvedRun = {
|
|
563
775
|
runId: string;
|
|
@@ -565,6 +777,17 @@ type ResolvedRun = {
|
|
|
565
777
|
workflow: SmithersWorkflow;
|
|
566
778
|
adapter: SmithersDb$4;
|
|
567
779
|
};
|
|
780
|
+
type ResolvedGatewayUiConfig = {
|
|
781
|
+
entry: string;
|
|
782
|
+
path: string;
|
|
783
|
+
title?: string;
|
|
784
|
+
props?: Record<string, unknown>;
|
|
785
|
+
};
|
|
786
|
+
type GatewayUiMount = {
|
|
787
|
+
kind: "gateway" | "workflow";
|
|
788
|
+
workflowKey: string | null;
|
|
789
|
+
config: ResolvedGatewayUiConfig;
|
|
790
|
+
};
|
|
568
791
|
|
|
569
792
|
type ServeOptions$1 = {
|
|
570
793
|
workflow: SmithersWorkflow$1<unknown>;
|
|
@@ -614,7 +837,7 @@ declare class NodeOutputRouteError extends Error {
|
|
|
614
837
|
/** @type {NodeOutputErrorCode} */
|
|
615
838
|
code: NodeOutputErrorCode;
|
|
616
839
|
}
|
|
617
|
-
type NodeOutputErrorCode =
|
|
840
|
+
type NodeOutputErrorCode = _smithers_orchestrator_protocol_errors.NodeOutputErrorCode;
|
|
618
841
|
|
|
619
842
|
/**
|
|
620
843
|
* @returns {DevToolsNode}
|
|
@@ -701,11 +924,11 @@ declare class DevToolsRouteError extends Error {
|
|
|
701
924
|
hint: string | undefined;
|
|
702
925
|
}
|
|
703
926
|
declare const DEVTOOLS_EMPTY_ROOT_ID: 0;
|
|
704
|
-
type SmithersDb$3 =
|
|
705
|
-
type DevToolsNode =
|
|
706
|
-
type DevToolsSnapshot =
|
|
707
|
-
type DevToolsNodeType =
|
|
708
|
-
type SnapshotSerializerWarning$1 =
|
|
927
|
+
type SmithersDb$3 = _smithers_orchestrator_db_adapter.SmithersDb;
|
|
928
|
+
type DevToolsNode = _smithers_orchestrator_protocol_devtools.DevToolsNode;
|
|
929
|
+
type DevToolsSnapshot = _smithers_orchestrator_protocol_devtools.DevToolsSnapshot;
|
|
930
|
+
type DevToolsNodeType = _smithers_orchestrator_protocol_devtools.DevToolsNodeType;
|
|
931
|
+
type SnapshotSerializerWarning$1 = _smithers_orchestrator_devtools_snapshotSerializer.SnapshotSerializerWarning;
|
|
709
932
|
|
|
710
933
|
type DiffSummary$1 = {
|
|
711
934
|
filesChanged: number;
|
|
@@ -752,7 +975,7 @@ type GetNodeDiffRouteResult$1 = {
|
|
|
752
975
|
* }} opts
|
|
753
976
|
* @returns {Promise<GetNodeDiffRouteResult>}
|
|
754
977
|
*/
|
|
755
|
-
declare function getNodeDiffRoute({ runId: rawRunId, nodeId: rawNodeId, iteration: rawIteration, resolveRun, emitEffect, computeDiffBundleImpl, computeDiffBundleBetweenRefsImpl, getCurrentPointerImpl, resolveCommitPointerImpl, restorePointerImpl, nowMs, stat, }: {
|
|
978
|
+
declare function getNodeDiffRoute({ runId: rawRunId, nodeId: rawNodeId, iteration: rawIteration, resolveRun, emitEffect, computeDiffBundleImpl, computeDiffBundleBetweenRefsImpl, getCurrentPointerImpl: _getCurrentPointerImpl, resolveCommitPointerImpl, restorePointerImpl: _restorePointerImpl, nowMs, stat, }: {
|
|
756
979
|
runId: unknown;
|
|
757
980
|
nodeId: unknown;
|
|
758
981
|
iteration: unknown;
|
|
@@ -760,8 +983,8 @@ declare function getNodeDiffRoute({ runId: rawRunId, nodeId: rawNodeId, iteratio
|
|
|
760
983
|
adapter: SmithersDb$2;
|
|
761
984
|
} | null>;
|
|
762
985
|
emitEffect?: (effect: Effect.Effect<void>) => Promise<unknown>;
|
|
763
|
-
computeDiffBundleImpl?: (baseRef: string, cwd: string, seq?: number) => Promise<
|
|
764
|
-
computeDiffBundleBetweenRefsImpl?: (baseRef: string, targetRef: string, cwd: string, seq?: number) => Promise<
|
|
986
|
+
computeDiffBundleImpl?: (baseRef: string, cwd: string, seq?: number) => Promise<_smithers_orchestrator_engine_effect_DiffBundle.DiffBundle>;
|
|
987
|
+
computeDiffBundleBetweenRefsImpl?: (baseRef: string, targetRef: string, cwd: string, seq?: number) => Promise<_smithers_orchestrator_engine_effect_DiffBundle.DiffBundle>;
|
|
765
988
|
getCurrentPointerImpl?: (cwd: string) => Promise<string | null>;
|
|
766
989
|
resolveCommitPointerImpl?: (pointer: string, cwd: string) => Promise<string | null>;
|
|
767
990
|
restorePointerImpl?: (pointer: string, cwd: string) => Promise<{
|
|
@@ -771,8 +994,8 @@ declare function getNodeDiffRoute({ runId: rawRunId, nodeId: rawNodeId, iteratio
|
|
|
771
994
|
nowMs?: () => number;
|
|
772
995
|
stat?: boolean;
|
|
773
996
|
}): Promise<GetNodeDiffRouteResult>;
|
|
774
|
-
type SmithersDb$2 =
|
|
775
|
-
type AttemptRow =
|
|
997
|
+
type SmithersDb$2 = _smithers_orchestrator_db_adapter.SmithersDb;
|
|
998
|
+
type AttemptRow = _smithers_orchestrator_db_adapter.AttemptRow;
|
|
776
999
|
type GetNodeDiffRouteResult = GetNodeDiffRouteResult$1;
|
|
777
1000
|
type DiffSummary = DiffSummary$1;
|
|
778
1001
|
|
|
@@ -832,8 +1055,8 @@ declare function getNodeOutputRoute(params: {
|
|
|
832
1055
|
nodeId: unknown;
|
|
833
1056
|
iteration: unknown;
|
|
834
1057
|
resolveRun: (runId: string) => Promise<{
|
|
835
|
-
workflow:
|
|
836
|
-
adapter:
|
|
1058
|
+
workflow: _smithers_orchestrator_components_SmithersWorkflow.SmithersWorkflow<unknown>;
|
|
1059
|
+
adapter: _smithers_orchestrator_db_adapter.SmithersDb;
|
|
837
1060
|
} | null>;
|
|
838
1061
|
selectOutputRowImpl?: typeof selectOutputRow;
|
|
839
1062
|
emitEffect?: (effect: Effect.Effect<void>) => Promise<unknown>;
|
|
@@ -883,9 +1106,9 @@ declare function jumpToFrameRoute(input: {
|
|
|
883
1106
|
onLog?: (level: "info" | "warn" | "error", message: string, fields?: Record<string, unknown>) => Promise<void> | void;
|
|
884
1107
|
}): Promise<JumpResult>;
|
|
885
1108
|
|
|
886
|
-
type SmithersDb$1 =
|
|
887
|
-
type SmithersEvent =
|
|
888
|
-
type JumpResult =
|
|
1109
|
+
type SmithersDb$1 = _smithers_orchestrator_db_adapter.SmithersDb;
|
|
1110
|
+
type SmithersEvent = _smithers_orchestrator_observability_SmithersEvent.SmithersEvent;
|
|
1111
|
+
type JumpResult = _smithers_orchestrator_time_travel_jumpToFrame.JumpResult;
|
|
889
1112
|
|
|
890
1113
|
/**
|
|
891
1114
|
* @param {{
|
|
@@ -934,20 +1157,21 @@ declare function streamDevToolsRoute(input: {
|
|
|
934
1157
|
declare const DEVTOOLS_REBASELINE_INTERVAL: 50;
|
|
935
1158
|
declare const DEVTOOLS_BACKPRESSURE_LIMIT: 1000;
|
|
936
1159
|
declare const DEVTOOLS_POLL_INTERVAL_MS: 25;
|
|
937
|
-
type SmithersDb =
|
|
938
|
-
type DevToolsEvent =
|
|
939
|
-
type SnapshotSerializerWarning =
|
|
1160
|
+
type SmithersDb = _smithers_orchestrator_db_adapter.SmithersDb;
|
|
1161
|
+
type DevToolsEvent = _smithers_orchestrator_protocol_devtools.DevToolsEvent;
|
|
1162
|
+
type SnapshotSerializerWarning = _smithers_orchestrator_devtools_snapshotSerializer.SnapshotSerializerWarning;
|
|
940
1163
|
|
|
941
1164
|
/**
|
|
942
1165
|
* @param {ServerOptions} [opts]
|
|
943
1166
|
*/
|
|
944
|
-
declare function startServerEffect(opts?: ServerOptions): Effect.Effect<node_http.Server<typeof IncomingMessage
|
|
1167
|
+
declare function startServerEffect(opts?: ServerOptions): Effect.Effect<node_http.Server<typeof node_http.IncomingMessage, typeof node_http.ServerResponse>, never, never>;
|
|
945
1168
|
/**
|
|
946
1169
|
* @param {ServerOptions} [opts]
|
|
947
1170
|
*/
|
|
948
|
-
declare function startServer(opts?: ServerOptions): node_http.Server<typeof IncomingMessage
|
|
1171
|
+
declare function startServer(opts?: ServerOptions): node_http.Server<typeof node_http.IncomingMessage, typeof node_http.ServerResponse>;
|
|
949
1172
|
|
|
950
|
-
type RunRow =
|
|
1173
|
+
type RunRow = _smithers_orchestrator_db_adapter_RunRow.RunRow;
|
|
1174
|
+
type ServerResponse = node_http.ServerResponse;
|
|
951
1175
|
type ServerOptions = ServerOptions$1;
|
|
952
1176
|
|
|
953
|
-
export { type AttemptRow, type ConnectRequest, type ConnectionState, DEVTOOLS_BACKPRESSURE_LIMIT, DEVTOOLS_EMPTY_ROOT_ID, DEVTOOLS_MAX_FRAME_NO, DEVTOOLS_POLL_INTERVAL_MS, DEVTOOLS_REBASELINE_INTERVAL, DEVTOOLS_RUN_ID_PATTERN, DEVTOOLS_TREE_MAX_DEPTH, type DevToolsEvent, type DevToolsNode, type DevToolsNodeType, DevToolsRouteError, type DiffSummary, type EventFrame, GATEWAY_FRAME_ID_MAX_LENGTH, GATEWAY_METHOD_NAME_MAX_LENGTH, GATEWAY_RPC_INPUT_MAX_BYTES, GATEWAY_RPC_INPUT_MAX_DEPTH, GATEWAY_RPC_MAX_ARRAY_LENGTH, GATEWAY_RPC_MAX_DEPTH, GATEWAY_RPC_MAX_PAYLOAD_BYTES, GATEWAY_RPC_MAX_STRING_LENGTH, Gateway, type GatewayAuthConfig, type GatewayDefaults, type GatewayMetricLabels, type GatewayOptions, type GatewayRequestContext, type GatewayTokenGrant, type GatewayTransport, type GatewayWebhookConfig, type GatewayWebhookRunConfig, type GatewayWebhookSignalConfig, type GetNodeDiffRouteResult, type HelloResponse, ITERATION_MAX, type IncomingMessage, type JumpResult, NODE_ID_PATTERN, NODE_OUTPUT_MAX_BYTES, NODE_OUTPUT_WARN_BYTES, type NodeOutputErrorCode, type NodeOutputResponse, NodeOutputRouteError, RUN_ID_PATTERN, type RegisteredWorkflow, type RequestFrame, type ResolvedRun, type ResponseFrame, type RunRow, type RunStartAuthContext, type ServeOptions, type ServerOptions, type ServerResponse, type SmithersWorkflow, assertGatewayInputDepthWithinBounds, createServeApp, emptyDevToolsRoot, getDevToolsSnapshotRoute, getGatewayInputDepth, getNodeDiffRoute, getNodeOutputRoute, jumpToFrameRoute, parseGatewayRequestFrame, parseXmlToDevToolsRoot, runFork, runPromise, runSync, snapshotFromFrameRow, startServer, startServerEffect, statusForRpcError, streamDevToolsRoute, summarizeBundle, validateFrameNoInput, validateFromSeqInput, validateGatewayMethodName, validateRequestedFrameNo, validateRunId };
|
|
1177
|
+
export { type AttemptRow, type ConnectRequest, type ConnectionState, DEVTOOLS_BACKPRESSURE_LIMIT, DEVTOOLS_EMPTY_ROOT_ID, DEVTOOLS_MAX_FRAME_NO, DEVTOOLS_POLL_INTERVAL_MS, DEVTOOLS_REBASELINE_INTERVAL, DEVTOOLS_RUN_ID_PATTERN, DEVTOOLS_TREE_MAX_DEPTH, type DevToolsEvent, type DevToolsNode, type DevToolsNodeType, DevToolsRouteError, type DiffSummary, type EventFrame, GATEWAY_FRAME_ID_MAX_LENGTH, GATEWAY_METHOD_NAME_MAX_LENGTH, GATEWAY_RPC_INPUT_MAX_BYTES, GATEWAY_RPC_INPUT_MAX_DEPTH, GATEWAY_RPC_MAX_ARRAY_LENGTH, GATEWAY_RPC_MAX_DEPTH, GATEWAY_RPC_MAX_PAYLOAD_BYTES, GATEWAY_RPC_MAX_STRING_LENGTH, Gateway, type GatewayAuthConfig, type GatewayDefaults, type GatewayMetricLabels, type GatewayOptions, type GatewayRegisterOptions, type GatewayRequestContext, type GatewayTokenGrant, type GatewayTransport, type GatewayUiConfig, type GatewayUiMount, type GatewayWebhookConfig, type GatewayWebhookRunConfig, type GatewayWebhookSignalConfig, type GetNodeDiffRouteResult, type HelloResponse, ITERATION_MAX, type IncomingMessage, type JumpResult, NODE_ID_PATTERN, NODE_OUTPUT_MAX_BYTES, NODE_OUTPUT_WARN_BYTES, type NodeOutputErrorCode, type NodeOutputResponse, NodeOutputRouteError, RUN_ID_PATTERN, type RegisteredWorkflow, type RequestFrame, type ResolvedGatewayUiConfig, type ResolvedRun, type ResponseFrame, type RunRow, type RunStartAuthContext, type ServeOptions, type ServerOptions, type ServerResponse, type SmithersWorkflow, assertGatewayInputDepthWithinBounds, createServeApp, emptyDevToolsRoot, getDevToolsSnapshotRoute, getGatewayInputDepth, getNodeDiffRoute, getNodeOutputRoute, jumpToFrameRoute, parseGatewayRequestFrame, parseXmlToDevToolsRoot, runFork, runPromise, runSync, snapshotFromFrameRow, startServer, startServerEffect, statusForRpcError, streamDevToolsRoute, summarizeBundle, validateFrameNoInput, validateFromSeqInput, validateGatewayMethodName, validateRequestedFrameNo, validateRunId };
|