bunqueue-dashboard 0.0.35 → 0.0.37
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 +36 -16
- package/agent/backup/processExecutor.ts +90 -0
- package/agent/backup/resultValidation.ts +85 -0
- package/agent/backup/routes.ts +161 -0
- package/agent/backup/runner.ts +91 -0
- package/agent/backup/standaloneWorker.ts +23 -0
- package/agent/backup/workerExecutor.ts +40 -0
- package/agent/backup/workerFactory.ts +21 -0
- package/agent/backup/workerProtocol.ts +10 -0
- package/agent/db/core.ts +141 -0
- package/agent/db/csvExport.ts +172 -0
- package/agent/db/exportTimeout.ts +190 -0
- package/agent/db/query.ts +82 -0
- package/agent/db/queryTimeout.ts +76 -0
- package/agent/db/schema.ts +79 -0
- package/agent/db/tables.ts +157 -0
- package/agent/db/types.ts +118 -0
- package/agent/db/workerFactory.ts +25 -0
- package/agent/db.ts +43 -1099
- package/agent/errorMessage.ts +9 -0
- package/agent/flow/routes.ts +251 -0
- package/agent/flow/service.ts +266 -0
- package/agent/flow/types.ts +34 -0
- package/agent/flow/validation.ts +230 -0
- package/agent/index.ts +22 -21
- package/agent/logger.ts +121 -17
- package/agent/managedTarget.ts +82 -0
- package/agent/manager/config.ts +84 -0
- package/agent/manager/logs.ts +83 -0
- package/agent/manager/process.ts +233 -0
- package/agent/manager/storage.ts +28 -0
- package/agent/manager/types.ts +38 -0
- package/agent/manager.ts +10 -490
- package/agent/queue/routes.ts +135 -0
- package/agent/queue/runtime.ts +119 -0
- package/agent/queue/types.ts +34 -0
- package/agent/queue/validation.ts +100 -0
- package/agent/server/controlRoutes.ts +185 -0
- package/agent/server/controlTarget.ts +116 -0
- package/agent/server/databaseRoutes.ts +165 -0
- package/agent/server/errors.ts +49 -0
- package/agent/server/handler.ts +155 -0
- package/agent/server/jsonBody.ts +109 -0
- package/agent/server/lifecycle.ts +72 -0
- package/agent/server/managedRuntime.ts +41 -0
- package/agent/server/policy.ts +60 -0
- package/agent/server/router.ts +161 -0
- package/agent/server/types.ts +46 -0
- package/agent/server/workflowReadRoutes.ts +80 -0
- package/agent/server.ts +26 -441
- package/agent/shutdown.ts +156 -0
- package/agent/workflow/codec.ts +78 -0
- package/agent/workflow/detail.ts +63 -0
- package/agent/workflow/list.ts +87 -0
- package/agent/workflow/runtime.ts +274 -0
- package/agent/workflow/runtimeConfig.ts +103 -0
- package/agent/workflow/runtimeRoutes.ts +163 -0
- package/agent/workflow/sqlite.ts +52 -0
- package/agent/workflow/stats.ts +79 -0
- package/agent/workflow/types.ts +81 -0
- package/agent/workflow/validation.ts +114 -0
- package/agent/workflows.ts +14 -489
- package/dist/.vite/manifest.json +611 -250
- package/dist/assets/AddJob-CWkkVHmf.js +3 -0
- package/dist/assets/Alerts-Gh1pVbqj.js +1 -0
- package/dist/assets/{AreaChart-REK4ZsTC.js → AreaChart-w0ruozXH.js} +1 -1
- package/dist/assets/Benchmark-Dir2A1CQ.js +1 -0
- package/dist/assets/BulkAddJobs-Di_IgRSH.js +5 -0
- package/dist/assets/Button-BPqpRZJD.js +1 -0
- package/dist/assets/Card-C7NMhqUt.js +1 -0
- package/dist/assets/{CopilotPanel-COLw-atS.js → CopilotPanel-Db5nYpo1.js} +3 -3
- package/dist/assets/Cron-BRgWcBGk.js +1 -0
- package/dist/assets/CronManager-CbM0x_s0.js +1 -0
- package/dist/assets/Database-BeoEreW0.js +3 -0
- package/dist/assets/Diagnostics-Cw9iJ84f.js +1 -0
- package/dist/assets/Dlq-DfCg04Jd.js +1 -0
- package/dist/assets/DlqControl-BRCkUXvb.js +1 -0
- package/dist/assets/DlqPro-BHJwBYsN.js +1 -0
- package/dist/assets/Flows-BAzbFP_W.js +2 -0
- package/dist/assets/JobInspector-qvW_APO6.js +2 -0
- package/dist/assets/Jobs-URpnFjC6.js +1 -0
- package/dist/assets/JobsPro-pQ_RFSU3.js +1 -0
- package/dist/assets/Logs-C5jX2OPE.js +1 -0
- package/dist/assets/LogsPro-Cq_npmmS.js +1 -0
- package/dist/assets/{McpServer-CbaU52l2.js → McpServer-DtCTmQBu.js} +2 -2
- package/dist/assets/Metrics-BdxitePr.js +1 -0
- package/dist/assets/MetricsPro-orHfW0mg.js +1 -0
- package/dist/assets/Overview-DaNns1aj.js +1 -0
- package/dist/assets/PageHeader-BXlZSBcc.js +1 -0
- package/dist/assets/Pagination-Q-vf4hsX.js +1 -0
- package/dist/assets/QueueActions-jiTzndPH.js +1 -0
- package/dist/assets/QueueControl-l5bSdMgb.js +1 -0
- package/dist/assets/QueueDetail-URK2pjtH.js +1 -0
- package/dist/assets/QueueDetailPro-C9M5CV4K.js +1 -0
- package/dist/assets/Queues-DeLXlww2.js +1 -0
- package/dist/assets/QueuesOverview-DoQ-MUfT.js +1 -0
- package/dist/assets/S3Backup-D2agV9_z.js +1 -0
- package/dist/assets/S3BackupPro--WSZWTQn.js +3 -0
- package/dist/assets/ServerControl-QVd6m_iR.js +3 -0
- package/dist/assets/Settings-CiJRj_SM.js +1 -0
- package/dist/assets/StatusBadge-B0I7hNBX.js +1 -0
- package/dist/assets/Usage-DbHJgA4t.js +1 -0
- package/dist/assets/UsagePro-LoPo3k1L.js +1 -0
- package/dist/assets/Webhooks-CuzIJHwk.js +1 -0
- package/dist/assets/Workers-BpUgpwUH.js +1 -0
- package/dist/assets/WorkersPro-BYY0P1Pt.js +1 -0
- package/dist/assets/Workflows-ByJw4FFH.js +1 -0
- package/dist/assets/api-V_sVpHDo.js +1 -0
- package/dist/assets/bq-DYmbVkgR.js +1 -0
- package/dist/assets/cn-zFEt5SO8.js +1 -0
- package/dist/assets/connectionStore-CKFQrxDo.js +1 -0
- package/dist/assets/controlConnectionEpoch-JM4omZ6j.js +1 -0
- package/dist/assets/feedback-BnGE2oW2.js +1 -0
- package/dist/assets/{flowMutationSafety-CoOp94wS.js → flowMutationSafety-DObp9nJo.js} +1 -1
- package/dist/assets/{form-DsUq0w8s.js → form-tC20r4Ma.js} +1 -1
- package/dist/assets/format-Cg7VCIZW.js +1 -0
- package/dist/assets/icons-CIvFfU2b.js +1 -0
- package/dist/assets/index-D64v2vNO.js +8 -0
- package/dist/assets/index-DOze4TKg.css +1 -0
- package/dist/assets/install-jXi1SOYY.js +3 -0
- package/dist/assets/{react-vendor-Bjui4wS4.js → react-vendor-CyjgmGTq.js} +3 -3
- package/dist/assets/responses-CBLyy1Ob.js +1 -0
- package/dist/assets/toastStore-B7n0zS0y.js +1 -0
- package/dist/assets/{upstreamPaths-D_LPsv7b.js → upstreamPaths-CDVsu6IM.js} +1 -1
- package/dist/assets/usePolledData-c53tx1jw.js +1 -0
- package/dist/assets/{useServerActionGuard-CItj3hvh.js → useServerActionGuard-OTv6_fU0.js} +1 -1
- package/dist/assets/useThroughputSeries-DWHQl7cM.js +1 -0
- package/dist/index.html +17 -6
- package/package.json +15 -4
- package/scripts/embedded.gen.ts +160 -134
- package/scripts/serve.ts +127 -484
- package/scripts/serveHandler.ts +237 -0
- package/scripts/servePolicy.ts +187 -0
- package/dist/assets/AddJob-CG28MSxU.js +0 -3
- package/dist/assets/Alerts-D9JojJrj.js +0 -1
- package/dist/assets/Benchmark-BVjUH9dG.js +0 -1
- package/dist/assets/BulkAddJobs-BHzUCMj_.js +0 -5
- package/dist/assets/Cron-DoEHDHwy.js +0 -1
- package/dist/assets/CronManager-vulcesqJ.js +0 -1
- package/dist/assets/Database-DlB_t04Z.js +0 -3
- package/dist/assets/Diagnostics-DddCUgeR.js +0 -1
- package/dist/assets/Dlq-DMKrsSMP.js +0 -1
- package/dist/assets/DlqControl-9m0Re_TH.js +0 -1
- package/dist/assets/DlqPro-Dmw-0wta.js +0 -1
- package/dist/assets/Flows-C3-9nXW4.js +0 -1
- package/dist/assets/JobInspector-DwIfABmI.js +0 -2
- package/dist/assets/Jobs-j8tTS3NC.js +0 -1
- package/dist/assets/JobsPro-CS__CJJl.js +0 -1
- package/dist/assets/Logs-BB-VDPA1.js +0 -1
- package/dist/assets/LogsPro-RNtSQZRT.js +0 -1
- package/dist/assets/Metrics-ivcddPwT.js +0 -1
- package/dist/assets/MetricsPro-xjZno4vg.js +0 -1
- package/dist/assets/Overview-D84aD2ph.js +0 -1
- package/dist/assets/Pagination-Bfi4vkpp.js +0 -1
- package/dist/assets/QueueActions-DTbD6uek.js +0 -1
- package/dist/assets/QueueControl-B5xK_SQ-.js +0 -1
- package/dist/assets/QueueDetail-BH59kwm9.js +0 -1
- package/dist/assets/QueueDetailPro-DoN25ndy.js +0 -1
- package/dist/assets/Queues-CKMJqFHX.js +0 -1
- package/dist/assets/QueuesOverview-BX1lzojl.js +0 -1
- package/dist/assets/S3Backup-Bz3GfoZ9.js +0 -1
- package/dist/assets/S3BackupPro-BC_6-uX-.js +0 -2
- package/dist/assets/ServerControl-CSSrN8G5.js +0 -3
- package/dist/assets/Settings-DkqmZUIS.js +0 -1
- package/dist/assets/Usage-Ba20p0xd.js +0 -1
- package/dist/assets/UsagePro-C2pQwjN9.js +0 -1
- package/dist/assets/Webhooks-CVuuvb0L.js +0 -1
- package/dist/assets/Workers-C1wPU6CS.js +0 -1
- package/dist/assets/WorkersPro-B0vEkC0T.js +0 -1
- package/dist/assets/Workflows-C8Qmkflf.js +0 -1
- package/dist/assets/cn-CMFYpumL.js +0 -1
- package/dist/assets/connectionStore-Cd9-3Fw0.js +0 -1
- package/dist/assets/index-BCNzbhhD.css +0 -1
- package/dist/assets/index-CAtsVmyh.js +0 -8
- package/dist/assets/install-D0eRLf9F.js +0 -3
- package/dist/assets/useThroughputSeries-DjxGN8ob.js +0 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { routeBackupRequest } from '../backup/routes';
|
|
2
|
+
import type { BackupRunnerPort } from '../backup/runner';
|
|
3
|
+
import { routeFlowRequest } from '../flow/routes';
|
|
4
|
+
import type { ManagedTargetPolicy } from '../managedTarget';
|
|
5
|
+
import type { ProcessManager } from '../manager';
|
|
6
|
+
import { routeQueueOperationsRequest } from '../queue/routes';
|
|
7
|
+
import type { QueueOperationsPort } from '../queue/types';
|
|
8
|
+
import type { WorkflowRuntimePort } from '../workflow/runtime';
|
|
9
|
+
import { routeWorkflowRuntimeRequest } from '../workflow/runtimeRoutes';
|
|
10
|
+
import { assertManagedControl, routeControlRequest } from './controlRoutes';
|
|
11
|
+
import type { ServerControlTarget } from './controlTarget';
|
|
12
|
+
import { routeDatabaseRequest } from './databaseRoutes';
|
|
13
|
+
import type { AgentLifecyclePort } from './lifecycle';
|
|
14
|
+
import { managedRuntimeAdmission } from './managedRuntime';
|
|
15
|
+
import type { RouteResponse } from './types';
|
|
16
|
+
import { routeWorkflowReadRequest } from './workflowReadRoutes';
|
|
17
|
+
|
|
18
|
+
export async function routeAgentRequest(
|
|
19
|
+
request: Request,
|
|
20
|
+
pathname: string,
|
|
21
|
+
method: string,
|
|
22
|
+
manager: ProcessManager,
|
|
23
|
+
runtime: WorkflowRuntimePort,
|
|
24
|
+
backupRunner: BackupRunnerPort,
|
|
25
|
+
queueRuntime: QueueOperationsPort,
|
|
26
|
+
lifecycle: AgentLifecyclePort,
|
|
27
|
+
origin: string | null,
|
|
28
|
+
allowedOrigins: string[],
|
|
29
|
+
controlTarget: ServerControlTarget,
|
|
30
|
+
managedTargetPolicy?: ManagedTargetPolicy
|
|
31
|
+
): Promise<RouteResponse | Response | null> {
|
|
32
|
+
if (pathname.startsWith('/control/')) {
|
|
33
|
+
const control = await routeControlRequest(
|
|
34
|
+
request,
|
|
35
|
+
pathname,
|
|
36
|
+
method,
|
|
37
|
+
manager,
|
|
38
|
+
runtime,
|
|
39
|
+
lifecycle,
|
|
40
|
+
controlTarget
|
|
41
|
+
);
|
|
42
|
+
if (control) return control;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const snapshot = manager.getStatus();
|
|
46
|
+
const managedConfig = snapshot.runningConfig ?? snapshot.config;
|
|
47
|
+
const admission = managedRuntimeAdmission(manager, lifecycle, snapshot);
|
|
48
|
+
if (pathname.startsWith('/flows/')) {
|
|
49
|
+
const flow = await routeFlowRequest(
|
|
50
|
+
request,
|
|
51
|
+
pathname,
|
|
52
|
+
method,
|
|
53
|
+
managedConfig,
|
|
54
|
+
snapshot.status === 'running',
|
|
55
|
+
{ admission, targetPolicy: managedTargetPolicy }
|
|
56
|
+
);
|
|
57
|
+
if (flow) return flow;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Runtime control must precede the generic /workflows/:executionId reader,
|
|
61
|
+
// otherwise GET /workflows/runtime is interpreted as an execution lookup.
|
|
62
|
+
if (isWorkflowRuntimeRoute(pathname, method)) {
|
|
63
|
+
const workflowRuntime = await routeWorkflowRuntimeRequest(
|
|
64
|
+
request,
|
|
65
|
+
pathname,
|
|
66
|
+
method,
|
|
67
|
+
managedConfig,
|
|
68
|
+
runtime,
|
|
69
|
+
snapshot.status === 'running',
|
|
70
|
+
admission,
|
|
71
|
+
managedTargetPolicy
|
|
72
|
+
);
|
|
73
|
+
if (workflowRuntime) return workflowRuntime;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const desiredConfig = manager.getConfig();
|
|
77
|
+
const workflowRead = routeWorkflowReadRequest(
|
|
78
|
+
request,
|
|
79
|
+
pathname,
|
|
80
|
+
method,
|
|
81
|
+
managedConfig.dataPath
|
|
82
|
+
);
|
|
83
|
+
if (workflowRead) return workflowRead;
|
|
84
|
+
|
|
85
|
+
if (pathname.startsWith('/queue-operations/')) {
|
|
86
|
+
const queueOperation = await routeQueueOperationsRequest(
|
|
87
|
+
request,
|
|
88
|
+
pathname,
|
|
89
|
+
method,
|
|
90
|
+
managedConfig,
|
|
91
|
+
queueRuntime,
|
|
92
|
+
snapshot.status === 'running',
|
|
93
|
+
admission,
|
|
94
|
+
managedTargetPolicy
|
|
95
|
+
);
|
|
96
|
+
if (queueOperation) return queueOperation;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (pathname.startsWith('/backup/')) {
|
|
100
|
+
if (pathname === '/backup/restore' && method === 'POST') {
|
|
101
|
+
assertManagedControl(controlTarget);
|
|
102
|
+
return manager.withStoppedMaintenance('restoring a backup', async () => {
|
|
103
|
+
const stoppedSnapshot = manager.getStatus();
|
|
104
|
+
const restoreDesired = manager.getConfig();
|
|
105
|
+
const restoreConfig = {
|
|
106
|
+
...(stoppedSnapshot.runningConfig ?? stoppedSnapshot.config),
|
|
107
|
+
extraEnv: restoreDesired.extraEnv,
|
|
108
|
+
};
|
|
109
|
+
return routeBackupRequest(
|
|
110
|
+
request,
|
|
111
|
+
pathname,
|
|
112
|
+
method,
|
|
113
|
+
restoreConfig,
|
|
114
|
+
stoppedSnapshot.status === 'running',
|
|
115
|
+
await manager.dbStats(),
|
|
116
|
+
backupRunner,
|
|
117
|
+
undefined,
|
|
118
|
+
managedTargetPolicy
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
const database = await manager.dbStats();
|
|
123
|
+
const backupConfig = { ...managedConfig, extraEnv: desiredConfig.extraEnv };
|
|
124
|
+
const backup = await routeBackupRequest(
|
|
125
|
+
request,
|
|
126
|
+
pathname,
|
|
127
|
+
method,
|
|
128
|
+
backupConfig,
|
|
129
|
+
snapshot.status === 'running',
|
|
130
|
+
database,
|
|
131
|
+
backupRunner,
|
|
132
|
+
(extraEnv) => manager.setConfig({ extraEnv }),
|
|
133
|
+
managedTargetPolicy
|
|
134
|
+
);
|
|
135
|
+
if (backup) return backup;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return routeDatabaseRequest(
|
|
139
|
+
request,
|
|
140
|
+
pathname,
|
|
141
|
+
method,
|
|
142
|
+
desiredConfig.dataPath,
|
|
143
|
+
origin,
|
|
144
|
+
allowedOrigins
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function isWorkflowRuntimeRoute(pathname: string, method: string): boolean {
|
|
149
|
+
if (method === 'GET') return pathname === '/workflows/runtime';
|
|
150
|
+
if (method !== 'POST') return false;
|
|
151
|
+
return (
|
|
152
|
+
[
|
|
153
|
+
'/workflows/runtime/reload',
|
|
154
|
+
'/workflows/start',
|
|
155
|
+
'/workflows/recover',
|
|
156
|
+
'/workflows/archive',
|
|
157
|
+
'/workflows/cleanup',
|
|
158
|
+
].includes(pathname) ||
|
|
159
|
+
/^\/workflows\/[^/]+\/(signal|resume-compensation|abandon-compensation)$/.test(pathname)
|
|
160
|
+
);
|
|
161
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { WorkflowRuntimePort } from '../workflow/runtime';
|
|
2
|
+
import type { ServerControlTarget } from './controlTarget';
|
|
3
|
+
|
|
4
|
+
export interface AgentOptions {
|
|
5
|
+
allowedOrigins: string[];
|
|
6
|
+
/** DNS-rebinding defense; compared by hostname only. */
|
|
7
|
+
allowedHosts?: string[];
|
|
8
|
+
/** On loopback, when set, changing requests must present this token. */
|
|
9
|
+
token?: string;
|
|
10
|
+
/** Network exposure: require token on every non-OPTIONS request. */
|
|
11
|
+
requireTokenForAll?: boolean;
|
|
12
|
+
/** Managed child by default; external mode makes lifecycle routes attach-only. */
|
|
13
|
+
controlTarget?: ServerControlTarget;
|
|
14
|
+
/** Exact browser-visible `/api` alias accepted by target-pinned agent routes. */
|
|
15
|
+
managedProxyPath?: string;
|
|
16
|
+
/** Upstream URL the alias must resolve to; it still passes the local-target gate. */
|
|
17
|
+
managedProxyUrl?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AgentFetchHandler {
|
|
21
|
+
(request: Request): Promise<Response>;
|
|
22
|
+
/** Release the handler's persistent SDK resources. */
|
|
23
|
+
close(): Promise<void>;
|
|
24
|
+
/** Synchronously close admission and latch the process manager, then drain resources. */
|
|
25
|
+
beginShutdown(): Promise<void>;
|
|
26
|
+
/** Close resources through the lifecycle gate, then stop the managed process. */
|
|
27
|
+
shutdown(): Promise<void>;
|
|
28
|
+
/** Send SIGKILL to the managed process after terminal grace is exhausted. */
|
|
29
|
+
forceShutdown(): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface RouteResponse {
|
|
33
|
+
status: number;
|
|
34
|
+
body: unknown;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type JsonResponder = (
|
|
38
|
+
data: unknown,
|
|
39
|
+
status: number,
|
|
40
|
+
origin: string | null
|
|
41
|
+
) => Response;
|
|
42
|
+
|
|
43
|
+
export interface HandlerResources {
|
|
44
|
+
runtime: WorkflowRuntimePort;
|
|
45
|
+
close(): Promise<void>;
|
|
46
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type WorkflowStateFilter,
|
|
3
|
+
type WorkflowStoreKind,
|
|
4
|
+
workflowExecution,
|
|
5
|
+
workflowExecutions,
|
|
6
|
+
workflowStats,
|
|
7
|
+
WORKFLOW_STATES,
|
|
8
|
+
} from '../workflows';
|
|
9
|
+
import type { RouteResponse } from './types';
|
|
10
|
+
|
|
11
|
+
function workflowKind(query: URLSearchParams): WorkflowStoreKind {
|
|
12
|
+
const kind = query.get('kind') ?? 'active';
|
|
13
|
+
if (kind !== 'active' && kind !== 'archive') {
|
|
14
|
+
throw new Error('Workflow kind must be "active" or "archive"');
|
|
15
|
+
}
|
|
16
|
+
return kind;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function integer(query: URLSearchParams, name: 'limit' | 'offset', fallback: number): number {
|
|
20
|
+
const raw = query.get(name);
|
|
21
|
+
if (raw === null) return fallback;
|
|
22
|
+
if (!/^\d+$/.test(raw)) throw new Error(`Workflow ${name} must be an integer`);
|
|
23
|
+
return Number(raw);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function routeWorkflowReadRequest(
|
|
27
|
+
request: Request,
|
|
28
|
+
pathname: string,
|
|
29
|
+
method: string,
|
|
30
|
+
dataPath: string
|
|
31
|
+
): RouteResponse | null {
|
|
32
|
+
if (pathname === '/workflows/stats' && method === 'GET') {
|
|
33
|
+
return { status: 200, body: { ok: true, ...workflowStats(dataPath) } };
|
|
34
|
+
}
|
|
35
|
+
if (pathname === '/workflows' && method === 'GET') {
|
|
36
|
+
const query = new URL(request.url).searchParams;
|
|
37
|
+
const allowed = new Set(['kind', 'workflowName', 'state', 'limit', 'offset']);
|
|
38
|
+
for (const key of query.keys()) {
|
|
39
|
+
if (!allowed.has(key)) throw new Error(`Unknown workflow option: ${key}`);
|
|
40
|
+
if (query.getAll(key).length !== 1) throw new Error(`Duplicate workflow option: ${key}`);
|
|
41
|
+
}
|
|
42
|
+
const state = query.get('state') || undefined;
|
|
43
|
+
if (
|
|
44
|
+
state &&
|
|
45
|
+
state !== 'compensation' &&
|
|
46
|
+
!(WORKFLOW_STATES as readonly string[]).includes(state)
|
|
47
|
+
) {
|
|
48
|
+
throw new Error('Unknown workflow execution state');
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
status: 200,
|
|
52
|
+
body: {
|
|
53
|
+
ok: true,
|
|
54
|
+
...workflowExecutions(dataPath, {
|
|
55
|
+
kind: workflowKind(query),
|
|
56
|
+
workflowName: query.get('workflowName') || undefined,
|
|
57
|
+
state: state as WorkflowStateFilter | undefined,
|
|
58
|
+
limit: integer(query, 'limit', 50),
|
|
59
|
+
offset: integer(query, 'offset', 0),
|
|
60
|
+
}),
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (!pathname.startsWith('/workflows/') || method !== 'GET') return null;
|
|
65
|
+
const rawId = pathname.slice('/workflows/'.length);
|
|
66
|
+
if (!rawId || rawId.includes('/')) {
|
|
67
|
+
return { status: 404, body: { ok: false, error: 'Not found' } };
|
|
68
|
+
}
|
|
69
|
+
const query = new URL(request.url).searchParams;
|
|
70
|
+
for (const key of query.keys()) {
|
|
71
|
+
if (key !== 'kind') throw new Error(`Unknown workflow detail option: ${key}`);
|
|
72
|
+
if (query.getAll(key).length !== 1) {
|
|
73
|
+
throw new Error(`Duplicate workflow detail option: ${key}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const execution = workflowExecution(dataPath, decodeURIComponent(rawId), workflowKind(query));
|
|
77
|
+
return execution
|
|
78
|
+
? { status: 200, body: { ok: true, execution } }
|
|
79
|
+
: { status: 404, body: { ok: false, error: 'Workflow execution not found' } };
|
|
80
|
+
}
|