@lostgradient/weft 0.12.0 → 0.14.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 +508 -12
- package/dist/cli/generated/operation-client.generated.d.ts +118 -10
- package/dist/cli/generated/operation-client.generated.js +74 -1
- package/dist/cli/help-text.d.ts +3 -3
- package/dist/cli/help-text.js +4 -4
- package/dist/cli/operation-catalog-snapshot.d.ts +12 -3
- package/dist/cli/operation-catalog-snapshot.js +14 -5
- package/dist/cli/operation-client-runtime.d.ts +29 -0
- package/dist/cli/schedule.js +1 -3
- package/dist/cli/serve-registrations.d.ts +3 -3
- package/dist/cli/serve-registrations.js +2 -2
- package/dist/cli/shutdown.d.ts +11 -0
- package/dist/cli/shutdown.js +25 -0
- package/dist/cli/validate.d.ts +1 -1
- package/dist/cli/version-check.d.ts +1 -1
- package/dist/cli/version-check.js +1 -1
- package/dist/cli-main.js +10 -29
- 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 +82 -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 +77 -1
- package/dist/client/http-request.d.ts +20 -14
- package/dist/client/http-request.js +21 -31
- 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 +5 -1
- package/dist/client/index.js +13 -2
- 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/core/bulk-workflow-filter.d.ts +2 -1
- package/dist/core/bulk-workflow-filter.js +5 -1
- package/dist/core/context/parallel-operations.d.ts +0 -2
- package/dist/core/context/parallel-operations.js +0 -7
- 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-checkpoint-persistence.d.ts +2 -0
- package/dist/core/engine/callback-checkpoint-persistence.js +6 -3
- 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/callback-creators.js +4 -22
- package/dist/core/engine/checkpoint-io.d.ts +1 -1
- 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 +26 -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 +11 -8
- 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/operations-coordination.d.ts +1 -12
- package/dist/core/engine/operations-coordination.js +58 -11
- package/dist/core/engine/operations-speculate.d.ts +1 -1
- package/dist/core/engine/operations-speculate.js +19 -5
- package/dist/core/engine/parallel-dispatch.d.ts +1 -1
- package/dist/core/engine/parallel-dispatch.js +1 -1
- package/dist/core/engine/registration.js +14 -0
- package/dist/core/engine/review-list-entries.d.ts +1 -1
- package/dist/core/engine/review-list-entries.js +6 -30
- 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 +91 -4
- package/dist/core/review/index.js +29 -0
- package/dist/core/types/activity.d.ts +52 -5
- package/dist/core/types/bulk.d.ts +1 -0
- 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/diagnostics/validate.d.ts +9 -30
- package/dist/diagnostics/validate.js +83 -21
- package/dist/diagnostics/version-check.d.ts +2 -2
- package/dist/http.js +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/indexeddb.js +1 -1
- package/dist/server/access-policy-metadata.d.ts +92 -0
- package/dist/server/access-policy-metadata.js +78 -0
- package/dist/server/fault-to-http.d.ts +3 -7
- package/dist/server/fault-to-http.js +2 -34
- package/dist/server/handler/index.js +1 -1
- package/dist/server/handler/route-dispatch.d.ts +10 -3
- package/dist/server/handler/route-dispatch.js +19 -4
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/interactive-operations.js +2 -0
- package/dist/server/openapi-error-responses.js +41 -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-catalog/index.d.ts +1 -1
- package/dist/server/operation-catalog/raise-fault.d.ts +2 -1
- package/dist/server/operation-catalog/types.d.ts +2 -1
- package/dist/server/operation-fault.d.ts +22 -8
- package/dist/server/operation-fault.js +65 -13
- package/dist/server/operation-registry.d.ts +1 -1
- 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-reviews.js +2 -19
- 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 +1 -9
- package/dist/server/operations/single-workflow-control-operation.d.ts +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/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/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/task-queue.d.ts +7 -5
- package/dist/storage/bounded-ndjson-response.d.ts +5 -0
- package/dist/storage/bounded-ndjson-response.js +33 -0
- package/dist/storage/capabilities.d.ts +1 -1
- package/dist/storage/cloudflare-value-codec.d.ts +5 -3
- package/dist/storage/cloudflare-value-codec.js +1 -1
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/http.js +5 -37
- package/dist/storage/index.d.ts +7 -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.d.ts +3 -16
- package/dist/storage/neon.js +4 -4
- 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/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommandOutput } from './types.ts';
|
|
2
|
-
/** Checks stored workflow history against the current workflow
|
|
2
|
+
/** Checks stored workflow history against the current workflow definitions. */
|
|
3
3
|
export declare function executeVersionCheck(options: {
|
|
4
4
|
database: string;
|
|
5
5
|
workflows: string;
|
|
@@ -8,7 +8,7 @@ export async function executeVersionCheck(options) {
|
|
|
8
8
|
};
|
|
9
9
|
const { runVersionCheck } = await import("../diagnostics/version-check.js"), { formatVersionCheckReport } = await import("../diagnostics/format.js"), { BunSQLiteStorage } = await import("../storage/bun-sql.js"), storage = new BunSQLiteStorage(options.database);
|
|
10
10
|
try {
|
|
11
|
-
const
|
|
11
|
+
const workflowsPath = resolve(process.cwd(), options.workflows), { loadRegistrationsFromModule } = await import("../diagnostics/validate.js"), { registrations } = await loadRegistrationsFromModule(workflowsPath), report = await runVersionCheck(storage, registrations);
|
|
12
12
|
return { stdout: options.json ? JSON.stringify(report, null, 2) : formatVersionCheckReport(report), exitCode: 0 };
|
|
13
13
|
} finally {
|
|
14
14
|
storage[Symbol.dispose]();
|
package/dist/cli-main.js
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
WORKFLOW_HELP_TEXT,
|
|
33
33
|
writeRunLockfile
|
|
34
34
|
} from "./cli/index.js";
|
|
35
|
+
import { CLI_SHUTDOWN_SIGNALS, createCliShutdownHandler } from "./cli/shutdown.js";
|
|
35
36
|
import { Engine } from "./core/engine.js";
|
|
36
37
|
import { serve } from "./server/index.js";
|
|
37
38
|
const parsedArguments = (() => {
|
|
@@ -67,36 +68,16 @@ if (parsedArguments.command === "version") {
|
|
|
67
68
|
console.log(`Health check: ${new URL("/v1/health", server.url).href}`);
|
|
68
69
|
console.log(`Storage: ${parsedArguments.storage}`);
|
|
69
70
|
console.log(`Database: ${parsedArguments.database}`);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
console.error("[weft] Failed to remove run lockfile:", error);
|
|
78
|
-
}
|
|
79
|
-
storage[Symbol.dispose]();
|
|
80
|
-
process.exit(0);
|
|
81
|
-
}).catch((error) => {
|
|
82
|
-
console.error("[weft] Shutdown error:", error);
|
|
83
|
-
process.exit(1);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
process.on("SIGTERM", () => {
|
|
87
|
-
server.stop().then(async () => {
|
|
88
|
-
try {
|
|
89
|
-
await removeRunLockfile(server.url);
|
|
90
|
-
} catch (error) {
|
|
91
|
-
console.error("[weft] Failed to remove run lockfile:", error);
|
|
92
|
-
}
|
|
93
|
-
storage[Symbol.dispose]();
|
|
94
|
-
process.exit(0);
|
|
95
|
-
}).catch((error) => {
|
|
96
|
-
console.error("[weft] Shutdown error:", error);
|
|
97
|
-
process.exit(1);
|
|
98
|
-
});
|
|
71
|
+
const shutdown = createCliShutdownHandler({
|
|
72
|
+
stopServer: () => server.stop(),
|
|
73
|
+
removeRunLockfile: () => removeRunLockfile(server.url),
|
|
74
|
+
disposeStorage: () => storage[Symbol.dispose](),
|
|
75
|
+
log: (message) => console.log(message),
|
|
76
|
+
reportError: (message, error) => console.error(message, error),
|
|
77
|
+
exit: (code) => process.exit(code)
|
|
99
78
|
});
|
|
79
|
+
for (const signal of CLI_SHUTDOWN_SIGNALS)
|
|
80
|
+
process.on(signal, () => void shutdown(signal));
|
|
100
81
|
} else if (parsedArguments.command === "doctor") {
|
|
101
82
|
if (parsedArguments.help) {
|
|
102
83
|
console.log(DOCTOR_HELP_TEXT);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type BatchOperation, type ConditionalBatchCondition, type ScanOptions, type Storage } from '../storage/interface.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Byte-oriented raw storage surface shared by local and HTTP clients.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { Engine, LocalClient, MemoryStorage, type WeftClientStorage } from '@lostgradient/weft';
|
|
8
|
+
*
|
|
9
|
+
* await using engine = new Engine({ storage: new MemoryStorage() });
|
|
10
|
+
* const client = new LocalClient(engine);
|
|
11
|
+
* const storage: WeftClientStorage = client.storage;
|
|
12
|
+
* await storage.put('example:key', new TextEncoder().encode('value'));
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export interface WeftClientStorage {
|
|
16
|
+
get(key: string): Promise<Uint8Array | null>;
|
|
17
|
+
put(key: string, value: Uint8Array): Promise<void>;
|
|
18
|
+
delete(key: string): Promise<void>;
|
|
19
|
+
scan(prefix: string, options?: ScanOptions): AsyncIterable<[string, Uint8Array]>;
|
|
20
|
+
batch(operations: BatchOperation[]): Promise<void>;
|
|
21
|
+
conditionalBatch(conditions: ConditionalBatchCondition[], operations: BatchOperation[]): Promise<boolean>;
|
|
22
|
+
}
|
|
23
|
+
/** Adapt an engine-owned storage backend without exposing adapter-only methods. */
|
|
24
|
+
export declare function createLocalClientStorage(storage: Storage): WeftClientStorage;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
storageBatch,
|
|
3
|
+
storageConditionalBatch
|
|
4
|
+
} from "../storage/interface.js";
|
|
5
|
+
export function createLocalClientStorage(storage) {
|
|
6
|
+
return {
|
|
7
|
+
get: (key) => storage.get(key),
|
|
8
|
+
put: (key, value) => storage.put(key, value),
|
|
9
|
+
delete: (key) => storage.delete(key),
|
|
10
|
+
scan: (prefix, options) => storage.scan(prefix, options),
|
|
11
|
+
batch: (operations) => storageBatch(storage, operations),
|
|
12
|
+
conditionalBatch: (conditions, operations) => storageConditionalBatch(storage, conditions, operations)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { WeftEventMap } from '../core/events.ts';
|
|
2
|
-
import type { QueryDefinition, ScheduleSpec, ScheduleSummary, SearchAttributeValue, SignalDefinition, SignalDeliveryOptions, UpdateDefinition } from '../core/types.ts';
|
|
2
|
+
import type { QueryDefinition, ScheduleSpec, ScheduleSummary, ScheduleUpdateOptions, SearchAttributeValue, SignalDefinition, SignalDeliveryOptions, UpdateDefinition } from '../core/types.ts';
|
|
3
3
|
import type { WorkflowEventTail } from './event-tail.ts';
|
|
4
4
|
import type { ClientHandle, ClientScheduleHandle, StartOrSignalOutcome } from './interface.ts';
|
|
5
5
|
export interface WorkflowHandleDelegationClient {
|
|
@@ -62,7 +62,7 @@ export interface ScheduleHandleDelegationClient {
|
|
|
62
62
|
pauseSchedule(id: string): Promise<void>;
|
|
63
63
|
resumeSchedule(id: string): Promise<void>;
|
|
64
64
|
cancelSchedule(id: string): Promise<void>;
|
|
65
|
-
updateSchedule(id: string, newSpec: string | ScheduleSpec): Promise<void>;
|
|
65
|
+
updateSchedule(id: string, newSpec: string | ScheduleSpec, options?: ScheduleUpdateOptions): Promise<void>;
|
|
66
66
|
getSchedule(id: string): Promise<ScheduleSummary | null>;
|
|
67
67
|
}
|
|
68
68
|
export declare abstract class ScheduleHandleDelegation<TClient extends ScheduleHandleDelegationClient = ScheduleHandleDelegationClient> implements ClientScheduleHandle {
|
|
@@ -72,7 +72,7 @@ export declare abstract class ScheduleHandleDelegation<TClient extends ScheduleH
|
|
|
72
72
|
pause(): Promise<void>;
|
|
73
73
|
resume(): Promise<void>;
|
|
74
74
|
cancel(): Promise<void>;
|
|
75
|
-
update(newSpec: string | ScheduleSpec): Promise<void>;
|
|
75
|
+
update(newSpec: string | ScheduleSpec, options?: ScheduleUpdateOptions): Promise<void>;
|
|
76
76
|
describe(): Promise<ScheduleSummary | null>;
|
|
77
77
|
abstract [Symbol.dispose](): void;
|
|
78
78
|
}
|
|
@@ -65,8 +65,8 @@ export class ScheduleHandleDelegation {
|
|
|
65
65
|
async cancel() {
|
|
66
66
|
return this.client.cancelSchedule(this.id);
|
|
67
67
|
}
|
|
68
|
-
async update(newSpec) {
|
|
69
|
-
return this.client.updateSchedule(this.id, newSpec);
|
|
68
|
+
async update(newSpec, options) {
|
|
69
|
+
return this.client.updateSchedule(this.id, newSpec, options);
|
|
70
70
|
}
|
|
71
71
|
async describe() {
|
|
72
72
|
return this.client.getSchedule(this.id);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StoredStreamChunk } from '../core/context.ts';
|
|
2
|
-
import type { BulkCancelResult, BulkDeleteResult, BulkRetryFailedResult, BulkSignalResult, BulkTagResult, CoordinatedUpdateResult, ForkOptions, ListFilter, PurgeResult, RetentionOverview, ReviewListEntry, ReviewListFilter, ScheduleSpec, ScheduleSummary, SearchAttributeValue, SignalDeliveryOptions, SubmitReviewOptions, WorkflowReplay, WorkflowState, WorkflowTimelineEntry } from '../core/types.ts';
|
|
2
|
+
import type { BulkCancelResult, BulkDeleteResult, BulkRetryFailedResult, BulkSignalResult, BulkTagResult, CoordinatedUpdateResult, ForkOptions, ListFilter, PendingAsyncActivityListOptions, PendingAsyncActivityPage, PurgeResult, RetentionOverview, ReviewListEntry, ReviewListFilter, ScheduleSpec, ScheduleSummary, ScheduleUpdateOptions, SearchAttributeValue, SignalDeliveryOptions, SubmitReviewOptions, WorkflowReplay, WorkflowState, WorkflowTimelineEntry } from '../core/types.ts';
|
|
3
3
|
import type { UpdateResult } from './interface.ts';
|
|
4
4
|
export type HttpClientRequestContext = {
|
|
5
5
|
readonly baseUrl: string;
|
|
@@ -37,6 +37,8 @@ export declare function signalWorkflowRequest(context: HttpClientRequestContext,
|
|
|
37
37
|
* workflow with `result`. Mirrors `LocalClient.activity.complete` over HTTP.
|
|
38
38
|
*/
|
|
39
39
|
export declare function completeAsyncActivityRequest(context: HttpClientRequestContext, token: string, result?: unknown): Promise<void>;
|
|
40
|
+
/** List durable async activities awaiting completion for one workflow. */
|
|
41
|
+
export declare function listPendingAsyncActivitiesRequest(context: HttpClientRequestContext, workflowId: string, options?: PendingAsyncActivityListOptions): Promise<PendingAsyncActivityPage>;
|
|
40
42
|
/**
|
|
41
43
|
* Fail a deferred ("async") activity by task token. A live `Error` cannot cross
|
|
42
44
|
* the wire, so the error is reduced to `message` + `name` — exactly the fields
|
|
@@ -59,8 +61,8 @@ export declare function pauseScheduleRequest(context: HttpClientRequestContext,
|
|
|
59
61
|
export declare function resumeScheduleRequest(context: HttpClientRequestContext, id: string): Promise<void>;
|
|
60
62
|
/** Cancel a recurring schedule (`DELETE /v1/schedules/:id`). */
|
|
61
63
|
export declare function cancelScheduleRequest(context: HttpClientRequestContext, id: string): Promise<void>;
|
|
62
|
-
/** Update a schedule's
|
|
63
|
-
export declare function updateScheduleRequest(context: HttpClientRequestContext, id: string, newSpec: string | ScheduleSpec): Promise<void>;
|
|
64
|
+
/** Update a schedule's cadence and mutable options (`PATCH /v1/schedules/:id`). */
|
|
65
|
+
export declare function updateScheduleRequest(context: HttpClientRequestContext, id: string, newSpec: string | ScheduleSpec, options?: ScheduleUpdateOptions): Promise<void>;
|
|
64
66
|
/**
|
|
65
67
|
* Query a named read-only accessor on a workflow. A no-input query is a GET;
|
|
66
68
|
* an input payload is sent as a POST body.
|
|
@@ -139,6 +139,15 @@ export async function completeAsyncActivityRequest(context, token, result) {
|
|
|
139
139
|
body: JSON.stringify({ token, result })
|
|
140
140
|
});
|
|
141
141
|
}
|
|
142
|
+
export async function listPendingAsyncActivitiesRequest(context, workflowId, options) {
|
|
143
|
+
const search = new URLSearchParams;
|
|
144
|
+
if (options?.limit !== void 0)
|
|
145
|
+
search.set("limit", String(options.limit));
|
|
146
|
+
if (options?.cursor !== void 0)
|
|
147
|
+
search.set("cursor", options.cursor);
|
|
148
|
+
const query = search.size > 0 ? `?${search.toString()}` : "";
|
|
149
|
+
return request(context.baseUrl, `/workflows/${encodeURIComponent(workflowId)}/pending-async-activities${query}`, context.headers);
|
|
150
|
+
}
|
|
142
151
|
export async function failAsyncActivityRequest(context, token, error) {
|
|
143
152
|
const reduced = { message: error instanceof Error ? error.message : String(error) };
|
|
144
153
|
if (error instanceof Error)
|
|
@@ -176,10 +185,19 @@ export function cancelScheduleRequest(context, id) {
|
|
|
176
185
|
method: "DELETE"
|
|
177
186
|
});
|
|
178
187
|
}
|
|
179
|
-
export function updateScheduleRequest(context, id, newSpec) {
|
|
188
|
+
export function updateScheduleRequest(context, id, newSpec, options) {
|
|
189
|
+
const body = scheduleSpecToWireFields(newSpec);
|
|
190
|
+
if (options?.description !== void 0)
|
|
191
|
+
body.description = options.description;
|
|
192
|
+
if (options?.overlap !== void 0)
|
|
193
|
+
body.overlap = options.overlap;
|
|
194
|
+
if (options?.backfill !== void 0)
|
|
195
|
+
body.backfill = options.backfill;
|
|
196
|
+
if (options?.jitter !== void 0)
|
|
197
|
+
body.jitter = options.jitter;
|
|
180
198
|
return request(context.baseUrl, `/schedules/${encodeURIComponent(id)}`, context.headers, {
|
|
181
199
|
method: "PATCH",
|
|
182
|
-
body: JSON.stringify(
|
|
200
|
+
body: JSON.stringify(body)
|
|
183
201
|
});
|
|
184
202
|
}
|
|
185
203
|
export async function queryWorkflowRequest(context, id, name, input) {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { readBoundedNdjsonResponse } from "../storage/bounded-ndjson-response.js";
|
|
2
|
+
import { decodeBase64ToBytes, encodeBytesToBase64, isRecord } from "../storage/byte-encoding.js";
|
|
3
|
+
import {
|
|
4
|
+
assertStorageBatchOperationCount
|
|
5
|
+
} from "../storage/interface.js";
|
|
6
|
+
import { request, requestResponse } from "./http-request.js";
|
|
7
|
+
const MAX_SCAN_RESPONSE_BYTES = 67108864;
|
|
8
|
+
function encodeOperation(operation) {
|
|
9
|
+
return operation.type === "put" ? { type: "put", key: operation.key, value: encodeBytesToBase64(operation.value) } : { type: "delete", key: operation.key };
|
|
10
|
+
}
|
|
11
|
+
function scanPath(prefix, options) {
|
|
12
|
+
const parameters = new URLSearchParams({ prefix });
|
|
13
|
+
for (const [name, value] of Object.entries(options))
|
|
14
|
+
if (value !== void 0)
|
|
15
|
+
parameters.set(name, String(value));
|
|
16
|
+
return `/storage?${parameters.toString()}`;
|
|
17
|
+
}
|
|
18
|
+
function scanEntry(value) {
|
|
19
|
+
if (!isRecord(value) || typeof value.key !== "string" || typeof value.value !== "string")
|
|
20
|
+
throw Error("HttpClient storage scan response contained an invalid NDJSON entry.");
|
|
21
|
+
return [value.key, decodeBase64ToBytes(value.value)];
|
|
22
|
+
}
|
|
23
|
+
async function* scanResponse(response) {
|
|
24
|
+
for await (const line of readBoundedNdjsonResponse(response, {
|
|
25
|
+
maximumBytes: MAX_SCAN_RESPONSE_BYTES,
|
|
26
|
+
sizeLimitError: () => Error("HttpClient storage scan response exceeded the maximum allowed size.")
|
|
27
|
+
}))
|
|
28
|
+
if (line.trim().length > 0)
|
|
29
|
+
yield scanEntry(JSON.parse(line));
|
|
30
|
+
}
|
|
31
|
+
export function createHttpClientStorage(baseUrl, headers) {
|
|
32
|
+
return {
|
|
33
|
+
async get(key) {
|
|
34
|
+
const response = await requestResponse(baseUrl, `/storage/${encodeURIComponent(key)}`, headers, { method: "GET" });
|
|
35
|
+
return response === null ? null : new Uint8Array(await response.arrayBuffer());
|
|
36
|
+
},
|
|
37
|
+
async put(key, value) {
|
|
38
|
+
await requestResponse(baseUrl, `/storage/${encodeURIComponent(key)}`, headers, {
|
|
39
|
+
method: "PUT",
|
|
40
|
+
headers: { "content-type": "application/octet-stream" },
|
|
41
|
+
body: new Blob([value])
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
async delete(key) {
|
|
45
|
+
await requestResponse(baseUrl, `/storage/${encodeURIComponent(key)}`, headers, {
|
|
46
|
+
method: "DELETE"
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
async* scan(prefix, options = {}) {
|
|
50
|
+
const response = await requestResponse(baseUrl, scanPath(prefix, options), headers, {
|
|
51
|
+
method: "GET",
|
|
52
|
+
headers: { accept: "application/x-ndjson" }
|
|
53
|
+
});
|
|
54
|
+
if (response !== null)
|
|
55
|
+
yield* scanResponse(response);
|
|
56
|
+
},
|
|
57
|
+
async batch(operations) {
|
|
58
|
+
assertStorageBatchOperationCount("batch operations", operations.length);
|
|
59
|
+
await request(baseUrl, "/storage/-/batch", headers, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
body: JSON.stringify({ operations: operations.map(encodeOperation) })
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
async conditionalBatch(conditions, operations) {
|
|
65
|
+
assertStorageBatchOperationCount("conditionalBatch conditions", conditions.length);
|
|
66
|
+
assertStorageBatchOperationCount("conditionalBatch operations", operations.length);
|
|
67
|
+
const result = await request(baseUrl, "/storage/-/conditional-batch", headers, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
body: JSON.stringify({
|
|
70
|
+
conditions: conditions.map((condition) => ({
|
|
71
|
+
key: condition.key,
|
|
72
|
+
expectedValue: condition.expectedValue === null ? null : encodeBytesToBase64(condition.expectedValue)
|
|
73
|
+
})),
|
|
74
|
+
operations: operations.map(encodeOperation)
|
|
75
|
+
})
|
|
76
|
+
});
|
|
77
|
+
if (!isRecord(result) || typeof result.applied !== "boolean")
|
|
78
|
+
throw Error('HttpClient storage conditional batch response must include a boolean "applied" field.');
|
|
79
|
+
return result.applied;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { type
|
|
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
|
|
53
|
-
readonly operations:
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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(
|
|
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
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
66
|
+
* When a transport response carries a recognized coarse fault 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
|
|
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.
|
|
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
|
|
@@ -96,8 +96,8 @@ export declare class HttpClientError extends WeftError<'HttpClientError'> {
|
|
|
96
96
|
/** HTTP status code of the failed response. */
|
|
97
97
|
readonly status: number;
|
|
98
98
|
/**
|
|
99
|
-
* The server's stable wire fault code, when the response carried a
|
|
100
|
-
*
|
|
99
|
+
* The server's stable wire fault code, when the transport response carried a
|
|
100
|
+
* recognized code. `undefined` for flat REST error bodies or unrecognized codes.
|
|
101
101
|
*/
|
|
102
102
|
readonly faultCode?: FaultCode | undefined;
|
|
103
103
|
/**
|
|
@@ -107,17 +107,17 @@ export declare class HttpClientError extends WeftError<'HttpClientError'> {
|
|
|
107
107
|
readonly category?: FailureCategory | undefined;
|
|
108
108
|
/**
|
|
109
109
|
* The fine-grained originating public {@link WeftErrorCode} the server
|
|
110
|
-
* attached (e.g. `WorkflowNotFoundError`), when the
|
|
111
|
-
*
|
|
110
|
+
* attached (e.g. `WorkflowNotFoundError`), when the response carried one.
|
|
111
|
+
* This is what makes cross-transport branching work: a producer can call
|
|
112
112
|
* `isWeftFault(error, 'WorkflowNotFoundError')` and have it match over HTTP
|
|
113
113
|
* exactly as it matches the in-process typed error. `undefined` when the fault
|
|
114
|
-
* carried only the coarse {@link faultCode} (most faults) or no
|
|
114
|
+
* carried only the coarse {@link faultCode} (most faults) or no recognized code.
|
|
115
115
|
*/
|
|
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
|
|
120
|
-
* fault-code-dependent — see {@link FaultCode} and the server's
|
|
119
|
+
* body (`{ error, data }` for production REST or `error.data` for JSON-RPC).
|
|
120
|
+
* Shape is fault-code-dependent — see {@link FaultCode} and the server's
|
|
121
121
|
* `OperationFault` per-code `data` union for what each code carries (e.g.
|
|
122
122
|
* `InvalidParams.data.issues`, `NotFound.data.resource`). `undefined` for
|
|
123
123
|
* plain-string error bodies, bodies with no `data` field, or a `data` field
|
|
@@ -138,3 +138,9 @@ export declare class HttpClientError extends WeftError<'HttpClientError'> {
|
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
export declare function request<T>(baseUrl: string, path: string, baseHeaders: Record<string, string>, options?: RequestInit): Promise<T>;
|
|
141
|
+
/**
|
|
142
|
+
* Execute a REST request with the canonical {@link HttpClientError} shaping
|
|
143
|
+
* while leaving the successful response body available to binary or streaming
|
|
144
|
+
* client surfaces.
|
|
145
|
+
*/
|
|
146
|
+
export declare function requestResponse(baseUrl: string, path: string, baseHeaders: Record<string, string>, options?: RequestInit): Promise<Response | null>;
|