@lostgradient/weft 0.15.0 → 0.17.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/README.md +1 -1
- package/dist/alerting/alert-manager.d.ts +5 -3
- package/dist/alerting/alert-manager.js +26 -5
- package/dist/alerting/index.d.ts +1 -1
- package/dist/alerting/types.d.ts +17 -13
- package/dist/alerting/types.js +5 -0
- package/dist/cli/api.js +5 -19
- package/dist/cli/console.d.ts +12 -0
- package/dist/cli/console.js +62 -0
- package/dist/cli/generated/operation-catalog.snapshot.json +71 -0
- package/dist/cli/generated/operation-client.generated.d.ts +15 -2
- package/dist/cli/generated/operation-client.generated.js +2 -0
- package/dist/cli/help-text.d.ts +1 -1
- package/dist/cli/help-text.js +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/cli/json-input.d.ts +20 -0
- package/dist/cli/json-input.js +33 -0
- package/dist/cli/parse-arguments.js +2 -0
- package/dist/cli/schedule.js +7 -9
- package/dist/cli/types.d.ts +1 -0
- package/dist/cli/workflow-commands.js +5 -25
- package/dist/cli-main.js +4 -2
- package/dist/core/engine/disposal.js +7 -0
- package/dist/core/engine/engine-runtime-helpers.d.ts +3 -1
- package/dist/core/engine/engine-runtime-helpers.js +2 -2
- package/dist/core/engine/errors.d.ts +20 -0
- package/dist/core/engine/errors.js +8 -0
- package/dist/core/engine/index.d.ts +39 -14
- package/dist/core/engine/index.js +84 -9
- package/dist/core/engine/inline-launch-queue.d.ts +6 -2
- package/dist/core/engine/inline-launch-queue.js +41 -6
- package/dist/core/engine/internals.d.ts +2 -0
- package/dist/core/engine/lease-manager.d.ts +3 -2
- package/dist/core/engine/lease-manager.js +7 -3
- package/dist/core/engine/operations-time.js +6 -0
- package/dist/core/execution-strategy.d.ts +8 -0
- package/dist/core/inline-execution-strategy.d.ts +1 -0
- package/dist/core/inline-execution-strategy.js +33 -20
- package/dist/core/weft-error.d.ts +1 -1
- package/dist/core/weft-error.js +1 -0
- package/dist/core/worker-execution-strategy.d.ts +2 -0
- package/dist/core/worker-execution-strategy.js +7 -2
- package/dist/core/worker-turn-watchdog.d.ts +4 -1
- package/dist/core/worker-turn-watchdog.js +9 -4
- package/dist/diagnostics/recommendations.js +1 -9
- package/dist/http.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -0
- package/dist/indexeddb.js +1 -1
- package/dist/json-schema.js +1 -1
- package/dist/mcp/tools.js +1 -3
- package/dist/server/authorization-scope.d.ts +1 -1
- package/dist/server/authorization-scope.js +0 -2
- package/dist/server/dashboard-assets.d.ts +37 -0
- package/dist/server/dashboard-assets.js +209 -0
- package/dist/server/index.d.ts +10 -1
- package/dist/server/index.js +11 -2
- package/dist/server/interactive-operations.js +1 -0
- package/dist/server/operations/aggregate-workflows.js +0 -7
- package/dist/server/operations/async-activity.js +5 -24
- package/dist/server/operations/bulk-cancel-workflows.js +3 -8
- package/dist/server/operations/bulk-delete-workflows.js +3 -8
- package/dist/server/operations/bulk-mutate-workflow-tags.js +3 -8
- package/dist/server/operations/bulk-operation-helpers.d.ts +2 -10
- package/dist/server/operations/bulk-operation-helpers.js +0 -6
- package/dist/server/operations/bulk-retry-failed-workflows.js +3 -8
- package/dist/server/operations/bulk-signal-workflows.js +3 -8
- package/dist/server/operations/cancel-schedule.js +1 -3
- package/dist/server/operations/cancel-workflow.js +1 -3
- package/dist/server/operations/create-schedule.js +21 -49
- package/dist/server/operations/fork-workflow.js +2 -3
- package/dist/server/operations/get-checkpoint-at.js +1 -6
- package/dist/server/operations/get-registry.js +1 -7
- package/dist/server/operations/get-retention-overview.js +2 -15
- package/dist/server/operations/get-review.js +2 -15
- package/dist/server/operations/get-schedule.js +2 -8
- package/dist/server/operations/get-stream-chunks.js +2 -6
- package/dist/server/operations/get-system-lease.js +1 -7
- package/dist/server/operations/get-system-metrics.js +0 -4
- package/dist/server/operations/get-task-diagnostics.js +2 -13
- package/dist/server/operations/get-update-result.js +1 -6
- package/dist/server/operations/get-workflow-attributes.js +2 -15
- package/dist/server/operations/get-workflow-events.js +2 -15
- package/dist/server/operations/get-workflow-observability.js +2 -5
- package/dist/server/operations/get-workflow-result.js +0 -7
- package/dist/server/operations/get-workflow-timeline.js +1 -6
- package/dist/server/operations/get-workflow.d.ts +3 -6
- package/dist/server/operations/get-workflow.js +2 -12
- package/dist/server/operations/list-alerts.d.ts +29 -0
- package/dist/server/operations/list-alerts.js +47 -0
- package/dist/server/operations/list-checkpoints.js +1 -6
- package/dist/server/operations/list-reviews.js +0 -7
- package/dist/server/operations/list-schedules.js +3 -8
- package/dist/server/operations/list-task-queues.js +0 -4
- package/dist/server/operations/list-workers.js +0 -4
- package/dist/server/operations/list-workflows.js +0 -7
- package/dist/server/operations/pause-schedule.js +1 -3
- package/dist/server/operations/purge-workflows.js +2 -5
- package/dist/server/operations/query-workflow.js +4 -15
- package/dist/server/operations/replay-workflow.js +2 -6
- package/dist/server/operations/resume-schedule.js +1 -3
- package/dist/server/operations/resume-workflow.js +1 -3
- package/dist/server/operations/schedule-faults.d.ts +9 -1
- package/dist/server/operations/schedule-faults.js +51 -0
- package/dist/server/operations/set-workflow-attributes.js +3 -15
- package/dist/server/operations/signal-workflow.js +3 -12
- package/dist/server/operations/single-workflow-tag-mutation.js +0 -7
- package/dist/server/operations/start-or-signal-workflow.js +2 -3
- package/dist/server/operations/start-workflow.js +2 -3
- package/dist/server/operations/storage-capabilities.js +1 -3
- package/dist/server/operations/storage.js +7 -13
- package/dist/server/operations/submit-review-decision.js +3 -12
- package/dist/server/operations/suspend-workflow.js +1 -3
- package/dist/server/operations/timeout-workflow.js +1 -3
- package/dist/server/operations/update-schedule.js +7 -56
- package/dist/server/operations/update-workflow.js +2 -3
- package/dist/server/operations/worker-drain.js +0 -8
- package/dist/server/rest-binding.d.ts +3 -2
- package/dist/server/rest-bindings.js +3 -0
- package/dist/server/route-model.d.ts +2 -0
- package/dist/server/route-model.js +1 -1
- package/dist/server/runtime/task-reconciliation.d.ts +10 -1
- package/dist/server/runtime/task-reconciliation.js +26 -2
- package/dist/server/serve-internals.js +12 -6
- package/dist/service-worker/index.d.ts +4 -1
- package/dist/service-worker/index.js +2 -2
- package/dist/service-worker/setup.d.ts +20 -0
- package/dist/service-worker/setup.js +5 -5
- package/dist/storage/bun-sql.js +13 -31
- package/dist/storage/indexeddb.js +28 -48
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +2 -2
- package/dist/storage/postgres.js +2 -2
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/testing.d.ts +6 -3
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/dist/worker/protocol-schemas.d.ts +2 -2
- package/dist/worker/protocol-schemas.js +2 -2
- package/dist/worker/protocol.js +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as fileSystem from "node:fs";
|
|
2
|
+
import { isAbsolute, join, relative, resolve as resolvePath, sep } from "node:path";
|
|
3
|
+
import { API_PREFIX, DIRECT_HTTP_ROUTES, ROOT_API_PREFIX } from "./route-model.js";
|
|
4
|
+
function overlapsDashboardPageRoute(prefix, route) {
|
|
5
|
+
if (route.endsWith("/*")) {
|
|
6
|
+
const base = route.slice(0, -2);
|
|
7
|
+
return prefix === base || prefix.startsWith(`${base}/`);
|
|
8
|
+
}
|
|
9
|
+
return prefix === route;
|
|
10
|
+
}
|
|
11
|
+
function overlapsWildcardRoute(prefix, route) {
|
|
12
|
+
return prefix === route || prefix.startsWith(`${route}/`) || route.startsWith(`${prefix}/`);
|
|
13
|
+
}
|
|
14
|
+
function hasInvalidPrefixShape(prefix) {
|
|
15
|
+
return prefix.length === 0 || prefix === "/" || !prefix.startsWith("/") || prefix.endsWith("/") || ["?", "#", "%", "*", ":", "\\"].some((character) => prefix.includes(character));
|
|
16
|
+
}
|
|
17
|
+
function validateAssetPrefixShape(prefix) {
|
|
18
|
+
if (hasInvalidPrefixShape(prefix))
|
|
19
|
+
throw Error("dashboardAssets.prefix must be an absolute path prefix without a trailing slash, wildcard, parameter, query, fragment, percent escape, or backslash");
|
|
20
|
+
if (prefix.split("/").slice(1).some((segment) => segment.length === 0 || segment === "." || segment === ".."))
|
|
21
|
+
throw Error("dashboardAssets.prefix must contain only concrete, non-empty path segments");
|
|
22
|
+
const serializedPathname = new URL(prefix, "http://weft.invalid").pathname;
|
|
23
|
+
if (serializedPathname !== prefix)
|
|
24
|
+
throw Error(`dashboardAssets.prefix must round-trip through URL serialization unchanged; ${prefix} serializes as ${serializedPathname}`);
|
|
25
|
+
}
|
|
26
|
+
function validateAssetPrefixReservations(prefix, pageRoutes) {
|
|
27
|
+
if ([
|
|
28
|
+
API_PREFIX,
|
|
29
|
+
ROOT_API_PREFIX,
|
|
30
|
+
...DIRECT_HTTP_ROUTES.map(({ path }) => path)
|
|
31
|
+
].some((reserved) => overlapsWildcardRoute(prefix, reserved)))
|
|
32
|
+
throw Error("dashboardAssets.prefix must not overlap the /api, /v1, or direct HTTP route spaces");
|
|
33
|
+
if (pageRoutes.some((route) => overlapsDashboardPageRoute(prefix, route)))
|
|
34
|
+
throw Error("dashboardAssets.prefix must not overlap dashboard page routes");
|
|
35
|
+
}
|
|
36
|
+
function validateAssetPrefix(prefix, pageRoutes) {
|
|
37
|
+
validateAssetPrefixShape(prefix);
|
|
38
|
+
validateAssetPrefixReservations(prefix, pageRoutes);
|
|
39
|
+
}
|
|
40
|
+
export function resolveDashboardAssets(value, pageRoutes) {
|
|
41
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
42
|
+
throw Error("dashboardAssets must be an object with prefix and directory strings");
|
|
43
|
+
if (!("prefix" in value) || !("directory" in value))
|
|
44
|
+
throw Error("dashboardAssets.prefix and dashboardAssets.directory must be strings");
|
|
45
|
+
const { prefix, directory } = value;
|
|
46
|
+
if (typeof prefix !== "string" || typeof directory !== "string")
|
|
47
|
+
throw Error("dashboardAssets.prefix and dashboardAssets.directory must be strings");
|
|
48
|
+
validateAssetPrefix(prefix, pageRoutes);
|
|
49
|
+
const resolvedDirectory = resolvePath(directory);
|
|
50
|
+
let directoryStats;
|
|
51
|
+
try {
|
|
52
|
+
directoryStats = fileSystem.statSync(resolvedDirectory);
|
|
53
|
+
} catch {
|
|
54
|
+
throw Error(`dashboardAssets.directory does not exist: ${directory}`);
|
|
55
|
+
}
|
|
56
|
+
if (!directoryStats.isDirectory())
|
|
57
|
+
throw Error(`dashboardAssets.directory must be a directory: ${directory}`);
|
|
58
|
+
return { prefix, directory: fileSystem.realpathSync(resolvedDirectory) };
|
|
59
|
+
}
|
|
60
|
+
function isWithinDirectory(directory, path) {
|
|
61
|
+
const pathRelativeToDirectory = relative(directory, path);
|
|
62
|
+
return pathRelativeToDirectory.length > 0 && pathRelativeToDirectory !== ".." && !pathRelativeToDirectory.startsWith(`..${sep}`) && !isAbsolute(pathRelativeToDirectory);
|
|
63
|
+
}
|
|
64
|
+
function hasSameFileIdentity(left, right) {
|
|
65
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
66
|
+
}
|
|
67
|
+
function resolveAssetPath(directory, prefix, request) {
|
|
68
|
+
if (request.signal.aborted)
|
|
69
|
+
return;
|
|
70
|
+
const rawWildcardPath = new URL(request.url).pathname.slice(prefix.length + 1);
|
|
71
|
+
let wildcardPath;
|
|
72
|
+
try {
|
|
73
|
+
wildcardPath = decodeURIComponent(rawWildcardPath);
|
|
74
|
+
} catch {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (wildcardPath.length === 0)
|
|
78
|
+
return;
|
|
79
|
+
const pathSegments = wildcardPath.split(/[\\/]/);
|
|
80
|
+
if (pathSegments.some((segment) => segment === ".." || segment.length === 0))
|
|
81
|
+
return;
|
|
82
|
+
const assetPath = resolvePath(join(directory, ...pathSegments));
|
|
83
|
+
if (!isWithinDirectory(directory, assetPath))
|
|
84
|
+
return;
|
|
85
|
+
return assetPath;
|
|
86
|
+
}
|
|
87
|
+
function isVerifiedAssetDescriptor(request, directory, canonicalStats, openedStats, postOpenStats, postOpenAssetPath, openedAssetPath) {
|
|
88
|
+
return !request.signal.aborted && isWithinDirectory(directory, postOpenAssetPath) && (openedAssetPath === void 0 || isWithinDirectory(directory, openedAssetPath)) && canonicalStats.isFile() && openedStats.isFile() && postOpenStats.isFile() && hasSameFileIdentity(openedStats, canonicalStats) && hasSameFileIdentity(openedStats, postOpenStats);
|
|
89
|
+
}
|
|
90
|
+
function resolveOpenedDescriptorPath(descriptor, assetFileSystem) {
|
|
91
|
+
for (const descriptorPath of [`/proc/self/fd/${descriptor}`, `/dev/fd/${descriptor}`])
|
|
92
|
+
try {
|
|
93
|
+
const resolvedPath = assetFileSystem.realpathSync(descriptorPath);
|
|
94
|
+
if (resolvedPath.startsWith("/proc/self/fd/") || resolvedPath.startsWith("/dev/fd/"))
|
|
95
|
+
continue;
|
|
96
|
+
return resolvedPath;
|
|
97
|
+
} catch {}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
function createAssetStream(descriptor, verifiedSize, assetFileSystem) {
|
|
101
|
+
let closed = !1, cancelled = !1, position = 0, remainingBytes = verifiedSize, inFlightRead;
|
|
102
|
+
const close = () => {
|
|
103
|
+
if (!closed) {
|
|
104
|
+
closed = !0;
|
|
105
|
+
assetFileSystem.closeSync(descriptor);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
return { stream: new ReadableStream({
|
|
109
|
+
async pull(controller) {
|
|
110
|
+
if (cancelled)
|
|
111
|
+
return;
|
|
112
|
+
if (remainingBytes === 0) {
|
|
113
|
+
close();
|
|
114
|
+
controller.close();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const buffer = Buffer.allocUnsafe(Math.min(65536, remainingBytes)), read = assetFileSystem.read(descriptor, buffer, 0, buffer.byteLength, position);
|
|
118
|
+
inFlightRead = read;
|
|
119
|
+
try {
|
|
120
|
+
const bytesRead = await read;
|
|
121
|
+
if (cancelled) {
|
|
122
|
+
close();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (bytesRead === 0) {
|
|
126
|
+
close();
|
|
127
|
+
controller.error(Error("Dashboard asset ended before its verified content length was read."));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const boundedBytesRead = Math.min(bytesRead, remainingBytes);
|
|
131
|
+
position += boundedBytesRead;
|
|
132
|
+
remainingBytes -= boundedBytesRead;
|
|
133
|
+
controller.enqueue(buffer.subarray(0, boundedBytesRead));
|
|
134
|
+
if (remainingBytes === 0) {
|
|
135
|
+
close();
|
|
136
|
+
controller.close();
|
|
137
|
+
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
close();
|
|
140
|
+
if (!cancelled)
|
|
141
|
+
controller.error(error);
|
|
142
|
+
} finally {
|
|
143
|
+
if (inFlightRead === read)
|
|
144
|
+
inFlightRead = void 0;
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
async cancel() {
|
|
148
|
+
cancelled = !0;
|
|
149
|
+
try {
|
|
150
|
+
await inFlightRead;
|
|
151
|
+
} catch {}
|
|
152
|
+
close();
|
|
153
|
+
}
|
|
154
|
+
}), close };
|
|
155
|
+
}
|
|
156
|
+
function readAssetDescriptor(descriptor, buffer, offset, length, position) {
|
|
157
|
+
return new Promise((_resolve, reject) => {
|
|
158
|
+
fileSystem.read(descriptor, buffer, offset, length, position, (error, bytesRead) => {
|
|
159
|
+
if (error)
|
|
160
|
+
reject(error);
|
|
161
|
+
else
|
|
162
|
+
_resolve(bytesRead);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function assetResponse(directory, prefix, request, assetFileSystem) {
|
|
167
|
+
const assetPath = resolveAssetPath(directory, prefix, request);
|
|
168
|
+
if (assetPath === void 0)
|
|
169
|
+
return new Response("Not Found", { status: 404 });
|
|
170
|
+
let descriptor;
|
|
171
|
+
try {
|
|
172
|
+
const realAssetPath = assetFileSystem.realpathSync(assetPath);
|
|
173
|
+
if (!isWithinDirectory(directory, realAssetPath))
|
|
174
|
+
return new Response("Not Found", { status: 404 });
|
|
175
|
+
const canonicalStats = assetFileSystem.statSync(realAssetPath);
|
|
176
|
+
descriptor = assetFileSystem.openSync(realAssetPath, assetFileSystem.constants.O_RDONLY | assetFileSystem.constants.O_NOFOLLOW | assetFileSystem.constants.O_NONBLOCK);
|
|
177
|
+
const fileStats = assetFileSystem.fstatSync(descriptor), postOpenAssetPath = assetFileSystem.realpathSync(realAssetPath), postOpenStats = assetFileSystem.statSync(postOpenAssetPath), openedAssetPath = resolveOpenedDescriptorPath(descriptor, assetFileSystem);
|
|
178
|
+
if (!isVerifiedAssetDescriptor(request, directory, canonicalStats, fileStats, postOpenStats, postOpenAssetPath, openedAssetPath))
|
|
179
|
+
return new Response("Not Found", { status: 404 });
|
|
180
|
+
const headers = {
|
|
181
|
+
"content-length": String(fileStats.size),
|
|
182
|
+
"content-type": Bun.file(realAssetPath).type
|
|
183
|
+
};
|
|
184
|
+
if (request.method === "HEAD")
|
|
185
|
+
return new Response(null, { headers });
|
|
186
|
+
const assetStream = createAssetStream(descriptor, fileStats.size, assetFileSystem);
|
|
187
|
+
try {
|
|
188
|
+
const response = new Response(assetStream.stream, { headers });
|
|
189
|
+
descriptor = void 0;
|
|
190
|
+
return response;
|
|
191
|
+
} catch {
|
|
192
|
+
assetStream.close();
|
|
193
|
+
descriptor = void 0;
|
|
194
|
+
return new Response("Not Found", { status: 404 });
|
|
195
|
+
}
|
|
196
|
+
} catch {
|
|
197
|
+
return new Response("Not Found", { status: 404 });
|
|
198
|
+
} finally {
|
|
199
|
+
if (descriptor !== void 0)
|
|
200
|
+
assetFileSystem.closeSync(descriptor);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
export function createDashboardAssetRoute(assets, assetFileSystem) {
|
|
204
|
+
const fileSystemForAsset = assetFileSystem ?? {
|
|
205
|
+
...fileSystem,
|
|
206
|
+
read: readAssetDescriptor
|
|
207
|
+
}, handler = (request) => assetResponse(assets.directory, assets.prefix, request, fileSystemForAsset);
|
|
208
|
+
return { GET: handler, HEAD: handler };
|
|
209
|
+
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -10,11 +10,13 @@ import type { PrometheusExporter } from '../observability/metrics.ts';
|
|
|
10
10
|
import type { RoutingPolicy } from '../worker/registry.ts';
|
|
11
11
|
import { WorkerRegistry } from '../worker/registry.ts';
|
|
12
12
|
import type { AuthConfig, RateLimitConfig } from './authentication.ts';
|
|
13
|
+
import { type DashboardAssets } from './dashboard-assets.ts';
|
|
13
14
|
import type { DiscoveryInfo } from './discovery-info.ts';
|
|
14
15
|
import type { CorsOptions } from './runtime/cors.ts';
|
|
15
16
|
import type { SchedulingPolicy } from './task-queue-types.ts';
|
|
16
17
|
import { TaskQueue } from './task-queue.ts';
|
|
17
18
|
export { wireEventBroadcasting, type EventBroadcastingHandle, } from './runtime/event-broadcasting.ts';
|
|
19
|
+
export type { DashboardAssets } from './dashboard-assets.ts';
|
|
18
20
|
export type { CorsOptions } from './runtime/cors.ts';
|
|
19
21
|
export { createRateLimiter, createRotatingApiKeyStore, defaultAuthAuditSink, isSensitiveHeader, redactCredential, redactHeaders, validateRateLimitConfig, type ApiKeyRegistration, type AuthAuditEvent, type AuthAuditSink, type AuthConfig, type RateLimitConfig, type RateLimitDecision, type RateLimiter, type RotatingApiKeyStore, } from './authentication.ts';
|
|
20
22
|
export type { RetryPolicy } from '../core/types.ts';
|
|
@@ -32,6 +34,8 @@ export { TaskQueue } from './task-queue.ts';
|
|
|
32
34
|
* They are intentionally specific (no blanket `/*`) so they cannot shadow the
|
|
33
35
|
* API served under the `/api` prefix or the root-stable discovery endpoints —
|
|
34
36
|
* those fall through to the `fetch` handler.
|
|
37
|
+
* The supported page routes are `/`, `/workflows`, `/workflows/*`, `/reviews`,
|
|
38
|
+
* `/workers`, `/schedules`, `/storage`, and `/system`.
|
|
35
39
|
*
|
|
36
40
|
* @example
|
|
37
41
|
* ```ts
|
|
@@ -42,7 +46,7 @@ export { TaskQueue } from './task-queue.ts';
|
|
|
42
46
|
* console.log(DASHBOARD_PAGE_ROUTES.includes('/workflows')); // true
|
|
43
47
|
* ```
|
|
44
48
|
*/
|
|
45
|
-
export declare const DASHBOARD_PAGE_ROUTES: readonly ["/", "/workflows", "/workflows/*", "/reviews", "/workers"];
|
|
49
|
+
export declare const DASHBOARD_PAGE_ROUTES: readonly ["/", "/workflows", "/workflows/*", "/reviews", "/workers", "/schedules", "/storage", "/system"];
|
|
46
50
|
/**
|
|
47
51
|
* Route pattern owned by an externally supplied dashboard shell.
|
|
48
52
|
*
|
|
@@ -129,6 +133,11 @@ export interface ServeOptions {
|
|
|
129
133
|
development?: boolean;
|
|
130
134
|
/** Optional external dashboard shell served at {@link DASHBOARD_PAGE_ROUTES}. */
|
|
131
135
|
dashboard?: DashboardRouteTarget;
|
|
136
|
+
/**
|
|
137
|
+
* Static files served below an explicit prefix for the supplied dashboard.
|
|
138
|
+
* The directory and prefix are validated synchronously before the port binds.
|
|
139
|
+
*/
|
|
140
|
+
dashboardAssets?: DashboardAssets;
|
|
132
141
|
/** Authentication configuration. When provided, all non-public endpoints require valid credentials. */
|
|
133
142
|
auth?: AuthConfig;
|
|
134
143
|
/**
|
package/dist/server/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { WorkerRegistry } from "../worker/registry.js";
|
|
2
|
+
import {
|
|
3
|
+
createDashboardAssetRoute,
|
|
4
|
+
resolveDashboardAssets
|
|
5
|
+
} from "./dashboard-assets.js";
|
|
2
6
|
import { createServerWebSocketHandlers } from "./runtime/authentication-bridge.js";
|
|
3
7
|
import {
|
|
4
8
|
wireEventBroadcasting
|
|
@@ -39,13 +43,18 @@ export const DASHBOARD_PAGE_ROUTES = [
|
|
|
39
43
|
"/workflows",
|
|
40
44
|
"/workflows/*",
|
|
41
45
|
"/reviews",
|
|
42
|
-
"/workers"
|
|
46
|
+
"/workers",
|
|
47
|
+
"/schedules",
|
|
48
|
+
"/storage",
|
|
49
|
+
"/system"
|
|
43
50
|
];
|
|
44
51
|
export function serve(options) {
|
|
45
|
-
const { port, hostname, development, tlsOptions, serverOptions, serverMetricsCollector } = resolveNetworkConfig(options), context = buildServerContext(serverOptions, serverMetricsCollector), boundCleanup = (operationId) => cleanupWorkflowIndex(context, operationId), routes = {};
|
|
52
|
+
const dashboardAssets = options.dashboardAssets === void 0 ? void 0 : resolveDashboardAssets(options.dashboardAssets, DASHBOARD_PAGE_ROUTES), { port, hostname, development, tlsOptions, serverOptions, serverMetricsCollector } = resolveNetworkConfig(options), context = buildServerContext(serverOptions, serverMetricsCollector), boundCleanup = (operationId) => cleanupWorkflowIndex(context, operationId), routes = {};
|
|
46
53
|
if (options.dashboard != null)
|
|
47
54
|
for (const path of DASHBOARD_PAGE_ROUTES)
|
|
48
55
|
routes[path] = options.dashboard;
|
|
56
|
+
if (dashboardAssets !== void 0)
|
|
57
|
+
routes[`${dashboardAssets.prefix}/*`] = createDashboardAssetRoute(dashboardAssets);
|
|
49
58
|
const serverHolder = { current: null }, server = Bun.serve(buildBunServeConfig(port, hostname, development, routes, tlsOptions, buildFetchHandler(serverHolder, context, serverOptions), createServerWebSocketHandlers(context, serverOptions, boundCleanup)));
|
|
50
59
|
serverHolder.current = server;
|
|
51
60
|
const stack = new AsyncDisposableStack;
|
|
@@ -79,12 +79,6 @@ function extractAggregateWorkflowsInput(request) {
|
|
|
79
79
|
...limitValue !== void 0 && Number.isFinite(limitValue) && limitValue >= 1 ? { limit: limitValue } : {}
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
|
-
function shapeAggregateWorkflowsSuccess(result) {
|
|
83
|
-
return new Response(JSON.stringify(result), {
|
|
84
|
-
status: 200,
|
|
85
|
-
headers: { "Content-Type": "application/json" }
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
82
|
function shapeAggregateWorkflowsFault(fault) {
|
|
89
83
|
if (fault.code === "Unprocessable")
|
|
90
84
|
return shapeRestFault(fault, { status: 400 });
|
|
@@ -106,6 +100,5 @@ export const aggregateWorkflowsRestBinding = {
|
|
|
106
100
|
},
|
|
107
101
|
extractInput: async (request) => extractAggregateWorkflowsInput(request),
|
|
108
102
|
success: { kind: "json", status: 200 },
|
|
109
|
-
shapeSuccess: (output) => shapeAggregateWorkflowsSuccess(output),
|
|
110
103
|
shapeFault: shapeAggregateWorkflowsFault
|
|
111
104
|
};
|
|
@@ -11,7 +11,7 @@ import { PayloadSizeExceededError } from "../../core/payload-size.js";
|
|
|
11
11
|
import { raiseFault } from "../operation-catalog.js";
|
|
12
12
|
import { defineOperation } from "../operation-registry.js";
|
|
13
13
|
import { readRestJsonBody } from "../rest-body.js";
|
|
14
|
-
import { invalidParamsFault, isOperationFault
|
|
14
|
+
import { invalidParamsFault, isOperationFault } from "./operation-helpers.js";
|
|
15
15
|
const asyncActivityReadAccess = {
|
|
16
16
|
kind: "scoped",
|
|
17
17
|
scopes: { kind: "anyOf", scopes: ["workflows:read"] }
|
|
@@ -137,20 +137,7 @@ export const completeAsyncActivityOperation = defineOperation({
|
|
|
137
137
|
}
|
|
138
138
|
return { ok: !0 };
|
|
139
139
|
}
|
|
140
|
-
})
|
|
141
|
-
function shapeAsyncActivitySuccess(output) {
|
|
142
|
-
return new Response(JSON.stringify(output), {
|
|
143
|
-
status: 200,
|
|
144
|
-
headers: { "Content-Type": "application/json" }
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
function shapePendingAsyncActivitiesSuccess(output) {
|
|
148
|
-
return new Response(JSON.stringify(output), {
|
|
149
|
-
status: 200,
|
|
150
|
-
headers: { "Content-Type": "application/json" }
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
export const listPendingAsyncActivitiesRestBinding = {
|
|
140
|
+
}), listPendingAsyncActivitiesRestBinding = {
|
|
154
141
|
method: "GET",
|
|
155
142
|
path: "/v1/workflows/:id/pending-async-activities",
|
|
156
143
|
pathParamNames: ["id"],
|
|
@@ -168,9 +155,7 @@ export const listPendingAsyncActivitiesRestBinding = {
|
|
|
168
155
|
...cursor === null ? {} : { cursor }
|
|
169
156
|
};
|
|
170
157
|
},
|
|
171
|
-
success: { kind: "json", status: 200 }
|
|
172
|
-
shapeSuccess: (output) => shapePendingAsyncActivitiesSuccess(output),
|
|
173
|
-
shapeFault: shapeRestFault
|
|
158
|
+
success: { kind: "json", status: 200 }
|
|
174
159
|
};
|
|
175
160
|
async function readJsonObjectBody(request, context) {
|
|
176
161
|
const body = await readRestJsonBody(request, context).catch((error) => {
|
|
@@ -198,9 +183,7 @@ export const completeAsyncActivityRestBinding = {
|
|
|
198
183
|
..."result" in body ? { result: body.result } : {}
|
|
199
184
|
};
|
|
200
185
|
},
|
|
201
|
-
success: { kind: "json", status: 200 }
|
|
202
|
-
shapeSuccess: (output) => shapeAsyncActivitySuccess(output),
|
|
203
|
-
shapeFault: shapeRestFault
|
|
186
|
+
success: { kind: "json", status: 200 }
|
|
204
187
|
}, failAsyncActivityRestBinding = {
|
|
205
188
|
method: "POST",
|
|
206
189
|
path: "/v1/activities/fail",
|
|
@@ -217,7 +200,5 @@ export const completeAsyncActivityRestBinding = {
|
|
|
217
200
|
error: body.error
|
|
218
201
|
};
|
|
219
202
|
},
|
|
220
|
-
success: { kind: "json", status: 200 }
|
|
221
|
-
shapeSuccess: (output) => shapeAsyncActivitySuccess(output),
|
|
222
|
-
shapeFault: shapeRestFault
|
|
203
|
+
success: { kind: "json", status: 200 }
|
|
223
204
|
};
|
|
@@ -12,11 +12,8 @@ import {
|
|
|
12
12
|
parseBulkOperationControlFromBody,
|
|
13
13
|
readOptionalJsonBody
|
|
14
14
|
} from "./bulk-filter-helpers.js";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
validatedListFilterFromBulkInput
|
|
18
|
-
} from "./bulk-operation-helpers.js";
|
|
19
|
-
import { invalidParamsFault, shapeRestFault } from "./operation-helpers.js";
|
|
15
|
+
import { validatedListFilterFromBulkInput } from "./bulk-operation-helpers.js";
|
|
16
|
+
import { invalidParamsFault } from "./operation-helpers.js";
|
|
20
17
|
const bulkCancelWorkflowsInput = bulkListFilterInputSchema.merge(bulkOperationControlInputSchema), bulkCancelWorkflowsOutput = z.unknown();
|
|
21
18
|
export const bulkCancelWorkflowsOperation = defineOperation({
|
|
22
19
|
name: "weft.workflows.bulk.cancel",
|
|
@@ -58,7 +55,5 @@ export const bulkCancelWorkflowsOperation = defineOperation({
|
|
|
58
55
|
throw invalidParamsFault(faultMessage(error));
|
|
59
56
|
}
|
|
60
57
|
},
|
|
61
|
-
success: { kind: "json", status: 200 }
|
|
62
|
-
shapeSuccess: (output) => shapeBulkJsonSuccess(output),
|
|
63
|
-
shapeFault: shapeRestFault
|
|
58
|
+
success: { kind: "json", status: 200 }
|
|
64
59
|
};
|
|
@@ -16,11 +16,8 @@ import {
|
|
|
16
16
|
readOptionalJsonBody,
|
|
17
17
|
unprocessableFault
|
|
18
18
|
} from "./bulk-filter-helpers.js";
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
validatedListFilterFromBulkInput
|
|
22
|
-
} from "./bulk-operation-helpers.js";
|
|
23
|
-
import { invalidParamsFault, shapeRestFault } from "./operation-helpers.js";
|
|
19
|
+
import { validatedListFilterFromBulkInput } from "./bulk-operation-helpers.js";
|
|
20
|
+
import { invalidParamsFault } from "./operation-helpers.js";
|
|
24
21
|
const bulkDeleteWorkflowsInput = bulkListFilterInputSchema.merge(bulkOperationControlInputSchema), bulkDeleteWorkflowsOutput = z.unknown();
|
|
25
22
|
export const bulkDeleteWorkflowsOperation = defineOperation({
|
|
26
23
|
name: "weft.workflows.bulk.delete",
|
|
@@ -65,7 +62,5 @@ export const bulkDeleteWorkflowsOperation = defineOperation({
|
|
|
65
62
|
throw invalidParamsFault(faultMessage(error));
|
|
66
63
|
}
|
|
67
64
|
},
|
|
68
|
-
success: { kind: "json", status: 200 }
|
|
69
|
-
shapeSuccess: (output) => shapeBulkJsonSuccess(output),
|
|
70
|
-
shapeFault: shapeRestFault
|
|
65
|
+
success: { kind: "json", status: 200 }
|
|
71
66
|
};
|
|
@@ -13,11 +13,8 @@ import {
|
|
|
13
13
|
parseBulkOperationControlFromBody,
|
|
14
14
|
readOptionalJsonBody
|
|
15
15
|
} from "./bulk-filter-helpers.js";
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
validatedListFilterFromBulkInput
|
|
19
|
-
} from "./bulk-operation-helpers.js";
|
|
20
|
-
import { invalidParamsFault, shapeRestFault } from "./operation-helpers.js";
|
|
16
|
+
import { validatedListFilterFromBulkInput } from "./bulk-operation-helpers.js";
|
|
17
|
+
import { invalidParamsFault } from "./operation-helpers.js";
|
|
21
18
|
const bulkMutateWorkflowTagsInput = z.object({
|
|
22
19
|
filter: bulkListFilterInputSchema.optional(),
|
|
23
20
|
tags: z.array(z.string()),
|
|
@@ -94,7 +91,5 @@ export const bulkMutateWorkflowTagsRestBinding = {
|
|
|
94
91
|
...parseBulkOperationControlFromBody(body)
|
|
95
92
|
};
|
|
96
93
|
},
|
|
97
|
-
success: { kind: "json", status: 200 }
|
|
98
|
-
shapeSuccess: (output) => shapeBulkJsonSuccess(output),
|
|
99
|
-
shapeFault: shapeRestFault
|
|
94
|
+
success: { kind: "json", status: 200 }
|
|
100
95
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ListFilter } from '../../core/types.ts';
|
|
2
2
|
import { type BulkListFilterInput } from './bulk-filter-helpers.ts';
|
|
3
3
|
/**
|
|
4
4
|
* Coerces filter tags (label `Field "filter.tags"`), builds a `ListFilter`
|
|
@@ -13,15 +13,7 @@ import { type BulkListFilterInput } from './bulk-filter-helpers.ts';
|
|
|
13
13
|
* runs.
|
|
14
14
|
*
|
|
15
15
|
* Not used by `purge-workflows.ts`: purge allows empty/unscoped filters and
|
|
16
|
-
*
|
|
16
|
+
* uses the canonical REST fault fallback (sanitized) rather than passing
|
|
17
17
|
* raw engine messages through unmasked.
|
|
18
18
|
*/
|
|
19
19
|
export declare function validatedListFilterFromBulkInput(input: BulkListFilterInput): ListFilter;
|
|
20
|
-
export type BulkOperationSuccessResult = BulkCancelResult | BulkDeleteResult | BulkRetryFailedResult | BulkSignalResult | BulkTagResult | BulkOperationDryRunResult | PurgeResult;
|
|
21
|
-
/**
|
|
22
|
-
* Standard JSON 200 response shape for bulk-workflow operations. Used by
|
|
23
|
-
* every bulk operation's REST `shapeSuccess`; the result types are unioned
|
|
24
|
-
* rather than left as `unknown` so the type system catches accidental
|
|
25
|
-
* `undefined` / `Response` / `Error` arguments at the call site.
|
|
26
|
-
*/
|
|
27
|
-
export declare function shapeBulkJsonSuccess(result: BulkOperationSuccessResult): Response;
|
|
@@ -21,9 +21,3 @@ export function validatedListFilterFromBulkInput(input) {
|
|
|
21
21
|
}
|
|
22
22
|
return filter;
|
|
23
23
|
}
|
|
24
|
-
export function shapeBulkJsonSuccess(result) {
|
|
25
|
-
return new Response(JSON.stringify(result), {
|
|
26
|
-
status: 200,
|
|
27
|
-
headers: { "Content-Type": "application/json" }
|
|
28
|
-
});
|
|
29
|
-
}
|
|
@@ -12,11 +12,8 @@ import {
|
|
|
12
12
|
parseBulkOperationControlFromBody,
|
|
13
13
|
readOptionalJsonBody
|
|
14
14
|
} from "./bulk-filter-helpers.js";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
validatedListFilterFromBulkInput
|
|
18
|
-
} from "./bulk-operation-helpers.js";
|
|
19
|
-
import { invalidParamsFault, shapeRestFault } from "./operation-helpers.js";
|
|
15
|
+
import { validatedListFilterFromBulkInput } from "./bulk-operation-helpers.js";
|
|
16
|
+
import { invalidParamsFault } from "./operation-helpers.js";
|
|
20
17
|
const bulkRetryFailedWorkflowsInput = bulkListFilterInputSchema.merge(bulkOperationControlInputSchema), bulkRetryFailedWorkflowsOutput = z.unknown();
|
|
21
18
|
export const bulkRetryFailedWorkflowsOperation = defineOperation({
|
|
22
19
|
name: "weft.workflows.bulk.retryfailed",
|
|
@@ -58,7 +55,5 @@ export const bulkRetryFailedWorkflowsOperation = defineOperation({
|
|
|
58
55
|
throw invalidParamsFault(faultMessage(error));
|
|
59
56
|
}
|
|
60
57
|
},
|
|
61
|
-
success: { kind: "json", status: 200 }
|
|
62
|
-
shapeSuccess: (output) => shapeBulkJsonSuccess(output),
|
|
63
|
-
shapeFault: shapeRestFault
|
|
58
|
+
success: { kind: "json", status: 200 }
|
|
64
59
|
};
|
|
@@ -12,11 +12,8 @@ import {
|
|
|
12
12
|
parseBulkOperationControlFromBody,
|
|
13
13
|
readOptionalJsonBody
|
|
14
14
|
} from "./bulk-filter-helpers.js";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
validatedListFilterFromBulkInput
|
|
18
|
-
} from "./bulk-operation-helpers.js";
|
|
19
|
-
import { invalidParamsFault, shapeRestFault } from "./operation-helpers.js";
|
|
15
|
+
import { validatedListFilterFromBulkInput } from "./bulk-operation-helpers.js";
|
|
16
|
+
import { invalidParamsFault } from "./operation-helpers.js";
|
|
20
17
|
const bulkSignalWorkflowsInput = bulkListFilterInputSchema.extend({
|
|
21
18
|
name: z.string().min(1),
|
|
22
19
|
payload: z.unknown().optional()
|
|
@@ -74,7 +71,5 @@ export const bulkSignalWorkflowsOperation = defineOperation({
|
|
|
74
71
|
...parseBulkOperationControlFromBody(body)
|
|
75
72
|
};
|
|
76
73
|
},
|
|
77
|
-
success: { kind: "json", status: 200 }
|
|
78
|
-
shapeSuccess: (output) => shapeBulkJsonSuccess(output),
|
|
79
|
-
shapeFault: shapeRestFault
|
|
74
|
+
success: { kind: "json", status: 200 }
|
|
80
75
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineOperation } from "../operation-registry.js";
|
|
3
|
-
import { shapeRestFault } from "./operation-helpers.js";
|
|
4
3
|
import { mapScheduleErrorToFault } from "./schedule-faults.js";
|
|
5
4
|
const cancelScheduleInput = z.object({
|
|
6
5
|
scheduleId: z.string().min(1)
|
|
@@ -38,6 +37,5 @@ export const cancelScheduleOperation = defineOperation({
|
|
|
38
37
|
extractInput: async (_request, pathParams) => ({
|
|
39
38
|
scheduleId: pathParams.id ?? ""
|
|
40
39
|
}),
|
|
41
|
-
success: { kind: "empty", status: 204 }
|
|
42
|
-
shapeFault: shapeRestFault
|
|
40
|
+
success: { kind: "empty", status: 204 }
|
|
43
41
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { shapeRestFault } from "./operation-helpers.js";
|
|
3
2
|
import {
|
|
4
3
|
createSingleWorkflowControlOperation,
|
|
5
4
|
extractWorkflowIdFromPath
|
|
@@ -29,6 +28,5 @@ export const cancelWorkflowOperation = createSingleWorkflowControlOperation({
|
|
|
29
28
|
workflowId: { kind: "path", pathParam: "id" }
|
|
30
29
|
},
|
|
31
30
|
extractInput: async (_request, pathParams) => extractWorkflowIdFromPath(pathParams),
|
|
32
|
-
success: { kind: "empty", status: 204 }
|
|
33
|
-
shapeFault: shapeRestFault
|
|
31
|
+
success: { kind: "empty", status: 204 }
|
|
34
32
|
};
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineOperation } from "../operation-registry.js";
|
|
3
|
-
import { invalidParamsFault
|
|
4
|
-
import {
|
|
3
|
+
import { invalidParamsFault } from "./operation-helpers.js";
|
|
4
|
+
import {
|
|
5
|
+
mapScheduleErrorToFault,
|
|
6
|
+
validateScheduleInputCadence,
|
|
7
|
+
validateScheduleMutableOptions
|
|
8
|
+
} from "./schedule-faults.js";
|
|
5
9
|
import {
|
|
6
10
|
extractSharedScheduleRestFields,
|
|
7
11
|
parseScheduleRestBodyRequestRecord
|
|
8
12
|
} from "./schedule-rest-body.js";
|
|
9
|
-
const
|
|
10
|
-
"skip",
|
|
11
|
-
"queue",
|
|
12
|
-
"cancel-running",
|
|
13
|
-
"allow"
|
|
14
|
-
]), createScheduleInput = z.object({
|
|
13
|
+
const createScheduleInput = z.object({
|
|
15
14
|
type: z.unknown().describe("Workflow type name. Runtime validation requires a non-empty string."),
|
|
16
15
|
cronExpression: z.unknown().optional().describe("Cron expression. Supply exactly one of cronExpression or every; runtime validation requires a non-empty string."),
|
|
17
16
|
every: z.unknown().optional().describe("Interval period (duration string or milliseconds). Supply exactly one of cronExpression or every."),
|
|
@@ -29,43 +28,21 @@ function validateRequiredScheduleFields(input) {
|
|
|
29
28
|
throw invalidParamsFault("Missing required field: type");
|
|
30
29
|
return { type: input.type, spec: validateScheduleInputCadence(input) };
|
|
31
30
|
}
|
|
31
|
+
function validateScheduleId(value) {
|
|
32
|
+
if (value === void 0)
|
|
33
|
+
return;
|
|
34
|
+
if (typeof value !== "string" || value.length === 0)
|
|
35
|
+
throw invalidParamsFault('Field "id" must be a non-empty string');
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
32
38
|
function validateOptionalScheduleFields(input) {
|
|
33
|
-
|
|
34
|
-
if (input.id !== void 0) {
|
|
35
|
-
if (typeof input.id !== "string" || input.id.length === 0)
|
|
36
|
-
throw invalidParamsFault('Field "id" must be a non-empty string');
|
|
37
|
-
validatedId = input.id;
|
|
38
|
-
}
|
|
39
|
-
let validatedDescription;
|
|
40
|
-
if (input.description !== void 0) {
|
|
41
|
-
if (typeof input.description !== "string")
|
|
42
|
-
throw invalidParamsFault('Field "description" must be a string');
|
|
43
|
-
validatedDescription = input.description;
|
|
44
|
-
}
|
|
45
|
-
let validatedOverlap;
|
|
46
|
-
if (input.overlap !== void 0) {
|
|
47
|
-
if (typeof input.overlap !== "string" || !isScheduleOverlapPolicy(input.overlap))
|
|
48
|
-
throw invalidParamsFault('Field "overlap" must be one of skip, queue, cancel-running, allow');
|
|
49
|
-
validatedOverlap = input.overlap;
|
|
50
|
-
}
|
|
51
|
-
let validatedBackfill;
|
|
52
|
-
if (input.backfill !== void 0) {
|
|
53
|
-
if (typeof input.backfill !== "boolean")
|
|
54
|
-
throw invalidParamsFault('Field "backfill" must be a boolean');
|
|
55
|
-
validatedBackfill = input.backfill;
|
|
56
|
-
}
|
|
57
|
-
let validatedJitter;
|
|
58
|
-
if (input.jitter !== void 0) {
|
|
59
|
-
if (typeof input.jitter !== "string" && typeof input.jitter !== "number")
|
|
60
|
-
throw invalidParamsFault('Field "jitter" must be a duration string or a number of milliseconds');
|
|
61
|
-
validatedJitter = input.jitter;
|
|
62
|
-
}
|
|
39
|
+
const validatedId = validateScheduleId(input.id), validatedOptions = validateScheduleMutableOptions(input);
|
|
63
40
|
return {
|
|
64
41
|
id: validatedId,
|
|
65
|
-
description:
|
|
66
|
-
overlap:
|
|
67
|
-
backfill:
|
|
68
|
-
jitter:
|
|
42
|
+
description: validatedOptions.description,
|
|
43
|
+
overlap: validatedOptions.overlap,
|
|
44
|
+
backfill: validatedOptions.backfill,
|
|
45
|
+
jitter: validatedOptions.jitter
|
|
69
46
|
};
|
|
70
47
|
}
|
|
71
48
|
function validateCreateScheduleInput(input) {
|
|
@@ -99,11 +76,7 @@ export const createScheduleOperation = defineOperation({
|
|
|
99
76
|
throw mapScheduleErrorToFault(validated.id ?? "", error);
|
|
100
77
|
}
|
|
101
78
|
}
|
|
102
|
-
})
|
|
103
|
-
function isScheduleOverlapPolicy(value) {
|
|
104
|
-
return VALID_SCHEDULE_OVERLAP_POLICIES.has(value);
|
|
105
|
-
}
|
|
106
|
-
export const createScheduleRestBinding = {
|
|
79
|
+
}), createScheduleRestBinding = {
|
|
107
80
|
method: "POST",
|
|
108
81
|
path: "/v1/schedules",
|
|
109
82
|
pathParamNames: [],
|
|
@@ -128,6 +101,5 @@ export const createScheduleRestBinding = {
|
|
|
128
101
|
...extractSharedScheduleRestFields(record)
|
|
129
102
|
};
|
|
130
103
|
},
|
|
131
|
-
success: { kind: "json", status: 201 }
|
|
132
|
-
shapeFault: shapeRestFault
|
|
104
|
+
success: { kind: "json", status: 201 }
|
|
133
105
|
};
|