@voyantjs/workflows-orchestrator-cloudflare 0.6.7 → 0.6.9

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.
@@ -0,0 +1,98 @@
1
+ // AWS SigV4 presigned URL generator for Cloudflare R2.
2
+ //
3
+ // R2 speaks S3, so any valid SigV4-GetObject presigned URL works.
4
+ // We hand-roll the signer (Web Crypto + fetch only) so the tenant
5
+ // Worker doesn't need the AWS SDK — which is heavy enough to matter
6
+ // on Workers' bundle-size limits.
7
+ //
8
+ // Usage on the orchestrator side:
9
+ //
10
+ // const presign = createR2Presigner({
11
+ // accountId: env.R2_ACCOUNT_ID,
12
+ // accessKeyId: env.R2_ACCESS_KEY_ID,
13
+ // secretAccessKey: env.R2_SECRET_ACCESS_KEY,
14
+ // bucket: "voyant-bundles",
15
+ // });
16
+ // const url = await presign({ key: "prj_1/v1/container.mjs", expiresIn: 300 });
17
+ export function createR2Presigner(opts) {
18
+ const host = `${opts.accountId}.r2.cloudflarestorage.com`;
19
+ const region = "auto"; // R2's SigV4 region convention.
20
+ const service = "s3";
21
+ return async ({ key, expiresIn }) => {
22
+ if (expiresIn < 1 || expiresIn > 604_800) {
23
+ throw new Error(`R2 presign: expiresIn must be 1..604800, got ${expiresIn}`);
24
+ }
25
+ const normalizedKey = key.replace(/^\/+/, "");
26
+ const encodedKey = normalizedKey
27
+ .split("/")
28
+ .map((seg) => encodeURIComponent(seg))
29
+ .join("/");
30
+ const now = new Date();
31
+ const amzDate = toAmzDate(now);
32
+ const shortDate = amzDate.slice(0, 8);
33
+ const credentialScope = `${shortDate}/${region}/${service}/aws4_request`;
34
+ const credential = `${opts.accessKeyId}/${credentialScope}`;
35
+ const params = [
36
+ ["X-Amz-Algorithm", "AWS4-HMAC-SHA256"],
37
+ ["X-Amz-Credential", credential],
38
+ ["X-Amz-Date", amzDate],
39
+ ["X-Amz-Expires", String(expiresIn)],
40
+ ["X-Amz-SignedHeaders", "host"],
41
+ ];
42
+ params.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
43
+ const canonicalQuery = params
44
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
45
+ .join("&");
46
+ const canonicalRequest = [
47
+ "GET",
48
+ `/${opts.bucket}/${encodedKey}`,
49
+ canonicalQuery,
50
+ `host:${host}\n`,
51
+ "host",
52
+ "UNSIGNED-PAYLOAD",
53
+ ].join("\n");
54
+ const stringToSign = [
55
+ "AWS4-HMAC-SHA256",
56
+ amzDate,
57
+ credentialScope,
58
+ await sha256Hex(canonicalRequest),
59
+ ].join("\n");
60
+ const signingKey = await deriveSigningKey(opts.secretAccessKey, shortDate, region, service);
61
+ const signature = toHex(await hmac(signingKey, stringToSign));
62
+ return `https://${host}/${opts.bucket}/${encodedKey}?${canonicalQuery}&X-Amz-Signature=${signature}`;
63
+ };
64
+ }
65
+ // ---- Crypto helpers ----
66
+ function toAmzDate(d) {
67
+ const yyyy = d.getUTCFullYear();
68
+ const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
69
+ const dd = String(d.getUTCDate()).padStart(2, "0");
70
+ const hh = String(d.getUTCHours()).padStart(2, "0");
71
+ const mi = String(d.getUTCMinutes()).padStart(2, "0");
72
+ const ss = String(d.getUTCSeconds()).padStart(2, "0");
73
+ return `${yyyy}${mm}${dd}T${hh}${mi}${ss}Z`;
74
+ }
75
+ function toHex(bytes) {
76
+ const arr = new Uint8Array(bytes);
77
+ let out = "";
78
+ for (const b of arr)
79
+ out += b.toString(16).padStart(2, "0");
80
+ return out;
81
+ }
82
+ async function sha256Hex(input) {
83
+ const bytes = new TextEncoder().encode(input);
84
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
85
+ return toHex(digest);
86
+ }
87
+ async function hmac(key, msg) {
88
+ const keyBuf = key instanceof Uint8Array ? key.slice().buffer : key;
89
+ const cryptoKey = await crypto.subtle.importKey("raw", keyBuf, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
90
+ return crypto.subtle.sign("HMAC", cryptoKey, new TextEncoder().encode(msg));
91
+ }
92
+ async function deriveSigningKey(secret, shortDate, region, service) {
93
+ const kDate = await hmac(new TextEncoder().encode(`AWS4${secret}`), shortDate);
94
+ const kRegion = await hmac(kDate, region);
95
+ const kService = await hmac(kRegion, service);
96
+ const kSigning = await hmac(kService, "aws4_request");
97
+ return kSigning;
98
+ }
@@ -0,0 +1,76 @@
1
+ import type { WaitpointInjection } from "@voyantjs/workflows-orchestrator";
2
+ /**
3
+ * Subset of Cloudflare's `DurableObjectStorage` we actually use.
4
+ * Keyed JSON blobs; no transactional guarantees beyond what a single
5
+ * method call gives.
6
+ *
7
+ * Alarm methods are optional so in-memory fakes can opt out. On the
8
+ * real CF runtime they are always available. The adapter uses them
9
+ * to wake parked runs when their earliest DATETIME waitpoint comes
10
+ * due — see `handleDurableObjectAlarm`.
11
+ */
12
+ export interface DurableObjectStorageLike {
13
+ get<T>(key: string): Promise<T | undefined>;
14
+ put<T>(key: string, value: T): Promise<void>;
15
+ delete(key: string): Promise<boolean>;
16
+ list<T>(options?: {
17
+ prefix?: string;
18
+ limit?: number;
19
+ }): Promise<Map<string, T>>;
20
+ /** ms-since-epoch of the scheduled alarm, or null if none. */
21
+ getAlarm?(): Promise<number | null>;
22
+ /** Schedule the DO's alarm() method to fire at `wakeAt`. */
23
+ setAlarm?(wakeAt: number): Promise<void>;
24
+ /** Cancel any pending alarm. */
25
+ deleteAlarm?(): Promise<void>;
26
+ }
27
+ /**
28
+ * Subset of a Workers-for-Platforms dispatch namespace. `get(name)`
29
+ * returns a binding whose `fetch` delivers to the tenant Worker
30
+ * registered under that name.
31
+ */
32
+ export interface DispatchNamespaceLike {
33
+ get(name: string, args?: Record<string, unknown>): {
34
+ fetch(request: Request): Promise<Response>;
35
+ };
36
+ }
37
+ /** Args the Worker passes when routing to a run DO. */
38
+ export interface RunOperation {
39
+ op: "trigger" | "resume" | "cancel" | "get";
40
+ payload?: unknown;
41
+ }
42
+ /** Injection payload on resume ops. */
43
+ export interface ResumePayload {
44
+ injection: WaitpointInjection;
45
+ }
46
+ /** Trigger payload. */
47
+ export interface TriggerPayload {
48
+ workflowId: string;
49
+ workflowVersion: string;
50
+ input: unknown;
51
+ tenantMeta: {
52
+ tenantId: string;
53
+ projectId: string;
54
+ organizationId: string;
55
+ /** Dispatch-namespace name to forward step requests to. */
56
+ tenantScript: string;
57
+ };
58
+ environment?: "production" | "preview" | "development";
59
+ tags?: string[];
60
+ runId?: string;
61
+ }
62
+ /** Cancel payload. */
63
+ export interface CancelPayload {
64
+ reason?: string;
65
+ }
66
+ /**
67
+ * The Worker runtime env the adapter expects. Callers provide their
68
+ * own wrangler config; this interface documents what we read.
69
+ */
70
+ export interface AdapterEnv<DONamespace = unknown, DispatchNS = DispatchNamespaceLike> {
71
+ /** Durable Object namespace holding one DO per run. Typed loosely to avoid a CF types dep. */
72
+ WORKFLOW_RUN_DO: DONamespace;
73
+ /** Dispatch namespace containing tenant Workers. */
74
+ DISPATCHER: DispatchNS;
75
+ }
76
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AAE1E;;;;;;;;;GASG;AACH,MAAM,WAAW,wBAAwB;IACvC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAA;IAC3C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACrC,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAA;IAC/E,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,gCAAgC;IAChC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,GAAG,CACD,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B;QACD,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;KAC3C,CAAA;CACF;AAED,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAA;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,uCAAuC;AACvC,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,kBAAkB,CAAA;CAC9B;AAED,uBAAuB;AACvB,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,OAAO,CAAA;IACd,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,cAAc,EAAE,MAAM,CAAA;QACtB,2DAA2D;QAC3D,YAAY,EAAE,MAAM,CAAA;KACrB,CAAA;IACD,WAAW,CAAC,EAAE,YAAY,GAAG,SAAS,GAAG,aAAa,CAAA;IACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,sBAAsB;AACtB,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU,CAAC,WAAW,GAAG,OAAO,EAAE,UAAU,GAAG,qBAAqB;IACnF,8FAA8F;IAC9F,eAAe,EAAE,WAAW,CAAA;IAC5B,oDAAoD;IACpD,UAAU,EAAE,UAAU,CAAA;CACvB"}
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ // Structural types for the Cloudflare surface we use. We don't take
2
+ // a hard dependency on `@cloudflare/workers-types` — matching the
3
+ // shape is enough, and tests can pass plain objects.
4
+ export {};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Minimal shape of a DO namespace. `idFromName` returns an opaque id;
3
+ * `get(id)` returns a stub with `fetch` (matching the CF DO API).
4
+ * Typed loosely so tests can pass any matching object.
5
+ */
6
+ export interface DurableObjectNamespaceLike<Id = unknown> {
7
+ idFromName(name: string): Id;
8
+ get(id: Id): {
9
+ fetch(req: Request): Promise<Response>;
10
+ };
11
+ }
12
+ export interface WorkerFetchDeps<Id = unknown> {
13
+ runDO: DurableObjectNamespaceLike<Id>;
14
+ /**
15
+ * Called before any routing. Throws/rejects to reject the request.
16
+ * Typical implementation validates a tenant access token.
17
+ */
18
+ verifyRequest?: (req: Request) => void | Promise<void>;
19
+ /** Optional logger. */
20
+ logger?: (level: "info" | "warn" | "error", msg: string, data?: object) => void;
21
+ /** id generator for new triggers; defaults to `run_<random>`. */
22
+ idGenerator?: () => string;
23
+ /** Injectable clock for id generation. */
24
+ now?: () => number;
25
+ }
26
+ export declare function handleWorkerRequest<Id>(req: Request, deps: WorkerFetchDeps<Id>): Promise<Response>;
27
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAeA;;;;GAIG;AACH,MAAM,WAAW,0BAA0B,CAAC,EAAE,GAAG,OAAO;IACtD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,CAAA;IAC5B,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG;QAAE,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;KAAE,CAAA;CACxD;AAED,MAAM,WAAW,eAAe,CAAC,EAAE,GAAG,OAAO;IAC3C,KAAK,EAAE,0BAA0B,CAAC,EAAE,CAAC,CAAA;IACrC;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD,uBAAuB;IACvB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/E,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,MAAM,CAAA;IAC1B,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED,wBAAsB,mBAAmB,CAAC,EAAE,EAC1C,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,eAAe,CAAC,EAAE,CAAC,GACxB,OAAO,CAAC,QAAQ,CAAC,CA6EnB"}
package/dist/worker.js ADDED
@@ -0,0 +1,165 @@
1
+ // Public HTTP surface of the Cloudflare orchestrator. The outer
2
+ // Worker receives a request, resolves the run DO by id (or creates
3
+ // one for a new trigger), and forwards to the DO. This layer owns
4
+ // only routing + auth; the state machine lives in the DO.
5
+ //
6
+ // Routes (all JSON bodies):
7
+ // POST /api/runs → trigger a run
8
+ // GET /api/runs/:id → fetch a run
9
+ // POST /api/runs/:id/signals → inject a SIGNAL waitpoint
10
+ // POST /api/runs/:id/events → inject an EVENT waitpoint
11
+ // POST /api/runs/:id/tokens/:token → inject a MANUAL (token) waitpoint
12
+ // POST /api/runs/:id/cancel → cancel a run
13
+ export async function handleWorkerRequest(req, deps) {
14
+ const url = new URL(req.url);
15
+ if (req.method === "OPTIONS") {
16
+ return new Response(null, {
17
+ status: 204,
18
+ headers: corsHeaders("GET,POST,OPTIONS"),
19
+ });
20
+ }
21
+ try {
22
+ if (deps.verifyRequest)
23
+ await deps.verifyRequest(req);
24
+ }
25
+ catch (err) {
26
+ return json(401, {
27
+ error: "unauthorized",
28
+ message: err instanceof Error ? err.message : String(err),
29
+ });
30
+ }
31
+ // POST /api/runs — trigger a new run.
32
+ if (req.method === "POST" && url.pathname === "/api/runs") {
33
+ let payload;
34
+ try {
35
+ payload = (await req.json());
36
+ }
37
+ catch (err) {
38
+ return json(400, { error: "invalid_json", message: errMsg(err) });
39
+ }
40
+ const runId = typeof payload.runId === "string" ? payload.runId : defaultRunId(deps);
41
+ const forward = new Request(`https://do-internal/trigger`, {
42
+ method: "POST",
43
+ headers: { "content-type": "application/json" },
44
+ body: JSON.stringify({ ...payload, runId }),
45
+ });
46
+ return forwardToRunDO(runId, forward, deps);
47
+ }
48
+ // Everything below operates on a specific runId.
49
+ const runMatch = url.pathname.match(/^\/api\/runs\/([^/]+)(\/.+)?$/);
50
+ if (!runMatch) {
51
+ return json(404, { error: "route_not_found", path: url.pathname });
52
+ }
53
+ const runId = decodeURIComponent(runMatch[1]);
54
+ const tail = runMatch[2] ?? "";
55
+ if (req.method === "GET" && tail === "") {
56
+ const forward = new Request(`https://do-internal/get`, { method: "GET" });
57
+ return forwardToRunDO(runId, forward, deps);
58
+ }
59
+ if (req.method === "POST" && tail === "/cancel") {
60
+ const body = await safeJson(req);
61
+ if (isErrorBody(body))
62
+ return json(400, body);
63
+ return forwardToRunDO(runId, new Request(`https://do-internal/cancel`, {
64
+ method: "POST",
65
+ headers: { "content-type": "application/json" },
66
+ body: JSON.stringify(body),
67
+ }), deps);
68
+ }
69
+ // Waitpoint injections: events, signals, tokens.
70
+ const body = await safeJson(req);
71
+ if (isErrorBody(body))
72
+ return json(400, body);
73
+ const injection = parseInjection(tail, body);
74
+ if ("error" in injection)
75
+ return json(400, injection);
76
+ return forwardToRunDO(runId, new Request(`https://do-internal/resume`, {
77
+ method: "POST",
78
+ headers: { "content-type": "application/json" },
79
+ body: JSON.stringify({ injection: injection.injection }),
80
+ }), deps);
81
+ }
82
+ function isErrorBody(body) {
83
+ return typeof body.error === "string";
84
+ }
85
+ function parseInjection(tail, body) {
86
+ if (tail === "/events") {
87
+ if (typeof body.eventType !== "string" || body.eventType.length === 0) {
88
+ return { error: "invalid_body", message: "`eventType` (string) is required" };
89
+ }
90
+ return {
91
+ injection: { kind: "EVENT", eventType: body.eventType, payload: body.payload },
92
+ };
93
+ }
94
+ if (tail === "/signals") {
95
+ if (typeof body.name !== "string" || body.name.length === 0) {
96
+ return { error: "invalid_body", message: "`name` (string) is required" };
97
+ }
98
+ return { injection: { kind: "SIGNAL", name: body.name, payload: body.payload } };
99
+ }
100
+ const tokenMatch = tail.match(/^\/tokens\/([^/]+)$/);
101
+ if (tokenMatch) {
102
+ return {
103
+ injection: {
104
+ kind: "MANUAL",
105
+ tokenId: decodeURIComponent(tokenMatch[1]),
106
+ payload: body.payload,
107
+ },
108
+ };
109
+ }
110
+ return { error: "route_not_found", message: `unknown path suffix ${tail}` };
111
+ }
112
+ async function forwardToRunDO(runId, req, deps) {
113
+ const id = deps.runDO.idFromName(runId);
114
+ const stub = deps.runDO.get(id);
115
+ const resp = await stub.fetch(req);
116
+ // Add CORS on outbound responses.
117
+ const out = new Response(resp.body, resp);
118
+ for (const [k, v] of Object.entries(corsHeaders("GET,POST,OPTIONS"))) {
119
+ out.headers.set(k, v);
120
+ }
121
+ return out;
122
+ }
123
+ function defaultRunId(deps) {
124
+ if (deps.idGenerator)
125
+ return deps.idGenerator();
126
+ const now = deps.now ?? (() => Date.now());
127
+ const ts = now().toString(36);
128
+ const rand = Math.floor(Math.random() * 1_000_000)
129
+ .toString(36)
130
+ .padStart(4, "0");
131
+ return `run_${ts}_${rand}`;
132
+ }
133
+ async function safeJson(req) {
134
+ // Some requests are bodyless (GET). Only parse when we have a body.
135
+ if (req.method === "GET" || req.method === "HEAD")
136
+ return {};
137
+ const text = await req.text();
138
+ if (text.length === 0)
139
+ return {};
140
+ try {
141
+ return JSON.parse(text);
142
+ }
143
+ catch (err) {
144
+ return { error: "invalid_json", message: errMsg(err) };
145
+ }
146
+ }
147
+ function corsHeaders(methods) {
148
+ return {
149
+ "access-control-allow-origin": "*",
150
+ "access-control-allow-methods": methods,
151
+ "access-control-allow-headers": "content-type, x-voyant-protocol",
152
+ };
153
+ }
154
+ function json(status, body) {
155
+ return new Response(JSON.stringify(body), {
156
+ status,
157
+ headers: {
158
+ "content-type": "application/json; charset=utf-8",
159
+ ...corsHeaders("GET,POST,OPTIONS"),
160
+ },
161
+ });
162
+ }
163
+ function errMsg(err) {
164
+ return err instanceof Error ? err.message : String(err);
165
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/workflows-orchestrator-cloudflare",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
4
4
  "description": "Cloudflare Worker + Durable Object adapter for @voyantjs/workflows-orchestrator. Dispatches workflow-step requests to tenant Workers via a Workers-for-Platforms dispatch namespace.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -12,35 +12,41 @@
12
12
  "type": "module",
13
13
  "exports": {
14
14
  ".": {
15
- "types": "./src/index.ts",
16
- "import": "./src/index.ts"
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
17
  }
18
18
  },
19
- "main": "./src/index.ts",
20
- "types": "./src/index.ts",
21
- "files": ["dist", "src", "!**/*.test.*", "!**/*.spec.*", "NOTICE"],
22
- "scripts": {
23
- "build": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator build && tsc -p tsconfig.json",
24
- "check-types": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator build && tsc --noEmit",
25
- "dev": "tsc -w -p tsconfig.json",
26
- "test": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator build && vitest run",
27
- "test:watch": "vitest",
28
- "test:workers": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator build && vitest run --config vitest.workers.config.ts"
29
- },
19
+ "main": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "files": [
22
+ "dist",
23
+ "src",
24
+ "!**/*.test.*",
25
+ "!**/*.spec.*",
26
+ "NOTICE"
27
+ ],
30
28
  "dependencies": {
31
- "@voyantjs/workflows-orchestrator": "workspace:*",
32
- "@voyantjs/workflows": "workspace:*"
29
+ "@voyantjs/workflows-orchestrator": "0.6.9",
30
+ "@voyantjs/workflows": "0.6.9"
33
31
  },
34
32
  "devDependencies": {
35
33
  "@cloudflare/vitest-pool-workers": "^0.7.0",
36
34
  "@cloudflare/workers-types": "^4.20241218.0",
37
35
  "@types/node": "^20.12.0",
38
- "@voyantjs/voyant-typescript-config": "workspace:*",
39
36
  "typescript": "^5.9.2",
40
37
  "vitest": "^3.2.0",
41
- "wrangler": "^3.99.0"
38
+ "wrangler": "^3.99.0",
39
+ "@voyantjs/voyant-typescript-config": "0.1.0"
42
40
  },
43
41
  "publishConfig": {
44
42
  "access": "public"
43
+ },
44
+ "scripts": {
45
+ "build": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator build && tsc -p tsconfig.json",
46
+ "check-types": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator build && tsc --noEmit",
47
+ "dev": "tsc -w -p tsconfig.json",
48
+ "test": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator build && vitest run",
49
+ "test:watch": "vitest",
50
+ "test:workers": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator build && vitest run --config vitest.workers.config.ts"
45
51
  }
46
- }
52
+ }