@voyantjs/workflows-cloud-adapter 0.37.0 → 0.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +79 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +277 -0
- package/package.json +17 -25
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type ContainerNamespaceLike, type DurableObjectNamespaceLike, type DurableObjectStorageLike, type KvNamespaceLike, type StepDispatcher, type WorkerFetchDeps } from "@voyantjs/workflows-orchestrator-cloudflare";
|
|
2
|
+
export interface CloudWorkflowsEnv {
|
|
3
|
+
/** Per-run Durable Object namespace declared by the tenant Worker. */
|
|
4
|
+
WORKFLOW_RUN_DO: DurableObjectNamespaceLike;
|
|
5
|
+
/**
|
|
6
|
+
* Platform-injected namespace for the node step-runner Container fleet.
|
|
7
|
+
* The binding may target the shared platform fleet or a platform-operated
|
|
8
|
+
* per-org dedicated runner; the tenant adapter treats both the same.
|
|
9
|
+
*/
|
|
10
|
+
STEP_RUNNER?: ContainerNamespaceLike;
|
|
11
|
+
/**
|
|
12
|
+
* Optional KV namespace for workflow manifests. When present,
|
|
13
|
+
* `/api/manifests*` and `/api/events` are enabled.
|
|
14
|
+
*/
|
|
15
|
+
WORKFLOW_MANIFESTS?: KvNamespaceLike;
|
|
16
|
+
/**
|
|
17
|
+
* Comma-separated bearer tokens for public `/api/*` routes. Omit for local
|
|
18
|
+
* development only.
|
|
19
|
+
*/
|
|
20
|
+
VOYANT_API_TOKENS?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Prefix for the R2 S3 API URL that hosts the container bundle.
|
|
23
|
+
* Expected form: `https://<account>.r2.cloudflarestorage.com/<bucket>`.
|
|
24
|
+
*/
|
|
25
|
+
VOYANT_WORKFLOW_BUNDLE_URL_PREFIX?: string;
|
|
26
|
+
/** R2 object key for this tenant Worker version's `container.mjs`. */
|
|
27
|
+
VOYANT_WORKFLOW_BUNDLE_KEY?: string;
|
|
28
|
+
/** SHA-256 hex, or `sha256:<hex>`, for the container bundle bytes. */
|
|
29
|
+
VOYANT_WORKFLOW_BUNDLE_HASH?: string;
|
|
30
|
+
/** R2 read-only access key id used to mint short-lived signed bundle URLs. */
|
|
31
|
+
VOYANT_WORKFLOW_BUNDLE_R2_ACCESS_KEY_ID?: string;
|
|
32
|
+
/** R2 read-only secret access key used to mint short-lived signed bundle URLs. */
|
|
33
|
+
VOYANT_WORKFLOW_BUNDLE_R2_SECRET_ACCESS_KEY?: string;
|
|
34
|
+
/** Optional explicit R2 account id. Defaults to parsing URL_PREFIX. */
|
|
35
|
+
VOYANT_WORKFLOW_BUNDLE_R2_ACCOUNT_ID?: string;
|
|
36
|
+
/** Optional explicit R2 bucket. Defaults to parsing URL_PREFIX. */
|
|
37
|
+
VOYANT_WORKFLOW_BUNDLE_R2_BUCKET?: string;
|
|
38
|
+
/** Optional signed URL TTL in seconds. Defaults to 300. */
|
|
39
|
+
VOYANT_WORKFLOW_BUNDLE_URL_TTL_SECONDS?: string;
|
|
40
|
+
/** Shared secret used to sign dispatches to the platform step runner. */
|
|
41
|
+
VOYANT_WORKFLOW_STEP_AUTH_SECRET?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface DurableObjectStateLike {
|
|
44
|
+
storage: DurableObjectStorageLike;
|
|
45
|
+
}
|
|
46
|
+
export interface CloudOrchestratorOptions<Env extends CloudWorkflowsEnv = CloudWorkflowsEnv> {
|
|
47
|
+
verifyRequest?: WorkerFetchDeps["verifyRequest"];
|
|
48
|
+
logger?: WorkerFetchDeps["logger"];
|
|
49
|
+
idGenerator?: WorkerFetchDeps["idGenerator"];
|
|
50
|
+
now?: () => number;
|
|
51
|
+
tenantMeta?: WorkerFetchDeps["tenantMeta"];
|
|
52
|
+
services?: import("@voyantjs/workflows/driver").ServiceResolver;
|
|
53
|
+
resolveEnv?: (env: Env) => Env;
|
|
54
|
+
}
|
|
55
|
+
export interface CloudOrchestrator<Env extends CloudWorkflowsEnv = CloudWorkflowsEnv> {
|
|
56
|
+
fetch: (request: Request, env?: Env) => Promise<Response>;
|
|
57
|
+
WorkflowRunDO: WorkflowRunDOClass<Env>;
|
|
58
|
+
}
|
|
59
|
+
export type WorkflowRunDOClass<Env extends CloudWorkflowsEnv = CloudWorkflowsEnv> = new (state: DurableObjectStateLike, env: Env) => WorkflowRunDO<Env>;
|
|
60
|
+
type CloudExecutionOptions<Env extends CloudWorkflowsEnv = CloudWorkflowsEnv> = Pick<CloudOrchestratorOptions<Env>, "services" | "now" | "logger">;
|
|
61
|
+
export declare function createCloudOrchestrator<Env extends CloudWorkflowsEnv = CloudWorkflowsEnv>(workflows?: unknown, boundEnv?: Env, options?: CloudOrchestratorOptions<Env>): CloudOrchestrator<Env>;
|
|
62
|
+
export declare function mountWorkflows<App extends {
|
|
63
|
+
all?: (path: string, handler: (...args: unknown[]) => Response | Promise<Response>) => unknown;
|
|
64
|
+
fetch?: (request: Request, env?: unknown, ctx?: unknown) => Response | Promise<Response>;
|
|
65
|
+
}, Env extends CloudWorkflowsEnv = CloudWorkflowsEnv>(app: App, env?: Env, options?: CloudOrchestratorOptions<Env> & {
|
|
66
|
+
pathPrefix?: string;
|
|
67
|
+
}): App;
|
|
68
|
+
export declare function handleCloudFetch<Env extends CloudWorkflowsEnv = CloudWorkflowsEnv>(request: Request, env: Env, options?: CloudOrchestratorOptions<Env>): Promise<Response>;
|
|
69
|
+
export declare class WorkflowRunDO<Env extends CloudWorkflowsEnv = CloudWorkflowsEnv> {
|
|
70
|
+
private readonly state;
|
|
71
|
+
private readonly env;
|
|
72
|
+
constructor(state: DurableObjectStateLike, env: Env);
|
|
73
|
+
fetch(request: Request): Promise<Response>;
|
|
74
|
+
alarm(): Promise<void>;
|
|
75
|
+
protected executionOptions(): CloudExecutionOptions<Env>;
|
|
76
|
+
}
|
|
77
|
+
export declare function createCloudStepDispatcher<Env extends CloudWorkflowsEnv = CloudWorkflowsEnv>(env: Env, options?: CloudExecutionOptions<Env>): StepDispatcher;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
// @voyantjs/workflows-cloud-adapter
|
|
2
|
+
//
|
|
3
|
+
// Tenant Worker adapter for Voyant Cloud's workflows runtime. The package
|
|
4
|
+
// keeps tenant entrypoints small while preserving the same Cloudflare
|
|
5
|
+
// Durable Object run model used by the lower-level orchestrator adapter.
|
|
6
|
+
import { createBearerVerifier, createHmacSigner } from "@voyantjs/workflows/auth";
|
|
7
|
+
import { handleStepRequest, } from "@voyantjs/workflows/handler";
|
|
8
|
+
import { createInMemoryRateLimiter } from "@voyantjs/workflows/rate-limit";
|
|
9
|
+
import { createCfContainerStepRunner, createInlineDispatcher, createKvManifestStore, createR2Presigner, handleDurableObjectAlarm, handleDurableObjectRequest, handleWorkerRequest, } from "@voyantjs/workflows-orchestrator-cloudflare";
|
|
10
|
+
const envCache = new WeakMap();
|
|
11
|
+
const defaultExecutionOptions = {};
|
|
12
|
+
export function createCloudOrchestrator(workflows, boundEnv, options = {}) {
|
|
13
|
+
void workflows;
|
|
14
|
+
const WorkflowRunDOWithOptions = createWorkflowRunDOClass(options);
|
|
15
|
+
return {
|
|
16
|
+
fetch(request, requestEnv) {
|
|
17
|
+
const env = resolveBoundEnv(boundEnv, requestEnv, options);
|
|
18
|
+
return handleCloudFetch(request, env, options);
|
|
19
|
+
},
|
|
20
|
+
WorkflowRunDO: WorkflowRunDOWithOptions,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function mountWorkflows(app, env, options = {}) {
|
|
24
|
+
const orchestrator = createCloudOrchestrator(undefined, env, options);
|
|
25
|
+
const pathPrefix = normalizePathPrefix(options.pathPrefix ?? "/api");
|
|
26
|
+
if (typeof app.all === "function") {
|
|
27
|
+
app.all(`${pathPrefix}/*`, (...args) => {
|
|
28
|
+
const request = extractRequest(args);
|
|
29
|
+
const requestEnv = extractEnv(args, env);
|
|
30
|
+
return orchestrator.fetch(request, requestEnv);
|
|
31
|
+
});
|
|
32
|
+
return app;
|
|
33
|
+
}
|
|
34
|
+
if (typeof app.fetch === "function") {
|
|
35
|
+
const originalFetch = app.fetch.bind(app);
|
|
36
|
+
app.fetch = (request, requestEnv, ctx) => {
|
|
37
|
+
if (isMountedPath(new URL(request.url).pathname, pathPrefix)) {
|
|
38
|
+
return orchestrator.fetch(request, requestEnv ?? env);
|
|
39
|
+
}
|
|
40
|
+
return originalFetch(request, requestEnv, ctx);
|
|
41
|
+
};
|
|
42
|
+
return app;
|
|
43
|
+
}
|
|
44
|
+
throw new Error("mountWorkflows: app must expose either all(path, handler) or fetch(request, env)");
|
|
45
|
+
}
|
|
46
|
+
export async function handleCloudFetch(request, env, options = {}) {
|
|
47
|
+
const resolvedEnv = options.resolveEnv?.(env) ?? env;
|
|
48
|
+
const tokens = (resolvedEnv.VOYANT_API_TOKENS ?? "")
|
|
49
|
+
.split(",")
|
|
50
|
+
.map((s) => s.trim())
|
|
51
|
+
.filter((s) => s.length > 0);
|
|
52
|
+
return handleWorkerRequest(request, {
|
|
53
|
+
runDO: resolvedEnv.WORKFLOW_RUN_DO,
|
|
54
|
+
verifyRequest: options.verifyRequest ?? (tokens.length > 0 ? createBearerVerifier(tokens) : undefined),
|
|
55
|
+
logger: options.logger,
|
|
56
|
+
idGenerator: options.idGenerator,
|
|
57
|
+
now: options.now,
|
|
58
|
+
tenantMeta: options.tenantMeta,
|
|
59
|
+
manifestStore: resolvedEnv.WORKFLOW_MANIFESTS
|
|
60
|
+
? createKvManifestStore({ kv: resolvedEnv.WORKFLOW_MANIFESTS })
|
|
61
|
+
: undefined,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
export class WorkflowRunDO {
|
|
65
|
+
state;
|
|
66
|
+
env;
|
|
67
|
+
constructor(state, env) {
|
|
68
|
+
this.state = state;
|
|
69
|
+
this.env = env;
|
|
70
|
+
}
|
|
71
|
+
async fetch(request) {
|
|
72
|
+
return handleDurableObjectRequest(request, {
|
|
73
|
+
storage: this.state.storage,
|
|
74
|
+
dispatcher: resolveDispatcher(this.env, this.executionOptions()),
|
|
75
|
+
now: this.executionOptions().now,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async alarm() {
|
|
79
|
+
await handleDurableObjectAlarm({
|
|
80
|
+
storage: this.state.storage,
|
|
81
|
+
dispatcher: resolveDispatcher(this.env, this.executionOptions()),
|
|
82
|
+
now: this.executionOptions().now,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
executionOptions() {
|
|
86
|
+
return defaultExecutionOptions;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export function createCloudStepDispatcher(env, options = defaultExecutionOptions) {
|
|
90
|
+
return createInlineDispatcher(resolveStepHandler(env, options));
|
|
91
|
+
}
|
|
92
|
+
function createWorkflowRunDOClass(options) {
|
|
93
|
+
return class CloudWorkflowRunDO extends WorkflowRunDO {
|
|
94
|
+
executionOptions() {
|
|
95
|
+
return options;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function resolveDispatcher(env, options = defaultExecutionOptions) {
|
|
100
|
+
const cache = cacheFor(env);
|
|
101
|
+
if (!cache.dispatcher || cache.dispatcherOptions !== options) {
|
|
102
|
+
cache.dispatcherOptions = options;
|
|
103
|
+
cache.dispatcher = createCloudStepDispatcher(env, options);
|
|
104
|
+
}
|
|
105
|
+
return cache.dispatcher;
|
|
106
|
+
}
|
|
107
|
+
function resolveStepHandler(env, options = defaultExecutionOptions) {
|
|
108
|
+
const cache = cacheFor(env);
|
|
109
|
+
if (!cache.stepHandler || cache.stepHandlerOptions !== options) {
|
|
110
|
+
cache.stepHandlerOptions = options;
|
|
111
|
+
const handlerPromise = buildStepHandler(env, options);
|
|
112
|
+
cache.stepHandler = (req, stepOptions) => handlerPromise.then((handler) => handler(req, stepOptions));
|
|
113
|
+
}
|
|
114
|
+
return cache.stepHandler;
|
|
115
|
+
}
|
|
116
|
+
async function buildStepHandler(env, options = defaultExecutionOptions) {
|
|
117
|
+
const nodeStepRunner = await createNodeStepRunner(env, options);
|
|
118
|
+
const rateLimiter = createInMemoryRateLimiter();
|
|
119
|
+
return (req, stepOptions) => handleStepRequest(req, {
|
|
120
|
+
rateLimiter,
|
|
121
|
+
nodeStepRunner,
|
|
122
|
+
services: options.services,
|
|
123
|
+
now: options.now,
|
|
124
|
+
logger: options.logger,
|
|
125
|
+
}, stepOptions);
|
|
126
|
+
}
|
|
127
|
+
async function createNodeStepRunner(env, options) {
|
|
128
|
+
if (!env.STEP_RUNNER) {
|
|
129
|
+
return createInlineNodeStepRunner(options.now);
|
|
130
|
+
}
|
|
131
|
+
const bundle = resolveBundleConfig(env);
|
|
132
|
+
const presign = createR2Presigner({
|
|
133
|
+
accountId: bundle.accountId,
|
|
134
|
+
accessKeyId: bundle.accessKeyId,
|
|
135
|
+
secretAccessKey: bundle.secretAccessKey,
|
|
136
|
+
bucket: bundle.bucket,
|
|
137
|
+
});
|
|
138
|
+
const sign = env.VOYANT_WORKFLOW_STEP_AUTH_SECRET
|
|
139
|
+
? await createHmacSigner(env.VOYANT_WORKFLOW_STEP_AUTH_SECRET)
|
|
140
|
+
: undefined;
|
|
141
|
+
return createCfContainerStepRunner({
|
|
142
|
+
namespace: env.STEP_RUNNER,
|
|
143
|
+
sign,
|
|
144
|
+
logger: options.logger,
|
|
145
|
+
resolveBundle: async () => ({
|
|
146
|
+
url: await presign({
|
|
147
|
+
key: bundle.key,
|
|
148
|
+
expiresIn: bundle.expiresIn,
|
|
149
|
+
}),
|
|
150
|
+
hash: bundle.hash,
|
|
151
|
+
}),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function createInlineNodeStepRunner(now = () => Date.now()) {
|
|
155
|
+
return async ({ attempt, fn, stepCtx }) => {
|
|
156
|
+
const startedAt = now();
|
|
157
|
+
try {
|
|
158
|
+
return {
|
|
159
|
+
attempt,
|
|
160
|
+
status: "ok",
|
|
161
|
+
output: await fn(stepCtx),
|
|
162
|
+
startedAt,
|
|
163
|
+
finishedAt: now(),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
const e = err;
|
|
168
|
+
return {
|
|
169
|
+
attempt,
|
|
170
|
+
status: "err",
|
|
171
|
+
startedAt,
|
|
172
|
+
finishedAt: now(),
|
|
173
|
+
error: {
|
|
174
|
+
category: "USER_ERROR",
|
|
175
|
+
code: typeof err.code === "string"
|
|
176
|
+
? err.code
|
|
177
|
+
: "UNKNOWN",
|
|
178
|
+
message: e?.message ?? String(err),
|
|
179
|
+
name: e?.name,
|
|
180
|
+
stack: e?.stack,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function resolveBundleConfig(env) {
|
|
187
|
+
const parsedPrefix = parseBundleUrlPrefix(env.VOYANT_WORKFLOW_BUNDLE_URL_PREFIX);
|
|
188
|
+
const accountId = env.VOYANT_WORKFLOW_BUNDLE_R2_ACCOUNT_ID ?? parsedPrefix.accountId;
|
|
189
|
+
const bucket = env.VOYANT_WORKFLOW_BUNDLE_R2_BUCKET ?? parsedPrefix.bucket;
|
|
190
|
+
const accessKeyId = env.VOYANT_WORKFLOW_BUNDLE_R2_ACCESS_KEY_ID;
|
|
191
|
+
const secretAccessKey = env.VOYANT_WORKFLOW_BUNDLE_R2_SECRET_ACCESS_KEY;
|
|
192
|
+
const key = env.VOYANT_WORKFLOW_BUNDLE_KEY;
|
|
193
|
+
const hash = env.VOYANT_WORKFLOW_BUNDLE_HASH;
|
|
194
|
+
const missing = [
|
|
195
|
+
["VOYANT_WORKFLOW_BUNDLE_R2_ACCESS_KEY_ID", accessKeyId],
|
|
196
|
+
["VOYANT_WORKFLOW_BUNDLE_R2_SECRET_ACCESS_KEY", secretAccessKey],
|
|
197
|
+
["VOYANT_WORKFLOW_BUNDLE_KEY", key],
|
|
198
|
+
["VOYANT_WORKFLOW_BUNDLE_HASH", hash],
|
|
199
|
+
].filter(([, value]) => typeof value !== "string" || value.length === 0);
|
|
200
|
+
if (!env.VOYANT_WORKFLOW_BUNDLE_URL_PREFIX && (!accountId || !bucket)) {
|
|
201
|
+
missing.push(["VOYANT_WORKFLOW_BUNDLE_URL_PREFIX", env.VOYANT_WORKFLOW_BUNDLE_URL_PREFIX]);
|
|
202
|
+
}
|
|
203
|
+
if (!accountId)
|
|
204
|
+
missing.push(["VOYANT_WORKFLOW_BUNDLE_R2_ACCOUNT_ID", accountId]);
|
|
205
|
+
if (!bucket)
|
|
206
|
+
missing.push(["VOYANT_WORKFLOW_BUNDLE_R2_BUCKET", bucket]);
|
|
207
|
+
if (missing.length > 0) {
|
|
208
|
+
throw new Error(`@voyantjs/workflows-cloud-adapter: STEP_RUNNER is configured but bundle env is incomplete: ${missing
|
|
209
|
+
.map(([name]) => name)
|
|
210
|
+
.join(", ")}`);
|
|
211
|
+
}
|
|
212
|
+
const expiresIn = Number(env.VOYANT_WORKFLOW_BUNDLE_URL_TTL_SECONDS ?? 300);
|
|
213
|
+
if (!Number.isFinite(expiresIn) || expiresIn < 1 || expiresIn > 604_800) {
|
|
214
|
+
throw new Error("@voyantjs/workflows-cloud-adapter: VOYANT_WORKFLOW_BUNDLE_URL_TTL_SECONDS must be 1..604800");
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
accountId: accountId,
|
|
218
|
+
bucket: bucket,
|
|
219
|
+
accessKeyId: accessKeyId,
|
|
220
|
+
secretAccessKey: secretAccessKey,
|
|
221
|
+
key: key,
|
|
222
|
+
hash: hash,
|
|
223
|
+
expiresIn,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function parseBundleUrlPrefix(prefix) {
|
|
227
|
+
if (!prefix)
|
|
228
|
+
return {};
|
|
229
|
+
const url = new URL(prefix);
|
|
230
|
+
const suffix = ".r2.cloudflarestorage.com";
|
|
231
|
+
const accountId = url.hostname.endsWith(suffix)
|
|
232
|
+
? url.hostname.slice(0, -suffix.length)
|
|
233
|
+
: undefined;
|
|
234
|
+
const bucket = url.pathname.replace(/^\/+/, "").split("/")[0];
|
|
235
|
+
return {
|
|
236
|
+
accountId: accountId && accountId.length > 0 ? accountId : undefined,
|
|
237
|
+
bucket: bucket && bucket.length > 0 ? bucket : undefined,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function cacheFor(env) {
|
|
241
|
+
let cache = envCache.get(env);
|
|
242
|
+
if (!cache) {
|
|
243
|
+
cache = {};
|
|
244
|
+
envCache.set(env, cache);
|
|
245
|
+
}
|
|
246
|
+
return cache;
|
|
247
|
+
}
|
|
248
|
+
function resolveBoundEnv(boundEnv, requestEnv, options) {
|
|
249
|
+
const env = requestEnv ?? boundEnv;
|
|
250
|
+
if (!env) {
|
|
251
|
+
throw new Error("@voyantjs/workflows-cloud-adapter: env must be passed to fetch(request, env) or createCloudOrchestrator(workflows, env)");
|
|
252
|
+
}
|
|
253
|
+
return options.resolveEnv?.(env) ?? env;
|
|
254
|
+
}
|
|
255
|
+
function normalizePathPrefix(prefix) {
|
|
256
|
+
if (prefix === "/")
|
|
257
|
+
return "";
|
|
258
|
+
return `/${prefix.replace(/^\/+|\/+$/g, "")}`;
|
|
259
|
+
}
|
|
260
|
+
function isMountedPath(pathname, prefix) {
|
|
261
|
+
return pathname === prefix || pathname.startsWith(`${prefix}/`);
|
|
262
|
+
}
|
|
263
|
+
function extractRequest(args) {
|
|
264
|
+
const first = args[0];
|
|
265
|
+
if (first instanceof Request)
|
|
266
|
+
return first;
|
|
267
|
+
const raw = first?.req?.raw;
|
|
268
|
+
if (raw instanceof Request)
|
|
269
|
+
return raw;
|
|
270
|
+
throw new Error("mountWorkflows: could not resolve Request from route handler arguments");
|
|
271
|
+
}
|
|
272
|
+
function extractEnv(args, boundEnv) {
|
|
273
|
+
if (boundEnv)
|
|
274
|
+
return boundEnv;
|
|
275
|
+
const firstEnv = args[0]?.env;
|
|
276
|
+
return firstEnv ?? args[1];
|
|
277
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/workflows-cloud-adapter",
|
|
3
|
-
"version": "0.37.
|
|
3
|
+
"version": "0.37.1",
|
|
4
4
|
"description": "Tenant Worker adapter for Voyant Cloud Workflows deployments. Wires WorkflowRunDO, inline local dispatch, and platform step-runner bindings from env.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"type": "module",
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
|
-
"types": "./
|
|
16
|
-
"import": "./
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"main": "./dist/index.js",
|
|
@@ -25,33 +25,25 @@
|
|
|
25
25
|
"!**/*.spec.*",
|
|
26
26
|
"NOTICE"
|
|
27
27
|
],
|
|
28
|
-
"scripts": {
|
|
29
|
-
"build": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator-cloudflare build && tsc -p tsconfig.json",
|
|
30
|
-
"check-types": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator-cloudflare build && tsc --noEmit",
|
|
31
|
-
"dev": "tsc -w -p tsconfig.json",
|
|
32
|
-
"test": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator-cloudflare build && vitest run",
|
|
33
|
-
"test:watch": "vitest"
|
|
34
|
-
},
|
|
35
28
|
"dependencies": {
|
|
36
|
-
"@voyantjs/workflows": "
|
|
37
|
-
"@voyantjs/workflows-orchestrator": "
|
|
38
|
-
"@voyantjs/workflows-orchestrator-cloudflare": "
|
|
29
|
+
"@voyantjs/workflows": "0.37.1",
|
|
30
|
+
"@voyantjs/workflows-orchestrator": "0.37.1",
|
|
31
|
+
"@voyantjs/workflows-orchestrator-cloudflare": "0.37.1"
|
|
39
32
|
},
|
|
40
33
|
"devDependencies": {
|
|
41
34
|
"@types/node": "^20.12.0",
|
|
42
|
-
"@voyantjs/voyant-typescript-config": "workspace:*",
|
|
43
35
|
"typescript": "^5.9.2",
|
|
44
|
-
"vitest": "^4.1.2"
|
|
36
|
+
"vitest": "^4.1.2",
|
|
37
|
+
"@voyantjs/voyant-typescript-config": "0.1.0"
|
|
45
38
|
},
|
|
46
39
|
"publishConfig": {
|
|
47
|
-
"access": "public"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
"types": "./dist/index.d.ts"
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator-cloudflare build && tsc -p tsconfig.json",
|
|
44
|
+
"check-types": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator-cloudflare build && tsc --noEmit",
|
|
45
|
+
"dev": "tsc -w -p tsconfig.json",
|
|
46
|
+
"test": "pnpm -C ../.. --filter @voyantjs/workflows-orchestrator-cloudflare build && vitest run",
|
|
47
|
+
"test:watch": "vitest"
|
|
56
48
|
}
|
|
57
|
-
}
|
|
49
|
+
}
|