@workflow/web 5.0.0-beta.37 → 5.0.0-beta.39
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/README.md +1 -0
- package/build/client/assets/app-BqwHo5GR.css +1 -0
- package/build/client/assets/{arrow-up-right-DDNPFYmg.js → arrow-up-right-Ccx_FPfU.js} +1 -1
- package/build/client/assets/{highlighted-body-B3W2YXNL-CRgNr0YA.js → highlighted-body-B3W2YXNL-DMawUm9n.js} +1 -1
- package/build/client/assets/{home-BqvW8ODs.js → home-B6O_uPSC.js} +3 -2
- package/build/client/assets/loader-circle-BrO0dxVn.js +12 -0
- package/build/client/assets/manifest-7e8691f4.js +1 -0
- package/build/client/assets/{mermaid-3ZIDBTTL-CMP9Tato.js → mermaid-3ZIDBTTL-D20ZkB54.js} +665 -1682
- package/build/client/assets/mermaid-3ZIDBTTL-D8CjRQta.css +1 -0
- package/build/client/assets/root-CxZylOIf.css +1 -0
- package/build/client/assets/{root-2ub-CsWS.js → root-dudvdmvf.js} +6 -2
- package/build/client/assets/{run-detail-B1PK-m7y.js → run-detail-DtCCxxv2.js} +277 -359
- package/build/client/assets/{workflow-graph-viewer-DOLwtzSv.js → workflow-graph-viewer-B01nH75E.js} +65 -86
- package/build/client/assets/{zstd-browser-decoder-BAY5XtBl.js → zstd-browser-decoder-Dw3HhTgO.js} +1 -1
- package/build/server/assets/{server-build-C11Xqmwk.js → app-Bd12Opaf.js} +96186 -87164
- package/build/server/assets/{highlighted-body-B3W2YXNL-DE3KXslx.js → highlighted-body-B3W2YXNL-CFlRme7u.js} +3 -4
- package/build/server/assets/{index-M4Ai7vsa.js → index-B6SJpqpo.js} +65 -63
- package/build/server/assets/{mermaid-3ZIDBTTL-DjL45D7x.js → mermaid-3ZIDBTTL-CQsU8DGa.js} +4 -5
- package/build/server/assets/{token-Ulh8Tdgw.js → token-XJr1pjmC.js} +1 -2
- package/build/server/assets/{token-util-CiVcDWD3.js → token-util-BJaMxWWP.js} +1 -2
- package/build/server/assets/{zstd-browser-decoder-tQARkzJ5.js → zstd-browser-decoder-DL7Vc3pV.js} +4 -5
- package/build/server/index.js +41 -2
- package/handler.d.ts +22 -0
- package/handler.js +186 -0
- package/package.json +20 -8
- package/registry.d.ts +29 -0
- package/registry.js +89 -0
- package/build/client/assets/manifest-7f03c136.js +0 -1
- package/build/client/assets/mermaid-3ZIDBTTL-DDxQhcP4.css +0 -1
- package/build/client/assets/root-15oK726f.css +0 -1
- package/build/client/assets/server-build-DblSGQ6A.css +0 -1
- package/build/client/assets/worker-CqHKTA7D.js +0 -115
- package/build/server/assets/app-BaJoK9ck.js +0 -9217
|
@@ -2,13 +2,12 @@ import { createRequire as __wkfCreateRequire } from "node:module";
|
|
|
2
2
|
if (typeof require === "undefined") {
|
|
3
3
|
globalThis.require = __wkfCreateRequire(import.meta.url);
|
|
4
4
|
}
|
|
5
|
-
import {
|
|
6
|
-
import { r as reactExports } from "./app-BaJoK9ck.js";
|
|
5
|
+
import { aA as reactExports, aB as R, aC as Ks, aD as jsxRuntimeExports, aE as Qe } from "./app-Bd12Opaf.js";
|
|
7
6
|
import "node:stream";
|
|
7
|
+
import "stream";
|
|
8
8
|
import "util";
|
|
9
9
|
import "crypto";
|
|
10
10
|
import "async_hooks";
|
|
11
|
-
import "stream";
|
|
12
11
|
import "node:crypto";
|
|
13
12
|
import "node:process";
|
|
14
13
|
import "node:path";
|
|
@@ -18,8 +17,8 @@ import "node:fs/promises";
|
|
|
18
17
|
import "node:module";
|
|
19
18
|
import "node:util";
|
|
20
19
|
import "node:async_hooks";
|
|
21
|
-
import "node:os";
|
|
22
20
|
import "node:fs";
|
|
21
|
+
import "node:os";
|
|
23
22
|
import "node:child_process";
|
|
24
23
|
import "node:timers/promises";
|
|
25
24
|
import "events";
|
|
@@ -2,12 +2,10 @@ import { createRequire as __wkfCreateRequire } from "node:module";
|
|
|
2
2
|
if (typeof require === "undefined") {
|
|
3
3
|
globalThis.require = __wkfCreateRequire(import.meta.url);
|
|
4
4
|
}
|
|
5
|
-
import { H as HookSchema } from "./
|
|
6
|
-
import { A, a, b, c, d, e, f, g, h, i, j, k, B, C, D, l, E, m, n, o, p, q, r, s, L, M, P,
|
|
7
|
-
import "./app-BaJoK9ck.js";
|
|
8
|
-
import "stream";
|
|
9
|
-
import "express";
|
|
5
|
+
import { H as HookSchema } from "./app-Bd12Opaf.js";
|
|
6
|
+
import { A, a, b, c, d, e, f, g, h, i, j, k, B, C, D, l, E, m, n, o, p, q, r, s, t, u, v, L, M, P, w, Q, x, R, y, z, S, F, G, I, J, K, O, T, U, V, W, X, Y, Z, _, $, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an, ao, ap, aq, ar, as, at, au, av, aw, ax, ay, az } from "./app-Bd12Opaf.js";
|
|
10
7
|
import "node:stream";
|
|
8
|
+
import "stream";
|
|
11
9
|
import "util";
|
|
12
10
|
import "crypto";
|
|
13
11
|
import "async_hooks";
|
|
@@ -20,8 +18,8 @@ import "node:fs/promises";
|
|
|
20
18
|
import "node:module";
|
|
21
19
|
import "node:util";
|
|
22
20
|
import "node:async_hooks";
|
|
23
|
-
import "node:os";
|
|
24
21
|
import "node:fs";
|
|
22
|
+
import "node:os";
|
|
25
23
|
import "node:child_process";
|
|
26
24
|
import "node:timers/promises";
|
|
27
25
|
import "events";
|
|
@@ -45,6 +43,7 @@ import "path";
|
|
|
45
43
|
import "fs";
|
|
46
44
|
import "os";
|
|
47
45
|
import "net";
|
|
46
|
+
import "express";
|
|
48
47
|
export {
|
|
49
48
|
A as ATTRIBUTE_KEY_MAX_LENGTH,
|
|
50
49
|
a as ATTRIBUTE_MAX_PER_RUN,
|
|
@@ -68,68 +67,71 @@ export {
|
|
|
68
67
|
o as EventTypeSchema,
|
|
69
68
|
p as HOOK_EVENTS_REQUIRING_EXISTENCE,
|
|
70
69
|
q as HOOK_LIFECYCLE_EVENT_TYPES,
|
|
71
|
-
r as
|
|
72
|
-
s as
|
|
70
|
+
r as HOOK_RESUME_DEDUP_VERSION,
|
|
71
|
+
s as HOOK_RESUME_INPUT_VERSION,
|
|
72
|
+
t as HealthCheckPayloadSchema,
|
|
73
|
+
u as HookCreatedEventSchema,
|
|
74
|
+
v as HookResumeCapabilitiesSchema,
|
|
73
75
|
HookSchema,
|
|
74
76
|
L as LegacySerializedDataSchemaV1,
|
|
75
77
|
M as MessageId,
|
|
76
78
|
P as PARENT_RUN_ID_ATTRIBUTE,
|
|
77
|
-
|
|
79
|
+
w as PaginatedResponseSchema,
|
|
78
80
|
Q as QueuePayloadSchema,
|
|
79
|
-
|
|
81
|
+
x as QueuePrefix,
|
|
80
82
|
R as RESERVED_ATTRIBUTE_KEY_PREFIX,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
y as ROOT_RUN_ID_ATTRIBUTE,
|
|
84
|
+
z as RunInputSchema,
|
|
83
85
|
S as SPEC_VERSION_CURRENT,
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
86
|
+
F as SPEC_VERSION_LEGACY,
|
|
87
|
+
G as SPEC_VERSION_SUPPORTS_ATTRIBUTES,
|
|
88
|
+
I as SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT,
|
|
89
|
+
J as SPEC_VERSION_SUPPORTS_COMPRESSION,
|
|
90
|
+
K as STEP_EVENT_TYPES,
|
|
91
|
+
O as SerializedDataSchema,
|
|
92
|
+
T as StepSchema,
|
|
93
|
+
U as StepStatusSchema,
|
|
94
|
+
V as StructuredErrorSchema,
|
|
95
|
+
W as TERMINAL_RUN_EVENT_TYPES,
|
|
96
|
+
X as TERMINAL_STEP_EVENT_TYPES,
|
|
97
|
+
Y as TERMINAL_STEP_STATUSES,
|
|
98
|
+
Z as TERMINAL_WORKFLOW_RUN_STATUSES,
|
|
99
|
+
_ as TerminalRunEventTypeSchema,
|
|
100
|
+
$ as TerminalStepStatusSchema,
|
|
101
|
+
a0 as TerminalWorkflowRunStatusSchema,
|
|
102
|
+
a1 as ValidQueueName,
|
|
103
|
+
a2 as WAIT_EVENT_TYPES,
|
|
104
|
+
a3 as WaitSchema,
|
|
105
|
+
a4 as WaitStatusSchema,
|
|
106
|
+
a5 as WorkflowInvokePayloadSchema,
|
|
107
|
+
a6 as WorkflowRunBaseSchema,
|
|
108
|
+
a7 as WorkflowRunSchema,
|
|
109
|
+
a8 as WorkflowRunStatusSchema,
|
|
110
|
+
a9 as applyAttributeChanges,
|
|
111
|
+
aa as envNumber,
|
|
112
|
+
ab as getEventDataPayloadField,
|
|
113
|
+
ac as getEventDataRefFields,
|
|
114
|
+
ad as getQueueTopicPrefix,
|
|
115
|
+
ae as isChildEntityCreationEvent,
|
|
116
|
+
af as isChildEntityCreationEventType,
|
|
117
|
+
ag as isHookEventRequiringExistence,
|
|
118
|
+
ah as isHookLifecycleEventType,
|
|
119
|
+
ai as isLegacySpecVersion,
|
|
120
|
+
aj as isStepEventType,
|
|
121
|
+
ak as isTerminalRunEventType,
|
|
122
|
+
al as isTerminalStepEventType,
|
|
123
|
+
am as isTerminalStepStatus,
|
|
124
|
+
an as isTerminalWorkflowRunStatus,
|
|
125
|
+
ao as isWaitEventType,
|
|
126
|
+
ap as parseQueueName,
|
|
127
|
+
aq as reenqueueActiveRuns,
|
|
128
|
+
ar as requiresNewerWorld,
|
|
129
|
+
as as resolveQueueNamespace,
|
|
130
|
+
at as stripEventDataRefs,
|
|
131
|
+
au as ulidToDate,
|
|
132
|
+
av as validateAttributeChanges,
|
|
133
|
+
aw as validateAttributeKey,
|
|
134
|
+
ax as validateAttributeValue,
|
|
135
|
+
ay as validateUlidTimestamp,
|
|
136
|
+
az as workflowRunIdSchema
|
|
135
137
|
};
|
|
@@ -2,11 +2,9 @@ import { createRequire as __wkfCreateRequire } from "node:module";
|
|
|
2
2
|
if (typeof require === "undefined") {
|
|
3
3
|
globalThis.require = __wkfCreateRequire(import.meta.url);
|
|
4
4
|
}
|
|
5
|
-
import { N as Nt } from "./
|
|
6
|
-
import "./app-BaJoK9ck.js";
|
|
7
|
-
import "stream";
|
|
8
|
-
import "express";
|
|
5
|
+
import { N as Nt } from "./app-Bd12Opaf.js";
|
|
9
6
|
import "node:stream";
|
|
7
|
+
import "stream";
|
|
10
8
|
import "util";
|
|
11
9
|
import "crypto";
|
|
12
10
|
import "async_hooks";
|
|
@@ -19,8 +17,8 @@ import "node:fs/promises";
|
|
|
19
17
|
import "node:module";
|
|
20
18
|
import "node:util";
|
|
21
19
|
import "node:async_hooks";
|
|
22
|
-
import "node:os";
|
|
23
20
|
import "node:fs";
|
|
21
|
+
import "node:os";
|
|
24
22
|
import "node:child_process";
|
|
25
23
|
import "node:timers/promises";
|
|
26
24
|
import "events";
|
|
@@ -44,6 +42,7 @@ import "path";
|
|
|
44
42
|
import "fs";
|
|
45
43
|
import "os";
|
|
46
44
|
import "net";
|
|
45
|
+
import "express";
|
|
47
46
|
export {
|
|
48
47
|
Nt as Mermaid
|
|
49
48
|
};
|
|
@@ -2,8 +2,7 @@ import { createRequire as __wkfCreateRequire } from "node:module";
|
|
|
2
2
|
if (typeof require === "undefined") {
|
|
3
3
|
globalThis.require = __wkfCreateRequire(import.meta.url);
|
|
4
4
|
}
|
|
5
|
-
import {
|
|
6
|
-
import { aD as requireTokenError, aC as requireTokenUtil } from "./server-build-C11Xqmwk.js";
|
|
5
|
+
import { aI as requireTokenError, aH as requireTokenUtil, aG as getDefaultExportFromCjs } from "./app-Bd12Opaf.js";
|
|
7
6
|
function _mergeNamespaces(n, m) {
|
|
8
7
|
for (var i = 0; i < m.length; i++) {
|
|
9
8
|
const e = m[i];
|
|
@@ -2,8 +2,7 @@ import { createRequire as __wkfCreateRequire } from "node:module";
|
|
|
2
2
|
if (typeof require === "undefined") {
|
|
3
3
|
globalThis.require = __wkfCreateRequire(import.meta.url);
|
|
4
4
|
}
|
|
5
|
-
import {
|
|
6
|
-
import { aC as requireTokenUtil } from "./server-build-C11Xqmwk.js";
|
|
5
|
+
import { aG as getDefaultExportFromCjs, aH as requireTokenUtil } from "./app-Bd12Opaf.js";
|
|
7
6
|
function _mergeNamespaces(n, m) {
|
|
8
7
|
for (var i = 0; i < m.length; i++) {
|
|
9
8
|
const e = m[i];
|
package/build/server/assets/{zstd-browser-decoder-tQARkzJ5.js → zstd-browser-decoder-DL7Vc3pV.js}
RENAMED
|
@@ -2,11 +2,9 @@ import { createRequire as __wkfCreateRequire } from "node:module";
|
|
|
2
2
|
if (typeof require === "undefined") {
|
|
3
3
|
globalThis.require = __wkfCreateRequire(import.meta.url);
|
|
4
4
|
}
|
|
5
|
-
import {
|
|
6
|
-
import "./app-BaJoK9ck.js";
|
|
7
|
-
import "stream";
|
|
8
|
-
import "express";
|
|
5
|
+
import { aF as registerZstdDecoder } from "./app-Bd12Opaf.js";
|
|
9
6
|
import "node:stream";
|
|
7
|
+
import "stream";
|
|
10
8
|
import "util";
|
|
11
9
|
import "crypto";
|
|
12
10
|
import "async_hooks";
|
|
@@ -19,8 +17,8 @@ import "node:fs/promises";
|
|
|
19
17
|
import "node:module";
|
|
20
18
|
import "node:util";
|
|
21
19
|
import "node:async_hooks";
|
|
22
|
-
import "node:os";
|
|
23
20
|
import "node:fs";
|
|
21
|
+
import "node:os";
|
|
24
22
|
import "node:child_process";
|
|
25
23
|
import "node:timers/promises";
|
|
26
24
|
import "events";
|
|
@@ -44,6 +42,7 @@ import "path";
|
|
|
44
42
|
import "fs";
|
|
45
43
|
import "os";
|
|
46
44
|
import "net";
|
|
45
|
+
import "express";
|
|
47
46
|
let registered = false;
|
|
48
47
|
let modulePromise;
|
|
49
48
|
function loadWasmModule() {
|
package/build/server/index.js
CHANGED
|
@@ -2,9 +2,48 @@ import { createRequire as __wkfCreateRequire } from "node:module";
|
|
|
2
2
|
if (typeof require === "undefined") {
|
|
3
3
|
globalThis.require = __wkfCreateRequire(import.meta.url);
|
|
4
4
|
}
|
|
5
|
-
import {
|
|
5
|
+
import { aJ, aK } from "./assets/app-Bd12Opaf.js";
|
|
6
6
|
import "express";
|
|
7
|
+
import "node:stream";
|
|
7
8
|
import "stream";
|
|
9
|
+
import "util";
|
|
10
|
+
import "crypto";
|
|
11
|
+
import "async_hooks";
|
|
12
|
+
import "node:crypto";
|
|
13
|
+
import "node:process";
|
|
14
|
+
import "node:path";
|
|
15
|
+
import "node:url";
|
|
16
|
+
import "module";
|
|
17
|
+
import "node:fs/promises";
|
|
18
|
+
import "node:module";
|
|
19
|
+
import "node:util";
|
|
20
|
+
import "node:async_hooks";
|
|
21
|
+
import "node:fs";
|
|
22
|
+
import "node:os";
|
|
23
|
+
import "node:child_process";
|
|
24
|
+
import "node:timers/promises";
|
|
25
|
+
import "events";
|
|
26
|
+
import "node:assert";
|
|
27
|
+
import "node:net";
|
|
28
|
+
import "node:http";
|
|
29
|
+
import "node:querystring";
|
|
30
|
+
import "node:events";
|
|
31
|
+
import "node:diagnostics_channel";
|
|
32
|
+
import "node:tls";
|
|
33
|
+
import "node:buffer";
|
|
34
|
+
import "node:zlib";
|
|
35
|
+
import "node:perf_hooks";
|
|
36
|
+
import "node:util/types";
|
|
37
|
+
import "node:sqlite";
|
|
38
|
+
import "node:worker_threads";
|
|
39
|
+
import "node:console";
|
|
40
|
+
import "node:timers";
|
|
41
|
+
import "node:dns";
|
|
42
|
+
import "path";
|
|
43
|
+
import "fs";
|
|
44
|
+
import "os";
|
|
45
|
+
import "net";
|
|
8
46
|
export {
|
|
9
|
-
|
|
47
|
+
aJ as app,
|
|
48
|
+
aK as createFetchHandler
|
|
10
49
|
};
|
package/handler.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for {@link createWorkflowWebHandler}.
|
|
3
|
+
*/
|
|
4
|
+
export interface CreateWorkflowWebHandlerOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Mount path the dashboard is served under (e.g. `"/_workflow"`). Routing and
|
|
7
|
+
* asset URLs are reprefixed to this base. Defaults to `"/"` (root).
|
|
8
|
+
*/
|
|
9
|
+
basename?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create a framework-agnostic Web `Request` -> `Response` handler that serves
|
|
14
|
+
* the Workflow observability UI (static client assets + React Router SSR)
|
|
15
|
+
* in-process, suitable for mounting inside another server under `basename`.
|
|
16
|
+
*
|
|
17
|
+
* Requires `@workflow/web` to have been built (`build/` must exist); throws
|
|
18
|
+
* otherwise.
|
|
19
|
+
*/
|
|
20
|
+
export function createWorkflowWebHandler(
|
|
21
|
+
options?: CreateWorkflowWebHandlerOptions
|
|
22
|
+
): Promise<(request: Request) => Promise<Response>>;
|
package/handler.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic, in-process entry point for @workflow/web.
|
|
3
|
+
*
|
|
4
|
+
* Unlike `server.js` (which starts a standalone Express HTTP server), this
|
|
5
|
+
* exports a single Web-standard fetch handler that another server can mount
|
|
6
|
+
* under an arbitrary base path — e.g. `@workflow/nitro` mounting the dashboard
|
|
7
|
+
* at `/_workflow` without spawning a second server/port.
|
|
8
|
+
*
|
|
9
|
+
* import { createWorkflowWebHandler } from "@workflow/web/handler";
|
|
10
|
+
* const handler = await createWorkflowWebHandler({ basename: "/_workflow" });
|
|
11
|
+
* const response = await handler(request); // (request: Request) => Response
|
|
12
|
+
*
|
|
13
|
+
* The handler serves both the prebuilt static client assets (from `build/client`)
|
|
14
|
+
* and the React Router SSR app. It reads the prebuilt `build/` as-is in every
|
|
15
|
+
* mode (it never runs Vite), so consumers must have built @workflow/web first
|
|
16
|
+
* (the published package ships `build/`).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { existsSync } from 'node:fs';
|
|
20
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
21
|
+
import path from 'node:path';
|
|
22
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
23
|
+
import { recordDashboard } from './registry.js';
|
|
24
|
+
|
|
25
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const buildDir = path.resolve(__dirname, 'build');
|
|
27
|
+
const clientDir = path.join(buildDir, 'client');
|
|
28
|
+
const serverEntry = path.join(buildDir, 'server', 'index.js');
|
|
29
|
+
|
|
30
|
+
// Minimal extension -> MIME map for serving the static client build. A wrong
|
|
31
|
+
// Content-Type on the entry module breaks the whole app, so be explicit.
|
|
32
|
+
const MIME_TYPES = {
|
|
33
|
+
'.js': 'text/javascript',
|
|
34
|
+
'.mjs': 'text/javascript',
|
|
35
|
+
'.css': 'text/css',
|
|
36
|
+
'.json': 'application/json',
|
|
37
|
+
'.map': 'application/json',
|
|
38
|
+
'.html': 'text/html',
|
|
39
|
+
'.ico': 'image/x-icon',
|
|
40
|
+
'.svg': 'image/svg+xml',
|
|
41
|
+
'.png': 'image/png',
|
|
42
|
+
'.jpg': 'image/jpeg',
|
|
43
|
+
'.jpeg': 'image/jpeg',
|
|
44
|
+
'.gif': 'image/gif',
|
|
45
|
+
'.webp': 'image/webp',
|
|
46
|
+
'.avif': 'image/avif',
|
|
47
|
+
'.woff': 'font/woff',
|
|
48
|
+
'.woff2': 'font/woff2',
|
|
49
|
+
'.ttf': 'font/ttf',
|
|
50
|
+
'.otf': 'font/otf',
|
|
51
|
+
'.txt': 'text/plain',
|
|
52
|
+
'.wasm': 'application/wasm',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** Normalize a mount path: `/` or empty -> "" (root); otherwise strip trailing slash. */
|
|
56
|
+
function normalizeBasename(basename) {
|
|
57
|
+
if (!basename || basename === '/') return '';
|
|
58
|
+
return basename.endsWith('/') ? basename.slice(0, -1) : basename;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// One handler per basename, lazily constructed and memoized so repeated
|
|
62
|
+
// requests reuse the same React Router handler and module import.
|
|
63
|
+
const handlerCache = new Map();
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {{ basename?: string }} [options]
|
|
67
|
+
* @returns {Promise<(request: Request) => Promise<Response>>}
|
|
68
|
+
*/
|
|
69
|
+
export async function createWorkflowWebHandler(options = {}) {
|
|
70
|
+
const basename = normalizeBasename(options.basename ?? '/');
|
|
71
|
+
let promise = handlerCache.get(basename);
|
|
72
|
+
if (!promise) {
|
|
73
|
+
promise = buildHandler(basename).catch((err) => {
|
|
74
|
+
handlerCache.delete(basename);
|
|
75
|
+
throw err;
|
|
76
|
+
});
|
|
77
|
+
handlerCache.set(basename, promise);
|
|
78
|
+
}
|
|
79
|
+
return promise;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function buildHandler(basename) {
|
|
83
|
+
if (!existsSync(serverEntry) || !existsSync(clientDir)) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
'@workflow/web has not been built (missing build/). ' +
|
|
86
|
+
'Run `pnpm --filter @workflow/web build` before embedding the dashboard.'
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const mod = await import(pathToFileURL(serverEntry).href);
|
|
91
|
+
if (typeof mod.createFetchHandler !== 'function') {
|
|
92
|
+
throw new Error(
|
|
93
|
+
'@workflow/web build does not export createFetchHandler; rebuild the package.'
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
const ssr = mod.createFetchHandler(basename || '/');
|
|
97
|
+
|
|
98
|
+
return async (request) => {
|
|
99
|
+
// Advertise this dashboard so the CLI can defer to it (best-effort, once).
|
|
100
|
+
// Done on first request because that's when the public origin is known.
|
|
101
|
+
try {
|
|
102
|
+
const origin = new URL(request.url).origin;
|
|
103
|
+
recordDashboard({
|
|
104
|
+
url: origin + basename,
|
|
105
|
+
basename,
|
|
106
|
+
world:
|
|
107
|
+
process.env.WORKFLOW_TARGET_WORLD ||
|
|
108
|
+
(process.env.VERCEL_DEPLOYMENT_ID ? 'vercel' : 'local'),
|
|
109
|
+
});
|
|
110
|
+
} catch {
|
|
111
|
+
// ignore — registration must never affect request handling
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const staticResponse = await tryServeStatic(request, basename);
|
|
115
|
+
if (staticResponse) return staticResponse;
|
|
116
|
+
return ssr(request);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Resolve a request to a path-within-the-client-build (relative to `clientDir`),
|
|
122
|
+
* stripping `basename` and guarding against traversal. Returns null when the
|
|
123
|
+
* request can't map to a client file (so it should fall through to the SSR
|
|
124
|
+
* handler) — e.g. the index, a directory, or an out-of-tree path.
|
|
125
|
+
*/
|
|
126
|
+
function resolveClientFile(request, basename) {
|
|
127
|
+
if (request.method !== 'GET' && request.method !== 'HEAD') return null;
|
|
128
|
+
|
|
129
|
+
let pathname;
|
|
130
|
+
try {
|
|
131
|
+
pathname = decodeURIComponent(new URL(request.url).pathname);
|
|
132
|
+
} catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (basename) {
|
|
137
|
+
if (!pathname.startsWith(`${basename}/`)) return null; // index/other -> SSR
|
|
138
|
+
pathname = pathname.slice(basename.length);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const relative = pathname.replace(/^\/+/, '');
|
|
142
|
+
if (!relative || relative.endsWith('/')) return null;
|
|
143
|
+
|
|
144
|
+
const filePath = path.join(clientDir, relative);
|
|
145
|
+
// Guard against path traversal escaping the client build directory.
|
|
146
|
+
if (filePath !== clientDir && !filePath.startsWith(clientDir + path.sep)) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
return { filePath, relative };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Serve a file from the prebuilt client bundle if the request maps to one;
|
|
154
|
+
* otherwise return null so the request falls through to the SSR handler.
|
|
155
|
+
*/
|
|
156
|
+
async function tryServeStatic(request, basename) {
|
|
157
|
+
const resolved = resolveClientFile(request, basename);
|
|
158
|
+
if (!resolved) return null;
|
|
159
|
+
const { filePath, relative } = resolved;
|
|
160
|
+
|
|
161
|
+
let stats;
|
|
162
|
+
try {
|
|
163
|
+
stats = await stat(filePath);
|
|
164
|
+
} catch {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
if (!stats.isFile()) return null;
|
|
168
|
+
|
|
169
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
170
|
+
const headers = new Headers({
|
|
171
|
+
'Content-Type': MIME_TYPES[ext] ?? 'application/octet-stream',
|
|
172
|
+
// Hashed assets are content-addressed and safe to cache forever; other
|
|
173
|
+
// client files (e.g. favicon) get a short cache.
|
|
174
|
+
'Cache-Control': relative.startsWith('assets/')
|
|
175
|
+
? 'public, max-age=31536000, immutable'
|
|
176
|
+
: 'public, max-age=3600',
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
if (request.method === 'HEAD') {
|
|
180
|
+
headers.set('Content-Length', String(stats.size));
|
|
181
|
+
return new Response(null, { status: 200, headers });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const body = await readFile(filePath);
|
|
185
|
+
return new Response(body, { status: 200, headers });
|
|
186
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workflow/web",
|
|
3
3
|
"description": "Workflow Observability UI",
|
|
4
|
-
"version": "5.0.0-beta.
|
|
4
|
+
"version": "5.0.0-beta.39",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"files": [
|
|
8
8
|
"build",
|
|
9
9
|
"server.js",
|
|
10
10
|
"server.d.ts",
|
|
11
|
+
"handler.js",
|
|
12
|
+
"handler.d.ts",
|
|
13
|
+
"registry.js",
|
|
14
|
+
"registry.d.ts",
|
|
11
15
|
"package.json"
|
|
12
16
|
],
|
|
13
17
|
"exports": {
|
|
@@ -15,6 +19,14 @@
|
|
|
15
19
|
"types": "./server.d.ts",
|
|
16
20
|
"default": "./server.js"
|
|
17
21
|
},
|
|
22
|
+
"./handler": {
|
|
23
|
+
"types": "./handler.d.ts",
|
|
24
|
+
"default": "./handler.js"
|
|
25
|
+
},
|
|
26
|
+
"./registry": {
|
|
27
|
+
"types": "./registry.d.ts",
|
|
28
|
+
"default": "./registry.js"
|
|
29
|
+
},
|
|
18
30
|
"./package.json": "./package.json"
|
|
19
31
|
},
|
|
20
32
|
"publishConfig": {
|
|
@@ -29,7 +41,7 @@
|
|
|
29
41
|
"dependencies": {
|
|
30
42
|
"express": "^5.2.1",
|
|
31
43
|
"swr": "^2.3.6",
|
|
32
|
-
"@workflow/world-local": "5.0.0-beta.
|
|
44
|
+
"@workflow/world-local": "5.0.0-beta.33"
|
|
33
45
|
},
|
|
34
46
|
"devDependencies": {
|
|
35
47
|
"@biomejs/biome": "^2.4.4",
|
|
@@ -74,12 +86,12 @@
|
|
|
74
86
|
"typescript": "^6.0.3",
|
|
75
87
|
"vite": "^6",
|
|
76
88
|
"vitest": "^3.2.7",
|
|
77
|
-
"@workflow/core": "5.0.0-beta.
|
|
78
|
-
"@workflow/errors": "5.0.0-beta.
|
|
79
|
-
"@workflow/utils": "5.0.0-beta.
|
|
80
|
-
"@workflow/web-shared": "5.0.0-beta.
|
|
81
|
-
"@workflow/world": "5.0.0-beta.
|
|
82
|
-
"@workflow/world-vercel": "5.0.0-beta.
|
|
89
|
+
"@workflow/core": "5.0.0-beta.39",
|
|
90
|
+
"@workflow/errors": "5.0.0-beta.15",
|
|
91
|
+
"@workflow/utils": "5.0.0-beta.8",
|
|
92
|
+
"@workflow/web-shared": "5.0.0-beta.39",
|
|
93
|
+
"@workflow/world": "5.0.0-beta.24",
|
|
94
|
+
"@workflow/world-vercel": "5.0.0-beta.35"
|
|
83
95
|
},
|
|
84
96
|
"scripts": {
|
|
85
97
|
"dev": "react-router dev",
|
package/registry.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** A recorded embedded-dashboard instance. */
|
|
2
|
+
export interface DashboardRegistryEntry {
|
|
3
|
+
/** Public base URL the dashboard is reachable at (e.g. `http://localhost:3000/_workflow`). */
|
|
4
|
+
url: string;
|
|
5
|
+
/** Mount path the dashboard is served under (e.g. `/_workflow`; `""` at root). */
|
|
6
|
+
basename: string;
|
|
7
|
+
/** World backend identifier, for display (e.g. `local`, `@workflow/world-postgres`). */
|
|
8
|
+
world: string;
|
|
9
|
+
/** PID of the process hosting the dashboard. */
|
|
10
|
+
pid: number;
|
|
11
|
+
/** ISO timestamp the entry was recorded. */
|
|
12
|
+
startedAt: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Absolute path of the registry file for the current working directory. */
|
|
16
|
+
export function dashboardRegistryPath(): string;
|
|
17
|
+
|
|
18
|
+
/** Read the registry entries (always returns an array; never throws). */
|
|
19
|
+
export function readDashboardRegistry(): DashboardRegistryEntry[];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Record this process's embedded dashboard (idempotent per process). Entirely
|
|
23
|
+
* best-effort — never throws.
|
|
24
|
+
*/
|
|
25
|
+
export function recordDashboard(entry: {
|
|
26
|
+
url: string;
|
|
27
|
+
basename?: string;
|
|
28
|
+
world?: string;
|
|
29
|
+
}): void;
|