@lostgradient/weft 0.11.0 → 0.13.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/cli/api.d.ts +2 -0
- package/dist/cli/api.js +3 -4
- package/dist/cli/generated/operation-catalog.snapshot.json +5167 -0
- package/dist/cli/generated/operation-client.generated.d.ts +119 -10
- package/dist/cli/generated/operation-client.generated.js +74 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/operation-catalog-snapshot.d.ts +11 -2
- package/dist/cli/operation-catalog-snapshot.js +14 -5
- package/dist/cli/operation-client-runtime.d.ts +29 -0
- package/dist/cli-main.js +227 -401
- package/dist/client/client-storage.d.ts +24 -0
- package/dist/client/client-storage.js +14 -0
- package/dist/client/handle-delegation.d.ts +3 -3
- package/dist/client/handle-delegation.js +2 -2
- package/dist/client/http-client-requests.d.ts +5 -3
- package/dist/client/http-client-requests.js +20 -2
- package/dist/client/http-client-storage.d.ts +3 -0
- package/dist/client/http-client-storage.js +110 -0
- package/dist/client/http-client.d.ts +9 -6
- package/dist/client/http-client.js +13 -18
- package/dist/client/http-operations.d.ts +3 -1
- package/dist/client/http-operations.js +84 -2
- package/dist/client/http-request.d.ts +35 -6
- package/dist/client/http-request.js +31 -10
- package/dist/client/in-process-operations.d.ts +2 -2
- package/dist/client/in-process-operations.js +2 -2
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +18 -0
- package/dist/client/interface.d.ts +26 -26
- package/dist/client/local.d.ts +9 -6
- package/dist/client/local.js +9 -4
- package/dist/client/search-params.js +10 -6
- package/dist/client/start-body.d.ts +3 -1
- package/dist/client/start-body.js +9 -0
- package/dist/connection.d.ts +8 -0
- package/dist/connection.js +41 -17
- package/dist/core/bulk-workflow-filter.d.ts +2 -1
- package/dist/core/bulk-workflow-filter.js +5 -1
- package/dist/core/engine/async-activity-records.d.ts +12 -1
- package/dist/core/engine/async-activity-records.js +81 -2
- package/dist/core/engine/bulk-operations-purge.js +16 -1
- package/dist/core/engine/bulk-operations-shared.js +2 -0
- package/dist/core/engine/callback-creators-core.js +2 -1
- package/dist/core/engine/callback-creators-schedule.d.ts +2 -1
- package/dist/core/engine/callback-creators-schedule.js +3 -3
- package/dist/core/engine/checkpoint-reads.js +11 -1
- package/dist/core/engine/child-workflow.js +15 -6
- package/dist/core/engine/construction.js +3 -0
- package/dist/core/engine/disposal.js +2 -0
- package/dist/core/engine/engine-internal-types.d.ts +4 -1
- package/dist/core/engine/fenced-write.d.ts +5 -3
- package/dist/core/engine/finalizer-status.d.ts +10 -0
- package/dist/core/engine/finalizer-status.js +82 -0
- package/dist/core/engine/index.d.ts +69 -2
- package/dist/core/engine/index.js +71 -8
- package/dist/core/engine/internals.d.ts +3 -0
- package/dist/core/engine/lease-health.d.ts +64 -0
- package/dist/core/engine/lease-health.js +0 -0
- package/dist/core/engine/lease-manager.d.ts +4 -2
- package/dist/core/engine/lease-manager.js +32 -4
- package/dist/core/engine/lifecycle/recovered-services.js +0 -2
- package/dist/core/engine/lifecycle/shared.d.ts +28 -0
- package/dist/core/engine/lifecycle/start-batch.js +12 -0
- package/dist/core/engine/lifecycle/start.d.ts +1 -1
- package/dist/core/engine/lifecycle/start.js +34 -5
- package/dist/core/engine/lifecycle/transition.js +19 -9
- package/dist/core/engine/operations-coordination.d.ts +1 -12
- package/dist/core/engine/operations-coordination.js +57 -10
- package/dist/core/engine/operations-speculate.d.ts +1 -1
- package/dist/core/engine/operations-speculate.js +19 -5
- package/dist/core/engine/registration.js +14 -0
- package/dist/core/engine/schedule-handle.d.ts +4 -4
- package/dist/core/engine/schedule-handle.js +2 -2
- package/dist/core/engine/schedule-overlap.d.ts +11 -0
- package/dist/core/engine/schedule-overlap.js +50 -0
- package/dist/core/engine/schedule-run.d.ts +11 -3
- package/dist/core/engine/schedule-run.js +27 -4
- package/dist/core/engine/schedule-timer.js +10 -1
- package/dist/core/engine/schedules.d.ts +5 -4
- package/dist/core/engine/schedules.js +62 -56
- package/dist/core/engine/state-utilities.js +1 -1
- package/dist/core/engine/storage-io.d.ts +12 -0
- package/dist/core/engine/storage-io.js +49 -10
- package/dist/core/engine/termination/finalizer-claim.d.ts +8 -6
- package/dist/core/engine/termination/finalizer-claim.js +2 -1
- package/dist/core/engine/termination/finalizer.js +10 -14
- package/dist/core/engine/timeline-coordinator-constants.d.ts +3 -0
- package/dist/core/engine/timeline-coordinator-constants.js +1 -0
- package/dist/core/engine/timeline-coordinator-detail.d.ts +13 -0
- package/dist/core/engine/timeline-coordinator-detail.js +76 -0
- package/dist/core/engine/validation/schedule-options.d.ts +8 -1
- package/dist/core/engine/validation/schedule-options.js +18 -0
- package/dist/core/engine/validation/schedule.d.ts +1 -1
- package/dist/core/engine/validation/schedule.js +27 -3
- package/dist/core/engine/validation.js +66 -2
- package/dist/core/engine/workflow-state-stream.d.ts +5 -1
- package/dist/core/engine/workflow-state-stream.js +37 -14
- package/dist/core/events/schedule-events.d.ts +3 -4
- package/dist/core/events/workflow-events.d.ts +2 -1
- package/dist/core/list-filter-validation.d.ts +3 -0
- package/dist/core/list-filter-validation.js +11 -0
- package/dist/core/registry-snapshot.d.ts +32 -0
- package/dist/core/registry-snapshot.js +28 -0
- package/dist/core/review/index.d.ts +4 -4
- package/dist/core/types/activity.d.ts +52 -5
- package/dist/core/types/bulk.d.ts +1 -0
- package/dist/core/types/definition-schema-to-json.d.ts +11 -0
- package/dist/core/types/definition-schema-to-json.js +11 -2
- package/dist/core/types/list-options.d.ts +6 -0
- package/dist/core/types/options.d.ts +6 -5
- package/dist/core/types/reviews.d.ts +2 -2
- package/dist/core/types/schedules.d.ts +45 -2
- package/dist/core/types/services-resolution.d.ts +5 -5
- package/dist/core/types/state.d.ts +64 -0
- package/dist/core/types/workflow-log.d.ts +3 -2
- package/dist/core/types/workflow-observability.d.ts +50 -0
- package/dist/core/types/workflow-observability.js +0 -0
- package/dist/core/types/workflow-registry.d.ts +7 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.js +1 -0
- package/dist/http.js +2 -0
- package/dist/index.d.ts +4 -3
- package/dist/indexeddb.js +1 -0
- package/dist/json-schema.js +3 -3
- package/dist/mcp/cli.js +63 -61
- package/dist/mcp/http.d.ts +7 -2
- package/dist/mcp/session.d.ts +3 -3
- package/dist/mcp/session.js +3 -2
- package/dist/mcp/stdio.d.ts +7 -2
- package/dist/observability/index.js +2 -2
- package/dist/runtime/portable.d.ts +33 -0
- package/dist/runtime/portable.js +17 -6
- package/dist/server/access-policy-metadata.d.ts +92 -0
- package/dist/server/access-policy-metadata.js +78 -0
- package/dist/server/engine-event-feed-backend.d.ts +22 -3
- package/dist/server/fault-to-http.d.ts +3 -7
- package/dist/server/fault-to-http.js +2 -34
- package/dist/server/fleet-event-feed.d.ts +65 -0
- package/dist/server/handler/index.d.ts +11 -2
- package/dist/server/handler/index.js +8 -1
- package/dist/server/handler/route-dispatch.d.ts +10 -3
- package/dist/server/handler/route-dispatch.js +19 -4
- package/dist/server/handler.js +1 -56
- package/dist/server/index.d.ts +13 -2
- package/dist/server/index.js +88 -64
- package/dist/server/interactive-operations.js +2 -0
- package/dist/server/openapi-error-responses.js +55 -4
- package/dist/server/openapi.d.ts +3 -1
- package/dist/server/openapi.js +4 -0
- package/dist/server/openrpc-document-schema.d.ts +64 -0
- package/dist/server/openrpc-document-schema.js +6 -26
- package/dist/server/openrpc.d.ts +4 -0
- package/dist/server/openrpc.js +9 -33
- package/dist/server/operation-fault.d.ts +24 -7
- package/dist/server/operation-fault.js +65 -13
- package/dist/server/operations/aggregate-workflows.d.ts +6 -0
- package/dist/server/operations/aggregate-workflows.js +3 -2
- package/dist/server/operations/async-activity.d.ts +14 -0
- package/dist/server/operations/async-activity.js +88 -4
- package/dist/server/operations/bulk-filter-helpers.d.ts +3 -0
- package/dist/server/operations/bulk-filter-helpers.js +27 -3
- package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +6 -0
- package/dist/server/operations/bulk-signal-workflows.d.ts +6 -0
- package/dist/server/operations/get-stream-chunks.js +2 -7
- package/dist/server/operations/get-system-lease.d.ts +19 -0
- package/dist/server/operations/get-system-lease.js +48 -0
- package/dist/server/operations/get-workflow-observability.d.ts +24 -0
- package/dist/server/operations/get-workflow-observability.js +80 -0
- package/dist/server/operations/get-workflow-result.js +2 -2
- package/dist/server/operations/get-workflow.d.ts +2 -2
- package/dist/server/operations/list-filter-query-extractor.js +15 -0
- package/dist/server/operations/list-workflows.d.ts +6 -0
- package/dist/server/operations/list-workflows.js +12 -3
- package/dist/server/operations/operation-helpers.d.ts +9 -18
- package/dist/server/operations/operation-helpers.js +5 -23
- package/dist/server/operations/purge-workflows.d.ts +3 -0
- package/dist/server/operations/recover-all.js +2 -1
- package/dist/server/operations/single-workflow-tag-mutation.js +2 -2
- package/dist/server/operations/sse-stream.js +2 -7
- package/dist/server/operations/storage-capabilities.d.ts +34 -0
- package/dist/server/operations/storage-capabilities.js +38 -0
- package/dist/server/operations/storage.js +8 -17
- package/dist/server/operations/stream-workflow-sse.js +3 -9
- package/dist/server/operations/submit-review-decision.d.ts +2 -0
- package/dist/server/operations/submit-review-decision.js +19 -2
- package/dist/server/operations/update-schedule.d.ts +8 -0
- package/dist/server/operations/update-schedule.js +70 -7
- package/dist/server/operations/workflow-events-sse.js +2 -2
- package/dist/server/replay-live-feed-internals.d.ts +19 -0
- package/dist/server/replay-live-feed-internals.js +76 -0
- package/dist/server/rest-binding.d.ts +7 -6
- package/dist/server/rest-bindings.d.ts +2 -13
- package/dist/server/rest-bindings.js +19 -10
- package/dist/server/runtime/authentication-bridge.d.ts +2 -2
- package/dist/server/serve-internals.js +3 -3
- package/dist/server/task-queue.d.ts +7 -5
- package/dist/server/workflow-event-feed.d.ts +100 -11
- package/dist/server/workflow-event-feed.js +1 -140
- package/dist/service-worker/index.d.ts +8 -2
- package/dist/service-worker/index.js +37 -56
- package/dist/service-worker/setup.d.ts +6 -2
- package/dist/storage/auto.js +1 -1
- package/dist/storage/bun-sql.js +3 -3
- package/dist/storage/capabilities.d.ts +1 -1
- package/dist/storage/cloudflare-durable-object-sql.d.ts +75 -0
- package/dist/storage/cloudflare-durable-object-sql.js +0 -0
- package/dist/storage/cloudflare-value-codec.d.ts +67 -0
- package/dist/storage/cloudflare-value-codec.js +46 -0
- package/dist/storage/cloudflare.d.ts +140 -0
- package/dist/storage/cloudflare.js +127 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/http.js +200 -2
- package/dist/storage/index.d.ts +8 -1
- package/dist/storage/indexeddb.js +311 -1
- package/dist/storage/interface.d.ts +16 -4
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +4 -0
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +4 -4
- package/dist/storage/node-sqlite.js +3 -3
- package/dist/storage/postgres-key-value-queries.d.ts +6 -0
- package/dist/storage/postgres-key-value-queries.js +2 -3
- package/dist/storage/postgres.js +4 -4
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/sql-identifier.d.ts +35 -0
- package/dist/storage/sql-identifier.js +5 -0
- package/dist/storage/sqlite-key-value-queries.d.ts +11 -6
- package/dist/storage/sqlite-key-value-queries.js +3 -3
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/storage/typed-storage.js +138 -2
- package/dist/storage/web-extension.js +298 -1
- package/dist/testing/index.js +21 -60
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -0
- package/dist/worker/protocol.js +1 -1
- package/package.json +8 -3
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
shapeRestFaultAsJson
|
|
3
|
+
} from "../operation-fault.js";
|
|
3
4
|
export function isOperationFault(value) {
|
|
4
5
|
return typeof value === "object" && value !== null && "code" in value && "message" in value && "data" in value;
|
|
5
6
|
}
|
|
6
|
-
export function jsonErrorResponse(message, status) {
|
|
7
|
-
return new Response(JSON.stringify({ error: message }), {
|
|
8
|
-
status,
|
|
9
|
-
headers: { "Content-Type": "application/json" }
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
7
|
export function invalidParamsFault(message, weftCode) {
|
|
13
8
|
return {
|
|
14
9
|
code: "InvalidParams",
|
|
@@ -16,19 +11,6 @@ export function invalidParamsFault(message, weftCode) {
|
|
|
16
11
|
data: weftCode === void 0 ? { issues: [] } : { issues: [], weftCode }
|
|
17
12
|
};
|
|
18
13
|
}
|
|
19
|
-
export function shapeRestFault(fault) {
|
|
20
|
-
|
|
21
|
-
return jsonErrorResponse("Internal server error", 500);
|
|
22
|
-
const status = FAULT_CODE_TO_HTTP_STATUS[fault.code], weftCode = weftCodeFromFaultData(fault.data);
|
|
23
|
-
if (weftCode === void 0)
|
|
24
|
-
return jsonErrorResponse(fault.message, status);
|
|
25
|
-
return new Response(JSON.stringify({ error: fault.message, weftCode }), {
|
|
26
|
-
status,
|
|
27
|
-
headers: { "Content-Type": "application/json" }
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
function weftCodeFromFaultData(data) {
|
|
31
|
-
if (typeof data !== "object" || data === null || !("weftCode" in data))
|
|
32
|
-
return;
|
|
33
|
-
return isWeftErrorCode(data.weftCode) ? data.weftCode : void 0;
|
|
14
|
+
export function shapeRestFault(fault, options) {
|
|
15
|
+
return shapeRestFaultAsJson(fault, options);
|
|
34
16
|
}
|
|
@@ -6,6 +6,9 @@ export type PurgeWorkflowsOutput = PurgeResult;
|
|
|
6
6
|
export declare const purgeWorkflowsOperation: import("../operation-catalog.ts").OperationDefinition<{
|
|
7
7
|
status?: import("../../index.ts").WorkflowStatus | import("../../index.ts").WorkflowStatus[] | undefined;
|
|
8
8
|
type?: string | undefined;
|
|
9
|
+
scheduleId?: string | undefined;
|
|
10
|
+
parentWorkflowId?: string | undefined;
|
|
11
|
+
parentWorkflowExecutionToken?: string | undefined;
|
|
9
12
|
tags?: string[] | undefined;
|
|
10
13
|
attributes?: {
|
|
11
14
|
key: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { WorkflowTypeNotRegisteredForRecoveryError } from "../../core/engine.js";
|
|
3
|
+
import { shapeRestFaultBody } from "../operation-fault.js";
|
|
3
4
|
import { defineOperation } from "../operation-registry.js";
|
|
4
5
|
import { shapeRestFault } from "./operation-helpers.js";
|
|
5
6
|
const recoverAllInput = z.object({}), recoverAllOutput = z.object({
|
|
@@ -54,7 +55,7 @@ function shapeRecoverAllFault(fault) {
|
|
|
54
55
|
if (fault.code !== "Conflict" || fault.data.missingTypes === void 0)
|
|
55
56
|
return shapeRestFault(fault);
|
|
56
57
|
return new Response(JSON.stringify({
|
|
57
|
-
|
|
58
|
+
...shapeRestFaultBody(fault, "workflow_type_not_registered_for_recovery"),
|
|
58
59
|
missingTypes: fault.data.missingTypes,
|
|
59
60
|
missingWorkflowCount: fault.data.missingWorkflowCount,
|
|
60
61
|
samplesTruncated: fault.data.samplesTruncated
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "../../core/start-workflow-validation.js";
|
|
7
7
|
import { defineOperation } from "../operation-registry.js";
|
|
8
8
|
import { readRestJsonBody } from "../rest-body.js";
|
|
9
|
-
import { isOperationFault,
|
|
9
|
+
import { isOperationFault, shapeRestFault } from "./operation-helpers.js";
|
|
10
10
|
const singleWorkflowTagMutationInput = z.object({
|
|
11
11
|
workflowId: z.string().min(1),
|
|
12
12
|
tags: z.unknown().optional()
|
|
@@ -78,7 +78,7 @@ function shapeSingleWorkflowTagMutationSuccess(output) {
|
|
|
78
78
|
}
|
|
79
79
|
function shapeSingleWorkflowTagMutationFault(fault) {
|
|
80
80
|
if (fault.code === "Unprocessable")
|
|
81
|
-
return
|
|
81
|
+
return shapeRestFault(fault, { status: 400 });
|
|
82
82
|
return shapeRestFault(fault);
|
|
83
83
|
}
|
|
84
84
|
function mapTagMutationErrorToFault(error, workflowId) {
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { decodeCursor } from "../workflow-event-feed.js";
|
|
2
|
-
import {
|
|
3
|
-
invalidParamsFault,
|
|
4
|
-
isOperationFault,
|
|
5
|
-
jsonErrorResponse,
|
|
6
|
-
shapeRestFault
|
|
7
|
-
} from "./operation-helpers.js";
|
|
2
|
+
import { invalidParamsFault, isOperationFault, shapeRestFault } from "./operation-helpers.js";
|
|
8
3
|
const textEncoder = new TextEncoder, DEFAULT_SSE_HEARTBEAT_INTERVAL_MS = 15000;
|
|
9
4
|
export const SSE_ACCEPT_REQUIRED_MESSAGE = "Accept header must include text/event-stream";
|
|
10
5
|
export function acceptsServerSentEvents(acceptHeader) {
|
|
@@ -30,7 +25,7 @@ export function readServerSentEventsCursor(value) {
|
|
|
30
25
|
}
|
|
31
26
|
export function shapeServerSentEventsFault(fault) {
|
|
32
27
|
if (fault.code === "InvalidParams" && fault.message === SSE_ACCEPT_REQUIRED_MESSAGE)
|
|
33
|
-
return
|
|
28
|
+
return shapeRestFault(fault, { status: 406 });
|
|
34
29
|
return shapeRestFault(fault);
|
|
35
30
|
}
|
|
36
31
|
export function formatServerSentEvent(event) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { UnknownRestBinding } from '../rest-bindings.ts';
|
|
3
|
+
declare const storageCapabilitiesInput: z.ZodObject<{}, z.core.$strip>;
|
|
4
|
+
declare const storageCapabilitiesOutput: z.ZodObject<{
|
|
5
|
+
persistence: z.ZodEnum<{
|
|
6
|
+
ephemeral: "ephemeral";
|
|
7
|
+
local: "local";
|
|
8
|
+
remote: "remote";
|
|
9
|
+
}>;
|
|
10
|
+
readAfterWrite: z.ZodEnum<{
|
|
11
|
+
linearizable: "linearizable";
|
|
12
|
+
session: "session";
|
|
13
|
+
eventual: "eventual";
|
|
14
|
+
}>;
|
|
15
|
+
scanConsistency: z.ZodEnum<{
|
|
16
|
+
snapshot: "snapshot";
|
|
17
|
+
"best-effort": "best-effort";
|
|
18
|
+
}>;
|
|
19
|
+
atomicBatch: z.ZodBoolean;
|
|
20
|
+
conditionalBatch: z.ZodBoolean;
|
|
21
|
+
boundedRangeDelete: z.ZodBoolean;
|
|
22
|
+
}, z.core.$strict>;
|
|
23
|
+
export type StorageCapabilitiesInput = z.infer<typeof storageCapabilitiesInput>;
|
|
24
|
+
export type StorageCapabilitiesOutput = z.infer<typeof storageCapabilitiesOutput>;
|
|
25
|
+
export declare const storageCapabilitiesOperation: import("../operation-catalog.ts").OperationDefinition<Record<string, never>, {
|
|
26
|
+
persistence: "ephemeral" | "local" | "remote";
|
|
27
|
+
readAfterWrite: "linearizable" | "session" | "eventual";
|
|
28
|
+
scanConsistency: "snapshot" | "best-effort";
|
|
29
|
+
atomicBatch: boolean;
|
|
30
|
+
conditionalBatch: boolean;
|
|
31
|
+
boundedRangeDelete: boolean;
|
|
32
|
+
}, unknown>;
|
|
33
|
+
export declare const storageCapabilitiesRestBinding: UnknownRestBinding;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineOperation } from "../operation-registry.js";
|
|
3
|
+
import { shapeRestFault } from "./operation-helpers.js";
|
|
4
|
+
const storageCapabilitiesInput = z.object({}), storageCapabilitiesOutput = z.object({
|
|
5
|
+
persistence: z.enum(["ephemeral", "local", "remote"]),
|
|
6
|
+
readAfterWrite: z.enum(["linearizable", "session", "eventual"]),
|
|
7
|
+
scanConsistency: z.enum(["snapshot", "best-effort"]),
|
|
8
|
+
atomicBatch: z.boolean(),
|
|
9
|
+
conditionalBatch: z.boolean(),
|
|
10
|
+
boundedRangeDelete: z.boolean()
|
|
11
|
+
}).strict();
|
|
12
|
+
export const storageCapabilitiesOperation = defineOperation({
|
|
13
|
+
name: "weft.storage.capabilities",
|
|
14
|
+
mcpExposable: !1,
|
|
15
|
+
summary: "Report the connected storage backend's capability profile",
|
|
16
|
+
destructive: !1,
|
|
17
|
+
tags: ["Storage"],
|
|
18
|
+
inputSchema: storageCapabilitiesInput,
|
|
19
|
+
outputSchema: storageCapabilitiesOutput,
|
|
20
|
+
access: {
|
|
21
|
+
kind: "scoped",
|
|
22
|
+
scopes: { kind: "anyOf", scopes: ["storage:read", "storage:admin"] }
|
|
23
|
+
},
|
|
24
|
+
discoverable: !0,
|
|
25
|
+
transports: { http: !0, jsonRpcHttp: !0, jsonRpcWebSocket: !0, jsonRpcStdio: !0 },
|
|
26
|
+
unknownKeyPolicy: { http: "strip", jsonRpc: "reject" },
|
|
27
|
+
invoke: async ({ engine }) => engine.storage.capabilities()
|
|
28
|
+
}), storageCapabilitiesRestBinding = {
|
|
29
|
+
method: "GET",
|
|
30
|
+
path: "/v1/storage/-/capabilities",
|
|
31
|
+
pathParamNames: [],
|
|
32
|
+
operationName: "weft.storage.capabilities",
|
|
33
|
+
inputSources: {},
|
|
34
|
+
extractInput: async () => ({}),
|
|
35
|
+
success: { kind: "json", status: 200 },
|
|
36
|
+
shapeSuccess: (output) => Response.json(output),
|
|
37
|
+
shapeFault: shapeRestFault
|
|
38
|
+
};
|
|
@@ -12,18 +12,9 @@ import { defineOperation } from "../operation-registry.js";
|
|
|
12
12
|
import { isAuthenticated } from "../principal.js";
|
|
13
13
|
import { readRestBodyBounded, readRestJsonBody } from "../rest-body.js";
|
|
14
14
|
import { invalidParamsFault, isOperationFault, shapeRestFault } from "./operation-helpers.js";
|
|
15
|
-
const
|
|
15
|
+
const rawStorageAccess = {
|
|
16
16
|
kind: "scoped",
|
|
17
|
-
scopes: { kind: "anyOf", scopes: ["storage:
|
|
18
|
-
}, storageWriteAccess = {
|
|
19
|
-
kind: "scoped",
|
|
20
|
-
scopes: { kind: "anyOf", scopes: ["storage:write", "storage:admin"] }
|
|
21
|
-
}, storageConditionalBatchAccess = {
|
|
22
|
-
kind: "scopedAlternatives",
|
|
23
|
-
alternatives: [
|
|
24
|
-
{ kind: "anyOf", scopes: ["storage:admin"] },
|
|
25
|
-
{ kind: "allOf", scopes: ["storage:read", "storage:write"] }
|
|
26
|
-
]
|
|
17
|
+
scopes: { kind: "anyOf", scopes: ["storage:admin"] }
|
|
27
18
|
}, httpOnlyStorageTransports = {
|
|
28
19
|
http: !0,
|
|
29
20
|
jsonRpcHttp: !1,
|
|
@@ -187,7 +178,7 @@ export const storageGetOperation = defineOperation({
|
|
|
187
178
|
tags: ["Storage"],
|
|
188
179
|
inputSchema: storageGetInput,
|
|
189
180
|
outputSchema: storageGetOutput,
|
|
190
|
-
access:
|
|
181
|
+
access: rawStorageAccess,
|
|
191
182
|
discoverable: !0,
|
|
192
183
|
transports: httpOnlyStorageTransports,
|
|
193
184
|
unknownKeyPolicy: { http: "strip", jsonRpc: "reject" },
|
|
@@ -202,7 +193,7 @@ export const storageGetOperation = defineOperation({
|
|
|
202
193
|
tags: ["Storage"],
|
|
203
194
|
inputSchema: storagePutInput,
|
|
204
195
|
outputSchema: emptyOutput,
|
|
205
|
-
access:
|
|
196
|
+
access: rawStorageAccess,
|
|
206
197
|
discoverable: !0,
|
|
207
198
|
transports: httpOnlyStorageTransports,
|
|
208
199
|
unknownKeyPolicy: { http: "strip", jsonRpc: "reject" },
|
|
@@ -218,7 +209,7 @@ export const storageGetOperation = defineOperation({
|
|
|
218
209
|
tags: ["Storage"],
|
|
219
210
|
inputSchema: storageDeleteInput,
|
|
220
211
|
outputSchema: emptyOutput,
|
|
221
|
-
access:
|
|
212
|
+
access: rawStorageAccess,
|
|
222
213
|
discoverable: !0,
|
|
223
214
|
transports: httpOnlyStorageTransports,
|
|
224
215
|
unknownKeyPolicy: { http: "strip", jsonRpc: "reject" },
|
|
@@ -234,7 +225,7 @@ export const storageGetOperation = defineOperation({
|
|
|
234
225
|
tags: ["Storage"],
|
|
235
226
|
inputSchema: storageScanInput,
|
|
236
227
|
outputSchema: storageScanOutput,
|
|
237
|
-
access:
|
|
228
|
+
access: rawStorageAccess,
|
|
238
229
|
discoverable: !0,
|
|
239
230
|
transports: httpOnlyStorageTransports,
|
|
240
231
|
unknownKeyPolicy: { http: "strip", jsonRpc: "reject" },
|
|
@@ -250,7 +241,7 @@ export const storageGetOperation = defineOperation({
|
|
|
250
241
|
tags: ["Storage"],
|
|
251
242
|
inputSchema: storageBatchInput,
|
|
252
243
|
outputSchema: emptyOutput,
|
|
253
|
-
access:
|
|
244
|
+
access: rawStorageAccess,
|
|
254
245
|
discoverable: !0,
|
|
255
246
|
transports: httpOnlyStorageTransports,
|
|
256
247
|
unknownKeyPolicy: { http: "strip", jsonRpc: "reject" },
|
|
@@ -267,7 +258,7 @@ export const storageGetOperation = defineOperation({
|
|
|
267
258
|
tags: ["Storage"],
|
|
268
259
|
inputSchema: storageConditionalBatchInput,
|
|
269
260
|
outputSchema: storageConditionalBatchOutput,
|
|
270
|
-
access:
|
|
261
|
+
access: rawStorageAccess,
|
|
271
262
|
discoverable: !0,
|
|
272
263
|
transports: httpOnlyStorageTransports,
|
|
273
264
|
producibleFaults: ["NotImplemented"],
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { FAULT_CODE_TO_HTTP_STATUS } from "../operation-fault.js";
|
|
3
2
|
import { defineOperation } from "../operation-registry.js";
|
|
4
3
|
import { parseOptionalSequenceCursor } from "../sequence-cursor.js";
|
|
5
|
-
import { invalidParamsFault,
|
|
4
|
+
import { invalidParamsFault, shapeRestFault } from "./operation-helpers.js";
|
|
6
5
|
import { createStoredChunkSSEStream, SSE_RESPONSE_HEADERS } from "./sse-stream.js";
|
|
7
6
|
const TOKENS_STREAM_KEY = "tokens", streamWorkflowSseInput = z.object({
|
|
8
7
|
workflowId: z.string().min(1),
|
|
@@ -42,16 +41,11 @@ export const streamWorkflowSseOperation = defineOperation({
|
|
|
42
41
|
});
|
|
43
42
|
const ACCEPT_HEADER_MUST_INCLUDE_SSE = "Accept header must include text/event-stream";
|
|
44
43
|
function shapeStreamWorkflowSseFault(fault) {
|
|
45
|
-
if (fault.code === "NotFound")
|
|
46
|
-
return jsonErrorResponse(fault.message, 404);
|
|
47
44
|
if (fault.code === "InvalidParams") {
|
|
48
45
|
if (fault.message === ACCEPT_HEADER_MUST_INCLUDE_SSE)
|
|
49
|
-
return
|
|
50
|
-
return jsonErrorResponse(fault.message, 400);
|
|
46
|
+
return shapeRestFault(fault, { status: 406 });
|
|
51
47
|
}
|
|
52
|
-
|
|
53
|
-
return jsonErrorResponse("Internal server error", 500);
|
|
54
|
-
return jsonErrorResponse(fault.message, FAULT_CODE_TO_HTTP_STATUS[fault.code]);
|
|
48
|
+
return shapeRestFault(fault);
|
|
55
49
|
}
|
|
56
50
|
function mapTokenChunkToText(chunk) {
|
|
57
51
|
if (typeof chunk.value === "string")
|
|
@@ -5,6 +5,7 @@ declare const submitReviewDecisionInput: z.ZodObject<{
|
|
|
5
5
|
decision: z.ZodOptional<z.ZodUnknown>;
|
|
6
6
|
reviewer: z.ZodOptional<z.ZodUnknown>;
|
|
7
7
|
feedback: z.ZodOptional<z.ZodUnknown>;
|
|
8
|
+
sectionDecisions: z.ZodOptional<z.ZodUnknown>;
|
|
8
9
|
workflowId: z.ZodOptional<z.ZodUnknown>;
|
|
9
10
|
}, z.core.$strip>;
|
|
10
11
|
declare const submitReviewDecisionOutput: z.ZodObject<{
|
|
@@ -17,6 +18,7 @@ export declare const submitReviewDecisionOperation: import("../operation-catalog
|
|
|
17
18
|
decision?: unknown;
|
|
18
19
|
reviewer?: unknown;
|
|
19
20
|
feedback?: unknown;
|
|
21
|
+
sectionDecisions?: unknown;
|
|
20
22
|
workflowId?: unknown;
|
|
21
23
|
}, {
|
|
22
24
|
ok: true;
|
|
@@ -6,15 +6,28 @@ const VALID_DECISIONS = [
|
|
|
6
6
|
"approved",
|
|
7
7
|
"rejected",
|
|
8
8
|
"needs-changes"
|
|
9
|
-
], submitReviewDecisionInput = z.object({
|
|
9
|
+
], sectionDecisionsSchema = z.record(z.string(), z.enum(["approved", "rejected"])), submitReviewDecisionInput = z.object({
|
|
10
10
|
reviewId: z.string().min(1),
|
|
11
11
|
decision: z.unknown().optional(),
|
|
12
12
|
reviewer: z.unknown().optional(),
|
|
13
13
|
feedback: z.unknown().optional(),
|
|
14
|
+
sectionDecisions: z.unknown().optional(),
|
|
14
15
|
workflowId: z.unknown().optional()
|
|
15
16
|
}), submitReviewDecisionOutput = z.object({
|
|
16
17
|
ok: z.literal(!0)
|
|
17
18
|
});
|
|
19
|
+
function parseSectionDecisions(sectionDecisions) {
|
|
20
|
+
if (sectionDecisions === void 0)
|
|
21
|
+
return;
|
|
22
|
+
const parsed = sectionDecisionsSchema.safeParse(sectionDecisions);
|
|
23
|
+
if (!parsed.success)
|
|
24
|
+
throw {
|
|
25
|
+
code: "InvalidParams",
|
|
26
|
+
message: 'Field "sectionDecisions" must be a record mapping section names to "approved" or "rejected"',
|
|
27
|
+
data: { issues: [] }
|
|
28
|
+
};
|
|
29
|
+
return parsed.data;
|
|
30
|
+
}
|
|
18
31
|
function validateReviewDecisionInput(input) {
|
|
19
32
|
if (typeof input.decision !== "string" || typeof input.reviewer !== "string")
|
|
20
33
|
throw {
|
|
@@ -34,9 +47,11 @@ function validateReviewDecisionInput(input) {
|
|
|
34
47
|
message: 'Field "feedback" must be a string when provided',
|
|
35
48
|
data: { issues: [] }
|
|
36
49
|
};
|
|
37
|
-
const
|
|
50
|
+
const sectionDecisions = parseSectionDecisions(input.sectionDecisions), decision = input.decision, reviewer = input.reviewer, reviewOptions = { decision, reviewer };
|
|
38
51
|
if (typeof input.feedback === "string")
|
|
39
52
|
reviewOptions.feedback = input.feedback;
|
|
53
|
+
if (sectionDecisions !== void 0)
|
|
54
|
+
reviewOptions.sectionDecisions = sectionDecisions;
|
|
40
55
|
if (typeof input.workflowId === "string")
|
|
41
56
|
reviewOptions.workflowId = input.workflowId;
|
|
42
57
|
return { decision, reviewer, reviewOptions };
|
|
@@ -94,6 +109,7 @@ export const submitReviewDecisionRestBinding = {
|
|
|
94
109
|
decision: { kind: "body-field", bodyField: "decision" },
|
|
95
110
|
reviewer: { kind: "body-field", bodyField: "reviewer" },
|
|
96
111
|
feedback: { kind: "body-field", bodyField: "feedback" },
|
|
112
|
+
sectionDecisions: { kind: "body-field", bodyField: "sectionDecisions" },
|
|
97
113
|
workflowId: { kind: "body-field", bodyField: "workflowId" }
|
|
98
114
|
},
|
|
99
115
|
extractInput: async (request, pathParams, context) => {
|
|
@@ -107,6 +123,7 @@ export const submitReviewDecisionRestBinding = {
|
|
|
107
123
|
decision: record.decision,
|
|
108
124
|
reviewer: record.reviewer,
|
|
109
125
|
feedback: record.feedback,
|
|
126
|
+
sectionDecisions: record.sectionDecisions,
|
|
110
127
|
workflowId: record.workflowId
|
|
111
128
|
};
|
|
112
129
|
},
|
|
@@ -4,12 +4,20 @@ declare const updateScheduleInput: z.ZodObject<{
|
|
|
4
4
|
scheduleId: z.ZodString;
|
|
5
5
|
cronExpression: z.ZodOptional<z.ZodUnknown>;
|
|
6
6
|
every: z.ZodOptional<z.ZodUnknown>;
|
|
7
|
+
description: z.ZodOptional<z.ZodUnknown>;
|
|
8
|
+
overlap: z.ZodOptional<z.ZodUnknown>;
|
|
9
|
+
backfill: z.ZodOptional<z.ZodUnknown>;
|
|
10
|
+
jitter: z.ZodOptional<z.ZodUnknown>;
|
|
7
11
|
}, z.core.$strip>;
|
|
8
12
|
export type UpdateScheduleInput = z.infer<typeof updateScheduleInput>;
|
|
9
13
|
export declare const updateScheduleOperation: import("../operation-catalog.ts").OperationDefinition<{
|
|
10
14
|
scheduleId: string;
|
|
11
15
|
cronExpression?: unknown;
|
|
12
16
|
every?: unknown;
|
|
17
|
+
description?: unknown;
|
|
18
|
+
overlap?: unknown;
|
|
19
|
+
backfill?: unknown;
|
|
20
|
+
jitter?: unknown;
|
|
13
21
|
}, null, unknown>;
|
|
14
22
|
export declare const updateScheduleRestBinding: UnknownRestBinding;
|
|
15
23
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { normalizeScheduleUpdateOptions } from "../../core/engine/validation/schedule.js";
|
|
2
3
|
import { defineOperation } from "../operation-registry.js";
|
|
3
4
|
import { readRestJsonBody } from "../rest-body.js";
|
|
4
5
|
import { invalidParamsFault, isOperationFault, shapeRestFault } from "./operation-helpers.js";
|
|
@@ -6,25 +7,79 @@ import { mapScheduleErrorToFault, validateScheduleInputCadence } from "./schedul
|
|
|
6
7
|
const updateScheduleInput = z.object({
|
|
7
8
|
scheduleId: z.string().min(1),
|
|
8
9
|
cronExpression: z.unknown().optional().describe("Cron expression. Supply exactly one of cronExpression or every; runtime validation requires a non-empty string."),
|
|
9
|
-
every: z.unknown().optional().describe("Interval period (duration string or milliseconds). Supply exactly one of cronExpression or every.")
|
|
10
|
+
every: z.unknown().optional().describe("Interval period (duration string or milliseconds). Supply exactly one of cronExpression or every."),
|
|
11
|
+
description: z.unknown().optional().describe("Operator-facing schedule description. Runtime validation requires a string."),
|
|
12
|
+
overlap: z.unknown().optional(),
|
|
13
|
+
backfill: z.unknown().optional(),
|
|
14
|
+
jitter: z.unknown().optional()
|
|
10
15
|
});
|
|
16
|
+
function isScheduleOverlapPolicy(value) {
|
|
17
|
+
return value === "skip" || value === "queue" || value === "cancel-running" || value === "allow";
|
|
18
|
+
}
|
|
19
|
+
function validateDescription(value) {
|
|
20
|
+
if (value === void 0)
|
|
21
|
+
return;
|
|
22
|
+
if (typeof value !== "string")
|
|
23
|
+
throw invalidParamsFault('Field "description" must be a string');
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
function validateOverlap(value) {
|
|
27
|
+
if (value === void 0)
|
|
28
|
+
return;
|
|
29
|
+
if (typeof value !== "string" || !isScheduleOverlapPolicy(value))
|
|
30
|
+
throw invalidParamsFault('Field "overlap" must be one of skip, queue, cancel-running, allow');
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
function validateBackfill(value) {
|
|
34
|
+
if (value === void 0)
|
|
35
|
+
return;
|
|
36
|
+
if (typeof value !== "boolean")
|
|
37
|
+
throw invalidParamsFault('Field "backfill" must be a boolean');
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function formatJitterValidationMessage(message) {
|
|
41
|
+
const enginePrefix = "Invalid options.jitter: ", hasEnginePrefix = message.startsWith(enginePrefix), wireDetail = (hasEnginePrefix ? message.slice(enginePrefix.length) : message).replaceAll("options.jitter", 'Field "jitter"');
|
|
42
|
+
return hasEnginePrefix ? `Field "jitter" is invalid: ${wireDetail}` : wireDetail;
|
|
43
|
+
}
|
|
44
|
+
function validateJitter(value) {
|
|
45
|
+
if (value === void 0)
|
|
46
|
+
return;
|
|
47
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
48
|
+
throw invalidParamsFault('Field "jitter" must be a duration string or a number of milliseconds');
|
|
49
|
+
try {
|
|
50
|
+
normalizeScheduleUpdateOptions({ jitter: value });
|
|
51
|
+
} catch (error) {
|
|
52
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
53
|
+
throw invalidParamsFault(formatJitterValidationMessage(message));
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
function validateScheduleUpdateOptions(input) {
|
|
58
|
+
const description = validateDescription(input.description), overlap = validateOverlap(input.overlap), backfill = validateBackfill(input.backfill), jitter = validateJitter(input.jitter);
|
|
59
|
+
return {
|
|
60
|
+
...description !== void 0 ? { description } : {},
|
|
61
|
+
...overlap !== void 0 ? { overlap } : {},
|
|
62
|
+
...backfill !== void 0 ? { backfill } : {},
|
|
63
|
+
...jitter !== void 0 ? { jitter } : {}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
11
66
|
export const updateScheduleOperation = defineOperation({
|
|
12
67
|
name: "weft.schedules.update",
|
|
13
68
|
mcpExposable: !1,
|
|
14
69
|
summary: "Update a recurring schedule",
|
|
15
|
-
description: "Update an existing recurring schedule by `id`, replacing its recurrence specification,
|
|
70
|
+
description: "Update an existing recurring schedule by `id`, replacing its recurrence specification and optionally changing description, overlap, backfill, or jitter. Omitted options retain their persisted values; schedule id, workflow type, and input remain unchanged. Returns null on success. Faults with NotFound when no schedule with the given id exists and InvalidParams for malformed fields.",
|
|
16
71
|
destructive: !1,
|
|
17
72
|
tags: ["Schedules"],
|
|
18
73
|
inputSchema: updateScheduleInput,
|
|
19
74
|
outputSchema: z.null(),
|
|
20
75
|
access: { kind: "public" },
|
|
21
|
-
producibleFaults: ["NotFound", "Conflict"],
|
|
76
|
+
producibleFaults: ["NotFound", "Conflict", "InvalidParams"],
|
|
22
77
|
transports: { http: !0, jsonRpcHttp: !0, jsonRpcWebSocket: !0, jsonRpcStdio: !0 },
|
|
23
78
|
unknownKeyPolicy: { http: "strip", jsonRpc: "reject" },
|
|
24
79
|
invoke: async ({ input, engine }) => {
|
|
25
|
-
const typedEngine = engine, spec = validateScheduleInputCadence(input);
|
|
80
|
+
const typedEngine = engine, spec = validateScheduleInputCadence(input), options = validateScheduleUpdateOptions(input);
|
|
26
81
|
try {
|
|
27
|
-
await typedEngine.updateSchedule(input.scheduleId, spec);
|
|
82
|
+
await typedEngine.updateSchedule(input.scheduleId, spec, options);
|
|
28
83
|
return null;
|
|
29
84
|
} catch (error) {
|
|
30
85
|
throw mapScheduleErrorToFault(input.scheduleId, error);
|
|
@@ -38,7 +93,11 @@ export const updateScheduleOperation = defineOperation({
|
|
|
38
93
|
inputSources: {
|
|
39
94
|
scheduleId: { kind: "path", pathParam: "id" },
|
|
40
95
|
cronExpression: { kind: "body-field", bodyField: "cronExpression" },
|
|
41
|
-
every: { kind: "body-field", bodyField: "every" }
|
|
96
|
+
every: { kind: "body-field", bodyField: "every" },
|
|
97
|
+
description: { kind: "body-field", bodyField: "description" },
|
|
98
|
+
overlap: { kind: "body-field", bodyField: "overlap" },
|
|
99
|
+
backfill: { kind: "body-field", bodyField: "backfill" },
|
|
100
|
+
jitter: { kind: "body-field", bodyField: "jitter" }
|
|
42
101
|
},
|
|
43
102
|
extractInput: async (request, pathParams, context) => {
|
|
44
103
|
let body;
|
|
@@ -55,7 +114,11 @@ export const updateScheduleOperation = defineOperation({
|
|
|
55
114
|
return {
|
|
56
115
|
scheduleId: pathParams.id ?? "",
|
|
57
116
|
cronExpression: Object.hasOwn(record, "cronExpression") ? record.cronExpression : void 0,
|
|
58
|
-
every: Object.hasOwn(record, "every") ? record.every : void 0
|
|
117
|
+
every: Object.hasOwn(record, "every") ? record.every : void 0,
|
|
118
|
+
description: record.description,
|
|
119
|
+
overlap: record.overlap,
|
|
120
|
+
backfill: record.backfill,
|
|
121
|
+
jitter: record.jitter
|
|
59
122
|
};
|
|
60
123
|
},
|
|
61
124
|
success: { kind: "empty", status: 204 },
|
|
@@ -4,7 +4,7 @@ import { isAuthenticated } from "../principal.js";
|
|
|
4
4
|
import {
|
|
5
5
|
decodeCursor
|
|
6
6
|
} from "../workflow-event-feed.js";
|
|
7
|
-
import { invalidParamsFault,
|
|
7
|
+
import { invalidParamsFault, shapeRestFault } from "./operation-helpers.js";
|
|
8
8
|
import {
|
|
9
9
|
createEventEnvelopeSSEStream,
|
|
10
10
|
readServerSentEventsCursor,
|
|
@@ -163,7 +163,7 @@ function shapeWorkflowEventsSseSuccess(output, request) {
|
|
|
163
163
|
}
|
|
164
164
|
function shapeWorkflowEventsSseFault(fault) {
|
|
165
165
|
if (fault.code === "InvalidParams" && fault.message === MAXIMUM_WORKFLOW_STREAMS_MESSAGE)
|
|
166
|
-
return
|
|
166
|
+
return shapeRestFault(fault, { status: 429 });
|
|
167
167
|
return shapeServerSentEventsFault(fault);
|
|
168
168
|
}
|
|
169
169
|
function readSelector(request) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Private replay/live-drain algorithm shared by every `createReplayLiveFeed()`
|
|
3
|
+
* instance (`workflow-event-feed.ts`'s per-workflow feed and
|
|
4
|
+
* `fleet-event-feed.ts`'s fleet-wide feed). Split out of
|
|
5
|
+
* `workflow-event-feed.ts` purely to keep that file under the repository's
|
|
6
|
+
* implementation-file line limit — nothing here is public API.
|
|
7
|
+
*
|
|
8
|
+
* @module server/replay-live-feed-internals
|
|
9
|
+
*/
|
|
10
|
+
import type { ReplayLiveFeedBackend, ReplayLiveSubscribeOptions, SequencedEventEnvelope } from './workflow-event-feed.ts';
|
|
11
|
+
/** Thrown when a replay window exceeds the caller's configured limit. */
|
|
12
|
+
export declare class ReplayWindowExceededError extends Error {
|
|
13
|
+
readonly count: number;
|
|
14
|
+
readonly limit: number;
|
|
15
|
+
constructor(count: number, limit: number);
|
|
16
|
+
}
|
|
17
|
+
export declare function replayUpTo<TEnvelope extends SequencedEventEnvelope>(backend: ReplayLiveFeedBackend<TEnvelope>, afterSequence: number, snapshot: number, signal: AbortSignal | undefined, replayOptions: ReplayLiveSubscribeOptions<TEnvelope> | undefined): AsyncIterable<TEnvelope>;
|
|
18
|
+
export declare function shouldDeliverEnvelope<TEnvelope extends SequencedEventEnvelope>(envelope: TEnvelope, replayOptions: ReplayLiveSubscribeOptions<TEnvelope> | undefined): boolean;
|
|
19
|
+
export declare function drainLive<TEnvelope extends SequencedEventEnvelope>(buffer: TEnvelope[], snapshot: number, signal: AbortSignal | undefined, overflowed: () => boolean, installWaker: (fn: (() => void) | null) => void): AsyncIterable<TEnvelope>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export class ReplayWindowExceededError extends Error {
|
|
2
|
+
count;
|
|
3
|
+
limit;
|
|
4
|
+
constructor(count, limit) {
|
|
5
|
+
super(`Replay window is ${count} events; maximum is ${limit}.`);
|
|
6
|
+
this.count = count;
|
|
7
|
+
this.limit = limit;
|
|
8
|
+
this.name = "ReplayWindowExceededError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export async function* replayUpTo(backend, afterSequence, snapshot, signal, replayOptions) {
|
|
12
|
+
let replayCount = 0;
|
|
13
|
+
for await (const envelope of backend.replay({ afterSequence })) {
|
|
14
|
+
if (envelope.sequence > snapshot)
|
|
15
|
+
break;
|
|
16
|
+
if (signal?.aborted)
|
|
17
|
+
return;
|
|
18
|
+
if (!shouldDeliverEnvelope(envelope, replayOptions))
|
|
19
|
+
continue;
|
|
20
|
+
if (shouldCountReplayEnvelope(envelope, replayOptions)) {
|
|
21
|
+
replayCount += 1;
|
|
22
|
+
const replayLimit = replayOptions?.replayLimit;
|
|
23
|
+
if (replayLimit !== void 0 && replayCount > replayLimit)
|
|
24
|
+
throw createReplayLimitError(replayOptions, replayCount, replayLimit);
|
|
25
|
+
}
|
|
26
|
+
yield envelope;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function shouldDeliverEnvelope(envelope, replayOptions) {
|
|
30
|
+
return replayOptions?.filterEnvelope?.(envelope) ?? !0;
|
|
31
|
+
}
|
|
32
|
+
function shouldCountReplayEnvelope(envelope, replayOptions) {
|
|
33
|
+
return replayOptions?.countReplayEnvelope?.(envelope) ?? !0;
|
|
34
|
+
}
|
|
35
|
+
function createReplayLimitError(replayOptions, count, limit) {
|
|
36
|
+
return replayOptions?.createReplayLimitError?.(count, limit) ?? new ReplayWindowExceededError(count, limit);
|
|
37
|
+
}
|
|
38
|
+
function flushPendingBuffer(buffer, watermark) {
|
|
39
|
+
const batch = [];
|
|
40
|
+
let newWatermark = watermark, head = buffer.shift();
|
|
41
|
+
while (head !== void 0) {
|
|
42
|
+
if (head.sequence > newWatermark) {
|
|
43
|
+
batch.push(head);
|
|
44
|
+
newWatermark = head.sequence;
|
|
45
|
+
}
|
|
46
|
+
head = buffer.shift();
|
|
47
|
+
}
|
|
48
|
+
return { batch, newWatermark };
|
|
49
|
+
}
|
|
50
|
+
async function armAndWait(buffer, overflowed, signal, installWaker) {
|
|
51
|
+
const armed = new Promise((resolve) => {
|
|
52
|
+
installWaker(resolve);
|
|
53
|
+
});
|
|
54
|
+
if (buffer.length > 0 || overflowed() || signal?.aborted) {
|
|
55
|
+
installWaker(null);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
await armed;
|
|
59
|
+
}
|
|
60
|
+
export async function* drainLive(buffer, snapshot, signal, overflowed, installWaker) {
|
|
61
|
+
let watermark = snapshot;
|
|
62
|
+
while (!0) {
|
|
63
|
+
if (signal?.aborted || overflowed())
|
|
64
|
+
break;
|
|
65
|
+
const { batch, newWatermark } = flushPendingBuffer(buffer, watermark);
|
|
66
|
+
watermark = newWatermark;
|
|
67
|
+
for (const envelope of batch) {
|
|
68
|
+
if (signal?.aborted || overflowed())
|
|
69
|
+
return;
|
|
70
|
+
yield envelope;
|
|
71
|
+
}
|
|
72
|
+
if (batch.length > 0)
|
|
73
|
+
continue;
|
|
74
|
+
await armAndWait(buffer, overflowed, signal, installWaker);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -114,16 +114,17 @@ export type RestBinding<Input, Output> = {
|
|
|
114
114
|
/**
|
|
115
115
|
* Optional override for fault → HTTP response mapping. When absent,
|
|
116
116
|
* the transport adapter falls back to `faultToHttpResponse`, which emits
|
|
117
|
-
* the
|
|
118
|
-
* distinct from the JSON-RPC fault object
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
117
|
+
* the same flat audited `{ error, weftCode?, data? }` body as
|
|
118
|
+
* `shapeRestFault`. This is distinct from the JSON-RPC fault object
|
|
119
|
+
* (`faultToJsonRpcError`), which uses `{ code, message, data }` with a numeric
|
|
120
|
+
* `code` and a broader data projection. REST and JSON-RPC deliberately differ
|
|
121
|
+
* in fault shape, so each transport owns its own projection.
|
|
122
122
|
*
|
|
123
123
|
* REST operations provide this to shape faults the way a REST client
|
|
124
124
|
* expects: most use `shapeRestFault`, which masks an `EngineFailure` to a
|
|
125
125
|
* flat `{ error: "Internal server error" }` with status `500` (never
|
|
126
|
-
* leaking internal detail over REST)
|
|
126
|
+
* leaking internal detail over REST), adds audited safe context under a
|
|
127
|
+
* `data` sibling for other faults, and maps the remaining fault codes to
|
|
127
128
|
* their HTTP statuses. A few operations supply a bespoke shaper to special-case
|
|
128
129
|
* a particular fault — typically to override its message or to handle one code
|
|
129
130
|
* explicitly — while delegating the rest. The status often matches what the
|