@saga-bus/hono 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 +263 -0
- package/dist/index.cjs +146 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +76 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -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,263 @@
|
|
|
1
|
+
# @saga-bus/hono
|
|
2
|
+
|
|
3
|
+
Hono integration for saga-bus, designed for edge runtimes (Cloudflare Workers, Deno, Bun).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @saga-bus/hono hono
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @saga-bus/hono hono
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- **Edge Runtime Compatible**: Works with Cloudflare Workers, Deno, Bun
|
|
16
|
+
- **Context Variables**: Type-safe `c.var.bus` and `c.var.correlationId`
|
|
17
|
+
- **Health Handler**: Factory for health check routes
|
|
18
|
+
- **Error Handler**: Saga-specific error responses
|
|
19
|
+
- **No Node.js Dependencies**: Uses simple UUID generator
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { Hono } from "hono";
|
|
25
|
+
import { createBus } from "@saga-bus/core";
|
|
26
|
+
import {
|
|
27
|
+
sagaBusMiddleware,
|
|
28
|
+
sagaErrorHandler,
|
|
29
|
+
createHealthHandler,
|
|
30
|
+
} from "@saga-bus/hono";
|
|
31
|
+
|
|
32
|
+
const bus = createBus({ /* config */ });
|
|
33
|
+
await bus.start();
|
|
34
|
+
|
|
35
|
+
const app = new Hono();
|
|
36
|
+
|
|
37
|
+
// Error handler first
|
|
38
|
+
app.use("*", sagaErrorHandler());
|
|
39
|
+
|
|
40
|
+
// Attach bus to context
|
|
41
|
+
app.use("*", sagaBusMiddleware({ bus }));
|
|
42
|
+
|
|
43
|
+
// Health check
|
|
44
|
+
app.get("/health", createHealthHandler({ bus }));
|
|
45
|
+
|
|
46
|
+
// Your routes
|
|
47
|
+
app.post("/orders", async (c) => {
|
|
48
|
+
const bus = c.get("bus");
|
|
49
|
+
const correlationId = c.get("correlationId");
|
|
50
|
+
|
|
51
|
+
await bus.publish({
|
|
52
|
+
type: "CreateOrder",
|
|
53
|
+
payload: await c.req.json(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return c.json({ correlationId });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export default app;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## API Reference
|
|
63
|
+
|
|
64
|
+
### sagaBusMiddleware(options)
|
|
65
|
+
|
|
66
|
+
Creates middleware that attaches the bus instance and correlation ID to context.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
interface SagaBusHonoOptions {
|
|
70
|
+
/** The bus instance to attach */
|
|
71
|
+
bus: Bus;
|
|
72
|
+
|
|
73
|
+
/** Header name for correlation ID (default: "x-correlation-id") */
|
|
74
|
+
correlationIdHeader?: string;
|
|
75
|
+
|
|
76
|
+
/** Whether to generate correlation ID if not present (default: true) */
|
|
77
|
+
generateCorrelationId?: boolean;
|
|
78
|
+
|
|
79
|
+
/** Custom correlation ID generator */
|
|
80
|
+
correlationIdGenerator?: () => string;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### sagaErrorHandler()
|
|
85
|
+
|
|
86
|
+
Error handler middleware for saga-related errors.
|
|
87
|
+
|
|
88
|
+
- **SagaTimeoutError**: Returns 408 Request Timeout
|
|
89
|
+
- **ConcurrencyError**: Returns 409 Conflict
|
|
90
|
+
|
|
91
|
+
### createHealthHandler(options)
|
|
92
|
+
|
|
93
|
+
Creates a health check handler.
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
interface HealthCheckOptions {
|
|
97
|
+
/** The bus instance to check */
|
|
98
|
+
bus: Bus;
|
|
99
|
+
|
|
100
|
+
/** Additional health checks */
|
|
101
|
+
checks?: Array<{
|
|
102
|
+
name: string;
|
|
103
|
+
check: () => Promise<boolean>;
|
|
104
|
+
}>;
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### SagaBusEnv
|
|
109
|
+
|
|
110
|
+
Type definition for Hono context variables.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
interface SagaBusEnv extends Env {
|
|
114
|
+
Variables: {
|
|
115
|
+
bus: Bus;
|
|
116
|
+
correlationId: string;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Examples
|
|
122
|
+
|
|
123
|
+
### Basic Usage
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { Hono } from "hono";
|
|
127
|
+
import { sagaBusMiddleware, SagaBusEnv } from "@saga-bus/hono";
|
|
128
|
+
|
|
129
|
+
const app = new Hono<SagaBusEnv>();
|
|
130
|
+
|
|
131
|
+
app.use("*", sagaBusMiddleware({ bus }));
|
|
132
|
+
|
|
133
|
+
app.post("/messages", async (c) => {
|
|
134
|
+
const bus = c.get("bus");
|
|
135
|
+
const correlationId = c.get("correlationId");
|
|
136
|
+
|
|
137
|
+
await bus.publish({
|
|
138
|
+
type: c.req.query("type") || "Message",
|
|
139
|
+
payload: await c.req.json(),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
return c.json({ success: true, correlationId });
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### With Health Checks
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import { createHealthHandler } from "@saga-bus/hono";
|
|
150
|
+
|
|
151
|
+
app.get("/health", createHealthHandler({
|
|
152
|
+
bus,
|
|
153
|
+
checks: [
|
|
154
|
+
{
|
|
155
|
+
name: "database",
|
|
156
|
+
check: async () => {
|
|
157
|
+
await db.query("SELECT 1");
|
|
158
|
+
return true;
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
}));
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Cloudflare Workers
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { Hono } from "hono";
|
|
169
|
+
import { sagaBusMiddleware, SagaBusEnv } from "@saga-bus/hono";
|
|
170
|
+
import { createBus } from "@saga-bus/core";
|
|
171
|
+
|
|
172
|
+
interface Env {
|
|
173
|
+
DB: D1Database;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const app = new Hono<SagaBusEnv & { Bindings: Env }>();
|
|
177
|
+
|
|
178
|
+
// Create bus per-request from environment
|
|
179
|
+
app.use("*", async (c, next) => {
|
|
180
|
+
const bus = createBusFromEnv(c.env);
|
|
181
|
+
return sagaBusMiddleware({ bus })(c, next);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
app.post("/messages", async (c) => {
|
|
185
|
+
await c.get("bus").publish({ type: "Message", payload: {} });
|
|
186
|
+
return c.json({ ok: true });
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
export default app;
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Deno
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import { Hono } from "https://deno.land/x/hono/mod.ts";
|
|
196
|
+
import { sagaBusMiddleware, SagaBusEnv } from "@saga-bus/hono";
|
|
197
|
+
|
|
198
|
+
const app = new Hono<SagaBusEnv>();
|
|
199
|
+
app.use("*", sagaBusMiddleware({ bus }));
|
|
200
|
+
|
|
201
|
+
Deno.serve(app.fetch);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Custom Correlation ID Generator
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
app.use("*", sagaBusMiddleware({
|
|
208
|
+
bus,
|
|
209
|
+
correlationIdHeader: "x-request-id",
|
|
210
|
+
correlationIdGenerator: () => `req-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
211
|
+
}));
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## TypeScript Support
|
|
215
|
+
|
|
216
|
+
The package provides full type safety for context variables:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import { Hono } from "hono";
|
|
220
|
+
import { SagaBusEnv } from "@saga-bus/hono";
|
|
221
|
+
|
|
222
|
+
// Use SagaBusEnv for typed context
|
|
223
|
+
const app = new Hono<SagaBusEnv>();
|
|
224
|
+
|
|
225
|
+
app.get("/", (c) => {
|
|
226
|
+
// c.get("bus") is typed as Bus
|
|
227
|
+
const bus = c.get("bus");
|
|
228
|
+
|
|
229
|
+
// c.get("correlationId") is typed as string
|
|
230
|
+
const correlationId = c.get("correlationId");
|
|
231
|
+
|
|
232
|
+
return c.json({ correlationId });
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Error Handling
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
app.use("*", sagaErrorHandler());
|
|
240
|
+
|
|
241
|
+
app.get("/order/:id", async (c) => {
|
|
242
|
+
// If this throws a ConcurrencyError, client gets 409
|
|
243
|
+
await c.get("bus").publish({
|
|
244
|
+
type: "UpdateOrder",
|
|
245
|
+
payload: { id: c.req.param("id") },
|
|
246
|
+
});
|
|
247
|
+
return c.json({ updated: true });
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Response on ConcurrencyError:
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"error": "Concurrency Conflict",
|
|
256
|
+
"message": "Expected version 1, but found 2",
|
|
257
|
+
"correlationId": "abc-123"
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
createHealthHandler: () => createHealthHandler,
|
|
24
|
+
createReadinessHandler: () => createReadinessHandler,
|
|
25
|
+
sagaBusMiddleware: () => sagaBusMiddleware,
|
|
26
|
+
sagaErrorHandler: () => sagaErrorHandler
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/middleware.ts
|
|
31
|
+
function generateId() {
|
|
32
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
33
|
+
const r = Math.random() * 16 | 0;
|
|
34
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
35
|
+
return v.toString(16);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function sagaBusMiddleware(options) {
|
|
39
|
+
const {
|
|
40
|
+
bus,
|
|
41
|
+
correlationIdHeader = "x-correlation-id",
|
|
42
|
+
generateCorrelationId = true,
|
|
43
|
+
correlationIdGenerator = generateId
|
|
44
|
+
} = options;
|
|
45
|
+
return async (c, next) => {
|
|
46
|
+
c.set("bus", bus);
|
|
47
|
+
let correlationId = c.req.header(correlationIdHeader);
|
|
48
|
+
if (!correlationId && generateCorrelationId) {
|
|
49
|
+
correlationId = correlationIdGenerator();
|
|
50
|
+
}
|
|
51
|
+
if (correlationId) {
|
|
52
|
+
c.set("correlationId", correlationId);
|
|
53
|
+
c.header(correlationIdHeader, correlationId);
|
|
54
|
+
}
|
|
55
|
+
await next();
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function sagaErrorHandler() {
|
|
59
|
+
return (err, c) => {
|
|
60
|
+
if (err instanceof Error) {
|
|
61
|
+
if (err.name === "SagaTimeoutError") {
|
|
62
|
+
return c.json(
|
|
63
|
+
{
|
|
64
|
+
error: "Saga Timeout",
|
|
65
|
+
message: err.message,
|
|
66
|
+
correlationId: c.get("correlationId")
|
|
67
|
+
},
|
|
68
|
+
408
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
if (err.name === "ConcurrencyError") {
|
|
72
|
+
return c.json(
|
|
73
|
+
{
|
|
74
|
+
error: "Concurrency Conflict",
|
|
75
|
+
message: err.message,
|
|
76
|
+
correlationId: c.get("correlationId")
|
|
77
|
+
},
|
|
78
|
+
409
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return c.json(
|
|
83
|
+
{
|
|
84
|
+
error: "Internal Server Error",
|
|
85
|
+
message: err instanceof Error ? err.message : "Unknown error",
|
|
86
|
+
correlationId: c.get("correlationId")
|
|
87
|
+
},
|
|
88
|
+
500
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/health.ts
|
|
94
|
+
function createHealthHandler(options) {
|
|
95
|
+
const { bus, checks = [] } = options;
|
|
96
|
+
return async (c) => {
|
|
97
|
+
const healthStatus = {
|
|
98
|
+
status: "healthy",
|
|
99
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
100
|
+
checks: {}
|
|
101
|
+
};
|
|
102
|
+
try {
|
|
103
|
+
if (bus) {
|
|
104
|
+
healthStatus.checks.bus = { status: "pass" };
|
|
105
|
+
} else {
|
|
106
|
+
throw new Error("Bus not available");
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
healthStatus.status = "unhealthy";
|
|
110
|
+
healthStatus.checks.bus = {
|
|
111
|
+
status: "fail",
|
|
112
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
for (const check of checks) {
|
|
116
|
+
try {
|
|
117
|
+
const result = await check.check();
|
|
118
|
+
healthStatus.checks[check.name] = {
|
|
119
|
+
status: result ? "pass" : "fail"
|
|
120
|
+
};
|
|
121
|
+
if (!result) {
|
|
122
|
+
healthStatus.status = "unhealthy";
|
|
123
|
+
}
|
|
124
|
+
} catch (error) {
|
|
125
|
+
healthStatus.status = "unhealthy";
|
|
126
|
+
healthStatus.checks[check.name] = {
|
|
127
|
+
status: "fail",
|
|
128
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const statusCode = healthStatus.status === "healthy" ? 200 : 503;
|
|
133
|
+
return c.json(healthStatus, statusCode);
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function createReadinessHandler(options) {
|
|
137
|
+
return createHealthHandler(options);
|
|
138
|
+
}
|
|
139
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
140
|
+
0 && (module.exports = {
|
|
141
|
+
createHealthHandler,
|
|
142
|
+
createReadinessHandler,
|
|
143
|
+
sagaBusMiddleware,
|
|
144
|
+
sagaErrorHandler
|
|
145
|
+
});
|
|
146
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/middleware.ts","../src/health.ts"],"sourcesContent":["export { sagaBusMiddleware, sagaErrorHandler } from \"./middleware.js\";\nexport { createHealthHandler, createReadinessHandler } from \"./health.js\";\nexport type {\n SagaBusEnv,\n SagaBusHonoOptions,\n HealthCheckOptions,\n HealthStatus,\n} from \"./types.js\";\n","import type { MiddlewareHandler, ErrorHandler } from \"hono\";\nimport type { SagaBusEnv, SagaBusHonoOptions } from \"./types.js\";\n\n// Simple UUID generator for edge compatibility (no crypto.randomUUID dependency)\nfunction generateId(): string {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Creates middleware that attaches the bus instance and correlation ID to context.\n */\nexport function sagaBusMiddleware(\n options: SagaBusHonoOptions\n): MiddlewareHandler<SagaBusEnv> {\n const {\n bus,\n correlationIdHeader = \"x-correlation-id\",\n generateCorrelationId = true,\n correlationIdGenerator = generateId,\n } = options;\n\n return async (c, next) => {\n // Attach bus to context\n c.set(\"bus\", bus);\n\n // Extract or generate correlation ID\n let correlationId = c.req.header(correlationIdHeader);\n\n if (!correlationId && generateCorrelationId) {\n correlationId = correlationIdGenerator();\n }\n\n if (correlationId) {\n c.set(\"correlationId\", correlationId);\n c.header(correlationIdHeader, correlationId);\n }\n\n await next();\n };\n}\n\n/**\n * Error handler for saga-related errors.\n * Use with app.onError(sagaErrorHandler())\n */\nexport function sagaErrorHandler(): ErrorHandler<SagaBusEnv> {\n return (err, c) => {\n if (err instanceof Error) {\n if (err.name === \"SagaTimeoutError\") {\n return c.json(\n {\n error: \"Saga Timeout\",\n message: err.message,\n correlationId: c.get(\"correlationId\"),\n },\n 408\n );\n }\n\n if (err.name === \"ConcurrencyError\") {\n return c.json(\n {\n error: \"Concurrency Conflict\",\n message: err.message,\n correlationId: c.get(\"correlationId\"),\n },\n 409\n );\n }\n }\n\n // Return generic error for other cases\n return c.json(\n {\n error: \"Internal Server Error\",\n message: err instanceof Error ? err.message : \"Unknown error\",\n correlationId: c.get(\"correlationId\"),\n },\n 500\n );\n };\n}\n","import type { Context } from \"hono\";\nimport type { HealthCheckOptions, HealthStatus, SagaBusEnv } from \"./types.js\";\n\n/**\n * Creates a health check handler.\n */\nexport function createHealthHandler(options: HealthCheckOptions) {\n const { bus, checks = [] } = options;\n\n return async (c: Context<SagaBusEnv>) => {\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 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 return c.json(healthStatus, statusCode);\n };\n}\n\n/**\n * Creates a readiness check handler (alias for health).\n */\nexport function createReadinessHandler(options: HealthCheckOptions) {\n return createHealthHandler(options);\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as hono from 'hono';
|
|
2
|
+
import { Env, MiddlewareHandler, ErrorHandler, Context } from 'hono';
|
|
3
|
+
import { Bus } from '@saga-bus/core';
|
|
4
|
+
|
|
5
|
+
interface SagaBusEnv extends Env {
|
|
6
|
+
Variables: {
|
|
7
|
+
bus: Bus;
|
|
8
|
+
correlationId: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
interface SagaBusHonoOptions {
|
|
12
|
+
/** The bus instance to attach */
|
|
13
|
+
bus: Bus;
|
|
14
|
+
/** Header name for correlation ID */
|
|
15
|
+
correlationIdHeader?: string;
|
|
16
|
+
/** Whether to generate correlation ID if not present */
|
|
17
|
+
generateCorrelationId?: boolean;
|
|
18
|
+
/** Custom correlation ID generator */
|
|
19
|
+
correlationIdGenerator?: () => string;
|
|
20
|
+
}
|
|
21
|
+
interface HealthCheckOptions {
|
|
22
|
+
/** The bus instance to check */
|
|
23
|
+
bus: Bus;
|
|
24
|
+
/** Additional health checks */
|
|
25
|
+
checks?: Array<{
|
|
26
|
+
name: string;
|
|
27
|
+
check: () => Promise<boolean>;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
interface HealthStatus {
|
|
31
|
+
status: "healthy" | "unhealthy";
|
|
32
|
+
timestamp: string;
|
|
33
|
+
checks: Record<string, {
|
|
34
|
+
status: "pass" | "fail";
|
|
35
|
+
message?: string;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Creates middleware that attaches the bus instance and correlation ID to context.
|
|
41
|
+
*/
|
|
42
|
+
declare function sagaBusMiddleware(options: SagaBusHonoOptions): MiddlewareHandler<SagaBusEnv>;
|
|
43
|
+
/**
|
|
44
|
+
* Error handler for saga-related errors.
|
|
45
|
+
* Use with app.onError(sagaErrorHandler())
|
|
46
|
+
*/
|
|
47
|
+
declare function sagaErrorHandler(): ErrorHandler<SagaBusEnv>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a health check handler.
|
|
51
|
+
*/
|
|
52
|
+
declare function createHealthHandler(options: HealthCheckOptions): (c: Context<SagaBusEnv>) => Promise<Response & hono.TypedResponse<{
|
|
53
|
+
status: "healthy" | "unhealthy";
|
|
54
|
+
timestamp: string;
|
|
55
|
+
checks: {
|
|
56
|
+
[x: string]: {
|
|
57
|
+
status: "pass" | "fail";
|
|
58
|
+
message?: string | undefined;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
}, 200 | 503, "json">>;
|
|
62
|
+
/**
|
|
63
|
+
* Creates a readiness check handler (alias for health).
|
|
64
|
+
*/
|
|
65
|
+
declare function createReadinessHandler(options: HealthCheckOptions): (c: Context<SagaBusEnv>) => Promise<Response & hono.TypedResponse<{
|
|
66
|
+
status: "healthy" | "unhealthy";
|
|
67
|
+
timestamp: string;
|
|
68
|
+
checks: {
|
|
69
|
+
[x: string]: {
|
|
70
|
+
status: "pass" | "fail";
|
|
71
|
+
message?: string | undefined;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
}, 200 | 503, "json">>;
|
|
75
|
+
|
|
76
|
+
export { type HealthCheckOptions, type HealthStatus, type SagaBusEnv, type SagaBusHonoOptions, createHealthHandler, createReadinessHandler, sagaBusMiddleware, sagaErrorHandler };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as hono from 'hono';
|
|
2
|
+
import { Env, MiddlewareHandler, ErrorHandler, Context } from 'hono';
|
|
3
|
+
import { Bus } from '@saga-bus/core';
|
|
4
|
+
|
|
5
|
+
interface SagaBusEnv extends Env {
|
|
6
|
+
Variables: {
|
|
7
|
+
bus: Bus;
|
|
8
|
+
correlationId: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
interface SagaBusHonoOptions {
|
|
12
|
+
/** The bus instance to attach */
|
|
13
|
+
bus: Bus;
|
|
14
|
+
/** Header name for correlation ID */
|
|
15
|
+
correlationIdHeader?: string;
|
|
16
|
+
/** Whether to generate correlation ID if not present */
|
|
17
|
+
generateCorrelationId?: boolean;
|
|
18
|
+
/** Custom correlation ID generator */
|
|
19
|
+
correlationIdGenerator?: () => string;
|
|
20
|
+
}
|
|
21
|
+
interface HealthCheckOptions {
|
|
22
|
+
/** The bus instance to check */
|
|
23
|
+
bus: Bus;
|
|
24
|
+
/** Additional health checks */
|
|
25
|
+
checks?: Array<{
|
|
26
|
+
name: string;
|
|
27
|
+
check: () => Promise<boolean>;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
interface HealthStatus {
|
|
31
|
+
status: "healthy" | "unhealthy";
|
|
32
|
+
timestamp: string;
|
|
33
|
+
checks: Record<string, {
|
|
34
|
+
status: "pass" | "fail";
|
|
35
|
+
message?: string;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Creates middleware that attaches the bus instance and correlation ID to context.
|
|
41
|
+
*/
|
|
42
|
+
declare function sagaBusMiddleware(options: SagaBusHonoOptions): MiddlewareHandler<SagaBusEnv>;
|
|
43
|
+
/**
|
|
44
|
+
* Error handler for saga-related errors.
|
|
45
|
+
* Use with app.onError(sagaErrorHandler())
|
|
46
|
+
*/
|
|
47
|
+
declare function sagaErrorHandler(): ErrorHandler<SagaBusEnv>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a health check handler.
|
|
51
|
+
*/
|
|
52
|
+
declare function createHealthHandler(options: HealthCheckOptions): (c: Context<SagaBusEnv>) => Promise<Response & hono.TypedResponse<{
|
|
53
|
+
status: "healthy" | "unhealthy";
|
|
54
|
+
timestamp: string;
|
|
55
|
+
checks: {
|
|
56
|
+
[x: string]: {
|
|
57
|
+
status: "pass" | "fail";
|
|
58
|
+
message?: string | undefined;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
}, 200 | 503, "json">>;
|
|
62
|
+
/**
|
|
63
|
+
* Creates a readiness check handler (alias for health).
|
|
64
|
+
*/
|
|
65
|
+
declare function createReadinessHandler(options: HealthCheckOptions): (c: Context<SagaBusEnv>) => Promise<Response & hono.TypedResponse<{
|
|
66
|
+
status: "healthy" | "unhealthy";
|
|
67
|
+
timestamp: string;
|
|
68
|
+
checks: {
|
|
69
|
+
[x: string]: {
|
|
70
|
+
status: "pass" | "fail";
|
|
71
|
+
message?: string | undefined;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
}, 200 | 503, "json">>;
|
|
75
|
+
|
|
76
|
+
export { type HealthCheckOptions, type HealthStatus, type SagaBusEnv, type SagaBusHonoOptions, createHealthHandler, createReadinessHandler, sagaBusMiddleware, sagaErrorHandler };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// src/middleware.ts
|
|
2
|
+
function generateId() {
|
|
3
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
4
|
+
const r = Math.random() * 16 | 0;
|
|
5
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
6
|
+
return v.toString(16);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
function sagaBusMiddleware(options) {
|
|
10
|
+
const {
|
|
11
|
+
bus,
|
|
12
|
+
correlationIdHeader = "x-correlation-id",
|
|
13
|
+
generateCorrelationId = true,
|
|
14
|
+
correlationIdGenerator = generateId
|
|
15
|
+
} = options;
|
|
16
|
+
return async (c, next) => {
|
|
17
|
+
c.set("bus", bus);
|
|
18
|
+
let correlationId = c.req.header(correlationIdHeader);
|
|
19
|
+
if (!correlationId && generateCorrelationId) {
|
|
20
|
+
correlationId = correlationIdGenerator();
|
|
21
|
+
}
|
|
22
|
+
if (correlationId) {
|
|
23
|
+
c.set("correlationId", correlationId);
|
|
24
|
+
c.header(correlationIdHeader, correlationId);
|
|
25
|
+
}
|
|
26
|
+
await next();
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function sagaErrorHandler() {
|
|
30
|
+
return (err, c) => {
|
|
31
|
+
if (err instanceof Error) {
|
|
32
|
+
if (err.name === "SagaTimeoutError") {
|
|
33
|
+
return c.json(
|
|
34
|
+
{
|
|
35
|
+
error: "Saga Timeout",
|
|
36
|
+
message: err.message,
|
|
37
|
+
correlationId: c.get("correlationId")
|
|
38
|
+
},
|
|
39
|
+
408
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
if (err.name === "ConcurrencyError") {
|
|
43
|
+
return c.json(
|
|
44
|
+
{
|
|
45
|
+
error: "Concurrency Conflict",
|
|
46
|
+
message: err.message,
|
|
47
|
+
correlationId: c.get("correlationId")
|
|
48
|
+
},
|
|
49
|
+
409
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return c.json(
|
|
54
|
+
{
|
|
55
|
+
error: "Internal Server Error",
|
|
56
|
+
message: err instanceof Error ? err.message : "Unknown error",
|
|
57
|
+
correlationId: c.get("correlationId")
|
|
58
|
+
},
|
|
59
|
+
500
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/health.ts
|
|
65
|
+
function createHealthHandler(options) {
|
|
66
|
+
const { bus, checks = [] } = options;
|
|
67
|
+
return async (c) => {
|
|
68
|
+
const healthStatus = {
|
|
69
|
+
status: "healthy",
|
|
70
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
71
|
+
checks: {}
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
if (bus) {
|
|
75
|
+
healthStatus.checks.bus = { status: "pass" };
|
|
76
|
+
} else {
|
|
77
|
+
throw new Error("Bus not available");
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
healthStatus.status = "unhealthy";
|
|
81
|
+
healthStatus.checks.bus = {
|
|
82
|
+
status: "fail",
|
|
83
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
for (const check of checks) {
|
|
87
|
+
try {
|
|
88
|
+
const result = await check.check();
|
|
89
|
+
healthStatus.checks[check.name] = {
|
|
90
|
+
status: result ? "pass" : "fail"
|
|
91
|
+
};
|
|
92
|
+
if (!result) {
|
|
93
|
+
healthStatus.status = "unhealthy";
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
healthStatus.status = "unhealthy";
|
|
97
|
+
healthStatus.checks[check.name] = {
|
|
98
|
+
status: "fail",
|
|
99
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const statusCode = healthStatus.status === "healthy" ? 200 : 503;
|
|
104
|
+
return c.json(healthStatus, statusCode);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function createReadinessHandler(options) {
|
|
108
|
+
return createHealthHandler(options);
|
|
109
|
+
}
|
|
110
|
+
export {
|
|
111
|
+
createHealthHandler,
|
|
112
|
+
createReadinessHandler,
|
|
113
|
+
sagaBusMiddleware,
|
|
114
|
+
sagaErrorHandler
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts","../src/health.ts"],"sourcesContent":["import type { MiddlewareHandler, ErrorHandler } from \"hono\";\nimport type { SagaBusEnv, SagaBusHonoOptions } from \"./types.js\";\n\n// Simple UUID generator for edge compatibility (no crypto.randomUUID dependency)\nfunction generateId(): string {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n/**\n * Creates middleware that attaches the bus instance and correlation ID to context.\n */\nexport function sagaBusMiddleware(\n options: SagaBusHonoOptions\n): MiddlewareHandler<SagaBusEnv> {\n const {\n bus,\n correlationIdHeader = \"x-correlation-id\",\n generateCorrelationId = true,\n correlationIdGenerator = generateId,\n } = options;\n\n return async (c, next) => {\n // Attach bus to context\n c.set(\"bus\", bus);\n\n // Extract or generate correlation ID\n let correlationId = c.req.header(correlationIdHeader);\n\n if (!correlationId && generateCorrelationId) {\n correlationId = correlationIdGenerator();\n }\n\n if (correlationId) {\n c.set(\"correlationId\", correlationId);\n c.header(correlationIdHeader, correlationId);\n }\n\n await next();\n };\n}\n\n/**\n * Error handler for saga-related errors.\n * Use with app.onError(sagaErrorHandler())\n */\nexport function sagaErrorHandler(): ErrorHandler<SagaBusEnv> {\n return (err, c) => {\n if (err instanceof Error) {\n if (err.name === \"SagaTimeoutError\") {\n return c.json(\n {\n error: \"Saga Timeout\",\n message: err.message,\n correlationId: c.get(\"correlationId\"),\n },\n 408\n );\n }\n\n if (err.name === \"ConcurrencyError\") {\n return c.json(\n {\n error: \"Concurrency Conflict\",\n message: err.message,\n correlationId: c.get(\"correlationId\"),\n },\n 409\n );\n }\n }\n\n // Return generic error for other cases\n return c.json(\n {\n error: \"Internal Server Error\",\n message: err instanceof Error ? err.message : \"Unknown error\",\n correlationId: c.get(\"correlationId\"),\n },\n 500\n );\n };\n}\n","import type { Context } from \"hono\";\nimport type { HealthCheckOptions, HealthStatus, SagaBusEnv } from \"./types.js\";\n\n/**\n * Creates a health check handler.\n */\nexport function createHealthHandler(options: HealthCheckOptions) {\n const { bus, checks = [] } = options;\n\n return async (c: Context<SagaBusEnv>) => {\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 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 return c.json(healthStatus, statusCode);\n };\n}\n\n/**\n * Creates a readiness check handler (alias for health).\n */\nexport function createReadinessHandler(options: HealthCheckOptions) {\n return createHealthHandler(options);\n}\n"],"mappings":";AAIA,SAAS,aAAqB;AAC5B,SAAO,uCAAuC,QAAQ,SAAS,CAAC,MAAM;AACpE,UAAM,IAAK,KAAK,OAAO,IAAI,KAAM;AACjC,UAAM,IAAI,MAAM,MAAM,IAAK,IAAI,IAAO;AACtC,WAAO,EAAE,SAAS,EAAE;AAAA,EACtB,CAAC;AACH;AAKO,SAAS,kBACd,SAC+B;AAC/B,QAAM;AAAA,IACJ;AAAA,IACA,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,yBAAyB;AAAA,EAC3B,IAAI;AAEJ,SAAO,OAAO,GAAG,SAAS;AAExB,MAAE,IAAI,OAAO,GAAG;AAGhB,QAAI,gBAAgB,EAAE,IAAI,OAAO,mBAAmB;AAEpD,QAAI,CAAC,iBAAiB,uBAAuB;AAC3C,sBAAgB,uBAAuB;AAAA,IACzC;AAEA,QAAI,eAAe;AACjB,QAAE,IAAI,iBAAiB,aAAa;AACpC,QAAE,OAAO,qBAAqB,aAAa;AAAA,IAC7C;AAEA,UAAM,KAAK;AAAA,EACb;AACF;AAMO,SAAS,mBAA6C;AAC3D,SAAO,CAAC,KAAK,MAAM;AACjB,QAAI,eAAe,OAAO;AACxB,UAAI,IAAI,SAAS,oBAAoB;AACnC,eAAO,EAAE;AAAA,UACP;AAAA,YACE,OAAO;AAAA,YACP,SAAS,IAAI;AAAA,YACb,eAAe,EAAE,IAAI,eAAe;AAAA,UACtC;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,UAAI,IAAI,SAAS,oBAAoB;AACnC,eAAO,EAAE;AAAA,UACP;AAAA,YACE,OAAO;AAAA,YACP,SAAS,IAAI;AAAA,YACb,eAAe,EAAE,IAAI,eAAe;AAAA,UACtC;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,WAAO,EAAE;AAAA,MACP;AAAA,QACE,OAAO;AAAA,QACP,SAAS,eAAe,QAAQ,IAAI,UAAU;AAAA,QAC9C,eAAe,EAAE,IAAI,eAAe;AAAA,MACtC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;;;AC/EO,SAAS,oBAAoB,SAA6B;AAC/D,QAAM,EAAE,KAAK,SAAS,CAAC,EAAE,IAAI;AAE7B,SAAO,OAAO,MAA2B;AACvC,UAAM,eAA6B;AAAA,MACjC,QAAQ;AAAA,MACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,QAAQ,CAAC;AAAA,IACX;AAGA,QAAI;AACF,UAAI,KAAK;AACP,qBAAa,OAAO,MAAM,EAAE,QAAQ,OAAO;AAAA,MAC7C,OAAO;AACL,cAAM,IAAI,MAAM,mBAAmB;AAAA,MACrC;AAAA,IACF,SAAS,OAAO;AACd,mBAAa,SAAS;AACtB,mBAAa,OAAO,MAAM;AAAA,QACxB,QAAQ;AAAA,QACR,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MACpD;AAAA,IACF;AAGA,eAAW,SAAS,QAAQ;AAC1B,UAAI;AACF,cAAM,SAAS,MAAM,MAAM,MAAM;AACjC,qBAAa,OAAO,MAAM,IAAI,IAAI;AAAA,UAChC,QAAQ,SAAS,SAAS;AAAA,QAC5B;AACA,YAAI,CAAC,QAAQ;AACX,uBAAa,SAAS;AAAA,QACxB;AAAA,MACF,SAAS,OAAO;AACd,qBAAa,SAAS;AACtB,qBAAa,OAAO,MAAM,IAAI,IAAI;AAAA,UAChC,QAAQ;AAAA,UACR,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,aAAa,WAAW,YAAY,MAAM;AAC7D,WAAO,EAAE,KAAK,cAAc,UAAU;AAAA,EACxC;AACF;AAKO,SAAS,uBAAuB,SAA6B;AAClE,SAAO,oBAAoB,OAAO;AACpC;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@saga-bus/hono",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Hono integration for saga-bus (edge runtime compatible)",
|
|
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/hono"
|
|
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
|
+
"hono",
|
|
36
|
+
"middleware",
|
|
37
|
+
"edge",
|
|
38
|
+
"cloudflare-workers",
|
|
39
|
+
"deno",
|
|
40
|
+
"bun"
|
|
41
|
+
],
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@saga-bus/core": "0.1.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"hono": "^4.6.0",
|
|
47
|
+
"tsup": "^8.0.0",
|
|
48
|
+
"typescript": "^5.9.2",
|
|
49
|
+
"vitest": "^3.0.0",
|
|
50
|
+
"@repo/eslint-config": "0.0.0",
|
|
51
|
+
"@repo/typescript-config": "0.0.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@saga-bus/core": ">=0.1.1",
|
|
55
|
+
"hono": ">=4.0.0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsup",
|
|
59
|
+
"dev": "tsup --watch",
|
|
60
|
+
"lint": "eslint src/",
|
|
61
|
+
"check-types": "tsc --noEmit",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"test:watch": "vitest"
|
|
64
|
+
}
|
|
65
|
+
}
|