@microfox/ai-worker 1.0.2 → 1.0.3
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/CHANGELOG.md +8 -0
- package/README.md +1 -2
- package/dist/{chunk-BJPQY2NJ.mjs → chunk-72XGFZCE.mjs} +61 -84
- package/dist/chunk-72XGFZCE.mjs.map +1 -0
- package/dist/{chunk-4WU5ZCHS.mjs → chunk-7LQNS2SG.mjs} +78 -334
- package/dist/chunk-7LQNS2SG.mjs.map +1 -0
- package/dist/chunk-AOXGONGI.mjs +351 -0
- package/dist/chunk-AOXGONGI.mjs.map +1 -0
- package/dist/{client-D25XR0V8.d.mts → client-BqSJQ9mZ.d.mts} +34 -18
- package/dist/{client-D25XR0V8.d.ts → client-BqSJQ9mZ.d.ts} +34 -18
- package/dist/client.d.mts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +62 -83
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +5 -1
- package/dist/handler.d.mts +32 -2
- package/dist/handler.d.ts +32 -2
- package/dist/handler.js +73 -24
- package/dist/handler.js.map +1 -1
- package/dist/handler.mjs +4 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +136 -107
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10 -2
- package/dist/index.mjs.map +1 -1
- package/dist/queueJobStore.d.mts +53 -0
- package/dist/queueJobStore.d.ts +53 -0
- package/dist/queueJobStore.js +378 -0
- package/dist/queueJobStore.js.map +1 -0
- package/dist/queueJobStore.mjs +14 -0
- package/dist/queueJobStore.mjs.map +1 -0
- package/package.json +7 -2
- package/dist/chunk-4WU5ZCHS.mjs.map +0 -1
- package/dist/chunk-BJPQY2NJ.mjs.map +0 -1
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// src/queueJobStore.ts
|
|
2
|
+
import { Redis as UpstashRedis } from "@upstash/redis";
|
|
3
|
+
import { MongoClient } from "mongodb";
|
|
4
|
+
var mongoUri = process.env.DATABASE_MONGODB_URI || process.env.MONGODB_URI;
|
|
5
|
+
var mongoDbName = process.env.DATABASE_MONGODB_DB || process.env.MONGODB_DB || "mediamake";
|
|
6
|
+
var mongoQueueCollectionName = process.env.MONGODB_QUEUE_JOBS_COLLECTION || "queue_jobs";
|
|
7
|
+
var mongoClientPromise = null;
|
|
8
|
+
async function getMongoClient() {
|
|
9
|
+
if (!mongoUri) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
"MongoDB URI required for queue job store. Set DATABASE_MONGODB_URI or MONGODB_URI."
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
if (!mongoClientPromise) {
|
|
15
|
+
mongoClientPromise = new MongoClient(mongoUri, {
|
|
16
|
+
maxPoolSize: 10,
|
|
17
|
+
minPoolSize: 0,
|
|
18
|
+
serverSelectionTimeoutMS: 1e4
|
|
19
|
+
}).connect();
|
|
20
|
+
}
|
|
21
|
+
return mongoClientPromise;
|
|
22
|
+
}
|
|
23
|
+
async function getMongoQueueCollection() {
|
|
24
|
+
const client = await getMongoClient();
|
|
25
|
+
return client.db(mongoDbName).collection(mongoQueueCollectionName);
|
|
26
|
+
}
|
|
27
|
+
var redisUrl = process.env.WORKER_UPSTASH_REDIS_REST_URL || process.env.UPSTASH_REDIS_REST_URL || process.env.UPSTASH_REDIS_URL;
|
|
28
|
+
var redisToken = process.env.WORKER_UPSTASH_REDIS_REST_TOKEN || process.env.UPSTASH_REDIS_REST_TOKEN || process.env.UPSTASH_REDIS_TOKEN;
|
|
29
|
+
var queueKeyPrefix = process.env.WORKER_UPSTASH_REDIS_QUEUE_PREFIX || process.env.UPSTASH_REDIS_QUEUE_PREFIX || "worker:queue-jobs:";
|
|
30
|
+
var defaultTtlSeconds = 60 * 60 * 24 * 7;
|
|
31
|
+
var queueJobTtlSeconds = typeof process.env.WORKER_QUEUE_JOBS_TTL_SECONDS === "string" ? parseInt(process.env.WORKER_QUEUE_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds : typeof process.env.WORKER_JOBS_TTL_SECONDS === "string" ? parseInt(process.env.WORKER_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds : defaultTtlSeconds;
|
|
32
|
+
var redisClient = null;
|
|
33
|
+
function getRedis() {
|
|
34
|
+
if (!redisUrl || !redisToken) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
"Upstash Redis configuration missing for queue job store. Set WORKER_UPSTASH_REDIS_REST_URL and WORKER_UPSTASH_REDIS_REST_TOKEN (or UPSTASH_REDIS_REST_URL/UPSTASH_REDIS_REST_TOKEN)."
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
if (!redisClient) {
|
|
40
|
+
redisClient = new UpstashRedis({
|
|
41
|
+
url: redisUrl,
|
|
42
|
+
token: redisToken
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return redisClient;
|
|
46
|
+
}
|
|
47
|
+
function queueKey(id) {
|
|
48
|
+
return `${queueKeyPrefix}${id}`;
|
|
49
|
+
}
|
|
50
|
+
function stepsFromHash(val) {
|
|
51
|
+
if (Array.isArray(val)) return val;
|
|
52
|
+
if (typeof val === "string") {
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(val);
|
|
55
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
56
|
+
} catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
function metadataFromHash(val) {
|
|
63
|
+
if (val && typeof val === "object" && !Array.isArray(val)) return val;
|
|
64
|
+
if (typeof val === "string") {
|
|
65
|
+
try {
|
|
66
|
+
const parsed = JSON.parse(val);
|
|
67
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
68
|
+
} catch {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
async function loadQueueJobRedis(queueJobId) {
|
|
75
|
+
const redis = getRedis();
|
|
76
|
+
const key = queueKey(queueJobId);
|
|
77
|
+
const data = await redis.hgetall(key);
|
|
78
|
+
if (!data || typeof data !== "object" || Object.keys(data).length === 0) return null;
|
|
79
|
+
const d = data;
|
|
80
|
+
const record = {
|
|
81
|
+
id: d.id === void 0 ? queueJobId : String(d.id),
|
|
82
|
+
queueId: String(d.queueId ?? ""),
|
|
83
|
+
status: String(d.status ?? "running"),
|
|
84
|
+
steps: stepsFromHash(d.steps),
|
|
85
|
+
metadata: metadataFromHash(d.metadata),
|
|
86
|
+
createdAt: String(d.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()),
|
|
87
|
+
updatedAt: String(d.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()),
|
|
88
|
+
completedAt: d.completedAt != null ? String(d.completedAt) : void 0
|
|
89
|
+
};
|
|
90
|
+
return record;
|
|
91
|
+
}
|
|
92
|
+
async function saveQueueJobRedis(record) {
|
|
93
|
+
const redis = getRedis();
|
|
94
|
+
const key = queueKey(record.id);
|
|
95
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
96
|
+
const toSet = {
|
|
97
|
+
id: record.id,
|
|
98
|
+
queueId: record.queueId,
|
|
99
|
+
status: record.status,
|
|
100
|
+
steps: JSON.stringify(record.steps || []),
|
|
101
|
+
metadata: JSON.stringify(record.metadata || {}),
|
|
102
|
+
createdAt: record.createdAt || now,
|
|
103
|
+
updatedAt: record.updatedAt || now
|
|
104
|
+
};
|
|
105
|
+
if (record.completedAt) {
|
|
106
|
+
toSet.completedAt = record.completedAt;
|
|
107
|
+
}
|
|
108
|
+
await redis.hset(key, toSet);
|
|
109
|
+
if (queueJobTtlSeconds > 0) {
|
|
110
|
+
await redis.expire(key, queueJobTtlSeconds);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function getStoreType() {
|
|
114
|
+
const t = (process.env.WORKER_DATABASE_TYPE || "upstash-redis").toLowerCase();
|
|
115
|
+
return t === "mongodb" ? "mongodb" : "upstash-redis";
|
|
116
|
+
}
|
|
117
|
+
function preferMongo() {
|
|
118
|
+
return getStoreType() === "mongodb" && Boolean(mongoUri?.trim());
|
|
119
|
+
}
|
|
120
|
+
function preferRedis() {
|
|
121
|
+
return getStoreType() !== "mongodb" && Boolean((redisUrl || "").trim() && (redisToken || "").trim());
|
|
122
|
+
}
|
|
123
|
+
async function upsertInitialQueueJob(options) {
|
|
124
|
+
const { queueJobId, queueId, firstWorkerId, firstWorkerJobId, metadata } = options;
|
|
125
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
126
|
+
if (preferMongo()) {
|
|
127
|
+
const coll = await getMongoQueueCollection();
|
|
128
|
+
const existing = await coll.findOne({ _id: queueJobId });
|
|
129
|
+
if (existing) {
|
|
130
|
+
const steps = existing.steps ?? [];
|
|
131
|
+
if (steps.length === 0) {
|
|
132
|
+
steps.push({
|
|
133
|
+
workerId: firstWorkerId,
|
|
134
|
+
workerJobId: firstWorkerJobId,
|
|
135
|
+
status: "queued"
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
await coll.updateOne(
|
|
139
|
+
{ _id: queueJobId },
|
|
140
|
+
{
|
|
141
|
+
$set: {
|
|
142
|
+
steps,
|
|
143
|
+
updatedAt: now
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
} else {
|
|
148
|
+
const doc = {
|
|
149
|
+
_id: queueJobId,
|
|
150
|
+
id: queueJobId,
|
|
151
|
+
queueId,
|
|
152
|
+
status: "running",
|
|
153
|
+
steps: [
|
|
154
|
+
{
|
|
155
|
+
workerId: firstWorkerId,
|
|
156
|
+
workerJobId: firstWorkerJobId,
|
|
157
|
+
status: "queued"
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
metadata: metadata ?? {},
|
|
161
|
+
createdAt: now,
|
|
162
|
+
updatedAt: now
|
|
163
|
+
};
|
|
164
|
+
await coll.updateOne(
|
|
165
|
+
{ _id: queueJobId },
|
|
166
|
+
{ $set: doc },
|
|
167
|
+
{ upsert: true }
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (preferRedis()) {
|
|
173
|
+
const existing = await loadQueueJobRedis(queueJobId);
|
|
174
|
+
if (existing) {
|
|
175
|
+
if (!existing.steps || existing.steps.length === 0) {
|
|
176
|
+
existing.steps = [
|
|
177
|
+
{
|
|
178
|
+
workerId: firstWorkerId,
|
|
179
|
+
workerJobId: firstWorkerJobId,
|
|
180
|
+
status: "queued"
|
|
181
|
+
}
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
existing.updatedAt = now;
|
|
185
|
+
await saveQueueJobRedis(existing);
|
|
186
|
+
} else {
|
|
187
|
+
const record = {
|
|
188
|
+
id: queueJobId,
|
|
189
|
+
queueId,
|
|
190
|
+
status: "running",
|
|
191
|
+
steps: [
|
|
192
|
+
{
|
|
193
|
+
workerId: firstWorkerId,
|
|
194
|
+
workerJobId: firstWorkerJobId,
|
|
195
|
+
status: "queued"
|
|
196
|
+
}
|
|
197
|
+
],
|
|
198
|
+
metadata: metadata ?? {},
|
|
199
|
+
createdAt: now,
|
|
200
|
+
updatedAt: now
|
|
201
|
+
};
|
|
202
|
+
await saveQueueJobRedis(record);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async function updateQueueJobStepInStore(options) {
|
|
207
|
+
const { queueJobId, stepIndex, status, input, output, error } = options;
|
|
208
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
209
|
+
if (preferMongo()) {
|
|
210
|
+
const coll = await getMongoQueueCollection();
|
|
211
|
+
const existing = await coll.findOne({ _id: queueJobId });
|
|
212
|
+
if (!existing) return;
|
|
213
|
+
const step = existing.steps[stepIndex];
|
|
214
|
+
if (!step) return;
|
|
215
|
+
const mergedStep = {
|
|
216
|
+
...step,
|
|
217
|
+
status,
|
|
218
|
+
...input !== void 0 && { input },
|
|
219
|
+
...output !== void 0 && { output },
|
|
220
|
+
...error !== void 0 && { error },
|
|
221
|
+
startedAt: step.startedAt ?? (status === "running" ? now : step.startedAt),
|
|
222
|
+
completedAt: step.completedAt ?? (status === "completed" || status === "failed" ? now : step.completedAt)
|
|
223
|
+
};
|
|
224
|
+
const setDoc = {
|
|
225
|
+
steps: existing.steps,
|
|
226
|
+
updatedAt: now
|
|
227
|
+
};
|
|
228
|
+
setDoc.steps[stepIndex] = mergedStep;
|
|
229
|
+
if (status === "failed") {
|
|
230
|
+
setDoc.status = "failed";
|
|
231
|
+
if (!existing.completedAt) setDoc.completedAt = now;
|
|
232
|
+
} else if (status === "completed" && stepIndex === existing.steps.length - 1) {
|
|
233
|
+
setDoc.status = "completed";
|
|
234
|
+
if (!existing.completedAt) setDoc.completedAt = now;
|
|
235
|
+
}
|
|
236
|
+
await coll.updateOne(
|
|
237
|
+
{ _id: queueJobId },
|
|
238
|
+
{
|
|
239
|
+
$set: setDoc
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (preferRedis()) {
|
|
245
|
+
const existing = await loadQueueJobRedis(queueJobId);
|
|
246
|
+
if (!existing) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const steps = existing.steps || [];
|
|
250
|
+
const step = steps[stepIndex];
|
|
251
|
+
if (!step) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
step.status = status;
|
|
255
|
+
if (input !== void 0) step.input = input;
|
|
256
|
+
if (output !== void 0) step.output = output;
|
|
257
|
+
if (error !== void 0) step.error = error;
|
|
258
|
+
if (status === "running") {
|
|
259
|
+
step.startedAt = step.startedAt ?? now;
|
|
260
|
+
}
|
|
261
|
+
if (status === "completed" || status === "failed") {
|
|
262
|
+
step.completedAt = step.completedAt ?? now;
|
|
263
|
+
}
|
|
264
|
+
existing.steps = steps;
|
|
265
|
+
existing.updatedAt = now;
|
|
266
|
+
if (status === "failed") {
|
|
267
|
+
existing.status = "failed";
|
|
268
|
+
existing.completedAt = existing.completedAt ?? now;
|
|
269
|
+
} else if (status === "completed" && stepIndex === steps.length - 1) {
|
|
270
|
+
existing.status = "completed";
|
|
271
|
+
existing.completedAt = existing.completedAt ?? now;
|
|
272
|
+
}
|
|
273
|
+
await saveQueueJobRedis(existing);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async function appendQueueJobStepInStore(options) {
|
|
277
|
+
const { queueJobId, workerId, workerJobId } = options;
|
|
278
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
279
|
+
if (preferMongo()) {
|
|
280
|
+
const coll = await getMongoQueueCollection();
|
|
281
|
+
await coll.updateOne(
|
|
282
|
+
{ _id: queueJobId },
|
|
283
|
+
{
|
|
284
|
+
$push: {
|
|
285
|
+
steps: {
|
|
286
|
+
workerId,
|
|
287
|
+
workerJobId,
|
|
288
|
+
status: "queued"
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
$set: { updatedAt: now }
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (preferRedis()) {
|
|
297
|
+
const existing = await loadQueueJobRedis(queueJobId);
|
|
298
|
+
if (!existing) return;
|
|
299
|
+
const steps = existing.steps || [];
|
|
300
|
+
steps.push({
|
|
301
|
+
workerId,
|
|
302
|
+
workerJobId,
|
|
303
|
+
status: "queued"
|
|
304
|
+
});
|
|
305
|
+
existing.steps = steps;
|
|
306
|
+
existing.updatedAt = now;
|
|
307
|
+
await saveQueueJobRedis(existing);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async function getQueueJob(queueJobId) {
|
|
311
|
+
if (preferMongo()) {
|
|
312
|
+
const coll = await getMongoQueueCollection();
|
|
313
|
+
const doc = await coll.findOne({ _id: queueJobId });
|
|
314
|
+
if (!doc) return null;
|
|
315
|
+
return {
|
|
316
|
+
id: doc.id ?? queueJobId,
|
|
317
|
+
queueId: doc.queueId,
|
|
318
|
+
status: doc.status,
|
|
319
|
+
steps: (doc.steps ?? []).map((s) => ({
|
|
320
|
+
workerId: s.workerId,
|
|
321
|
+
workerJobId: s.workerJobId,
|
|
322
|
+
status: s.status,
|
|
323
|
+
output: s.output
|
|
324
|
+
}))
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
if (preferRedis()) {
|
|
328
|
+
const record = await loadQueueJobRedis(queueJobId);
|
|
329
|
+
if (!record) return null;
|
|
330
|
+
return {
|
|
331
|
+
id: record.id,
|
|
332
|
+
queueId: record.queueId,
|
|
333
|
+
status: record.status,
|
|
334
|
+
steps: (record.steps ?? []).map((s) => ({
|
|
335
|
+
workerId: s.workerId,
|
|
336
|
+
workerJobId: s.workerJobId,
|
|
337
|
+
status: s.status,
|
|
338
|
+
output: s.output
|
|
339
|
+
}))
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export {
|
|
346
|
+
upsertInitialQueueJob,
|
|
347
|
+
updateQueueJobStepInStore,
|
|
348
|
+
appendQueueJobStepInStore,
|
|
349
|
+
getQueueJob
|
|
350
|
+
};
|
|
351
|
+
//# sourceMappingURL=chunk-AOXGONGI.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/queueJobStore.ts"],"sourcesContent":["/**\n * Queue job store for worker queues (MongoDB or Upstash Redis).\n *\n * Mirrors the worker_jobs pattern but optimized for queues:\n * - MongoDB: collection `queue_jobs` (configurable via MONGODB_QUEUE_JOBS_COLLECTION)\n * - Upstash Redis: JSON blob per queue job with compact step entries\n *\n * This module is runtime-only (used by Lambda workers). Next.js APIs can read\n * the same collections/keys to show queue progress.\n */\n\nimport type { Redis } from '@upstash/redis';\nimport { Redis as UpstashRedis } from '@upstash/redis';\nimport { MongoClient, type Collection } from 'mongodb';\n\ntype QueueJobStep = {\n workerId: string;\n workerJobId: string;\n status: 'queued' | 'running' | 'completed' | 'failed';\n input?: unknown;\n output?: unknown;\n error?: { message: string };\n startedAt?: string;\n completedAt?: string;\n};\n\ntype QueueJobDoc = {\n _id: string; // queueJobId\n id: string;\n queueId: string;\n status: 'running' | 'completed' | 'failed' | 'partial';\n steps: QueueJobStep[];\n metadata?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n completedAt?: string;\n};\n\n\n// === Mongo backend (shares connection pattern with mongoJobStore) ===\n\nconst mongoUri = process.env.DATABASE_MONGODB_URI || process.env.MONGODB_URI;\nconst mongoDbName =\n process.env.DATABASE_MONGODB_DB ||\n process.env.MONGODB_DB ||\n 'mediamake';\nconst mongoQueueCollectionName =\n process.env.MONGODB_QUEUE_JOBS_COLLECTION || 'queue_jobs';\n\nlet mongoClientPromise: Promise<MongoClient> | null = null;\n\nasync function getMongoClient(): Promise<MongoClient> {\n if (!mongoUri) {\n throw new Error(\n 'MongoDB URI required for queue job store. Set DATABASE_MONGODB_URI or MONGODB_URI.'\n );\n }\n if (!mongoClientPromise) {\n mongoClientPromise = new MongoClient(mongoUri, {\n maxPoolSize: 10,\n minPoolSize: 0,\n serverSelectionTimeoutMS: 10_000,\n }).connect();\n }\n return mongoClientPromise;\n}\n\nasync function getMongoQueueCollection(): Promise<Collection<QueueJobDoc>> {\n const client = await getMongoClient();\n return client.db(mongoDbName).collection<QueueJobDoc>(mongoQueueCollectionName);\n}\n\n// === Redis backend (Upstash) ===\n\nconst redisUrl =\n process.env.WORKER_UPSTASH_REDIS_REST_URL ||\n process.env.UPSTASH_REDIS_REST_URL ||\n process.env.UPSTASH_REDIS_URL;\nconst redisToken =\n process.env.WORKER_UPSTASH_REDIS_REST_TOKEN ||\n process.env.UPSTASH_REDIS_REST_TOKEN ||\n process.env.UPSTASH_REDIS_TOKEN;\nconst queueKeyPrefix =\n process.env.WORKER_UPSTASH_REDIS_QUEUE_PREFIX ||\n process.env.UPSTASH_REDIS_QUEUE_PREFIX ||\n 'worker:queue-jobs:';\n\nconst defaultTtlSeconds = 60 * 60 * 24 * 7; // 7 days\nconst queueJobTtlSeconds =\n typeof process.env.WORKER_QUEUE_JOBS_TTL_SECONDS === 'string'\n ? parseInt(process.env.WORKER_QUEUE_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds\n : typeof process.env.WORKER_JOBS_TTL_SECONDS === 'string'\n ? parseInt(process.env.WORKER_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds\n : defaultTtlSeconds;\n\nlet redisClient: Redis | null = null;\n\nfunction getRedis(): Redis {\n if (!redisUrl || !redisToken) {\n throw new Error(\n 'Upstash Redis configuration missing for queue job store. Set WORKER_UPSTASH_REDIS_REST_URL and WORKER_UPSTASH_REDIS_REST_TOKEN (or UPSTASH_REDIS_REST_URL/UPSTASH_REDIS_REST_TOKEN).'\n );\n }\n if (!redisClient) {\n redisClient = new UpstashRedis({\n url: redisUrl,\n token: redisToken,\n });\n }\n return redisClient;\n}\n\nfunction queueKey(id: string): string {\n return `${queueKeyPrefix}${id}`;\n}\n\ntype QueueJobRecord = Omit<QueueJobDoc, '_id'>;\n\n/** Hash values from Upstash hgetall may be auto-parsed (array/object) or raw strings. */\nfunction stepsFromHash(val: unknown): QueueJobStep[] {\n if (Array.isArray(val)) return val as QueueJobStep[];\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val) as QueueJobStep[];\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n return [];\n}\n\nfunction metadataFromHash(val: unknown): Record<string, unknown> {\n if (val && typeof val === 'object' && !Array.isArray(val)) return val as Record<string, unknown>;\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val) as Record<string, unknown>;\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n }\n return {};\n}\n\nasync function loadQueueJobRedis(queueJobId: string): Promise<QueueJobRecord | null> {\n const redis = getRedis();\n const key = queueKey(queueJobId);\n const data = await redis.hgetall(key);\n if (!data || typeof data !== 'object' || Object.keys(data).length === 0) return null;\n const d = data as Record<string, unknown>;\n const record: QueueJobRecord = {\n id: (d.id === undefined ? queueJobId : String(d.id)) as string,\n queueId: String(d.queueId ?? ''),\n status: (String(d.status ?? 'running') as QueueJobRecord['status']),\n steps: stepsFromHash(d.steps),\n metadata: metadataFromHash(d.metadata),\n createdAt: String(d.createdAt ?? new Date().toISOString()),\n updatedAt: String(d.updatedAt ?? new Date().toISOString()),\n completedAt: d.completedAt != null ? String(d.completedAt) : undefined,\n };\n return record;\n}\n\nasync function saveQueueJobRedis(record: QueueJobRecord): Promise<void> {\n const redis = getRedis();\n const key = queueKey(record.id);\n const now = new Date().toISOString();\n const toSet: Record<string, string> = {\n id: record.id,\n queueId: record.queueId,\n status: record.status,\n steps: JSON.stringify(record.steps || []),\n metadata: JSON.stringify(record.metadata || {}),\n createdAt: record.createdAt || now,\n updatedAt: record.updatedAt || now,\n };\n if (record.completedAt) {\n toSet.completedAt = record.completedAt;\n }\n await redis.hset(key, toSet);\n if (queueJobTtlSeconds > 0) {\n await redis.expire(key, queueJobTtlSeconds);\n }\n}\n\n// === Backend selection ===\n\nfunction getStoreType(): 'mongodb' | 'upstash-redis' {\n const t = (process.env.WORKER_DATABASE_TYPE || 'upstash-redis').toLowerCase();\n return t === 'mongodb' ? 'mongodb' : 'upstash-redis';\n}\n\nfunction preferMongo(): boolean {\n return getStoreType() === 'mongodb' && Boolean(mongoUri?.trim());\n}\n\nfunction preferRedis(): boolean {\n return getStoreType() !== 'mongodb' && Boolean((redisUrl || '').trim() && (redisToken || '').trim());\n}\n\n// === Public API used from handler.ts ===\n\nexport async function upsertInitialQueueJob(options: {\n queueJobId: string;\n queueId: string;\n firstWorkerId: string;\n firstWorkerJobId: string;\n metadata?: Record<string, any>;\n}): Promise<void> {\n const { queueJobId, queueId, firstWorkerId, firstWorkerJobId, metadata } = options;\n const now = new Date().toISOString();\n\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n const existing = await coll.findOne({ _id: queueJobId });\n if (existing) {\n const steps = existing.steps ?? [];\n if (steps.length === 0) {\n steps.push({\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n });\n }\n await coll.updateOne(\n { _id: queueJobId },\n {\n $set: {\n steps,\n updatedAt: now,\n },\n }\n );\n } else {\n const doc: QueueJobDoc = {\n _id: queueJobId,\n id: queueJobId,\n queueId,\n status: 'running',\n steps: [\n {\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n },\n ],\n metadata: metadata ?? {},\n createdAt: now,\n updatedAt: now,\n };\n await coll.updateOne(\n { _id: queueJobId },\n { $set: doc },\n { upsert: true }\n );\n }\n return;\n }\n\n if (preferRedis()) {\n const existing = await loadQueueJobRedis(queueJobId);\n if (existing) {\n // Ensure we have at least one step\n if (!existing.steps || existing.steps.length === 0) {\n existing.steps = [\n {\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n },\n ];\n }\n existing.updatedAt = now;\n await saveQueueJobRedis(existing);\n } else {\n const record: QueueJobRecord = {\n id: queueJobId,\n queueId,\n status: 'running',\n steps: [\n {\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n },\n ],\n metadata: metadata ?? {},\n createdAt: now,\n updatedAt: now,\n };\n await saveQueueJobRedis(record);\n }\n }\n}\n\nexport async function updateQueueJobStepInStore(options: {\n queueJobId: string;\n queueId?: string;\n stepIndex: number;\n workerId: string;\n workerJobId: string;\n status: 'running' | 'completed' | 'failed';\n input?: unknown;\n output?: unknown;\n error?: { message: string };\n}): Promise<void> {\n const { queueJobId, stepIndex, status, input, output, error } = options;\n const now = new Date().toISOString();\n\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n const existing = await coll.findOne({ _id: queueJobId });\n if (!existing) return;\n const step = existing.steps[stepIndex];\n if (!step) return;\n\n const mergedStep: QueueJobStep = {\n ...step,\n status,\n ...(input !== undefined && { input }),\n ...(output !== undefined && { output }),\n ...(error !== undefined && { error }),\n startedAt: step.startedAt ?? (status === 'running' ? now : step.startedAt),\n completedAt:\n step.completedAt ??\n (status === 'completed' || status === 'failed' ? now : step.completedAt),\n };\n\n const setDoc: Partial<QueueJobDoc> & { steps: QueueJobStep[] } = {\n steps: existing.steps,\n updatedAt: now,\n };\n setDoc.steps[stepIndex] = mergedStep;\n if (status === 'failed') {\n setDoc.status = 'failed';\n if (!existing.completedAt) setDoc.completedAt = now;\n } else if (status === 'completed' && stepIndex === existing.steps.length - 1) {\n setDoc.status = 'completed';\n if (!existing.completedAt) setDoc.completedAt = now;\n }\n\n await coll.updateOne(\n { _id: queueJobId },\n {\n $set: setDoc,\n }\n );\n return;\n }\n\n if (preferRedis()) {\n const existing = await loadQueueJobRedis(queueJobId);\n if (!existing) {\n // No queue job; nothing to update\n return;\n }\n const steps = existing.steps || [];\n const step = steps[stepIndex];\n if (!step) {\n return;\n }\n step.status = status;\n if (input !== undefined) step.input = input;\n if (output !== undefined) step.output = output;\n if (error !== undefined) step.error = error;\n if (status === 'running') {\n step.startedAt = step.startedAt ?? now;\n }\n if (status === 'completed' || status === 'failed') {\n step.completedAt = step.completedAt ?? now;\n }\n\n existing.steps = steps;\n existing.updatedAt = now;\n if (status === 'failed') {\n existing.status = 'failed';\n existing.completedAt = existing.completedAt ?? now;\n } else if (status === 'completed' && stepIndex === steps.length - 1) {\n existing.status = 'completed';\n existing.completedAt = existing.completedAt ?? now;\n }\n await saveQueueJobRedis(existing);\n }\n}\n\nexport async function appendQueueJobStepInStore(options: {\n queueJobId: string;\n queueId?: string;\n workerId: string;\n workerJobId: string;\n}): Promise<void> {\n const { queueJobId, workerId, workerJobId } = options;\n const now = new Date().toISOString();\n\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n await coll.updateOne(\n { _id: queueJobId },\n {\n $push: {\n steps: {\n workerId,\n workerJobId,\n status: 'queued',\n } as QueueJobStep,\n },\n $set: { updatedAt: now },\n }\n );\n return;\n }\n\n if (preferRedis()) {\n const existing = await loadQueueJobRedis(queueJobId);\n if (!existing) return;\n const steps = existing.steps || [];\n steps.push({\n workerId,\n workerJobId,\n status: 'queued',\n });\n existing.steps = steps;\n existing.updatedAt = now;\n await saveQueueJobRedis(existing);\n }\n}\n\n/**\n * Load a queue job by ID (for mapping context: previous step outputs).\n * Used by wrapHandlerForQueue when invoking mapInputFromPrev with previousOutputs.\n */\nexport async function getQueueJob(queueJobId: string): Promise<{\n id: string;\n queueId: string;\n status: string;\n steps: Array<{ workerId: string; workerJobId: string; status: string; output?: unknown }>;\n} | null> {\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n const doc = await coll.findOne({ _id: queueJobId });\n if (!doc) return null;\n return {\n id: doc.id ?? queueJobId,\n queueId: doc.queueId,\n status: doc.status,\n steps: (doc.steps ?? []).map((s: QueueJobStep) => ({\n workerId: s.workerId,\n workerJobId: s.workerJobId,\n status: s.status,\n output: s.output,\n })),\n };\n }\n if (preferRedis()) {\n const record = await loadQueueJobRedis(queueJobId);\n if (!record) return null;\n return {\n id: record.id,\n queueId: record.queueId,\n status: record.status,\n steps: (record.steps ?? []).map((s) => ({\n workerId: s.workerId,\n workerJobId: s.workerJobId,\n status: s.status,\n output: s.output,\n })),\n };\n }\n return null;\n}\n\n"],"mappings":"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","names":[]}
|
|
@@ -15,9 +15,11 @@ interface WorkerQueueStep {
|
|
|
15
15
|
*/
|
|
16
16
|
delaySeconds?: number;
|
|
17
17
|
/**
|
|
18
|
-
* Optional name of a mapping function exported from the .queue.ts file
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Optional name of a mapping function exported from the .queue.ts file.
|
|
19
|
+
* The function is called with (initialInput, previousOutputs):
|
|
20
|
+
* - initialInput: original input passed to dispatchQueue (always first, for best DX).
|
|
21
|
+
* - previousOutputs: array of { stepIndex, workerId, output } for steps 0..current-1.
|
|
22
|
+
* Use any prior step's output; the immediate previous step is previousOutputs[previousOutputs.length - 1]?.output.
|
|
21
23
|
*/
|
|
22
24
|
mapInputFromPrev?: string;
|
|
23
25
|
}
|
|
@@ -67,7 +69,12 @@ declare function defineWorkerQueue<T extends WorkerQueueConfig>(config: T): T;
|
|
|
67
69
|
|
|
68
70
|
interface WorkerQueueRegistry {
|
|
69
71
|
getQueueById(queueId: string): WorkerQueueConfig | undefined;
|
|
70
|
-
|
|
72
|
+
/** (initialInput, previousOutputs) for best DX: derive next input from original request and all prior step outputs. */
|
|
73
|
+
invokeMapInput?: (queueId: string, stepIndex: number, initialInput: unknown, previousOutputs: Array<{
|
|
74
|
+
stepIndex: number;
|
|
75
|
+
workerId: string;
|
|
76
|
+
output: unknown;
|
|
77
|
+
}>) => Promise<unknown> | unknown;
|
|
71
78
|
}
|
|
72
79
|
interface DispatchOptions {
|
|
73
80
|
/**
|
|
@@ -120,16 +127,18 @@ interface SerializedContext {
|
|
|
120
127
|
/**
|
|
121
128
|
* Derives the full /workers/trigger URL from env.
|
|
122
129
|
* Exported for use by local dispatchWorker (worker-to-worker in dev).
|
|
130
|
+
* Server-side only; clients should use useWorkflowJob with your app's /api/workflows routes.
|
|
123
131
|
*
|
|
124
|
-
*
|
|
132
|
+
* Env vars:
|
|
125
133
|
* - WORKER_BASE_URL: base URL of the workers service (e.g. https://.../prod)
|
|
126
|
-
* -
|
|
127
|
-
*
|
|
128
|
-
* Legacy env vars (still supported for backwards compatibility):
|
|
129
|
-
* - WORKERS_TRIGGER_API_URL / NEXT_PUBLIC_WORKERS_TRIGGER_API_URL
|
|
130
|
-
* - WORKERS_CONFIG_API_URL / NEXT_PUBLIC_WORKERS_CONFIG_API_URL
|
|
134
|
+
* - WORKERS_TRIGGER_API_URL / WORKERS_CONFIG_API_URL: legacy, still supported
|
|
131
135
|
*/
|
|
132
136
|
declare function getWorkersTriggerUrl(): string;
|
|
137
|
+
/**
|
|
138
|
+
* URL for the queue start endpoint (dispatch proxy). Use this so queue starts
|
|
139
|
+
* go through the queue handler Lambda for easier debugging (one log stream per queue).
|
|
140
|
+
*/
|
|
141
|
+
declare function getQueueStartUrl(queueId: string): string;
|
|
133
142
|
/**
|
|
134
143
|
* Dispatches a background worker job to SQS.
|
|
135
144
|
*
|
|
@@ -141,6 +150,17 @@ declare function getWorkersTriggerUrl(): string;
|
|
|
141
150
|
* @returns Promise resolving to dispatch result with messageId and jobId
|
|
142
151
|
*/
|
|
143
152
|
declare function dispatch<INPUT_SCHEMA extends ZodType<any>>(workerId: string, input: z.input<INPUT_SCHEMA>, inputSchema: INPUT_SCHEMA, options: DispatchOptions, ctx?: any): Promise<DispatchResult>;
|
|
153
|
+
/**
|
|
154
|
+
* Dispatch a worker by ID without importing the worker module.
|
|
155
|
+
* Sends to the workers trigger API (WORKER_BASE_URL). No input schema validation at call site.
|
|
156
|
+
*
|
|
157
|
+
* @param workerId - The worker ID (e.g. 'echo', 'data-processor')
|
|
158
|
+
* @param input - Input payload (object or undefined)
|
|
159
|
+
* @param options - Optional jobId, webhookUrl, metadata
|
|
160
|
+
* @param ctx - Optional context (serializable parts sent in the request)
|
|
161
|
+
* @returns Promise resolving to { messageId, status: 'queued', jobId }
|
|
162
|
+
*/
|
|
163
|
+
declare function dispatchWorker(workerId: string, input?: Record<string, unknown>, options?: DispatchOptions, ctx?: any): Promise<DispatchResult>;
|
|
144
164
|
/**
|
|
145
165
|
* Local development mode: runs the handler immediately in the same process.
|
|
146
166
|
* This bypasses SQS and Lambda for faster iteration during development.
|
|
@@ -155,13 +175,9 @@ declare function dispatchLocal<INPUT, OUTPUT>(handler: (params: {
|
|
|
155
175
|
ctx: any;
|
|
156
176
|
}) => Promise<OUTPUT>, input: INPUT, ctx?: any): Promise<OUTPUT>;
|
|
157
177
|
/**
|
|
158
|
-
* Dispatches a queue by ID
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* This API intentionally mirrors the ergonomics of dispatching a single
|
|
162
|
-
* worker, but under the hood it embeds queue context into the job input
|
|
163
|
-
* so queue-aware wrappers can chain subsequent steps.
|
|
178
|
+
* Dispatches a queue by ID. POSTs to the queue-start API; the queue-start handler creates the queue job.
|
|
179
|
+
* Pass the first worker's input directly (no registry required).
|
|
164
180
|
*/
|
|
165
|
-
declare function dispatchQueue<InitialInput = any>(queueId: string, initialInput
|
|
181
|
+
declare function dispatchQueue<InitialInput = any>(queueId: string, initialInput?: InitialInput, options?: DispatchOptions, _ctx?: any): Promise<DispatchQueueResult>;
|
|
166
182
|
|
|
167
|
-
export { type DispatchOptions as D, type SerializedContext as S, type WorkerQueueRegistry as W, type DispatchResult as a, type DispatchQueueResult as b,
|
|
183
|
+
export { type DispatchOptions as D, type SerializedContext as S, type WorkerQueueRegistry as W, type DispatchResult as a, type DispatchQueueResult as b, getQueueStartUrl as c, dispatch as d, dispatchWorker as e, dispatchLocal as f, getWorkersTriggerUrl as g, dispatchQueue as h, type WorkerQueueStep as i, type WorkerQueueConfig as j, type WorkerQueueContext as k, defineWorkerQueue as l };
|
|
@@ -15,9 +15,11 @@ interface WorkerQueueStep {
|
|
|
15
15
|
*/
|
|
16
16
|
delaySeconds?: number;
|
|
17
17
|
/**
|
|
18
|
-
* Optional name of a mapping function exported from the .queue.ts file
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Optional name of a mapping function exported from the .queue.ts file.
|
|
19
|
+
* The function is called with (initialInput, previousOutputs):
|
|
20
|
+
* - initialInput: original input passed to dispatchQueue (always first, for best DX).
|
|
21
|
+
* - previousOutputs: array of { stepIndex, workerId, output } for steps 0..current-1.
|
|
22
|
+
* Use any prior step's output; the immediate previous step is previousOutputs[previousOutputs.length - 1]?.output.
|
|
21
23
|
*/
|
|
22
24
|
mapInputFromPrev?: string;
|
|
23
25
|
}
|
|
@@ -67,7 +69,12 @@ declare function defineWorkerQueue<T extends WorkerQueueConfig>(config: T): T;
|
|
|
67
69
|
|
|
68
70
|
interface WorkerQueueRegistry {
|
|
69
71
|
getQueueById(queueId: string): WorkerQueueConfig | undefined;
|
|
70
|
-
|
|
72
|
+
/** (initialInput, previousOutputs) for best DX: derive next input from original request and all prior step outputs. */
|
|
73
|
+
invokeMapInput?: (queueId: string, stepIndex: number, initialInput: unknown, previousOutputs: Array<{
|
|
74
|
+
stepIndex: number;
|
|
75
|
+
workerId: string;
|
|
76
|
+
output: unknown;
|
|
77
|
+
}>) => Promise<unknown> | unknown;
|
|
71
78
|
}
|
|
72
79
|
interface DispatchOptions {
|
|
73
80
|
/**
|
|
@@ -120,16 +127,18 @@ interface SerializedContext {
|
|
|
120
127
|
/**
|
|
121
128
|
* Derives the full /workers/trigger URL from env.
|
|
122
129
|
* Exported for use by local dispatchWorker (worker-to-worker in dev).
|
|
130
|
+
* Server-side only; clients should use useWorkflowJob with your app's /api/workflows routes.
|
|
123
131
|
*
|
|
124
|
-
*
|
|
132
|
+
* Env vars:
|
|
125
133
|
* - WORKER_BASE_URL: base URL of the workers service (e.g. https://.../prod)
|
|
126
|
-
* -
|
|
127
|
-
*
|
|
128
|
-
* Legacy env vars (still supported for backwards compatibility):
|
|
129
|
-
* - WORKERS_TRIGGER_API_URL / NEXT_PUBLIC_WORKERS_TRIGGER_API_URL
|
|
130
|
-
* - WORKERS_CONFIG_API_URL / NEXT_PUBLIC_WORKERS_CONFIG_API_URL
|
|
134
|
+
* - WORKERS_TRIGGER_API_URL / WORKERS_CONFIG_API_URL: legacy, still supported
|
|
131
135
|
*/
|
|
132
136
|
declare function getWorkersTriggerUrl(): string;
|
|
137
|
+
/**
|
|
138
|
+
* URL for the queue start endpoint (dispatch proxy). Use this so queue starts
|
|
139
|
+
* go through the queue handler Lambda for easier debugging (one log stream per queue).
|
|
140
|
+
*/
|
|
141
|
+
declare function getQueueStartUrl(queueId: string): string;
|
|
133
142
|
/**
|
|
134
143
|
* Dispatches a background worker job to SQS.
|
|
135
144
|
*
|
|
@@ -141,6 +150,17 @@ declare function getWorkersTriggerUrl(): string;
|
|
|
141
150
|
* @returns Promise resolving to dispatch result with messageId and jobId
|
|
142
151
|
*/
|
|
143
152
|
declare function dispatch<INPUT_SCHEMA extends ZodType<any>>(workerId: string, input: z.input<INPUT_SCHEMA>, inputSchema: INPUT_SCHEMA, options: DispatchOptions, ctx?: any): Promise<DispatchResult>;
|
|
153
|
+
/**
|
|
154
|
+
* Dispatch a worker by ID without importing the worker module.
|
|
155
|
+
* Sends to the workers trigger API (WORKER_BASE_URL). No input schema validation at call site.
|
|
156
|
+
*
|
|
157
|
+
* @param workerId - The worker ID (e.g. 'echo', 'data-processor')
|
|
158
|
+
* @param input - Input payload (object or undefined)
|
|
159
|
+
* @param options - Optional jobId, webhookUrl, metadata
|
|
160
|
+
* @param ctx - Optional context (serializable parts sent in the request)
|
|
161
|
+
* @returns Promise resolving to { messageId, status: 'queued', jobId }
|
|
162
|
+
*/
|
|
163
|
+
declare function dispatchWorker(workerId: string, input?: Record<string, unknown>, options?: DispatchOptions, ctx?: any): Promise<DispatchResult>;
|
|
144
164
|
/**
|
|
145
165
|
* Local development mode: runs the handler immediately in the same process.
|
|
146
166
|
* This bypasses SQS and Lambda for faster iteration during development.
|
|
@@ -155,13 +175,9 @@ declare function dispatchLocal<INPUT, OUTPUT>(handler: (params: {
|
|
|
155
175
|
ctx: any;
|
|
156
176
|
}) => Promise<OUTPUT>, input: INPUT, ctx?: any): Promise<OUTPUT>;
|
|
157
177
|
/**
|
|
158
|
-
* Dispatches a queue by ID
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* This API intentionally mirrors the ergonomics of dispatching a single
|
|
162
|
-
* worker, but under the hood it embeds queue context into the job input
|
|
163
|
-
* so queue-aware wrappers can chain subsequent steps.
|
|
178
|
+
* Dispatches a queue by ID. POSTs to the queue-start API; the queue-start handler creates the queue job.
|
|
179
|
+
* Pass the first worker's input directly (no registry required).
|
|
164
180
|
*/
|
|
165
|
-
declare function dispatchQueue<InitialInput = any>(queueId: string, initialInput
|
|
181
|
+
declare function dispatchQueue<InitialInput = any>(queueId: string, initialInput?: InitialInput, options?: DispatchOptions, _ctx?: any): Promise<DispatchQueueResult>;
|
|
166
182
|
|
|
167
|
-
export { type DispatchOptions as D, type SerializedContext as S, type WorkerQueueRegistry as W, type DispatchResult as a, type DispatchQueueResult as b,
|
|
183
|
+
export { type DispatchOptions as D, type SerializedContext as S, type WorkerQueueRegistry as W, type DispatchResult as a, type DispatchQueueResult as b, getQueueStartUrl as c, dispatch as d, dispatchWorker as e, dispatchLocal as f, getWorkersTriggerUrl as g, dispatchQueue as h, type WorkerQueueStep as i, type WorkerQueueConfig as j, type WorkerQueueContext as k, defineWorkerQueue as l };
|
package/dist/client.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import 'zod';
|
|
2
|
-
export { D as DispatchOptions, b as DispatchQueueResult, a as DispatchResult, S as SerializedContext, W as WorkerQueueRegistry, d as dispatch,
|
|
2
|
+
export { D as DispatchOptions, b as DispatchQueueResult, a as DispatchResult, S as SerializedContext, W as WorkerQueueRegistry, d as dispatch, f as dispatchLocal, h as dispatchQueue, e as dispatchWorker, c as getQueueStartUrl, g as getWorkersTriggerUrl } from './client-BqSJQ9mZ.mjs';
|
package/dist/client.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import 'zod';
|
|
2
|
-
export { D as DispatchOptions, b as DispatchQueueResult, a as DispatchResult, S as SerializedContext, W as WorkerQueueRegistry, d as dispatch,
|
|
2
|
+
export { D as DispatchOptions, b as DispatchQueueResult, a as DispatchResult, S as SerializedContext, W as WorkerQueueRegistry, d as dispatch, f as dispatchLocal, h as dispatchQueue, e as dispatchWorker, c as getQueueStartUrl, g as getWorkersTriggerUrl } from './client-BqSJQ9mZ.js';
|