@stepflowjs/adapter-fastify 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.
@@ -0,0 +1,52 @@
1
+ import * as fastify from 'fastify';
2
+ import { FastifyRequest as FastifyRequest$1, FastifyPluginAsync } from 'fastify';
3
+ import { Stepflow } from '@stepflowjs/core';
4
+ import { AuthContext, AuthConfig, EndpointOption, BaseAdapterOptions } from '@stepflowjs/adapter-shared';
5
+ export { AuthConfig, AuthContext, AuthHandler, AuthResult, EndpointConfig, EndpointOption, EndpointPreset, RouteName, allOf, anyOf, createApiKeyAuth, createBearerAuth, isRouteEnabled, resolveEndpoints } from '@stepflowjs/adapter-shared';
6
+
7
+ /** Fastify-specific request type for auth handlers */
8
+ type FastifyRequest = {
9
+ header(name: string): string | undefined;
10
+ headers: Record<string, string | string[] | undefined>;
11
+ url: string;
12
+ method: string;
13
+ query(name: string): string | undefined;
14
+ };
15
+ /** Fastify-specific auth context */
16
+ type FastifyAuthContext = AuthContext<FastifyRequest, FastifyRequest$1>;
17
+ /** Fastify-specific auth config */
18
+ type FastifyAuthConfig = AuthConfig<FastifyRequest, FastifyRequest$1>;
19
+ interface RouteOptions {
20
+ /** Prefix all routes under this base path (e.g. "/api/stepflow"). */
21
+ basePath?: string;
22
+ /** Custom health check function. Defaults to stepflow.healthCheck(). */
23
+ healthCheck?: () => Promise<boolean>;
24
+ /** Endpoint configuration - preset or fine-grained */
25
+ endpoints?: EndpointOption;
26
+ /** Authorization configuration */
27
+ auth?: FastifyAuthConfig;
28
+ /** Callback when authorization fails */
29
+ onAuthFailure?: BaseAdapterOptions<FastifyRequest, FastifyRequest$1>["onAuthFailure"];
30
+ }
31
+ interface StepflowPluginOptions extends RouteOptions {
32
+ stepflow: Stepflow;
33
+ }
34
+ interface TriggerRequestBody<TPayload = unknown> {
35
+ payload: TPayload;
36
+ metadata?: Record<string, unknown>;
37
+ runId?: string;
38
+ delay?: number;
39
+ idempotencyKey?: string;
40
+ }
41
+ interface NotifyRequestBody {
42
+ data: unknown;
43
+ }
44
+ interface ErrorResponseBody {
45
+ error: string;
46
+ message?: string;
47
+ }
48
+
49
+ declare function createStepflowRoutes(stepflow: Stepflow, options?: RouteOptions): FastifyPluginAsync;
50
+ declare const stepflowPlugin: fastify.FastifyPluginCallback<StepflowPluginOptions, fastify.RawServerDefault, fastify.FastifyTypeProviderDefault, fastify.FastifyBaseLogger>;
51
+
52
+ export { type ErrorResponseBody, type FastifyAuthConfig, type FastifyAuthContext, type FastifyRequest, type NotifyRequestBody, type RouteOptions, type StepflowPluginOptions, type TriggerRequestBody, createStepflowRoutes, stepflowPlugin };
package/dist/index.js ADDED
@@ -0,0 +1,561 @@
1
+ // src/index.ts
2
+ import {
3
+ isRouteEnabled,
4
+ runAuth,
5
+ getAuthFailureResponse,
6
+ createErrorBody
7
+ } from "@stepflowjs/adapter-shared";
8
+ import fp from "fastify-plugin";
9
+ import {
10
+ createApiKeyAuth,
11
+ createBearerAuth,
12
+ anyOf,
13
+ allOf,
14
+ isRouteEnabled as isRouteEnabled2,
15
+ resolveEndpoints
16
+ } from "@stepflowjs/adapter-shared";
17
+ function normalizeBasePath(basePath) {
18
+ if (!basePath) return "";
19
+ if (basePath === "/") return "";
20
+ return basePath.startsWith("/") ? basePath.replace(/\/$/, "") : `/${basePath}`;
21
+ }
22
+ function getQueryStringValue(request, key) {
23
+ const query = request.query;
24
+ if (typeof query !== "object" || query === null) return void 0;
25
+ if (!(key in query)) return void 0;
26
+ const value = query[key];
27
+ if (typeof value === "string" && value.length > 0) return value;
28
+ return void 0;
29
+ }
30
+ function getAccessToken(request) {
31
+ const queryToken = getQueryStringValue(request, "token");
32
+ if (queryToken) return queryToken;
33
+ const authHeader = request.headers["authorization"] ?? request.headers["Authorization"];
34
+ if (typeof authHeader !== "string") return void 0;
35
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
36
+ return match?.[1];
37
+ }
38
+ function parseThrottleMs(request) {
39
+ const value = getQueryStringValue(request, "throttle");
40
+ if (!value) return void 0;
41
+ const ms = Number(value);
42
+ if (!Number.isFinite(ms) || ms < 0) return void 0;
43
+ return ms;
44
+ }
45
+ function jsonError(reply, status, error, message) {
46
+ const body = message ? { error, message } : { error };
47
+ reply.code(status).send(body);
48
+ }
49
+ function jsonAuthError(reply, status, code, message) {
50
+ const body = createErrorBody(code, message);
51
+ reply.code(status).send(body);
52
+ }
53
+ function getErrorMessage(error) {
54
+ if (error instanceof Error) return error.message;
55
+ return String(error);
56
+ }
57
+ function getErrorStatusCode(error) {
58
+ if (typeof error !== "object" || error === null) return void 0;
59
+ if (!("statusCode" in error)) return void 0;
60
+ const statusCode = error.statusCode;
61
+ if (typeof statusCode === "number") return statusCode;
62
+ return void 0;
63
+ }
64
+ function getErrorCode(error) {
65
+ if (typeof error !== "object" || error === null) return void 0;
66
+ if (!("code" in error)) return void 0;
67
+ const code = error.code;
68
+ if (typeof code === "string") return code;
69
+ return void 0;
70
+ }
71
+ function registerErrorHandler(fastify) {
72
+ fastify.setErrorHandler((error, _request, reply) => {
73
+ if (reply.sent) return;
74
+ const statusCode = getErrorStatusCode(error);
75
+ const code = getErrorCode(error);
76
+ if (statusCode === 400 && (error instanceof SyntaxError || code === "FST_ERR_CTP_INVALID_JSON_BODY")) {
77
+ jsonError(reply, 400, "Bad request", "Invalid JSON body");
78
+ return;
79
+ }
80
+ jsonError(
81
+ reply,
82
+ statusCode && statusCode >= 400 && statusCode <= 599 ? statusCode : 500,
83
+ "Internal server error",
84
+ getErrorMessage(error)
85
+ );
86
+ });
87
+ }
88
+ function createFastifyRequest(request) {
89
+ return {
90
+ header: (name) => {
91
+ const value = request.headers[name.toLowerCase()];
92
+ return Array.isArray(value) ? value[0] : value;
93
+ },
94
+ headers: request.headers,
95
+ url: request.url,
96
+ method: request.method,
97
+ query: (name) => getQueryStringValue(request, name)
98
+ };
99
+ }
100
+ async function checkAuth(request, reply, route, options, params = {}) {
101
+ const ctx = {
102
+ route,
103
+ request: createFastifyRequest(request),
104
+ extra: request,
105
+ ...params
106
+ };
107
+ const result = await runAuth(ctx, options.auth);
108
+ if (!result.ok) {
109
+ const { status, code, message } = getAuthFailureResponse(result);
110
+ await options.onAuthFailure?.(ctx, result);
111
+ jsonAuthError(reply, status, code, message);
112
+ return false;
113
+ }
114
+ return true;
115
+ }
116
+ function createStepflowRoutes(stepflow, options = {}) {
117
+ return async (fastify) => {
118
+ const basePath = normalizeBasePath(options.basePath);
119
+ registerErrorHandler(fastify);
120
+ if (isRouteEnabled("health", options.endpoints)) {
121
+ fastify.get(`${basePath}/health`, async (request, reply) => {
122
+ const authorized = await checkAuth(request, reply, "health", options);
123
+ if (!authorized) return;
124
+ try {
125
+ const ok = await (options.healthCheck?.() ?? stepflow.healthCheck());
126
+ reply.code(200).send({ ok });
127
+ } catch (error) {
128
+ jsonError(
129
+ reply,
130
+ 500,
131
+ "Internal server error",
132
+ getErrorMessage(error)
133
+ );
134
+ }
135
+ });
136
+ }
137
+ if (isRouteEnabled("trigger", options.endpoints)) {
138
+ fastify.post(`${basePath}/trigger/:workflowId`, async (request, reply) => {
139
+ const workflowId = request.params.workflowId;
140
+ const authorized = await checkAuth(request, reply, "trigger", options, {
141
+ workflowId
142
+ });
143
+ if (!authorized) return;
144
+ try {
145
+ const body = request.body;
146
+ if (!body || typeof body !== "object") {
147
+ jsonError(reply, 400, "Bad request", "Invalid JSON body");
148
+ return;
149
+ }
150
+ const result = await stepflow.trigger(workflowId, body.payload, {
151
+ runId: body.runId,
152
+ metadata: body.metadata,
153
+ delay: body.delay,
154
+ idempotencyKey: body.idempotencyKey
155
+ });
156
+ const response = result;
157
+ reply.code(200).send(response);
158
+ } catch (error) {
159
+ const message = getErrorMessage(error);
160
+ if (message.includes("Workflow") && message.includes("not found")) {
161
+ jsonError(reply, 404, "Not found", message);
162
+ return;
163
+ }
164
+ jsonError(reply, 500, "Internal server error", message);
165
+ }
166
+ });
167
+ }
168
+ if (isRouteEnabled("runs", options.endpoints)) {
169
+ fastify.get(
170
+ `${basePath}/runs/:runId`,
171
+ async (request, reply) => {
172
+ const runId = request.params.runId;
173
+ const authorized = await checkAuth(request, reply, "runs", options, {
174
+ runId
175
+ });
176
+ if (!authorized) return;
177
+ try {
178
+ const accessToken = getAccessToken(request);
179
+ const run = await stepflow.getRun(runId, { accessToken });
180
+ if (!run) {
181
+ jsonError(reply, 404, "Not found", `Run "${runId}" not found`);
182
+ return;
183
+ }
184
+ const response = run;
185
+ reply.code(200).send(response);
186
+ } catch (error) {
187
+ const message = getErrorMessage(error);
188
+ if (message === "Invalid access token") {
189
+ jsonError(reply, 401, "Unauthorized", message);
190
+ return;
191
+ }
192
+ jsonError(reply, 500, "Internal server error", message);
193
+ }
194
+ }
195
+ );
196
+ }
197
+ if (isRouteEnabled("runsStream", options.endpoints)) {
198
+ fastify.get(
199
+ `${basePath}/runs/:runId/stream`,
200
+ async (request, reply) => {
201
+ const runId = request.params.runId;
202
+ const authorized = await checkAuth(
203
+ request,
204
+ reply,
205
+ "runsStream",
206
+ options,
207
+ {
208
+ runId
209
+ }
210
+ );
211
+ if (!authorized) return;
212
+ const accessToken = getAccessToken(request);
213
+ if (accessToken) {
214
+ try {
215
+ await stepflow.getRun(runId, { accessToken });
216
+ } catch (error) {
217
+ const message = getErrorMessage(error);
218
+ if (message === "Invalid access token") {
219
+ jsonError(reply, 401, "Unauthorized", message);
220
+ return;
221
+ }
222
+ jsonError(reply, 500, "Internal server error", message);
223
+ return;
224
+ }
225
+ }
226
+ const throttleMs = parseThrottleMs(request);
227
+ reply.raw.writeHead(200, {
228
+ "Content-Type": "text/event-stream",
229
+ "Cache-Control": "no-cache",
230
+ Connection: "keep-alive",
231
+ "X-Accel-Buffering": "no"
232
+ });
233
+ reply.raw.write(`: connected
234
+
235
+ `);
236
+ reply.hijack();
237
+ let lastSentAt = 0;
238
+ let executionId;
239
+ let unsubscribeExecution;
240
+ let closed = false;
241
+ const send = (type, data) => {
242
+ if (closed) return;
243
+ if (throttleMs !== void 0) {
244
+ const now = Date.now();
245
+ if (now - lastSentAt < throttleMs) {
246
+ return;
247
+ }
248
+ lastSentAt = now;
249
+ }
250
+ reply.raw.write(`event: ${type}
251
+ `);
252
+ reply.raw.write(`data: ${JSON.stringify(data)}
253
+
254
+ `);
255
+ };
256
+ const stop = () => {
257
+ if (closed) return;
258
+ closed = true;
259
+ unsubscribeExecution?.();
260
+ reply.raw.end();
261
+ };
262
+ request.raw.on("close", stop);
263
+ const publishCurrentExecution = async () => {
264
+ const current = await stepflow.getRun(runId);
265
+ if (!current) return;
266
+ executionId = current.id;
267
+ send("update", current);
268
+ if (current.status === "completed") {
269
+ send("execution:complete", { result: current.result });
270
+ }
271
+ if (current.status === "failed") {
272
+ send("execution:failed", { error: current.error });
273
+ }
274
+ };
275
+ const handleExecutionEvent = (event) => {
276
+ void (async () => {
277
+ if (!executionId || closed) return;
278
+ const execution = await stepflow.getExecution(executionId);
279
+ if (execution) {
280
+ send("update", execution);
281
+ if (execution.status === "completed") {
282
+ send("execution:complete", { result: execution.result });
283
+ }
284
+ if (execution.status === "failed") {
285
+ send("execution:failed", { error: execution.error });
286
+ }
287
+ if (typeof event === "object" && event !== null && "type" in event && "stepName" in event && typeof event.type === "string" && typeof event.stepName === "string") {
288
+ const type = event.type;
289
+ const stepName = event.stepName;
290
+ if (type === "step:complete") {
291
+ const step = execution.steps.find(
292
+ (s) => s.name === stepName
293
+ );
294
+ if (step) send("step:complete", step);
295
+ }
296
+ if (type === "step:failed") {
297
+ const step = execution.steps.find(
298
+ (s) => s.name === stepName
299
+ );
300
+ if (step) send("step:failed", step);
301
+ }
302
+ }
303
+ }
304
+ })();
305
+ };
306
+ void (async () => {
307
+ try {
308
+ await publishCurrentExecution();
309
+ while (!closed && !executionId) {
310
+ await new Promise((r) => setTimeout(r, 250));
311
+ await publishCurrentExecution();
312
+ }
313
+ if (!executionId || closed) return;
314
+ unsubscribeExecution = stepflow.subscribeToExecution(
315
+ executionId,
316
+ handleExecutionEvent
317
+ );
318
+ } catch (error) {
319
+ if (!closed) {
320
+ send("error", {
321
+ error: "Internal server error",
322
+ message: getErrorMessage(error)
323
+ });
324
+ stop();
325
+ }
326
+ }
327
+ })();
328
+ }
329
+ );
330
+ }
331
+ if (isRouteEnabled("notify", options.endpoints)) {
332
+ fastify.post(
333
+ `${basePath}/notify/:eventId`,
334
+ async (request, reply) => {
335
+ const eventId = request.params.eventId;
336
+ const authorized = await checkAuth(
337
+ request,
338
+ reply,
339
+ "notify",
340
+ options,
341
+ {
342
+ eventId
343
+ }
344
+ );
345
+ if (!authorized) return;
346
+ try {
347
+ const body = request.body;
348
+ if (!body || typeof body !== "object") {
349
+ jsonError(reply, 400, "Bad request", "Invalid JSON body");
350
+ return;
351
+ }
352
+ const result = await stepflow.notify(eventId, body.data);
353
+ const response = result;
354
+ reply.code(200).send(response);
355
+ } catch (error) {
356
+ jsonError(
357
+ reply,
358
+ 500,
359
+ "Internal server error",
360
+ getErrorMessage(error)
361
+ );
362
+ }
363
+ }
364
+ );
365
+ }
366
+ if (isRouteEnabled("workflowsTrigger", options.endpoints)) {
367
+ fastify.post(
368
+ `${basePath}/workflows/:workflowId/trigger`,
369
+ async (request, reply) => {
370
+ const workflowId = request.params.workflowId;
371
+ const authorized = await checkAuth(
372
+ request,
373
+ reply,
374
+ "workflowsTrigger",
375
+ options,
376
+ { workflowId }
377
+ );
378
+ if (!authorized) return;
379
+ try {
380
+ const body = request.body;
381
+ if (!body || typeof body !== "object") {
382
+ jsonError(reply, 400, "Bad request", "Invalid JSON body");
383
+ return;
384
+ }
385
+ const result = await stepflow.trigger(workflowId, body.payload, {
386
+ runId: body.runId,
387
+ metadata: body.metadata,
388
+ delay: body.delay,
389
+ idempotencyKey: body.idempotencyKey
390
+ });
391
+ const response = result;
392
+ reply.code(200).send(response);
393
+ } catch (error) {
394
+ const message = getErrorMessage(error);
395
+ if (message.includes("Workflow") && message.includes("not found")) {
396
+ jsonError(reply, 404, "Not found", message);
397
+ return;
398
+ }
399
+ jsonError(reply, 500, "Internal server error", message);
400
+ }
401
+ }
402
+ );
403
+ }
404
+ if (isRouteEnabled("eventsNotify", options.endpoints)) {
405
+ fastify.post(
406
+ `${basePath}/events/:eventId/notify`,
407
+ async (request, reply) => {
408
+ const eventId = request.params.eventId;
409
+ const authorized = await checkAuth(
410
+ request,
411
+ reply,
412
+ "eventsNotify",
413
+ options,
414
+ { eventId }
415
+ );
416
+ if (!authorized) return;
417
+ try {
418
+ const body = request.body;
419
+ if (!body || typeof body !== "object") {
420
+ jsonError(reply, 400, "Bad request", "Invalid JSON body");
421
+ return;
422
+ }
423
+ const result = await stepflow.notify(eventId, body.data);
424
+ const response = result;
425
+ reply.code(200).send(response);
426
+ } catch (error) {
427
+ jsonError(
428
+ reply,
429
+ 500,
430
+ "Internal server error",
431
+ getErrorMessage(error)
432
+ );
433
+ }
434
+ }
435
+ );
436
+ }
437
+ if (isRouteEnabled("workflowsStream", options.endpoints)) {
438
+ fastify.post(`${basePath}/workflows/:workflowId/stream`, async (request, reply) => {
439
+ const workflowId = request.params.workflowId;
440
+ const authorized = await checkAuth(
441
+ request,
442
+ reply,
443
+ "workflowsStream",
444
+ options,
445
+ { workflowId }
446
+ );
447
+ if (!authorized) return;
448
+ try {
449
+ const body = request.body;
450
+ if (!body || typeof body !== "object") {
451
+ jsonError(reply, 400, "Bad request", "Invalid JSON body");
452
+ return;
453
+ }
454
+ const { runId, publicAccessToken } = await stepflow.trigger(
455
+ workflowId,
456
+ body.payload
457
+ );
458
+ reply.raw.writeHead(200, {
459
+ "Content-Type": "text/event-stream",
460
+ "Cache-Control": "no-cache",
461
+ Connection: "keep-alive",
462
+ "X-Accel-Buffering": "no"
463
+ });
464
+ reply.hijack();
465
+ let closed = false;
466
+ const send = (type, data) => {
467
+ if (closed) return;
468
+ reply.raw.write(`event: ${type}
469
+ `);
470
+ reply.raw.write(`data: ${JSON.stringify(data)}
471
+
472
+ `);
473
+ };
474
+ const stop = () => {
475
+ if (closed) return;
476
+ closed = true;
477
+ reply.raw.end();
478
+ };
479
+ request.raw.on("close", stop);
480
+ void (async () => {
481
+ try {
482
+ send("trigger", { runId, accessToken: publicAccessToken });
483
+ let executionId;
484
+ while (!closed && !executionId) {
485
+ const run = await stepflow.getRun(runId);
486
+ executionId = run?.id;
487
+ if (!executionId) {
488
+ await new Promise((r) => setTimeout(r, 100));
489
+ }
490
+ }
491
+ if (!executionId || closed) return;
492
+ const unsubscribe = stepflow.subscribeToExecution(
493
+ executionId,
494
+ () => {
495
+ void (async () => {
496
+ if (closed) return;
497
+ const execution = await stepflow.getExecution(executionId);
498
+ if (execution) {
499
+ send("update", execution);
500
+ }
501
+ })();
502
+ }
503
+ );
504
+ await new Promise((resolve) => {
505
+ const timeout = setTimeout(resolve, 60 * 60 * 1e3);
506
+ request.raw.on("close", () => {
507
+ clearTimeout(timeout);
508
+ resolve(void 0);
509
+ });
510
+ });
511
+ unsubscribe();
512
+ } catch (error) {
513
+ if (!closed) {
514
+ send("error", {
515
+ error: "Internal server error",
516
+ message: getErrorMessage(error)
517
+ });
518
+ stop();
519
+ }
520
+ }
521
+ })();
522
+ } catch (error) {
523
+ const message = getErrorMessage(error);
524
+ if (message.includes("Workflow") && message.includes("not found")) {
525
+ jsonError(reply, 404, "Not found", message);
526
+ return;
527
+ }
528
+ jsonError(reply, 500, "Internal server error", message);
529
+ }
530
+ });
531
+ }
532
+ };
533
+ }
534
+ var stepflowPlugin = fp(
535
+ async (fastify, options) => {
536
+ const { stepflow, basePath, healthCheck, endpoints, auth, onAuthFailure } = options;
537
+ await fastify.register(
538
+ createStepflowRoutes(stepflow, {
539
+ basePath,
540
+ healthCheck,
541
+ endpoints,
542
+ auth,
543
+ onAuthFailure
544
+ })
545
+ );
546
+ },
547
+ {
548
+ name: "@stepflowjs/adapter-fastify"
549
+ }
550
+ );
551
+ export {
552
+ allOf,
553
+ anyOf,
554
+ createApiKeyAuth,
555
+ createBearerAuth,
556
+ createStepflowRoutes,
557
+ isRouteEnabled2 as isRouteEnabled,
558
+ resolveEndpoints,
559
+ stepflowPlugin
560
+ };
561
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Execution, NotifyResult, TriggerResult } 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\";\nimport fp from \"fastify-plugin\";\nimport type {\n FastifyInstance,\n FastifyPluginAsync,\n FastifyReply,\n FastifyRequest as FastifyRequestType,\n} from \"fastify\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Fastify-specific request type for auth handlers */\nexport type FastifyRequest = {\n header(name: string): string | undefined;\n headers: Record<string, string | string[] | undefined>;\n url: string;\n method: string;\n query(name: string): string | undefined;\n};\n\n/** Fastify-specific auth context */\nexport type FastifyAuthContext = AuthContext<\n FastifyRequest,\n FastifyRequestType\n>;\n\n/** Fastify-specific auth config */\nexport type FastifyAuthConfig = AuthConfig<FastifyRequest, FastifyRequestType>;\n\nexport interface RouteOptions {\n /** Prefix all routes under this base path (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?: FastifyAuthConfig;\n /** Callback when authorization fails */\n onAuthFailure?: BaseAdapterOptions<\n FastifyRequest,\n FastifyRequestType\n >[\"onAuthFailure\"];\n}\n\nexport interface StepflowPluginOptions extends RouteOptions {\n stepflow: Stepflow;\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\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 getQueryStringValue(\n request: FastifyRequestType,\n key: string,\n): string | undefined {\n const query = request.query;\n if (typeof query !== \"object\" || query === null) return undefined;\n\n if (!(key in query)) return undefined;\n const value = (query as Record<string, unknown>)[key];\n if (typeof value === \"string\" && value.length > 0) return value;\n return undefined;\n}\n\nfunction getAccessToken(request: FastifyRequestType): string | undefined {\n const queryToken = getQueryStringValue(request, \"token\");\n if (queryToken) return queryToken;\n\n const authHeader =\n request.headers[\"authorization\"] ?? request.headers[\"Authorization\"];\n if (typeof authHeader !== \"string\") return undefined;\n\n const match = authHeader.match(/^Bearer\\s+(.+)$/i);\n return match?.[1];\n}\n\nfunction parseThrottleMs(request: FastifyRequestType): number | undefined {\n const value = getQueryStringValue(request, \"throttle\");\n if (!value) return undefined;\n const ms = Number(value);\n if (!Number.isFinite(ms) || ms < 0) return undefined;\n return ms;\n}\n\nfunction jsonError(\n reply: FastifyReply,\n status: number,\n error: string,\n message?: string,\n): void {\n const body: ErrorResponseBody = message ? { error, message } : { error };\n reply.code(status).send(body);\n}\n\nfunction jsonAuthError(\n reply: FastifyReply,\n status: number,\n code: string,\n message: string,\n): void {\n const body = createErrorBody(code, message);\n reply.code(status).send(body);\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\nfunction getErrorStatusCode(error: unknown): number | undefined {\n if (typeof error !== \"object\" || error === null) return undefined;\n if (!(\"statusCode\" in error)) return undefined;\n\n const statusCode = (error as { statusCode?: unknown }).statusCode;\n if (typeof statusCode === \"number\") return statusCode;\n return undefined;\n}\n\nfunction getErrorCode(error: unknown): string | undefined {\n if (typeof error !== \"object\" || error === null) return undefined;\n if (!(\"code\" in error)) return undefined;\n\n const code = (error as { code?: unknown }).code;\n if (typeof code === \"string\") return code;\n return undefined;\n}\n\nfunction registerErrorHandler(fastify: FastifyInstance): void {\n fastify.setErrorHandler((error, _request, reply) => {\n if (reply.sent) return;\n\n const statusCode = getErrorStatusCode(error);\n const code = getErrorCode(error);\n\n if (\n statusCode === 400 &&\n (error instanceof SyntaxError || code === \"FST_ERR_CTP_INVALID_JSON_BODY\")\n ) {\n jsonError(reply, 400, \"Bad request\", \"Invalid JSON body\");\n return;\n }\n\n jsonError(\n reply,\n statusCode && statusCode >= 400 && statusCode <= 599 ? statusCode : 500,\n \"Internal server error\",\n getErrorMessage(error),\n );\n });\n}\n\n/**\n * Creates a FastifyRequest object from Fastify request for auth handlers\n */\nfunction createFastifyRequest(request: FastifyRequestType): FastifyRequest {\n return {\n header: (name: string) => {\n const value = request.headers[name.toLowerCase()];\n return Array.isArray(value) ? value[0] : value;\n },\n headers: request.headers as Record<string, string | string[] | undefined>,\n url: request.url,\n method: request.method,\n query: (name: string) => getQueryStringValue(request, name),\n };\n}\n\n/**\n * Runs authorization check and returns error response if denied\n */\nasync function checkAuth(\n request: FastifyRequestType,\n reply: FastifyReply,\n route: RouteName,\n options: RouteOptions,\n params: { workflowId?: string; eventId?: string; runId?: string } = {},\n): Promise<boolean> {\n const ctx: FastifyAuthContext = {\n route,\n request: createFastifyRequest(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 jsonAuthError(reply, status, code, message);\n return false;\n }\n\n return true;\n}\n\n// ============================================================================\n// Routes\n// ============================================================================\n\nexport function createStepflowRoutes(\n stepflow: Stepflow,\n options: RouteOptions = {},\n): FastifyPluginAsync {\n return async (fastify: FastifyInstance) => {\n const basePath = normalizeBasePath(options.basePath);\n\n registerErrorHandler(fastify);\n\n // Health check\n if (isRouteEnabled(\"health\", options.endpoints)) {\n fastify.get(`${basePath}/health`, async (request, reply) => {\n const authorized = await checkAuth(request, reply, \"health\", options);\n if (!authorized) return;\n\n try {\n const ok = await (options.healthCheck?.() ?? stepflow.healthCheck());\n reply.code(200).send({ ok });\n } catch (error) {\n jsonError(\n reply,\n 500,\n \"Internal server error\",\n getErrorMessage(error),\n );\n }\n });\n }\n\n // Trigger a workflow\n if (isRouteEnabled(\"trigger\", options.endpoints)) {\n fastify.post<{\n Params: { workflowId: string };\n Body: TriggerRequestBody;\n }>(`${basePath}/trigger/:workflowId`, async (request, reply) => {\n const workflowId = request.params.workflowId;\n\n const authorized = await checkAuth(request, reply, \"trigger\", options, {\n workflowId,\n });\n if (!authorized) return;\n\n try {\n const body = request.body;\n if (!body || typeof body !== \"object\") {\n jsonError(reply, 400, \"Bad request\", \"Invalid JSON body\");\n return;\n }\n\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 reply.code(200).send(response);\n } catch (error) {\n const message = getErrorMessage(error);\n if (message.includes(\"Workflow\") && message.includes(\"not found\")) {\n jsonError(reply, 404, \"Not found\", message);\n return;\n }\n jsonError(reply, 500, \"Internal server error\", message);\n }\n });\n }\n\n // Get run status\n if (isRouteEnabled(\"runs\", options.endpoints)) {\n fastify.get<{ Params: { runId: string } }>(\n `${basePath}/runs/:runId`,\n async (request, reply) => {\n const runId = request.params.runId;\n\n const authorized = await checkAuth(request, reply, \"runs\", options, {\n runId,\n });\n if (!authorized) return;\n\n try {\n const accessToken = getAccessToken(request);\n const run = await stepflow.getRun(runId, { accessToken });\n\n if (!run) {\n jsonError(reply, 404, \"Not found\", `Run \"${runId}\" not found`);\n return;\n }\n\n const response: Execution = run;\n reply.code(200).send(response);\n } catch (error) {\n const message = getErrorMessage(error);\n if (message === \"Invalid access token\") {\n jsonError(reply, 401, \"Unauthorized\", message);\n return;\n }\n jsonError(reply, 500, \"Internal server error\", message);\n }\n },\n );\n }\n\n // SSE stream for run updates\n if (isRouteEnabled(\"runsStream\", options.endpoints)) {\n fastify.get<{ Params: { runId: string } }>(\n `${basePath}/runs/:runId/stream`,\n async (request, reply) => {\n const runId = request.params.runId;\n\n const authorized = await checkAuth(\n request,\n reply,\n \"runsStream\",\n options,\n {\n runId,\n },\n );\n if (!authorized) return;\n\n const accessToken = getAccessToken(request);\n if (accessToken) {\n try {\n await stepflow.getRun(runId, { accessToken });\n } catch (error) {\n const message = getErrorMessage(error);\n if (message === \"Invalid access token\") {\n jsonError(reply, 401, \"Unauthorized\", message);\n return;\n }\n jsonError(reply, 500, \"Internal server error\", message);\n return;\n }\n }\n\n const throttleMs = parseThrottleMs(request);\n\n reply.raw.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"X-Accel-Buffering\": \"no\",\n });\n\n // Ensure the client receives an initial chunk immediately.\n reply.raw.write(`: connected\\n\\n`);\n\n reply.hijack();\n\n let lastSentAt = 0;\n let executionId: string | undefined;\n let unsubscribeExecution: (() => void) | undefined;\n let closed = false;\n\n const send = (type: string, data: unknown) => {\n if (closed) return;\n\n if (throttleMs !== undefined) {\n const now = Date.now();\n if (now - lastSentAt < throttleMs) {\n return;\n }\n lastSentAt = now;\n }\n\n reply.raw.write(`event: ${type}\\n`);\n reply.raw.write(`data: ${JSON.stringify(data)}\\n\\n`);\n };\n\n const stop = () => {\n if (closed) return;\n closed = true;\n unsubscribeExecution?.();\n reply.raw.end();\n };\n\n request.raw.on(\"close\", stop);\n\n const publishCurrentExecution = async () => {\n const current = await stepflow.getRun(runId);\n if (!current) return;\n\n executionId = current.id;\n send(\"update\", current);\n\n if (current.status === \"completed\") {\n send(\"execution:complete\", { result: current.result });\n }\n if (current.status === \"failed\") {\n send(\"execution:failed\", { error: current.error });\n }\n };\n\n const handleExecutionEvent = (event: unknown) => {\n // We cannot await inside the realtime callback.\n void (async () => {\n if (!executionId || closed) return;\n\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 if (\n typeof event === \"object\" &&\n event !== null &&\n \"type\" in event &&\n \"stepName\" in event &&\n typeof (event as { type: unknown }).type === \"string\" &&\n typeof (event as { stepName: unknown }).stepName === \"string\"\n ) {\n const type = (event as { type: string }).type;\n const stepName = (event as { stepName: string }).stepName;\n\n if (type === \"step:complete\") {\n const step = execution.steps.find(\n (s: { name: string }) => s.name === stepName,\n );\n if (step) send(\"step:complete\", step);\n }\n if (type === \"step:failed\") {\n const step = execution.steps.find(\n (s: { name: string }) => s.name === stepName,\n );\n if (step) send(\"step:failed\", step);\n }\n }\n }\n })();\n };\n\n void (async () => {\n try {\n await publishCurrentExecution();\n\n // If the run doesn't exist yet, poll until it does.\n while (!closed && !executionId) {\n await new Promise((r) => setTimeout(r, 250));\n await publishCurrentExecution();\n }\n\n if (!executionId || closed) return;\n\n unsubscribeExecution = stepflow.subscribeToExecution(\n executionId,\n handleExecutionEvent,\n );\n } catch (error) {\n if (!closed) {\n send(\"error\", {\n error: \"Internal server error\",\n message: getErrorMessage(error),\n });\n stop();\n }\n }\n })();\n },\n );\n }\n\n // Notify an event\n if (isRouteEnabled(\"notify\", options.endpoints)) {\n fastify.post<{ Params: { eventId: string }; Body: NotifyRequestBody }>(\n `${basePath}/notify/:eventId`,\n async (request, reply) => {\n const eventId = request.params.eventId;\n\n const authorized = await checkAuth(\n request,\n reply,\n \"notify\",\n options,\n {\n eventId,\n },\n );\n if (!authorized) return;\n\n try {\n const body = request.body;\n if (!body || typeof body !== \"object\") {\n jsonError(reply, 400, \"Bad request\", \"Invalid JSON body\");\n return;\n }\n\n const result = await stepflow.notify(eventId, body.data);\n const response: NotifyResult = result;\n reply.code(200).send(response);\n } catch (error) {\n jsonError(\n reply,\n 500,\n \"Internal server error\",\n getErrorMessage(error),\n );\n }\n },\n );\n }\n\n // Alias routes for StepflowClient (client-ts) conventions\n\n if (isRouteEnabled(\"workflowsTrigger\", options.endpoints)) {\n fastify.post<{\n Params: { workflowId: string };\n Body: {\n payload: unknown;\n metadata?: Record<string, unknown>;\n runId?: string;\n delay?: number;\n idempotencyKey?: string;\n };\n }>(\n `${basePath}/workflows/:workflowId/trigger`,\n async (request, reply) => {\n const workflowId = request.params.workflowId;\n\n const authorized = await checkAuth(\n request,\n reply,\n \"workflowsTrigger\",\n options,\n { workflowId },\n );\n if (!authorized) return;\n\n try {\n const body = request.body;\n if (!body || typeof body !== \"object\") {\n jsonError(reply, 400, \"Bad request\", \"Invalid JSON body\");\n return;\n }\n\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 reply.code(200).send(response);\n } catch (error) {\n const message = getErrorMessage(error);\n if (message.includes(\"Workflow\") && message.includes(\"not found\")) {\n jsonError(reply, 404, \"Not found\", message);\n return;\n }\n jsonError(reply, 500, \"Internal server error\", message);\n }\n },\n );\n }\n\n if (isRouteEnabled(\"eventsNotify\", options.endpoints)) {\n fastify.post<{ Params: { eventId: string }; Body: NotifyRequestBody }>(\n `${basePath}/events/:eventId/notify`,\n async (request, reply) => {\n const eventId = request.params.eventId;\n\n const authorized = await checkAuth(\n request,\n reply,\n \"eventsNotify\",\n options,\n { eventId },\n );\n if (!authorized) return;\n\n try {\n const body = request.body;\n if (!body || typeof body !== \"object\") {\n jsonError(reply, 400, \"Bad request\", \"Invalid JSON body\");\n return;\n }\n\n const result = await stepflow.notify(eventId, body.data);\n const response: NotifyResult = result;\n reply.code(200).send(response);\n } catch (error) {\n jsonError(\n reply,\n 500,\n \"Internal server error\",\n getErrorMessage(error),\n );\n }\n },\n );\n }\n\n // Minimal stream endpoint: trigger + return SSE stream\n if (isRouteEnabled(\"workflowsStream\", options.endpoints)) {\n fastify.post<{\n Params: { workflowId: string };\n Body: { payload: unknown };\n }>(`${basePath}/workflows/:workflowId/stream`, async (request, reply) => {\n const workflowId = request.params.workflowId;\n\n const authorized = await checkAuth(\n request,\n reply,\n \"workflowsStream\",\n options,\n { workflowId },\n );\n if (!authorized) return;\n\n try {\n const body = request.body;\n if (!body || typeof body !== \"object\") {\n jsonError(reply, 400, \"Bad request\", \"Invalid JSON body\");\n return;\n }\n\n const { runId, publicAccessToken } = await stepflow.trigger(\n workflowId,\n body.payload,\n );\n\n reply.raw.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"X-Accel-Buffering\": \"no\",\n });\n\n reply.hijack();\n\n let closed = false;\n\n const send = (type: string, data: unknown) => {\n if (closed) return;\n reply.raw.write(`event: ${type}\\n`);\n reply.raw.write(`data: ${JSON.stringify(data)}\\n\\n`);\n };\n\n const stop = () => {\n if (closed) return;\n closed = true;\n reply.raw.end();\n };\n\n request.raw.on(\"close\", stop);\n\n void (async () => {\n try {\n send(\"trigger\", { runId, accessToken: publicAccessToken });\n\n // Delegate to the run stream logic by subscribing to the execution.\n // We need executionId; poll until the run exists.\n let executionId: string | undefined;\n while (!closed && !executionId) {\n const run = await stepflow.getRun(runId);\n executionId = run?.id;\n if (!executionId) {\n await new Promise((r) => setTimeout(r, 100));\n }\n }\n\n if (!executionId || closed) return;\n\n const unsubscribe = stepflow.subscribeToExecution(\n executionId,\n () => {\n void (async () => {\n if (closed) return;\n const execution = await stepflow.getExecution(executionId);\n if (execution) {\n send(\"update\", execution);\n }\n })();\n },\n );\n\n // Keep connection open\n await new Promise((resolve) => {\n const timeout = setTimeout(resolve, 60 * 60 * 1000);\n request.raw.on(\"close\", () => {\n clearTimeout(timeout);\n resolve(undefined);\n });\n });\n\n unsubscribe();\n } catch (error) {\n if (!closed) {\n send(\"error\", {\n error: \"Internal server error\",\n message: getErrorMessage(error),\n });\n stop();\n }\n }\n })();\n } catch (error) {\n const message = getErrorMessage(error);\n if (message.includes(\"Workflow\") && message.includes(\"not found\")) {\n jsonError(reply, 404, \"Not found\", message);\n return;\n }\n jsonError(reply, 500, \"Internal server error\", message);\n }\n });\n }\n };\n}\n\n// ============================================================================\n// Plugin\n// ============================================================================\n\nexport const stepflowPlugin = fp<StepflowPluginOptions>(\n async (fastify, options) => {\n const { stepflow, basePath, healthCheck, endpoints, auth, onAuthFailure } =\n options;\n await fastify.register(\n createStepflowRoutes(stepflow, {\n basePath,\n healthCheck,\n endpoints,\n auth,\n onAuthFailure,\n }),\n );\n },\n {\n name: \"@stepflowjs/adapter-fastify\",\n },\n);\n"],"mappings":"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","names":["isRouteEnabled"]}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@stepflowjs/adapter-fastify",
3
+ "version": "0.0.1",
4
+ "description": "Fastify framework 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
+ "fastify-plugin": "^5.0.0",
20
+ "@stepflowjs/adapter-shared": "0.0.1",
21
+ "@stepflowjs/core": "0.0.1"
22
+ },
23
+ "devDependencies": {
24
+ "fastify": "^5.2.3",
25
+ "tsup": "^8.5.1",
26
+ "vitest": "^4.0.17"
27
+ },
28
+ "peerDependencies": {
29
+ "fastify": "^4.0.0 || ^5.0.0",
30
+ "typescript": "^5.0.0"
31
+ },
32
+ "license": "MIT",
33
+ "author": "Stepflow Contributors",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://stepflow-production.up.railway.app",
37
+ "directory": "packages/adapters/fastify"
38
+ },
39
+ "homepage": "https://stepflow-production.up.railway.app",
40
+ "bugs": {
41
+ "url": "https://stepflow-production.up.railway.app"
42
+ },
43
+ "keywords": [
44
+ "stepflow",
45
+ "adapter",
46
+ "fastify",
47
+ "framework",
48
+ "workflow",
49
+ "orchestration"
50
+ ],
51
+ "publishConfig": {
52
+ "access": "public"
53
+ },
54
+ "scripts": {
55
+ "build": "tsup",
56
+ "dev": "tsup --watch",
57
+ "typecheck": "tsc --noEmit",
58
+ "test": "vitest",
59
+ "clean": "rm -rf dist"
60
+ }
61
+ }