@stepflowjs/adapter-cloudflare 0.0.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 +69 -0
- package/dist/index.js +333 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Stepflow } from '@stepflowjs/core';
|
|
2
|
+
export { Execution, NotifyResult, TriggerResult } from '@stepflowjs/core';
|
|
3
|
+
import { AuthContext, AuthConfig, EndpointOption, BaseAdapterOptions } from '@stepflowjs/adapter-shared';
|
|
4
|
+
export { AuthConfig, AuthContext, AuthHandler, AuthResult, EndpointConfig, EndpointOption, EndpointPreset, RouteName, allOf, anyOf, createApiKeyAuth, createBearerAuth, isRouteEnabled, resolveEndpoints } from '@stepflowjs/adapter-shared';
|
|
5
|
+
|
|
6
|
+
/** Cloudflare-specific request type for auth handlers */
|
|
7
|
+
type CFRequest = {
|
|
8
|
+
header(name: string): string | undefined;
|
|
9
|
+
headers: Headers;
|
|
10
|
+
url: string;
|
|
11
|
+
method: string;
|
|
12
|
+
query(name: string): string | undefined;
|
|
13
|
+
};
|
|
14
|
+
/** Cloudflare-specific auth context */
|
|
15
|
+
type CFAuthContext = AuthContext<CFRequest, Request>;
|
|
16
|
+
/** Cloudflare-specific auth config */
|
|
17
|
+
type CFAuthConfig = AuthConfig<CFRequest, Request>;
|
|
18
|
+
interface HandlerOptions {
|
|
19
|
+
/** Base path prefix for all routes (e.g., "/api/stepflow"). */
|
|
20
|
+
basePath?: string;
|
|
21
|
+
/** Custom health check function. Defaults to stepflow.healthCheck(). */
|
|
22
|
+
healthCheck?: () => Promise<boolean>;
|
|
23
|
+
/** Endpoint configuration - preset or fine-grained */
|
|
24
|
+
endpoints?: EndpointOption;
|
|
25
|
+
/** Authorization configuration */
|
|
26
|
+
auth?: CFAuthConfig;
|
|
27
|
+
/** Callback when authorization fails */
|
|
28
|
+
onAuthFailure?: BaseAdapterOptions<CFRequest, Request>["onAuthFailure"];
|
|
29
|
+
}
|
|
30
|
+
interface TriggerRequestBody<TPayload = unknown> {
|
|
31
|
+
payload: TPayload;
|
|
32
|
+
metadata?: Record<string, unknown>;
|
|
33
|
+
runId?: string;
|
|
34
|
+
delay?: number;
|
|
35
|
+
idempotencyKey?: string;
|
|
36
|
+
}
|
|
37
|
+
interface NotifyRequestBody {
|
|
38
|
+
data: unknown;
|
|
39
|
+
}
|
|
40
|
+
interface ErrorResponseBody {
|
|
41
|
+
error: string;
|
|
42
|
+
message?: string;
|
|
43
|
+
}
|
|
44
|
+
type FetchHandler = (request: Request) => Promise<Response>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create a Cloudflare Workers fetch handler for Stepflow
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // src/index.ts
|
|
52
|
+
* import { Stepflow } from '@stepflowjs/core';
|
|
53
|
+
* import { createStepflowHandler } from '@stepflowjs/adapter-cloudflare';
|
|
54
|
+
*
|
|
55
|
+
* const stepflow = new Stepflow({ storage: ... });
|
|
56
|
+
* const handler = createStepflowHandler(stepflow, { basePath: '/api/stepflow' });
|
|
57
|
+
*
|
|
58
|
+
* export default {
|
|
59
|
+
* async fetch(request: Request): Promise<Response> {
|
|
60
|
+
* const response = await handler(request);
|
|
61
|
+
* if (response) return response;
|
|
62
|
+
* return new Response('Not found', { status: 404 });
|
|
63
|
+
* }
|
|
64
|
+
* };
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
declare function createStepflowHandler(stepflow: Stepflow, options?: HandlerOptions): FetchHandler;
|
|
68
|
+
|
|
69
|
+
export { type CFAuthConfig, type CFAuthContext, type CFRequest, type ErrorResponseBody, type FetchHandler, type HandlerOptions, type NotifyRequestBody, type TriggerRequestBody, createStepflowHandler };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
isRouteEnabled,
|
|
4
|
+
runAuth,
|
|
5
|
+
getAuthFailureResponse,
|
|
6
|
+
createErrorBody
|
|
7
|
+
} from "@stepflowjs/adapter-shared";
|
|
8
|
+
import {
|
|
9
|
+
createApiKeyAuth,
|
|
10
|
+
createBearerAuth,
|
|
11
|
+
anyOf,
|
|
12
|
+
allOf,
|
|
13
|
+
isRouteEnabled as isRouteEnabled2,
|
|
14
|
+
resolveEndpoints
|
|
15
|
+
} from "@stepflowjs/adapter-shared";
|
|
16
|
+
function normalizeBasePath(basePath) {
|
|
17
|
+
if (!basePath) return "";
|
|
18
|
+
if (basePath === "/") return "";
|
|
19
|
+
return basePath.startsWith("/") ? basePath.replace(/\/$/, "") : `/${basePath}`;
|
|
20
|
+
}
|
|
21
|
+
function getAccessToken(request) {
|
|
22
|
+
const url = new URL(request.url);
|
|
23
|
+
const queryToken = url.searchParams.get("token");
|
|
24
|
+
if (queryToken) return queryToken;
|
|
25
|
+
const authHeader = request.headers.get("authorization");
|
|
26
|
+
if (!authHeader) return void 0;
|
|
27
|
+
const match = authHeader.match(/^Bearer\s+(.+)$/i);
|
|
28
|
+
return match?.[1];
|
|
29
|
+
}
|
|
30
|
+
function jsonResponse(data, status = 200) {
|
|
31
|
+
return new Response(JSON.stringify(data), {
|
|
32
|
+
status,
|
|
33
|
+
headers: { "Content-Type": "application/json" }
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function jsonError(status, error, message) {
|
|
37
|
+
const body = message ? { error, message } : { error };
|
|
38
|
+
return new Response(JSON.stringify(body), {
|
|
39
|
+
status,
|
|
40
|
+
headers: { "Content-Type": "application/json" }
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function jsonAuthError(status, code, message) {
|
|
44
|
+
const body = createErrorBody(code, message);
|
|
45
|
+
return new Response(JSON.stringify(body), {
|
|
46
|
+
status,
|
|
47
|
+
headers: { "Content-Type": "application/json" }
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function parseJsonBody(request) {
|
|
51
|
+
try {
|
|
52
|
+
return await request.json();
|
|
53
|
+
} catch {
|
|
54
|
+
throw new Error("Invalid JSON body");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function createCFRequest(request) {
|
|
58
|
+
const url = new URL(request.url);
|
|
59
|
+
return {
|
|
60
|
+
header: (name) => request.headers.get(name) ?? void 0,
|
|
61
|
+
headers: request.headers,
|
|
62
|
+
url: request.url,
|
|
63
|
+
method: request.method,
|
|
64
|
+
query: (name) => url.searchParams.get(name) ?? void 0
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function checkAuth(request, route, options, params = {}) {
|
|
68
|
+
const ctx = {
|
|
69
|
+
route,
|
|
70
|
+
request: createCFRequest(request),
|
|
71
|
+
extra: request,
|
|
72
|
+
...params
|
|
73
|
+
};
|
|
74
|
+
const result = await runAuth(ctx, options.auth);
|
|
75
|
+
if (!result.ok) {
|
|
76
|
+
const { status, code, message } = getAuthFailureResponse(result);
|
|
77
|
+
await options.onAuthFailure?.(ctx, result);
|
|
78
|
+
return jsonAuthError(status, code, message);
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function matchRoute(pathname, basePath) {
|
|
83
|
+
const path = basePath ? pathname.slice(basePath.length) : pathname;
|
|
84
|
+
if (path === "/health") {
|
|
85
|
+
return { handler: "health", params: {} };
|
|
86
|
+
}
|
|
87
|
+
const triggerMatch = path.match(/^\/trigger\/([^/]+)$/);
|
|
88
|
+
if (triggerMatch) {
|
|
89
|
+
return { handler: "trigger", params: { workflowId: triggerMatch[1] } };
|
|
90
|
+
}
|
|
91
|
+
const runMatch = path.match(/^\/runs\/([^/]+)$/);
|
|
92
|
+
if (runMatch) {
|
|
93
|
+
return { handler: "run", params: { runId: runMatch[1] } };
|
|
94
|
+
}
|
|
95
|
+
const streamMatch = path.match(/^\/runs\/([^/]+)\/stream$/);
|
|
96
|
+
if (streamMatch) {
|
|
97
|
+
return { handler: "stream", params: { runId: streamMatch[1] } };
|
|
98
|
+
}
|
|
99
|
+
const notifyMatch = path.match(/^\/notify\/([^/]+)$/);
|
|
100
|
+
if (notifyMatch) {
|
|
101
|
+
return { handler: "notify", params: { eventId: notifyMatch[1] } };
|
|
102
|
+
}
|
|
103
|
+
const workflowTriggerMatch = path.match(/^\/workflows\/([^/]+)\/trigger$/);
|
|
104
|
+
if (workflowTriggerMatch) {
|
|
105
|
+
return {
|
|
106
|
+
handler: "trigger",
|
|
107
|
+
params: { workflowId: workflowTriggerMatch[1] }
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const eventNotifyMatch = path.match(/^\/events\/([^/]+)\/notify$/);
|
|
111
|
+
if (eventNotifyMatch) {
|
|
112
|
+
return { handler: "notify", params: { eventId: eventNotifyMatch[1] } };
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
function createSSEStream() {
|
|
117
|
+
let controller;
|
|
118
|
+
const encoder = new TextEncoder();
|
|
119
|
+
const stream = new ReadableStream({
|
|
120
|
+
start(ctrl) {
|
|
121
|
+
controller = ctrl;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return { stream, controller, encoder };
|
|
125
|
+
}
|
|
126
|
+
function writeSSE(controller, encoder, event, data) {
|
|
127
|
+
const message = `event: ${event}
|
|
128
|
+
data: ${JSON.stringify(data)}
|
|
129
|
+
|
|
130
|
+
`;
|
|
131
|
+
controller.enqueue(encoder.encode(message));
|
|
132
|
+
}
|
|
133
|
+
function createStepflowHandler(stepflow, options = {}) {
|
|
134
|
+
const basePath = normalizeBasePath(options.basePath);
|
|
135
|
+
return async (request) => {
|
|
136
|
+
const url = new URL(request.url);
|
|
137
|
+
const pathname = url.pathname;
|
|
138
|
+
if (basePath && !pathname.startsWith(basePath)) {
|
|
139
|
+
return jsonError(404, "Not found");
|
|
140
|
+
}
|
|
141
|
+
const match = matchRoute(pathname, basePath);
|
|
142
|
+
if (!match) {
|
|
143
|
+
return jsonError(404, "Not found");
|
|
144
|
+
}
|
|
145
|
+
const { handler, params } = match;
|
|
146
|
+
if (handler === "health" && request.method === "GET") {
|
|
147
|
+
if (!isRouteEnabled("health", options.endpoints)) {
|
|
148
|
+
return jsonError(404, "Not found");
|
|
149
|
+
}
|
|
150
|
+
const authError = await checkAuth(request, "health", options);
|
|
151
|
+
if (authError) return authError;
|
|
152
|
+
try {
|
|
153
|
+
const ok = await (options.healthCheck?.() ?? stepflow.healthCheck());
|
|
154
|
+
return jsonResponse({ ok });
|
|
155
|
+
} catch (error) {
|
|
156
|
+
return jsonError(
|
|
157
|
+
500,
|
|
158
|
+
"Internal server error",
|
|
159
|
+
error.message
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (handler === "trigger" && request.method === "POST") {
|
|
164
|
+
if (!isRouteEnabled("trigger", options.endpoints)) {
|
|
165
|
+
return jsonError(404, "Not found");
|
|
166
|
+
}
|
|
167
|
+
const workflowId = params.workflowId;
|
|
168
|
+
const authError = await checkAuth(request, "trigger", options, {
|
|
169
|
+
workflowId
|
|
170
|
+
});
|
|
171
|
+
if (authError) return authError;
|
|
172
|
+
try {
|
|
173
|
+
const body = await parseJsonBody(request);
|
|
174
|
+
const result = await stepflow.trigger(workflowId, body.payload, {
|
|
175
|
+
runId: body.runId,
|
|
176
|
+
metadata: body.metadata,
|
|
177
|
+
delay: body.delay,
|
|
178
|
+
idempotencyKey: body.idempotencyKey
|
|
179
|
+
});
|
|
180
|
+
const response = result;
|
|
181
|
+
return jsonResponse(response);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
const message = error.message;
|
|
184
|
+
if (message.includes("Workflow") && message.includes("not found")) {
|
|
185
|
+
return jsonError(404, "Not found", message);
|
|
186
|
+
}
|
|
187
|
+
if (message === "Invalid JSON body") {
|
|
188
|
+
return jsonError(400, "Bad request", message);
|
|
189
|
+
}
|
|
190
|
+
return jsonError(500, "Internal server error", message);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (handler === "run" && request.method === "GET") {
|
|
194
|
+
if (!isRouteEnabled("runs", options.endpoints)) {
|
|
195
|
+
return jsonError(404, "Not found");
|
|
196
|
+
}
|
|
197
|
+
const runId = params.runId;
|
|
198
|
+
const authError = await checkAuth(request, "runs", options, { runId });
|
|
199
|
+
if (authError) return authError;
|
|
200
|
+
try {
|
|
201
|
+
const accessToken = getAccessToken(request);
|
|
202
|
+
const run = await stepflow.getRun(runId, { accessToken });
|
|
203
|
+
if (!run) {
|
|
204
|
+
return jsonError(404, "Not found", `Run "${runId}" not found`);
|
|
205
|
+
}
|
|
206
|
+
const response = run;
|
|
207
|
+
return jsonResponse(response);
|
|
208
|
+
} catch (error) {
|
|
209
|
+
const message = error.message;
|
|
210
|
+
if (message === "Invalid access token") {
|
|
211
|
+
return jsonError(401, "Unauthorized", message);
|
|
212
|
+
}
|
|
213
|
+
return jsonError(500, "Internal server error", message);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (handler === "stream" && request.method === "GET") {
|
|
217
|
+
if (!isRouteEnabled("runsStream", options.endpoints)) {
|
|
218
|
+
return jsonError(404, "Not found");
|
|
219
|
+
}
|
|
220
|
+
const runId = params.runId;
|
|
221
|
+
const authError = await checkAuth(request, "runsStream", options, {
|
|
222
|
+
runId
|
|
223
|
+
});
|
|
224
|
+
if (authError) return authError;
|
|
225
|
+
const accessToken = getAccessToken(request);
|
|
226
|
+
if (accessToken) {
|
|
227
|
+
try {
|
|
228
|
+
await stepflow.getRun(runId, { accessToken });
|
|
229
|
+
} catch (error) {
|
|
230
|
+
const message = error.message;
|
|
231
|
+
if (message === "Invalid access token") {
|
|
232
|
+
return jsonError(401, "Unauthorized", message);
|
|
233
|
+
}
|
|
234
|
+
return jsonError(500, "Internal server error", message);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const throttleMsParam = url.searchParams.get("throttle");
|
|
238
|
+
const throttleMs = throttleMsParam ? Number(throttleMsParam) : void 0;
|
|
239
|
+
const effectiveThrottleMs = throttleMs !== void 0 && Number.isFinite(throttleMs) && throttleMs >= 0 ? throttleMs : void 0;
|
|
240
|
+
const { stream, controller, encoder } = createSSEStream();
|
|
241
|
+
let lastSentAt = 0;
|
|
242
|
+
const send = (event, data) => {
|
|
243
|
+
if (effectiveThrottleMs !== void 0) {
|
|
244
|
+
const now = Date.now();
|
|
245
|
+
if (now - lastSentAt < effectiveThrottleMs) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
lastSentAt = now;
|
|
249
|
+
}
|
|
250
|
+
writeSSE(controller, encoder, event, data);
|
|
251
|
+
};
|
|
252
|
+
void (async () => {
|
|
253
|
+
try {
|
|
254
|
+
let run = await stepflow.getRun(runId);
|
|
255
|
+
while (!run) {
|
|
256
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
257
|
+
run = await stepflow.getRun(runId);
|
|
258
|
+
}
|
|
259
|
+
const executionId = run.id;
|
|
260
|
+
send("update", run);
|
|
261
|
+
if (run.status === "completed") {
|
|
262
|
+
send("execution:complete", { result: run.result });
|
|
263
|
+
}
|
|
264
|
+
if (run.status === "failed") {
|
|
265
|
+
send("execution:failed", { error: run.error });
|
|
266
|
+
}
|
|
267
|
+
const unsubscribe = stepflow.subscribeToExecution(executionId, () => {
|
|
268
|
+
void (async () => {
|
|
269
|
+
const execution = await stepflow.getExecution(executionId);
|
|
270
|
+
if (execution) {
|
|
271
|
+
send("update", execution);
|
|
272
|
+
if (execution.status === "completed") {
|
|
273
|
+
send("execution:complete", { result: execution.result });
|
|
274
|
+
}
|
|
275
|
+
if (execution.status === "failed") {
|
|
276
|
+
send("execution:failed", { error: execution.error });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
})();
|
|
280
|
+
});
|
|
281
|
+
await new Promise((resolve) => setTimeout(resolve, 60 * 60 * 1e3));
|
|
282
|
+
unsubscribe();
|
|
283
|
+
} catch {
|
|
284
|
+
} finally {
|
|
285
|
+
try {
|
|
286
|
+
controller.close();
|
|
287
|
+
} catch {
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
})();
|
|
291
|
+
return new Response(stream, {
|
|
292
|
+
headers: {
|
|
293
|
+
"Content-Type": "text/event-stream",
|
|
294
|
+
"Cache-Control": "no-cache",
|
|
295
|
+
Connection: "keep-alive"
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
if (handler === "notify" && request.method === "POST") {
|
|
300
|
+
if (!isRouteEnabled("notify", options.endpoints)) {
|
|
301
|
+
return jsonError(404, "Not found");
|
|
302
|
+
}
|
|
303
|
+
const eventId = params.eventId;
|
|
304
|
+
const authError = await checkAuth(request, "notify", options, {
|
|
305
|
+
eventId
|
|
306
|
+
});
|
|
307
|
+
if (authError) return authError;
|
|
308
|
+
try {
|
|
309
|
+
const body = await parseJsonBody(request);
|
|
310
|
+
const result = await stepflow.notify(eventId, body.data);
|
|
311
|
+
const response = result;
|
|
312
|
+
return jsonResponse(response);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
const message = error.message;
|
|
315
|
+
if (message === "Invalid JSON body") {
|
|
316
|
+
return jsonError(400, "Bad request", message);
|
|
317
|
+
}
|
|
318
|
+
return jsonError(500, "Internal server error", message);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return jsonError(405, "Method not allowed");
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
export {
|
|
325
|
+
allOf,
|
|
326
|
+
anyOf,
|
|
327
|
+
createApiKeyAuth,
|
|
328
|
+
createBearerAuth,
|
|
329
|
+
createStepflowHandler,
|
|
330
|
+
isRouteEnabled2 as isRouteEnabled,
|
|
331
|
+
resolveEndpoints
|
|
332
|
+
};
|
|
333
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Execution, TriggerResult, NotifyResult } from \"@stepflowjs/core\";\nimport type { Stepflow } from \"@stepflowjs/core\";\nimport {\n type AuthConfig,\n type AuthContext,\n type BaseAdapterOptions,\n type EndpointOption,\n type RouteName,\n isRouteEnabled,\n runAuth,\n getAuthFailureResponse,\n createErrorBody,\n} from \"@stepflowjs/adapter-shared\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Cloudflare-specific request type for auth handlers */\nexport type CFRequest = {\n header(name: string): string | undefined;\n headers: Headers;\n url: string;\n method: string;\n query(name: string): string | undefined;\n};\n\n/** Cloudflare-specific auth context */\nexport type CFAuthContext = AuthContext<CFRequest, Request>;\n\n/** Cloudflare-specific auth config */\nexport type CFAuthConfig = AuthConfig<CFRequest, Request>;\n\nexport interface HandlerOptions {\n /** Base path prefix for all routes (e.g., \"/api/stepflow\"). */\n basePath?: string;\n /** Custom health check function. Defaults to stepflow.healthCheck(). */\n healthCheck?: () => Promise<boolean>;\n /** Endpoint configuration - preset or fine-grained */\n endpoints?: EndpointOption;\n /** Authorization configuration */\n auth?: CFAuthConfig;\n /** Callback when authorization fails */\n onAuthFailure?: BaseAdapterOptions<CFRequest, Request>[\"onAuthFailure\"];\n}\n\nexport interface TriggerRequestBody<TPayload = unknown> {\n payload: TPayload;\n metadata?: Record<string, unknown>;\n runId?: string;\n delay?: number;\n idempotencyKey?: string;\n}\n\nexport interface NotifyRequestBody {\n data: unknown;\n}\n\nexport interface ErrorResponseBody {\n error: string;\n message?: string;\n}\n\nexport type FetchHandler = (request: Request) => Promise<Response>;\n\n// ============================================================================\n// Re-exports from shared\n// ============================================================================\n\nexport {\n type AuthContext,\n type AuthResult,\n type AuthHandler,\n type AuthConfig,\n type EndpointConfig,\n type EndpointOption,\n type EndpointPreset,\n type RouteName,\n createApiKeyAuth,\n createBearerAuth,\n anyOf,\n allOf,\n isRouteEnabled,\n resolveEndpoints,\n} from \"@stepflowjs/adapter-shared\";\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction normalizeBasePath(basePath: string | undefined): string {\n if (!basePath) return \"\";\n if (basePath === \"/\") return \"\";\n return basePath.startsWith(\"/\")\n ? basePath.replace(/\\/$/, \"\")\n : `/${basePath}`;\n}\n\nfunction getAccessToken(request: Request): string | undefined {\n const url = new URL(request.url);\n const queryToken = url.searchParams.get(\"token\");\n if (queryToken) return queryToken;\n\n const authHeader = request.headers.get(\"authorization\");\n if (!authHeader) return undefined;\n\n const match = authHeader.match(/^Bearer\\s+(.+)$/i);\n return match?.[1];\n}\n\nfunction jsonResponse<T>(data: T, status = 200): Response {\n return new Response(JSON.stringify(data), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nfunction jsonError(status: number, error: string, message?: string): Response {\n const body: ErrorResponseBody = message ? { error, message } : { error };\n return new Response(JSON.stringify(body), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nfunction jsonAuthError(\n status: number,\n code: string,\n message: string,\n): Response {\n const body = createErrorBody(code, message);\n return new Response(JSON.stringify(body), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nasync function parseJsonBody<T>(request: Request): Promise<T> {\n try {\n return (await request.json()) as T;\n } catch {\n throw new Error(\"Invalid JSON body\");\n }\n}\n\n/**\n * Creates a CFRequest object from Request for auth handlers\n */\nfunction createCFRequest(request: Request): CFRequest {\n const url = new URL(request.url);\n return {\n header: (name: string) => request.headers.get(name) ?? undefined,\n headers: request.headers,\n url: request.url,\n method: request.method,\n query: (name: string) => url.searchParams.get(name) ?? undefined,\n };\n}\n\n/**\n * Runs authorization check and returns error response if denied\n */\nasync function checkAuth(\n request: Request,\n route: RouteName,\n options: HandlerOptions,\n params: { workflowId?: string; eventId?: string; runId?: string } = {},\n): Promise<Response | null> {\n const ctx: CFAuthContext = {\n route,\n request: createCFRequest(request),\n extra: request,\n ...params,\n };\n\n const result = await runAuth(ctx, options.auth);\n\n if (!result.ok) {\n const { status, code, message } = getAuthFailureResponse(result);\n await options.onAuthFailure?.(ctx, result);\n return jsonAuthError(status, code, message);\n }\n\n return null;\n}\n\n// ============================================================================\n// Route Matching\n// ============================================================================\n\ninterface RouteMatch {\n handler: string;\n params: Record<string, string>;\n}\n\nfunction matchRoute(pathname: string, basePath: string): RouteMatch | null {\n const path = basePath ? pathname.slice(basePath.length) : pathname;\n\n // Health check\n if (path === \"/health\") {\n return { handler: \"health\", params: {} };\n }\n\n // Trigger workflow: POST /trigger/:workflowId\n const triggerMatch = path.match(/^\\/trigger\\/([^/]+)$/);\n if (triggerMatch) {\n return { handler: \"trigger\", params: { workflowId: triggerMatch[1] } };\n }\n\n // Run status: GET /runs/:runId\n const runMatch = path.match(/^\\/runs\\/([^/]+)$/);\n if (runMatch) {\n return { handler: \"run\", params: { runId: runMatch[1] } };\n }\n\n // Run stream: GET /runs/:runId/stream\n const streamMatch = path.match(/^\\/runs\\/([^/]+)\\/stream$/);\n if (streamMatch) {\n return { handler: \"stream\", params: { runId: streamMatch[1] } };\n }\n\n // Notify event: POST /notify/:eventId\n const notifyMatch = path.match(/^\\/notify\\/([^/]+)$/);\n if (notifyMatch) {\n return { handler: \"notify\", params: { eventId: notifyMatch[1] } };\n }\n\n // Client SDK compatibility routes\n // POST /workflows/:workflowId/trigger\n const workflowTriggerMatch = path.match(/^\\/workflows\\/([^/]+)\\/trigger$/);\n if (workflowTriggerMatch) {\n return {\n handler: \"trigger\",\n params: { workflowId: workflowTriggerMatch[1] },\n };\n }\n\n // POST /events/:eventId/notify\n const eventNotifyMatch = path.match(/^\\/events\\/([^/]+)\\/notify$/);\n if (eventNotifyMatch) {\n return { handler: \"notify\", params: { eventId: eventNotifyMatch[1] } };\n }\n\n return null;\n}\n\n// ============================================================================\n// SSE Helpers\n// ============================================================================\n\nfunction createSSEStream(): {\n stream: ReadableStream<Uint8Array>;\n controller: ReadableStreamDefaultController<Uint8Array>;\n encoder: TextEncoder;\n} {\n let controller: ReadableStreamDefaultController<Uint8Array>;\n const encoder = new TextEncoder();\n\n const stream = new ReadableStream<Uint8Array>({\n start(ctrl) {\n controller = ctrl;\n },\n });\n\n return { stream, controller: controller!, encoder };\n}\n\nfunction writeSSE(\n controller: ReadableStreamDefaultController<Uint8Array>,\n encoder: TextEncoder,\n event: string,\n data: unknown,\n): void {\n const message = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n controller.enqueue(encoder.encode(message));\n}\n\n// ============================================================================\n// Handler Factory\n// ============================================================================\n\n/**\n * Create a Cloudflare Workers fetch handler for Stepflow\n *\n * @example\n * ```typescript\n * // src/index.ts\n * import { Stepflow } from '@stepflowjs/core';\n * import { createStepflowHandler } from '@stepflowjs/adapter-cloudflare';\n *\n * const stepflow = new Stepflow({ storage: ... });\n * const handler = createStepflowHandler(stepflow, { basePath: '/api/stepflow' });\n *\n * export default {\n * async fetch(request: Request): Promise<Response> {\n * const response = await handler(request);\n * if (response) return response;\n * return new Response('Not found', { status: 404 });\n * }\n * };\n * ```\n */\nexport function createStepflowHandler(\n stepflow: Stepflow,\n options: HandlerOptions = {},\n): FetchHandler {\n const basePath = normalizeBasePath(options.basePath);\n\n return async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const pathname = url.pathname;\n\n // Check if path matches our basePath\n if (basePath && !pathname.startsWith(basePath)) {\n return jsonError(404, \"Not found\");\n }\n\n const match = matchRoute(pathname, basePath);\n if (!match) {\n return jsonError(404, \"Not found\");\n }\n\n const { handler, params } = match;\n\n // -----------------------------------------------------------------------\n // Health Check - GET /health\n // -----------------------------------------------------------------------\n if (handler === \"health\" && request.method === \"GET\") {\n if (!isRouteEnabled(\"health\", options.endpoints)) {\n return jsonError(404, \"Not found\");\n }\n\n const authError = await checkAuth(request, \"health\", options);\n if (authError) return authError;\n\n try {\n const ok = await (options.healthCheck?.() ?? stepflow.healthCheck());\n return jsonResponse({ ok });\n } catch (error) {\n return jsonError(\n 500,\n \"Internal server error\",\n (error as Error).message,\n );\n }\n }\n\n // -----------------------------------------------------------------------\n // Trigger Workflow - POST /trigger/:workflowId\n // -----------------------------------------------------------------------\n if (handler === \"trigger\" && request.method === \"POST\") {\n if (!isRouteEnabled(\"trigger\", options.endpoints)) {\n return jsonError(404, \"Not found\");\n }\n\n const workflowId = params.workflowId;\n\n const authError = await checkAuth(request, \"trigger\", options, {\n workflowId,\n });\n if (authError) return authError;\n\n try {\n const body = await parseJsonBody<TriggerRequestBody>(request);\n const result = await stepflow.trigger(workflowId, body.payload, {\n runId: body.runId,\n metadata: body.metadata,\n delay: body.delay,\n idempotencyKey: body.idempotencyKey,\n });\n\n const response: TriggerResult = result;\n return jsonResponse(response);\n } catch (error) {\n const message = (error as Error).message;\n if (message.includes(\"Workflow\") && message.includes(\"not found\")) {\n return jsonError(404, \"Not found\", message);\n }\n if (message === \"Invalid JSON body\") {\n return jsonError(400, \"Bad request\", message);\n }\n return jsonError(500, \"Internal server error\", message);\n }\n }\n\n // -----------------------------------------------------------------------\n // Get Run Status - GET /runs/:runId\n // -----------------------------------------------------------------------\n if (handler === \"run\" && request.method === \"GET\") {\n if (!isRouteEnabled(\"runs\", options.endpoints)) {\n return jsonError(404, \"Not found\");\n }\n\n const runId = params.runId;\n\n const authError = await checkAuth(request, \"runs\", options, { runId });\n if (authError) return authError;\n\n try {\n const accessToken = getAccessToken(request);\n const run = await stepflow.getRun(runId, { accessToken });\n\n if (!run) {\n return jsonError(404, \"Not found\", `Run \"${runId}\" not found`);\n }\n\n const response: Execution = run;\n return jsonResponse(response);\n } catch (error) {\n const message = (error as Error).message;\n if (message === \"Invalid access token\") {\n return jsonError(401, \"Unauthorized\", message);\n }\n return jsonError(500, \"Internal server error\", message);\n }\n }\n\n // -----------------------------------------------------------------------\n // Stream Run Updates - GET /runs/:runId/stream\n // -----------------------------------------------------------------------\n if (handler === \"stream\" && request.method === \"GET\") {\n if (!isRouteEnabled(\"runsStream\", options.endpoints)) {\n return jsonError(404, \"Not found\");\n }\n\n const runId = params.runId;\n\n const authError = await checkAuth(request, \"runsStream\", options, {\n runId,\n });\n if (authError) return authError;\n\n // Validate access token if provided\n const accessToken = getAccessToken(request);\n if (accessToken) {\n try {\n await stepflow.getRun(runId, { accessToken });\n } catch (error) {\n const message = (error as Error).message;\n if (message === \"Invalid access token\") {\n return jsonError(401, \"Unauthorized\", message);\n }\n return jsonError(500, \"Internal server error\", message);\n }\n }\n\n // Parse throttle parameter\n const throttleMsParam = url.searchParams.get(\"throttle\");\n const throttleMs = throttleMsParam ? Number(throttleMsParam) : undefined;\n const effectiveThrottleMs =\n throttleMs !== undefined &&\n Number.isFinite(throttleMs) &&\n throttleMs >= 0\n ? throttleMs\n : undefined;\n\n const { stream, controller, encoder } = createSSEStream();\n let lastSentAt = 0;\n\n const send = (event: string, data: unknown) => {\n if (effectiveThrottleMs !== undefined) {\n const now = Date.now();\n if (now - lastSentAt < effectiveThrottleMs) {\n return;\n }\n lastSentAt = now;\n }\n writeSSE(controller, encoder, event, data);\n };\n\n // Start async processing\n void (async () => {\n try {\n // Get initial run state\n let run = await stepflow.getRun(runId);\n\n // Poll until run exists\n while (!run) {\n await new Promise((resolve) => setTimeout(resolve, 250));\n run = await stepflow.getRun(runId);\n }\n\n const executionId = run.id;\n send(\"update\", run);\n\n if (run.status === \"completed\") {\n send(\"execution:complete\", { result: run.result });\n }\n if (run.status === \"failed\") {\n send(\"execution:failed\", { error: run.error });\n }\n\n // Subscribe to updates\n const unsubscribe = stepflow.subscribeToExecution(executionId, () => {\n void (async () => {\n const execution = await stepflow.getExecution(executionId);\n if (execution) {\n send(\"update\", execution);\n\n if (execution.status === \"completed\") {\n send(\"execution:complete\", { result: execution.result });\n }\n if (execution.status === \"failed\") {\n send(\"execution:failed\", { error: execution.error });\n }\n }\n })();\n });\n\n // Keep connection open\n await new Promise((resolve) => setTimeout(resolve, 60 * 60 * 1000));\n unsubscribe();\n } catch {\n // Stream closed\n } finally {\n try {\n controller.close();\n } catch {\n // Already closed\n }\n }\n })();\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n }\n\n // -----------------------------------------------------------------------\n // Notify Event - POST /notify/:eventId\n // -----------------------------------------------------------------------\n if (handler === \"notify\" && request.method === \"POST\") {\n if (!isRouteEnabled(\"notify\", options.endpoints)) {\n return jsonError(404, \"Not found\");\n }\n\n const eventId = params.eventId;\n\n const authError = await checkAuth(request, \"notify\", options, {\n eventId,\n });\n if (authError) return authError;\n\n try {\n const body = await parseJsonBody<NotifyRequestBody>(request);\n const result = await stepflow.notify(eventId, body.data);\n const response: NotifyResult = result;\n return jsonResponse(response);\n } catch (error) {\n const message = (error as Error).message;\n if (message === \"Invalid JSON body\") {\n return jsonError(400, \"Bad request\", message);\n }\n return jsonError(500, \"Internal server error\", message);\n }\n }\n\n // Method not allowed for matched route\n return jsonError(405, \"Method not allowed\");\n };\n}\n\n// Re-export types\nexport type { Execution, TriggerResult, NotifyResult } from \"@stepflowjs/core\";\n"],"mappings":"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","names":["isRouteEnabled"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stepflowjs/adapter-cloudflare",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Cloudflare Workers adapter for Stepflow workflows",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@stepflowjs/core": "0.0.1",
|
|
20
|
+
"@stepflowjs/adapter-shared": "0.0.1"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@cloudflare/workers-types": "^4.20250610.0",
|
|
24
|
+
"tsup": "^8.5.1",
|
|
25
|
+
"vitest": "^4.0.17"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"typescript": "^5.0.0"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"author": "Stepflow Contributors",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://stepflow-production.up.railway.app",
|
|
35
|
+
"directory": "packages/adapters/cloudflare"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://stepflow-production.up.railway.app",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://stepflow-production.up.railway.app"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"stepflow",
|
|
43
|
+
"adapter",
|
|
44
|
+
"cloudflare",
|
|
45
|
+
"workers",
|
|
46
|
+
"workflow",
|
|
47
|
+
"orchestration"
|
|
48
|
+
],
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsup",
|
|
54
|
+
"dev": "tsup --watch",
|
|
55
|
+
"typecheck": "tsc --noEmit",
|
|
56
|
+
"test": "vitest",
|
|
57
|
+
"clean": "rm -rf dist"
|
|
58
|
+
}
|
|
59
|
+
}
|