@workflow/core 4.0.1-beta.9 → 4.1.0-beta.51
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/dist/builtins.js +1 -1
- package/dist/class-serialization.d.ts +26 -0
- package/dist/class-serialization.d.ts.map +1 -0
- package/dist/class-serialization.js +66 -0
- package/dist/create-hook.js +1 -1
- package/dist/define-hook.d.ts +40 -25
- package/dist/define-hook.d.ts.map +1 -1
- package/dist/define-hook.js +22 -27
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +5 -1
- package/dist/flushable-stream.d.ts +82 -0
- package/dist/flushable-stream.d.ts.map +1 -0
- package/dist/flushable-stream.js +214 -0
- package/dist/global.d.ts +4 -1
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js +21 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/logger.js +1 -1
- package/dist/observability.d.ts +60 -0
- package/dist/observability.d.ts.map +1 -1
- package/dist/observability.js +265 -32
- package/dist/private.d.ts +10 -1
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +6 -1
- package/dist/runtime/helpers.d.ts +52 -0
- package/dist/runtime/helpers.d.ts.map +1 -0
- package/dist/runtime/helpers.js +264 -0
- package/dist/runtime/resume-hook.d.ts +17 -12
- package/dist/runtime/resume-hook.d.ts.map +1 -1
- package/dist/runtime/resume-hook.js +79 -64
- package/dist/runtime/start.d.ts +14 -0
- package/dist/runtime/start.d.ts.map +1 -1
- package/dist/runtime/start.js +71 -45
- package/dist/runtime/step-handler.d.ts +7 -0
- package/dist/runtime/step-handler.d.ts.map +1 -0
- package/dist/runtime/step-handler.js +337 -0
- package/dist/runtime/suspension-handler.d.ts +25 -0
- package/dist/runtime/suspension-handler.d.ts.map +1 -0
- package/dist/runtime/suspension-handler.js +182 -0
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +20 -21
- package/dist/runtime.d.ts +3 -7
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +103 -411
- package/dist/schemas.d.ts +1 -15
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +2 -15
- package/dist/serialization.d.ts +112 -21
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +469 -85
- package/dist/sleep.d.ts +10 -0
- package/dist/sleep.d.ts.map +1 -1
- package/dist/sleep.js +1 -1
- package/dist/source-map.d.ts +10 -0
- package/dist/source-map.d.ts.map +1 -0
- package/dist/source-map.js +56 -0
- package/dist/step/context-storage.d.ts +2 -1
- package/dist/step/context-storage.d.ts.map +1 -1
- package/dist/step/context-storage.js +1 -1
- package/dist/step/get-closure-vars.d.ts +9 -0
- package/dist/step/get-closure-vars.d.ts.map +1 -0
- package/dist/step/get-closure-vars.js +16 -0
- package/dist/step/get-step-metadata.js +1 -1
- package/dist/step/get-workflow-metadata.js +1 -1
- package/dist/step/writable-stream.d.ts +10 -2
- package/dist/step/writable-stream.d.ts.map +1 -1
- package/dist/step/writable-stream.js +6 -5
- package/dist/step.d.ts +1 -1
- package/dist/step.d.ts.map +1 -1
- package/dist/step.js +93 -47
- package/dist/symbols.d.ts +6 -0
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +7 -1
- package/dist/telemetry/semantic-conventions.d.ts +66 -38
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +16 -3
- package/dist/telemetry.d.ts +8 -4
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +39 -6
- package/dist/types.js +1 -1
- package/dist/util.d.ts +5 -24
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +19 -38
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/vm/index.js +2 -2
- package/dist/vm/uuid.js +1 -1
- package/dist/workflow/create-hook.js +1 -1
- package/dist/workflow/define-hook.d.ts +3 -3
- package/dist/workflow/define-hook.d.ts.map +1 -1
- package/dist/workflow/define-hook.js +1 -1
- package/dist/workflow/get-workflow-metadata.js +1 -1
- package/dist/workflow/hook.d.ts.map +1 -1
- package/dist/workflow/hook.js +49 -14
- package/dist/workflow/index.d.ts +1 -1
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +2 -2
- package/dist/workflow/sleep.d.ts +1 -1
- package/dist/workflow/sleep.d.ts.map +1 -1
- package/dist/workflow/sleep.js +26 -39
- package/dist/workflow/writable-stream.d.ts +1 -1
- package/dist/workflow/writable-stream.d.ts.map +1 -1
- package/dist/workflow/writable-stream.js +1 -1
- package/dist/workflow.d.ts +1 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +72 -9
- package/docs/api-reference/create-hook.mdx +133 -0
- package/docs/api-reference/create-webhook.mdx +225 -0
- package/docs/api-reference/define-hook.mdx +206 -0
- package/docs/api-reference/fatal-error.mdx +37 -0
- package/docs/api-reference/fetch.mdx +139 -0
- package/docs/api-reference/get-step-metadata.mdx +76 -0
- package/docs/api-reference/get-workflow-metadata.mdx +44 -0
- package/docs/api-reference/get-writable.mdx +292 -0
- package/docs/api-reference/index.mdx +55 -0
- package/docs/api-reference/meta.json +3 -0
- package/docs/api-reference/retryable-error.mdx +106 -0
- package/docs/api-reference/sleep.mdx +59 -0
- package/docs/foundations/common-patterns.mdx +253 -0
- package/docs/foundations/errors-and-retries.mdx +190 -0
- package/docs/foundations/hooks.mdx +455 -0
- package/docs/foundations/idempotency.mdx +55 -0
- package/docs/foundations/index.mdx +32 -0
- package/docs/foundations/meta.json +14 -0
- package/docs/foundations/serialization.mdx +157 -0
- package/docs/foundations/starting-workflows.mdx +211 -0
- package/docs/foundations/streaming.mdx +569 -0
- package/docs/foundations/workflows-and-steps.mdx +197 -0
- package/docs/how-it-works/code-transform.mdx +334 -0
- package/docs/how-it-works/event-sourcing.mdx +254 -0
- package/docs/how-it-works/framework-integrations.mdx +437 -0
- package/docs/how-it-works/meta.json +10 -0
- package/docs/how-it-works/understanding-directives.mdx +611 -0
- package/package.json +31 -25
- package/dist/builtins.js.map +0 -1
- package/dist/create-hook.js.map +0 -1
- package/dist/define-hook.js.map +0 -1
- package/dist/events-consumer.js.map +0 -1
- package/dist/global.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/observability.js.map +0 -1
- package/dist/parse-name.d.ts +0 -25
- package/dist/parse-name.d.ts.map +0 -1
- package/dist/parse-name.js +0 -40
- package/dist/parse-name.js.map +0 -1
- package/dist/private.js.map +0 -1
- package/dist/runtime/resume-hook.js.map +0 -1
- package/dist/runtime/start.js.map +0 -1
- package/dist/runtime/world.js.map +0 -1
- package/dist/runtime.js.map +0 -1
- package/dist/schemas.js.map +0 -1
- package/dist/serialization.js.map +0 -1
- package/dist/sleep.js.map +0 -1
- package/dist/step/context-storage.js.map +0 -1
- package/dist/step/get-step-metadata.js.map +0 -1
- package/dist/step/get-workflow-metadata.js.map +0 -1
- package/dist/step/writable-stream.js.map +0 -1
- package/dist/step.js.map +0 -1
- package/dist/symbols.js.map +0 -1
- package/dist/telemetry/semantic-conventions.js.map +0 -1
- package/dist/telemetry.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/util.js.map +0 -1
- package/dist/vm/index.js.map +0 -1
- package/dist/vm/uuid.js.map +0 -1
- package/dist/workflow/create-hook.js.map +0 -1
- package/dist/workflow/define-hook.js.map +0 -1
- package/dist/workflow/get-workflow-metadata.js.map +0 -1
- package/dist/workflow/hook.js.map +0 -1
- package/dist/workflow/index.js.map +0 -1
- package/dist/workflow/sleep.js.map +0 -1
- package/dist/workflow/writable-stream.js.map +0 -1
- package/dist/workflow.js.map +0 -1
- package/dist/writable-stream.d.ts +0 -23
- package/dist/writable-stream.d.ts.map +0 -1
- package/dist/writable-stream.js +0 -17
- package/dist/writable-stream.js.map +0 -1
package/dist/workflow/hook.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { withResolvers } from '@workflow/utils';
|
|
1
2
|
import { EventConsumerResult } from '../events-consumer.js';
|
|
2
3
|
import { WorkflowSuspension } from '../global.js';
|
|
3
4
|
import { webhookLogger } from '../logger.js';
|
|
4
5
|
import { hydrateStepReturnValue } from '../serialization.js';
|
|
5
|
-
import {
|
|
6
|
+
import { ERROR_SLUGS, WorkflowRuntimeError } from '@workflow/errors';
|
|
6
7
|
export function createCreateHook(ctx) {
|
|
7
8
|
return function createHookImpl(options = {}) {
|
|
8
9
|
// Generate hook ID and token
|
|
9
10
|
const correlationId = `hook_${ctx.generateUlid()}`;
|
|
10
11
|
const token = options.token ?? ctx.generateNanoid();
|
|
11
|
-
// Add hook creation to invocations queue
|
|
12
|
-
ctx.invocationsQueue.
|
|
12
|
+
// Add hook creation to invocations queue (using Map for O(1) operations)
|
|
13
|
+
ctx.invocationsQueue.set(correlationId, {
|
|
13
14
|
type: 'hook',
|
|
14
15
|
correlationId,
|
|
15
16
|
token,
|
|
@@ -20,6 +21,9 @@ export function createCreateHook(ctx) {
|
|
|
20
21
|
// Queue of promises that resolve to the next hook payload
|
|
21
22
|
const promises = [];
|
|
22
23
|
let eventLogEmpty = false;
|
|
24
|
+
// Track if we have a conflict so we can reject future awaits
|
|
25
|
+
let hasConflict = false;
|
|
26
|
+
let conflictErrorRef = null;
|
|
23
27
|
webhookLogger.debug('Hook consumer setup', { correlationId, token });
|
|
24
28
|
ctx.eventsConsumer.subscribe((event) => {
|
|
25
29
|
// If there are no events and there are promises waiting,
|
|
@@ -31,21 +35,37 @@ export function createCreateHook(ctx) {
|
|
|
31
35
|
setTimeout(() => {
|
|
32
36
|
ctx.onWorkflowError(new WorkflowSuspension(ctx.invocationsQueue, ctx.globalThis));
|
|
33
37
|
}, 0);
|
|
34
|
-
return EventConsumerResult.Finished;
|
|
35
38
|
}
|
|
39
|
+
return EventConsumerResult.NotConsumed;
|
|
40
|
+
}
|
|
41
|
+
if (event.correlationId !== correlationId) {
|
|
42
|
+
// We're not interested in this event - the correlationId belongs to a different entity
|
|
43
|
+
return EventConsumerResult.NotConsumed;
|
|
36
44
|
}
|
|
37
45
|
// Check for hook_created event to remove this hook from the queue if it was already created
|
|
38
|
-
if (event
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
if (event.eventType === 'hook_created') {
|
|
47
|
+
// Remove this hook from the invocations queue (O(1) delete using Map)
|
|
48
|
+
ctx.invocationsQueue.delete(correlationId);
|
|
49
|
+
return EventConsumerResult.Consumed;
|
|
50
|
+
}
|
|
51
|
+
// Handle hook_conflict event - another workflow is using this token
|
|
52
|
+
if (event.eventType === 'hook_conflict') {
|
|
53
|
+
// Remove this hook from the invocations queue
|
|
54
|
+
ctx.invocationsQueue.delete(correlationId);
|
|
55
|
+
// Store the conflict event so we can reject any awaited promises
|
|
56
|
+
const conflictEvent = event;
|
|
57
|
+
const conflictError = new WorkflowRuntimeError(`Hook token "${conflictEvent.eventData.token}" is already in use by another workflow`, { slug: ERROR_SLUGS.HOOK_CONFLICT });
|
|
58
|
+
// Reject any pending promises
|
|
59
|
+
for (const resolver of promises) {
|
|
60
|
+
resolver.reject(conflictError);
|
|
44
61
|
}
|
|
62
|
+
promises.length = 0;
|
|
63
|
+
// Mark that we have a conflict so future awaits also reject
|
|
64
|
+
hasConflict = true;
|
|
65
|
+
conflictErrorRef = conflictError;
|
|
45
66
|
return EventConsumerResult.Consumed;
|
|
46
67
|
}
|
|
47
|
-
if (event
|
|
48
|
-
event.correlationId === correlationId) {
|
|
68
|
+
if (event.eventType === 'hook_received') {
|
|
49
69
|
if (promises.length > 0) {
|
|
50
70
|
const next = promises.shift();
|
|
51
71
|
if (next) {
|
|
@@ -59,11 +79,26 @@ export function createCreateHook(ctx) {
|
|
|
59
79
|
}
|
|
60
80
|
return EventConsumerResult.Consumed;
|
|
61
81
|
}
|
|
62
|
-
|
|
82
|
+
if (event.eventType === 'hook_disposed') {
|
|
83
|
+
// If a hook is explicitly disposed, we're done processing any more
|
|
84
|
+
// events for it
|
|
85
|
+
return EventConsumerResult.Finished;
|
|
86
|
+
}
|
|
87
|
+
// An unexpected event type has been received, this event log looks corrupted. Let's fail immediately.
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
ctx.onWorkflowError(new WorkflowRuntimeError(`Unexpected event type for hook ${correlationId} (token: ${token}) "${event.eventType}"`));
|
|
90
|
+
}, 0);
|
|
91
|
+
return EventConsumerResult.Finished;
|
|
63
92
|
});
|
|
64
93
|
// Helper function to create a new promise that waits for the next hook payload
|
|
65
94
|
function createHookPromise() {
|
|
66
95
|
const resolvers = withResolvers();
|
|
96
|
+
// If we have a conflict, reject immediately
|
|
97
|
+
// This handles the iterator case where each await should reject
|
|
98
|
+
if (hasConflict && conflictErrorRef) {
|
|
99
|
+
resolvers.reject(conflictErrorRef);
|
|
100
|
+
return resolvers.promise;
|
|
101
|
+
}
|
|
67
102
|
if (payloadsQueue.length > 0) {
|
|
68
103
|
const nextPayload = payloadsQueue.shift();
|
|
69
104
|
if (nextPayload) {
|
|
@@ -98,4 +133,4 @@ export function createCreateHook(ctx) {
|
|
|
98
133
|
return hook;
|
|
99
134
|
};
|
|
100
135
|
}
|
|
101
|
-
//# sourceMappingURL=
|
|
136
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaG9vay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93b3JrZmxvdy9ob29rLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBNkIsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFHM0UsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ2xELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFN0MsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFdBQVcsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRXJFLE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxHQUFnQztJQUMvRCxPQUFPLFNBQVMsY0FBYyxDQUFVLFVBQXVCLEVBQUU7UUFDL0QsNkJBQTZCO1FBQzdCLE1BQU0sYUFBYSxHQUFHLFFBQVEsR0FBRyxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUM7UUFDbkQsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssSUFBSSxHQUFHLENBQUMsY0FBYyxFQUFFLENBQUM7UUFFcEQseUVBQXlFO1FBQ3pFLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFO1lBQ3RDLElBQUksRUFBRSxNQUFNO1lBQ1osYUFBYTtZQUNiLEtBQUs7WUFDTCxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7U0FDM0IsQ0FBQyxDQUFDO1FBRUgscUVBQXFFO1FBQ3JFLE1BQU0sYUFBYSxHQUF3QixFQUFFLENBQUM7UUFFOUMsMERBQTBEO1FBQzFELE1BQU0sUUFBUSxHQUE4QixFQUFFLENBQUM7UUFFL0MsSUFBSSxhQUFhLEdBQUcsS0FBSyxDQUFDO1FBRTFCLDZEQUE2RDtRQUM3RCxJQUFJLFdBQVcsR0FBRyxLQUFLLENBQUM7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
|
package/dist/workflow/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { StepMetadata } from '../step/get-step-metadata.js';
|
|
2
2
|
export { FatalError, RetryableError, type RetryableErrorOptions, } from '@workflow/errors';
|
|
3
3
|
export type { Hook, HookOptions } from '../create-hook.js';
|
|
4
|
+
export { sleep } from '../sleep.js';
|
|
4
5
|
export { createHook, createWebhook } from './create-hook.js';
|
|
5
6
|
export { defineHook } from './define-hook.js';
|
|
6
7
|
export { getWorkflowMetadata } from './get-workflow-metadata.js';
|
|
7
|
-
export { sleep } from '../sleep.js';
|
|
8
8
|
export { getWritable } from './writable-stream.js';
|
|
9
9
|
export declare function getStepMetadata(): StepMetadata;
|
|
10
10
|
export declare function resumeHook(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workflow/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EACL,UAAU,EACV,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workflow/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EACL,UAAU,EACV,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAInD,wBAAgB,eAAe,IAAI,YAAY,CAI9C;AACD,wBAAgB,UAAU,SAIzB"}
|
package/dist/workflow/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { FatalError, RetryableError, } from '@workflow/errors';
|
|
2
|
+
export { sleep } from '../sleep.js';
|
|
2
3
|
export { createHook, createWebhook } from './create-hook.js';
|
|
3
4
|
export { defineHook } from './define-hook.js';
|
|
4
5
|
export { getWorkflowMetadata } from './get-workflow-metadata.js';
|
|
5
|
-
export { sleep } from '../sleep.js';
|
|
6
6
|
export { getWritable } from './writable-stream.js';
|
|
7
7
|
// workflows can't use these functions, but we still need to provide
|
|
8
8
|
// the export so bundling doesn't fail when step and workflow are in same file
|
|
@@ -12,4 +12,4 @@ export function getStepMetadata() {
|
|
|
12
12
|
export function resumeHook() {
|
|
13
13
|
throw new Error('`resumeHook()` can only be called from outside a workflow function');
|
|
14
14
|
}
|
|
15
|
-
//# sourceMappingURL=
|
|
15
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2Zsb3cvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUNMLFVBQVUsRUFDVixjQUFjLEdBRWYsTUFBTSxrQkFBa0IsQ0FBQztBQUUxQixPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxVQUFVLEVBQUUsYUFBYSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVuRCxvRUFBb0U7QUFDcEUsOEVBQThFO0FBQzlFLE1BQU0sVUFBVSxlQUFlO0lBQzdCLE1BQU0sSUFBSSxLQUFLLENBQ2IsK0RBQStELENBQ2hFLENBQUM7QUFDSixDQUFDO0FBQ0QsTUFBTSxVQUFVLFVBQVU7SUFDeEIsTUFBTSxJQUFJLEtBQUssQ0FDYixvRUFBb0UsQ0FDckUsQ0FBQztBQUNKLENBQUMifQ==
|
package/dist/workflow/sleep.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { StringValue } from 'ms';
|
|
2
2
|
import type { WorkflowOrchestratorContext } from '../private.js';
|
|
3
|
-
export declare function createSleep(ctx: WorkflowOrchestratorContext): (param: StringValue | Date) => Promise<void>;
|
|
3
|
+
export declare function createSleep(ctx: WorkflowOrchestratorContext): (param: StringValue | Date | number) => Promise<void>;
|
|
4
4
|
//# sourceMappingURL=sleep.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/workflow/sleep.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/workflow/sleep.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AAGtC,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAGjE,wBAAgB,WAAW,CAAC,GAAG,EAAE,2BAA2B,IAExD,OAAO,WAAW,GAAG,IAAI,GAAG,MAAM,KACjC,OAAO,CAAC,IAAI,CAAC,CAqEjB"}
|
package/dist/workflow/sleep.js
CHANGED
|
@@ -1,37 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { parseDurationToDate, withResolvers } from '@workflow/utils';
|
|
2
2
|
import { EventConsumerResult } from '../events-consumer.js';
|
|
3
3
|
import { WorkflowSuspension } from '../global.js';
|
|
4
|
-
import {
|
|
4
|
+
import { WorkflowRuntimeError } from '@workflow/errors';
|
|
5
5
|
export function createSleep(ctx) {
|
|
6
6
|
return async function sleepImpl(param) {
|
|
7
7
|
const { promise, resolve } = withResolvers();
|
|
8
8
|
const correlationId = `wait_${ctx.generateUlid()}`;
|
|
9
9
|
// Calculate the resume time
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (typeof durationMs !== 'number' || durationMs < 0) {
|
|
14
|
-
throw new Error(`Invalid sleep duration: "${param}". Expected a valid duration string like "1s", "1m", "1h", etc.`);
|
|
15
|
-
}
|
|
16
|
-
resumeAt = new Date(Date.now() + durationMs);
|
|
17
|
-
}
|
|
18
|
-
else if (param instanceof Date ||
|
|
19
|
-
(param &&
|
|
20
|
-
typeof param === 'object' &&
|
|
21
|
-
typeof param.getTime === 'function')) {
|
|
22
|
-
// Handle both Date instances and date-like objects (from deserialization)
|
|
23
|
-
const dateParam = param instanceof Date ? param : new Date(param.getTime());
|
|
24
|
-
resumeAt = dateParam;
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
throw new Error(`Invalid sleep parameter. Expected a duration string or Date object.`);
|
|
28
|
-
}
|
|
29
|
-
// Add wait to invocations queue
|
|
30
|
-
ctx.invocationsQueue.push({
|
|
10
|
+
const resumeAt = parseDurationToDate(param);
|
|
11
|
+
// Add wait to invocations queue (using Map for O(1) operations)
|
|
12
|
+
const waitItem = {
|
|
31
13
|
type: 'wait',
|
|
32
14
|
correlationId,
|
|
33
15
|
resumeAt,
|
|
34
|
-
}
|
|
16
|
+
};
|
|
17
|
+
ctx.invocationsQueue.set(correlationId, waitItem);
|
|
35
18
|
ctx.eventsConsumer.subscribe((event) => {
|
|
36
19
|
// If there are no events and we're waiting for wait_completed,
|
|
37
20
|
// suspend the workflow until the wait fires
|
|
@@ -41,34 +24,38 @@ export function createSleep(ctx) {
|
|
|
41
24
|
}, 0);
|
|
42
25
|
return EventConsumerResult.NotConsumed;
|
|
43
26
|
}
|
|
27
|
+
if (event.correlationId !== correlationId) {
|
|
28
|
+
// We're not interested in this event - the correlationId belongs to a different entity
|
|
29
|
+
return EventConsumerResult.NotConsumed;
|
|
30
|
+
}
|
|
44
31
|
// Check for wait_created event to mark this wait as having the event created
|
|
45
|
-
if (event
|
|
46
|
-
event.correlationId === correlationId) {
|
|
32
|
+
if (event.eventType === 'wait_created') {
|
|
47
33
|
// Mark this wait as having the created event, but keep it in the queue
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
34
|
+
// O(1) lookup using Map
|
|
35
|
+
const queueItem = ctx.invocationsQueue.get(correlationId);
|
|
36
|
+
if (queueItem && queueItem.type === 'wait') {
|
|
37
|
+
queueItem.hasCreatedEvent = true;
|
|
38
|
+
queueItem.resumeAt = event.eventData.resumeAt;
|
|
52
39
|
}
|
|
53
40
|
return EventConsumerResult.Consumed;
|
|
54
41
|
}
|
|
55
42
|
// Check for wait_completed event
|
|
56
|
-
if (event
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const index = ctx.invocationsQueue.findIndex((item) => item.type === 'wait' && item.correlationId === correlationId);
|
|
60
|
-
if (index !== -1) {
|
|
61
|
-
ctx.invocationsQueue.splice(index, 1);
|
|
62
|
-
}
|
|
43
|
+
if (event.eventType === 'wait_completed') {
|
|
44
|
+
// Remove this wait from the invocations queue (O(1) delete using Map)
|
|
45
|
+
ctx.invocationsQueue.delete(correlationId);
|
|
63
46
|
// Wait has elapsed, resolve the sleep
|
|
64
47
|
setTimeout(() => {
|
|
65
48
|
resolve();
|
|
66
49
|
}, 0);
|
|
67
50
|
return EventConsumerResult.Finished;
|
|
68
51
|
}
|
|
69
|
-
|
|
52
|
+
// An unexpected event type has been received, this event log looks corrupted. Let's fail immediately.
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
ctx.onWorkflowError(new WorkflowRuntimeError(`Unexpected event type for wait ${correlationId} "${event.eventType}"`));
|
|
55
|
+
}, 0);
|
|
56
|
+
return EventConsumerResult.Finished;
|
|
70
57
|
});
|
|
71
58
|
return promise;
|
|
72
59
|
};
|
|
73
60
|
}
|
|
74
|
-
//# sourceMappingURL=
|
|
61
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2xlZXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvd29ya2Zsb3cvc2xlZXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRXJFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzVELE9BQU8sRUFBZ0Msa0JBQWtCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFaEYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFeEQsTUFBTSxVQUFVLFdBQVcsQ0FBQyxHQUFnQztJQUMxRCxPQUFPLEtBQUssVUFBVSxTQUFTLENBQzdCLEtBQWtDO1FBRWxDLE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLEdBQUcsYUFBYSxFQUFRLENBQUM7UUFDbkQsTUFBTSxhQUFhLEdBQUcsUUFBUSxHQUFHLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQztRQUVuRCw0QkFBNEI7UUFDNUIsTUFBTSxRQUFRLEdBQUcsbUJBQW1CLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFNUMsZ0VBQWdFO1FBQ2hFLE1BQU0sUUFBUSxHQUE0QjtZQUN4QyxJQUFJLEVBQUUsTUFBTTtZQUNaLGFBQWE7WUFDYixRQUFRO1NBQ1QsQ0FBQztRQUNGLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRWxELEdBQUcsQ0FBQyxjQUFjLENBQUMsU0FBUyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDckMsK0RBQStEO1lBQy9ELDRDQUE0QztZQUM1QyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ1gsVUFBVSxDQUFDLEdBQUcsRUFBRTtvQkFDZCxHQUFHLENBQUMsZUFBZSxDQUNqQixJQUFJLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLENBQUMsVUFBVSxDQUFDLENBQzdELENBQUM7Z0JBQ0osQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUNOLE9BQU8sbUJBQW1CLENBQUMsV0FBVyxDQUFDO1lBQ3pDLENBQUM7WUFFRCxJQUFJLEtBQUssQ0FBQyxhQUFhLEtBQUssYUFBYSxFQUFFLENBQUM7Z0JBQzFDLHVGQUF1RjtnQkFDdkYsT0FBTyxtQkFBbUIsQ0FBQyxXQUFXLENBQUM7WUFDekMsQ0FBQztZQUVELDZFQUE2RTtZQUM3RSxJQUFJLEtBQUssQ0FBQyxTQUFTLEtBQUssY0FBYyxFQUFFLENBQUM7Z0JBQ3ZDLHVFQUF1RTtnQkFDdkUsd0JBQXdCO2dCQUN4QixNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUMxRCxJQUFJLFNBQVMsSUFBSSxTQUFTLENBQUMsSUFBSSxLQUFLLE1BQU0sRUFBRSxDQUFDO29CQUMzQyxTQUFTLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQztvQkFDakMsU0FBUyxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQztnQkFDaEQsQ0FBQztnQkFDRCxPQUFPLG1CQUFtQixDQUFDLFFBQVEsQ0FBQztZQUN0QyxDQUFDO1lBRUQsaUNBQWlDO1lBQ2pDLElBQUksS0FBSyxDQUFDLFNBQVMsS0FBSyxnQkFBZ0IsRUFBRSxDQUFDO2dCQUN6QyxzRUFBc0U7Z0JBQ3RFLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7Z0JBRTNDLHNDQUFzQztnQkFDdEMsVUFBVSxDQUFDLEdBQUcsRUFBRTtvQkFDZCxPQUFPLEVBQUUsQ0FBQztnQkFDWixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7Z0JBQ04sT0FBTyxtQkFBbUIsQ0FBQyxRQUFRLENBQUM7WUFDdEMsQ0FBQztZQUVELHNHQUFzRztZQUN0RyxVQUFVLENBQUMsR0FBRyxFQUFFO2dCQUNkLEdBQUcsQ0FBQyxlQUFlLENBQ2pCLElBQUksb0JBQW9CLENBQ3RCLGtDQUFrQyxhQUFhLEtBQUssS0FBSyxDQUFDLFNBQVMsR0FBRyxDQUN2RSxDQUNGLENBQUM7WUFDSixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDTixPQUFPLG1CQUFtQixDQUFDLFFBQVEsQ0FBQztRQUN0QyxDQUFDLENBQUMsQ0FBQztRQUVILE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUMsQ0FBQztBQUNKLENBQUMifQ==
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { WorkflowWritableStreamOptions } from '../writable-stream.js';
|
|
1
|
+
import type { WorkflowWritableStreamOptions } from '../step/writable-stream.js';
|
|
2
2
|
export declare function getWritable<W = any>(options?: WorkflowWritableStreamOptions): WritableStream<W>;
|
|
3
3
|
//# sourceMappingURL=writable-stream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writable-stream.d.ts","sourceRoot":"","sources":["../../src/workflow/writable-stream.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"writable-stream.d.ts","sourceRoot":"","sources":["../../src/workflow/writable-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAGhF,wBAAgB,WAAW,CAAC,CAAC,GAAG,GAAG,EACjC,OAAO,GAAE,6BAAkC,GAC1C,cAAc,CAAC,CAAC,CAAC,CASnB"}
|
|
@@ -9,4 +9,4 @@ export function getWritable(options = {}) {
|
|
|
9
9
|
},
|
|
10
10
|
});
|
|
11
11
|
}
|
|
12
|
-
//# sourceMappingURL=
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JpdGFibGUtc3RyZWFtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dvcmtmbG93L3dyaXRhYmxlLXN0cmVhbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFM0UsTUFBTSxVQUFVLFdBQVcsQ0FDekIsVUFBeUMsRUFBRTtJQUUzQyxNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsT0FBTyxDQUFDO0lBQzlCLE1BQU0sSUFBSSxHQUFJLFVBQWtCLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNwRSxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLGNBQWMsQ0FBQyxTQUFTLEVBQUU7UUFDeEQsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFO1lBQ3BCLEtBQUssRUFBRSxJQUFJO1lBQ1gsUUFBUSxFQUFFLEtBQUs7U0FDaEI7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDIn0=
|
package/dist/workflow.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Event, WorkflowRun } from '@workflow/world';
|
|
2
|
-
export declare function runWorkflow(workflowCode: string, workflowRun: WorkflowRun, events: Event[]): Promise<unknown>;
|
|
2
|
+
export declare function runWorkflow(workflowCode: string, workflowRun: WorkflowRun, events: Event[]): Promise<Uint8Array | unknown>;
|
|
3
3
|
//# sourceMappingURL=workflow.d.ts.map
|
package/dist/workflow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA4B1D,wBAAsB,WAAW,CAC/B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,KAAK,EAAE,GACd,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,CAimB/B"}
|
package/dist/workflow.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { runInContext } from 'node:vm';
|
|
2
|
-
import { ERROR_SLUGS } from '@workflow/errors';
|
|
2
|
+
import { ERROR_SLUGS, WorkflowRuntimeError } from '@workflow/errors';
|
|
3
|
+
import { withResolvers } from '@workflow/utils';
|
|
4
|
+
import { getPort } from '@workflow/utils/get-port';
|
|
5
|
+
import { parseWorkflowName } from '@workflow/utils/parse-name';
|
|
3
6
|
import * as nanoid from 'nanoid';
|
|
4
7
|
import { monotonicFactory } from 'ulid';
|
|
5
8
|
import { EventConsumerResult, EventsConsumer } from './events-consumer.js';
|
|
6
9
|
import { ENOTSUP } from './global.js';
|
|
7
10
|
import { dehydrateWorkflowReturnValue, hydrateWorkflowArguments, } from './serialization.js';
|
|
8
11
|
import { createUseStep } from './step.js';
|
|
9
|
-
import { BODY_INIT_SYMBOL, WORKFLOW_CREATE_HOOK, WORKFLOW_GET_STREAM_ID, WORKFLOW_SLEEP, WORKFLOW_USE_STEP, } from './symbols.js';
|
|
12
|
+
import { BODY_INIT_SYMBOL, STABLE_ULID, WORKFLOW_CREATE_HOOK, WORKFLOW_GET_STREAM_ID, WORKFLOW_SLEEP, WORKFLOW_USE_STEP, } from './symbols.js';
|
|
10
13
|
import * as Attribute from './telemetry/semantic-conventions.js';
|
|
11
14
|
import { trace } from './telemetry.js';
|
|
12
|
-
import { getWorkflowRunStreamId
|
|
15
|
+
import { getWorkflowRunStreamId } from './util.js';
|
|
13
16
|
import { createContext } from './vm/index.js';
|
|
14
17
|
import { WORKFLOW_CONTEXT_SYMBOL } from './workflow/get-workflow-metadata.js';
|
|
15
18
|
import { createCreateHook } from './workflow/hook.js';
|
|
@@ -26,6 +29,9 @@ export async function runWorkflow(workflowCode, workflowRun, events) {
|
|
|
26
29
|
if (!startedAt) {
|
|
27
30
|
throw new Error(`Workflow run "${workflowRun.runId}" has no "startedAt" timestamp (should not happen)`);
|
|
28
31
|
}
|
|
32
|
+
// Get the port before creating VM context to avoid async operations
|
|
33
|
+
// affecting the deterministic timestamp
|
|
34
|
+
const port = await getPort();
|
|
29
35
|
const { context, globalThis: vmGlobalThis, updateTimestamp, } = createContext({
|
|
30
36
|
seed: workflowRun.runId,
|
|
31
37
|
fixedTimestamp: +startedAt,
|
|
@@ -39,7 +45,7 @@ export async function runWorkflow(workflowCode, workflowRun, events) {
|
|
|
39
45
|
eventsConsumer: new EventsConsumer(events),
|
|
40
46
|
generateUlid: () => ulid(+startedAt),
|
|
41
47
|
generateNanoid,
|
|
42
|
-
invocationsQueue:
|
|
48
|
+
invocationsQueue: new Map(),
|
|
43
49
|
};
|
|
44
50
|
// Subscribe to the events log to update the timestamp in the vm context
|
|
45
51
|
workflowContext.eventsConsumer.subscribe((event) => {
|
|
@@ -50,6 +56,23 @@ export async function runWorkflow(workflowCode, workflowRun, events) {
|
|
|
50
56
|
// Never consume events - this is only a passive subscriber
|
|
51
57
|
return EventConsumerResult.NotConsumed;
|
|
52
58
|
});
|
|
59
|
+
// Consume run lifecycle events - these are structural events that don't
|
|
60
|
+
// need special handling in the workflow, but must be consumed to advance
|
|
61
|
+
// past them in the event log
|
|
62
|
+
workflowContext.eventsConsumer.subscribe((event) => {
|
|
63
|
+
if (!event) {
|
|
64
|
+
return EventConsumerResult.NotConsumed;
|
|
65
|
+
}
|
|
66
|
+
// Consume run_created - every run has exactly one
|
|
67
|
+
if (event.eventType === 'run_created') {
|
|
68
|
+
return EventConsumerResult.Consumed;
|
|
69
|
+
}
|
|
70
|
+
// Consume run_started - every run has exactly one
|
|
71
|
+
if (event.eventType === 'run_started') {
|
|
72
|
+
return EventConsumerResult.Consumed;
|
|
73
|
+
}
|
|
74
|
+
return EventConsumerResult.NotConsumed;
|
|
75
|
+
});
|
|
53
76
|
const useStep = createUseStep(workflowContext);
|
|
54
77
|
const createHook = createCreateHook(workflowContext);
|
|
55
78
|
const sleep = createSleep(workflowContext);
|
|
@@ -62,10 +85,10 @@ export async function runWorkflow(workflowCode, workflowRun, events) {
|
|
|
62
85
|
// @ts-expect-error - `@types/node` says symbol is not valid, but it does work
|
|
63
86
|
vmGlobalThis[WORKFLOW_GET_STREAM_ID] = (namespace) => getWorkflowRunStreamId(workflowRun.runId, namespace);
|
|
64
87
|
// TODO: there should be a getUrl method on the world interface itself. This
|
|
65
|
-
// solution only works for vercel +
|
|
88
|
+
// solution only works for vercel + local worlds.
|
|
66
89
|
const url = process.env.VERCEL_URL
|
|
67
90
|
? `https://${process.env.VERCEL_URL}`
|
|
68
|
-
: `http://localhost:${
|
|
91
|
+
: `http://localhost:${port ?? 3000}`;
|
|
69
92
|
// For the workflow VM, we store the context in a symbol on the `globalThis` object
|
|
70
93
|
const ctx = {
|
|
71
94
|
workflowRunId: workflowRun.runId,
|
|
@@ -74,11 +97,47 @@ export async function runWorkflow(workflowCode, workflowRun, events) {
|
|
|
74
97
|
};
|
|
75
98
|
// @ts-expect-error - `@types/node` says symbol is not valid, but it does work
|
|
76
99
|
vmGlobalThis[WORKFLOW_CONTEXT_SYMBOL] = ctx;
|
|
100
|
+
// @ts-expect-error - `@types/node` says symbol is not valid, but it does work
|
|
101
|
+
vmGlobalThis[STABLE_ULID] = ulid;
|
|
77
102
|
// NOTE: Will have a config override to use the custom fetch step.
|
|
78
103
|
// For now `fetch` must be explicitly imported from `workflow`.
|
|
79
104
|
vmGlobalThis.fetch = () => {
|
|
80
105
|
throw new vmGlobalThis.Error(`Global "fetch" is unavailable in workflow functions. Use the "fetch" step function from "workflow" to make HTTP requests.\n\nLearn more: https://useworkflow.dev/err/${ERROR_SLUGS.FETCH_IN_WORKFLOW_FUNCTION}`);
|
|
81
106
|
};
|
|
107
|
+
// Override timeout/interval functions to throw helpful errors
|
|
108
|
+
// These are not supported in workflow functions because they rely on
|
|
109
|
+
// asynchronous scheduling which breaks deterministic replay
|
|
110
|
+
const timeoutErrorMessage = 'Timeout functions like "setTimeout" and "setInterval" are not supported in workflow functions. Use the "sleep" function from "workflow" for time-based delays.';
|
|
111
|
+
vmGlobalThis.setTimeout = () => {
|
|
112
|
+
throw new WorkflowRuntimeError(timeoutErrorMessage, {
|
|
113
|
+
slug: ERROR_SLUGS.TIMEOUT_FUNCTIONS_IN_WORKFLOW,
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
vmGlobalThis.setInterval = () => {
|
|
117
|
+
throw new WorkflowRuntimeError(timeoutErrorMessage, {
|
|
118
|
+
slug: ERROR_SLUGS.TIMEOUT_FUNCTIONS_IN_WORKFLOW,
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
vmGlobalThis.clearTimeout = () => {
|
|
122
|
+
throw new WorkflowRuntimeError(timeoutErrorMessage, {
|
|
123
|
+
slug: ERROR_SLUGS.TIMEOUT_FUNCTIONS_IN_WORKFLOW,
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
vmGlobalThis.clearInterval = () => {
|
|
127
|
+
throw new WorkflowRuntimeError(timeoutErrorMessage, {
|
|
128
|
+
slug: ERROR_SLUGS.TIMEOUT_FUNCTIONS_IN_WORKFLOW,
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
vmGlobalThis.setImmediate = () => {
|
|
132
|
+
throw new WorkflowRuntimeError(timeoutErrorMessage, {
|
|
133
|
+
slug: ERROR_SLUGS.TIMEOUT_FUNCTIONS_IN_WORKFLOW,
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
vmGlobalThis.clearImmediate = () => {
|
|
137
|
+
throw new WorkflowRuntimeError(timeoutErrorMessage, {
|
|
138
|
+
slug: ERROR_SLUGS.TIMEOUT_FUNCTIONS_IN_WORKFLOW,
|
|
139
|
+
});
|
|
140
|
+
};
|
|
82
141
|
// `Request` and `Response` are special built-in classes that invoke steps
|
|
83
142
|
// for the `json()`, `text()` and `arrayBuffer()` instance methods
|
|
84
143
|
class Request {
|
|
@@ -435,8 +494,12 @@ export async function runWorkflow(workflowCode, workflowRun, events) {
|
|
|
435
494
|
const SYMBOL_FOR_REQ_CONTEXT = Symbol.for('@vercel/request-context');
|
|
436
495
|
// @ts-expect-error - `@types/node` says symbol is not valid, but it does work
|
|
437
496
|
vmGlobalThis[SYMBOL_FOR_REQ_CONTEXT] = globalThis[SYMBOL_FOR_REQ_CONTEXT];
|
|
438
|
-
// Get a reference to the user-defined workflow function
|
|
439
|
-
|
|
497
|
+
// Get a reference to the user-defined workflow function.
|
|
498
|
+
// The filename parameter ensures stack traces show a meaningful name
|
|
499
|
+
// (e.g., "example/workflows/99_e2e.ts") instead of "evalmachine.<anonymous>".
|
|
500
|
+
const parsedName = parseWorkflowName(workflowRun.workflowName);
|
|
501
|
+
const filename = parsedName?.path || workflowRun.workflowName;
|
|
502
|
+
const workflowFn = runInContext(`${workflowCode}; globalThis.__private_workflows?.get(${JSON.stringify(workflowRun.workflowName)})`, context, { filename });
|
|
440
503
|
if (typeof workflowFn !== 'function') {
|
|
441
504
|
throw new ReferenceError(`Workflow ${JSON.stringify(workflowRun.workflowName)} must be a function, but got "${typeof workflowFn}" instead`);
|
|
442
505
|
}
|
|
@@ -456,4 +519,4 @@ export async function runWorkflow(workflowCode, workflowRun, events) {
|
|
|
456
519
|
return dehydrated;
|
|
457
520
|
});
|
|
458
521
|
}
|
|
459
|
-
//# sourceMappingURL=workflow.js.map
|
|
522
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2Zsb3cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvd29ya2Zsb3cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUN2QyxPQUFPLEVBQUUsV0FBVyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDckUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUUvRCxPQUFPLEtBQUssTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUNqQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDeEMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGNBQWMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzNFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFdEMsT0FBTyxFQUNMLDRCQUE0QixFQUM1Qix3QkFBd0IsR0FDekIsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzFDLE9BQU8sRUFDTCxnQkFBZ0IsRUFDaEIsV0FBVyxFQUNYLG9CQUFvQixFQUNwQixzQkFBc0IsRUFDdEIsY0FBYyxFQUNkLGlCQUFpQixHQUNsQixNQUFNLGNBQWMsQ0FBQztBQUN0QixPQUFPLEtBQUssU0FBUyxNQUFNLHFDQUFxQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN2QyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDbkQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUU5QyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUM5RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFbEQsTUFBTSxDQUFDLEtBQUssVUFBVSxXQUFXLENBQy9CLFlBQW9CLEVBQ3BCLFdBQXdCLEVBQ3hCLE1BQWU7SUFFZixPQUFPLEtBQUssQ0FBQyxnQkFBZ0IsV0FBVyxDQUFDLFlBQVksRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRTtRQUN0RSxJQUFJLEVBQUUsYUFBYSxDQUFDO1lBQ2xCLEdBQUcsU0FBUyxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsWUFBWSxDQUFDO1lBQ25ELEdBQUcsU0FBUyxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDO1lBQzdDLEdBQUcsU0FBUyxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUM7WUFDbEQsR0FBRyxTQUFTLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztTQUNoRCxDQUFDLENBQUM7UUFFSCxNQUFNLFNBQVMsR0FBRyxXQUFXLENBQUMsU0FBUyxDQUFDO1FBQ3hDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNmLE1BQU0sSUFBSSxLQUFLLENBQ2IsaUJBQWlCLFdBQVcsQ0FBQyxLQUFLLG9EQUFvRCxDQUN2RixDQUFDO1FBQ0osQ0FBQztRQUVELG9FQUFvRTtRQUNwRSx3Q0FBd0M7UUFDeEMsTUFBTSxJQUFJLEdBQUcsTUFBTSxPQUFPLEVBQUUsQ0FBQztRQUU3QixNQUFNLEVBQ0osT0FBTyxFQUNQLFVBQVUsRUFBRSxZQUFZLEVBQ3hCLGVBQWUsR0FDaEIsR0FBRyxhQUFhLENBQUM7WUFDaEIsSUFBSSxFQUFFLFdBQVcsQ0FBQyxLQUFLO1lBQ3ZCLGNBQWMsRUFBRSxDQUFDLFNBQVM7U0FDM0IsQ0FBQyxDQUFDO1FBRUgsTUFBTSx1QkFBdUIsR0FBRyxhQUFhLEVBQVEsQ0FBQztRQUV0RCxNQUFNLElBQUksR0FBRyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDaEUsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLEVBQUUsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQzFFLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUNqRSxDQUFDO1FBRUYsTUFBTSxlQUFlLEdBQWdDO1lBQ25ELFVBQVUsRUFBRSxZQUFZO1lBQ3hCLGVBQWUsRUFBRSx1QkFBdUIsQ0FBQyxNQUFNO1lBQy9DLGNBQWMsRUFBRSxJQUFJLGNBQWMsQ0FBQyxNQUFNLENBQUM7WUFDMUMsWUFBWSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQztZQUNwQyxjQUFjO1lBQ2QsZ0JBQWdCLEVBQUUsSUFBSSxHQUFHLEVBQUU7U0FDNUIsQ0FBQztRQUVGLHdFQUF3RTtRQUN4RSxlQUFlLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQ2pELE1BQU0sU0FBUyxHQUFHLEtBQUssRUFBRSxTQUFTLENBQUM7WUFDbkMsSUFBSSxTQUFTLEVBQUUsQ0FBQztnQkFDZCxlQUFlLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUM5QixDQUFDO1lBQ0QsMkRBQTJEO1lBQzNELE9BQU8sbUJBQW1CLENBQUMsV0FBVyxDQUFDO1FBQ3pDLENBQUMsQ0FBQyxDQUFDO1FBRUgsd0VBQXdFO1FBQ3hFLHlFQUF5RTtRQUN6RSw2QkFBNkI7UUFDN0IsZUFBZSxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNqRCxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ1gsT0FBTyxtQkFBbUIsQ0FBQyxXQUFXLENBQUM7WUFDekMsQ0FBQztZQUVELGtEQUFrRDtZQUNsRCxJQUFJLEtBQUssQ0FBQyxTQUFTLEtBQUssYUFBYSxFQUFFLENBQUM7Z0JBQ3RDLE9BQU8sbUJBQW1CLENBQUMsUUFBUSxDQUFDO1lBQ3RDLENBQUM7WUFFRCxrREFBa0Q7WUFDbEQsSUFBSSxLQUFLLENBQUMsU0FBUyxLQUFLLGFBQWEsRUFBRSxDQUFDO2dCQUN0QyxPQUFPLG1CQUFtQixDQUFDLFFBQVEsQ0FBQztZQUN0QyxDQUFDO1lBRUQsT0FBTyxtQkFBbUIsQ0FBQyxXQUFXLENBQUM7UUFDekMsQ0FBQyxDQUFDLENBQUM7UUFFSCxNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDL0MsTUFBTSxVQUFVLEdBQUcsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDckQsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBRTNDLDhFQUE4RTtRQUM5RSxZQUFZLENBQUMsaUJBQWlCLENBQUMsR0FBRyxPQUFPLENBQUM7UUFDMUMsOEVBQThFO1FBQzlFLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLFVBQVUsQ0FBQztRQUNoRCw4RUFBOEU7UUFDOUUsWUFBWSxDQUFDLGNBQWMsQ0FBQyxHQUFHLEtBQUssQ0FBQztRQUNyQyw4RUFBOEU7UUFDOUUsWUFBWSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxTQUFrQixFQUFFLEVBQUUsQ0FDNUQsc0JBQXNCLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQztRQUV2RCw0RUFBNEU7UUFDNUUsaURBQWlEO1FBQ2pELE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVTtZQUNoQyxDQUFDLENBQUMsV0FBVyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRTtZQUNyQyxDQUFDLENBQUMsb0JBQW9CLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUV2QyxtRkFBbUY7UUFDbkYsTUFBTSxHQUFHLEdBQXFCO1lBQzVCLGFBQWEsRUFBRSxXQUFXLENBQUMsS0FBSztZQUNoQyxpQkFBaUIsRUFBRSxJQUFJLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUM7WUFDcEQsR0FBRztTQUNKLENBQUM7UUFFRiw4RUFBOEU7UUFDOUUsWUFBWSxDQUFDLHVCQUF1QixDQUFDLEdBQUcsR0FBRyxDQUFDO1FBQzVDLDhFQUE4RTtRQUM5RSxZQUFZLENBQUMsV0FBVyxDQUFDLEdBQUcsSUFBSSxDQUFDO1FBRWpDLGtFQUFrRTtRQUNsRSxxRUFBcUU7UUFDckUsWUFBWSxDQUFDLEtBQUssR0FBRyxHQUFHLEVBQUU7WUFDeEIsTUFBTSxJQUFJLFlBQVksQ0FBQyxLQUFLLENBQzFCLHdLQUF3SyxXQUFXLENBQUMsMEJBQTBCLEVBQUUsQ0FDak4sQ0FBQztRQUNKLENBQUMsQ0FBQztRQUVGLDhEQUE4RDtRQUM5RCxxRUFBcUU7UUFDckUsNERBQTREO1FBQzVELE1BQU0sbUJBQW1CLEdBQ3ZCLGdLQUFnSyxDQUFDO1FBRWxLLFlBQW9CLENBQUMsVUFBVSxHQUFHLEdBQUcsRUFBRTtZQUN0QyxNQUFNLElBQUksb0JBQW9CLENBQUMsbUJBQW1CLEVBQUU7Z0JBQ2xELElBQUksRUFBRSxXQUFXLENBQUMsNkJBQTZCO2FBQ2hELENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQztRQUNELFlBQW9CLENBQUMsV0FBVyxHQUFHLEdBQUcsRUFBRTtZQUN2QyxNQUFNLElBQUksb0JBQW9CLENBQUMsbUJBQW1CLEVBQUU7Z0JBQ2xELElBQUksRUFBRSxXQUFXLENBQUMsNkJBQTZCO2FBQ2hELENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQztRQUNELFlBQW9CLENBQUMsWUFBWSxHQUFHLEdBQUcsRUFBRTtZQUN4QyxNQUFNLElBQUksb0JBQW9CLENBQUMsbUJBQW1CLEVBQUU7Z0JBQ2xELElBQUksRUFBRSxXQUFXLENBQUMsNkJBQTZCO2FBQ2hELENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQztRQUNELFlBQW9CLENBQUMsYUFBYSxHQUFHLEdBQUcsRUFBRTtZQUN6QyxNQUFNLElBQUksb0JBQW9CLENBQUMsbUJBQW1CLEVBQUU7Z0JBQ2xELElBQUksRUFBRSxXQUFXLENBQUMsNkJBQTZCO2FBQ2hELENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQztRQUNELFlBQW9CLENBQUMsWUFBWSxHQUFHLEdBQUcsRUFBRTtZQUN4QyxNQUFNLElBQUksb0JBQW9CLENBQUMsbUJBQW1CLEVBQUU7Z0JBQ2xELElBQUksRUFBRSxXQUFXLENBQUMsNkJBQTZCO2FBQ2hELENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQztRQUNELFlBQW9CLENBQUMsY0FBYyxHQUFHLEdBQUcsRUFBRTtZQUMxQyxNQUFNLElBQUksb0JBQW9CLENBQUMsbUJBQW1CLEVBQUU7Z0JBQ2xELElBQUksRUFBRSxXQUFXLENBQUMsNkJBQTZCO2FBQ2hELENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQztRQUVGLDBFQUEwRTtRQUMxRSxrRUFBa0U7UUFDbEUsTUFBTSxPQUFPO1lBQ1gsS0FBSyxDQUErQjtZQUNwQyxXQUFXLENBQXFDO1lBQ2hELFdBQVcsQ0FBcUM7WUFDaEQsT0FBTyxDQUFXO1lBQ2xCLFNBQVMsQ0FBVTtZQUNuQixNQUFNLENBQVU7WUFDaEIsSUFBSSxDQUE4QjtZQUNsQyxRQUFRLENBQWtDO1lBQzFDLFFBQVEsQ0FBVTtZQUNsQixjQUFjLENBQXdDO1lBQ3RELEdBQUcsQ0FBVTtZQUNiLFNBQVMsQ0FBVztZQUNwQixNQUFNLENBQWU7WUFDckIsTUFBTSxDQUFVO1lBQ2hCLElBQUksQ0FBOEI7WUFFbEMsWUFBWSxLQUFVLEVBQUUsSUFBa0I7Z0JBQ3hDLG1CQUFtQjtnQkFDbkIsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksS0FBSyxZQUFZLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQztvQkFDbkUsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUNoQyxzQkFBc0I7b0JBQ3RCLElBQUksQ0FBQzt3QkFDSCxJQUFJLFlBQVksQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7d0JBQ2hDLElBQUksQ0FBQyxHQUFHLEdBQUcsU0FBUyxDQUFDO29CQUN2QixDQUFDO29CQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7d0JBQ2YsTUFBTSxJQUFJLFNBQVMsQ0FBQyw0QkFBNEIsU0FBUyxFQUFFLEVBQUU7NEJBQzNELEtBQUs7eUJBQ04sQ0FBQyxDQUFDO29CQUNMLENBQUM7Z0JBQ0gsQ0FBQztxQkFBTSxDQUFDO29CQUNOLG1EQUFtRDtvQkFDbkQsSUFBSSxDQUFDLEdBQUcsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDO29CQUNyQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7d0JBQ1YsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO3dCQUMzQixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksWUFBWSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7d0JBQ3ZELElBQUksQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQzt3QkFDdkIsSUFBSSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDO3dCQUN2QixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUM7d0JBQ3JDLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQzt3QkFDekIsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDO3dCQUMvQixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUM7d0JBQy9CLElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQzt3QkFDM0MsSUFBSSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDO3dCQUNqQyxJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUM7d0JBQ2pDLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQzt3QkFDM0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO3dCQUMzQixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUM7d0JBQ3JDLE9BQU87b0JBQ1QsQ0FBQztvQkFDRCw2RUFBNkU7b0JBQzdFLG9EQUFvRDtvQkFDcEQsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO29CQUMzQixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksWUFBWSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBQ3ZELElBQUksQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztvQkFDdkIsSUFBSSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDO29CQUN2QixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUM7b0JBQ3JDLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQztvQkFDekIsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDO29CQUMvQixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUM7b0JBQy9CLElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQztvQkFDM0MsSUFBSSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDO29CQUNqQyxJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUM7b0JBQ2pDLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQztvQkFDM0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO29CQUMzQixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUM7Z0JBQ3ZDLENBQUM7Z0JBRUQseUNBQXlDO2dCQUN6QyxhQUFhO2dCQUNiLElBQUksSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDO29CQUNqQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQzFDLENBQUM7cUJBQU0sSUFBSSxPQUFPLElBQUksQ0FBQyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7b0JBQzNDLDRDQUE0QztvQkFDNUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7Z0JBQ3RCLENBQUM7Z0JBRUQsY0FBYztnQkFDZCxJQUFJLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztvQkFDbEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLFlBQVksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUN4RCxDQUFDO3FCQUFNLElBQ0wsT0FBTyxLQUFLLEtBQUssUUFBUTtvQkFDekIsS0FBSyxZQUFZLFlBQVksQ0FBQyxHQUFHLEVBQ2pDLENBQUM7b0JBQ0QsNkNBQTZDO29CQUM3QyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksWUFBWSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUM1QyxDQUFDO2dCQUVELG9EQUFvRDtnQkFDcEQsSUFBSSxJQUFJLEVBQUUsSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUM3QixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7Z0JBQ3hCLENBQUM7cUJBQU0sSUFBSSxPQUFPLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7b0JBQ3pDLElBQUksQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFDO2dCQUNyQixDQUFDO2dCQUVELElBQUksSUFBSSxFQUFFLFdBQVcsS0FBSyxTQUFTLEVBQUUsQ0FBQztvQkFDcEMsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDO2dCQUN0QyxDQUFDO3FCQUFNLElBQUksT0FBTyxJQUFJLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRSxDQUFDO29CQUNoRCxJQUFJLENBQUMsV0FBVyxHQUFHLGFBQWEsQ0FBQztnQkFDbkMsQ0FBQztnQkFFRCxvRUFBb0U7Z0JBQ3BFLElBQUssSUFBWSxFQUFFLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQztvQkFDdkMsSUFBSSxDQUFDLEtBQUssR0FBSSxJQUFZLENBQUMsS0FBSyxDQUFDO2dCQUNuQyxDQUFDO3FCQUFNLElBQUksT0FBTyxJQUFJLENBQUMsS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO29CQUMxQyxJQUFJLENBQUMsS0FBSyxHQUFHLFNBQVMsQ0FBQztnQkFDekIsQ0FBQztnQkFFRCxJQUFJLElBQUksRUFBRSxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7b0JBQ2pDLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztnQkFDaEMsQ0FBQztxQkFBTSxJQUFJLE9BQU8sSUFBSSxDQUFDLFFBQVEsS0FBSyxRQUFRLEVBQUUsQ0FBQztvQkFDN0MsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7Z0JBQzNCLENBQUM7Z0JBRUQsSUFBSSxJQUFJLEVBQUUsUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUNqQyxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7Z0JBQ2hDLENBQUM7cUJBQU0sSUFBSSxPQUFPLElBQUksQ0FBQyxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7b0JBQzdDLElBQUksQ0FBQyxRQUFRLEdBQUcsY0FBYyxDQUFDO2dCQUNqQyxDQUFDO2dCQUVELElBQUksSUFBSSxFQUFFLGNBQWMsS0FBSyxTQUFTLEVBQUUsQ0FBQztvQkFDdkMsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDO2dCQUM1QyxDQUFDO3FCQUFNLElBQUksT0FBTyxJQUFJLENBQUMsY0FBYyxLQUFLLFFBQVEsRUFBRSxDQUFDO29CQUNuRCxJQUFJLENBQUMsY0FBYyxHQUFHLEVBQUUsQ0FBQztnQkFDM0IsQ0FBQztnQkFFRCxJQUFJLElBQUksRUFBRSxTQUFTLEtBQUssU0FBUyxFQUFFLENBQUM7b0JBQ2xDLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztnQkFDbEMsQ0FBQztxQkFBTSxJQUFJLE9BQU8sSUFBSSxDQUFDLFNBQVMsS0FBSyxRQUFRLEVBQUUsQ0FBQztvQkFDOUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxFQUFFLENBQUM7Z0JBQ3RCLENBQUM7Z0JBRUQsSUFBSSxJQUFJLEVBQUUsU0FBUyxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUNsQyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7Z0JBQ2xDLENBQUM7cUJBQU0sSUFBSSxPQUFPLElBQUksQ0FBQyxTQUFTLEtBQUssU0FBUyxFQUFFLENBQUM7b0JBQy9DLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO2dCQUN6QixDQUFDO2dCQUVELElBQUksSUFBSSxFQUFFLE1BQU0sS0FBSyxTQUFTLEVBQUUsQ0FBQztvQkFDL0Isc0NBQXNDO29CQUN0QyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUM7Z0JBQzVCLENBQUM7cUJBQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDeEIsc0NBQXNDO29CQUN0QyxJQUFJLENBQUMsTUFBTSxHQUFHLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDO2dCQUNuQyxDQUFDO2dCQUVELElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ2pCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO2dCQUN2QixDQUFDO2dCQUVELElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7b0JBQ3RCLElBQUksQ0FBQyxXQUFXLEdBQUcsVUFBVSxDQUFDO2dCQUNoQyxDQUFDO2dCQUVELE1BQU0sSUFBSSxHQUFHLElBQUksRUFBRSxJQUFJLENBQUM7Z0JBRXhCLG1EQUFtRDtnQkFDbkQsSUFDRSxJQUFJLEtBQUssSUFBSTtvQkFDYixJQUFJLEtBQUssU0FBUztvQkFDbEIsQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLEtBQUssSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLE1BQU0sQ0FBQyxFQUNqRCxDQUFDO29CQUNELE1BQU0sSUFBSSxTQUFTLENBQUMsZ0RBQWdELENBQUMsQ0FBQztnQkFDeEUsQ0FBQztnQkFFRCxnREFBZ0Q7Z0JBQ2hELElBQUksSUFBSSxLQUFLLElBQUksSUFBSSxJQUFJLEtBQUssU0FBUyxFQUFFLENBQUM7b0JBQ3hDLCtEQUErRDtvQkFDL0Qsc0RBQXNEO29CQUN0RCxJQUFJLENBQUMsSUFBSSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxTQUFTLEVBQUU7d0JBQy9ELENBQUMsZ0JBQWdCLENBQUMsRUFBRTs0QkFDbEIsS0FBSyxFQUFFLElBQUk7NEJBQ1gsUUFBUSxFQUFFLEtBQUs7eUJBQ2hCO3FCQUNGLENBQUMsQ0FBQztnQkFDTCxDQUFDO3FCQUFNLENBQUM7b0JBQ04sSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7Z0JBQ25CLENBQUM7WUFDSCxDQUFDO1lBRUQsS0FBSztnQkFDSCxPQUFPLEVBQUUsQ0FBQztZQUNaLENBQUM7WUFFRCxJQUFJLFFBQVE7Z0JBQ1YsT0FBTyxLQUFLLENBQUM7WUFDZixDQUFDO1lBRUQsd0JBQXdCO1lBQ3hCLElBQUksQ0FBdUI7WUFDM0IsUUFBUSxDQUEyQjtZQUVuQyxLQUFLLENBQUMsV0FBVztnQkFDZixPQUFPLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM5QixDQUFDO1lBRUQsS0FBSyxDQUFDLEtBQUs7Z0JBQ1QsT0FBTyxJQUFJLFVBQVUsQ0FBQyxNQUFNLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3BELENBQUM7WUFFRCxLQUFLLENBQUMsSUFBSTtnQkFDUixPQUFPLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUN2QixDQUFDO1lBRUQsS0FBSyxDQUFDLElBQUk7Z0JBQ1IsT0FBTyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkIsQ0FBQztTQUNGO1FBQ0QsWUFBWSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFFL0IsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFhLHlCQUF5QixDQUFDLENBQUM7UUFDL0QsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFnQix5QkFBeUIsQ0FBQyxDQUFDO1FBQ2xFLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FDNUIsaUNBQWlDLENBQ2xDLENBQUM7UUFDRixNQUFNLFFBQVE7WUFDWixJQUFJLENBQStCO1lBQ25DLEdBQUcsQ0FBVTtZQUNiLE1BQU0sQ0FBVTtZQUNoQixVQUFVLENBQVU7WUFDcEIsSUFBSSxDQUFxQztZQUN6QyxPQUFPLENBQVc7WUFDbEIsVUFBVSxDQUFXO1lBRXJCLFlBQVksSUFBVSxFQUFFLElBQW1CO2dCQUN6QyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksRUFBRSxNQUFNLElBQUksR0FBRyxDQUFDO2dCQUNsQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksRUFBRSxVQUFVLElBQUksRUFBRSxDQUFDO2dCQUN6QyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7Z0JBQ3ZELElBQUksQ0FBQyxJQUFJLEdBQUcsU0FBUyxDQUFDO2dCQUN0QixJQUFJLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQztnQkFDZCxJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQztnQkFFeEIseURBQXlEO2dCQUN6RCwrRUFBK0U7Z0JBQy9FLElBQ0UsSUFBSSxLQUFLLElBQUk7b0JBQ2IsSUFBSSxLQUFLLFNBQVM7b0JBQ2xCLENBQUMsSUFBSSxDQUFDLE1BQU0sS0FBSyxHQUFHLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxHQUFHLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxHQUFHLENBQUMsRUFDbkUsQ0FBQztvQkFDRCxNQUFNLElBQUksU0FBUyxDQUNqQixzREFBc0QsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUNwRSxDQUFDO2dCQUNKLENBQUM7Z0JBRUQsZ0RBQWdEO2dCQUNoRCxJQUFJLElBQUksS0FBSyxJQUFJLElBQUksSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUN4QywrREFBK0Q7b0JBQy9ELHNEQUFzRDtvQkFDdEQsSUFBSSxDQUFDLElBQUksR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsU0FBUyxFQUFFO3dCQUMvRCxDQUFDLGdCQUFnQixDQUFDLEVBQUU7NEJBQ2xCLEtBQUssRUFBRSxJQUFJOzRCQUNYLFFBQVEsRUFBRSxLQUFLO3lCQUNoQjtxQkFDRixDQUFDLENBQUM7Z0JBQ0wsQ0FBQztxQkFBTSxDQUFDO29CQUNOLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO2dCQUNuQixDQUFDO1lBQ0gsQ0FBQztZQUVELHdCQUF3QjtZQUN4QixLQUFLLENBQWtCO1lBQ3ZCLElBQUksQ0FBa0M7WUFDdEMsUUFBUSxDQUFzQztZQUU5QyxJQUFJLEVBQUU7Z0JBQ0osT0FBTyxJQUFJLENBQUMsTUFBTSxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQztZQUNqRCxDQUFDO1lBRUQsSUFBSSxRQUFRO2dCQUNWLE9BQU8sS0FBSyxDQUFDO1lBQ2YsQ0FBQztZQUVELEtBQUssQ0FBQyxXQUFXO2dCQUNmLE9BQU8sY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzlCLENBQUM7WUFFRCxLQUFLLENBQUMsS0FBSztnQkFDVCxPQUFPLElBQUksVUFBVSxDQUFDLE1BQU0sY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDcEQsQ0FBQztZQUVELEtBQUssQ0FBQyxJQUFJO2dCQUNSLE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3ZCLENBQUM7WUFFRCxNQUFNLENBQUMsSUFBSSxDQUFDLElBQVMsRUFBRSxJQUFtQjtnQkFDeEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDbEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxZQUFZLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztnQkFDeEQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztvQkFDakMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztnQkFDbEQsQ0FBQztnQkFDRCxPQUFPLElBQUksUUFBUSxDQUFDLElBQUksRUFBRSxFQUFFLEdBQUcsSUFBSSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDbEQsQ0FBQztZQUVELEtBQUssQ0FBQyxJQUFJO2dCQUNSLE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3ZCLENBQUM7WUFFRCxNQUFNLENBQUMsS0FBSztnQkFDVixPQUFPLEVBQUUsQ0FBQztZQUNaLENBQUM7WUFFRCxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQWlCLEVBQUUsU0FBaUIsR0FBRztnQkFDckQsa0VBQWtFO2dCQUNsRSxJQUFJLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7b0JBQ2hELE1BQU0sSUFBSSxVQUFVLENBQ2xCLGlDQUFpQyxNQUFNLDJDQUEyQyxDQUNuRixDQUFDO2dCQUNKLENBQUM7Z0JBRUQsdUNBQXVDO2dCQUN2QyxNQUFNLE9BQU8sR0FBRyxJQUFJLFlBQVksQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDM0MsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBRXJDLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUNuRCxRQUFRLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztnQkFDekIsUUFBUSxDQUFDLFVBQVUsR0FBRyxFQUFFLENBQUM7Z0JBQ3pCLFFBQVEsQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO2dCQUMzQixRQUFRLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztnQkFDckIsUUFBUSxDQUFDLElBQUksR0FBRyxTQUFTLENBQUM7Z0JBQzFCLFFBQVEsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDO2dCQUNsQixRQUFRLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQztnQkFFNUIsT0FBTyxRQUFRLENBQUM7WUFDbEIsQ0FBQztTQUNGO1FBQ0QsWUFBWSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFFakMsTUFBTSxjQUFjO1lBQ2xCO2dCQUNFLE9BQU8sRUFBRSxDQUFDO1lBQ1osQ0FBQztZQUVELElBQUksTUFBTTtnQkFDUixPQUFPLEtBQUssQ0FBQztZQUNmLENBQUM7WUFFRCxNQUFNO2dCQUNKLE9BQU8sRUFBRSxDQUFDO1lBQ1osQ0FBQztZQUVELFNBQVM7Z0JBQ1AsT0FBTyxFQUFFLENBQUM7WUFDWixDQUFDO1lBRUQsV0FBVztnQkFDVCxPQUFPLEVBQUUsQ0FBQztZQUNaLENBQUM7WUFFRCxNQUFNO2dCQUNKLE9BQU8sRUFBRSxDQUFDO1lBQ1osQ0FBQztZQUVELEdBQUc7Z0JBQ0QsT0FBTyxFQUFFLENBQUM7WUFDWixDQUFDO1lBRUQsTUFBTTtnQkFDSixPQUFPLEVBQUUsQ0FBQztZQUNaLENBQUM7WUFFRCxNQUFNLENBQUMsSUFBSTtnQkFDVCxPQUFPLEVBQUUsQ0FBQztZQUNaLENBQUM7WUFFRCxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUM7Z0JBQ3BCLE9BQU8sRUFBRSxDQUFDO1lBQ1osQ0FBQztTQUNGO1FBQ0QsWUFBWSxDQUFDLGNBQWMsR0FBRyxjQUFjLENBQUM7UUFFN0MsTUFBTSxjQUFjO1lBQ2xCO2dCQUNFLE9BQU8sRUFBRSxDQUFDO1lBQ1osQ0FBQztZQUVELElBQUksTUFBTTtnQkFDUixPQUFPLEtBQUssQ0FBQztZQUNmLENBQUM7WUFFRCxLQUFLO2dCQUNILE9BQU8sRUFBRSxDQUFDO1lBQ1osQ0FBQztZQUVELEtBQUs7Z0JBQ0gsT0FBTyxFQUFFLENBQUM7WUFDWixDQUFDO1lBRUQsU0FBUztnQkFDUCxPQUFPLEVBQUUsQ0FBQztZQUNaLENBQUM7U0FDRjtRQUNELFlBQVksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFDO1FBRTdDLE1BQU0sZUFBZTtZQUNuQixRQUFRLENBQStCO1lBQ3ZDLFFBQVEsQ0FBK0I7WUFFdkM7Z0JBQ0UsT0FBTyxFQUFFLENBQUM7WUFDWixDQUFDO1NBQ0Y7UUFDRCxZQUFZLENBQUMsZUFBZSxHQUFHLGVBQWUsQ0FBQztRQUUvQyxzRUFBc0U7UUFDdEUsZ0RBQWdEO1FBQ2hELFlBQVksQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQztRQUUxQyxxREFBcUQ7UUFDckQsTUFBTSxzQkFBc0IsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLHlCQUF5QixDQUFDLENBQUM7UUFDckUsOEVBQThFO1FBQzlFLFlBQVksQ0FBQyxzQkFBc0IsQ0FBQyxHQUFJLFVBQWtCLENBQ3hELHNCQUFzQixDQUN2QixDQUFDO1FBRUYseURBQXlEO1FBQ3pELHFFQUFxRTtRQUNyRSw4RUFBOEU7UUFDOUUsTUFBTSxVQUFVLEdBQUcsaUJBQWlCLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQy9ELE1BQU0sUUFBUSxHQUFHLFVBQVUsRUFBRSxJQUFJLElBQUksV0FBVyxDQUFDLFlBQVksQ0FBQztRQUU5RCxNQUFNLFVBQVUsR0FBRyxZQUFZLENBQzdCLEdBQUcsWUFBWSx5Q0FBeUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsWUFBWSxDQUFDLEdBQUcsRUFDbkcsT0FBTyxFQUNQLEVBQUUsUUFBUSxFQUFFLENBQ2IsQ0FBQztRQUVGLElBQUksT0FBTyxVQUFVLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDckMsTUFBTSxJQUFJLGNBQWMsQ0FDdEIsWUFBWSxJQUFJLENBQUMsU0FBUyxDQUN4QixXQUFXLENBQUMsWUFBWSxDQUN6QixpQ0FBaUMsT0FBTyxVQUFVLFdBQVcsQ0FDL0QsQ0FBQztRQUNKLENBQUM7UUFFRCxNQUFNLElBQUksR0FBRyx3QkFBd0IsQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBRXZFLElBQUksRUFBRSxhQUFhLENBQUM7WUFDbEIsR0FBRyxTQUFTLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztTQUNqRCxDQUFDLENBQUM7UUFFSCx1QkFBdUI7UUFDdkIsTUFBTSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDO1lBQ2hDLFVBQVUsQ0FBQyxHQUFHLElBQUksQ0FBQztZQUNuQix1QkFBdUIsQ0FBQyxPQUFPO1NBQ2hDLENBQUMsQ0FBQztRQUVILE1BQU0sVUFBVSxHQUFHLDRCQUE0QixDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztRQUV0RSxJQUFJLEVBQUUsYUFBYSxDQUFDO1lBQ2xCLEdBQUcsU0FBUyxDQUFDLGtCQUFrQixDQUFDLE9BQU8sTUFBTSxDQUFDO1NBQy9DLENBQUMsQ0FBQztRQUVILE9BQU8sVUFBVSxDQUFDO0lBQ3BCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyJ9
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: createHook
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Creates a low-level hook primitive that can be used to resume a workflow run with arbitrary payloads.
|
|
6
|
+
|
|
7
|
+
Hooks allow external systems to send data to a paused workflow without the HTTP-specific constraints of webhooks. They're identified by a token and can receive any serializable payload.
|
|
8
|
+
|
|
9
|
+
```ts lineNumbers
|
|
10
|
+
import { createHook } from "workflow"
|
|
11
|
+
|
|
12
|
+
export async function hookWorkflow() {
|
|
13
|
+
"use workflow";
|
|
14
|
+
const hook = createHook(); // [!code highlight]
|
|
15
|
+
const result = await hook; // Suspends the workflow until the hook is resumed
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## API Signature
|
|
20
|
+
|
|
21
|
+
### Parameters
|
|
22
|
+
|
|
23
|
+
<TSDoc
|
|
24
|
+
definition={`
|
|
25
|
+
import { createHook } from "workflow";
|
|
26
|
+
export default createHook;`
|
|
27
|
+
}
|
|
28
|
+
showSections={['parameters']}
|
|
29
|
+
/>
|
|
30
|
+
|
|
31
|
+
#### HookOptions
|
|
32
|
+
|
|
33
|
+
<TSDoc
|
|
34
|
+
definition={`
|
|
35
|
+
import type { HookOptions } from "workflow";
|
|
36
|
+
export default HookOptions;`
|
|
37
|
+
}
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
### Returns
|
|
41
|
+
|
|
42
|
+
<TSDoc
|
|
43
|
+
definition={`
|
|
44
|
+
import { createHook } from "workflow";
|
|
45
|
+
export default createHook;`}
|
|
46
|
+
showSections={['returns']}
|
|
47
|
+
/>
|
|
48
|
+
|
|
49
|
+
#### Hook
|
|
50
|
+
|
|
51
|
+
<TSDoc
|
|
52
|
+
definition={`
|
|
53
|
+
import type { Hook } from "workflow";
|
|
54
|
+
export default Hook;`}
|
|
55
|
+
/>
|
|
56
|
+
|
|
57
|
+
The returned `Hook` object also implements `AsyncIterable<T>`, which allows you to iterate over incoming payloads using `for await...of` syntax.
|
|
58
|
+
|
|
59
|
+
## Examples
|
|
60
|
+
|
|
61
|
+
### Basic Usage
|
|
62
|
+
|
|
63
|
+
When creating a hook, you can specify a payload type to be used for automatic type safety.
|
|
64
|
+
|
|
65
|
+
```typescript lineNumbers
|
|
66
|
+
import { createHook } from "workflow"
|
|
67
|
+
|
|
68
|
+
export async function approvalWorkflow() {
|
|
69
|
+
"use workflow";
|
|
70
|
+
|
|
71
|
+
const hook = createHook<{ approved: boolean; comment: string }>(); // [!code highlight]
|
|
72
|
+
console.log("Send approval to token:", hook.token);
|
|
73
|
+
|
|
74
|
+
const result = await hook;
|
|
75
|
+
|
|
76
|
+
if (result.approved) {
|
|
77
|
+
console.log("Approved with comment:", result.comment);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Customizing Tokens
|
|
83
|
+
|
|
84
|
+
Tokens are used to identify a specific hook. You can customize the token to be more specific to a use case.
|
|
85
|
+
|
|
86
|
+
```typescript lineNumbers
|
|
87
|
+
import { createHook } from "workflow";
|
|
88
|
+
|
|
89
|
+
export async function slackBotWorkflow(channelId: string) {
|
|
90
|
+
"use workflow";
|
|
91
|
+
|
|
92
|
+
// Token constructed from channel ID
|
|
93
|
+
const hook = createHook<SlackMessage>({ // [!code highlight]
|
|
94
|
+
token: `slack_webhook:${channelId}`, // [!code highlight]
|
|
95
|
+
}); // [!code highlight]
|
|
96
|
+
|
|
97
|
+
for await (const message of hook) {
|
|
98
|
+
if (message.text === "/stop") {
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
await processMessage(message);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Waiting for Multiple Payloads
|
|
107
|
+
|
|
108
|
+
You can also wait for multiple payloads by using the `for await...of` syntax.
|
|
109
|
+
|
|
110
|
+
```typescript lineNumbers
|
|
111
|
+
import { createHook } from "workflow"
|
|
112
|
+
|
|
113
|
+
export async function collectHookWorkflow() {
|
|
114
|
+
"use workflow";
|
|
115
|
+
|
|
116
|
+
const hook = createHook<{ message: string; done?: boolean }>();
|
|
117
|
+
|
|
118
|
+
const payloads = [];
|
|
119
|
+
for await (const payload of hook) { // [!code highlight]
|
|
120
|
+
payloads.push(payload);
|
|
121
|
+
|
|
122
|
+
if (payload.done) break;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return payloads;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Related Functions
|
|
130
|
+
|
|
131
|
+
- [`defineHook()`](/docs/api-reference/workflow/define-hook) - Type-safe hook helper
|
|
132
|
+
- [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook) - Resume a hook with a payload
|
|
133
|
+
- [`createWebhook()`](/docs/api-reference/workflow/create-webhook) - Higher-level HTTP webhook abstraction
|