@hotmeshio/hotmesh 0.0.53 → 0.0.54

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 (40) hide show
  1. package/build/modules/errors.d.ts +6 -48
  2. package/build/modules/errors.js +5 -5
  3. package/build/package.json +1 -1
  4. package/build/services/activities/hook.js +5 -1
  5. package/build/services/activities/trigger.d.ts +5 -2
  6. package/build/services/activities/trigger.js +22 -1
  7. package/build/services/durable/client.js +1 -8
  8. package/build/services/durable/exporter.d.ts +24 -13
  9. package/build/services/durable/exporter.js +145 -127
  10. package/build/services/durable/handle.d.ts +2 -2
  11. package/build/services/durable/handle.js +2 -2
  12. package/build/services/durable/worker.js +1 -1
  13. package/build/services/durable/workflow.d.ts +29 -17
  14. package/build/services/durable/workflow.js +116 -96
  15. package/build/services/engine/index.d.ts +2 -2
  16. package/build/services/engine/index.js +2 -2
  17. package/build/services/hotmesh/index.d.ts +2 -2
  18. package/build/services/hotmesh/index.js +2 -2
  19. package/build/types/durable.d.ts +15 -3
  20. package/build/types/error.d.ts +48 -0
  21. package/build/types/error.js +2 -0
  22. package/build/types/exporter.d.ts +26 -20
  23. package/build/types/index.d.ts +2 -1
  24. package/build/types/job.d.ts +24 -1
  25. package/modules/errors.ts +18 -55
  26. package/package.json +1 -1
  27. package/services/activities/hook.ts +8 -1
  28. package/services/activities/trigger.ts +27 -2
  29. package/services/durable/client.ts +2 -8
  30. package/services/durable/exporter.ts +149 -128
  31. package/services/durable/handle.ts +3 -3
  32. package/services/durable/worker.ts +1 -1
  33. package/services/durable/workflow.ts +136 -103
  34. package/services/engine/index.ts +4 -3
  35. package/services/hotmesh/index.ts +4 -3
  36. package/types/durable.ts +18 -3
  37. package/types/error.ts +52 -0
  38. package/types/exporter.ts +31 -23
  39. package/types/index.ts +8 -1
  40. package/types/job.ts +27 -0
@@ -14,10 +14,12 @@ import { asyncLocalStorage } from '../../modules/storage';
14
14
  import {
15
15
  deterministicRandom,
16
16
  formatISODate,
17
+ guid,
17
18
  sleepFor } from '../../modules/utils';
18
19
  import { Search } from './search';
19
20
  import { WorkerService } from './worker';
20
21
  import { HotMeshService as HotMesh } from '../hotmesh';
22
+ import { SerializerService } from '../serializer';
21
23
  import {
22
24
  ActivityConfig,
23
25
  ChildResponseType,
@@ -28,8 +30,8 @@ import {
28
30
  WorkflowOptions
29
31
  } from "../../types/durable";
30
32
  import { JobInterruptOptions } from '../../types/job';
31
- import { StreamCode, StreamError, StreamStatus } from '../../types/stream';
32
- import { StringStringType } from '../../types';
33
+ import { StreamCode, StreamStatus } from '../../types/stream';
34
+ import { StringStringType } from '../../types/serializer';
33
35
  import {
34
36
  HMSH_CODE_DURABLE_CHILD,
35
37
  HMSH_CODE_DURABLE_FATAL,
@@ -41,19 +43,62 @@ import {
41
43
  HMSH_DURABLE_EXP_BACKOFF,
42
44
  HMSH_DURABLE_MAX_ATTEMPTS,
43
45
  HMSH_DURABLE_MAX_INTERVAL} from '../../modules/enums';
44
- import { SerializerService } from '../serializer';
46
+ import { DurableChildErrorType, DurableProxyErrorType } from '../../types/error';
45
47
 
46
48
  export class WorkflowService {
47
49
 
48
50
  /**
49
- * Return a handle to the hotmesh client currently running the workflow
50
- * @returns {Promise<HotMesh>} - a hotmesh client
51
+ * Returns the synchronous output from the activity (replay)
52
+ * if available locally, revealing whether or not the activity already
53
+ * ran during a prior execution cycle
54
+ * @param {string} prefix - one of: proxy, child, start, wait etc
55
+ * @returns
51
56
  */
52
- static async getHotMesh(): Promise<HotMesh> {
57
+ static async didRun(prefix: string): Promise<[boolean, number, any]> {
58
+ const {
59
+ COUNTER,
60
+ replay,
61
+ workflowDimension,
62
+ } = WorkflowService.getContext();
63
+ const execIndex = COUNTER.counter = COUNTER.counter + 1;
64
+ const sessionId = `-${prefix}${workflowDimension}-${execIndex}-`;
65
+ if (sessionId in replay) {
66
+ const restored = SerializerService.fromString(replay[sessionId]);
67
+ return [true, execIndex, restored];
68
+ }
69
+ return [false, execIndex, null];
70
+ }
71
+
72
+ /**
73
+ * Those methods that may only be called once must be protected by flagging
74
+ * their execution with a unique key (the key is stored in the HASH alongside
75
+ * process state and job state)
76
+ * @private
77
+ */
78
+ static async isSideEffectAllowed(hotMeshClient: HotMesh, prefix: string): Promise<boolean> {
53
79
  const store = asyncLocalStorage.getStore();
54
- const workflowTopic = store.get('workflowTopic');
55
- const namespace = store.get('namespace');
56
- return await WorkerService.getHotMesh(workflowTopic, { namespace });
80
+ const workflowId = store.get('workflowId');
81
+ const workflowDimension = store.get('workflowDimension') ?? '';
82
+ const COUNTER = store.get('counter');
83
+ const execIndex = COUNTER.counter = COUNTER.counter + 1;
84
+ const sessionId = `-${prefix}${workflowDimension}-${execIndex}-`;
85
+ const replay = store.get('replay') as StringStringType;
86
+ if (sessionId in replay) {
87
+ return false;
88
+ }
89
+ const keyParams = {
90
+ appId: hotMeshClient.appId,
91
+ jobId: workflowId
92
+ }
93
+ const workflowGuid = KeyService.mintKey(hotMeshClient.namespace, KeyType.JOB_STATE, keyParams);
94
+ const guidValue = Number(
95
+ await hotMeshClient.engine.store.exec(
96
+ 'HINCRBYFLOAT',
97
+ workflowGuid,
98
+ sessionId,
99
+ '1') as string
100
+ );
101
+ return guidValue === 1;
57
102
  }
58
103
 
59
104
  /**
@@ -65,9 +110,11 @@ export class WorkflowService {
65
110
  const workflowId = store.get('workflowId');
66
111
  const replay = store.get('replay');
67
112
  const cursor = store.get('cursor');
113
+ const interruptionRegistry = store.get('interruptionRegistry');
68
114
  const workflowDimension = store.get('workflowDimension') ?? '';
69
115
  const workflowTopic = store.get('workflowTopic');
70
116
  const namespace = store.get('namespace');
117
+ const originJobId = store.get('originJobId');
71
118
  const workflowTrace = store.get('workflowTrace');
72
119
  const canRetry = store.get('canRetry');
73
120
  const workflowSpan = store.get('workflowSpan');
@@ -78,7 +125,9 @@ export class WorkflowService {
78
125
  COUNTER,
79
126
  counter: COUNTER.counter,
80
127
  cursor,
128
+ interruptionRegistry,
81
129
  namespace,
130
+ originJobId,
82
131
  raw,
83
132
  replay,
84
133
  workflowId,
@@ -89,6 +138,17 @@ export class WorkflowService {
89
138
  };
90
139
  }
91
140
 
141
+ /**
142
+ * Return a handle to the hotmesh client hosting the workflow execution
143
+ * @returns {Promise<HotMesh>} - a hotmesh client
144
+ */
145
+ static async getHotMesh(): Promise<HotMesh> {
146
+ const store = asyncLocalStorage.getStore();
147
+ const workflowTopic = store.get('workflowTopic');
148
+ const namespace = store.get('namespace');
149
+ return await WorkerService.getHotMesh(workflowTopic, { namespace });
150
+ }
151
+
92
152
  /**
93
153
  * Spawns a child workflow and awaits the return.
94
154
  * @template T - the result type
@@ -101,14 +161,15 @@ export class WorkflowService {
101
161
  //SYNC
102
162
  //check if the activity already ran (check $error/done)
103
163
  const isStartChild = options.await === false;
104
- const [didRun, execIndex, result]: [boolean, number, ChildResponseType<T>] = await WorkflowService.didRun(isStartChild ? 'start' : 'child');
105
- const store = asyncLocalStorage.getStore();
106
- const canRetry = store.get('canRetry');
164
+ const prefix = isStartChild ? 'start' : 'child';
165
+ const [didRun, execIndex, result]: [boolean, number, ChildResponseType<T>] = await WorkflowService.didRun(prefix);
166
+ const context = this.getContext();
167
+ const { canRetry, interruptionRegistry } = context;
107
168
 
108
169
  if (didRun) {
109
170
  if (result?.$error && (!result.$error.is_stream_error || (result.$error.is_stream_error && !canRetry))) {
110
171
  if (options?.config?.throwOnError !== false) {
111
- //rethrow remote execution error (simulates throw)
172
+ //rethrow remote execution error (simulates local failure)
112
173
  const code: StreamCode = result.$error.code;
113
174
  const message = result.$error.message;
114
175
  const stack = result.$error.stack;
@@ -127,18 +188,36 @@ export class WorkflowService {
127
188
  return result.data as T;
128
189
  }
129
190
  }
130
- //package the interruption inputs
131
- const interruptionRegistry = store.get('interruptionRegistry');
132
- const workflowId = store.get('workflowId');
133
- const originJobId = store.get('originJobId');
134
- const workflowDimension = store.get('workflowDimension') ?? '';
135
- const entityOrEmptyString = options.entity ?? '';
136
- const childJobId = options.workflowId ?? `${entityOrEmptyString}-${workflowId}-$${options.entity ?? options.workflowName}${workflowDimension}-${execIndex}`;
191
+ const interruptionMessage = this.getChildInterruptPayload(context, options, execIndex);
192
+ //push the packaged inputs to the registry
193
+ interruptionRegistry.push({
194
+ code: HMSH_CODE_DURABLE_CHILD,
195
+ ...interruptionMessage,
196
+ });
197
+ //ASYNC
198
+ //sleep (allow others to be packaged / registered) and throw the error
199
+ await sleepFor(0);
200
+ throw new DurableChildError(interruptionMessage );
201
+ }
202
+
203
+ /**
204
+ * constructs the payload necessary to spawn a child job
205
+ * @private
206
+ */
207
+ static getChildInterruptPayload(context: WorkflowContext, options: WorkflowOptions, execIndex: number): DurableChildErrorType {
208
+ const { workflowId, originJobId, workflowDimension } = context; let childJobId: string;
209
+ if (options.workflowId) {
210
+ childJobId = options.workflowId;
211
+ } else if (options.entity) {
212
+ childJobId = `${options.entity}-${workflowId.substring(0, 7)}-${guid()}-${workflowDimension}-${execIndex}`;
213
+ } else {
214
+ childJobId = `-${options.workflowName}-${guid()}-${workflowDimension}-${execIndex}`;
215
+ }
137
216
  const parentWorkflowId = workflowId;
138
217
  const taskQueueName = options.entity ?? options.taskQueue;
139
218
  const workflowName = options.entity ?? options.workflowName;
140
219
  const workflowTopic = `${taskQueueName}-${workflowName}`;
141
- const interruptionMessage = {
220
+ return {
142
221
  arguments: [...(options.args || [])],
143
222
  await: options?.await ?? true,
144
223
  backoffCoefficient: options?.config?.backoffCoefficient ?? HMSH_DURABLE_EXP_BACKOFF,
@@ -151,15 +230,6 @@ export class WorkflowService {
151
230
  workflowId: childJobId,
152
231
  workflowTopic,
153
232
  };
154
- //push the packaged inputs to the registry
155
- interruptionRegistry.push({
156
- code: HMSH_CODE_DURABLE_CHILD,
157
- ...interruptionMessage,
158
- });
159
- //ASYNC
160
- //sleep (allow others to be packaged / registered) and throw the error
161
- await sleepFor(0);
162
- throw new DurableChildError(interruptionMessage);
163
233
  }
164
234
 
165
235
  /**
@@ -234,31 +304,15 @@ export class WorkflowService {
234
304
  return result.data as T;
235
305
  }
236
306
  //package the interruption inputs
237
- const store = asyncLocalStorage.getStore();
238
- const interruptionRegistry = store.get('interruptionRegistry');
239
- const workflowDimension = store.get('workflowDimension') ?? '';
240
- const workflowId = store.get('workflowId');
241
- const originJobId = store.get('originJobId');
242
- const workflowTopic = store.get('workflowTopic');
243
- const activityTopic = `${workflowTopic}-activity`;
244
- const activityJobId = `-${workflowId}-$${activityName}${workflowDimension}-${execIndex}`;
245
- let maximumInterval: number;
246
- if (options.retryPolicy?.maximumInterval) {
247
- maximumInterval = ms(options.retryPolicy.maximumInterval) / 1000;
248
- }
249
- const interruptionMessage = {
250
- arguments: Array.from(arguments),
251
- workflowDimension: workflowDimension,
252
- index: execIndex,
253
- originJobId: originJobId || workflowId,
254
- parentWorkflowId: workflowId,
255
- workflowId: activityJobId,
256
- workflowTopic: activityTopic,
307
+ const context = WorkflowService.getContext();
308
+ const { interruptionRegistry } = context;
309
+ const interruptionMessage = WorkflowService.getProxyInterruptPayload(
310
+ context,
257
311
  activityName,
258
- backoffCoefficient: options?.retryPolicy?.backoffCoefficient ?? undefined,
259
- maximumAttempts: options?.retryPolicy?.maximumAttempts ?? undefined,
260
- maximumInterval: maximumInterval ?? undefined,
261
- };
312
+ execIndex,
313
+ Array.from(arguments),
314
+ options
315
+ );
262
316
  //push the packaged inputs to the registry
263
317
  interruptionRegistry.push({
264
318
  code: HMSH_CODE_DURABLE_PROXY,
@@ -271,6 +325,33 @@ export class WorkflowService {
271
325
  } as T;
272
326
  }
273
327
 
328
+ /**
329
+ * constructs the payload necessary to spawn a proxyActivity job
330
+ * @private
331
+ */
332
+ static getProxyInterruptPayload(context: WorkflowContext, activityName: string, execIndex: number, args: any[], options?: ActivityConfig): DurableProxyErrorType {
333
+ const { workflowDimension, workflowId, originJobId, workflowTopic } = context;
334
+ const activityTopic = `${workflowTopic}-activity`;
335
+ const activityJobId = `-${workflowId}-$${activityName}${workflowDimension}-${execIndex}`;
336
+ let maximumInterval: number;
337
+ if (options.retryPolicy?.maximumInterval) {
338
+ maximumInterval = ms(options.retryPolicy.maximumInterval) / 1000;
339
+ }
340
+ return {
341
+ arguments: args,
342
+ workflowDimension: workflowDimension,
343
+ index: execIndex,
344
+ originJobId: originJobId || workflowId,
345
+ parentWorkflowId: workflowId,
346
+ workflowId: activityJobId,
347
+ workflowTopic: activityTopic,
348
+ activityName,
349
+ backoffCoefficient: options?.retryPolicy?.backoffCoefficient ?? undefined,
350
+ maximumAttempts: options?.retryPolicy?.maximumAttempts ?? undefined,
351
+ maximumInterval: maximumInterval ?? undefined,
352
+ };
353
+ }
354
+
274
355
  /**
275
356
  * Returns a search session for use when reading/writing to the workflow HASH.
276
357
  * The search session provides access to methods like `get`, `mget`, `set`, `del`, and `incr`.
@@ -290,52 +371,6 @@ export class WorkflowService {
290
371
  return new Search(workflowId, hotMeshClient, searchSessionId);
291
372
  }
292
373
 
293
- /**
294
- * Returns the synchronous output from the activity (replay)
295
- * if available locally
296
- * @param {string} prefix - one of: proxy, child, start, wait etc
297
- * @returns
298
- */
299
- static async didRun(prefix: string): Promise<[boolean, number, any]> {
300
- const {
301
- COUNTER,
302
- replay,
303
- workflowDimension,
304
- } = WorkflowService.getContext();
305
- const execIndex = COUNTER.counter = COUNTER.counter + 1;
306
- const sessionId = `-${prefix}${workflowDimension}-${execIndex}-`;
307
- if (sessionId in replay) {
308
- return [true, execIndex, SerializerService.fromString(replay[sessionId])];
309
- }
310
- return [false, execIndex, null];
311
- }
312
-
313
- /**
314
- * Those methods that may only be called once must be protected by flagging
315
- * their execution with a unique key (the key is stored in the HASH alongside
316
- * process state and job state)
317
- * @private
318
- */
319
- static async isSideEffectAllowed(hotMeshClient: HotMesh, prefix: string): Promise<boolean> {
320
- const store = asyncLocalStorage.getStore();
321
- const workflowId = store.get('workflowId');
322
- const workflowDimension = store.get('workflowDimension') ?? '';
323
- const COUNTER = store.get('counter');
324
- const execIndex = COUNTER.counter = COUNTER.counter + 1;
325
- const sessionId = `-${prefix}${workflowDimension}-${execIndex}-`;
326
- const replay = store.get('replay') as StringStringType;
327
- if (sessionId in replay) {
328
- return false;
329
- }
330
- const keyParams = {
331
- appId: hotMeshClient.appId,
332
- jobId: workflowId
333
- }
334
- const workflowGuid = KeyService.mintKey(hotMeshClient.namespace, KeyType.JOB_STATE, keyParams);
335
- const guidValue = Number(await hotMeshClient.engine.store.exec('HINCRBYFLOAT', workflowGuid, sessionId, '1') as string);
336
- return guidValue === 1;
337
- }
338
-
339
374
  /**
340
375
  * Returns a random number between 0 and 1. This number is deterministic
341
376
  * and will never vary for a given seed. This is useful for randomizing
@@ -440,9 +475,7 @@ export class WorkflowService {
440
475
  * Interrupts a running job
441
476
  */
442
477
  static async interrupt(jobId: string, options: JobInterruptOptions = {}): Promise<string | void> {
443
- const store = asyncLocalStorage.getStore();
444
- const workflowTopic = store.get('workflowTopic');
445
- const namespace = store.get('namespace');
478
+ const { workflowTopic, namespace } = WorkflowService.getContext();
446
479
  const hotMeshClient = await WorkerService.getHotMesh(workflowTopic, { namespace });
447
480
  if (await WorkflowService.isSideEffectAllowed(hotMeshClient, 'interrupt')) {
448
481
  return await hotMeshClient.interrupt(`${hotMeshClient.appId}.execute`, jobId, options);
@@ -51,7 +51,8 @@ import {
51
51
  PartialJobState,
52
52
  JobStatus,
53
53
  JobInterruptOptions,
54
- JobCompletionOptions } from '../../types/job';
54
+ JobCompletionOptions,
55
+ ExtensionType} from '../../types/job';
55
56
  import {
56
57
  HotMeshApps,
57
58
  HotMeshConfig,
@@ -566,10 +567,10 @@ class EngineService {
566
567
 
567
568
  // ********************** PUB/SUB ENTRY POINT **********************
568
569
  //publish (returns just the job id)
569
- async pub(topic: string, data: JobData, context?: JobState): Promise<string> {
570
+ async pub(topic: string, data: JobData, context?: JobState, extended?: ExtensionType): Promise<string> {
570
571
  const activityHandler = await this.initActivity(topic, data, context);
571
572
  if (activityHandler) {
572
- return await activityHandler.process();
573
+ return await activityHandler.process(extended);
573
574
  } else {
574
575
  throw new Error(`unable to process activity for topic ${topic}`);
575
576
  }
@@ -12,7 +12,8 @@ import {
12
12
  JobData,
13
13
  JobOutput,
14
14
  JobStatus,
15
- JobInterruptOptions} from '../../types/job';
15
+ JobInterruptOptions,
16
+ ExtensionType} from '../../types/job';
16
17
  import {
17
18
  HotMeshConfig,
18
19
  HotMeshManifest } from '../../types/hotmesh';
@@ -115,8 +116,8 @@ class HotMeshService {
115
116
  }
116
117
 
117
118
  // ************* PUB/SUB METHODS *************
118
- async pub(topic: string, data: JobData = {}, context?: JobState): Promise<string> {
119
- return await this.engine?.pub(topic, data, context);
119
+ async pub(topic: string, data: JobData = {}, context?: JobState, extended?: ExtensionType): Promise<string> {
120
+ return await this.engine?.pub(topic, data, context, extended);
120
121
  }
121
122
  async sub(topic: string, callback: JobMessageCallback): Promise<void> {
122
123
  return await this.engine?.sub(topic, callback);
package/types/durable.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { LogLevel } from './logger';
2
2
  import { RedisClass, RedisOptions } from './redis';
3
- import { StringStringType } from './serializer';
3
+ import { StringAnyType, StringStringType } from './serializer';
4
4
  import { StreamData, StreamError } from './stream';
5
5
 
6
6
  /**
@@ -68,6 +68,16 @@ type WorkflowContext = {
68
68
  */
69
69
  namespace: string;
70
70
 
71
+ /**
72
+ * holds list of interruption payloads; if list is longer than 1 when the error is thrown, a `collator` subflow will be used
73
+ */
74
+ interruptionRegistry: any[];
75
+
76
+ /**
77
+ * entry point ancestor flow; might be the parent; will never be self
78
+ */
79
+ originJobId: string;
80
+
71
81
  /**
72
82
  * the workflow/job ID
73
83
  */
@@ -112,7 +122,7 @@ type WorkflowSearchOptions = {
112
122
  schema?: Record<string, { type: 'TEXT' | 'NUMERIC' | 'TAG', sortable?: boolean }>;
113
123
 
114
124
  /** Additional data as a key-value record */
115
- data?: Record<string, string>;
125
+ data?: StringStringType;
116
126
  }
117
127
 
118
128
 
@@ -173,6 +183,11 @@ type WorkflowOptions = {
173
183
  */
174
184
  search?: WorkflowSearchOptions
175
185
 
186
+ /**
187
+ * marker data (begins with a -)
188
+ */
189
+ marker?: StringStringType
190
+
176
191
  /**
177
192
  * the workflow configuration object
178
193
  */
@@ -235,7 +250,7 @@ type SignalOptions = {
235
250
  /**
236
251
  * Input data for the signal (any serializable object)
237
252
  */
238
- data: Record<string, any>;
253
+ data: StringAnyType;
239
254
 
240
255
  /**
241
256
  * Execution ID, also known as the job ID
package/types/error.ts ADDED
@@ -0,0 +1,52 @@
1
+ export type DurableChildErrorType = {
2
+ arguments: string[],
3
+ await?: boolean,
4
+ backoffCoefficient?: number,
5
+ index: number,
6
+ maximumAttempts?: number,
7
+ maximumInterval?: number,
8
+ originJobId: string | null,
9
+ parentWorkflowId: string,
10
+ workflowDimension: string,
11
+ workflowId: string,
12
+ workflowTopic: string,
13
+ };
14
+
15
+ export type DurableWaitForAllErrorType = {
16
+ items: string[],
17
+ workflowId: string,
18
+ workflowTopic: string,
19
+ parentWorkflowId: string,
20
+ originJobId: string | null,
21
+ size: number,
22
+ index: number,
23
+ workflowDimension: string
24
+ };
25
+
26
+ export type DurableProxyErrorType = {
27
+ arguments: string[],
28
+ activityName: string,
29
+ backoffCoefficient?: number,
30
+ index: number,
31
+ maximumAttempts?: number,
32
+ maximumInterval?: number,
33
+ originJobId: string | null,
34
+ parentWorkflowId: string,
35
+ workflowDimension: string,
36
+ workflowId: string,
37
+ workflowTopic: string,
38
+ };
39
+
40
+ export type DurableWaitForErrorType = {
41
+ signalId: string,
42
+ index: number,
43
+ workflowDimension: string
44
+ workflowId: string;
45
+ };
46
+
47
+ export type DurableSleepErrorType = {
48
+ duration: number,
49
+ index: number,
50
+ workflowDimension: string,
51
+ workflowId: string,
52
+ };
package/types/exporter.ts CHANGED
@@ -2,7 +2,28 @@ import { StringAnyType } from "./serializer";
2
2
 
3
3
  export type ExportItem = [(string | null), string, any];
4
4
 
5
- export interface ExportOptions {};
5
+ /**
6
+ * job export data can be large, particularly transitions the timeline
7
+ */
8
+ export type ExportFields = 'data' | 'state' | 'status' | 'timeline' | 'transitions';
9
+
10
+ export interface ExportOptions {
11
+ /**
12
+ * limit the export byte size by specifying an allowlist
13
+ */
14
+ allow?: Array<ExportFields>;
15
+
16
+ /**
17
+ * limit the export byte size by specifying a block list
18
+ */
19
+ block?: Array<ExportFields>;
20
+
21
+ /**
22
+ * If false, do not return timeline values (like child job response, proxy activity response, etc)
23
+ * @default true
24
+ */
25
+ values?: boolean;
26
+ };
6
27
 
7
28
  export type JobAction = {
8
29
  cursor: number;
@@ -46,26 +67,15 @@ export interface ExportCycles {
46
67
  [key: string]: string[];
47
68
  };
48
69
 
49
- export type IdemParts = {
70
+ export type TimelineType = {
71
+ key: string;
72
+ value: Record<string, any> | string | number | null;
50
73
  index: number;
51
74
  secondary?: number;
52
75
  dimension?: string;
53
76
  };
54
77
 
55
- export type IdemType = {
56
- key: string;
57
- value: string;
58
- parts: IdemParts;
59
- };
60
-
61
- export interface TimelineEntry {
62
- activity: string;
63
- dimensions: string;
64
- created: string;
65
- updated: string;
66
- }
67
-
68
- export interface TimestampParts {
78
+ export interface TransitionType {
69
79
  activity: string;
70
80
  dimensions: string;
71
81
  created: string;
@@ -73,13 +83,11 @@ export interface TimestampParts {
73
83
  }
74
84
 
75
85
  export interface DurableJobExport {
76
- data: StringAnyType;
77
- dependencies?: Record<string, any>[];
78
- state: StringAnyType;
79
- status: string;
80
- timeline?: JobTimeline[];
81
- idempotents: IdemType[];
82
- replay: TimestampParts[];
86
+ data?: StringAnyType;
87
+ state?: StringAnyType;
88
+ status?: number;
89
+ timeline?: TimelineType[];
90
+ transitions?: TransitionType[];
83
91
  };
84
92
 
85
93
  export interface JobExport {
package/types/index.ts CHANGED
@@ -51,6 +51,12 @@ export {
51
51
  WorkflowDataType,
52
52
  WorkflowOptions,
53
53
  } from './durable';
54
+ export {
55
+ DurableChildErrorType,
56
+ DurableProxyErrorType,
57
+ DurableSleepErrorType,
58
+ DurableWaitForAllErrorType,
59
+ DurableWaitForErrorType } from "./error";
54
60
  export {
55
61
  ActivityAction,
56
62
  DependencyExport,
@@ -83,7 +89,8 @@ export {
83
89
  JobOutput,
84
90
  JobState,
85
91
  JobStatus,
86
- PartialJobState } from './job';
92
+ PartialJobState,
93
+ ExtensionType } from './job';
87
94
  export { MappingStatements } from './map';
88
95
  export {
89
96
  Pipe,
package/types/job.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { StringStringType } from "./serializer";
2
+
1
3
  type JobData = Record<string, unknown|Record<string, unknown>>;
2
4
  type JobsData = Record<string, unknown>;
3
5
 
@@ -82,6 +84,30 @@ type JobMetadata = {
82
84
  expire?: number;
83
85
  };
84
86
 
87
+ /**
88
+ * User-defined (extended) types for job data. Users may interleave
89
+ * data into the job hash safely by using the `ExtensionType` interface.
90
+ * The data will be prefixed as necessary using an underscore or
91
+ * dash to ensure it is not confused with system process data.
92
+ */
93
+ type ExtensionType = {
94
+ /**
95
+ * Custom search data field (name/value pairs) to seed the Hash.
96
+ * Every field will be prefixed with an underscore before being
97
+ * stored with the initial Hash data set along side system
98
+ * process data.
99
+ */
100
+ search?: StringStringType;
101
+
102
+ /**
103
+ * Custom marker data field used for adding a searchable marker to the job.
104
+ * markers always begin with a dash (-). Any field that does not
105
+ * begin with a dash will be removed and will not be inserted with
106
+ * the initial data set.
107
+ */
108
+ marker?: StringStringType;
109
+ }
110
+
85
111
  /**
86
112
  * job_status semaphore
87
113
  */
@@ -183,4 +209,5 @@ export {
183
209
  JobState,
184
210
  JobStatus,
185
211
  PartialJobState,
212
+ ExtensionType,
186
213
  };