@superdurable/dex 0.5.0 → 0.7.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 +25 -6
- package/dist/src/client.d.ts +14 -102
- package/dist/src/client.js +76 -139
- package/dist/src/client.js.map +1 -1
- package/dist/src/errors.d.ts +5 -0
- package/dist/src/errors.js +5 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/gen/dex.d.ts +11 -3
- package/dist/src/gen/dex.js +1 -0
- package/dist/src/gen/dex.js.map +1 -1
- package/dist/src/grpc-status.js +25 -4
- package/dist/src/grpc-status.js.map +1 -1
- package/dist/src/options.d.ts +14 -0
- package/dist/src/options.js.map +1 -1
- package/native/linux-aarch64/dex_blob_cache_node.node +0 -0
- package/native/linux-x86_64/dex_blob_cache_node.node +0 -0
- package/native/macos-aarch64/dex_blob_cache_node.node +0 -0
- package/native/macos-x86_64/dex_blob_cache_node.node +0 -0
- package/native/windows-x86_64/dex_blob_cache_node.node +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Dex SDK for TypeScript
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Flow state I/O
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Applications read and write Flow state through typed RPCs. The Client does not
|
|
6
|
+
expose direct Attribute reads or writes, Channel publication, or pending-message
|
|
7
|
+
mutation. This keeps each external state transition behind a Flow-owned method.
|
|
8
8
|
|
|
9
9
|
An RPC can stage `channel.delete(context, messageId)`. Set the decorator option
|
|
10
10
|
`isTransactional: true` when a missing ID must abort all other RPC writes.
|
|
@@ -221,6 +221,17 @@ and `getAllInstanceKeys` include buffered sets and deletes. The matching
|
|
|
221
221
|
instances. Keys are decoded and sorted. Use
|
|
222
222
|
`forceCompleteIfChannelsEmpty(...)` for conditional completion.
|
|
223
223
|
|
|
224
|
+
Request IDs are optional for both durable waits. When omitted, the server
|
|
225
|
+
derives a namespaced stable ID from the Step execution or Attribute condition,
|
|
226
|
+
such as `wait-for-attribute:myInt>10`. Reuse an override only for the same
|
|
227
|
+
logical wait. The Client automatically reattaches transport long polls. If an
|
|
228
|
+
earlier Update with that ID exhausted its handler budget, the server appends an
|
|
229
|
+
increasing `-N` suffix and starts a new Update. `maximumWaitTimeMs` is optional
|
|
230
|
+
and is the total handler budget across reattachments; omit it or use zero to
|
|
231
|
+
wait indefinitely. A positive budget expiry throws `WaitHandlerTimeoutError`.
|
|
232
|
+
An abandoned infinite wait remains accepted and counts against Temporal's
|
|
233
|
+
in-flight Update limit until it completes or the Flow closes.
|
|
234
|
+
|
|
224
235
|
### Async handlers
|
|
225
236
|
|
|
226
237
|
`Step.execute`, `Step.waitFor`, and RPC methods may be `async` and return a
|
|
@@ -299,6 +310,14 @@ must be non-empty, may contain `#`, and may repeat; every write appends a new
|
|
|
299
310
|
message. `Client.readStream` returns it as `StreamMessage.source`. Step writes
|
|
300
311
|
use `#<stepExecutionID>` as source metadata.
|
|
301
312
|
|
|
313
|
+
`Client.readStream` moves forward one message at a time and can long-poll.
|
|
314
|
+
`Client.listStreamMessages` returns a non-blocking newest-first retained page.
|
|
315
|
+
Pass the registered typed `Stream`, a positive page size, and an empty token for
|
|
316
|
+
the first page. Pass `StreamMessagesPage.nextPageToken` unchanged to read older
|
|
317
|
+
messages until it is empty. The server caps page size at 1000 by default. A
|
|
318
|
+
trimmed anchor returns an empty page, and newer concurrent writes do not enter
|
|
319
|
+
an existing older-page chain.
|
|
320
|
+
|
|
302
321
|
Step durability defaults to the Flow configuration and then sync. Regular
|
|
303
322
|
attempts default to two hours, heartbeat timeout defaults to one minute, and
|
|
304
323
|
retry total duration defaults to four hours. The SDK accepts non-negative
|
|
@@ -347,7 +366,7 @@ Flow config, Condition ID, and reuse. Parent completion does not cancel an unfin
|
|
|
347
366
|
## Errors
|
|
348
367
|
|
|
349
368
|
Client calls reject with concrete `DexServiceError` subclasses. Existing-Flow
|
|
350
|
-
reads (`
|
|
369
|
+
reads (`describeFlow`, `waitForFlow`, and `timeTravel`) use
|
|
351
370
|
`FlowNotFoundError`; operations that require a running Flow use
|
|
352
371
|
`FlowNotActiveError`. Start conflicts, worker failures, RPC lock contention,
|
|
353
372
|
and long-poll timeouts use `FlowAlreadyStartedError`,
|
|
@@ -355,7 +374,7 @@ and long-poll timeouts use `FlowAlreadyStartedError`,
|
|
|
355
374
|
|
|
356
375
|
```typescript
|
|
357
376
|
try {
|
|
358
|
-
await client.
|
|
377
|
+
await client.invokeRPC(orders.updateOrder, flowId, update);
|
|
359
378
|
} catch (error) {
|
|
360
379
|
if (error instanceof FlowNotActiveError) {
|
|
361
380
|
// The Flow is missing or already closed.
|
package/dist/src/client.d.ts
CHANGED
|
@@ -3,10 +3,9 @@ import { AttributeMatch } from "./attribute-match.js";
|
|
|
3
3
|
import type { Context } from "./context.js";
|
|
4
4
|
import { type Flow, type Registry } from "./flow.js";
|
|
5
5
|
import { type FlowResult } from "./flow-result.js";
|
|
6
|
-
import { type ClientOptions, type FlowConfig, type FlowInfo, type TimeTravelOptions, type SearchFlowsPage, type StartFlowOptions, type StepExecutionId, type StopFlowOptions, type TimerId } from "./options.js";
|
|
6
|
+
import { type ClientOptions, type FlowConfig, type FlowInfo, type TimeTravelOptions, type SearchFlowsPage, type StartFlowOptions, type StepExecutionId, type StopFlowOptions, type TimerId, type WaitForAttributeOptions, type WaitForStepCompletionOptions } from "./options.js";
|
|
7
7
|
import { Attribute, AttributeMap } from "./persistence.js";
|
|
8
8
|
import type { RPCResult } from "./rpc.js";
|
|
9
|
-
import { Channel, ChannelMap, type ChannelMessage } from "./wait.js";
|
|
10
9
|
import type { Stream, StreamMessage, StreamMessagesPage } from "./stream.js";
|
|
11
10
|
/**
|
|
12
11
|
* Calls Dex FlowService through registered, typed Flow definitions.
|
|
@@ -87,97 +86,6 @@ export declare class Client {
|
|
|
87
86
|
* @returns A promise resolved after successful handler completion.
|
|
88
87
|
*/
|
|
89
88
|
invokeRPC(rpcMethod: (context: Context) => void | Promise<void>, flowId: string, runId?: string): Promise<void>;
|
|
90
|
-
/**
|
|
91
|
-
* Reads a singleton Attribute.
|
|
92
|
-
* @typeParam T - Attribute value type.
|
|
93
|
-
* @param flowId - Non-empty existing Flow ID.
|
|
94
|
-
* @param attribute - Typed singleton Attribute definition.
|
|
95
|
-
* @param runId - Optional exact run; targets the current run when omitted.
|
|
96
|
-
* @returns The decoded value, or `undefined` when unset.
|
|
97
|
-
*/
|
|
98
|
-
getAttribute<T>(flowId: string, attribute: Attribute<T>, runId?: string): Promise<T | undefined>;
|
|
99
|
-
/**
|
|
100
|
-
* Reads one AttributeMap instance.
|
|
101
|
-
* @typeParam T - Attribute value type.
|
|
102
|
-
* @param flowId - Non-empty existing Flow ID.
|
|
103
|
-
* @param attribute - Typed AttributeMap definition.
|
|
104
|
-
* @param instance - The map instance. Slash is prohibited because it is a reserved character.
|
|
105
|
-
* @param runId - Optional exact run; targets the current run when omitted.
|
|
106
|
-
* @returns The decoded value, or `undefined` when unset.
|
|
107
|
-
*/
|
|
108
|
-
getAttribute<T>(flowId: string, attribute: AttributeMap<T>, instance: string, runId?: string): Promise<T | undefined>;
|
|
109
|
-
/**
|
|
110
|
-
* Writes a singleton Attribute on an active Flow.
|
|
111
|
-
* @typeParam T - Attribute value type.
|
|
112
|
-
* @param flowId - Non-empty active Flow ID.
|
|
113
|
-
* @param attribute - Typed singleton Attribute definition.
|
|
114
|
-
* @param value - Value encoded by the Attribute codec.
|
|
115
|
-
* @param runId - Optional exact run; targets the active run when omitted.
|
|
116
|
-
* @returns A promise resolved after Dex applies the write.
|
|
117
|
-
*/
|
|
118
|
-
setAttribute<T>(flowId: string, attribute: Attribute<T>, value: T, runId?: string): Promise<void>;
|
|
119
|
-
/**
|
|
120
|
-
* Writes one AttributeMap instance on an active Flow.
|
|
121
|
-
* @typeParam T - Attribute value type.
|
|
122
|
-
* @param flowId - Non-empty active Flow ID.
|
|
123
|
-
* @param attribute - Typed AttributeMap definition.
|
|
124
|
-
* @param instance - The map instance. Slash is prohibited because it is a reserved character.
|
|
125
|
-
* @param value - Value encoded by the Attribute codec.
|
|
126
|
-
* @param runId - Optional exact run; targets the active run when omitted.
|
|
127
|
-
* @returns A promise resolved after Dex applies the write.
|
|
128
|
-
*/
|
|
129
|
-
setAttribute<T>(flowId: string, attribute: AttributeMap<T>, instance: string, value: T, runId?: string): Promise<void>;
|
|
130
|
-
/**
|
|
131
|
-
* Publishes one or more values to a singleton Channel.
|
|
132
|
-
* @typeParam T - Channel element type.
|
|
133
|
-
* @param flowId - Non-empty active Flow ID.
|
|
134
|
-
* @param channel - Typed singleton Channel definition.
|
|
135
|
-
* @param values - Values appended in argument order.
|
|
136
|
-
* @returns A promise resolved after Dex accepts the batch.
|
|
137
|
-
*/
|
|
138
|
-
publish<T>(flowId: string, channel: Channel<T>, ...values: readonly T[]): Promise<void>;
|
|
139
|
-
/**
|
|
140
|
-
* Publishes one or more values to a ChannelMap instance.
|
|
141
|
-
* @typeParam T - Channel element type.
|
|
142
|
-
* @param flowId - Non-empty active Flow ID.
|
|
143
|
-
* @param channel - Typed ChannelMap definition.
|
|
144
|
-
* @param instance - The map instance. Slash is prohibited because it is a reserved character.
|
|
145
|
-
* @param values - Values appended in argument order.
|
|
146
|
-
* @returns A promise resolved after Dex accepts the batch.
|
|
147
|
-
*/
|
|
148
|
-
publish<T>(flowId: string, channel: ChannelMap<T>, instance: string, ...values: readonly T[]): Promise<void>;
|
|
149
|
-
/**
|
|
150
|
-
* Returns every pending singleton Channel message in FIFO order.
|
|
151
|
-
* @typeParam T - Channel value type.
|
|
152
|
-
* @param flowId - Non-empty existing Flow ID.
|
|
153
|
-
* @param channel - Registered singleton Channel.
|
|
154
|
-
* @returns Typed pending message envelopes.
|
|
155
|
-
*/
|
|
156
|
-
getChannelMessages<T>(flowId: string, channel: Channel<T>): Promise<readonly ChannelMessage<T>[]>;
|
|
157
|
-
/**
|
|
158
|
-
* Returns every pending message for one ChannelMap instance in FIFO order.
|
|
159
|
-
* @typeParam T - Channel value type.
|
|
160
|
-
* @param flowId - Non-empty existing Flow ID.
|
|
161
|
-
* @param channel - Registered ChannelMap.
|
|
162
|
-
* @param instance - The ChannelMap instance. Slash is prohibited because it is a reserved character.
|
|
163
|
-
* @returns Typed pending message envelopes.
|
|
164
|
-
*/
|
|
165
|
-
getChannelMessages<T>(flowId: string, channel: ChannelMap<T>, instance: string): Promise<readonly ChannelMessage<T>[]>;
|
|
166
|
-
/**
|
|
167
|
-
* Deletes one pending singleton Channel message by its server-assigned ID.
|
|
168
|
-
* @param flowId - Non-empty active Flow ID.
|
|
169
|
-
* @param channel - Registered singleton Channel.
|
|
170
|
-
* @param messageId - Non-empty server-assigned message ID.
|
|
171
|
-
*/
|
|
172
|
-
deleteChannelMessage(flowId: string, channel: Channel<unknown>, messageId: string): Promise<void>;
|
|
173
|
-
/**
|
|
174
|
-
* Deletes one pending message from a ChannelMap instance by server-assigned ID.
|
|
175
|
-
* @param flowId - Non-empty active Flow ID.
|
|
176
|
-
* @param channel - Registered ChannelMap.
|
|
177
|
-
* @param instance - The ChannelMap instance. Slash is prohibited because it is a reserved character.
|
|
178
|
-
* @param messageId - Non-empty server-assigned message ID.
|
|
179
|
-
*/
|
|
180
|
-
deleteChannelMessage(flowId: string, channel: ChannelMap<unknown>, instance: string, messageId: string): Promise<void>;
|
|
181
89
|
/**
|
|
182
90
|
* Appends one typed best-effort Stream message with source metadata.
|
|
183
91
|
* @typeParam T - Stream message type.
|
|
@@ -257,36 +165,40 @@ export declare class Client {
|
|
|
257
165
|
*/
|
|
258
166
|
skipTimer(flowId: string, stepExecutionId: StepExecutionId, timerId: TimerId): Promise<void>;
|
|
259
167
|
/**
|
|
260
|
-
*
|
|
168
|
+
* Waits until one Step execution completes or its total handler budget expires.
|
|
169
|
+
* The server derives a stable Request ID from the Step execution when none is supplied.
|
|
170
|
+
* Transport long polls automatically reattach to the same logical wait.
|
|
261
171
|
* @param flowId - Non-empty active Flow ID.
|
|
262
172
|
* @param stepExecutionId - Step type and positive execution number.
|
|
263
|
-
* @param
|
|
264
|
-
* @throws {@link
|
|
173
|
+
* @param options - Optional Request ID override and total handler wait budget.
|
|
174
|
+
* @throws {@link WaitHandlerTimeoutError} when a positive handler budget expires first.
|
|
265
175
|
*/
|
|
266
|
-
waitForStepCompletion(flowId: string, stepExecutionId: StepExecutionId,
|
|
176
|
+
waitForStepCompletion(flowId: string, stepExecutionId: StepExecutionId, options: WaitForStepCompletionOptions): Promise<void>;
|
|
267
177
|
/**
|
|
268
178
|
* Waits until a singleton Attribute in the current run satisfies a match.
|
|
269
179
|
* Returns the current value observed by the successful wait operation.
|
|
180
|
+
* The server derives a stable Request ID from the condition when none is supplied.
|
|
181
|
+
* Transport long polls automatically reattach to the same logical wait.
|
|
270
182
|
* @typeParam T - Attribute value type.
|
|
271
183
|
* @param flowId - Non-empty active Flow ID.
|
|
272
184
|
* @param attribute - Registered singleton Attribute to observe.
|
|
273
185
|
* @param match - Scalar predicate whose operand has the Attribute value type.
|
|
274
|
-
* @param
|
|
186
|
+
* @param options - Optional Request ID override and total handler wait budget.
|
|
275
187
|
* @returns The matched current Attribute value.
|
|
276
188
|
*/
|
|
277
|
-
waitForAttributeMatch<T>(flowId: string, attribute: Attribute<T>, match: AttributeMatch<T>,
|
|
189
|
+
waitForAttributeMatch<T>(flowId: string, attribute: Attribute<T>, match: AttributeMatch<T>, options: WaitForAttributeOptions): Promise<T>;
|
|
278
190
|
/**
|
|
279
191
|
* Waits until one AttributeMap instance in the current run satisfies a match.
|
|
280
|
-
* Primitive-value restrictions and timeout errors match `waitForAttributeMatch`.
|
|
192
|
+
* Primitive-value restrictions, options, and timeout errors match `waitForAttributeMatch`.
|
|
281
193
|
* @typeParam T - AttributeMap value type.
|
|
282
194
|
* @param flowId - Non-empty active Flow ID.
|
|
283
195
|
* @param attribute - Registered AttributeMap to observe.
|
|
284
196
|
* @param instance - The map instance to observe. Slash is prohibited because it is a reserved character.
|
|
285
197
|
* @param match - Scalar predicate whose operand has the AttributeMap value type.
|
|
286
|
-
* @param
|
|
198
|
+
* @param options - Optional Request ID override and total handler wait budget.
|
|
287
199
|
* @returns The matched current AttributeMap value.
|
|
288
200
|
*/
|
|
289
|
-
waitForAttributeMatch<T>(flowId: string, attribute: AttributeMap<T>, instance: string, match: AttributeMatch<T>,
|
|
201
|
+
waitForAttributeMatch<T>(flowId: string, attribute: AttributeMap<T>, instance: string, match: AttributeMatch<T>, options: WaitForAttributeOptions): Promise<T>;
|
|
290
202
|
private waitForAttributeValue;
|
|
291
203
|
/**
|
|
292
204
|
* Replaces mutable configuration for an active Flow.
|
package/dist/src/client.js
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
// See the LICENSE file in the repository root.
|
|
6
6
|
//
|
|
7
7
|
// SPDX-License-Identifier: LicenseRef-Sustainable-Use-1.0
|
|
8
|
-
import { credentials } from "@grpc/grpc-js";
|
|
8
|
+
import { credentials, status } from "@grpc/grpc-js";
|
|
9
9
|
import { AttributeMatch } from "./attribute-match.js";
|
|
10
10
|
import { mapAttributeStoreNames, mapAttributeStoreSync } from "./attribute-store-sync.js";
|
|
11
11
|
import { ActiveStepSearchMode as ProtoActiveStepSearchMode, FlowErrorType as ProtoFlowErrorType, FlowTimeoutPolicy as ProtoFlowTimeoutPolicy, FlowResetStepMethod as ProtoFlowResetStepMethod, FlowResetType as ProtoFlowResetType, FlowServiceClient, FlowStatus as ProtoFlowStatus, IdReusePolicy as ProtoIdReusePolicy, IndexType as ProtoIndexType, ExecuteMethodFailurePolicy, StartFlowRequest, StepDurability as ProtoStepDurability, StepOptions as ProtoStepOptions, FlowTimeoutHandlerOptions as ProtoFlowTimeoutHandlerOptions, StopType as ProtoStopType, WaitForMethodFailurePolicy, } from "./gen/dex.js";
|
|
12
|
-
import { FlowErrorType, } from "./errors.js";
|
|
12
|
+
import { ErrorSubStatus, FlowErrorType, LongPollTimeoutError, WaitHandlerTimeoutError, } from "./errors.js";
|
|
13
13
|
import { registeredFlow, registeredRPC, registeredStream, } from "./flow.js";
|
|
14
14
|
import { createFlowResultFromProto, } from "./flow-result.js";
|
|
15
15
|
import { translateServiceError } from "./grpc-status.js";
|
|
@@ -149,115 +149,6 @@ export class Client {
|
|
|
149
149
|
}
|
|
150
150
|
return decodeValue(codecOrJson(rpc.options.outputCodec), await this.hydrator.hydrate(response.output));
|
|
151
151
|
}
|
|
152
|
-
/**
|
|
153
|
-
* Reads and decodes a singleton or map Attribute.
|
|
154
|
-
* @param flowId - Non-empty existing Flow ID.
|
|
155
|
-
* @param attribute - Typed Attribute definition.
|
|
156
|
-
* @param instanceOrRunId - Map instance, or singleton run ID.
|
|
157
|
-
* @param runId - Exact run for a map read.
|
|
158
|
-
* @returns The decoded value, or `undefined` when unset.
|
|
159
|
-
*/
|
|
160
|
-
async getAttribute(flowId, attribute, instanceOrRunId = "", runId = "") {
|
|
161
|
-
const isMap = attribute instanceof AttributeMap;
|
|
162
|
-
const response = await unary({ operation: "getAttribute", flowId, requirement: "existing" }, (callback) => this.service.getAttributes({
|
|
163
|
-
flowId: requireName(flowId),
|
|
164
|
-
runId: isMap ? runId : instanceOrRunId,
|
|
165
|
-
keys: [physicalName(attribute.name, isMap ? instanceOrRunId : undefined)],
|
|
166
|
-
allKeys: false,
|
|
167
|
-
}, callback));
|
|
168
|
-
const value = response.attributes[0]?.value;
|
|
169
|
-
if (value === undefined) {
|
|
170
|
-
return undefined;
|
|
171
|
-
}
|
|
172
|
-
return decodeValue(attribute.codec, await this.hydrator.hydrate(value));
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Encodes and writes a singleton or map Attribute.
|
|
176
|
-
* @param flowId - Non-empty active Flow ID.
|
|
177
|
-
* @param attribute - Typed Attribute definition.
|
|
178
|
-
* @param instanceOrValue - Map instance or singleton value.
|
|
179
|
-
* @param valueOrRunId - Map value or singleton run ID.
|
|
180
|
-
* @param runId - Exact run for a map write.
|
|
181
|
-
* @returns A promise resolved after Dex applies the write.
|
|
182
|
-
*/
|
|
183
|
-
async setAttribute(flowId, attribute, instanceOrValue, valueOrRunId, runId = "") {
|
|
184
|
-
const isMap = attribute instanceof AttributeMap;
|
|
185
|
-
const instance = isMap ? String(instanceOrValue) : undefined;
|
|
186
|
-
const value = isMap ? valueOrRunId : instanceOrValue;
|
|
187
|
-
await unary({ operation: "setAttribute", flowId, requirement: "active" }, (callback) => this.service.setAttributes({
|
|
188
|
-
flowId: requireName(flowId),
|
|
189
|
-
runId: isMap ? runId : typeof valueOrRunId === "string" ? valueOrRunId : "",
|
|
190
|
-
attributes: [
|
|
191
|
-
{
|
|
192
|
-
key: physicalName(attribute.name, instance),
|
|
193
|
-
value: encodeValue(attribute.codec, value),
|
|
194
|
-
indexConfig: mapIndex(attribute.index),
|
|
195
|
-
syncConfig: mapAttributeStoreSync(attribute),
|
|
196
|
-
},
|
|
197
|
-
],
|
|
198
|
-
requestId: crypto.randomUUID(),
|
|
199
|
-
}, callback));
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Encodes and publishes a singleton or map Channel batch.
|
|
203
|
-
* @param flowId - Non-empty active Flow ID.
|
|
204
|
-
* @param channel - Typed Channel definition.
|
|
205
|
-
* @param instanceAndValues - Optional map instance followed by values.
|
|
206
|
-
* @returns A promise resolved after Dex accepts the batch.
|
|
207
|
-
*/
|
|
208
|
-
async publish(flowId, channel, ...instanceAndValues) {
|
|
209
|
-
const isMap = channel instanceof ChannelMap;
|
|
210
|
-
const instance = isMap ? String(instanceAndValues[0]) : undefined;
|
|
211
|
-
const values = isMap ? instanceAndValues.slice(1) : instanceAndValues;
|
|
212
|
-
await unary({ operation: "publish", flowId, requirement: "active" }, (callback) => this.service.publishToChannel({
|
|
213
|
-
flowId: requireName(flowId),
|
|
214
|
-
runId: "",
|
|
215
|
-
messages: values.map((value) => ({
|
|
216
|
-
channelName: physicalName(channel.name, instance),
|
|
217
|
-
value: encodeValue(channel.codec, value),
|
|
218
|
-
messageId: "",
|
|
219
|
-
})),
|
|
220
|
-
}, callback));
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Implements singleton and ChannelMap pending-message reads.
|
|
224
|
-
* @typeParam T - Channel value type.
|
|
225
|
-
* @param flowId - Non-empty existing Flow ID.
|
|
226
|
-
* @param channel - Registered singleton or map definition.
|
|
227
|
-
* @param instance - Required ChannelMap instance; omitted for a singleton.
|
|
228
|
-
* @returns Typed pending message envelopes in FIFO order.
|
|
229
|
-
*/
|
|
230
|
-
async getChannelMessages(flowId, channel, instance) {
|
|
231
|
-
const response = await unary({ operation: "getChannelMessages", flowId, requirement: "existing" }, (callback) => this.service.getChannelMessages({
|
|
232
|
-
flowId: requireName(flowId),
|
|
233
|
-
runId: "",
|
|
234
|
-
channelName: physicalName(channel.name, instance),
|
|
235
|
-
}, callback));
|
|
236
|
-
return Promise.all(response.messages.map(async (message) => ({
|
|
237
|
-
messageId: message.messageId,
|
|
238
|
-
value: decodeValue(channel.codec, await this.hydrator.hydrate(message.value)),
|
|
239
|
-
})));
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Implements singleton and ChannelMap pending-message deletion.
|
|
243
|
-
* @param flowId - Non-empty active Flow ID.
|
|
244
|
-
* @param channel - Registered singleton or map definition.
|
|
245
|
-
* @param instanceOrMessageId - Map instance or singleton message ID.
|
|
246
|
-
* @param mapMessageId - Required message ID for a ChannelMap.
|
|
247
|
-
* @returns A promise resolved after Dex accepts the deletion.
|
|
248
|
-
*/
|
|
249
|
-
async deleteChannelMessage(flowId, channel, instanceOrMessageId, mapMessageId) {
|
|
250
|
-
const isMap = channel instanceof ChannelMap;
|
|
251
|
-
const instance = isMap ? instanceOrMessageId : undefined;
|
|
252
|
-
const messageId = isMap ? mapMessageId : instanceOrMessageId;
|
|
253
|
-
await unary({ operation: "deleteChannelMessage", flowId, requirement: "active" }, (callback) => this.service.deleteChannelMessage({
|
|
254
|
-
flowId: requireName(flowId),
|
|
255
|
-
runId: "",
|
|
256
|
-
channelName: physicalName(channel.name, instance),
|
|
257
|
-
messageId: requireName(messageId ?? ""),
|
|
258
|
-
requestId: crypto.randomUUID(),
|
|
259
|
-
}, callback));
|
|
260
|
-
}
|
|
261
152
|
/**
|
|
262
153
|
* Appends one typed best-effort Stream message with source metadata.
|
|
263
154
|
* @typeParam T - Stream message type.
|
|
@@ -468,62 +359,85 @@ export class Client {
|
|
|
468
359
|
}, callback));
|
|
469
360
|
}
|
|
470
361
|
/**
|
|
471
|
-
*
|
|
362
|
+
* Waits until one Step execution completes or its total handler budget expires.
|
|
363
|
+
* The server derives a stable Request ID from the Step execution when none is supplied.
|
|
364
|
+
* Transport long polls automatically reattach to the same logical wait.
|
|
472
365
|
* @param flowId - Non-empty active Flow ID.
|
|
473
366
|
* @param stepExecutionId - Step type and positive execution number.
|
|
474
|
-
* @param
|
|
475
|
-
* @throws {@link
|
|
367
|
+
* @param options - Optional Request ID override and total handler wait budget.
|
|
368
|
+
* @throws {@link WaitHandlerTimeoutError} when a positive handler budget expires first.
|
|
476
369
|
*/
|
|
477
|
-
async waitForStepCompletion(flowId, stepExecutionId,
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
370
|
+
async waitForStepCompletion(flowId, stepExecutionId, options) {
|
|
371
|
+
const waitBudget = new ClientWaitBudget(options.maximumWaitTimeMs);
|
|
372
|
+
while (true) {
|
|
373
|
+
try {
|
|
374
|
+
await unary({ operation: "waitForStepCompletion", flowId, requirement: "active" }, (callback) => this.service.waitForStepCompletion({
|
|
375
|
+
flowId: requireName(flowId),
|
|
376
|
+
stepType: stepExecutionId.stepType,
|
|
377
|
+
stepExecutionNumber: String(stepExecutionId.number ?? 1),
|
|
378
|
+
waitTimeSeconds: waitBudget.remainingSeconds("waitForStepCompletion", flowId),
|
|
379
|
+
requestId: options.requestId ?? "",
|
|
380
|
+
}, callback));
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
if (!(error instanceof LongPollTimeoutError)) {
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
485
389
|
}
|
|
486
390
|
/**
|
|
487
391
|
* Waits until a singleton Attribute or AttributeMap instance satisfies a match.
|
|
488
392
|
* @param flowId - Non-empty active Flow ID.
|
|
489
393
|
* @param attribute - Registered Attribute or AttributeMap to observe.
|
|
490
|
-
* @param args - Match and
|
|
394
|
+
* @param args - Match and options, optionally preceded by a map instance.
|
|
491
395
|
* @returns The matched current value.
|
|
492
396
|
*/
|
|
493
397
|
async waitForAttributeMatch(flowId, attribute, ...args) {
|
|
494
398
|
if (attribute instanceof Attribute) {
|
|
495
|
-
if (args.length !== 2 ||
|
|
399
|
+
if (args.length !== 2 || !isWaitForAttributeOptions(args[1])) {
|
|
496
400
|
throw new TypeError("waitForAttributeMatch received invalid Attribute arguments");
|
|
497
401
|
}
|
|
498
402
|
return this.waitForAttributeValue(flowId, attribute, undefined, args[0], args[1]);
|
|
499
403
|
}
|
|
500
404
|
if (attribute instanceof AttributeMap) {
|
|
501
|
-
if (args.length !== 3 || typeof args[0] !== "string" ||
|
|
405
|
+
if (args.length !== 3 || typeof args[0] !== "string" || !isWaitForAttributeOptions(args[2])) {
|
|
502
406
|
throw new TypeError("waitForAttributeMatch received invalid AttributeMap arguments");
|
|
503
407
|
}
|
|
504
408
|
return this.waitForAttributeValue(flowId, attribute, args[0], args[1], args[2]);
|
|
505
409
|
}
|
|
506
410
|
throw new TypeError("waitForAttributeMatch received an invalid Attribute definition");
|
|
507
411
|
}
|
|
508
|
-
async waitForAttributeValue(flowId, attribute, instance, match,
|
|
412
|
+
async waitForAttributeValue(flowId, attribute, instance, match, options) {
|
|
509
413
|
if (!(match instanceof AttributeMatch)) {
|
|
510
414
|
throw new TypeError("waitForAttributeMatch requires an AttributeMatch");
|
|
511
415
|
}
|
|
512
416
|
const encoded = match.encode(attribute.codec);
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
417
|
+
const waitBudget = new ClientWaitBudget(options.maximumWaitTimeMs);
|
|
418
|
+
while (true) {
|
|
419
|
+
try {
|
|
420
|
+
const response = await unary({ operation: "waitForAttributeMatch", flowId, requirement: "active" }, (callback) => this.service.waitForAttribute({
|
|
421
|
+
flowId: requireName(flowId),
|
|
422
|
+
match: {
|
|
423
|
+
key: physicalName(attribute.name, instance),
|
|
424
|
+
operator: encoded.operator,
|
|
425
|
+
operand: encoded.operand,
|
|
426
|
+
},
|
|
427
|
+
waitTimeSeconds: waitBudget.remainingSeconds("waitForAttributeMatch", flowId),
|
|
428
|
+
requestId: options.requestId ?? "",
|
|
429
|
+
}, callback));
|
|
430
|
+
if (response.matchedValue === undefined) {
|
|
431
|
+
throw new Error("waitForAttributeMatch response is incomplete");
|
|
432
|
+
}
|
|
433
|
+
return decodeValue(attribute.codec, response.matchedValue);
|
|
434
|
+
}
|
|
435
|
+
catch (error) {
|
|
436
|
+
if (!(error instanceof LongPollTimeoutError)) {
|
|
437
|
+
throw error;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
525
440
|
}
|
|
526
|
-
return decodeValue(attribute.codec, response.matchedValue);
|
|
527
441
|
}
|
|
528
442
|
/**
|
|
529
443
|
* Replaces mutable configuration for an active Flow.
|
|
@@ -878,6 +792,29 @@ function seconds(milliseconds) {
|
|
|
878
792
|
}
|
|
879
793
|
return milliseconds / 1_000;
|
|
880
794
|
}
|
|
795
|
+
function isWaitForAttributeOptions(value) {
|
|
796
|
+
return typeof value === "object" && value !== null;
|
|
797
|
+
}
|
|
798
|
+
class ClientWaitBudget {
|
|
799
|
+
deadlineMs;
|
|
800
|
+
constructor(maximumWaitTimeMs) {
|
|
801
|
+
const maximumWaitSeconds = seconds(maximumWaitTimeMs);
|
|
802
|
+
if (maximumWaitSeconds > 2_147_483_647) {
|
|
803
|
+
throw new RangeError("duration exceeds the int32 seconds range");
|
|
804
|
+
}
|
|
805
|
+
this.deadlineMs = maximumWaitSeconds === 0 ? undefined : performance.now() + maximumWaitSeconds * 1_000;
|
|
806
|
+
}
|
|
807
|
+
remainingSeconds(operation, flowId) {
|
|
808
|
+
if (this.deadlineMs === undefined) {
|
|
809
|
+
return 0;
|
|
810
|
+
}
|
|
811
|
+
const remainingMs = this.deadlineMs - performance.now();
|
|
812
|
+
if (remainingMs <= 0) {
|
|
813
|
+
throw new WaitHandlerTimeoutError(status.DEADLINE_EXCEEDED, ErrorSubStatus.WAIT_HANDLER_TIMEOUT, "wait handler timed out", operation, flowId);
|
|
814
|
+
}
|
|
815
|
+
return Math.ceil(remainingMs / 1_000);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
881
818
|
function heartbeatSeconds(milliseconds) {
|
|
882
819
|
const value = seconds(milliseconds);
|
|
883
820
|
if (value > 2_147_483_647) {
|