@lostgradient/weft 0.12.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 (191) 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 +508 -12
  5. package/dist/cli/generated/operation-client.generated.d.ts +118 -10
  6. package/dist/cli/generated/operation-client.generated.js +74 -1
  7. package/dist/cli/operation-catalog-snapshot.d.ts +11 -2
  8. package/dist/cli/operation-catalog-snapshot.js +14 -5
  9. package/dist/cli/operation-client-runtime.d.ts +29 -0
  10. package/dist/client/client-storage.d.ts +24 -0
  11. package/dist/client/client-storage.js +14 -0
  12. package/dist/client/handle-delegation.d.ts +3 -3
  13. package/dist/client/handle-delegation.js +2 -2
  14. package/dist/client/http-client-requests.d.ts +5 -3
  15. package/dist/client/http-client-requests.js +20 -2
  16. package/dist/client/http-client-storage.d.ts +3 -0
  17. package/dist/client/http-client-storage.js +110 -0
  18. package/dist/client/http-client.d.ts +9 -6
  19. package/dist/client/http-client.js +13 -18
  20. package/dist/client/http-operations.d.ts +3 -1
  21. package/dist/client/http-operations.js +77 -1
  22. package/dist/client/http-request.d.ts +15 -8
  23. package/dist/client/http-request.js +19 -7
  24. package/dist/client/in-process-operations.d.ts +2 -2
  25. package/dist/client/in-process-operations.js +2 -2
  26. package/dist/client/index.d.ts +5 -1
  27. package/dist/client/index.js +13 -2
  28. package/dist/client/interface.d.ts +26 -26
  29. package/dist/client/local.d.ts +9 -6
  30. package/dist/client/local.js +9 -4
  31. package/dist/client/search-params.js +10 -6
  32. package/dist/client/start-body.d.ts +3 -1
  33. package/dist/client/start-body.js +9 -0
  34. package/dist/core/bulk-workflow-filter.d.ts +2 -1
  35. package/dist/core/bulk-workflow-filter.js +5 -1
  36. package/dist/core/engine/async-activity-records.d.ts +12 -1
  37. package/dist/core/engine/async-activity-records.js +81 -2
  38. package/dist/core/engine/bulk-operations-purge.js +16 -1
  39. package/dist/core/engine/bulk-operations-shared.js +2 -0
  40. package/dist/core/engine/callback-creators-schedule.d.ts +2 -1
  41. package/dist/core/engine/callback-creators-schedule.js +3 -3
  42. package/dist/core/engine/checkpoint-reads.js +11 -1
  43. package/dist/core/engine/child-workflow.js +15 -6
  44. package/dist/core/engine/construction.js +3 -0
  45. package/dist/core/engine/disposal.js +2 -0
  46. package/dist/core/engine/engine-internal-types.d.ts +4 -1
  47. package/dist/core/engine/fenced-write.d.ts +5 -3
  48. package/dist/core/engine/finalizer-status.d.ts +10 -0
  49. package/dist/core/engine/finalizer-status.js +82 -0
  50. package/dist/core/engine/index.d.ts +26 -2
  51. package/dist/core/engine/index.js +71 -8
  52. package/dist/core/engine/internals.d.ts +3 -0
  53. package/dist/core/engine/lease-health.d.ts +64 -0
  54. package/dist/core/engine/lease-health.js +0 -0
  55. package/dist/core/engine/lease-manager.d.ts +4 -2
  56. package/dist/core/engine/lease-manager.js +32 -4
  57. package/dist/core/engine/lifecycle/recovered-services.js +0 -2
  58. package/dist/core/engine/lifecycle/shared.d.ts +11 -8
  59. package/dist/core/engine/lifecycle/start-batch.js +12 -0
  60. package/dist/core/engine/lifecycle/start.d.ts +1 -1
  61. package/dist/core/engine/lifecycle/start.js +34 -5
  62. package/dist/core/engine/operations-coordination.d.ts +1 -12
  63. package/dist/core/engine/operations-coordination.js +57 -10
  64. package/dist/core/engine/operations-speculate.d.ts +1 -1
  65. package/dist/core/engine/operations-speculate.js +19 -5
  66. package/dist/core/engine/registration.js +14 -0
  67. package/dist/core/engine/schedule-handle.d.ts +4 -4
  68. package/dist/core/engine/schedule-handle.js +2 -2
  69. package/dist/core/engine/schedule-overlap.d.ts +11 -0
  70. package/dist/core/engine/schedule-overlap.js +50 -0
  71. package/dist/core/engine/schedule-run.d.ts +11 -3
  72. package/dist/core/engine/schedule-run.js +27 -4
  73. package/dist/core/engine/schedule-timer.js +10 -1
  74. package/dist/core/engine/schedules.d.ts +5 -4
  75. package/dist/core/engine/schedules.js +62 -56
  76. package/dist/core/engine/state-utilities.js +1 -1
  77. package/dist/core/engine/storage-io.d.ts +12 -0
  78. package/dist/core/engine/storage-io.js +49 -10
  79. package/dist/core/engine/termination/finalizer-claim.d.ts +8 -6
  80. package/dist/core/engine/termination/finalizer-claim.js +2 -1
  81. package/dist/core/engine/termination/finalizer.js +10 -14
  82. package/dist/core/engine/timeline-coordinator-constants.d.ts +3 -0
  83. package/dist/core/engine/timeline-coordinator-constants.js +1 -0
  84. package/dist/core/engine/timeline-coordinator-detail.d.ts +13 -0
  85. package/dist/core/engine/timeline-coordinator-detail.js +76 -0
  86. package/dist/core/engine/validation/schedule-options.d.ts +8 -1
  87. package/dist/core/engine/validation/schedule-options.js +18 -0
  88. package/dist/core/engine/validation/schedule.d.ts +1 -1
  89. package/dist/core/engine/validation/schedule.js +27 -3
  90. package/dist/core/engine/validation.js +66 -2
  91. package/dist/core/engine/workflow-state-stream.d.ts +5 -1
  92. package/dist/core/engine/workflow-state-stream.js +37 -14
  93. package/dist/core/events/schedule-events.d.ts +3 -4
  94. package/dist/core/events/workflow-events.d.ts +2 -1
  95. package/dist/core/list-filter-validation.d.ts +3 -0
  96. package/dist/core/list-filter-validation.js +11 -0
  97. package/dist/core/registry-snapshot.d.ts +32 -0
  98. package/dist/core/registry-snapshot.js +28 -0
  99. package/dist/core/review/index.d.ts +4 -4
  100. package/dist/core/types/activity.d.ts +52 -5
  101. package/dist/core/types/bulk.d.ts +1 -0
  102. package/dist/core/types/list-options.d.ts +6 -0
  103. package/dist/core/types/options.d.ts +6 -5
  104. package/dist/core/types/reviews.d.ts +2 -2
  105. package/dist/core/types/schedules.d.ts +45 -2
  106. package/dist/core/types/services-resolution.d.ts +5 -5
  107. package/dist/core/types/state.d.ts +64 -0
  108. package/dist/core/types/workflow-log.d.ts +3 -2
  109. package/dist/core/types/workflow-observability.d.ts +50 -0
  110. package/dist/core/types/workflow-observability.js +0 -0
  111. package/dist/core/types/workflow-registry.d.ts +7 -0
  112. package/dist/core/types.d.ts +1 -0
  113. package/dist/core/types.js +1 -0
  114. package/dist/http.js +2 -2
  115. package/dist/index.d.ts +4 -3
  116. package/dist/indexeddb.js +1 -1
  117. package/dist/server/access-policy-metadata.d.ts +92 -0
  118. package/dist/server/access-policy-metadata.js +78 -0
  119. package/dist/server/fault-to-http.d.ts +3 -7
  120. package/dist/server/fault-to-http.js +2 -34
  121. package/dist/server/handler/index.js +1 -1
  122. package/dist/server/handler/route-dispatch.d.ts +10 -3
  123. package/dist/server/handler/route-dispatch.js +19 -4
  124. package/dist/server/index.d.ts +1 -1
  125. package/dist/server/index.js +1 -0
  126. package/dist/server/interactive-operations.js +2 -0
  127. package/dist/server/openapi-error-responses.js +55 -4
  128. package/dist/server/openapi.d.ts +3 -1
  129. package/dist/server/openapi.js +4 -0
  130. package/dist/server/openrpc-document-schema.d.ts +64 -0
  131. package/dist/server/openrpc-document-schema.js +6 -26
  132. package/dist/server/openrpc.d.ts +4 -0
  133. package/dist/server/openrpc.js +9 -33
  134. package/dist/server/operation-fault.d.ts +24 -7
  135. package/dist/server/operation-fault.js +65 -13
  136. package/dist/server/operations/aggregate-workflows.d.ts +6 -0
  137. package/dist/server/operations/aggregate-workflows.js +3 -2
  138. package/dist/server/operations/async-activity.d.ts +14 -0
  139. package/dist/server/operations/async-activity.js +88 -4
  140. package/dist/server/operations/bulk-filter-helpers.d.ts +3 -0
  141. package/dist/server/operations/bulk-filter-helpers.js +27 -3
  142. package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +6 -0
  143. package/dist/server/operations/bulk-signal-workflows.d.ts +6 -0
  144. package/dist/server/operations/get-stream-chunks.js +2 -7
  145. package/dist/server/operations/get-system-lease.d.ts +19 -0
  146. package/dist/server/operations/get-system-lease.js +48 -0
  147. package/dist/server/operations/get-workflow-observability.d.ts +24 -0
  148. package/dist/server/operations/get-workflow-observability.js +80 -0
  149. package/dist/server/operations/get-workflow-result.js +2 -2
  150. package/dist/server/operations/get-workflow.d.ts +2 -2
  151. package/dist/server/operations/list-filter-query-extractor.js +15 -0
  152. package/dist/server/operations/list-workflows.d.ts +6 -0
  153. package/dist/server/operations/list-workflows.js +12 -3
  154. package/dist/server/operations/operation-helpers.d.ts +9 -18
  155. package/dist/server/operations/operation-helpers.js +5 -23
  156. package/dist/server/operations/purge-workflows.d.ts +3 -0
  157. package/dist/server/operations/recover-all.js +2 -1
  158. package/dist/server/operations/single-workflow-tag-mutation.js +2 -2
  159. package/dist/server/operations/sse-stream.js +2 -7
  160. package/dist/server/operations/storage-capabilities.d.ts +34 -0
  161. package/dist/server/operations/storage-capabilities.js +38 -0
  162. package/dist/server/operations/storage.js +8 -17
  163. package/dist/server/operations/stream-workflow-sse.js +3 -9
  164. package/dist/server/operations/update-schedule.d.ts +8 -0
  165. package/dist/server/operations/update-schedule.js +70 -7
  166. package/dist/server/operations/workflow-events-sse.js +2 -2
  167. package/dist/server/rest-binding.d.ts +7 -6
  168. package/dist/server/rest-bindings.d.ts +2 -13
  169. package/dist/server/rest-bindings.js +19 -10
  170. package/dist/server/task-queue.d.ts +7 -5
  171. package/dist/storage/capabilities.d.ts +1 -1
  172. package/dist/storage/cloudflare-value-codec.d.ts +5 -3
  173. package/dist/storage/cloudflare-value-codec.js +1 -1
  174. package/dist/storage/compressed-storage.js +1 -1
  175. package/dist/storage/index.d.ts +7 -1
  176. package/dist/storage/interface.d.ts +16 -4
  177. package/dist/storage/interface.js +1 -1
  178. package/dist/storage/key-prefixes.d.ts +1 -1
  179. package/dist/storage/key-prefixes.js +4 -0
  180. package/dist/storage/lmdb.js +1 -1
  181. package/dist/storage/memory.js +1 -1
  182. package/dist/storage/neon.js +4 -4
  183. package/dist/storage/postgres.js +4 -4
  184. package/dist/storage/resolve.js +1 -1
  185. package/dist/storage/scoped-storage.js +1 -1
  186. package/dist/storage/testing.js +1 -1
  187. package/dist/storage/turso.js +2 -2
  188. package/dist/version.d.ts +1 -1
  189. package/dist/version.js +1 -1
  190. package/dist/web-extension.js +1 -1
  191. package/package.json +1 -1
@@ -0,0 +1,110 @@
1
+ import { decodeBase64ToBytes, encodeBytesToBase64, isRecord } from "../storage/byte-encoding.js";
2
+ import {
3
+ assertStorageBatchOperationCount
4
+ } from "../storage/interface.js";
5
+ import { request, requestResponse } from "./http-request.js";
6
+ const MAX_SCAN_RESPONSE_BYTES = 67108864;
7
+ function encodeOperation(operation) {
8
+ return operation.type === "put" ? { type: "put", key: operation.key, value: encodeBytesToBase64(operation.value) } : { type: "delete", key: operation.key };
9
+ }
10
+ function scanPath(prefix, options) {
11
+ const parameters = new URLSearchParams({ prefix });
12
+ for (const [name, value] of Object.entries(options))
13
+ if (value !== void 0)
14
+ parameters.set(name, String(value));
15
+ return `/storage?${parameters.toString()}`;
16
+ }
17
+ function scanEntry(value) {
18
+ if (!isRecord(value) || typeof value.key !== "string" || typeof value.value !== "string")
19
+ throw Error("HttpClient storage scan response contained an invalid NDJSON entry.");
20
+ return [value.key, decodeBase64ToBytes(value.value)];
21
+ }
22
+ async function releaseScanReader(reader, reachedEndOfStream) {
23
+ if (!reachedEndOfStream)
24
+ try {
25
+ await reader.cancel();
26
+ } catch {}
27
+ reader.releaseLock();
28
+ }
29
+ async function* scanResponse(response) {
30
+ if (response.body === null)
31
+ return;
32
+ const reader = response.body.getReader(), decoder = new TextDecoder;
33
+ let bufferedText = "", bytesRead = 0, reachedEndOfStream = !1;
34
+ try {
35
+ while (!0) {
36
+ const { done, value } = await reader.read();
37
+ if (done) {
38
+ reachedEndOfStream = !0;
39
+ break;
40
+ }
41
+ bytesRead += value.byteLength;
42
+ if (bytesRead > MAX_SCAN_RESPONSE_BYTES)
43
+ throw Error("HttpClient storage scan response exceeded the maximum allowed size.");
44
+ bufferedText += decoder.decode(value, { stream: !0 });
45
+ const lines = bufferedText.split(`
46
+ `);
47
+ bufferedText = lines.pop() ?? "";
48
+ for (const line of lines)
49
+ if (line.trim().length > 0)
50
+ yield scanEntry(JSON.parse(line));
51
+ }
52
+ bufferedText += decoder.decode();
53
+ if (bufferedText.trim().length > 0)
54
+ yield scanEntry(JSON.parse(bufferedText));
55
+ } finally {
56
+ await releaseScanReader(reader, reachedEndOfStream);
57
+ }
58
+ }
59
+ export function createHttpClientStorage(baseUrl, headers) {
60
+ return {
61
+ async get(key) {
62
+ const response = await requestResponse(baseUrl, `/storage/${encodeURIComponent(key)}`, headers, { method: "GET" });
63
+ return response === null ? null : new Uint8Array(await response.arrayBuffer());
64
+ },
65
+ async put(key, value) {
66
+ await requestResponse(baseUrl, `/storage/${encodeURIComponent(key)}`, headers, {
67
+ method: "PUT",
68
+ headers: { "content-type": "application/octet-stream" },
69
+ body: new Blob([value])
70
+ });
71
+ },
72
+ async delete(key) {
73
+ await requestResponse(baseUrl, `/storage/${encodeURIComponent(key)}`, headers, {
74
+ method: "DELETE"
75
+ });
76
+ },
77
+ async* scan(prefix, options = {}) {
78
+ const response = await requestResponse(baseUrl, scanPath(prefix, options), headers, {
79
+ method: "GET",
80
+ headers: { accept: "application/x-ndjson" }
81
+ });
82
+ if (response !== null)
83
+ yield* scanResponse(response);
84
+ },
85
+ async batch(operations) {
86
+ assertStorageBatchOperationCount("batch operations", operations.length);
87
+ await request(baseUrl, "/storage/-/batch", headers, {
88
+ method: "POST",
89
+ body: JSON.stringify({ operations: operations.map(encodeOperation) })
90
+ });
91
+ },
92
+ async conditionalBatch(conditions, operations) {
93
+ assertStorageBatchOperationCount("conditionalBatch conditions", conditions.length);
94
+ assertStorageBatchOperationCount("conditionalBatch operations", operations.length);
95
+ const result = await request(baseUrl, "/storage/-/conditional-batch", headers, {
96
+ method: "POST",
97
+ body: JSON.stringify({
98
+ conditions: conditions.map((condition) => ({
99
+ key: condition.key,
100
+ expectedValue: condition.expectedValue === null ? null : encodeBytesToBase64(condition.expectedValue)
101
+ })),
102
+ operations: operations.map(encodeOperation)
103
+ })
104
+ });
105
+ if (!isRecord(result) || typeof result.applied !== "boolean")
106
+ throw Error('HttpClient storage conditional batch response must include a boolean "applied" field.');
107
+ return result.applied;
108
+ }
109
+ };
110
+ }
@@ -1,6 +1,7 @@
1
- import { type CatalogOperationName, type CatalogOperationTypes, type WeftClient as CatalogOperations } from '../cli/generated/operation-client.generated.ts';
1
+ import { type ClientOperationName, type ClientOperationTypes, type ClientOperations } from '../cli/generated/operation-client.generated.ts';
2
2
  import type { StoredStreamChunk } from '../core/context.ts';
3
- import type { AttributeFilterKey, BulkCancelResult, BulkDeleteResult, BulkRetryFailedResult, BulkSignalResult, BulkTagResult, CoordinatedUpdateResult, ForkOptions, ListFilter, PaginatedResult, PurgeResult, QueryDefinition, RetentionOverview, ReviewListEntry, ReviewListFilter, ScheduleFilter, ScheduleOptions, ScheduleSpec, ScheduleSummary, SearchAttributeValue, SignalDefinition, SignalDeliveryOptions, StartOrSignalSignal, SubmitReviewOptions, TypedListFilter, UpdateDefinition, WorkflowEvent, WorkflowInput, WorkflowOutput, WorkflowRegistry, WorkflowReplay, WorkflowState, WorkflowSummary, WorkflowTimelineEntry } from '../core/types.ts';
3
+ import type { AttributeFilterKey, BulkCancelResult, BulkDeleteResult, BulkRetryFailedResult, BulkSignalResult, BulkTagResult, CoordinatedUpdateResult, ForkOptions, ListFilter, PaginatedResult, PurgeResult, QueryDefinition, RetentionOverview, ReviewListEntry, ReviewListFilter, ScheduleFilter, ScheduleOptions, ScheduleSpec, ScheduleSummary, ScheduleUpdateOptions, SearchAttributeValue, SignalDefinition, SignalDeliveryOptions, StartOrSignalSignal, SubmitReviewOptions, TypedListFilter, UpdateDefinition, WorkflowEvent, WorkflowInput, WorkflowOutput, WorkflowRegistry, WorkflowReplay, WorkflowState, WorkflowSummary, WorkflowTimelineEntry } from '../core/types.ts';
4
+ import type { WeftClientStorage } from './client-storage.ts';
4
5
  import type { WorkflowEventTail } from './event-tail.ts';
5
6
  import { type HttpClientOptions } from './http-request.ts';
6
7
  import type { ClientHandle, ClientScheduleHandle, ClientStartOptions, ClientStartOrSignalOptions, UpdateResult, WeftClient, WeftClientActivity } from './interface.ts';
@@ -49,15 +50,17 @@ export declare class HttpClient implements WeftClient {
49
50
  readonly baseUrl: string;
50
51
  /** @internal Exposed for handle access. */
51
52
  readonly headers: Record<string, string>;
52
- /** Typed low-level accessor for every catalog operation over JSON-RPC. */
53
- readonly operations: CatalogOperations;
53
+ /** Typed low-level accessor over JSON-RPC and generated ordinary REST bindings. */
54
+ readonly operations: ClientOperations;
55
+ /** Raw storage administration over the byte-oriented REST bindings. */
56
+ readonly storage: WeftClientStorage;
54
57
  /**
55
58
  * Out-of-band ("async") activity completion over HTTP. POSTs to
56
59
  * `/v1/activities/{complete,fail}`; mirrors {@link LocalClient}'s `activity`.
57
60
  */
58
61
  readonly activity: WeftClientActivity;
59
62
  constructor(options?: HttpClientOptions);
60
- call<Name extends CatalogOperationName>(name: Name, input: CatalogOperationTypes[Name]['input']): Promise<CatalogOperationTypes[Name]['output']>;
63
+ call<Name extends ClientOperationName>(name: Name, input: ClientOperationTypes[Name]['input']): Promise<ClientOperationTypes[Name]['output']>;
61
64
  start<TName extends KnownWorkflowName>(type: TName, input: WorkflowInput<WorkflowRegistry, TName>, options?: ClientStartOptions): Promise<ClientHandle<WorkflowOutput<WorkflowRegistry, TName>>>;
62
65
  start<TName extends string>(type: UnknownNameWhenRegistryEmpty<TName>, input: unknown, options?: ClientStartOptions): Promise<ClientHandle>;
63
66
  startOrSignal<TName extends KnownWorkflowName>(type: TName, input: WorkflowInput<WorkflowRegistry, TName>, signal: StartOrSignalSignal, options?: ClientStartOrSignalOptions): Promise<ClientHandle<WorkflowOutput<WorkflowRegistry, TName>>>;
@@ -75,7 +78,7 @@ export declare class HttpClient implements WeftClient {
75
78
  pauseSchedule(id: string): Promise<void>;
76
79
  resumeSchedule(id: string): Promise<void>;
77
80
  cancelSchedule(id: string): Promise<void>;
78
- updateSchedule(id: string, newSpec: string | ScheduleSpec): Promise<void>;
81
+ updateSchedule(id: string, newSpec: string | ScheduleSpec, options?: ScheduleUpdateOptions): Promise<void>;
79
82
  signal(id: string, name: SignalDefinition): Promise<void>;
80
83
  signal<TInput>(id: string, name: SignalDefinition<TInput>, payload: TInput, options?: SignalDeliveryOptions): Promise<void>;
81
84
  signal(id: string, name: string, payload?: unknown, options?: SignalDeliveryOptions): Promise<void>;
@@ -1,5 +1,6 @@
1
1
  import {
2
- CATALOG_OPERATION_NAMES
2
+ CLIENT_OPERATION_NAMES,
3
+ CLIENT_REST_OPERATION_BINDINGS
3
4
  } from "../cli/generated/operation-client.generated.js";
4
5
  import { createCatalogWeftClient } from "../cli/operation-client-runtime.js";
5
6
  import { messageName } from "../core/types.js";
@@ -19,6 +20,7 @@ import {
19
20
  getTimelineRequest,
20
21
  getUpdateResultRequest,
21
22
  getWorkflowRequest,
23
+ listPendingAsyncActivitiesRequest,
22
24
  listReviewRequests,
23
25
  pauseScheduleRequest,
24
26
  purgeWorkflowRequests,
@@ -38,27 +40,31 @@ import {
38
40
  untagAllWorkflowRequests,
39
41
  updateScheduleRequest
40
42
  } from "./http-client-requests.js";
43
+ import { createHttpClientStorage } from "./http-client-storage.js";
41
44
  import { HttpHandle } from "./http-handle.js";
42
- import { httpClientCatalogTransport } from "./http-operations.js";
45
+ import { httpClientOperationTransport } from "./http-operations.js";
43
46
  import { request, resolveHttpClientConnection } from "./http-request.js";
44
47
  import { HttpScheduleHandle } from "./http-schedule-handle.js";
45
48
  import { openClientEventSubscription } from "./open-event-subscription.js";
46
49
  import { buildScheduleListSearchParams } from "./schedule-list-search-params.js";
47
50
  import { buildWorkflowListSearchParams } from "./search-params.js";
48
- import { buildStartBody, buildStartOrSignalBody, scheduleSpecToWireFields } from "./start-body.js";
51
+ import { buildScheduleBody, buildStartBody, buildStartOrSignalBody } from "./start-body.js";
49
52
 
50
53
  export class HttpClient {
51
54
  baseUrl;
52
55
  headers;
53
56
  operations;
57
+ storage;
54
58
  activity;
55
59
  #streamOptions;
56
60
  constructor(options = {}) {
57
61
  const connection = resolveHttpClientConnection(options);
58
62
  this.baseUrl = connection.baseUrl;
59
63
  this.headers = connection.headers;
60
- this.operations = createCatalogWeftClient(CATALOG_OPERATION_NAMES, httpClientCatalogTransport(this.baseUrl, this.headers));
64
+ this.operations = createCatalogWeftClient(CLIENT_OPERATION_NAMES, httpClientOperationTransport(this.baseUrl, this.headers, CLIENT_REST_OPERATION_BINDINGS));
65
+ this.storage = createHttpClientStorage(this.baseUrl, this.headers);
61
66
  this.activity = {
67
+ listPending: (workflowId, listOptions) => listPendingAsyncActivitiesRequest(this, workflowId, listOptions),
62
68
  complete: (token, result) => completeAsyncActivityRequest(this, token, result),
63
69
  completeExceptionally: (token, error) => failAsyncActivityRequest(this, token, error)
64
70
  };
@@ -82,18 +88,7 @@ export class HttpClient {
82
88
  return new HttpHandle(response.id, this, response.outcome);
83
89
  }
84
90
  async schedule(type, input, spec, options) {
85
- const body = {
86
- type,
87
- input,
88
- ...scheduleSpecToWireFields(spec)
89
- };
90
- if (options?.id !== void 0)
91
- body.id = options.id;
92
- if (options?.overlap !== void 0)
93
- body.overlap = options.overlap;
94
- if (options?.backfill !== void 0)
95
- body.backfill = options.backfill;
96
- const response = await request(this.baseUrl, "/schedules", this.headers, {
91
+ const body = buildScheduleBody(type, input, spec, options), response = await request(this.baseUrl, "/schedules", this.headers, {
97
92
  method: "POST",
98
93
  body: JSON.stringify(body)
99
94
  });
@@ -133,8 +128,8 @@ export class HttpClient {
133
128
  async cancelSchedule(id) {
134
129
  return cancelScheduleRequest(this, id);
135
130
  }
136
- async updateSchedule(id, newSpec) {
137
- return updateScheduleRequest(this, id, newSpec);
131
+ async updateSchedule(id, newSpec, options) {
132
+ return updateScheduleRequest(this, id, newSpec, options);
138
133
  }
139
134
  async signal(id, nameOrDefinition, payload, options) {
140
135
  await signalWorkflowRequest(this, id, messageName(nameOrDefinition), payload, options);
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * @module client/http-operations
12
12
  */
13
- import type { CatalogTransport } from '../cli/operation-client-runtime.ts';
13
+ import type { CatalogTransport, ClientRestOperationBinding } from '../cli/operation-client-runtime.ts';
14
14
  /**
15
15
  * Build a {@link CatalogTransport} that dispatches catalog operations as
16
16
  * JSON-RPC requests to a remote Weft server at `${baseUrl}/jsonrpc`.
@@ -27,3 +27,5 @@ import type { CatalogTransport } from '../cli/operation-client-runtime.ts';
27
27
  * `HttpClientError` rather than a raw `SyntaxError`.
28
28
  */
29
29
  export declare function httpClientCatalogTransport(baseUrl: string, headers: Record<string, string>): CatalogTransport;
30
+ /** Route generated client operations over JSON-RPC or ordinary REST metadata. */
31
+ export declare function httpClientOperationTransport(baseUrl: string, headers: Record<string, string>, restBindings: Readonly<Record<string, ClientRestOperationBinding>>): CatalogTransport;
@@ -1,5 +1,5 @@
1
1
  import { isFaultCode } from "../core/fault-code.js";
2
- import { HttpClientError } from "./http-request.js";
2
+ import { HttpClientError, request } from "./http-request.js";
3
3
  function isJsonRpcFailure(value) {
4
4
  return typeof value === "object" && value !== null && "error" in value && typeof value.error === "object" && value.error !== null && "message" in value.error && typeof value.error.message === "string";
5
5
  }
@@ -40,3 +40,79 @@ export function httpClientCatalogTransport(baseUrl, headers) {
40
40
  throw new HttpClientError(response.status, `Invalid JSON-RPC response from ${endpoint}`);
41
41
  };
42
42
  }
43
+ function inputRecord(operationName, input) {
44
+ if (isRecord(input))
45
+ return input;
46
+ throw new HttpClientError(400, `Operation ${operationName} input must be an object.`);
47
+ }
48
+ function requiredString(operationName, field, value) {
49
+ if (typeof value === "string" && value.length > 0)
50
+ return value;
51
+ throw new HttpClientError(400, `Operation ${operationName} requires a non-empty string "${field}" field.`);
52
+ }
53
+ function restParameterValue(operationName, field, value) {
54
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
55
+ return String(value);
56
+ throw new HttpClientError(400, `Operation ${operationName} requires a string, number, or boolean "${field}" field.`);
57
+ }
58
+ function appendQueryValues(projection, operationName, field, queryParameter, value, repeating) {
59
+ if (repeating && Array.isArray(value)) {
60
+ for (const entry of value)
61
+ projection.searchParameters.append(queryParameter, restParameterValue(operationName, field, entry));
62
+ return;
63
+ }
64
+ projection.searchParameters.set(queryParameter, restParameterValue(operationName, field, value));
65
+ }
66
+ function projectRestInput(projection, operationName, field, source, value) {
67
+ if (source.kind === "path") {
68
+ const pathValue = requiredString(operationName, field, value);
69
+ projection.path = projection.path.replaceAll(`:${source.pathParam}`, encodeURIComponent(pathValue));
70
+ return;
71
+ }
72
+ if (value === void 0)
73
+ return;
74
+ if (source.kind === "query") {
75
+ appendQueryValues(projection, operationName, field, source.queryParam, value, source.repeating === !0);
76
+ return;
77
+ }
78
+ if (source.kind === "header") {
79
+ projection.requestHeaders.set(source.headerName, restParameterValue(operationName, field, value));
80
+ return;
81
+ }
82
+ if (source.kind === "body-field") {
83
+ projection.bodyFields[source.bodyField] = value;
84
+ return;
85
+ }
86
+ projection.directBody = value;
87
+ projection.directBodyMediaType = source.mediaType ?? "application/json";
88
+ }
89
+ async function callRestOperation(baseUrl, headers, operationName, binding, input) {
90
+ const fields = inputRecord(operationName, input), projection = {
91
+ path: binding.path,
92
+ searchParameters: new URLSearchParams,
93
+ requestHeaders: new Headers,
94
+ bodyFields: {},
95
+ directBody: void 0,
96
+ directBodyMediaType: void 0
97
+ };
98
+ for (const [field, source] of Object.entries(binding.inputSources))
99
+ projectRestInput(projection, operationName, field, source, fields[field]);
100
+ const query = projection.searchParameters.toString();
101
+ if (query.length > 0)
102
+ projection.path += `?${query}`;
103
+ const hasBodyFields = Object.keys(projection.bodyFields).length > 0, body = projection.directBody === void 0 ? hasBodyFields ? projection.bodyFields : void 0 : projection.directBody;
104
+ if (body !== void 0)
105
+ projection.requestHeaders.set("content-type", projection.directBodyMediaType ?? "application/json");
106
+ return request(baseUrl, projection.path, headers, {
107
+ method: binding.method,
108
+ ...[...projection.requestHeaders].length === 0 ? {} : { headers: projection.requestHeaders },
109
+ ...body === void 0 ? {} : { body: JSON.stringify(body) }
110
+ });
111
+ }
112
+ export function httpClientOperationTransport(baseUrl, headers, restBindings) {
113
+ const jsonRpc = httpClientCatalogTransport(baseUrl, headers);
114
+ return (operationName, input) => {
115
+ const restBinding = restBindings[operationName];
116
+ return restBinding === void 0 ? jsonRpc(operationName, input) : callRestOperation(baseUrl, headers, operationName, restBinding, input);
117
+ };
118
+ }
@@ -63,14 +63,14 @@ export declare function resolveHttpClientConnection(options: HttpClientOptions):
63
63
  /**
64
64
  * Error thrown when the server returns a non-2xx response.
65
65
  *
66
- * When the server sends a structured fault body (`{ error: { code, message } }`),
67
- * the wire fault `code` is surfaced as {@link HttpClientError.faultCode} and a
68
- * derived {@link HttpClientError.category} so callers can branch programmatically
69
- * instead of string-matching `message`. Both are `undefined` when the body is a
70
- * plain `{ error: string }` or carries no recognized code. The fault's typed
66
+ * When the server sends a fault body with a recognized coarse `code`, the wire
67
+ * value is surfaced as {@link HttpClientError.faultCode} with a derived
68
+ * {@link HttpClientError.category}, so callers can branch without
69
+ * string-matching `message`. Both are `undefined` for the production flat REST
70
+ * body, which carries no coarse code. The fault's typed
71
71
  * `data` payload (e.g. `InvalidParams`'s `issues`, `NotFound`/`Conflict`'s
72
72
  * `resource`/`identifier`) is surfaced verbatim as {@link HttpClientError.data}
73
- * when the body carries a structured `data` object; `undefined` otherwise —
73
+ * when the body carries an audited `data` object; `undefined` otherwise —
74
74
  * including for a masked `EngineFailure`, whose flat body carries no `data`.
75
75
  *
76
76
  * @example
@@ -82,7 +82,7 @@ export declare function resolveHttpClientConnection(options: HttpClientOptions):
82
82
  * await client.cancel('nonexistent-id');
83
83
  * } catch (err) {
84
84
  * if (err instanceof HttpClientError) {
85
- * if (err.faultCode === 'NotFound') {
85
+ * if (err.status === 404 && err.data?.['resource'] === 'workflow') {
86
86
  * // handle a missing resource specifically
87
87
  * } else if (err.category === 'resource') {
88
88
  * // back off on rate limits and capacity faults
@@ -116,7 +116,8 @@ export declare class HttpClientError extends WeftError<'HttpClientError'> {
116
116
  readonly weftCode?: WeftErrorCode | undefined;
117
117
  /**
118
118
  * The fault's wire `data` payload, when the response carried a structured
119
- * body (`{ error: { data } }` for REST, `error.data` for JSON-RPC). Shape is
119
+ * body (`{ error, data }` for production REST, nested `{ error: { data } }`
120
+ * for structured REST responses, or `error.data` for JSON-RPC). Shape is
120
121
  * fault-code-dependent — see {@link FaultCode} and the server's
121
122
  * `OperationFault` per-code `data` union for what each code carries (e.g.
122
123
  * `InvalidParams.data.issues`, `NotFound.data.resource`). `undefined` for
@@ -138,3 +139,9 @@ export declare class HttpClientError extends WeftError<'HttpClientError'> {
138
139
  });
139
140
  }
140
141
  export declare function request<T>(baseUrl: string, path: string, baseHeaders: Record<string, string>, options?: RequestInit): Promise<T>;
142
+ /**
143
+ * Execute a REST request with the canonical {@link HttpClientError} shaping
144
+ * while leaving the successful response body available to binary or streaming
145
+ * client surfaces.
146
+ */
147
+ export declare function requestResponse(baseUrl: string, path: string, baseHeaders: Record<string, string>, options?: RequestInit): Promise<Response | null>;
@@ -41,6 +41,14 @@ function buildRequestHeaders(baseHeaders, options) {
41
41
  function isFlatErrorBody(value) {
42
42
  return value !== null && typeof value === "object" && typeof value.error === "string";
43
43
  }
44
+ function parseFlatErrorBody(body) {
45
+ const weftCode = isWeftErrorCode(body.weftCode) ? body.weftCode : void 0, data = isRecord(body.data) ? body.data : void 0;
46
+ return {
47
+ message: body.error,
48
+ ...weftCode === void 0 ? {} : { weftCode },
49
+ ...data === void 0 ? {} : { data }
50
+ };
51
+ }
44
52
  function isStructuredErrorBody(value) {
45
53
  if (value === null || typeof value !== "object")
46
54
  return !1;
@@ -69,16 +77,22 @@ async function parseErrorBody(response) {
69
77
  base.data = data;
70
78
  return isFaultCode(code) ? { ...base, faultCode: code } : base;
71
79
  }
72
- if (isFlatErrorBody(body) && body.error) {
73
- const weftCode = isWeftErrorCode(body.weftCode) ? body.weftCode : void 0;
74
- return weftCode === void 0 ? { message: body.error } : { message: body.error, weftCode };
75
- }
80
+ if (isFlatErrorBody(body) && body.error)
81
+ return parseFlatErrorBody(body);
76
82
  return { message: response.statusText };
77
83
  } catch {
78
84
  return { message: response.statusText };
79
85
  }
80
86
  }
81
87
  export async function request(baseUrl, path, baseHeaders, options) {
88
+ const response = await requestResponse(baseUrl, path, baseHeaders, options);
89
+ if (response === null)
90
+ return null;
91
+ if (response.status === 204)
92
+ return;
93
+ return response.json();
94
+ }
95
+ export async function requestResponse(baseUrl, path, baseHeaders, options) {
82
96
  const headers = buildRequestHeaders(baseHeaders, options), response = await fetch(`${baseUrl}/v1${path}`, { ...options, headers });
83
97
  if (response.status === 404 && (!options?.method || options.method === "GET"))
84
98
  return null;
@@ -86,7 +100,5 @@ export async function request(baseUrl, path, baseHeaders, options) {
86
100
  const { message, faultCode, weftCode, data } = await parseErrorBody(response);
87
101
  throw new HttpClientError(response.status, message, { faultCode, weftCode, data });
88
102
  }
89
- if (response.status === 204)
90
- return;
91
- return response.json();
103
+ return response;
92
104
  }
@@ -22,9 +22,9 @@ import type { Engine } from '../core/engine.ts';
22
22
  *
23
23
  * The registry and trusted principal are constructed once and reused across
24
24
  * calls. Operations run with `transport: 'jsonRpcHttp'` so input/output
25
- * validation and unknown-key handling match the remote JSON-RPC path exactly.
25
+ * validation and unknown-key handling match the selected remote transport.
26
26
  * A failed dispatch throws with the fault message, mirroring the HTTP
27
27
  * transport's `throw new Error(result.error.message)` contract so both clients
28
28
  * surface operation faults the same way.
29
29
  */
30
- export declare function inProcessCatalogTransport(engine: Engine): CatalogTransport;
30
+ export declare function inProcessCatalogTransport(engine: Engine, restOperationNames?: ReadonlySet<string>): CatalogTransport;
@@ -1,13 +1,13 @@
1
1
  import { executeOperation } from "../server/operation-catalog.js";
2
2
  import { principalFromStdioLocal } from "../server/principal.js";
3
3
  import { createLiveOperationRegistry } from "../server/rest-bindings.js";
4
- export function inProcessCatalogTransport(engine) {
4
+ export function inProcessCatalogTransport(engine, restOperationNames = new Set) {
5
5
  const registry = createLiveOperationRegistry(), principal = principalFromStdioLocal();
6
6
  return async (operationName, input) => {
7
7
  const result = await executeOperation(operationName, input, {
8
8
  principal,
9
9
  engine,
10
- transport: "jsonRpcHttp",
10
+ transport: restOperationNames.has(operationName) ? "http-rest" : "jsonRpcHttp",
11
11
  registry
12
12
  });
13
13
  if (!result.ok)
@@ -7,8 +7,12 @@
7
7
  *
8
8
  * @module client/index
9
9
  */
10
- export { isWeftError, isWeftErrorCode, isWeftErrorLike, isWeftFault, WeftError, } from '../core/weft-error.ts';
10
+ export { WorkflowCancelledEvent, WorkflowCompletedEvent, WorkflowFailedEvent, WorkflowResumedEvent, WorkflowStartedEvent, WorkflowSuspendedEvent, WorkflowTeardownEvent, WorkflowTimedOutEvent, } from '../core/events/workflow-events.ts';
11
+ export { isFaultCode, type FaultCode } from '../core/fault-code.ts';
12
+ export type { PendingAsyncActivityInfo, PendingAsyncActivityListOptions, PendingAsyncActivityPage, } from '../core/types.ts';
13
+ export { WeftError, isWeftError, isWeftErrorCode, isWeftErrorLike, isWeftFault, } from '../core/weft-error.ts';
11
14
  export type { WeftErrorCode } from '../core/weft-error.ts';
15
+ export type { WeftClientStorage } from './client-storage.ts';
12
16
  export type { WorkflowEventStreamOptions, WorkflowEventTransport } from './event-stream-options.ts';
13
17
  export type { WorkflowEventTail } from './event-tail.ts';
14
18
  export { HttpClient } from './http-client.ts';
@@ -1,9 +1,20 @@
1
1
  export {
2
+ WorkflowCancelledEvent,
3
+ WorkflowCompletedEvent,
4
+ WorkflowFailedEvent,
5
+ WorkflowResumedEvent,
6
+ WorkflowStartedEvent,
7
+ WorkflowSuspendedEvent,
8
+ WorkflowTeardownEvent,
9
+ WorkflowTimedOutEvent
10
+ } from "../core/events/workflow-events.js";
11
+ export { isFaultCode } from "../core/fault-code.js";
12
+ export {
13
+ WeftError,
2
14
  isWeftError,
3
15
  isWeftErrorCode,
4
16
  isWeftErrorLike,
5
- isWeftFault,
6
- WeftError
17
+ isWeftFault
7
18
  } from "../core/weft-error.js";
8
19
  export { HttpClient } from "./http-client.js";
9
20
  export { HttpClientError } from "./http-request.js";
@@ -5,11 +5,12 @@
5
5
  *
6
6
  * @module client/interface
7
7
  */
8
- import type { CatalogOperationName, CatalogOperationTypes, WeftClient as CatalogOperations } from '../cli/generated/operation-client.generated.ts';
8
+ import type { ClientOperationName, ClientOperationTypes, ClientOperations } from '../cli/generated/operation-client.generated.ts';
9
9
  import type { StoredStreamChunk } from '../core/context.ts';
10
10
  import type { StartOrSignalOutcome as EngineStartOrSignalOutcome } from '../core/engine/handles.ts';
11
11
  import type { TypedEventTarget, WeftEventMap } from '../core/events.ts';
12
- import type { AttributeFilterKey, BulkCancelResult, BulkDeleteResult, BulkRetryFailedResult, BulkSignalResult, BulkTagResult, CoordinatedUpdateResult, ForkOptions, ListFilter, PaginatedResult, PurgeResult, QueryDefinition, RetentionOverview, ReviewListEntry, ReviewListFilter, ScheduleFilter, ScheduleOptions, ScheduleSpec, ScheduleSummary, SearchAttributeValue, SignalDefinition, SignalDeliveryOptions, StartOptions, StartOrSignalOptions, StartOrSignalSignal, SubmitReviewOptions, TypedListFilter, UpdateDefinition, WorkflowEvent, WorkflowInput, WorkflowOutput, WorkflowRegistry, WorkflowReplay, WorkflowState, WorkflowSummary, WorkflowTimelineEntry } from '../core/types.ts';
12
+ import type { AttributeFilterKey, BulkCancelResult, BulkDeleteResult, BulkRetryFailedResult, BulkSignalResult, BulkTagResult, CoordinatedUpdateResult, ForkOptions, ListFilter, PaginatedResult, PendingAsyncActivityListOptions, PendingAsyncActivityPage, PurgeResult, QueryDefinition, RetentionOverview, ReviewListEntry, ReviewListFilter, ScheduleUpdateOptions as ScheduleEdit, ScheduleFilter, ScheduleOptions, ScheduleSpec, ScheduleSummary, SearchAttributeValue, SignalDefinition, SignalDeliveryOptions, StartOptions, StartOrSignalOptions, StartOrSignalSignal, SubmitReviewOptions, TypedListFilter, UpdateDefinition, WorkflowEvent, WorkflowInput, WorkflowOutput, WorkflowRegistry, WorkflowReplay, WorkflowState, WorkflowSummary, WorkflowTimelineEntry } from '../core/types.ts';
13
+ import type { WeftClientStorage } from './client-storage.ts';
13
14
  import type { WorkflowEventTail } from './event-tail.ts';
14
15
  import type { KnownWorkflowName, UnknownNameWhenRegistryEmpty } from './workflow-name-typing.ts';
15
16
  /**
@@ -197,8 +198,8 @@ export interface ClientScheduleHandle extends Disposable {
197
198
  resume(): Promise<void>;
198
199
  /** Cancel this schedule. */
199
200
  cancel(): Promise<void>;
200
- /** Update the schedule's recurrence specification (cron string or interval spec). */
201
- update(newSpec: string | ScheduleSpec): Promise<void>;
201
+ /** Update the schedule cadence and optional mutable schedule settings. */
202
+ update(newSpec: string | ScheduleSpec, options?: ScheduleEdit): Promise<void>;
202
203
  /** Read the latest persisted summary for this schedule. */
203
204
  describe(): Promise<ScheduleSummary | null>;
204
205
  }
@@ -212,24 +213,21 @@ export type UpdateResult = {
212
213
  * Out-of-band ("async") activity completion surface, shared by every client.
213
214
  *
214
215
  * An activity that called `ActivityContext.completeAsync()` parks its workflow
215
- * until an external system resolves it by the durable task token announced on
216
- * the engine's `activity:async-pending` event. Library mode calls the engine
217
- * directly; server mode POSTs to `/v1/activities/{complete,fail}`. After a
218
- * restart, wait for recovery to settle first a completion racing `recoverAll()`
219
- * consumes the single-use token before re-adoption and strands the workflow. The
220
- * token is a deterministic identifier, not a secret (see `completeAsync`).
216
+ * until an external system resolves it by durable task token. `listPending()`
217
+ * queries the durable record after a missed live event or process restart.
218
+ * Library mode calls the engine directly; server mode uses the matching REST
219
+ * operations. The token is a deterministic identifier, not a secret.
221
220
  *
222
221
  * @example
223
222
  * ```ts
224
- * import { Engine, LocalClient, type WeftClientActivity } from '@lostgradient/weft';
225
- *
226
- * const activity: WeftClientActivity = new LocalClient(new Engine()).activity;
227
- * // `token` comes from the engine's `activity:async-pending` event:
228
- * // await activity.complete(token, { approved: true });
229
- * void activity;
223
+ * import type { WeftClientActivity } from '@lostgradient/weft/client';
224
+ * declare const activity: WeftClientActivity;
225
+ * void activity.listPending('order-1');
230
226
  * ```
231
227
  */
232
228
  export interface WeftClientActivity {
229
+ /** List a bounded page of durable activities awaiting completion for one workflow. */
230
+ listPending(workflowId: string, options?: PendingAsyncActivityListOptions): Promise<PendingAsyncActivityPage>;
233
231
  /** Complete a deferred activity by token, resuming its workflow with `result` (optional; omitted/`undefined` resumes with `undefined`). */
234
232
  complete(token: string, result?: unknown): Promise<void>;
235
233
  /** Fail a deferred activity by token; the error is thrown into its workflow. */
@@ -259,7 +257,6 @@ export interface WeftClient {
259
257
  * returned handle's `result()` to its output type. Without augmentation the
260
258
  * permissive string-name overload applies, so the client stays usable with
261
259
  * plain string names and no hard dependency on codegen.
262
- *
263
260
  * Pass `options.idempotencyKey` for at-most-once starts: a repeated key returns
264
261
  * a handle to the existing run rather than starting a second. Conflicts (a
265
262
  * duplicate `id`, or a key whose run was purged) are transport-dependent:
@@ -339,8 +336,8 @@ export interface WeftClient {
339
336
  resumeSchedule(id: string): Promise<void>;
340
337
  /** Cancel a recurring schedule. */
341
338
  cancelSchedule(id: string): Promise<void>;
342
- /** Update a recurring schedule's recurrence specification (cron string or interval spec). */
343
- updateSchedule(id: string, newSpec: string | ScheduleSpec): Promise<void>;
339
+ /** Update a recurring schedule's cadence and optional mutable schedule settings. */
340
+ updateSchedule(id: string, newSpec: string | ScheduleSpec, options?: ScheduleEdit): Promise<void>;
344
341
  /** Send a named signal to a workflow. */
345
342
  signal(id: string, name: SignalDefinition): Promise<void>;
346
343
  signal<TInput>(id: string, name: SignalDefinition<TInput>, payload: TInput, options?: SignalDeliveryOptions): Promise<void>;
@@ -433,11 +430,12 @@ export interface WeftClient {
433
430
  /**
434
431
  * Typed low-level accessor for the full operation catalog.
435
432
  *
436
- * Every catalog operation is reachable as `client.operations['weft.<op>']`,
437
- * including server operations the ergonomic surface does not curate (workers,
438
- * task queues, task diagnostics, system metrics/registry, checkpoints). New
439
- * catalog operations appear here automatically when the snapshot regenerates,
440
- * so the client never drifts behind the server.
433
+ * Every unary JSON-RPC operation and ordinary schema-shaped REST-only
434
+ * operation is reachable as `client.operations['weft.<op>']`, including
435
+ * server operations the ergonomic surface does not curate (workers, task
436
+ * queues, task diagnostics, system lease/metrics/registry, checkpoints). Binary
437
+ * and streaming raw-storage routes use {@link storage} instead. New compatible
438
+ * operations appear here when the snapshot regenerates.
441
439
  *
442
440
  * @example
443
441
  * ```ts
@@ -450,11 +448,13 @@ export interface WeftClient {
450
448
  * void metrics;
451
449
  * ```
452
450
  */
453
- readonly operations: CatalogOperations;
451
+ readonly operations: ClientOperations;
452
+ /** Raw storage administration with byte values and streaming scans. */
453
+ readonly storage: WeftClientStorage;
454
454
  /**
455
455
  * Invoke a single catalog operation by name, with its input and output typed
456
456
  * from the generated catalog. Equivalent to `client.operations[name](input)`
457
457
  * but ergonomic when the operation name is known dynamically.
458
458
  */
459
- call<Name extends CatalogOperationName>(name: Name, input: CatalogOperationTypes[Name]['input']): Promise<CatalogOperationTypes[Name]['output']>;
459
+ call<Name extends ClientOperationName>(name: Name, input: ClientOperationTypes[Name]['input']): Promise<ClientOperationTypes[Name]['output']>;
460
460
  }