@saga-bus/fastify 0.1.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/LICENSE +21 -0
- package/README.md +265 -0
- package/dist/index.cjs +146 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +49 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Dean Foran
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# @saga-bus/fastify
|
|
2
|
+
|
|
3
|
+
Fastify plugin for saga-bus with lifecycle management, request decoration, and health checks.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @saga-bus/fastify fastify
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @saga-bus/fastify fastify
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- **Plugin Registration**: Register bus as a Fastify plugin
|
|
16
|
+
- **Request Decoration**: Access bus via `request.bus`
|
|
17
|
+
- **Correlation ID**: Automatic extraction and generation
|
|
18
|
+
- **Lifecycle Hooks**: Auto-start/stop bus with Fastify
|
|
19
|
+
- **Health Check**: Built-in health check route
|
|
20
|
+
- **Error Handler**: Saga-specific error handling
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import Fastify from "fastify";
|
|
26
|
+
import { createBus } from "@saga-bus/core";
|
|
27
|
+
import { sagaBusFastifyPlugin } from "@saga-bus/fastify";
|
|
28
|
+
|
|
29
|
+
const bus = createBus({ /* config */ });
|
|
30
|
+
|
|
31
|
+
const app = Fastify({ logger: true });
|
|
32
|
+
|
|
33
|
+
// Register plugin
|
|
34
|
+
await app.register(sagaBusFastifyPlugin, {
|
|
35
|
+
bus,
|
|
36
|
+
healthCheck: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Your routes
|
|
40
|
+
app.post("/orders", async (request, reply) => {
|
|
41
|
+
await request.bus.publish({
|
|
42
|
+
type: "CreateOrder",
|
|
43
|
+
payload: request.body,
|
|
44
|
+
});
|
|
45
|
+
return { correlationId: request.correlationId };
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
await app.listen({ port: 3000 });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## API Reference
|
|
52
|
+
|
|
53
|
+
### sagaBusFastifyPlugin
|
|
54
|
+
|
|
55
|
+
Fastify plugin that integrates saga-bus.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
interface SagaBusFastifyOptions {
|
|
59
|
+
/** The bus instance to register */
|
|
60
|
+
bus: Bus;
|
|
61
|
+
|
|
62
|
+
/** Whether to start bus when Fastify starts (default: true) */
|
|
63
|
+
autoStart?: boolean;
|
|
64
|
+
|
|
65
|
+
/** Whether to stop bus when Fastify closes (default: true) */
|
|
66
|
+
autoStop?: boolean;
|
|
67
|
+
|
|
68
|
+
/** Header name for correlation ID (default: "x-correlation-id") */
|
|
69
|
+
correlationIdHeader?: string;
|
|
70
|
+
|
|
71
|
+
/** Whether to generate correlation ID if not present (default: true) */
|
|
72
|
+
generateCorrelationId?: boolean;
|
|
73
|
+
|
|
74
|
+
/** Custom correlation ID generator */
|
|
75
|
+
correlationIdGenerator?: () => string;
|
|
76
|
+
|
|
77
|
+
/** Enable health check route */
|
|
78
|
+
healthCheck?: boolean | HealthCheckConfig;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface HealthCheckConfig {
|
|
82
|
+
/** Route path for health check (default: "/health") */
|
|
83
|
+
path?: string;
|
|
84
|
+
|
|
85
|
+
/** Additional health checks */
|
|
86
|
+
checks?: Array<{
|
|
87
|
+
name: string;
|
|
88
|
+
check: () => Promise<boolean>;
|
|
89
|
+
}>;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Examples
|
|
94
|
+
|
|
95
|
+
### Basic Usage
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import Fastify from "fastify";
|
|
99
|
+
import { createBus } from "@saga-bus/core";
|
|
100
|
+
import { sagaBusFastifyPlugin } from "@saga-bus/fastify";
|
|
101
|
+
|
|
102
|
+
const bus = createBus({ /* config */ });
|
|
103
|
+
const app = Fastify();
|
|
104
|
+
|
|
105
|
+
await app.register(sagaBusFastifyPlugin, { bus });
|
|
106
|
+
|
|
107
|
+
app.post("/messages", async (request) => {
|
|
108
|
+
await request.bus.publish({
|
|
109
|
+
type: request.body.type,
|
|
110
|
+
payload: request.body.payload,
|
|
111
|
+
});
|
|
112
|
+
return { success: true, correlationId: request.correlationId };
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await app.listen({ port: 3000 });
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### With Health Check
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
await app.register(sagaBusFastifyPlugin, {
|
|
122
|
+
bus,
|
|
123
|
+
healthCheck: {
|
|
124
|
+
path: "/health",
|
|
125
|
+
checks: [
|
|
126
|
+
{
|
|
127
|
+
name: "database",
|
|
128
|
+
check: async () => {
|
|
129
|
+
await pool.query("SELECT 1");
|
|
130
|
+
return true;
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Health check response:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"status": "healthy",
|
|
143
|
+
"timestamp": "2024-01-01T00:00:00.000Z",
|
|
144
|
+
"checks": {
|
|
145
|
+
"bus": { "status": "pass" },
|
|
146
|
+
"database": { "status": "pass" }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Custom Correlation ID
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
await app.register(sagaBusFastifyPlugin, {
|
|
155
|
+
bus,
|
|
156
|
+
correlationIdHeader: "x-request-id",
|
|
157
|
+
correlationIdGenerator: () => `req-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Manual Lifecycle Control
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
await app.register(sagaBusFastifyPlugin, {
|
|
165
|
+
bus,
|
|
166
|
+
autoStart: false,
|
|
167
|
+
autoStop: false,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Start bus manually
|
|
171
|
+
await bus.start();
|
|
172
|
+
|
|
173
|
+
// Stop bus manually before close
|
|
174
|
+
app.addHook("onClose", async () => {
|
|
175
|
+
await bus.stop();
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## TypeScript Support
|
|
180
|
+
|
|
181
|
+
The plugin extends Fastify types:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// In your route handlers
|
|
185
|
+
app.get("/", async (request, reply) => {
|
|
186
|
+
// request.bus is typed as Bus
|
|
187
|
+
await request.bus.publish(message);
|
|
188
|
+
|
|
189
|
+
// request.correlationId is typed as string
|
|
190
|
+
console.log(`Processing ${request.correlationId}`);
|
|
191
|
+
|
|
192
|
+
// fastify.bus is also available
|
|
193
|
+
await request.server.bus.publish(message);
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Error Handling
|
|
198
|
+
|
|
199
|
+
The plugin installs a custom error handler for saga-specific errors:
|
|
200
|
+
|
|
201
|
+
- **SagaTimeoutError**: Returns 408 Request Timeout
|
|
202
|
+
- **ConcurrencyError**: Returns 409 Conflict
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
app.get("/order/:id", async (request) => {
|
|
206
|
+
// If this throws a ConcurrencyError, client gets 409
|
|
207
|
+
await request.bus.publish({ type: "UpdateOrder", payload: { id: request.params.id } });
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Response on ConcurrencyError:
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"error": "Concurrency Conflict",
|
|
216
|
+
"message": "Expected version 1, but found 2",
|
|
217
|
+
"correlationId": "abc-123"
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Example: Complete Application
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import Fastify from "fastify";
|
|
225
|
+
import { createBus, InMemoryTransport, InMemorySagaStore } from "@saga-bus/core";
|
|
226
|
+
import { sagaBusFastifyPlugin } from "@saga-bus/fastify";
|
|
227
|
+
|
|
228
|
+
// Create bus
|
|
229
|
+
const bus = createBus({
|
|
230
|
+
transport: new InMemoryTransport(),
|
|
231
|
+
store: new InMemorySagaStore(),
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Create Fastify app
|
|
235
|
+
const app = Fastify({ logger: true });
|
|
236
|
+
|
|
237
|
+
// Register saga-bus plugin
|
|
238
|
+
await app.register(sagaBusFastifyPlugin, {
|
|
239
|
+
bus,
|
|
240
|
+
healthCheck: true,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Routes
|
|
244
|
+
app.post("/orders", async (request) => {
|
|
245
|
+
await request.bus.publish({
|
|
246
|
+
type: "CreateOrder",
|
|
247
|
+
payload: request.body,
|
|
248
|
+
});
|
|
249
|
+
return { orderId: "new-order", correlationId: request.correlationId };
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
app.get("/orders/:id", async (request) => {
|
|
253
|
+
// Access bus from request
|
|
254
|
+
const state = await request.bus.getSagaState("OrderSaga", request.params.id);
|
|
255
|
+
return state;
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Start server
|
|
259
|
+
await app.listen({ port: 3000 });
|
|
260
|
+
console.log("Server running on port 3000");
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## License
|
|
264
|
+
|
|
265
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
sagaBusFastifyPlugin: () => sagaBusFastifyPlugin
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// src/plugin.ts
|
|
38
|
+
var import_fastify_plugin = __toESM(require("fastify-plugin"), 1);
|
|
39
|
+
var import_crypto = require("crypto");
|
|
40
|
+
var sagaBusPlugin = async (fastify, options) => {
|
|
41
|
+
const {
|
|
42
|
+
bus,
|
|
43
|
+
autoStart = true,
|
|
44
|
+
autoStop = true,
|
|
45
|
+
correlationIdHeader = "x-correlation-id",
|
|
46
|
+
generateCorrelationId = true,
|
|
47
|
+
correlationIdGenerator = import_crypto.randomUUID,
|
|
48
|
+
healthCheck = false
|
|
49
|
+
} = options;
|
|
50
|
+
fastify.decorate("bus", bus);
|
|
51
|
+
fastify.decorateRequest("bus", null);
|
|
52
|
+
fastify.decorateRequest("correlationId", "");
|
|
53
|
+
fastify.addHook("onRequest", async (request, reply) => {
|
|
54
|
+
request.bus = bus;
|
|
55
|
+
let correlationId = request.headers[correlationIdHeader.toLowerCase()];
|
|
56
|
+
if (!correlationId && generateCorrelationId) {
|
|
57
|
+
correlationId = correlationIdGenerator();
|
|
58
|
+
}
|
|
59
|
+
if (correlationId) {
|
|
60
|
+
request.correlationId = correlationId;
|
|
61
|
+
reply.header(correlationIdHeader, correlationId);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
if (autoStart) {
|
|
65
|
+
fastify.addHook("onReady", async () => {
|
|
66
|
+
await bus.start();
|
|
67
|
+
fastify.log.info("Saga bus started");
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (autoStop) {
|
|
71
|
+
fastify.addHook("onClose", async () => {
|
|
72
|
+
await bus.stop();
|
|
73
|
+
fastify.log.info("Saga bus stopped");
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (healthCheck) {
|
|
77
|
+
const config = typeof healthCheck === "boolean" ? { path: "/health", checks: [] } : { path: "/health", checks: [], ...healthCheck };
|
|
78
|
+
fastify.get(config.path, async (_request, reply) => {
|
|
79
|
+
const healthStatus = {
|
|
80
|
+
status: "healthy",
|
|
81
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
82
|
+
checks: {}
|
|
83
|
+
};
|
|
84
|
+
try {
|
|
85
|
+
if (bus) {
|
|
86
|
+
healthStatus.checks.bus = { status: "pass" };
|
|
87
|
+
} else {
|
|
88
|
+
throw new Error("Bus not available");
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
healthStatus.status = "unhealthy";
|
|
92
|
+
healthStatus.checks.bus = {
|
|
93
|
+
status: "fail",
|
|
94
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
for (const check of config.checks || []) {
|
|
98
|
+
try {
|
|
99
|
+
const result = await check.check();
|
|
100
|
+
healthStatus.checks[check.name] = {
|
|
101
|
+
status: result ? "pass" : "fail"
|
|
102
|
+
};
|
|
103
|
+
if (!result) {
|
|
104
|
+
healthStatus.status = "unhealthy";
|
|
105
|
+
}
|
|
106
|
+
} catch (error) {
|
|
107
|
+
healthStatus.status = "unhealthy";
|
|
108
|
+
healthStatus.checks[check.name] = {
|
|
109
|
+
status: "fail",
|
|
110
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const statusCode = healthStatus.status === "healthy" ? 200 : 503;
|
|
115
|
+
reply.code(statusCode).send(healthStatus);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
fastify.setErrorHandler((error, request, reply) => {
|
|
119
|
+
if (error.name === "SagaTimeoutError") {
|
|
120
|
+
reply.code(408).send({
|
|
121
|
+
error: "Saga Timeout",
|
|
122
|
+
message: error.message,
|
|
123
|
+
correlationId: request.correlationId
|
|
124
|
+
});
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (error.name === "ConcurrencyError") {
|
|
128
|
+
reply.code(409).send({
|
|
129
|
+
error: "Concurrency Conflict",
|
|
130
|
+
message: error.message,
|
|
131
|
+
correlationId: request.correlationId
|
|
132
|
+
});
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
reply.send(error);
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
var sagaBusFastifyPlugin = (0, import_fastify_plugin.default)(sagaBusPlugin, {
|
|
139
|
+
fastify: ">=4.0.0",
|
|
140
|
+
name: "@saga-bus/fastify"
|
|
141
|
+
});
|
|
142
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
143
|
+
0 && (module.exports = {
|
|
144
|
+
sagaBusFastifyPlugin
|
|
145
|
+
});
|
|
146
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/plugin.ts"],"sourcesContent":["export { sagaBusFastifyPlugin } from \"./plugin.js\";\nexport type {\n SagaBusFastifyOptions,\n HealthCheckConfig,\n HealthStatus,\n} from \"./types.js\";\n","import type { FastifyPluginAsync, FastifyError } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { randomUUID } from \"crypto\";\nimport type { SagaBusFastifyOptions, HealthCheckConfig, HealthStatus } from \"./types.js\";\n\nconst sagaBusPlugin: FastifyPluginAsync<SagaBusFastifyOptions> = async (\n fastify,\n options\n) => {\n const {\n bus,\n autoStart = true,\n autoStop = true,\n correlationIdHeader = \"x-correlation-id\",\n generateCorrelationId = true,\n correlationIdGenerator = randomUUID,\n healthCheck = false,\n } = options;\n\n // Decorate fastify instance with bus\n fastify.decorate(\"bus\", bus);\n\n // Decorate request with bus and correlationId\n // @ts-expect-error - Fastify decorateRequest typing is complex, null is valid for initial decoration\n fastify.decorateRequest(\"bus\", null);\n fastify.decorateRequest(\"correlationId\", \"\");\n\n // Add hook to set bus and correlation ID on request\n fastify.addHook(\"onRequest\", async (request, reply) => {\n request.bus = bus;\n\n // Extract or generate correlation ID\n let correlationId = request.headers[correlationIdHeader.toLowerCase()] as string | undefined;\n\n if (!correlationId && generateCorrelationId) {\n correlationId = correlationIdGenerator();\n }\n\n if (correlationId) {\n request.correlationId = correlationId;\n reply.header(correlationIdHeader, correlationId);\n }\n });\n\n // Auto-start bus\n if (autoStart) {\n fastify.addHook(\"onReady\", async () => {\n await bus.start();\n fastify.log.info(\"Saga bus started\");\n });\n }\n\n // Auto-stop bus\n if (autoStop) {\n fastify.addHook(\"onClose\", async () => {\n await bus.stop();\n fastify.log.info(\"Saga bus stopped\");\n });\n }\n\n // Register health check route\n if (healthCheck) {\n const config: HealthCheckConfig = typeof healthCheck === \"boolean\"\n ? { path: \"/health\", checks: [] }\n : { path: \"/health\", checks: [], ...healthCheck };\n\n fastify.get(config.path!, async (_request, reply) => {\n const healthStatus: HealthStatus = {\n status: \"healthy\",\n timestamp: new Date().toISOString(),\n checks: {},\n };\n\n // Check bus\n try {\n if (bus) {\n healthStatus.checks.bus = { status: \"pass\" };\n } else {\n throw new Error(\"Bus not available\");\n }\n } catch (error) {\n healthStatus.status = \"unhealthy\";\n healthStatus.checks.bus = {\n status: \"fail\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n\n // Run additional checks\n for (const check of config.checks || []) {\n try {\n const result = await check.check();\n healthStatus.checks[check.name] = {\n status: result ? \"pass\" : \"fail\",\n };\n if (!result) {\n healthStatus.status = \"unhealthy\";\n }\n } catch (error) {\n healthStatus.status = \"unhealthy\";\n healthStatus.checks[check.name] = {\n status: \"fail\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }\n\n const statusCode = healthStatus.status === \"healthy\" ? 200 : 503;\n reply.code(statusCode).send(healthStatus);\n });\n }\n\n // Error handler for saga errors\n fastify.setErrorHandler((error: FastifyError, request, reply) => {\n if (error.name === \"SagaTimeoutError\") {\n reply.code(408).send({\n error: \"Saga Timeout\",\n message: error.message,\n correlationId: request.correlationId,\n });\n return;\n }\n\n if (error.name === \"ConcurrencyError\") {\n reply.code(409).send({\n error: \"Concurrency Conflict\",\n message: error.message,\n correlationId: request.correlationId,\n });\n return;\n }\n\n // Default error handling\n reply.send(error);\n });\n};\n\nexport const sagaBusFastifyPlugin = fp(sagaBusPlugin, {\n fastify: \">=4.0.0\",\n name: \"@saga-bus/fastify\",\n});\n"],"mappings":"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","names":["fp"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { FastifyPluginAsync } from 'fastify';
|
|
2
|
+
import { Bus } from '@saga-bus/core';
|
|
3
|
+
|
|
4
|
+
declare module "fastify" {
|
|
5
|
+
interface FastifyRequest {
|
|
6
|
+
bus: Bus;
|
|
7
|
+
correlationId: string;
|
|
8
|
+
}
|
|
9
|
+
interface FastifyInstance {
|
|
10
|
+
bus: Bus;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
interface SagaBusFastifyOptions {
|
|
14
|
+
/** The bus instance to register */
|
|
15
|
+
bus: Bus;
|
|
16
|
+
/** Whether to start bus when Fastify starts */
|
|
17
|
+
autoStart?: boolean;
|
|
18
|
+
/** Whether to stop bus when Fastify closes */
|
|
19
|
+
autoStop?: boolean;
|
|
20
|
+
/** Header name for correlation ID */
|
|
21
|
+
correlationIdHeader?: string;
|
|
22
|
+
/** Whether to generate correlation ID if not present */
|
|
23
|
+
generateCorrelationId?: boolean;
|
|
24
|
+
/** Custom correlation ID generator */
|
|
25
|
+
correlationIdGenerator?: () => string;
|
|
26
|
+
/** Enable health check route */
|
|
27
|
+
healthCheck?: boolean | HealthCheckConfig;
|
|
28
|
+
}
|
|
29
|
+
interface HealthCheckConfig {
|
|
30
|
+
/** Route path for health check */
|
|
31
|
+
path?: string;
|
|
32
|
+
/** Additional health checks */
|
|
33
|
+
checks?: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
check: () => Promise<boolean>;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
interface HealthStatus {
|
|
39
|
+
status: "healthy" | "unhealthy";
|
|
40
|
+
timestamp: string;
|
|
41
|
+
checks: Record<string, {
|
|
42
|
+
status: "pass" | "fail";
|
|
43
|
+
message?: string;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
declare const sagaBusFastifyPlugin: FastifyPluginAsync<SagaBusFastifyOptions>;
|
|
48
|
+
|
|
49
|
+
export { type HealthCheckConfig, type HealthStatus, type SagaBusFastifyOptions, sagaBusFastifyPlugin };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { FastifyPluginAsync } from 'fastify';
|
|
2
|
+
import { Bus } from '@saga-bus/core';
|
|
3
|
+
|
|
4
|
+
declare module "fastify" {
|
|
5
|
+
interface FastifyRequest {
|
|
6
|
+
bus: Bus;
|
|
7
|
+
correlationId: string;
|
|
8
|
+
}
|
|
9
|
+
interface FastifyInstance {
|
|
10
|
+
bus: Bus;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
interface SagaBusFastifyOptions {
|
|
14
|
+
/** The bus instance to register */
|
|
15
|
+
bus: Bus;
|
|
16
|
+
/** Whether to start bus when Fastify starts */
|
|
17
|
+
autoStart?: boolean;
|
|
18
|
+
/** Whether to stop bus when Fastify closes */
|
|
19
|
+
autoStop?: boolean;
|
|
20
|
+
/** Header name for correlation ID */
|
|
21
|
+
correlationIdHeader?: string;
|
|
22
|
+
/** Whether to generate correlation ID if not present */
|
|
23
|
+
generateCorrelationId?: boolean;
|
|
24
|
+
/** Custom correlation ID generator */
|
|
25
|
+
correlationIdGenerator?: () => string;
|
|
26
|
+
/** Enable health check route */
|
|
27
|
+
healthCheck?: boolean | HealthCheckConfig;
|
|
28
|
+
}
|
|
29
|
+
interface HealthCheckConfig {
|
|
30
|
+
/** Route path for health check */
|
|
31
|
+
path?: string;
|
|
32
|
+
/** Additional health checks */
|
|
33
|
+
checks?: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
check: () => Promise<boolean>;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
interface HealthStatus {
|
|
39
|
+
status: "healthy" | "unhealthy";
|
|
40
|
+
timestamp: string;
|
|
41
|
+
checks: Record<string, {
|
|
42
|
+
status: "pass" | "fail";
|
|
43
|
+
message?: string;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
declare const sagaBusFastifyPlugin: FastifyPluginAsync<SagaBusFastifyOptions>;
|
|
48
|
+
|
|
49
|
+
export { type HealthCheckConfig, type HealthStatus, type SagaBusFastifyOptions, sagaBusFastifyPlugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// src/plugin.ts
|
|
2
|
+
import fp from "fastify-plugin";
|
|
3
|
+
import { randomUUID } from "crypto";
|
|
4
|
+
var sagaBusPlugin = async (fastify, options) => {
|
|
5
|
+
const {
|
|
6
|
+
bus,
|
|
7
|
+
autoStart = true,
|
|
8
|
+
autoStop = true,
|
|
9
|
+
correlationIdHeader = "x-correlation-id",
|
|
10
|
+
generateCorrelationId = true,
|
|
11
|
+
correlationIdGenerator = randomUUID,
|
|
12
|
+
healthCheck = false
|
|
13
|
+
} = options;
|
|
14
|
+
fastify.decorate("bus", bus);
|
|
15
|
+
fastify.decorateRequest("bus", null);
|
|
16
|
+
fastify.decorateRequest("correlationId", "");
|
|
17
|
+
fastify.addHook("onRequest", async (request, reply) => {
|
|
18
|
+
request.bus = bus;
|
|
19
|
+
let correlationId = request.headers[correlationIdHeader.toLowerCase()];
|
|
20
|
+
if (!correlationId && generateCorrelationId) {
|
|
21
|
+
correlationId = correlationIdGenerator();
|
|
22
|
+
}
|
|
23
|
+
if (correlationId) {
|
|
24
|
+
request.correlationId = correlationId;
|
|
25
|
+
reply.header(correlationIdHeader, correlationId);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
if (autoStart) {
|
|
29
|
+
fastify.addHook("onReady", async () => {
|
|
30
|
+
await bus.start();
|
|
31
|
+
fastify.log.info("Saga bus started");
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (autoStop) {
|
|
35
|
+
fastify.addHook("onClose", async () => {
|
|
36
|
+
await bus.stop();
|
|
37
|
+
fastify.log.info("Saga bus stopped");
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (healthCheck) {
|
|
41
|
+
const config = typeof healthCheck === "boolean" ? { path: "/health", checks: [] } : { path: "/health", checks: [], ...healthCheck };
|
|
42
|
+
fastify.get(config.path, async (_request, reply) => {
|
|
43
|
+
const healthStatus = {
|
|
44
|
+
status: "healthy",
|
|
45
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
46
|
+
checks: {}
|
|
47
|
+
};
|
|
48
|
+
try {
|
|
49
|
+
if (bus) {
|
|
50
|
+
healthStatus.checks.bus = { status: "pass" };
|
|
51
|
+
} else {
|
|
52
|
+
throw new Error("Bus not available");
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
healthStatus.status = "unhealthy";
|
|
56
|
+
healthStatus.checks.bus = {
|
|
57
|
+
status: "fail",
|
|
58
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
for (const check of config.checks || []) {
|
|
62
|
+
try {
|
|
63
|
+
const result = await check.check();
|
|
64
|
+
healthStatus.checks[check.name] = {
|
|
65
|
+
status: result ? "pass" : "fail"
|
|
66
|
+
};
|
|
67
|
+
if (!result) {
|
|
68
|
+
healthStatus.status = "unhealthy";
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
healthStatus.status = "unhealthy";
|
|
72
|
+
healthStatus.checks[check.name] = {
|
|
73
|
+
status: "fail",
|
|
74
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const statusCode = healthStatus.status === "healthy" ? 200 : 503;
|
|
79
|
+
reply.code(statusCode).send(healthStatus);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
fastify.setErrorHandler((error, request, reply) => {
|
|
83
|
+
if (error.name === "SagaTimeoutError") {
|
|
84
|
+
reply.code(408).send({
|
|
85
|
+
error: "Saga Timeout",
|
|
86
|
+
message: error.message,
|
|
87
|
+
correlationId: request.correlationId
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (error.name === "ConcurrencyError") {
|
|
92
|
+
reply.code(409).send({
|
|
93
|
+
error: "Concurrency Conflict",
|
|
94
|
+
message: error.message,
|
|
95
|
+
correlationId: request.correlationId
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
reply.send(error);
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
var sagaBusFastifyPlugin = fp(sagaBusPlugin, {
|
|
103
|
+
fastify: ">=4.0.0",
|
|
104
|
+
name: "@saga-bus/fastify"
|
|
105
|
+
});
|
|
106
|
+
export {
|
|
107
|
+
sagaBusFastifyPlugin
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { FastifyPluginAsync, FastifyError } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { randomUUID } from \"crypto\";\nimport type { SagaBusFastifyOptions, HealthCheckConfig, HealthStatus } from \"./types.js\";\n\nconst sagaBusPlugin: FastifyPluginAsync<SagaBusFastifyOptions> = async (\n fastify,\n options\n) => {\n const {\n bus,\n autoStart = true,\n autoStop = true,\n correlationIdHeader = \"x-correlation-id\",\n generateCorrelationId = true,\n correlationIdGenerator = randomUUID,\n healthCheck = false,\n } = options;\n\n // Decorate fastify instance with bus\n fastify.decorate(\"bus\", bus);\n\n // Decorate request with bus and correlationId\n // @ts-expect-error - Fastify decorateRequest typing is complex, null is valid for initial decoration\n fastify.decorateRequest(\"bus\", null);\n fastify.decorateRequest(\"correlationId\", \"\");\n\n // Add hook to set bus and correlation ID on request\n fastify.addHook(\"onRequest\", async (request, reply) => {\n request.bus = bus;\n\n // Extract or generate correlation ID\n let correlationId = request.headers[correlationIdHeader.toLowerCase()] as string | undefined;\n\n if (!correlationId && generateCorrelationId) {\n correlationId = correlationIdGenerator();\n }\n\n if (correlationId) {\n request.correlationId = correlationId;\n reply.header(correlationIdHeader, correlationId);\n }\n });\n\n // Auto-start bus\n if (autoStart) {\n fastify.addHook(\"onReady\", async () => {\n await bus.start();\n fastify.log.info(\"Saga bus started\");\n });\n }\n\n // Auto-stop bus\n if (autoStop) {\n fastify.addHook(\"onClose\", async () => {\n await bus.stop();\n fastify.log.info(\"Saga bus stopped\");\n });\n }\n\n // Register health check route\n if (healthCheck) {\n const config: HealthCheckConfig = typeof healthCheck === \"boolean\"\n ? { path: \"/health\", checks: [] }\n : { path: \"/health\", checks: [], ...healthCheck };\n\n fastify.get(config.path!, async (_request, reply) => {\n const healthStatus: HealthStatus = {\n status: \"healthy\",\n timestamp: new Date().toISOString(),\n checks: {},\n };\n\n // Check bus\n try {\n if (bus) {\n healthStatus.checks.bus = { status: \"pass\" };\n } else {\n throw new Error(\"Bus not available\");\n }\n } catch (error) {\n healthStatus.status = \"unhealthy\";\n healthStatus.checks.bus = {\n status: \"fail\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n\n // Run additional checks\n for (const check of config.checks || []) {\n try {\n const result = await check.check();\n healthStatus.checks[check.name] = {\n status: result ? \"pass\" : \"fail\",\n };\n if (!result) {\n healthStatus.status = \"unhealthy\";\n }\n } catch (error) {\n healthStatus.status = \"unhealthy\";\n healthStatus.checks[check.name] = {\n status: \"fail\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }\n\n const statusCode = healthStatus.status === \"healthy\" ? 200 : 503;\n reply.code(statusCode).send(healthStatus);\n });\n }\n\n // Error handler for saga errors\n fastify.setErrorHandler((error: FastifyError, request, reply) => {\n if (error.name === \"SagaTimeoutError\") {\n reply.code(408).send({\n error: \"Saga Timeout\",\n message: error.message,\n correlationId: request.correlationId,\n });\n return;\n }\n\n if (error.name === \"ConcurrencyError\") {\n reply.code(409).send({\n error: \"Concurrency Conflict\",\n message: error.message,\n correlationId: request.correlationId,\n });\n return;\n }\n\n // Default error handling\n reply.send(error);\n });\n};\n\nexport const sagaBusFastifyPlugin = fp(sagaBusPlugin, {\n fastify: \">=4.0.0\",\n name: \"@saga-bus/fastify\",\n});\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@saga-bus/fastify",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Fastify integration for saga-bus",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/d-e-a-n-f/saga-bus.git",
|
|
26
|
+
"directory": "packages/fastify"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/d-e-a-n-f/saga-bus/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/d-e-a-n-f/saga-bus#readme",
|
|
32
|
+
"keywords": [
|
|
33
|
+
"saga",
|
|
34
|
+
"message-bus",
|
|
35
|
+
"fastify",
|
|
36
|
+
"plugin",
|
|
37
|
+
"integration"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"fastify-plugin": "^5.0.0",
|
|
41
|
+
"@saga-bus/core": "0.1.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"fastify": "^5.0.0",
|
|
45
|
+
"tsup": "^8.0.0",
|
|
46
|
+
"typescript": "^5.9.2",
|
|
47
|
+
"vitest": "^3.0.0",
|
|
48
|
+
"@repo/eslint-config": "0.0.0",
|
|
49
|
+
"@repo/typescript-config": "0.0.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@saga-bus/core": ">=0.1.1",
|
|
53
|
+
"fastify": ">=4.0.0"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsup",
|
|
57
|
+
"dev": "tsup --watch",
|
|
58
|
+
"lint": "eslint src/",
|
|
59
|
+
"check-types": "tsc --noEmit",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:watch": "vitest"
|
|
62
|
+
}
|
|
63
|
+
}
|