@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
package/dist/client.js
CHANGED
|
@@ -23,14 +23,16 @@ __export(client_exports, {
|
|
|
23
23
|
dispatch: () => dispatch,
|
|
24
24
|
dispatchLocal: () => dispatchLocal,
|
|
25
25
|
dispatchQueue: () => dispatchQueue,
|
|
26
|
+
dispatchWorker: () => dispatchWorker,
|
|
27
|
+
getQueueStartUrl: () => getQueueStartUrl,
|
|
26
28
|
getWorkersTriggerUrl: () => getWorkersTriggerUrl
|
|
27
29
|
});
|
|
28
30
|
module.exports = __toCommonJS(client_exports);
|
|
29
31
|
function getWorkersTriggerUrl() {
|
|
30
|
-
const raw = process.env.WORKER_BASE_URL || process.env.
|
|
32
|
+
const raw = process.env.WORKER_BASE_URL || process.env.WORKERS_TRIGGER_API_URL || process.env.WORKERS_CONFIG_API_URL;
|
|
31
33
|
if (!raw) {
|
|
32
34
|
throw new Error(
|
|
33
|
-
"WORKER_BASE_URL
|
|
35
|
+
"WORKER_BASE_URL is required for background workers. Set it server-side only."
|
|
34
36
|
);
|
|
35
37
|
}
|
|
36
38
|
const url = new URL(raw);
|
|
@@ -42,6 +44,23 @@ function getWorkersTriggerUrl() {
|
|
|
42
44
|
url.pathname = `${basePath}/workers/trigger`.replace(/\/+$/, "");
|
|
43
45
|
return url.toString();
|
|
44
46
|
}
|
|
47
|
+
function getQueueStartUrl(queueId) {
|
|
48
|
+
const raw = process.env.WORKER_BASE_URL || process.env.WORKERS_TRIGGER_API_URL || process.env.WORKERS_CONFIG_API_URL;
|
|
49
|
+
if (!raw) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
"WORKER_BASE_URL is required for background workers. Set it server-side only."
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
const url = new URL(raw);
|
|
55
|
+
url.search = "";
|
|
56
|
+
url.hash = "";
|
|
57
|
+
const path = url.pathname || "";
|
|
58
|
+
url.pathname = path.replace(/\/?workers\/(trigger|config)\/?$/, "");
|
|
59
|
+
const basePath = url.pathname.replace(/\/+$/, "");
|
|
60
|
+
const safeSegment = encodeURIComponent(queueId);
|
|
61
|
+
url.pathname = `${basePath}/queues/${safeSegment}/start`.replace(/\/+$/, "");
|
|
62
|
+
return url.toString();
|
|
63
|
+
}
|
|
45
64
|
function serializeContext(ctx) {
|
|
46
65
|
const serialized = {};
|
|
47
66
|
if (ctx.requestId) {
|
|
@@ -99,115 +118,75 @@ async function dispatch(workerId, input, inputSchema, options, ctx) {
|
|
|
99
118
|
jobId
|
|
100
119
|
};
|
|
101
120
|
}
|
|
102
|
-
async function
|
|
103
|
-
return handler({ input, ctx: ctx || {} });
|
|
104
|
-
}
|
|
105
|
-
async function dispatchQueue(queueId, initialInput, options = {}, ctx) {
|
|
106
|
-
const registry = options.registry;
|
|
107
|
-
if (!registry?.getQueueById) {
|
|
108
|
-
throw new Error(
|
|
109
|
-
"dispatchQueue requires options.registry with getQueueById. Use getQueueRegistry() from your workflows registry (e.g. app/api/workflows/registry/workers) and pass { registry: await getQueueRegistry() }."
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
const { getQueueById, invokeMapInput } = registry;
|
|
113
|
-
const queue = getQueueById(queueId);
|
|
114
|
-
if (!queue) {
|
|
115
|
-
throw new Error(`Worker queue "${queueId}" not found in registry`);
|
|
116
|
-
}
|
|
117
|
-
if (!queue.steps || queue.steps.length === 0) {
|
|
118
|
-
throw new Error(`Worker queue "${queueId}" has no steps defined`);
|
|
119
|
-
}
|
|
120
|
-
const stepIndex = 0;
|
|
121
|
-
const firstStep = queue.steps[stepIndex];
|
|
122
|
-
const firstWorkerId = firstStep.workerId;
|
|
123
|
-
if (!firstWorkerId) {
|
|
124
|
-
throw new Error(
|
|
125
|
-
`Worker queue "${queueId}" has an invalid first step (missing workerId)`
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
let firstInput = initialInput;
|
|
129
|
-
if (firstStep.mapInputFromPrev && typeof invokeMapInput === "function") {
|
|
130
|
-
firstInput = await invokeMapInput(
|
|
131
|
-
queueId,
|
|
132
|
-
stepIndex,
|
|
133
|
-
void 0,
|
|
134
|
-
initialInput
|
|
135
|
-
);
|
|
136
|
-
}
|
|
121
|
+
async function dispatchWorker(workerId, input, options = {}, ctx) {
|
|
137
122
|
const jobId = options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
138
|
-
const queueContext = {
|
|
139
|
-
id: queueId,
|
|
140
|
-
stepIndex,
|
|
141
|
-
initialInput,
|
|
142
|
-
queueJobId: jobId
|
|
143
|
-
};
|
|
144
|
-
if (options.onCreateQueueJob) {
|
|
145
|
-
try {
|
|
146
|
-
await options.onCreateQueueJob({
|
|
147
|
-
queueJobId: jobId,
|
|
148
|
-
queueId,
|
|
149
|
-
firstStep: { workerId: firstWorkerId, workerJobId: jobId },
|
|
150
|
-
metadata: options.metadata
|
|
151
|
-
});
|
|
152
|
-
} catch (err) {
|
|
153
|
-
console.warn("[dispatchQueue] onCreateQueueJob failed:", err?.message ?? err);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
const normalizedFirstInput = firstInput !== null && typeof firstInput === "object" ? firstInput : { value: firstInput };
|
|
157
|
-
const inputWithQueue = {
|
|
158
|
-
...normalizedFirstInput,
|
|
159
|
-
__workerQueue: queueContext
|
|
160
|
-
};
|
|
161
|
-
const metadataWithQueue = {
|
|
162
|
-
...options.metadata || {},
|
|
163
|
-
__workerQueue: queueContext
|
|
164
|
-
};
|
|
165
123
|
const triggerUrl = getWorkersTriggerUrl();
|
|
166
124
|
const serializedContext = ctx ? serializeContext(ctx) : {};
|
|
167
125
|
const messageBody = {
|
|
168
|
-
workerId
|
|
126
|
+
workerId,
|
|
169
127
|
jobId,
|
|
170
|
-
input:
|
|
128
|
+
input: input ?? {},
|
|
171
129
|
context: serializedContext,
|
|
172
130
|
webhookUrl: options.webhookUrl,
|
|
173
|
-
metadata:
|
|
131
|
+
metadata: options.metadata || {},
|
|
174
132
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
175
133
|
};
|
|
176
|
-
const headers = {
|
|
177
|
-
"Content-Type": "application/json"
|
|
178
|
-
};
|
|
134
|
+
const headers = { "Content-Type": "application/json" };
|
|
179
135
|
const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;
|
|
180
|
-
if (triggerKey)
|
|
181
|
-
headers["x-workers-trigger-key"] = triggerKey;
|
|
182
|
-
}
|
|
136
|
+
if (triggerKey) headers["x-workers-trigger-key"] = triggerKey;
|
|
183
137
|
const response = await fetch(triggerUrl, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers,
|
|
140
|
+
body: JSON.stringify({ workerId, body: messageBody })
|
|
141
|
+
});
|
|
142
|
+
if (!response.ok) {
|
|
143
|
+
const text = await response.text().catch(() => "");
|
|
144
|
+
throw new Error(
|
|
145
|
+
`Failed to trigger worker "${workerId}": ${response.status} ${response.statusText}${text ? ` - ${text}` : ""}`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
const data = await response.json().catch(() => ({}));
|
|
149
|
+
const messageId = data?.messageId ? String(data.messageId) : `trigger-${jobId}`;
|
|
150
|
+
return { messageId, status: "queued", jobId };
|
|
151
|
+
}
|
|
152
|
+
async function dispatchLocal(handler, input, ctx) {
|
|
153
|
+
return handler({ input, ctx: ctx || {} });
|
|
154
|
+
}
|
|
155
|
+
async function dispatchQueue(queueId, initialInput, options = {}, _ctx) {
|
|
156
|
+
const jobId = options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
157
|
+
const queueStartUrl = getQueueStartUrl(queueId);
|
|
158
|
+
const normalizedInput = initialInput !== null && typeof initialInput === "object" ? initialInput : { value: initialInput };
|
|
159
|
+
const headers = { "Content-Type": "application/json" };
|
|
160
|
+
const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;
|
|
161
|
+
if (triggerKey) headers["x-workers-trigger-key"] = triggerKey;
|
|
162
|
+
const response = await fetch(queueStartUrl, {
|
|
184
163
|
method: "POST",
|
|
185
164
|
headers,
|
|
186
165
|
body: JSON.stringify({
|
|
187
|
-
|
|
188
|
-
|
|
166
|
+
input: normalizedInput,
|
|
167
|
+
initialInput: normalizedInput,
|
|
168
|
+
metadata: options.metadata ?? {},
|
|
169
|
+
jobId,
|
|
170
|
+
...options.webhookUrl ? { webhookUrl: options.webhookUrl } : {}
|
|
189
171
|
})
|
|
190
172
|
});
|
|
191
173
|
if (!response.ok) {
|
|
192
174
|
const text = await response.text().catch(() => "");
|
|
193
175
|
throw new Error(
|
|
194
|
-
`Failed to
|
|
176
|
+
`Failed to start queue "${queueId}": ${response.status} ${response.statusText}${text ? ` - ${text}` : ""}`
|
|
195
177
|
);
|
|
196
178
|
}
|
|
197
179
|
const data = await response.json().catch(() => ({}));
|
|
198
|
-
const messageId = data?.messageId
|
|
199
|
-
return {
|
|
200
|
-
queueId,
|
|
201
|
-
messageId,
|
|
202
|
-
status: "queued",
|
|
203
|
-
jobId
|
|
204
|
-
};
|
|
180
|
+
const messageId = data?.messageId ?? data?.jobId ?? `queue-${jobId}`;
|
|
181
|
+
return { queueId, messageId, status: "queued", jobId };
|
|
205
182
|
}
|
|
206
183
|
// Annotate the CommonJS export names for ESM import in node:
|
|
207
184
|
0 && (module.exports = {
|
|
208
185
|
dispatch,
|
|
209
186
|
dispatchLocal,
|
|
210
187
|
dispatchQueue,
|
|
188
|
+
dispatchWorker,
|
|
189
|
+
getQueueStartUrl,
|
|
211
190
|
getWorkersTriggerUrl
|
|
212
191
|
});
|
|
213
192
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["/**\n * Client for dispatching background worker jobs.\n *\n * In production, dispatching happens via the workers HTTP API:\n * POST /workers/trigger -> enqueues message to SQS on the workers service side\n *\n * This avoids requiring AWS credentials in your Next.js app.\n */\n\nimport type { ZodType, z } from 'zod';\nimport type { WorkerQueueConfig, WorkerQueueContext } from './queue.js';\n\nexport interface WorkerQueueRegistry {\n getQueueById(queueId: string): WorkerQueueConfig | undefined;\n invokeMapInput?: (\n queueId: string,\n stepIndex: number,\n prevOutput: unknown,\n initialInput: unknown\n ) => Promise<unknown> | unknown;\n}\n\nexport interface DispatchOptions {\n /**\n * Optional webhook callback URL to notify when the job finishes.\n * Only called when provided. Default: no webhook (use job store / MongoDB only).\n */\n webhookUrl?: string;\n /**\n * Controls how dispatch executes.\n * - \"auto\" (default): local inline execution in development unless WORKERS_LOCAL_MODE=false.\n * - \"local\": force inline execution (no SQS).\n * - \"remote\": force SQS/Lambda dispatch even in development.\n */\n mode?: 'auto' | 'local' | 'remote';\n jobId?: string;\n metadata?: Record<string, any>;\n /**\n * In-memory queue registry for dispatchQueue. Required when using dispatchQueue.\n * Pass a registry that imports from your .queue.ts definitions (works on Vercel/serverless).\n */\n registry?: WorkerQueueRegistry;\n /**\n * Optional callback to create a queue job record before dispatching.\n * Called with queueJobId (= first worker's jobId), queueId, and firstStep.\n */\n onCreateQueueJob?: (params: {\n queueJobId: string;\n queueId: string;\n firstStep: { workerId: string; workerJobId: string };\n metadata?: Record<string, unknown>;\n }) => Promise<void>;\n}\n\nexport interface DispatchResult {\n messageId: string;\n status: 'queued';\n jobId: string;\n}\n\nexport interface DispatchQueueResult extends DispatchResult {\n queueId: string;\n}\n\nexport interface SerializedContext {\n requestId?: string;\n userId?: string;\n traceId?: string;\n [key: string]: any;\n}\n\n/**\n * Derives the full /workers/trigger URL from env.\n * Exported for use by local dispatchWorker (worker-to-worker in dev).\n *\n * Preferred env vars:\n * - WORKER_BASE_URL: base URL of the workers service (e.g. https://.../prod)\n * - NEXT_PUBLIC_WORKER_BASE_URL: same, but exposed to the browser\n *\n * Legacy env vars (still supported for backwards compatibility):\n * - WORKERS_TRIGGER_API_URL / NEXT_PUBLIC_WORKERS_TRIGGER_API_URL\n * - WORKERS_CONFIG_API_URL / NEXT_PUBLIC_WORKERS_CONFIG_API_URL\n */\nexport function getWorkersTriggerUrl(): string {\n const raw =\n process.env.WORKER_BASE_URL ||\n process.env.NEXT_PUBLIC_WORKER_BASE_URL ||\n process.env.WORKERS_TRIGGER_API_URL ||\n process.env.NEXT_PUBLIC_WORKERS_TRIGGER_API_URL ||\n process.env.WORKERS_CONFIG_API_URL ||\n process.env.NEXT_PUBLIC_WORKERS_CONFIG_API_URL;\n\n if (!raw) {\n throw new Error(\n 'WORKER_BASE_URL (preferred) or NEXT_PUBLIC_WORKER_BASE_URL is required for background workers'\n );\n }\n\n const url = new URL(raw);\n url.search = '';\n url.hash = '';\n\n const path = url.pathname || '';\n\n // If the user pointed at a specific endpoint, normalize back to the service root.\n url.pathname = path.replace(/\\/?workers\\/(trigger|config)\\/?$/, '');\n\n const basePath = url.pathname.replace(/\\/+$/, '');\n url.pathname = `${basePath}/workers/trigger`.replace(/\\/+$/, '');\n\n return url.toString();\n}\n\n/**\n * Serializes context data for transmission to Lambda.\n * Only serializes safe, JSON-compatible properties.\n */\nfunction serializeContext(ctx: any): SerializedContext {\n const serialized: SerializedContext = {};\n\n if (ctx.requestId) {\n serialized.requestId = ctx.requestId;\n }\n\n // Extract any additional serializable metadata\n if (ctx.metadata && typeof ctx.metadata === 'object') {\n Object.assign(serialized, ctx.metadata);\n }\n\n // Allow custom context serialization via a helper property\n if (ctx._serializeContext && typeof ctx._serializeContext === 'function') {\n const custom = ctx._serializeContext();\n Object.assign(serialized, custom);\n }\n\n return serialized;\n}\n\n\n/**\n * Dispatches a background worker job to SQS.\n *\n * @param workerId - The ID of the worker to dispatch\n * @param input - The input data for the worker (will be validated against inputSchema)\n * @param inputSchema - Zod schema for input validation\n * @param options - Dispatch options including webhook URL\n * @param ctx - Optional context object (only serializable parts will be sent)\n * @returns Promise resolving to dispatch result with messageId and jobId\n */\nexport async function dispatch<INPUT_SCHEMA extends ZodType<any>>(\n workerId: string,\n input: z.input<INPUT_SCHEMA>,\n inputSchema: INPUT_SCHEMA,\n options: DispatchOptions,\n ctx?: any\n): Promise<DispatchResult> {\n // Validate input against schema\n const validatedInput = inputSchema.parse(input);\n\n // Generate job ID if not provided\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n // Resolve /workers/trigger endpoint URL\n const triggerUrl = getWorkersTriggerUrl();\n\n // Serialize context (only safe, JSON-compatible parts)\n const serializedContext = ctx ? serializeContext(ctx) : {};\n\n // Job updates use MongoDB only; never pass jobStoreUrl/origin URL.\n const messageBody = {\n workerId,\n jobId,\n input: validatedInput,\n context: serializedContext,\n webhookUrl: options.webhookUrl,\n metadata: options.metadata || {},\n timestamp: new Date().toISOString(),\n };\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) {\n headers['x-workers-trigger-key'] = triggerKey;\n }\n\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n workerId,\n body: messageBody,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger worker \"${workerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${jobId}`;\n\n return {\n messageId,\n status: 'queued',\n jobId,\n };\n}\n\n/**\n * Local development mode: runs the handler immediately in the same process.\n * This bypasses SQS and Lambda for faster iteration during development.\n *\n * @param handler - The worker handler function\n * @param input - The input data\n * @param ctx - The context object\n * @returns The handler result\n */\nexport async function dispatchLocal<INPUT, OUTPUT>(\n handler: (params: { input: INPUT; ctx: any }) => Promise<OUTPUT>,\n input: INPUT,\n ctx?: any\n): Promise<OUTPUT> {\n return handler({ input, ctx: ctx || {} });\n}\n\n/**\n * Dispatches a queue by ID, using a generated registry of .queue.ts\n * definitions to determine the first worker and initial input mapping.\n *\n * This API intentionally mirrors the ergonomics of dispatching a single\n * worker, but under the hood it embeds queue context into the job input\n * so queue-aware wrappers can chain subsequent steps.\n */\nexport async function dispatchQueue<InitialInput = any>(\n queueId: string,\n initialInput: InitialInput,\n options: DispatchOptions = {},\n ctx?: any\n): Promise<DispatchQueueResult> {\n const registry = options.registry;\n if (!registry?.getQueueById) {\n throw new Error(\n 'dispatchQueue requires options.registry with getQueueById. ' +\n 'Use getQueueRegistry() from your workflows registry (e.g. app/api/workflows/registry/workers) and pass { registry: await getQueueRegistry() }.'\n );\n }\n const { getQueueById, invokeMapInput } = registry;\n const queue = getQueueById(queueId);\n\n if (!queue) {\n throw new Error(`Worker queue \"${queueId}\" not found in registry`);\n }\n\n if (!queue.steps || queue.steps.length === 0) {\n throw new Error(`Worker queue \"${queueId}\" has no steps defined`);\n }\n\n const stepIndex = 0;\n const firstStep = queue.steps[stepIndex];\n const firstWorkerId = firstStep.workerId;\n\n if (!firstWorkerId) {\n throw new Error(\n `Worker queue \"${queueId}\" has an invalid first step (missing workerId)`\n );\n }\n\n // Compute the first step's input:\n // - If a mapping function is configured and the registry exposes invokeMapInput,\n // use it (prevOutput is undefined for the first step).\n // - Otherwise, default to the initial input.\n let firstInput: unknown = initialInput;\n if (firstStep.mapInputFromPrev && typeof invokeMapInput === 'function') {\n firstInput = await invokeMapInput(\n queueId,\n stepIndex,\n undefined,\n initialInput\n );\n }\n\n const jobId =\n options.jobId ||\n `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n const queueContext: WorkerQueueContext<InitialInput> = {\n id: queueId,\n stepIndex,\n initialInput,\n queueJobId: jobId,\n };\n\n // Create queue job record if callback provided (for progress tracking)\n if (options.onCreateQueueJob) {\n try {\n await options.onCreateQueueJob({\n queueJobId: jobId,\n queueId,\n firstStep: { workerId: firstWorkerId, workerJobId: jobId },\n metadata: options.metadata as Record<string, unknown> | undefined,\n });\n } catch (err: any) {\n console.warn('[dispatchQueue] onCreateQueueJob failed:', err?.message ?? err);\n }\n }\n\n // Embed queue context into the worker input under a reserved key.\n const normalizedFirstInput =\n firstInput !== null && typeof firstInput === 'object'\n ? (firstInput as Record<string, any>)\n : { value: firstInput };\n\n const inputWithQueue = {\n ...normalizedFirstInput,\n __workerQueue: queueContext,\n };\n\n const metadataWithQueue = {\n ...(options.metadata || {}),\n __workerQueue: queueContext,\n };\n\n const triggerUrl = getWorkersTriggerUrl();\n const serializedContext = ctx ? serializeContext(ctx) : {};\n\n const messageBody = {\n workerId: firstWorkerId,\n jobId,\n input: inputWithQueue,\n context: serializedContext,\n webhookUrl: options.webhookUrl,\n metadata: metadataWithQueue,\n timestamp: new Date().toISOString(),\n };\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) {\n headers['x-workers-trigger-key'] = triggerKey;\n }\n\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n workerId: firstWorkerId,\n body: messageBody,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger queue \"${queueId}\" (worker \"${firstWorkerId}\"): ` +\n `${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${jobId}`;\n\n return {\n queueId,\n messageId,\n status: 'queued',\n jobId,\n };\n}\n\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["/**\n * Client for dispatching background worker jobs.\n *\n * In production, dispatching happens via the workers HTTP API:\n * POST /workers/trigger -> enqueues message to SQS on the workers service side\n *\n * This avoids requiring AWS credentials in your Next.js app.\n */\n\nimport type { ZodType, z } from 'zod';\nimport type { WorkerQueueConfig } from './queue.js';\n\nexport interface WorkerQueueRegistry {\n getQueueById(queueId: string): WorkerQueueConfig | undefined;\n /** (initialInput, previousOutputs) for best DX: derive next input from original request and all prior step outputs. */\n invokeMapInput?: (\n queueId: string,\n stepIndex: number,\n initialInput: unknown,\n previousOutputs: Array<{ stepIndex: number; workerId: string; output: unknown }>\n ) => Promise<unknown> | unknown;\n}\n\nexport interface DispatchOptions {\n /**\n * Optional webhook callback URL to notify when the job finishes.\n * Only called when provided. Default: no webhook (use job store / MongoDB only).\n */\n webhookUrl?: string;\n /**\n * Controls how dispatch executes.\n * - \"auto\" (default): local inline execution in development unless WORKERS_LOCAL_MODE=false.\n * - \"local\": force inline execution (no SQS).\n * - \"remote\": force SQS/Lambda dispatch even in development.\n */\n mode?: 'auto' | 'local' | 'remote';\n jobId?: string;\n metadata?: Record<string, any>;\n /**\n * In-memory queue registry for dispatchQueue. Required when using dispatchQueue.\n * Pass a registry that imports from your .queue.ts definitions (works on Vercel/serverless).\n */\n registry?: WorkerQueueRegistry;\n /**\n * Optional callback to create a queue job record before dispatching.\n * Called with queueJobId (= first worker's jobId), queueId, and firstStep.\n */\n onCreateQueueJob?: (params: {\n queueJobId: string;\n queueId: string;\n firstStep: { workerId: string; workerJobId: string };\n metadata?: Record<string, unknown>;\n }) => Promise<void>;\n}\n\nexport interface DispatchResult {\n messageId: string;\n status: 'queued';\n jobId: string;\n}\n\nexport interface DispatchQueueResult extends DispatchResult {\n queueId: string;\n}\n\nexport interface SerializedContext {\n requestId?: string;\n userId?: string;\n traceId?: string;\n [key: string]: any;\n}\n\n/**\n * Derives the full /workers/trigger URL from env.\n * Exported for use by local dispatchWorker (worker-to-worker in dev).\n * Server-side only; clients should use useWorkflowJob with your app's /api/workflows routes.\n *\n * Env vars:\n * - WORKER_BASE_URL: base URL of the workers service (e.g. https://.../prod)\n * - WORKERS_TRIGGER_API_URL / WORKERS_CONFIG_API_URL: legacy, still supported\n */\nexport function getWorkersTriggerUrl(): string {\n const raw =\n process.env.WORKER_BASE_URL ||\n process.env.WORKERS_TRIGGER_API_URL ||\n process.env.WORKERS_CONFIG_API_URL;\n\n if (!raw) {\n throw new Error(\n 'WORKER_BASE_URL is required for background workers. Set it server-side only.'\n );\n }\n\n const url = new URL(raw);\n url.search = '';\n url.hash = '';\n\n const path = url.pathname || '';\n\n // If the user pointed at a specific endpoint, normalize back to the service root.\n url.pathname = path.replace(/\\/?workers\\/(trigger|config)\\/?$/, '');\n\n const basePath = url.pathname.replace(/\\/+$/, '');\n url.pathname = `${basePath}/workers/trigger`.replace(/\\/+$/, '');\n\n return url.toString();\n}\n\n/**\n * URL for the queue start endpoint (dispatch proxy). Use this so queue starts\n * go through the queue handler Lambda for easier debugging (one log stream per queue).\n */\nexport function getQueueStartUrl(queueId: string): string {\n const raw =\n process.env.WORKER_BASE_URL ||\n process.env.WORKERS_TRIGGER_API_URL ||\n process.env.WORKERS_CONFIG_API_URL;\n\n if (!raw) {\n throw new Error(\n 'WORKER_BASE_URL is required for background workers. Set it server-side only.'\n );\n }\n\n const url = new URL(raw);\n url.search = '';\n url.hash = '';\n\n const path = url.pathname || '';\n url.pathname = path.replace(/\\/?workers\\/(trigger|config)\\/?$/, '');\n const basePath = url.pathname.replace(/\\/+$/, '');\n const safeSegment = encodeURIComponent(queueId);\n url.pathname = `${basePath}/queues/${safeSegment}/start`.replace(/\\/+$/, '');\n\n return url.toString();\n}\n\n/**\n * Serializes context data for transmission to Lambda.\n * Only serializes safe, JSON-compatible properties.\n */\nfunction serializeContext(ctx: any): SerializedContext {\n const serialized: SerializedContext = {};\n\n if (ctx.requestId) {\n serialized.requestId = ctx.requestId;\n }\n\n // Extract any additional serializable metadata\n if (ctx.metadata && typeof ctx.metadata === 'object') {\n Object.assign(serialized, ctx.metadata);\n }\n\n // Allow custom context serialization via a helper property\n if (ctx._serializeContext && typeof ctx._serializeContext === 'function') {\n const custom = ctx._serializeContext();\n Object.assign(serialized, custom);\n }\n\n return serialized;\n}\n\n\n/**\n * Dispatches a background worker job to SQS.\n *\n * @param workerId - The ID of the worker to dispatch\n * @param input - The input data for the worker (will be validated against inputSchema)\n * @param inputSchema - Zod schema for input validation\n * @param options - Dispatch options including webhook URL\n * @param ctx - Optional context object (only serializable parts will be sent)\n * @returns Promise resolving to dispatch result with messageId and jobId\n */\nexport async function dispatch<INPUT_SCHEMA extends ZodType<any>>(\n workerId: string,\n input: z.input<INPUT_SCHEMA>,\n inputSchema: INPUT_SCHEMA,\n options: DispatchOptions,\n ctx?: any\n): Promise<DispatchResult> {\n // Validate input against schema\n const validatedInput = inputSchema.parse(input);\n\n // Generate job ID if not provided\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n // Resolve /workers/trigger endpoint URL\n const triggerUrl = getWorkersTriggerUrl();\n\n // Serialize context (only safe, JSON-compatible parts)\n const serializedContext = ctx ? serializeContext(ctx) : {};\n\n // Job updates use MongoDB only; never pass jobStoreUrl/origin URL.\n const messageBody = {\n workerId,\n jobId,\n input: validatedInput,\n context: serializedContext,\n webhookUrl: options.webhookUrl,\n metadata: options.metadata || {},\n timestamp: new Date().toISOString(),\n };\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) {\n headers['x-workers-trigger-key'] = triggerKey;\n }\n\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n workerId,\n body: messageBody,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger worker \"${workerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${jobId}`;\n\n return {\n messageId,\n status: 'queued',\n jobId,\n };\n}\n\n/**\n * Dispatch a worker by ID without importing the worker module.\n * Sends to the workers trigger API (WORKER_BASE_URL). No input schema validation at call site.\n *\n * @param workerId - The worker ID (e.g. 'echo', 'data-processor')\n * @param input - Input payload (object or undefined)\n * @param options - Optional jobId, webhookUrl, metadata\n * @param ctx - Optional context (serializable parts sent in the request)\n * @returns Promise resolving to { messageId, status: 'queued', jobId }\n */\nexport async function dispatchWorker(\n workerId: string,\n input?: Record<string, unknown>,\n options: DispatchOptions = {},\n ctx?: any\n): Promise<DispatchResult> {\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const triggerUrl = getWorkersTriggerUrl();\n const serializedContext = ctx ? serializeContext(ctx) : {};\n const messageBody = {\n workerId,\n jobId,\n input: input ?? {},\n context: serializedContext,\n webhookUrl: options.webhookUrl,\n metadata: options.metadata || {},\n timestamp: new Date().toISOString(),\n };\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) headers['x-workers-trigger-key'] = triggerKey;\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({ workerId, body: messageBody }),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger worker \"${workerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${jobId}`;\n return { messageId, status: 'queued', jobId };\n}\n\n/**\n * Local development mode: runs the handler immediately in the same process.\n * This bypasses SQS and Lambda for faster iteration during development.\n *\n * @param handler - The worker handler function\n * @param input - The input data\n * @param ctx - The context object\n * @returns The handler result\n */\nexport async function dispatchLocal<INPUT, OUTPUT>(\n handler: (params: { input: INPUT; ctx: any }) => Promise<OUTPUT>,\n input: INPUT,\n ctx?: any\n): Promise<OUTPUT> {\n return handler({ input, ctx: ctx || {} });\n}\n\n/**\n * Dispatches a queue by ID. POSTs to the queue-start API; the queue-start handler creates the queue job.\n * Pass the first worker's input directly (no registry required).\n */\nexport async function dispatchQueue<InitialInput = any>(\n queueId: string,\n initialInput?: InitialInput,\n options: DispatchOptions = {},\n _ctx?: any\n): Promise<DispatchQueueResult> {\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const queueStartUrl = getQueueStartUrl(queueId);\n const normalizedInput =\n initialInput !== null && typeof initialInput === 'object'\n ? (initialInput as Record<string, unknown>)\n : { value: initialInput };\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) headers['x-workers-trigger-key'] = triggerKey;\n const response = await fetch(queueStartUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n input: normalizedInput,\n initialInput: normalizedInput,\n metadata: options.metadata ?? {},\n jobId,\n ...(options.webhookUrl ? { webhookUrl: options.webhookUrl } : {}),\n }),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to start queue \"${queueId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ?? data?.jobId ?? `queue-${jobId}`;\n return { queueId, messageId, status: 'queued', jobId };\n}\n\n"],"mappings":"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","names":[]}
|
package/dist/client.mjs
CHANGED
|
@@ -2,13 +2,17 @@ import {
|
|
|
2
2
|
dispatch,
|
|
3
3
|
dispatchLocal,
|
|
4
4
|
dispatchQueue,
|
|
5
|
+
dispatchWorker,
|
|
6
|
+
getQueueStartUrl,
|
|
5
7
|
getWorkersTriggerUrl
|
|
6
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-72XGFZCE.mjs";
|
|
7
9
|
import "./chunk-BJTO5JO5.mjs";
|
|
8
10
|
export {
|
|
9
11
|
dispatch,
|
|
10
12
|
dispatchLocal,
|
|
11
13
|
dispatchQueue,
|
|
14
|
+
dispatchWorker,
|
|
15
|
+
getQueueStartUrl,
|
|
12
16
|
getWorkersTriggerUrl
|
|
13
17
|
};
|
|
14
18
|
//# sourceMappingURL=client.mjs.map
|
package/dist/handler.d.mts
CHANGED
|
@@ -81,6 +81,17 @@ interface DispatchWorkerOptions {
|
|
|
81
81
|
*/
|
|
82
82
|
delaySeconds?: number;
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Logger provided on ctx with prefixed levels: [INFO], [WARN], [ERROR], [DEBUG].
|
|
86
|
+
* Each method accepts a message and optional data (logged as JSON).
|
|
87
|
+
*/
|
|
88
|
+
interface WorkerLogger {
|
|
89
|
+
info(message: string, data?: Record<string, unknown>): void;
|
|
90
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
91
|
+
error(message: string, data?: Record<string, unknown>): void;
|
|
92
|
+
debug(message: string, data?: Record<string, unknown>): void;
|
|
93
|
+
}
|
|
94
|
+
declare function createWorkerLogger(jobId: string, workerId: string): WorkerLogger;
|
|
84
95
|
interface WorkerHandlerParams<INPUT, OUTPUT> {
|
|
85
96
|
input: INPUT;
|
|
86
97
|
ctx: {
|
|
@@ -92,6 +103,10 @@ interface WorkerHandlerParams<INPUT, OUTPUT> {
|
|
|
92
103
|
* Uses MongoDB directly when configured; never HTTP/origin URL.
|
|
93
104
|
*/
|
|
94
105
|
jobStore?: JobStore;
|
|
106
|
+
/**
|
|
107
|
+
* Logger with prefixed levels: ctx.logger.info(), .warn(), .error(), .debug().
|
|
108
|
+
*/
|
|
109
|
+
logger: WorkerLogger;
|
|
95
110
|
/**
|
|
96
111
|
* Dispatch another worker (fire-and-forget or await). Uses WORKER_QUEUE_URL_<SANITIZED_ID> env.
|
|
97
112
|
* Always provided by the runtime (Lambda and local).
|
|
@@ -111,10 +126,24 @@ interface QueueNextStep {
|
|
|
111
126
|
delaySeconds?: number;
|
|
112
127
|
mapInputFromPrev?: string;
|
|
113
128
|
}
|
|
129
|
+
/** One previous step's output (for mapInputFromPrev context). */
|
|
130
|
+
interface QueueStepOutput {
|
|
131
|
+
stepIndex: number;
|
|
132
|
+
workerId: string;
|
|
133
|
+
output: unknown;
|
|
134
|
+
}
|
|
114
135
|
/** Runtime helpers for queue-aware wrappers (provided by generated registry). */
|
|
115
136
|
interface QueueRuntime {
|
|
116
137
|
getNextStep(queueId: string, stepIndex: number): QueueNextStep | undefined;
|
|
117
|
-
|
|
138
|
+
/** Optional: when provided, mapping can use outputs from any previous step. */
|
|
139
|
+
getQueueJob?(queueJobId: string): Promise<{
|
|
140
|
+
steps: Array<{
|
|
141
|
+
workerId: string;
|
|
142
|
+
output?: unknown;
|
|
143
|
+
}>;
|
|
144
|
+
} | null>;
|
|
145
|
+
/** (initialInput, previousOutputs) – previousOutputs includes outputs for steps 0..stepIndex-1 and current step. */
|
|
146
|
+
invokeMapInput?(queueId: string, stepIndex: number, initialInput: unknown, previousOutputs: QueueStepOutput[]): Promise<unknown> | unknown;
|
|
118
147
|
}
|
|
119
148
|
/**
|
|
120
149
|
* Wraps a user handler so that when the job has __workerQueue context (from
|
|
@@ -127,6 +156,7 @@ declare function wrapHandlerForQueue<INPUT, OUTPUT>(handler: WorkerHandler<INPUT
|
|
|
127
156
|
id: string;
|
|
128
157
|
stepIndex: number;
|
|
129
158
|
initialInput: unknown;
|
|
159
|
+
queueJobId?: string;
|
|
130
160
|
};
|
|
131
161
|
}, OUTPUT>;
|
|
132
162
|
interface SQSMessageBody {
|
|
@@ -162,4 +192,4 @@ interface WebhookPayload {
|
|
|
162
192
|
*/
|
|
163
193
|
declare function createLambdaHandler<INPUT, OUTPUT>(handler: WorkerHandler<INPUT, OUTPUT>, outputSchema?: ZodType<OUTPUT>): (event: SQSEvent, context: Context) => Promise<void>;
|
|
164
194
|
|
|
165
|
-
export { type DispatchWorkerOptions, type JobRecord, type JobStore, type JobStoreUpdate, type QueueNextStep, type QueueRuntime, type SQSMessageBody, SQS_MAX_DELAY_SECONDS, type WebhookPayload, type WorkerHandler, type WorkerHandlerParams, createLambdaHandler, wrapHandlerForQueue };
|
|
195
|
+
export { type DispatchWorkerOptions, type JobRecord, type JobStore, type JobStoreUpdate, type QueueNextStep, type QueueRuntime, type QueueStepOutput, type SQSMessageBody, SQS_MAX_DELAY_SECONDS, type WebhookPayload, type WorkerHandler, type WorkerHandlerParams, type WorkerLogger, createLambdaHandler, createWorkerLogger, wrapHandlerForQueue };
|
package/dist/handler.d.ts
CHANGED
|
@@ -81,6 +81,17 @@ interface DispatchWorkerOptions {
|
|
|
81
81
|
*/
|
|
82
82
|
delaySeconds?: number;
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Logger provided on ctx with prefixed levels: [INFO], [WARN], [ERROR], [DEBUG].
|
|
86
|
+
* Each method accepts a message and optional data (logged as JSON).
|
|
87
|
+
*/
|
|
88
|
+
interface WorkerLogger {
|
|
89
|
+
info(message: string, data?: Record<string, unknown>): void;
|
|
90
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
91
|
+
error(message: string, data?: Record<string, unknown>): void;
|
|
92
|
+
debug(message: string, data?: Record<string, unknown>): void;
|
|
93
|
+
}
|
|
94
|
+
declare function createWorkerLogger(jobId: string, workerId: string): WorkerLogger;
|
|
84
95
|
interface WorkerHandlerParams<INPUT, OUTPUT> {
|
|
85
96
|
input: INPUT;
|
|
86
97
|
ctx: {
|
|
@@ -92,6 +103,10 @@ interface WorkerHandlerParams<INPUT, OUTPUT> {
|
|
|
92
103
|
* Uses MongoDB directly when configured; never HTTP/origin URL.
|
|
93
104
|
*/
|
|
94
105
|
jobStore?: JobStore;
|
|
106
|
+
/**
|
|
107
|
+
* Logger with prefixed levels: ctx.logger.info(), .warn(), .error(), .debug().
|
|
108
|
+
*/
|
|
109
|
+
logger: WorkerLogger;
|
|
95
110
|
/**
|
|
96
111
|
* Dispatch another worker (fire-and-forget or await). Uses WORKER_QUEUE_URL_<SANITIZED_ID> env.
|
|
97
112
|
* Always provided by the runtime (Lambda and local).
|
|
@@ -111,10 +126,24 @@ interface QueueNextStep {
|
|
|
111
126
|
delaySeconds?: number;
|
|
112
127
|
mapInputFromPrev?: string;
|
|
113
128
|
}
|
|
129
|
+
/** One previous step's output (for mapInputFromPrev context). */
|
|
130
|
+
interface QueueStepOutput {
|
|
131
|
+
stepIndex: number;
|
|
132
|
+
workerId: string;
|
|
133
|
+
output: unknown;
|
|
134
|
+
}
|
|
114
135
|
/** Runtime helpers for queue-aware wrappers (provided by generated registry). */
|
|
115
136
|
interface QueueRuntime {
|
|
116
137
|
getNextStep(queueId: string, stepIndex: number): QueueNextStep | undefined;
|
|
117
|
-
|
|
138
|
+
/** Optional: when provided, mapping can use outputs from any previous step. */
|
|
139
|
+
getQueueJob?(queueJobId: string): Promise<{
|
|
140
|
+
steps: Array<{
|
|
141
|
+
workerId: string;
|
|
142
|
+
output?: unknown;
|
|
143
|
+
}>;
|
|
144
|
+
} | null>;
|
|
145
|
+
/** (initialInput, previousOutputs) – previousOutputs includes outputs for steps 0..stepIndex-1 and current step. */
|
|
146
|
+
invokeMapInput?(queueId: string, stepIndex: number, initialInput: unknown, previousOutputs: QueueStepOutput[]): Promise<unknown> | unknown;
|
|
118
147
|
}
|
|
119
148
|
/**
|
|
120
149
|
* Wraps a user handler so that when the job has __workerQueue context (from
|
|
@@ -127,6 +156,7 @@ declare function wrapHandlerForQueue<INPUT, OUTPUT>(handler: WorkerHandler<INPUT
|
|
|
127
156
|
id: string;
|
|
128
157
|
stepIndex: number;
|
|
129
158
|
initialInput: unknown;
|
|
159
|
+
queueJobId?: string;
|
|
130
160
|
};
|
|
131
161
|
}, OUTPUT>;
|
|
132
162
|
interface SQSMessageBody {
|
|
@@ -162,4 +192,4 @@ interface WebhookPayload {
|
|
|
162
192
|
*/
|
|
163
193
|
declare function createLambdaHandler<INPUT, OUTPUT>(handler: WorkerHandler<INPUT, OUTPUT>, outputSchema?: ZodType<OUTPUT>): (event: SQSEvent, context: Context) => Promise<void>;
|
|
164
194
|
|
|
165
|
-
export { type DispatchWorkerOptions, type JobRecord, type JobStore, type JobStoreUpdate, type QueueNextStep, type QueueRuntime, type SQSMessageBody, SQS_MAX_DELAY_SECONDS, type WebhookPayload, type WorkerHandler, type WorkerHandlerParams, createLambdaHandler, wrapHandlerForQueue };
|
|
195
|
+
export { type DispatchWorkerOptions, type JobRecord, type JobStore, type JobStoreUpdate, type QueueNextStep, type QueueRuntime, type QueueStepOutput, type SQSMessageBody, SQS_MAX_DELAY_SECONDS, type WebhookPayload, type WorkerHandler, type WorkerHandlerParams, type WorkerLogger, createLambdaHandler, createWorkerLogger, wrapHandlerForQueue };
|
package/dist/handler.js
CHANGED
|
@@ -22,6 +22,7 @@ var handler_exports = {};
|
|
|
22
22
|
__export(handler_exports, {
|
|
23
23
|
SQS_MAX_DELAY_SECONDS: () => SQS_MAX_DELAY_SECONDS,
|
|
24
24
|
createLambdaHandler: () => createLambdaHandler,
|
|
25
|
+
createWorkerLogger: () => createWorkerLogger,
|
|
25
26
|
wrapHandlerForQueue: () => wrapHandlerForQueue
|
|
26
27
|
});
|
|
27
28
|
module.exports = __toCommonJS(handler_exports);
|
|
@@ -666,6 +667,25 @@ async function appendQueueJobStepInStore(options) {
|
|
|
666
667
|
|
|
667
668
|
// src/handler.ts
|
|
668
669
|
var SQS_MAX_DELAY_SECONDS = 900;
|
|
670
|
+
function createWorkerLogger(jobId, workerId) {
|
|
671
|
+
const prefix = (level) => `[${level}] [${workerId}] [${jobId}]`;
|
|
672
|
+
return {
|
|
673
|
+
info(msg, data) {
|
|
674
|
+
console.log(prefix("INFO"), msg, data !== void 0 ? JSON.stringify(data) : "");
|
|
675
|
+
},
|
|
676
|
+
warn(msg, data) {
|
|
677
|
+
console.warn(prefix("WARN"), msg, data !== void 0 ? JSON.stringify(data) : "");
|
|
678
|
+
},
|
|
679
|
+
error(msg, data) {
|
|
680
|
+
console.error(prefix("ERROR"), msg, data !== void 0 ? JSON.stringify(data) : "");
|
|
681
|
+
},
|
|
682
|
+
debug(msg, data) {
|
|
683
|
+
if (process.env.DEBUG || process.env.WORKER_DEBUG) {
|
|
684
|
+
console.debug(prefix("DEBUG"), msg, data !== void 0 ? JSON.stringify(data) : "");
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
}
|
|
669
689
|
var WORKER_QUEUE_KEY = "__workerQueue";
|
|
670
690
|
async function notifyQueueJobStep(queueJobId, action, params) {
|
|
671
691
|
try {
|
|
@@ -698,14 +718,13 @@ async function notifyQueueJobStep(queueJobId, action, params) {
|
|
|
698
718
|
output: params.output,
|
|
699
719
|
error: params.error
|
|
700
720
|
});
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
}
|
|
721
|
+
console.log("[Worker] Queue job step updated", {
|
|
722
|
+
queueId: params.queueId ?? queueJobId,
|
|
723
|
+
queueJobId,
|
|
724
|
+
stepIndex: params.stepIndex,
|
|
725
|
+
workerId: params.workerId,
|
|
726
|
+
status
|
|
727
|
+
});
|
|
709
728
|
} catch (err) {
|
|
710
729
|
console.warn("[Worker] Queue job update error:", {
|
|
711
730
|
queueJobId,
|
|
@@ -722,20 +741,52 @@ function wrapHandlerForQueue(handler, queueRuntime) {
|
|
|
722
741
|
return output;
|
|
723
742
|
}
|
|
724
743
|
const { id: queueId, stepIndex, initialInput, queueJobId } = queueContext;
|
|
744
|
+
const jobId = params.ctx?.jobId;
|
|
745
|
+
const workerId = params.ctx?.workerId ?? "";
|
|
725
746
|
const next = queueRuntime.getNextStep(queueId, stepIndex);
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
}
|
|
729
|
-
const childJobId = `job-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
730
|
-
if (queueJobId) {
|
|
747
|
+
const childJobId = next ? `job-${Date.now()}-${Math.random().toString(36).slice(2, 11)}` : void 0;
|
|
748
|
+
if (next && queueJobId) {
|
|
731
749
|
await notifyQueueJobStep(queueJobId, "append", {
|
|
732
750
|
workerJobId: childJobId,
|
|
733
751
|
workerId: next.workerId
|
|
734
752
|
});
|
|
735
753
|
}
|
|
754
|
+
if (queueJobId && typeof stepIndex === "number") {
|
|
755
|
+
await notifyQueueJobStep(queueJobId, "complete", {
|
|
756
|
+
queueId,
|
|
757
|
+
stepIndex,
|
|
758
|
+
workerJobId: jobId,
|
|
759
|
+
workerId,
|
|
760
|
+
output
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
if (!next) {
|
|
764
|
+
return output;
|
|
765
|
+
}
|
|
736
766
|
let nextInput = output;
|
|
737
767
|
if (next.mapInputFromPrev && typeof queueRuntime.invokeMapInput === "function") {
|
|
738
|
-
|
|
768
|
+
let previousOutputs = [];
|
|
769
|
+
if (queueJobId && typeof queueRuntime.getQueueJob === "function") {
|
|
770
|
+
try {
|
|
771
|
+
const job = await queueRuntime.getQueueJob(queueJobId);
|
|
772
|
+
if (job?.steps) {
|
|
773
|
+
const fromStore = job.steps.slice(0, stepIndex).map((s, i) => ({ stepIndex: i, workerId: s.workerId, output: s.output }));
|
|
774
|
+
previousOutputs = fromStore.concat([
|
|
775
|
+
{ stepIndex, workerId: params.ctx?.workerId ?? "", output }
|
|
776
|
+
]);
|
|
777
|
+
}
|
|
778
|
+
} catch (e) {
|
|
779
|
+
if (process.env.AI_WORKER_QUEUES_DEBUG === "1") {
|
|
780
|
+
console.warn("[Worker] getQueueJob failed, mapping without previousOutputs:", e?.message ?? e);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
nextInput = await queueRuntime.invokeMapInput(
|
|
785
|
+
queueId,
|
|
786
|
+
stepIndex + 1,
|
|
787
|
+
initialInput,
|
|
788
|
+
previousOutputs
|
|
789
|
+
);
|
|
739
790
|
}
|
|
740
791
|
const nextInputWithQueue = {
|
|
741
792
|
...nextInput !== null && typeof nextInput === "object" ? nextInput : { value: nextInput },
|
|
@@ -914,6 +965,7 @@ function createLambdaHandler(handler, outputSchema) {
|
|
|
914
965
|
const handlerContext = {
|
|
915
966
|
...baseContext,
|
|
916
967
|
...jobStore ? { jobStore } : {},
|
|
968
|
+
logger: createWorkerLogger(jobId, workerId),
|
|
917
969
|
dispatchWorker: createDispatchWorker(
|
|
918
970
|
jobId,
|
|
919
971
|
workerId,
|
|
@@ -924,9 +976,12 @@ function createLambdaHandler(handler, outputSchema) {
|
|
|
924
976
|
if (jobStore) {
|
|
925
977
|
try {
|
|
926
978
|
await jobStore.update({ status: "running" });
|
|
979
|
+
const queueCtxForLog = input?.__workerQueue ?? metadata?.__workerQueue;
|
|
927
980
|
console.log("[Worker] Job status updated to running:", {
|
|
928
981
|
jobId,
|
|
929
|
-
workerId
|
|
982
|
+
workerId,
|
|
983
|
+
...queueCtxForLog?.id && { queueId: queueCtxForLog.id },
|
|
984
|
+
...queueCtxForLog?.queueJobId && { queueJobId: queueCtxForLog.queueJobId }
|
|
930
985
|
});
|
|
931
986
|
} catch (error) {
|
|
932
987
|
console.warn("[Worker] Failed to update status to running:", {
|
|
@@ -956,6 +1011,7 @@ function createLambdaHandler(handler, outputSchema) {
|
|
|
956
1011
|
}
|
|
957
1012
|
}
|
|
958
1013
|
await notifyQueueJobStep(queueCtx.queueJobId, "start", {
|
|
1014
|
+
queueId: queueCtx.id,
|
|
959
1015
|
stepIndex: queueCtx.stepIndex,
|
|
960
1016
|
workerJobId: jobId,
|
|
961
1017
|
workerId,
|
|
@@ -1004,6 +1060,7 @@ function createLambdaHandler(handler, outputSchema) {
|
|
|
1004
1060
|
const queueCtxFail = input?.__workerQueue ?? metadata?.__workerQueue;
|
|
1005
1061
|
if (queueCtxFail?.queueJobId && typeof queueCtxFail.stepIndex === "number") {
|
|
1006
1062
|
await notifyQueueJobStep(queueCtxFail.queueJobId, "fail", {
|
|
1063
|
+
queueId: queueCtxFail.id,
|
|
1007
1064
|
stepIndex: queueCtxFail.stepIndex,
|
|
1008
1065
|
workerJobId: jobId,
|
|
1009
1066
|
workerId,
|
|
@@ -1033,15 +1090,6 @@ function createLambdaHandler(handler, outputSchema) {
|
|
|
1033
1090
|
});
|
|
1034
1091
|
}
|
|
1035
1092
|
}
|
|
1036
|
-
const queueCtxSuccess = input?.__workerQueue ?? metadata?.__workerQueue;
|
|
1037
|
-
if (queueCtxSuccess?.queueJobId && typeof queueCtxSuccess.stepIndex === "number") {
|
|
1038
|
-
await notifyQueueJobStep(queueCtxSuccess.queueJobId, "complete", {
|
|
1039
|
-
stepIndex: queueCtxSuccess.stepIndex,
|
|
1040
|
-
workerJobId: jobId,
|
|
1041
|
-
workerId,
|
|
1042
|
-
output
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
1093
|
console.log("[Worker] Job completed:", {
|
|
1046
1094
|
jobId,
|
|
1047
1095
|
workerId,
|
|
@@ -1074,6 +1122,7 @@ function createLambdaHandler(handler, outputSchema) {
|
|
|
1074
1122
|
0 && (module.exports = {
|
|
1075
1123
|
SQS_MAX_DELAY_SECONDS,
|
|
1076
1124
|
createLambdaHandler,
|
|
1125
|
+
createWorkerLogger,
|
|
1077
1126
|
wrapHandlerForQueue
|
|
1078
1127
|
});
|
|
1079
1128
|
//# sourceMappingURL=handler.js.map
|