queuebear 0.1.4 → 0.1.6
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/index.d.ts +30 -47
- package/dist/index.js +139 -181
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Base HTTP client for QueueBear API requests
|
|
3
3
|
*/
|
|
4
4
|
interface BaseClientOptions {
|
|
5
|
-
baseUrl: string;
|
|
6
5
|
apiKey: string;
|
|
7
6
|
projectId: string;
|
|
8
7
|
}
|
|
@@ -14,7 +13,6 @@ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
|
14
13
|
* Base client providing shared HTTP functionality
|
|
15
14
|
*/
|
|
16
15
|
declare class BaseClient {
|
|
17
|
-
protected baseUrl: string;
|
|
18
16
|
protected apiKey: string;
|
|
19
17
|
protected projectId: string;
|
|
20
18
|
constructor(options: BaseClientOptions);
|
|
@@ -51,7 +49,7 @@ type StepType = "run" | "sleep" | "call" | "continuation" | "wait_event";
|
|
|
51
49
|
* Workflow run information returned by client.getStatus()
|
|
52
50
|
*/
|
|
53
51
|
interface WorkflowRun {
|
|
54
|
-
|
|
52
|
+
id: string;
|
|
55
53
|
workflowId: string;
|
|
56
54
|
workflowUrl: string;
|
|
57
55
|
status: WorkflowRunStatus;
|
|
@@ -83,7 +81,7 @@ interface WorkflowStep {
|
|
|
83
81
|
* Response from client.trigger()
|
|
84
82
|
*/
|
|
85
83
|
interface TriggerResponse {
|
|
86
|
-
|
|
84
|
+
id: string;
|
|
87
85
|
}
|
|
88
86
|
/**
|
|
89
87
|
* Response from client.getStatus() - includes run details and steps
|
|
@@ -113,7 +111,6 @@ interface StepRetryOptions {
|
|
|
113
111
|
* Options for serve() function
|
|
114
112
|
*/
|
|
115
113
|
interface ServeOptions {
|
|
116
|
-
baseUrl?: string;
|
|
117
114
|
retries?: number;
|
|
118
115
|
signingSecret?: string;
|
|
119
116
|
}
|
|
@@ -781,7 +778,7 @@ declare class WorkflowsAPI extends BaseClient {
|
|
|
781
778
|
*
|
|
782
779
|
* @example
|
|
783
780
|
* ```typescript
|
|
784
|
-
* const {
|
|
781
|
+
* const { id } = await qb.workflows.trigger(
|
|
785
782
|
* "user-onboarding",
|
|
786
783
|
* "https://your-app.com/api/workflows/onboarding",
|
|
787
784
|
* { userId: "123", email: "user@example.com" },
|
|
@@ -825,12 +822,12 @@ declare class WorkflowsAPI extends BaseClient {
|
|
|
825
822
|
* @example
|
|
826
823
|
* ```typescript
|
|
827
824
|
* const result = await qb.workflows.retry(runId);
|
|
828
|
-
* console.log(result.
|
|
825
|
+
* console.log(result.id);
|
|
829
826
|
* console.log(result.resumed); // true
|
|
830
827
|
* ```
|
|
831
828
|
*/
|
|
832
829
|
retry(runId: string): Promise<{
|
|
833
|
-
|
|
830
|
+
id: string;
|
|
834
831
|
resumed: boolean;
|
|
835
832
|
}>;
|
|
836
833
|
/**
|
|
@@ -919,8 +916,6 @@ declare class WorkflowsAPI extends BaseClient {
|
|
|
919
916
|
* QueueBear client options
|
|
920
917
|
*/
|
|
921
918
|
interface QueueBearOptions {
|
|
922
|
-
/** Base URL of your QueueBear instance */
|
|
923
|
-
baseUrl: string;
|
|
924
919
|
/** API key (qb_live_* or qb_test_*) */
|
|
925
920
|
apiKey: string;
|
|
926
921
|
/** Project ID */
|
|
@@ -937,7 +932,6 @@ interface QueueBearOptions {
|
|
|
937
932
|
* import { QueueBear, serve } from "@queuebear/workflow";
|
|
938
933
|
*
|
|
939
934
|
* const qb = new QueueBear({
|
|
940
|
-
* baseUrl: "https://your-queuebear-instance.com",
|
|
941
935
|
* apiKey: "qb_live_xxx",
|
|
942
936
|
* projectId: "proj_xxx",
|
|
943
937
|
* });
|
|
@@ -1109,6 +1103,22 @@ declare class WorkflowPausedError extends Error {
|
|
|
1109
1103
|
reason: string;
|
|
1110
1104
|
constructor(reason: string);
|
|
1111
1105
|
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Error thrown when parallel execution has failures
|
|
1108
|
+
*/
|
|
1109
|
+
declare class ParallelExecutionError extends Error {
|
|
1110
|
+
errors: Array<{
|
|
1111
|
+
index: number;
|
|
1112
|
+
stepName: string;
|
|
1113
|
+
error: Error;
|
|
1114
|
+
}>;
|
|
1115
|
+
constructor(message: string, errors: Array<{
|
|
1116
|
+
index: number;
|
|
1117
|
+
stepName: string;
|
|
1118
|
+
error: Error;
|
|
1119
|
+
}>);
|
|
1120
|
+
get failedStepCount(): number;
|
|
1121
|
+
}
|
|
1112
1122
|
/**
|
|
1113
1123
|
* Context options for creating a new WorkflowContext
|
|
1114
1124
|
*/
|
|
@@ -1116,26 +1126,17 @@ interface WorkflowContextOptions<T> {
|
|
|
1116
1126
|
runId: string;
|
|
1117
1127
|
runToken: string;
|
|
1118
1128
|
input: T;
|
|
1119
|
-
baseUrl: string;
|
|
1120
1129
|
authHeader: string;
|
|
1121
1130
|
}
|
|
1122
1131
|
/**
|
|
1123
1132
|
* WorkflowContext provides methods for executing workflow steps
|
|
1124
1133
|
*/
|
|
1125
|
-
|
|
1134
|
+
interface WorkflowContext<T> {
|
|
1126
1135
|
readonly runId: string;
|
|
1127
1136
|
readonly input: T;
|
|
1128
|
-
private runToken;
|
|
1129
|
-
private baseUrl;
|
|
1130
|
-
private authHeader;
|
|
1131
|
-
private stepIndex;
|
|
1132
|
-
constructor(options: WorkflowContextOptions<T>);
|
|
1133
1137
|
/**
|
|
1134
1138
|
* Execute a step with caching
|
|
1135
1139
|
* Step names must be unique within a workflow run
|
|
1136
|
-
* @param stepName - Unique name for this step
|
|
1137
|
-
* @param fn - Function to execute
|
|
1138
|
-
* @param options - Optional retry configuration
|
|
1139
1140
|
*/
|
|
1140
1141
|
run<R>(stepName: string, fn: () => Promise<R>, options?: StepRetryOptions): Promise<R>;
|
|
1141
1142
|
/**
|
|
@@ -1158,44 +1159,26 @@ declare class WorkflowContext<T> {
|
|
|
1158
1159
|
call<R>(stepName: string, config: CallConfig): Promise<R>;
|
|
1159
1160
|
/**
|
|
1160
1161
|
* Wait for an external event
|
|
1161
|
-
* @param stepName - Unique step name
|
|
1162
|
-
* @param eventName - Name of the event to wait for
|
|
1163
|
-
* @param options - Optional event key and timeout
|
|
1164
1162
|
*/
|
|
1165
|
-
waitForEvent<
|
|
1163
|
+
waitForEvent<E = unknown>(stepName: string, eventName: string, options?: WaitForEventOptions): Promise<E>;
|
|
1166
1164
|
/**
|
|
1167
1165
|
* Send a fire-and-forget notification event
|
|
1168
|
-
* @param eventName - Name of the event to send
|
|
1169
|
-
* @param payload - Optional payload to include
|
|
1170
1166
|
*/
|
|
1171
1167
|
notify(eventName: string, payload?: unknown): Promise<void>;
|
|
1172
1168
|
/**
|
|
1173
1169
|
* Execute multiple steps in parallel
|
|
1174
|
-
* @param steps - Array of step definitions with name and function
|
|
1175
1170
|
*/
|
|
1176
|
-
parallel<
|
|
1177
|
-
[K in keyof
|
|
1171
|
+
parallel<R extends readonly unknown[]>(steps: {
|
|
1172
|
+
[K in keyof R]: {
|
|
1178
1173
|
name: string;
|
|
1179
|
-
fn: () => Promise<
|
|
1174
|
+
fn: () => Promise<R[K]>;
|
|
1180
1175
|
};
|
|
1181
|
-
}): Promise<
|
|
1176
|
+
}): Promise<R>;
|
|
1182
1177
|
}
|
|
1183
1178
|
/**
|
|
1184
|
-
*
|
|
1179
|
+
* Create a workflow context for executing workflow steps
|
|
1185
1180
|
*/
|
|
1186
|
-
declare
|
|
1187
|
-
errors: Array<{
|
|
1188
|
-
index: number;
|
|
1189
|
-
stepName: string;
|
|
1190
|
-
error: Error;
|
|
1191
|
-
}>;
|
|
1192
|
-
constructor(message: string, errors: Array<{
|
|
1193
|
-
index: number;
|
|
1194
|
-
stepName: string;
|
|
1195
|
-
error: Error;
|
|
1196
|
-
}>);
|
|
1197
|
-
get failedStepCount(): number;
|
|
1198
|
-
}
|
|
1181
|
+
declare function createWorkflowContext<T>(options: WorkflowContextOptions<T>): WorkflowContext<T>;
|
|
1199
1182
|
|
|
1200
1183
|
/**
|
|
1201
1184
|
* Workflow handler function type
|
|
@@ -1206,4 +1189,4 @@ type WorkflowHandler<TInput = unknown, TOutput = unknown> = (context: WorkflowCo
|
|
|
1206
1189
|
*/
|
|
1207
1190
|
declare function serve<TInput = unknown, TOutput = unknown>(handler: WorkflowHandler<TInput, TOutput>, options?: ServeOptions): (request: Request) => Promise<Response>;
|
|
1208
1191
|
|
|
1209
|
-
export { type CallConfig, type CancelMessageResponse, type CompletedStep, type CreateScheduleOptions, type CreateScheduleResponse, DLQAPI, type DLQEntry, type DLQEntrySummary, type DeleteDLQResponse, type DeleteScheduleResponse, type DeliveryLog, type LastResponse, type ListDLQOptions, type ListDLQResponse, type ListMessagesOptions, type ListMessagesResponse, type ListRunsOptions, type ListRunsResponse, type ListSchedulesOptions, type ListSchedulesResponse, type Message, type MessageMethod, type MessageStatus, type MessageSummary, MessagesAPI, type Pagination, ParallelExecutionError, type ParallelStepDefinition, type PauseScheduleResponse, type PublishOptions, type PublishResponse, type PurgeDLQResponse, QueueBear, QueueBearError, type QueueBearOptions, type ResumeScheduleResponse, type RetryDLQResponse, type Schedule, type ScheduleSummary, SchedulesAPI, type SendEventOptions, type SendEventResponse, type ServeOptions, type StatusResponse, type StepRetryOptions, type StepType, type TriggerOptions, type TriggerResponse, type WaitForEventOptions, WorkflowContext, type WorkflowContextOptions, type WorkflowHandler, WorkflowPausedError, type WorkflowRun, type WorkflowRunStatus, type WorkflowStep, WorkflowsAPI, serve };
|
|
1192
|
+
export { type CallConfig, type CancelMessageResponse, type CompletedStep, type CreateScheduleOptions, type CreateScheduleResponse, DLQAPI, type DLQEntry, type DLQEntrySummary, type DeleteDLQResponse, type DeleteScheduleResponse, type DeliveryLog, type LastResponse, type ListDLQOptions, type ListDLQResponse, type ListMessagesOptions, type ListMessagesResponse, type ListRunsOptions, type ListRunsResponse, type ListSchedulesOptions, type ListSchedulesResponse, type Message, type MessageMethod, type MessageStatus, type MessageSummary, MessagesAPI, type Pagination, ParallelExecutionError, type ParallelStepDefinition, type PauseScheduleResponse, type PublishOptions, type PublishResponse, type PurgeDLQResponse, QueueBear, QueueBearError, type QueueBearOptions, type ResumeScheduleResponse, type RetryDLQResponse, type Schedule, type ScheduleSummary, SchedulesAPI, type SendEventOptions, type SendEventResponse, type ServeOptions, type StatusResponse, type StepRetryOptions, type StepType, type TriggerOptions, type TriggerResponse, type WaitForEventOptions, type WorkflowContext, type WorkflowContextOptions, type WorkflowHandler, WorkflowPausedError, type WorkflowRun, type WorkflowRunStatus, type WorkflowStep, WorkflowsAPI, createWorkflowContext, serve };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
// src/api/base.ts
|
|
2
2
|
var BaseClient = class {
|
|
3
|
-
baseUrl;
|
|
4
3
|
apiKey;
|
|
5
4
|
projectId;
|
|
6
5
|
constructor(options) {
|
|
7
|
-
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
8
6
|
this.apiKey = options.apiKey;
|
|
9
7
|
this.projectId = options.projectId;
|
|
10
8
|
}
|
|
@@ -12,7 +10,9 @@ var BaseClient = class {
|
|
|
12
10
|
* Build the full URL for a project-scoped endpoint
|
|
13
11
|
*/
|
|
14
12
|
buildUrl(path, queryParams) {
|
|
15
|
-
const url = new URL(
|
|
13
|
+
const url = new URL(
|
|
14
|
+
`https://api.queuebear.com/v1/projects/${this.projectId}${path}`
|
|
15
|
+
);
|
|
16
16
|
if (queryParams) {
|
|
17
17
|
for (const [key, value] of Object.entries(queryParams)) {
|
|
18
18
|
if (value !== void 0) {
|
|
@@ -80,36 +80,36 @@ var MessagesAPI = class extends BaseClient {
|
|
|
80
80
|
* ```
|
|
81
81
|
*/
|
|
82
82
|
async publish(destination, body, options) {
|
|
83
|
-
const
|
|
84
|
-
|
|
83
|
+
const requestBody = {
|
|
84
|
+
destination,
|
|
85
|
+
body
|
|
85
86
|
};
|
|
86
87
|
if (options?.delay) {
|
|
87
|
-
|
|
88
|
+
requestBody.delay = options.delay;
|
|
88
89
|
}
|
|
89
90
|
if (options?.retries !== void 0) {
|
|
90
|
-
|
|
91
|
+
requestBody.retries = options.retries;
|
|
91
92
|
}
|
|
92
93
|
if (options?.method) {
|
|
93
|
-
|
|
94
|
+
requestBody.method = options.method;
|
|
94
95
|
}
|
|
95
96
|
if (options?.callbackUrl) {
|
|
96
|
-
|
|
97
|
+
requestBody.callbackUrl = options.callbackUrl;
|
|
97
98
|
}
|
|
98
99
|
if (options?.failureCallbackUrl) {
|
|
99
|
-
|
|
100
|
+
requestBody.failureCallbackUrl = options.failureCallbackUrl;
|
|
100
101
|
}
|
|
101
102
|
if (options?.deduplicationId) {
|
|
102
|
-
|
|
103
|
+
requestBody.deduplicationId = options.deduplicationId;
|
|
103
104
|
}
|
|
104
105
|
if (options?.headers) {
|
|
105
|
-
|
|
106
|
-
headers[`queuebear-forward-${key}`] = value;
|
|
107
|
-
}
|
|
106
|
+
requestBody.headers = options.headers;
|
|
108
107
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
return this.request("POST", "/publish", {
|
|
109
|
+
body: requestBody,
|
|
110
|
+
headers: {
|
|
111
|
+
"Content-Type": "application/json"
|
|
112
|
+
}
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
@@ -468,7 +468,7 @@ var WorkflowsAPI = class extends BaseClient {
|
|
|
468
468
|
*
|
|
469
469
|
* @example
|
|
470
470
|
* ```typescript
|
|
471
|
-
* const {
|
|
471
|
+
* const { id } = await qb.workflows.trigger(
|
|
472
472
|
* "user-onboarding",
|
|
473
473
|
* "https://your-app.com/api/workflows/onboarding",
|
|
474
474
|
* { userId: "123", email: "user@example.com" },
|
|
@@ -526,7 +526,7 @@ var WorkflowsAPI = class extends BaseClient {
|
|
|
526
526
|
* @example
|
|
527
527
|
* ```typescript
|
|
528
528
|
* const result = await qb.workflows.retry(runId);
|
|
529
|
-
* console.log(result.
|
|
529
|
+
* console.log(result.id);
|
|
530
530
|
* console.log(result.resumed); // true
|
|
531
531
|
* ```
|
|
532
532
|
*/
|
|
@@ -646,8 +646,8 @@ var WorkflowsAPI = class extends BaseClient {
|
|
|
646
646
|
*/
|
|
647
647
|
async triggerAndWait(workflowId, workflowUrl, input, options) {
|
|
648
648
|
const { pollIntervalMs, timeoutMs, ...triggerOptions } = options || {};
|
|
649
|
-
const {
|
|
650
|
-
return this.waitForCompletion(
|
|
649
|
+
const { id } = await this.trigger(workflowId, workflowUrl, input, triggerOptions);
|
|
650
|
+
return this.waitForCompletion(id, { pollIntervalMs, timeoutMs });
|
|
651
651
|
}
|
|
652
652
|
};
|
|
653
653
|
|
|
@@ -748,7 +748,6 @@ var QueueBear = class {
|
|
|
748
748
|
workflows;
|
|
749
749
|
constructor(options) {
|
|
750
750
|
this.options = {
|
|
751
|
-
baseUrl: options.baseUrl.replace(/\/$/, ""),
|
|
752
751
|
apiKey: options.apiKey,
|
|
753
752
|
projectId: options.projectId
|
|
754
753
|
};
|
|
@@ -803,11 +802,17 @@ var QueueBear = class {
|
|
|
803
802
|
* ```
|
|
804
803
|
*/
|
|
805
804
|
async triggerAndWait(workflowId, workflowUrl, input, options) {
|
|
806
|
-
return this.workflows.triggerAndWait(
|
|
805
|
+
return this.workflows.triggerAndWait(
|
|
806
|
+
workflowId,
|
|
807
|
+
workflowUrl,
|
|
808
|
+
input,
|
|
809
|
+
options
|
|
810
|
+
);
|
|
807
811
|
}
|
|
808
812
|
};
|
|
809
813
|
|
|
810
814
|
// src/context.ts
|
|
815
|
+
var BASE_URL = "https://api.queuebear.com/v1/workflows";
|
|
811
816
|
var WorkflowPausedError = class extends Error {
|
|
812
817
|
constructor(reason) {
|
|
813
818
|
super(reason);
|
|
@@ -815,63 +820,55 @@ var WorkflowPausedError = class extends Error {
|
|
|
815
820
|
this.name = "WorkflowPausedError";
|
|
816
821
|
}
|
|
817
822
|
};
|
|
818
|
-
var
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
authHeader;
|
|
824
|
-
stepIndex = 0;
|
|
825
|
-
constructor(options) {
|
|
826
|
-
this.runId = options.runId;
|
|
827
|
-
this.runToken = options.runToken;
|
|
828
|
-
this.input = options.input;
|
|
829
|
-
this.baseUrl = options.baseUrl;
|
|
830
|
-
this.authHeader = options.authHeader;
|
|
823
|
+
var ParallelExecutionError = class extends Error {
|
|
824
|
+
constructor(message, errors) {
|
|
825
|
+
super(message);
|
|
826
|
+
this.errors = errors;
|
|
827
|
+
this.name = "ParallelExecutionError";
|
|
831
828
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
async
|
|
829
|
+
get failedStepCount() {
|
|
830
|
+
return this.errors.length;
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
function createWorkflowContext(options) {
|
|
834
|
+
const { runId, runToken, input, authHeader } = options;
|
|
835
|
+
let stepIndex = 0;
|
|
836
|
+
const run = async (stepName, fn, retryOptions) => {
|
|
840
837
|
const checkResponse = await fetch(
|
|
841
|
-
`${
|
|
838
|
+
`${BASE_URL}/internal/step/check`,
|
|
842
839
|
{
|
|
843
840
|
method: "POST",
|
|
844
841
|
headers: {
|
|
845
842
|
"Content-Type": "application/json",
|
|
846
|
-
Authorization:
|
|
847
|
-
"X-QueueBear-Run-Token":
|
|
843
|
+
Authorization: authHeader,
|
|
844
|
+
"X-QueueBear-Run-Token": runToken
|
|
848
845
|
},
|
|
849
846
|
body: JSON.stringify({
|
|
850
|
-
runId
|
|
847
|
+
runId,
|
|
851
848
|
stepName
|
|
852
849
|
})
|
|
853
850
|
}
|
|
854
851
|
);
|
|
855
852
|
const checkData = await checkResponse.json();
|
|
856
853
|
if (checkData.cached) {
|
|
857
|
-
|
|
854
|
+
stepIndex++;
|
|
858
855
|
return checkData.result;
|
|
859
856
|
}
|
|
860
857
|
const startResponse = await fetch(
|
|
861
|
-
`${
|
|
858
|
+
`${BASE_URL}/internal/step/start`,
|
|
862
859
|
{
|
|
863
860
|
method: "POST",
|
|
864
861
|
headers: {
|
|
865
862
|
"Content-Type": "application/json",
|
|
866
|
-
Authorization:
|
|
867
|
-
"X-QueueBear-Run-Token":
|
|
863
|
+
Authorization: authHeader,
|
|
864
|
+
"X-QueueBear-Run-Token": runToken
|
|
868
865
|
},
|
|
869
866
|
body: JSON.stringify({
|
|
870
|
-
runId
|
|
867
|
+
runId,
|
|
871
868
|
stepName,
|
|
872
|
-
stepIndex
|
|
869
|
+
stepIndex,
|
|
873
870
|
stepType: "run",
|
|
874
|
-
retryOptions
|
|
871
|
+
retryOptions
|
|
875
872
|
})
|
|
876
873
|
}
|
|
877
874
|
);
|
|
@@ -881,76 +878,72 @@ var WorkflowContext = class {
|
|
|
881
878
|
}
|
|
882
879
|
try {
|
|
883
880
|
const result = await fn();
|
|
884
|
-
await fetch(`${
|
|
881
|
+
await fetch(`${BASE_URL}/internal/step/complete`, {
|
|
885
882
|
method: "POST",
|
|
886
883
|
headers: {
|
|
887
884
|
"Content-Type": "application/json",
|
|
888
|
-
Authorization:
|
|
889
|
-
"X-QueueBear-Run-Token":
|
|
885
|
+
Authorization: authHeader,
|
|
886
|
+
"X-QueueBear-Run-Token": runToken
|
|
890
887
|
},
|
|
891
888
|
body: JSON.stringify({
|
|
892
|
-
runId
|
|
889
|
+
runId,
|
|
893
890
|
stepName,
|
|
894
891
|
result
|
|
895
892
|
})
|
|
896
893
|
});
|
|
897
|
-
|
|
894
|
+
stepIndex++;
|
|
898
895
|
return result;
|
|
899
896
|
} catch (error) {
|
|
900
|
-
await fetch(`${
|
|
897
|
+
await fetch(`${BASE_URL}/internal/step/fail`, {
|
|
901
898
|
method: "POST",
|
|
902
899
|
headers: {
|
|
903
900
|
"Content-Type": "application/json",
|
|
904
|
-
Authorization:
|
|
905
|
-
"X-QueueBear-Run-Token":
|
|
901
|
+
Authorization: authHeader,
|
|
902
|
+
"X-QueueBear-Run-Token": runToken
|
|
906
903
|
},
|
|
907
904
|
body: JSON.stringify({
|
|
908
|
-
runId
|
|
905
|
+
runId,
|
|
909
906
|
stepName,
|
|
910
907
|
error: error instanceof Error ? error.message : String(error)
|
|
911
908
|
})
|
|
912
909
|
});
|
|
913
910
|
throw error;
|
|
914
911
|
}
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
* Sleep for specified seconds
|
|
918
|
-
* Step names must be unique within a workflow run
|
|
919
|
-
*/
|
|
920
|
-
async sleep(stepName, seconds) {
|
|
912
|
+
};
|
|
913
|
+
const sleep = async (stepName, seconds) => {
|
|
921
914
|
const checkResponse = await fetch(
|
|
922
|
-
`${
|
|
915
|
+
`${BASE_URL}/internal/step/check`,
|
|
923
916
|
{
|
|
924
917
|
method: "POST",
|
|
925
918
|
headers: {
|
|
926
919
|
"Content-Type": "application/json",
|
|
927
|
-
Authorization:
|
|
928
|
-
"X-QueueBear-Run-Token":
|
|
920
|
+
Authorization: authHeader,
|
|
921
|
+
"X-QueueBear-Run-Token": runToken
|
|
929
922
|
},
|
|
930
923
|
body: JSON.stringify({
|
|
931
|
-
runId
|
|
924
|
+
runId,
|
|
932
925
|
stepName
|
|
933
926
|
})
|
|
934
927
|
}
|
|
935
928
|
);
|
|
936
929
|
const checkData = await checkResponse.json();
|
|
937
930
|
if (checkData.cached) {
|
|
938
|
-
|
|
931
|
+
stepIndex++;
|
|
939
932
|
return;
|
|
940
933
|
}
|
|
941
934
|
const sleepResponse = await fetch(
|
|
942
|
-
`${
|
|
935
|
+
`${BASE_URL}/internal/sleep`,
|
|
943
936
|
{
|
|
944
937
|
method: "POST",
|
|
945
938
|
headers: {
|
|
946
939
|
"Content-Type": "application/json",
|
|
947
|
-
Authorization:
|
|
948
|
-
"X-QueueBear-Run-Token":
|
|
940
|
+
Authorization: authHeader,
|
|
941
|
+
"X-QueueBear-Run-Token": runToken
|
|
949
942
|
},
|
|
950
943
|
body: JSON.stringify({
|
|
951
|
-
runId
|
|
944
|
+
runId,
|
|
952
945
|
stepName,
|
|
953
|
-
stepIndex
|
|
946
|
+
stepIndex,
|
|
954
947
|
seconds
|
|
955
948
|
})
|
|
956
949
|
}
|
|
@@ -960,28 +953,21 @@ var WorkflowContext = class {
|
|
|
960
953
|
throw new Error(errorData.error || "Failed to schedule sleep");
|
|
961
954
|
}
|
|
962
955
|
throw new WorkflowPausedError(`Sleeping for ${seconds}s`);
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
* Sleep until specific date
|
|
966
|
-
*/
|
|
967
|
-
async sleepUntil(stepName, until) {
|
|
956
|
+
};
|
|
957
|
+
const sleepUntil = async (stepName, until) => {
|
|
968
958
|
const seconds = Math.max(
|
|
969
959
|
0,
|
|
970
960
|
Math.ceil((until.getTime() - Date.now()) / 1e3)
|
|
971
961
|
);
|
|
972
|
-
return
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
* Get all completed steps for the current run
|
|
976
|
-
* Useful for inspecting progress or debugging
|
|
977
|
-
*/
|
|
978
|
-
async getCompletedSteps() {
|
|
962
|
+
return sleep(stepName, seconds);
|
|
963
|
+
};
|
|
964
|
+
const getCompletedSteps = async () => {
|
|
979
965
|
const response = await fetch(
|
|
980
|
-
`${
|
|
966
|
+
`${BASE_URL}/internal/steps/${runId}`,
|
|
981
967
|
{
|
|
982
968
|
headers: {
|
|
983
|
-
Authorization:
|
|
984
|
-
"X-QueueBear-Run-Token":
|
|
969
|
+
Authorization: authHeader,
|
|
970
|
+
"X-QueueBear-Run-Token": runToken
|
|
985
971
|
}
|
|
986
972
|
}
|
|
987
973
|
);
|
|
@@ -990,12 +976,9 @@ var WorkflowContext = class {
|
|
|
990
976
|
}
|
|
991
977
|
const data = await response.json();
|
|
992
978
|
return data.steps;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
*/
|
|
997
|
-
async call(stepName, config) {
|
|
998
|
-
return this.run(stepName, async () => {
|
|
979
|
+
};
|
|
980
|
+
const call = async (stepName, config) => {
|
|
981
|
+
return run(stepName, async () => {
|
|
999
982
|
const response = await fetch(config.url, {
|
|
1000
983
|
method: config.method || "GET",
|
|
1001
984
|
headers: {
|
|
@@ -1013,53 +996,47 @@ var WorkflowContext = class {
|
|
|
1013
996
|
}
|
|
1014
997
|
return response.text();
|
|
1015
998
|
});
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
* Wait for an external event
|
|
1019
|
-
* @param stepName - Unique step name
|
|
1020
|
-
* @param eventName - Name of the event to wait for
|
|
1021
|
-
* @param options - Optional event key and timeout
|
|
1022
|
-
*/
|
|
1023
|
-
async waitForEvent(stepName, eventName, options) {
|
|
999
|
+
};
|
|
1000
|
+
const waitForEvent = async (stepName, eventName, eventOptions) => {
|
|
1024
1001
|
const checkResponse = await fetch(
|
|
1025
|
-
`${
|
|
1002
|
+
`${BASE_URL}/internal/event/check`,
|
|
1026
1003
|
{
|
|
1027
1004
|
method: "POST",
|
|
1028
1005
|
headers: {
|
|
1029
1006
|
"Content-Type": "application/json",
|
|
1030
|
-
Authorization:
|
|
1031
|
-
"X-QueueBear-Run-Token":
|
|
1007
|
+
Authorization: authHeader,
|
|
1008
|
+
"X-QueueBear-Run-Token": runToken
|
|
1032
1009
|
},
|
|
1033
1010
|
body: JSON.stringify({
|
|
1034
|
-
runId
|
|
1011
|
+
runId,
|
|
1035
1012
|
stepName
|
|
1036
1013
|
})
|
|
1037
1014
|
}
|
|
1038
1015
|
);
|
|
1039
1016
|
const checkData = await checkResponse.json();
|
|
1040
1017
|
if (checkData.received) {
|
|
1041
|
-
|
|
1018
|
+
stepIndex++;
|
|
1042
1019
|
return checkData.payload;
|
|
1043
1020
|
}
|
|
1044
1021
|
if (checkData.expired) {
|
|
1045
1022
|
throw new Error(`Event "${eventName}" timed out`);
|
|
1046
1023
|
}
|
|
1047
1024
|
const waitResponse = await fetch(
|
|
1048
|
-
`${
|
|
1025
|
+
`${BASE_URL}/internal/event/wait`,
|
|
1049
1026
|
{
|
|
1050
1027
|
method: "POST",
|
|
1051
1028
|
headers: {
|
|
1052
1029
|
"Content-Type": "application/json",
|
|
1053
|
-
Authorization:
|
|
1054
|
-
"X-QueueBear-Run-Token":
|
|
1030
|
+
Authorization: authHeader,
|
|
1031
|
+
"X-QueueBear-Run-Token": runToken
|
|
1055
1032
|
},
|
|
1056
1033
|
body: JSON.stringify({
|
|
1057
|
-
runId
|
|
1034
|
+
runId,
|
|
1058
1035
|
stepName,
|
|
1059
|
-
stepIndex
|
|
1036
|
+
stepIndex,
|
|
1060
1037
|
eventName,
|
|
1061
|
-
eventKey:
|
|
1062
|
-
timeoutSeconds:
|
|
1038
|
+
eventKey: eventOptions?.eventKey,
|
|
1039
|
+
timeoutSeconds: eventOptions?.timeoutSeconds
|
|
1063
1040
|
})
|
|
1064
1041
|
}
|
|
1065
1042
|
);
|
|
@@ -1068,20 +1045,15 @@ var WorkflowContext = class {
|
|
|
1068
1045
|
throw new Error(errorData.error || "Failed to register event wait");
|
|
1069
1046
|
}
|
|
1070
1047
|
throw new WorkflowPausedError(`Waiting for event: ${eventName}`);
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
* Send a fire-and-forget notification event
|
|
1074
|
-
* @param eventName - Name of the event to send
|
|
1075
|
-
* @param payload - Optional payload to include
|
|
1076
|
-
*/
|
|
1077
|
-
async notify(eventName, payload) {
|
|
1048
|
+
};
|
|
1049
|
+
const notify = async (eventName, payload) => {
|
|
1078
1050
|
const response = await fetch(
|
|
1079
|
-
`${
|
|
1051
|
+
`${BASE_URL}/events/${encodeURIComponent(eventName)}`,
|
|
1080
1052
|
{
|
|
1081
1053
|
method: "POST",
|
|
1082
1054
|
headers: {
|
|
1083
1055
|
"Content-Type": "application/json",
|
|
1084
|
-
Authorization:
|
|
1056
|
+
Authorization: authHeader
|
|
1085
1057
|
},
|
|
1086
1058
|
body: JSON.stringify({ payload })
|
|
1087
1059
|
}
|
|
@@ -1090,24 +1062,20 @@ var WorkflowContext = class {
|
|
|
1090
1062
|
const errorData = await response.json();
|
|
1091
1063
|
throw new Error(errorData.error || `Failed to send event: ${eventName}`);
|
|
1092
1064
|
}
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
* Execute multiple steps in parallel
|
|
1096
|
-
* @param steps - Array of step definitions with name and function
|
|
1097
|
-
*/
|
|
1098
|
-
async parallel(steps) {
|
|
1065
|
+
};
|
|
1066
|
+
const parallel = async (steps) => {
|
|
1099
1067
|
const stepNames = steps.map((s) => s.name);
|
|
1100
1068
|
const batchResponse = await fetch(
|
|
1101
|
-
`${
|
|
1069
|
+
`${BASE_URL}/internal/steps/batch-check`,
|
|
1102
1070
|
{
|
|
1103
1071
|
method: "POST",
|
|
1104
1072
|
headers: {
|
|
1105
1073
|
"Content-Type": "application/json",
|
|
1106
|
-
Authorization:
|
|
1107
|
-
"X-QueueBear-Run-Token":
|
|
1074
|
+
Authorization: authHeader,
|
|
1075
|
+
"X-QueueBear-Run-Token": runToken
|
|
1108
1076
|
},
|
|
1109
1077
|
body: JSON.stringify({
|
|
1110
|
-
runId
|
|
1078
|
+
runId,
|
|
1111
1079
|
stepNames
|
|
1112
1080
|
})
|
|
1113
1081
|
}
|
|
@@ -1126,7 +1094,7 @@ var WorkflowContext = class {
|
|
|
1126
1094
|
results[i] = cached.result;
|
|
1127
1095
|
} else {
|
|
1128
1096
|
pendingPromises.push(
|
|
1129
|
-
|
|
1097
|
+
run(step.name, step.fn).then((result) => {
|
|
1130
1098
|
results[i] = result;
|
|
1131
1099
|
}).catch((error) => {
|
|
1132
1100
|
errors.push({
|
|
@@ -1147,26 +1115,28 @@ var WorkflowContext = class {
|
|
|
1147
1115
|
);
|
|
1148
1116
|
}
|
|
1149
1117
|
return results;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1118
|
+
};
|
|
1119
|
+
return {
|
|
1120
|
+
runId,
|
|
1121
|
+
input,
|
|
1122
|
+
run,
|
|
1123
|
+
sleep,
|
|
1124
|
+
sleepUntil,
|
|
1125
|
+
getCompletedSteps,
|
|
1126
|
+
call,
|
|
1127
|
+
waitForEvent,
|
|
1128
|
+
notify,
|
|
1129
|
+
parallel
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1162
1132
|
|
|
1163
1133
|
// src/serve.ts
|
|
1164
1134
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
1135
|
+
var BASE_URL2 = "https://api.queuebear.com/v1/workflows";
|
|
1165
1136
|
function serve(handler, options) {
|
|
1166
1137
|
return async (request) => {
|
|
1167
1138
|
let runId;
|
|
1168
1139
|
let runToken;
|
|
1169
|
-
let baseUrl;
|
|
1170
1140
|
try {
|
|
1171
1141
|
if (options?.signingSecret) {
|
|
1172
1142
|
const signature = request.headers.get("X-QueueBear-Signature");
|
|
@@ -1187,15 +1157,11 @@ function serve(handler, options) {
|
|
|
1187
1157
|
headers: { "Content-Type": "application/json" }
|
|
1188
1158
|
});
|
|
1189
1159
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
{
|
|
1194
|
-
headers: {
|
|
1195
|
-
Authorization: request.headers.get("Authorization") || ""
|
|
1196
|
-
}
|
|
1160
|
+
const runResponse = await fetch(`${BASE_URL2}/runs/${runId}`, {
|
|
1161
|
+
headers: {
|
|
1162
|
+
Authorization: request.headers.get("Authorization") || ""
|
|
1197
1163
|
}
|
|
1198
|
-
);
|
|
1164
|
+
});
|
|
1199
1165
|
if (!runResponse.ok) {
|
|
1200
1166
|
return new Response(
|
|
1201
1167
|
JSON.stringify({ error: "Failed to fetch workflow run" }),
|
|
@@ -1206,15 +1172,14 @@ function serve(handler, options) {
|
|
|
1206
1172
|
);
|
|
1207
1173
|
}
|
|
1208
1174
|
const runData = await runResponse.json();
|
|
1209
|
-
const context =
|
|
1175
|
+
const context = createWorkflowContext({
|
|
1210
1176
|
runId,
|
|
1211
1177
|
runToken,
|
|
1212
1178
|
input: runData.input,
|
|
1213
|
-
baseUrl,
|
|
1214
1179
|
authHeader: request.headers.get("Authorization") || ""
|
|
1215
1180
|
});
|
|
1216
1181
|
const result = await handler(context);
|
|
1217
|
-
await fetch(`${
|
|
1182
|
+
await fetch(`${BASE_URL2}/internal/complete`, {
|
|
1218
1183
|
method: "POST",
|
|
1219
1184
|
headers: {
|
|
1220
1185
|
"Content-Type": "application/json",
|
|
@@ -1242,9 +1207,9 @@ function serve(handler, options) {
|
|
|
1242
1207
|
);
|
|
1243
1208
|
}
|
|
1244
1209
|
console.error("[Workflow] Unhandled error - failing run:", error);
|
|
1245
|
-
if (runId && runToken
|
|
1210
|
+
if (runId && runToken) {
|
|
1246
1211
|
try {
|
|
1247
|
-
await fetch(`${
|
|
1212
|
+
await fetch(`${BASE_URL2}/internal/fail`, {
|
|
1248
1213
|
method: "POST",
|
|
1249
1214
|
headers: {
|
|
1250
1215
|
"Content-Type": "application/json",
|
|
@@ -1275,14 +1240,11 @@ function serve(handler, options) {
|
|
|
1275
1240
|
}
|
|
1276
1241
|
function verifySignature(body, signature, secret) {
|
|
1277
1242
|
if (!signature) return false;
|
|
1278
|
-
const parts = signature.split(",").reduce(
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
},
|
|
1284
|
-
{}
|
|
1285
|
-
);
|
|
1243
|
+
const parts = signature.split(",").reduce((acc, part) => {
|
|
1244
|
+
const [key, value] = part.split("=");
|
|
1245
|
+
acc[key] = value;
|
|
1246
|
+
return acc;
|
|
1247
|
+
}, {});
|
|
1286
1248
|
if (!parts.t || !parts.v1) return false;
|
|
1287
1249
|
const timestamp = parseInt(parts.t, 10);
|
|
1288
1250
|
const now = Math.floor(Date.now() / 1e3);
|
|
@@ -1295,10 +1257,6 @@ function verifySignature(body, signature, secret) {
|
|
|
1295
1257
|
return false;
|
|
1296
1258
|
}
|
|
1297
1259
|
}
|
|
1298
|
-
function getBaseUrl(request) {
|
|
1299
|
-
const url = new URL(request.url);
|
|
1300
|
-
return `${url.protocol}//${url.host}`;
|
|
1301
|
-
}
|
|
1302
1260
|
export {
|
|
1303
1261
|
DLQAPI,
|
|
1304
1262
|
MessagesAPI,
|
|
@@ -1306,8 +1264,8 @@ export {
|
|
|
1306
1264
|
QueueBear,
|
|
1307
1265
|
QueueBearError,
|
|
1308
1266
|
SchedulesAPI,
|
|
1309
|
-
WorkflowContext,
|
|
1310
1267
|
WorkflowPausedError,
|
|
1311
1268
|
WorkflowsAPI,
|
|
1269
|
+
createWorkflowContext,
|
|
1312
1270
|
serve
|
|
1313
1271
|
};
|