@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.
Files changed (242) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/api.d.ts +2 -0
  3. package/dist/cli/api.js +3 -4
  4. package/dist/cli/generated/operation-catalog.snapshot.json +5167 -0
  5. package/dist/cli/generated/operation-client.generated.d.ts +119 -10
  6. package/dist/cli/generated/operation-client.generated.js +74 -1
  7. package/dist/cli/index.js +1 -0
  8. package/dist/cli/operation-catalog-snapshot.d.ts +11 -2
  9. package/dist/cli/operation-catalog-snapshot.js +14 -5
  10. package/dist/cli/operation-client-runtime.d.ts +29 -0
  11. package/dist/cli-main.js +227 -401
  12. package/dist/client/client-storage.d.ts +24 -0
  13. package/dist/client/client-storage.js +14 -0
  14. package/dist/client/handle-delegation.d.ts +3 -3
  15. package/dist/client/handle-delegation.js +2 -2
  16. package/dist/client/http-client-requests.d.ts +5 -3
  17. package/dist/client/http-client-requests.js +20 -2
  18. package/dist/client/http-client-storage.d.ts +3 -0
  19. package/dist/client/http-client-storage.js +110 -0
  20. package/dist/client/http-client.d.ts +9 -6
  21. package/dist/client/http-client.js +13 -18
  22. package/dist/client/http-operations.d.ts +3 -1
  23. package/dist/client/http-operations.js +84 -2
  24. package/dist/client/http-request.d.ts +35 -6
  25. package/dist/client/http-request.js +31 -10
  26. package/dist/client/in-process-operations.d.ts +2 -2
  27. package/dist/client/in-process-operations.js +2 -2
  28. package/dist/client/index.d.ts +6 -0
  29. package/dist/client/index.js +18 -0
  30. package/dist/client/interface.d.ts +26 -26
  31. package/dist/client/local.d.ts +9 -6
  32. package/dist/client/local.js +9 -4
  33. package/dist/client/search-params.js +10 -6
  34. package/dist/client/start-body.d.ts +3 -1
  35. package/dist/client/start-body.js +9 -0
  36. package/dist/connection.d.ts +8 -0
  37. package/dist/connection.js +41 -17
  38. package/dist/core/bulk-workflow-filter.d.ts +2 -1
  39. package/dist/core/bulk-workflow-filter.js +5 -1
  40. package/dist/core/engine/async-activity-records.d.ts +12 -1
  41. package/dist/core/engine/async-activity-records.js +81 -2
  42. package/dist/core/engine/bulk-operations-purge.js +16 -1
  43. package/dist/core/engine/bulk-operations-shared.js +2 -0
  44. package/dist/core/engine/callback-creators-core.js +2 -1
  45. package/dist/core/engine/callback-creators-schedule.d.ts +2 -1
  46. package/dist/core/engine/callback-creators-schedule.js +3 -3
  47. package/dist/core/engine/checkpoint-reads.js +11 -1
  48. package/dist/core/engine/child-workflow.js +15 -6
  49. package/dist/core/engine/construction.js +3 -0
  50. package/dist/core/engine/disposal.js +2 -0
  51. package/dist/core/engine/engine-internal-types.d.ts +4 -1
  52. package/dist/core/engine/fenced-write.d.ts +5 -3
  53. package/dist/core/engine/finalizer-status.d.ts +10 -0
  54. package/dist/core/engine/finalizer-status.js +82 -0
  55. package/dist/core/engine/index.d.ts +69 -2
  56. package/dist/core/engine/index.js +71 -8
  57. package/dist/core/engine/internals.d.ts +3 -0
  58. package/dist/core/engine/lease-health.d.ts +64 -0
  59. package/dist/core/engine/lease-health.js +0 -0
  60. package/dist/core/engine/lease-manager.d.ts +4 -2
  61. package/dist/core/engine/lease-manager.js +32 -4
  62. package/dist/core/engine/lifecycle/recovered-services.js +0 -2
  63. package/dist/core/engine/lifecycle/shared.d.ts +28 -0
  64. package/dist/core/engine/lifecycle/start-batch.js +12 -0
  65. package/dist/core/engine/lifecycle/start.d.ts +1 -1
  66. package/dist/core/engine/lifecycle/start.js +34 -5
  67. package/dist/core/engine/lifecycle/transition.js +19 -9
  68. package/dist/core/engine/operations-coordination.d.ts +1 -12
  69. package/dist/core/engine/operations-coordination.js +57 -10
  70. package/dist/core/engine/operations-speculate.d.ts +1 -1
  71. package/dist/core/engine/operations-speculate.js +19 -5
  72. package/dist/core/engine/registration.js +14 -0
  73. package/dist/core/engine/schedule-handle.d.ts +4 -4
  74. package/dist/core/engine/schedule-handle.js +2 -2
  75. package/dist/core/engine/schedule-overlap.d.ts +11 -0
  76. package/dist/core/engine/schedule-overlap.js +50 -0
  77. package/dist/core/engine/schedule-run.d.ts +11 -3
  78. package/dist/core/engine/schedule-run.js +27 -4
  79. package/dist/core/engine/schedule-timer.js +10 -1
  80. package/dist/core/engine/schedules.d.ts +5 -4
  81. package/dist/core/engine/schedules.js +62 -56
  82. package/dist/core/engine/state-utilities.js +1 -1
  83. package/dist/core/engine/storage-io.d.ts +12 -0
  84. package/dist/core/engine/storage-io.js +49 -10
  85. package/dist/core/engine/termination/finalizer-claim.d.ts +8 -6
  86. package/dist/core/engine/termination/finalizer-claim.js +2 -1
  87. package/dist/core/engine/termination/finalizer.js +10 -14
  88. package/dist/core/engine/timeline-coordinator-constants.d.ts +3 -0
  89. package/dist/core/engine/timeline-coordinator-constants.js +1 -0
  90. package/dist/core/engine/timeline-coordinator-detail.d.ts +13 -0
  91. package/dist/core/engine/timeline-coordinator-detail.js +76 -0
  92. package/dist/core/engine/validation/schedule-options.d.ts +8 -1
  93. package/dist/core/engine/validation/schedule-options.js +18 -0
  94. package/dist/core/engine/validation/schedule.d.ts +1 -1
  95. package/dist/core/engine/validation/schedule.js +27 -3
  96. package/dist/core/engine/validation.js +66 -2
  97. package/dist/core/engine/workflow-state-stream.d.ts +5 -1
  98. package/dist/core/engine/workflow-state-stream.js +37 -14
  99. package/dist/core/events/schedule-events.d.ts +3 -4
  100. package/dist/core/events/workflow-events.d.ts +2 -1
  101. package/dist/core/list-filter-validation.d.ts +3 -0
  102. package/dist/core/list-filter-validation.js +11 -0
  103. package/dist/core/registry-snapshot.d.ts +32 -0
  104. package/dist/core/registry-snapshot.js +28 -0
  105. package/dist/core/review/index.d.ts +4 -4
  106. package/dist/core/types/activity.d.ts +52 -5
  107. package/dist/core/types/bulk.d.ts +1 -0
  108. package/dist/core/types/definition-schema-to-json.d.ts +11 -0
  109. package/dist/core/types/definition-schema-to-json.js +11 -2
  110. package/dist/core/types/list-options.d.ts +6 -0
  111. package/dist/core/types/options.d.ts +6 -5
  112. package/dist/core/types/reviews.d.ts +2 -2
  113. package/dist/core/types/schedules.d.ts +45 -2
  114. package/dist/core/types/services-resolution.d.ts +5 -5
  115. package/dist/core/types/state.d.ts +64 -0
  116. package/dist/core/types/workflow-log.d.ts +3 -2
  117. package/dist/core/types/workflow-observability.d.ts +50 -0
  118. package/dist/core/types/workflow-observability.js +0 -0
  119. package/dist/core/types/workflow-registry.d.ts +7 -0
  120. package/dist/core/types.d.ts +1 -0
  121. package/dist/core/types.js +1 -0
  122. package/dist/http.js +2 -0
  123. package/dist/index.d.ts +4 -3
  124. package/dist/indexeddb.js +1 -0
  125. package/dist/json-schema.js +3 -3
  126. package/dist/mcp/cli.js +63 -61
  127. package/dist/mcp/http.d.ts +7 -2
  128. package/dist/mcp/session.d.ts +3 -3
  129. package/dist/mcp/session.js +3 -2
  130. package/dist/mcp/stdio.d.ts +7 -2
  131. package/dist/observability/index.js +2 -2
  132. package/dist/runtime/portable.d.ts +33 -0
  133. package/dist/runtime/portable.js +17 -6
  134. package/dist/server/access-policy-metadata.d.ts +92 -0
  135. package/dist/server/access-policy-metadata.js +78 -0
  136. package/dist/server/engine-event-feed-backend.d.ts +22 -3
  137. package/dist/server/fault-to-http.d.ts +3 -7
  138. package/dist/server/fault-to-http.js +2 -34
  139. package/dist/server/fleet-event-feed.d.ts +65 -0
  140. package/dist/server/handler/index.d.ts +11 -2
  141. package/dist/server/handler/index.js +8 -1
  142. package/dist/server/handler/route-dispatch.d.ts +10 -3
  143. package/dist/server/handler/route-dispatch.js +19 -4
  144. package/dist/server/handler.js +1 -56
  145. package/dist/server/index.d.ts +13 -2
  146. package/dist/server/index.js +88 -64
  147. package/dist/server/interactive-operations.js +2 -0
  148. package/dist/server/openapi-error-responses.js +55 -4
  149. package/dist/server/openapi.d.ts +3 -1
  150. package/dist/server/openapi.js +4 -0
  151. package/dist/server/openrpc-document-schema.d.ts +64 -0
  152. package/dist/server/openrpc-document-schema.js +6 -26
  153. package/dist/server/openrpc.d.ts +4 -0
  154. package/dist/server/openrpc.js +9 -33
  155. package/dist/server/operation-fault.d.ts +24 -7
  156. package/dist/server/operation-fault.js +65 -13
  157. package/dist/server/operations/aggregate-workflows.d.ts +6 -0
  158. package/dist/server/operations/aggregate-workflows.js +3 -2
  159. package/dist/server/operations/async-activity.d.ts +14 -0
  160. package/dist/server/operations/async-activity.js +88 -4
  161. package/dist/server/operations/bulk-filter-helpers.d.ts +3 -0
  162. package/dist/server/operations/bulk-filter-helpers.js +27 -3
  163. package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +6 -0
  164. package/dist/server/operations/bulk-signal-workflows.d.ts +6 -0
  165. package/dist/server/operations/get-stream-chunks.js +2 -7
  166. package/dist/server/operations/get-system-lease.d.ts +19 -0
  167. package/dist/server/operations/get-system-lease.js +48 -0
  168. package/dist/server/operations/get-workflow-observability.d.ts +24 -0
  169. package/dist/server/operations/get-workflow-observability.js +80 -0
  170. package/dist/server/operations/get-workflow-result.js +2 -2
  171. package/dist/server/operations/get-workflow.d.ts +2 -2
  172. package/dist/server/operations/list-filter-query-extractor.js +15 -0
  173. package/dist/server/operations/list-workflows.d.ts +6 -0
  174. package/dist/server/operations/list-workflows.js +12 -3
  175. package/dist/server/operations/operation-helpers.d.ts +9 -18
  176. package/dist/server/operations/operation-helpers.js +5 -23
  177. package/dist/server/operations/purge-workflows.d.ts +3 -0
  178. package/dist/server/operations/recover-all.js +2 -1
  179. package/dist/server/operations/single-workflow-tag-mutation.js +2 -2
  180. package/dist/server/operations/sse-stream.js +2 -7
  181. package/dist/server/operations/storage-capabilities.d.ts +34 -0
  182. package/dist/server/operations/storage-capabilities.js +38 -0
  183. package/dist/server/operations/storage.js +8 -17
  184. package/dist/server/operations/stream-workflow-sse.js +3 -9
  185. package/dist/server/operations/submit-review-decision.d.ts +2 -0
  186. package/dist/server/operations/submit-review-decision.js +19 -2
  187. package/dist/server/operations/update-schedule.d.ts +8 -0
  188. package/dist/server/operations/update-schedule.js +70 -7
  189. package/dist/server/operations/workflow-events-sse.js +2 -2
  190. package/dist/server/replay-live-feed-internals.d.ts +19 -0
  191. package/dist/server/replay-live-feed-internals.js +76 -0
  192. package/dist/server/rest-binding.d.ts +7 -6
  193. package/dist/server/rest-bindings.d.ts +2 -13
  194. package/dist/server/rest-bindings.js +19 -10
  195. package/dist/server/runtime/authentication-bridge.d.ts +2 -2
  196. package/dist/server/serve-internals.js +3 -3
  197. package/dist/server/task-queue.d.ts +7 -5
  198. package/dist/server/workflow-event-feed.d.ts +100 -11
  199. package/dist/server/workflow-event-feed.js +1 -140
  200. package/dist/service-worker/index.d.ts +8 -2
  201. package/dist/service-worker/index.js +37 -56
  202. package/dist/service-worker/setup.d.ts +6 -2
  203. package/dist/storage/auto.js +1 -1
  204. package/dist/storage/bun-sql.js +3 -3
  205. package/dist/storage/capabilities.d.ts +1 -1
  206. package/dist/storage/cloudflare-durable-object-sql.d.ts +75 -0
  207. package/dist/storage/cloudflare-durable-object-sql.js +0 -0
  208. package/dist/storage/cloudflare-value-codec.d.ts +67 -0
  209. package/dist/storage/cloudflare-value-codec.js +46 -0
  210. package/dist/storage/cloudflare.d.ts +140 -0
  211. package/dist/storage/cloudflare.js +127 -0
  212. package/dist/storage/compressed-storage.js +1 -1
  213. package/dist/storage/http.js +200 -2
  214. package/dist/storage/index.d.ts +8 -1
  215. package/dist/storage/indexeddb.js +311 -1
  216. package/dist/storage/interface.d.ts +16 -4
  217. package/dist/storage/interface.js +1 -1
  218. package/dist/storage/key-prefixes.d.ts +1 -1
  219. package/dist/storage/key-prefixes.js +4 -0
  220. package/dist/storage/lmdb.js +1 -1
  221. package/dist/storage/memory.js +1 -1
  222. package/dist/storage/neon.js +4 -4
  223. package/dist/storage/node-sqlite.js +3 -3
  224. package/dist/storage/postgres-key-value-queries.d.ts +6 -0
  225. package/dist/storage/postgres-key-value-queries.js +2 -3
  226. package/dist/storage/postgres.js +4 -4
  227. package/dist/storage/resolve.js +1 -1
  228. package/dist/storage/scoped-storage.js +1 -1
  229. package/dist/storage/sql-identifier.d.ts +35 -0
  230. package/dist/storage/sql-identifier.js +5 -0
  231. package/dist/storage/sqlite-key-value-queries.d.ts +11 -6
  232. package/dist/storage/sqlite-key-value-queries.js +3 -3
  233. package/dist/storage/testing.js +1 -1
  234. package/dist/storage/turso.js +2 -2
  235. package/dist/storage/typed-storage.js +138 -2
  236. package/dist/storage/web-extension.js +298 -1
  237. package/dist/testing/index.js +21 -60
  238. package/dist/version.d.ts +1 -1
  239. package/dist/version.js +1 -1
  240. package/dist/web-extension.js +1 -0
  241. package/dist/worker/protocol.js +1 -1
  242. package/package.json +8 -3
@@ -1,14 +1,9 @@
1
- import { isWeftErrorCode } from "../../core/weft-error.js";
2
- import { FAULT_CODE_TO_HTTP_STATUS } from "../operation-fault.js";
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
- if (fault.code === "EngineFailure")
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
- error: "workflow_type_not_registered_for_recovery",
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, jsonErrorResponse, shapeRestFault } from "./operation-helpers.js";
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 jsonErrorResponse(fault.message, 400);
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 jsonErrorResponse(fault.message, 406);
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 storageReadAccess = {
15
+ const rawStorageAccess = {
16
16
  kind: "scoped",
17
- scopes: { kind: "anyOf", scopes: ["storage:read", "storage:admin"] }
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: storageReadAccess,
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: storageWriteAccess,
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: storageWriteAccess,
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: storageReadAccess,
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: storageWriteAccess,
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: storageConditionalBatchAccess,
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, jsonErrorResponse } from "./operation-helpers.js";
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 jsonErrorResponse(fault.message, 406);
50
- return jsonErrorResponse(fault.message, 400);
46
+ return shapeRestFault(fault, { status: 406 });
51
47
  }
52
- if (fault.code === "EngineFailure")
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 { decision, reviewer } = input, reviewOptions = { decision, reviewer };
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, target workflow input, or start options. Returns null on success. Faults with NotFound when no schedule with the given id exists and InvalidParams for a malformed 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, jsonErrorResponse } from "./operation-helpers.js";
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 jsonErrorResponse(fault.message, 429);
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 REST fault body `{ error: { code, message, data? } }`. This is
118
- * distinct from the JSON-RPC fault object (`faultToJsonRpcError`): JSON-RPC
119
- * uses a flat `{ code, message, data }` with a numeric `code` and the
120
- * symbolic name relocated to `data.weftCode`. REST and JSON-RPC deliberately
121
- * differ in fault shape, so each transport owns its own projection.
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) and maps the remaining fault codes to
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