@ezghcloud/workflows 0.0.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +418 -1
  3. package/dist/client.d.ts +209 -0
  4. package/dist/client.js +259 -0
  5. package/dist/env.d.ts +2 -0
  6. package/dist/env.js +32 -0
  7. package/dist/index.d.ts +15 -0
  8. package/dist/index.js +7 -0
  9. package/dist/protocol/bytes.d.ts +8 -0
  10. package/dist/protocol/bytes.js +49 -0
  11. package/dist/protocol/callback.d.ts +6 -0
  12. package/dist/protocol/callback.js +31 -0
  13. package/dist/protocol/codec.d.ts +6 -0
  14. package/dist/protocol/codec.js +38 -0
  15. package/dist/protocol/derived.d.ts +5 -0
  16. package/dist/protocol/derived.js +41 -0
  17. package/dist/protocol/index.d.ts +14 -0
  18. package/dist/protocol/index.js +21 -0
  19. package/dist/protocol/public.d.ts +2 -0
  20. package/dist/protocol/public.js +1 -0
  21. package/dist/protocol/signature.d.ts +17 -0
  22. package/dist/protocol/signature.js +101 -0
  23. package/dist/protocol/stepid.d.ts +4 -0
  24. package/dist/protocol/stepid.js +9 -0
  25. package/dist/protocol/tokens.d.ts +2 -0
  26. package/dist/protocol/tokens.js +38 -0
  27. package/dist/protocol/types.d.ts +185 -0
  28. package/dist/protocol/types.js +1 -0
  29. package/dist/protocol/validate.d.ts +15 -0
  30. package/dist/protocol/validate.js +279 -0
  31. package/dist/queues.d.ts +47 -0
  32. package/dist/queues.js +126 -0
  33. package/dist/runtime/context.d.ts +82 -0
  34. package/dist/runtime/context.js +1 -0
  35. package/dist/runtime/errors.d.ts +49 -0
  36. package/dist/runtime/errors.js +160 -0
  37. package/dist/runtime/execution.d.ts +17 -0
  38. package/dist/runtime/execution.js +608 -0
  39. package/dist/runtime/invocation.d.ts +5 -0
  40. package/dist/runtime/invocation.js +47 -0
  41. package/dist/runtime/live.d.ts +23 -0
  42. package/dist/runtime/live.js +103 -0
  43. package/dist/runtime/workflow.d.ts +26 -0
  44. package/dist/runtime/workflow.js +49 -0
  45. package/dist/serve.d.ts +12 -0
  46. package/dist/serve.js +149 -0
  47. package/dist/version.d.ts +2 -0
  48. package/dist/version.js +2 -0
  49. package/dist/worker.d.ts +43 -0
  50. package/dist/worker.js +364 -0
  51. package/package.json +48 -4
@@ -0,0 +1,23 @@
1
+ import type { Checkpoint, Journal } from "../protocol/index.ts";
2
+ export interface LiveIO {
3
+ checkpoint(cp: Checkpoint): Promise<void>;
4
+ journalPage(afterSeq: number): Promise<Journal>;
5
+ payload(id: string): Promise<unknown>;
6
+ }
7
+ export declare class InvocationSuperseded extends Error {
8
+ name: string;
9
+ }
10
+ export declare class CheckpointFailed extends Error {
11
+ readonly code: "checkpoint_failed" | "payload_unavailable";
12
+ name: string;
13
+ constructor(message: string, code?: "checkpoint_failed" | "payload_unavailable");
14
+ }
15
+ export interface LiveOptions {
16
+ deadline?: number;
17
+ reserveMs?: number;
18
+ now?: () => number;
19
+ attempts?: number;
20
+ retryDelayMs?: number;
21
+ }
22
+ export declare function httpLive(base: string, token: string, fetchImpl?: FetchLike, opts?: LiveOptions): LiveIO;
23
+ export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
@@ -0,0 +1,103 @@
1
+ // The engine has moved on: another invocation owns the run. Stop at once.
2
+ export class InvocationSuperseded extends Error {
3
+ name = "InvocationSuperseded";
4
+ }
5
+ // workflows-live refused or couldn't take a call after retries: the step must not run. code is
6
+ // what serve() tells dispatch: "payload_unavailable" when the live host's last answer was a 503
7
+ // payload_unavailable (its payload store is down: dispatch charges no step attempt), else
8
+ // "checkpoint_failed".
9
+ export class CheckpointFailed extends Error {
10
+ code;
11
+ name = "CheckpointFailed";
12
+ constructor(message, code = "checkpoint_failed") {
13
+ super(message);
14
+ this.code = code;
15
+ }
16
+ }
17
+ // errorCode reads the kit's {"error":{"code"}} from a small error body, or undefined.
18
+ async function errorCode(res) {
19
+ try {
20
+ const text = await res.text();
21
+ if (text.length > 64 * 1024)
22
+ return undefined;
23
+ const code = JSON.parse(text).error?.code;
24
+ return typeof code === "string" ? code : undefined;
25
+ }
26
+ catch {
27
+ return undefined;
28
+ }
29
+ }
30
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
31
+ const MAX_BACKOFF_MS = 5000;
32
+ function retryAfterMs(res) {
33
+ const v = res.headers.get("Retry-After");
34
+ if (!v)
35
+ return undefined;
36
+ const n = Number(v);
37
+ if (Number.isFinite(n) && n >= 0)
38
+ return n * 1000;
39
+ const at = Date.parse(v);
40
+ return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());
41
+ }
42
+ // httpLive talks to workflows-live (plan D2, D25) with Authorization: Bearer <invocation token>.
43
+ // 409 means superseded; 429, 5xx and network errors are retried; anything else non-2xx fails
44
+ // the invocation (CheckpointFailed).
45
+ export function httpLive(base, token, fetchImpl = (u, i) => fetch(u, i), opts = {}) {
46
+ const root = base.replace(/\/+$/, "");
47
+ const now = opts.now ?? Date.now;
48
+ const reserve = opts.reserveMs ?? 0;
49
+ const firstDelay = opts.retryDelayMs ?? 200;
50
+ async function call(path, init) {
51
+ const headers = { Authorization: `Bearer ${token}` };
52
+ if (init.body !== undefined)
53
+ headers["Content-Type"] = "application/json";
54
+ const what = path.split("?")[0];
55
+ let last = "";
56
+ let payloadDown = false; // the last answer was 503 payload_unavailable
57
+ const failed = (message) => new CheckpointFailed(message, payloadDown ? "payload_unavailable" : "checkpoint_failed");
58
+ for (let attempt = 0;; attempt++) {
59
+ const timeout = opts.deadline === undefined ? 30_000 : opts.deadline - now();
60
+ if (timeout <= 0)
61
+ throw failed(`No time left for ${what}: ${last || "the deadline passed"}`);
62
+ let res;
63
+ let wait;
64
+ try {
65
+ res = await fetchImpl(root + path, { ...init, headers, signal: AbortSignal.timeout(Math.max(1, Math.floor(timeout))), redirect: "manual" });
66
+ }
67
+ catch (e) {
68
+ last = e instanceof Error ? e.name : "network error";
69
+ payloadDown = false;
70
+ }
71
+ if (res) {
72
+ if (res.ok)
73
+ return res;
74
+ const code = res.status === 503 ? await errorCode(res) : (await res.body?.cancel().catch(() => { }), undefined);
75
+ if (res.status === 409)
76
+ throw new InvocationSuperseded("The engine superseded this invocation");
77
+ if (res.status !== 429 && res.status < 500)
78
+ throw new CheckpointFailed(`workflows-live answered ${res.status} for ${what}`);
79
+ last = code ? `HTTP ${res.status} ${code}` : `HTTP ${res.status}`;
80
+ payloadDown = code === "payload_unavailable";
81
+ wait = retryAfterMs(res);
82
+ }
83
+ // Retry-After never shortens the backoff (a 0 or a past date mustn't spin).
84
+ const delay = Math.max(wait ?? 0, Math.min(MAX_BACKOFF_MS, firstDelay * 2 ** attempt));
85
+ const more = opts.deadline === undefined ? attempt + 1 < (opts.attempts ?? 4) : opts.deadline - now() - delay > reserve;
86
+ if (!more)
87
+ throw failed(`workflows-live didn't take ${what}: ${last}`);
88
+ await sleep(delay);
89
+ }
90
+ }
91
+ return {
92
+ async checkpoint(cp) {
93
+ const res = await call("/v1/invocations/checkpoint", { method: "POST", body: JSON.stringify(cp) });
94
+ await res.body?.cancel().catch(() => { });
95
+ },
96
+ async journalPage(afterSeq) {
97
+ return (await (await call(`/v1/invocations/journal?afterSeq=${afterSeq}`, { method: "GET" })).json());
98
+ },
99
+ async payload(id) {
100
+ return (await call(`/v1/invocations/payloads/${encodeURIComponent(id)}`, { method: "GET" })).json();
101
+ },
102
+ };
103
+ }
@@ -0,0 +1,26 @@
1
+ import type { RetryPolicy } from "../protocol/index.ts";
2
+ import type { WorkflowContext } from "./context.ts";
3
+ export interface WorkflowOptions {
4
+ retry?: Partial<RetryPolicy>;
5
+ timeoutMs?: number;
6
+ }
7
+ declare const io: unique symbol;
8
+ export interface Workflow<I = unknown, O = unknown> {
9
+ readonly name: string;
10
+ readonly [io]?: (input: I) => O;
11
+ }
12
+ export interface WorkflowDefinition {
13
+ readonly name: string;
14
+ readonly fn: (ctx: WorkflowContext<any>) => Promise<unknown>;
15
+ readonly opts: {
16
+ readonly retry?: RetryPolicy;
17
+ readonly timeoutMs?: number;
18
+ };
19
+ }
20
+ export declare function definitionOf(wf: Workflow<any, any>): WorkflowDefinition;
21
+ export declare function workflow<I = unknown, O = unknown>(name: string, fn: (ctx: WorkflowContext<I>) => Promise<O>, opts?: WorkflowOptions): Workflow<I, O>;
22
+ export declare function mergeRetry(base: RetryPolicy, over: Partial<RetryPolicy> | undefined): RetryPolicy;
23
+ export declare function checkRetry(p: Partial<RetryPolicy>): void;
24
+ export declare const MAX_TIMEOUT_MS = 86400000;
25
+ export declare function checkTimeout(ms: number): void;
26
+ export {};
@@ -0,0 +1,49 @@
1
+ import { DEFAULT_RETRY, validWorkflowName } from "../protocol/index.js";
2
+ const definitions = new WeakMap();
3
+ // definitionOf returns what workflow() recorded, or throws for anything else.
4
+ export function definitionOf(wf) {
5
+ const d = typeof wf === "object" && wf !== null ? definitions.get(wf) : undefined;
6
+ if (!d)
7
+ throw new TypeError("Not a workflow: create workflows with workflow()");
8
+ return d;
9
+ }
10
+ export function workflow(name, fn, opts = {}) {
11
+ if (!validWorkflowName(name))
12
+ throw new TypeError(`Workflow names match ^[A-Za-z0-9_-]{1,64}$; got "${name}"`);
13
+ if (typeof fn !== "function")
14
+ throw new TypeError("A workflow needs a function");
15
+ if (opts.timeoutMs !== undefined)
16
+ checkTimeout(opts.timeoutMs);
17
+ const retry = opts.retry === undefined ? undefined : mergeRetry(DEFAULT_RETRY, opts.retry);
18
+ const wf = Object.freeze({ name });
19
+ definitions.set(wf, Object.freeze({
20
+ name, fn: fn,
21
+ opts: Object.freeze({ ...(retry ? { retry: Object.freeze(retry) } : {}), ...(opts.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}) }),
22
+ }));
23
+ return wf;
24
+ }
25
+ // mergeRetry overlays the defined fields of over on base and checks the result.
26
+ export function mergeRetry(base, over) {
27
+ const merged = { ...base };
28
+ for (const [k, v] of Object.entries(over ?? {}))
29
+ if (v !== undefined && k in merged)
30
+ merged[k] = v;
31
+ checkRetry(merged);
32
+ return merged;
33
+ }
34
+ // checkRetry enforces the protocol's bounds (protocol/schemas; the engine refuses others):
35
+ // maxAttempts 1–100, initialMs ≥ 0, maxMs 0–86,400,000, multiplier 1–10.
36
+ export function checkRetry(p) {
37
+ const ok = (v, min, max, int) => v === undefined || (typeof v === "number" && Number.isFinite(v) && v >= min && v <= max && (!int || Number.isInteger(v)));
38
+ if (!ok(p.maxAttempts, 1, 100, true) || !ok(p.initialMs, 0, Number.MAX_SAFE_INTEGER, true) || !ok(p.maxMs, 0, 86_400_000, true) || !ok(p.multiplier, 1, 10, false))
39
+ throw new TypeError("A retry policy has integer maxAttempts 1–100, integer initialMs ≥ 0, integer maxMs 0–86,400,000 and multiplier 1–10");
40
+ }
41
+ // The longest step timeout: 24 hours, a pull invocation's longest deadline (a pull app's deadline
42
+ // is its longest announced workflow timeout, at least 15 minutes). Pushed invocations are shorter
43
+ // (serve()'s maxInvocationSeconds, at most 900 s), and serve() refuses a workflow default longer
44
+ // than that; a step can never outlive its invocation.
45
+ export const MAX_TIMEOUT_MS = 86_400_000;
46
+ export function checkTimeout(ms) {
47
+ if (typeof ms !== "number" || !Number.isInteger(ms) || ms <= 0 || ms > MAX_TIMEOUT_MS)
48
+ throw new TypeError("timeoutMs is a whole number of milliseconds from 1 to 86,400,000 (24 hours)");
49
+ }
@@ -0,0 +1,12 @@
1
+ import { type FetchLike } from "./runtime/live.ts";
2
+ import { type Workflow } from "./runtime/workflow.ts";
3
+ export interface ServeOptions {
4
+ workflows: Workflow<any, any>[];
5
+ signingSecrets: (string | undefined)[];
6
+ maxInvocationSeconds?: number;
7
+ deployment?: string;
8
+ fetch?: FetchLike;
9
+ maxStepsPerInvocation?: number;
10
+ apiBaseUrl?: string;
11
+ }
12
+ export declare function serve(opts: ServeOptions): (req: Request) => Promise<Response>;
package/dist/serve.js ADDED
@@ -0,0 +1,149 @@
1
+ import { PROTOCOL_VERSIONS, SIGNATURE_HEADER, SignatureError, decodeSecret, parseSignature, verifyParsed } from "./protocol/index.js";
2
+ import { cleanDeployment, detectDeployment } from "./env.js";
3
+ import { execute } from "./runtime/execution.js";
4
+ import { InvalidInvocation, parseInvocation } from "./runtime/invocation.js";
5
+ import { CheckpointFailed, InvocationSuperseded, httpLive } from "./runtime/live.js";
6
+ import { definitionOf } from "./runtime/workflow.js";
7
+ import { SDK_NAME, SDK_VERSION } from "./version.js";
8
+ const MAX_BODY = 8 * 1024 * 1024;
9
+ // The result dispatch reads back (workflows-dispatch's cap).
10
+ const MAX_RESULT = 16 * 1024 * 1024;
11
+ const json = (status, body) => new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json" } });
12
+ class TooLarge extends Error {
13
+ }
14
+ async function readBody(req) {
15
+ const declared = Number(req.headers.get("Content-Length") ?? "0");
16
+ if (declared > MAX_BODY)
17
+ throw new TooLarge();
18
+ if (!req.body)
19
+ return new Uint8Array(0);
20
+ const reader = req.body.getReader();
21
+ const chunks = [];
22
+ let size = 0;
23
+ for (;;) {
24
+ const { done, value } = await reader.read();
25
+ if (done)
26
+ break;
27
+ size += value.length;
28
+ if (size > MAX_BODY) {
29
+ await reader.cancel().catch(() => { });
30
+ throw new TooLarge();
31
+ }
32
+ chunks.push(value);
33
+ }
34
+ const out = new Uint8Array(size);
35
+ let at = 0;
36
+ for (const c of chunks) {
37
+ out.set(c, at);
38
+ at += c.length;
39
+ }
40
+ return out;
41
+ }
42
+ // serve returns a Fetch-API handler for push invocations. Bun, Deno, Cloudflare Workers and
43
+ // Next.js route handlers take it as is; Node needs a small adapter (examples/node). Answers
44
+ // (plan D25): 200 SyncReply or InvocationResult, 401 bad signature, 400 bad invocation, 409
45
+ // superseded, 503 checkpoint failed, 500 SDK error, 405 non-POST, 413 over 8 MiB.
46
+ export function serve(opts) {
47
+ const byName = new Map();
48
+ for (const wf of opts.workflows) {
49
+ const def = definitionOf(wf);
50
+ if (byName.has(def.name))
51
+ throw new TypeError(`Two workflows are named "${def.name}"`);
52
+ byName.set(def.name, { wf, def });
53
+ }
54
+ if (!Array.isArray(opts.signingSecrets) || opts.signingSecrets.length === 0)
55
+ throw new TypeError("serve() needs at least one signing secret");
56
+ // A malformed secret fails now; an unset or empty one (an env var at build time) is skipped.
57
+ for (const s of opts.signingSecrets)
58
+ if (s !== undefined && s !== "")
59
+ decodeSecret(s);
60
+ let secrets;
61
+ const keys = () => (secrets ??= opts.signingSecrets.filter((s) => typeof s === "string" && s !== "").map(decodeSecret));
62
+ if (opts.maxStepsPerInvocation !== undefined && (!Number.isInteger(opts.maxStepsPerInvocation) || opts.maxStepsPerInvocation < 1))
63
+ throw new TypeError("maxStepsPerInvocation is a whole number ≥ 1");
64
+ const maxSeconds = opts.maxInvocationSeconds ?? 300;
65
+ if (!Number.isInteger(maxSeconds) || maxSeconds < 1 || maxSeconds > 900)
66
+ throw new TypeError("maxInvocationSeconds is a whole number from 1 to 900");
67
+ for (const { def } of byName.values())
68
+ if (def.opts.timeoutMs !== undefined && def.opts.timeoutMs > maxSeconds * 1000)
69
+ throw new TypeError(`Workflow "${def.name}" has timeoutMs ${def.opts.timeoutMs}, longer than an invocation (maxInvocationSeconds ${maxSeconds}): a step can't outlive its invocation; long steps need a pull worker`);
70
+ const deployment = opts.deployment !== undefined ? cleanDeployment(opts.deployment) : detectDeployment();
71
+ const sdk = { name: SDK_NAME, version: SDK_VERSION };
72
+ const fetchImpl = opts.fetch ?? ((u, i) => fetch(u, i));
73
+ return async (req) => {
74
+ const receivedAt = Date.now();
75
+ if (req.method !== "POST")
76
+ return json(405, { code: "method_not_allowed" });
77
+ const active = keys();
78
+ if (active.length === 0)
79
+ return json(500, { code: "sdk_error", message: "No signing secret is configured" });
80
+ // The header and its timestamp first: a stale or malformed signature costs no body read.
81
+ let sig;
82
+ try {
83
+ sig = parseSignature(req.headers.get(SIGNATURE_HEADER) ?? "", new Date(receivedAt));
84
+ }
85
+ catch (e) {
86
+ if (e instanceof SignatureError)
87
+ return json(401, { code: e.reason === "expired" ? "expired_signature" : "invalid_signature" });
88
+ return json(500, { code: "sdk_error" });
89
+ }
90
+ let body;
91
+ try {
92
+ body = await readBody(req);
93
+ }
94
+ catch (e) {
95
+ if (e instanceof TooLarge)
96
+ return json(413, { code: "payload_too_large" });
97
+ return json(400, { code: "invalid_invocation" });
98
+ }
99
+ try {
100
+ await verifyParsed(sig, active, body);
101
+ }
102
+ catch (e) {
103
+ if (e instanceof SignatureError)
104
+ return json(401, { code: "invalid_signature" });
105
+ return json(500, { code: "sdk_error" });
106
+ }
107
+ let inv;
108
+ try {
109
+ inv = parseInvocation(new TextDecoder().decode(body));
110
+ }
111
+ catch (e) {
112
+ if (e instanceof InvalidInvocation)
113
+ return json(400, { code: "invalid_invocation", message: e.message });
114
+ return json(500, { code: "sdk_error" });
115
+ }
116
+ // A push request carries the traceparent as a header (only while the setting is on).
117
+ inv = { ...inv, traceparent: req.headers.get("traceparent") ?? "" };
118
+ if (inv.kind === "sync") {
119
+ const reply = {
120
+ protocolVersions: [...PROTOCOL_VERSIONS], sdk, maxInvocationSeconds: maxSeconds,
121
+ workflows: [...byName.values()].map(({ def }) => ({ name: def.name, ...(def.opts.retry ? { retry: def.opts.retry } : {}), ...(def.opts.timeoutMs ? { timeoutMs: def.opts.timeoutMs } : {}) })),
122
+ ...(deployment ? { deployment } : {}),
123
+ };
124
+ return json(200, reply);
125
+ }
126
+ const result = (commands) => ({ commands, ...(deployment ? { deployment } : {}), sdk });
127
+ const wf = byName.get(inv.run.workflow)?.wf;
128
+ if (!wf)
129
+ return json(200, result([{ type: "workflowNotFound", workflow: inv.run.workflow }]));
130
+ // The deadline on this machine's clock: the engine's budget (deadline − t) from receipt, and
131
+ // never later than the deadline as this clock reads it.
132
+ const deadline = Math.min(receivedAt + (Date.parse(inv.deadline) - sig.t * 1000), Date.parse(inv.deadline));
133
+ const total = Math.max(0, deadline - receivedAt);
134
+ const reserveMs = Math.max(5000, total * 0.1);
135
+ try {
136
+ const io = httpLive(inv.endpoints.live, inv.token, fetchImpl, { deadline, reserveMs });
137
+ return json(200, result(await execute(inv, wf, io, { deadline, maxResultBytes: MAX_RESULT, ...(opts.apiBaseUrl ? { apiBaseUrl: opts.apiBaseUrl } : {}), ...(opts.maxStepsPerInvocation ? { maxStepsPerInvocation: opts.maxStepsPerInvocation } : {}) })));
138
+ }
139
+ catch (e) {
140
+ if (e instanceof InvocationSuperseded)
141
+ return json(409, { code: "invocation_superseded" });
142
+ // The code goes top level (as before) and in the kit's error shape, which dispatch reads:
143
+ // payload_unavailable costs the run no step attempt.
144
+ if (e instanceof CheckpointFailed)
145
+ return json(503, { code: e.code, error: { code: e.code, message: e.message } });
146
+ return json(500, { code: "sdk_error" });
147
+ }
148
+ };
149
+ }
@@ -0,0 +1,2 @@
1
+ export declare const SDK_NAME = "@ezghcloud/workflows";
2
+ export declare const SDK_VERSION = "1.0.0";
@@ -0,0 +1,2 @@
1
+ export const SDK_NAME = "@ezghcloud/workflows";
2
+ export const SDK_VERSION = "1.0.0";
@@ -0,0 +1,43 @@
1
+ import { type FetchLike } from "./runtime/live.ts";
2
+ import { type Workflow } from "./runtime/workflow.ts";
3
+ export interface WorkerOptions {
4
+ apiKey: string;
5
+ organizationId: string;
6
+ projectId: string;
7
+ app: string;
8
+ queue?: string;
9
+ workflows: Workflow<any, any>[];
10
+ maxTasks?: number;
11
+ concurrency?: number;
12
+ liveUrl?: string;
13
+ apiBaseUrl?: string;
14
+ workerId?: string;
15
+ dev?: boolean | {
16
+ user?: string;
17
+ };
18
+ heartbeatIntervalMs?: number;
19
+ backoffMaxMs?: number;
20
+ maxStepsPerInvocation?: number;
21
+ deployment?: string;
22
+ fetch?: FetchLike;
23
+ onError?: (error: unknown, context: string) => void;
24
+ }
25
+ export interface Worker {
26
+ run(): Promise<void>;
27
+ stop(opts?: {
28
+ graceMs?: number;
29
+ }): Promise<void>;
30
+ }
31
+ export declare class WorkerAuthError extends Error {
32
+ readonly status: number;
33
+ name: string;
34
+ constructor(status: number, message: string);
35
+ }
36
+ export declare class WorkerConfigError extends Error {
37
+ readonly status: number;
38
+ readonly code: string;
39
+ name: string;
40
+ constructor(status: number, code: string, message: string);
41
+ }
42
+ export declare function devQueue(user?: string): string;
43
+ export declare function worker(opts: WorkerOptions): Worker;