serverstruct 1.0.0 → 1.2.0
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/.claude/settings.local.json +8 -0
- package/OPENAPI.md +286 -0
- package/OTEL.md +208 -0
- package/README.md +224 -81
- package/dist/index.cjs +193 -24
- package/dist/index.d.cts +175 -23
- package/dist/index.d.mts +175 -23
- package/dist/index.mjs +188 -24
- package/dist/openapi.cjs +242 -0
- package/dist/openapi.d.cts +241 -0
- package/dist/openapi.d.mts +241 -0
- package/dist/openapi.mjs +231 -0
- package/dist/openapi.scalar.cjs +13 -0
- package/dist/openapi.scalar.d.cts +8 -0
- package/dist/openapi.scalar.d.mts +8 -0
- package/dist/openapi.scalar.mjs +13 -0
- package/package.json +46 -10
- package/tsdown.config.mts +11 -0
package/README.md
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
⚡️ Typesafe and modular servers with [H3](https://github.com/unjs/h3).
|
|
4
4
|
|
|
5
|
-
Serverstruct provides simple helpers for building modular
|
|
5
|
+
Serverstruct provides simple helpers for building modular H3 applications with dependency injection using [getbox](https://github.com/eriicafes/getbox).
|
|
6
|
+
|
|
7
|
+
## Integrations
|
|
8
|
+
|
|
9
|
+
- [OpenAPI](./OPENAPI.md) - Typesafe OpenAPI operations with Zod schema validation.
|
|
10
|
+
- [OpenTelemetry](./OTEL.md) - Distributed tracing middleware for HTTP requests.
|
|
6
11
|
|
|
7
12
|
## Installation
|
|
8
13
|
|
|
@@ -13,173 +18,311 @@ npm i serverstruct h3 getbox
|
|
|
13
18
|
## Quick Start
|
|
14
19
|
|
|
15
20
|
```typescript
|
|
16
|
-
import { application } from "serverstruct";
|
|
21
|
+
import { application, serve } from "serverstruct";
|
|
17
22
|
|
|
18
23
|
const app = application((app) => {
|
|
19
24
|
app.get("/", () => "Hello world!");
|
|
20
25
|
});
|
|
21
26
|
|
|
22
|
-
|
|
27
|
+
serve(app, { port: 3000 });
|
|
23
28
|
```
|
|
24
29
|
|
|
25
|
-
##
|
|
30
|
+
## Application
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
`application()` creates an H3 instance and a Box instance for dependency injection.
|
|
33
|
+
You can pass a Box instance to share dependencies across applications (see [Box Instance](#box-instance)).
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
import { application } from "serverstruct";
|
|
35
|
+
You can mount other apps using `app.mount()`:
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
```typescript
|
|
38
|
+
import { H3 } from "h3";
|
|
39
|
+
import { application, serve } from "serverstruct";
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
users.push(body);
|
|
40
|
-
return body;
|
|
41
|
-
});
|
|
41
|
+
// Create a sub application
|
|
42
|
+
const usersApp = application((app) => {
|
|
43
|
+
app.get("/", () => ["Alice", "Bob"]);
|
|
42
44
|
});
|
|
43
45
|
|
|
44
|
-
//
|
|
46
|
+
// Create a regular H3 instance
|
|
47
|
+
const docsApp = new H3().get("/", () => "API Documentation");
|
|
48
|
+
|
|
49
|
+
// Mount in main app
|
|
45
50
|
const app = application((app) => {
|
|
46
|
-
app.get("/
|
|
51
|
+
app.get("/", () => "Hello world!");
|
|
47
52
|
app.mount("/users", usersApp);
|
|
53
|
+
app.mount("/docs", docsApp);
|
|
48
54
|
});
|
|
49
55
|
|
|
50
|
-
|
|
56
|
+
serve(app, { port: 3000 });
|
|
51
57
|
```
|
|
52
58
|
|
|
53
|
-
|
|
59
|
+
When an app is mounted, its middlewares and routes are copied to the main app in place with middlewares scoped to the base path.
|
|
60
|
+
|
|
61
|
+
Both `application()` and `controller()` can return a custom H3 instance:
|
|
54
62
|
|
|
55
63
|
```typescript
|
|
56
64
|
import { H3 } from "h3";
|
|
57
65
|
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
onError: (error) => {
|
|
61
|
-
console.error(error);
|
|
66
|
+
const customApp = application(() => {
|
|
67
|
+
const app = new H3({
|
|
68
|
+
onError: (error, event) => {
|
|
69
|
+
console.error("Error:", error);
|
|
62
70
|
},
|
|
63
71
|
});
|
|
64
|
-
|
|
65
|
-
return
|
|
72
|
+
app.get("/", () => "Hello from custom app!");
|
|
73
|
+
return app;
|
|
66
74
|
});
|
|
67
75
|
```
|
|
68
76
|
|
|
69
|
-
## Controllers
|
|
77
|
+
## Controllers
|
|
70
78
|
|
|
71
|
-
|
|
79
|
+
Controllers are apps that are initialized with a parent Box instance, sharing the same dependency container. Use `controller()` to create H3 app constructors:
|
|
72
80
|
|
|
73
81
|
```typescript
|
|
74
82
|
import { application, controller } from "serverstruct";
|
|
75
83
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const users: User[] = [];
|
|
84
|
+
class UserStore {
|
|
85
|
+
public users: User[] = [];
|
|
79
86
|
|
|
80
|
-
|
|
87
|
+
add(user: User) {
|
|
88
|
+
this.users.push(user);
|
|
89
|
+
return user;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Create a controller
|
|
94
|
+
const usersController = controller((app, box) => {
|
|
95
|
+
const store = box.get(UserStore);
|
|
96
|
+
|
|
97
|
+
app.get("/", () => store.users);
|
|
81
98
|
app.post("/", async (event) => {
|
|
82
|
-
const body = await
|
|
83
|
-
|
|
84
|
-
return body;
|
|
99
|
+
const body = await readBody(event);
|
|
100
|
+
return store.add(body);
|
|
85
101
|
});
|
|
86
102
|
});
|
|
87
103
|
|
|
88
104
|
// Use it in your main app
|
|
89
105
|
const app = application((app, box) => {
|
|
90
|
-
|
|
106
|
+
const store = box.get(UserStore);
|
|
107
|
+
|
|
108
|
+
app.get("/count", () => ({
|
|
109
|
+
users: store.users.length,
|
|
110
|
+
}));
|
|
91
111
|
app.mount("/users", box.new(usersController));
|
|
92
112
|
});
|
|
93
113
|
|
|
94
|
-
|
|
114
|
+
serve(app, { port: 3000 });
|
|
95
115
|
```
|
|
96
116
|
|
|
97
|
-
|
|
117
|
+
## Handlers
|
|
98
118
|
|
|
99
|
-
|
|
119
|
+
Use `handler()` to create H3 handler constructors:
|
|
100
120
|
|
|
101
|
-
|
|
121
|
+
```typescript
|
|
122
|
+
import { application, handler } from "serverstruct";
|
|
102
123
|
|
|
103
|
-
|
|
124
|
+
// Define a handler
|
|
125
|
+
const getUserHandler = handler((event, box) => {
|
|
126
|
+
const store = box.get(UserStore);
|
|
127
|
+
|
|
128
|
+
const id = event.context.params?.id;
|
|
129
|
+
return store.users.find((user) => user.id === id);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Use it in your app
|
|
133
|
+
const app = application((app, box) => {
|
|
134
|
+
app.get("/users/:id", box.new(getUserHandler));
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Event Handlers
|
|
139
|
+
|
|
140
|
+
Use `eventHandler()` to create H3 handler constructors with additional options like meta and middleware:
|
|
104
141
|
|
|
105
142
|
```typescript
|
|
106
|
-
import { application,
|
|
143
|
+
import { application, eventHandler } from "serverstruct";
|
|
144
|
+
|
|
145
|
+
// Define an event handler with additional options
|
|
146
|
+
const getUserHandler = eventHandler((box) => ({
|
|
147
|
+
handler(event) {
|
|
148
|
+
const store = box.get(UserStore);
|
|
149
|
+
|
|
150
|
+
const id = event.context.params?.id;
|
|
151
|
+
return store.users.find((user) => user.id === id);
|
|
152
|
+
},
|
|
153
|
+
meta: { auth: true },
|
|
154
|
+
middleware: [],
|
|
155
|
+
}));
|
|
156
|
+
|
|
157
|
+
// Use it in your app
|
|
158
|
+
const app = application((app, box) => {
|
|
159
|
+
app.get("/users/:id", box.new(getUserHandler));
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Middleware
|
|
164
|
+
|
|
165
|
+
Use `middleware()` to create H3 middleware constructors:
|
|
107
166
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
users: User[] = [];
|
|
167
|
+
```typescript
|
|
168
|
+
import { application, middleware } from "serverstruct";
|
|
111
169
|
|
|
112
|
-
|
|
113
|
-
|
|
170
|
+
class Logger {
|
|
171
|
+
log(message: string) {
|
|
172
|
+
console.log(message);
|
|
173
|
+
}
|
|
114
174
|
}
|
|
115
175
|
|
|
116
|
-
//
|
|
117
|
-
const
|
|
118
|
-
const
|
|
176
|
+
// Define a middleware
|
|
177
|
+
const logMiddleware = middleware((event, next, box) => {
|
|
178
|
+
const logger = box.get(Logger);
|
|
179
|
+
logger.log("Request received");
|
|
180
|
+
});
|
|
119
181
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
182
|
+
// Use it in your app
|
|
183
|
+
const app = application((app, box) => {
|
|
184
|
+
app.use(box.get(logMiddleware));
|
|
185
|
+
app.get("/", () => "Hello world!");
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
All middlewares defined with `app.use()` are global and execute before the matched handler in the exact order they are defined.
|
|
190
|
+
|
|
191
|
+
## Error Handling
|
|
192
|
+
|
|
193
|
+
Error handlers are middleware that catch errors after calling `await next()`.
|
|
194
|
+
|
|
195
|
+
The last error handler defined executes before earlier ones. The error bubbles through each error handler until a response is returned or the default error response is sent.
|
|
196
|
+
|
|
197
|
+
Use H3's `onError` helper to define error handlers:
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import { onError } from "h3";
|
|
201
|
+
import { application } from "serverstruct";
|
|
202
|
+
|
|
203
|
+
const app = application((app) => {
|
|
204
|
+
app.use(
|
|
205
|
+
onError((error) => {
|
|
206
|
+
console.log("Error:", error);
|
|
207
|
+
}),
|
|
208
|
+
);
|
|
209
|
+
app.get("/", () => {
|
|
210
|
+
throw new Error("Oops");
|
|
125
211
|
});
|
|
126
212
|
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
When the error handler needs access to the Box, wrap it with `middleware()`:
|
|
127
216
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
217
|
+
```typescript
|
|
218
|
+
import { onError } from "h3";
|
|
219
|
+
import { application, middleware } from "serverstruct";
|
|
131
220
|
|
|
132
|
-
|
|
221
|
+
const errorHandler = middleware((event, next, box) => {
|
|
222
|
+
return onError((error) => {
|
|
223
|
+
console.log("Error:", error);
|
|
224
|
+
});
|
|
133
225
|
});
|
|
134
226
|
|
|
135
227
|
const app = application((app, box) => {
|
|
136
|
-
app.
|
|
137
|
-
app.
|
|
228
|
+
app.use(box.get(errorHandler));
|
|
229
|
+
app.get("/", () => {
|
|
230
|
+
throw new Error("Oops");
|
|
231
|
+
});
|
|
138
232
|
});
|
|
139
|
-
|
|
140
|
-
await app.serve({ port: 3000 });
|
|
141
233
|
```
|
|
142
234
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
## Middleware
|
|
235
|
+
### Not Found Routes
|
|
146
236
|
|
|
147
|
-
|
|
237
|
+
To catch not found routes, define a catch-all handler and return the desired error:
|
|
148
238
|
|
|
149
239
|
```typescript
|
|
150
|
-
|
|
151
|
-
// Global middleware
|
|
152
|
-
app.use(() => console.log("Request received"));
|
|
240
|
+
import { H3Error } from "h3";
|
|
153
241
|
|
|
242
|
+
const app = application((app) => {
|
|
154
243
|
app.get("/", () => "Hello world!");
|
|
244
|
+
app.all("**", () => new H3Error({ status: 404, message: "Not found" }));
|
|
155
245
|
});
|
|
156
246
|
```
|
|
157
247
|
|
|
158
|
-
|
|
248
|
+
Mounted apps can define their own not found handlers:
|
|
159
249
|
|
|
160
250
|
```typescript
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
app.
|
|
251
|
+
const usersApp = application((app) => {
|
|
252
|
+
app.get("/", () => ["Alice", "Bob"]);
|
|
253
|
+
app.all(
|
|
254
|
+
"**",
|
|
255
|
+
() => new H3Error({ status: 404, message: "User route not found" }),
|
|
256
|
+
);
|
|
257
|
+
});
|
|
164
258
|
|
|
165
|
-
|
|
166
|
-
app.
|
|
259
|
+
const app = application((app) => {
|
|
260
|
+
app.mount("/users", usersApp);
|
|
261
|
+
app.all("**", () => new H3Error({ status: 404, message: "Not found" }));
|
|
167
262
|
});
|
|
168
263
|
```
|
|
169
264
|
|
|
170
|
-
##
|
|
265
|
+
## Box Instance
|
|
171
266
|
|
|
172
|
-
|
|
267
|
+
By default, `application()` creates a new Box instance. Pass a Box instance to reuse it:
|
|
173
268
|
|
|
174
269
|
```typescript
|
|
175
270
|
import { Box } from "getbox";
|
|
271
|
+
import { application, serve } from "serverstruct";
|
|
176
272
|
|
|
177
273
|
const box = new Box();
|
|
178
274
|
|
|
179
|
-
|
|
180
|
-
|
|
275
|
+
const usersApp = application((app, box) => {
|
|
276
|
+
const store = box.get(UserStore);
|
|
277
|
+
app.get("/", () => store.users);
|
|
278
|
+
}, box);
|
|
181
279
|
|
|
182
280
|
const app = application((app, box) => {
|
|
183
|
-
|
|
281
|
+
const store = box.get(UserStore);
|
|
282
|
+
app.get("/count", () => store.users.length);
|
|
283
|
+
app.mount("/users", usersApp);
|
|
184
284
|
}, box);
|
|
285
|
+
|
|
286
|
+
serve(app, { port: 3000 });
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Context
|
|
290
|
+
|
|
291
|
+
`context()` creates a request-scoped, type-safe store for per-request values.
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
import { application, context } from "serverstruct";
|
|
295
|
+
|
|
296
|
+
interface User {
|
|
297
|
+
id: string;
|
|
298
|
+
name: string;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Create a context store
|
|
302
|
+
const userContext = context<User>();
|
|
303
|
+
|
|
304
|
+
const app = application((app) => {
|
|
305
|
+
// Set context in middleware
|
|
306
|
+
app.use((event) => {
|
|
307
|
+
const user = { id: "123", name: "Alice" };
|
|
308
|
+
userContext.set(event, user);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Access context in handlers
|
|
312
|
+
app.get("/profile", (event) => {
|
|
313
|
+
// Optional access - returns undefined if not set
|
|
314
|
+
const maybeUser = userContext.lookup(event);
|
|
315
|
+
|
|
316
|
+
// Safe access - throws if not set
|
|
317
|
+
const user = userContext.get(event);
|
|
318
|
+
|
|
319
|
+
return { profile: user };
|
|
320
|
+
});
|
|
321
|
+
});
|
|
185
322
|
```
|
|
323
|
+
|
|
324
|
+
### Context Methods
|
|
325
|
+
|
|
326
|
+
- `set(event, value)` - Store a value for the current request
|
|
327
|
+
- `get(event)` - Retrieve the value for the current request (throws if not found)
|
|
328
|
+
- `lookup(event)` - Retrieve the value or `undefined` if not found
|
package/dist/index.cjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
let h3 = require("h3");
|
|
2
1
|
let getbox = require("getbox");
|
|
2
|
+
let h3 = require("h3");
|
|
3
3
|
|
|
4
4
|
//#region src/index.ts
|
|
5
5
|
/**
|
|
6
|
-
* Creates an h3 application
|
|
6
|
+
* Creates an h3 application.
|
|
7
7
|
*
|
|
8
|
-
* @param
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* @param setup - Function that configures the app. Receives a fresh H3 instance
|
|
9
|
+
* and Box instance. Can add routes to the provided app, or create
|
|
10
|
+
* and return a new H3 instance.
|
|
11
11
|
* @param box - Optional Box instance. If not provided, creates a new one.
|
|
12
|
-
* @returns Object with `app` (H3 instance) and `serve` method.
|
|
12
|
+
* @returns Object with `app` (H3 instance), `box` (Box instance), and `serve` method.
|
|
13
13
|
*
|
|
14
14
|
* @example
|
|
15
15
|
* ```typescript
|
|
@@ -30,28 +30,33 @@ let getbox = require("getbox");
|
|
|
30
30
|
* await app.serve({ port: 3000 });
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
|
-
function application(
|
|
33
|
+
function application(setup, box = new getbox.Box()) {
|
|
34
34
|
const defaultApp = new h3.H3();
|
|
35
|
-
const app =
|
|
35
|
+
const app = setup(defaultApp, box) || defaultApp;
|
|
36
36
|
return {
|
|
37
37
|
app,
|
|
38
|
+
box,
|
|
38
39
|
serve: (options) => (0, h3.serve)(app, options)
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
42
|
-
* Creates
|
|
43
|
-
*
|
|
44
|
-
* Use `box.new(controller)` to create fresh controller instances.
|
|
45
|
-
* Controllers can use `box.get()` to access shared dependencies.
|
|
43
|
+
* Creates an h3 app constructor.
|
|
46
44
|
*
|
|
47
|
-
* @param
|
|
48
|
-
* @returns A Constructor that
|
|
45
|
+
* @param setup - Function that configures the app.
|
|
46
|
+
* @returns A Constructor that produces an h3 app.
|
|
49
47
|
*
|
|
50
48
|
* @example
|
|
51
49
|
* ```typescript
|
|
50
|
+
* import { application, controller } from "serverstruct";
|
|
51
|
+
*
|
|
52
|
+
* class Database {
|
|
53
|
+
* getUsers() { return ["Alice", "Bob"]; }
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
52
56
|
* // Define a controller
|
|
53
57
|
* const usersController = controller((app, box) => {
|
|
54
|
-
*
|
|
58
|
+
* const db = box.get(Database);
|
|
59
|
+
* app.get("/", () => db.getUsers());
|
|
55
60
|
* });
|
|
56
61
|
*
|
|
57
62
|
* // Use it in your app
|
|
@@ -59,24 +64,188 @@ function application(fn, box = new getbox.Box()) {
|
|
|
59
64
|
* app.mount("/users", box.new(usersController));
|
|
60
65
|
* });
|
|
61
66
|
* ```
|
|
67
|
+
*/
|
|
68
|
+
function controller(setup) {
|
|
69
|
+
return (0, getbox.factory)((box) => application(setup, box).app);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates a handler constructor.
|
|
73
|
+
*
|
|
74
|
+
* @param setup - Handler function that receives the event and Box instance.
|
|
75
|
+
* @returns A Constructor that produces an h3 handler.
|
|
62
76
|
*
|
|
63
77
|
* @example
|
|
64
78
|
* ```typescript
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
79
|
+
* import { application, handler } from "serverstruct";
|
|
80
|
+
*
|
|
81
|
+
* class UserService {
|
|
82
|
+
* getUser(id: string) { return { id, name: "Alice" }; }
|
|
68
83
|
* }
|
|
69
84
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
85
|
+
* // Define a handler
|
|
86
|
+
* const getUserHandler = handler((event, box) => {
|
|
87
|
+
* const userService = box.get(UserService);
|
|
88
|
+
* const id = event.context.params?.id;
|
|
89
|
+
* return userService.getUser(id);
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* // Use it in your app
|
|
93
|
+
* const app = application((app, box) => {
|
|
94
|
+
* app.get("/users/:id", box.get(getUserHandler));
|
|
95
|
+
* });
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
function handler(setup) {
|
|
99
|
+
return (0, getbox.factory)((box) => (0, h3.defineHandler)((event) => setup(event, box)));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Creates an event handler constructor from a setup function.
|
|
103
|
+
*
|
|
104
|
+
* @param setup - Function that receives Box instance and returns an event handler object.
|
|
105
|
+
* @returns A Constructor that produces an h3 event handler.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* import { application, eventHandler } from "serverstruct";
|
|
110
|
+
*
|
|
111
|
+
* class UserService {
|
|
112
|
+
* getUser(id: string) { return { id, name: "Alice" }; }
|
|
113
|
+
* }
|
|
114
|
+
*
|
|
115
|
+
* // Define an event handler
|
|
116
|
+
* const getUserHandler = eventHandler((box) => ({
|
|
117
|
+
* handler(event) {
|
|
118
|
+
* const userService = box.get(UserService);
|
|
119
|
+
* const id = event.context.params?.id;
|
|
120
|
+
* return userService.getUser(id);
|
|
121
|
+
* },
|
|
122
|
+
* meta: { auth: true }
|
|
123
|
+
* }));
|
|
124
|
+
*
|
|
125
|
+
* // Use it in your app
|
|
126
|
+
* const app = application((app, box) => {
|
|
127
|
+
* app.get("/users/:id", box.get(getUserHandler));
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
function eventHandler(setup) {
|
|
132
|
+
return (0, getbox.factory)((box) => (0, h3.defineHandler)(setup(box)));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Creates a middleware constructor.
|
|
136
|
+
*
|
|
137
|
+
* @param setup - Middleware function that receives the event, next function, and Box instance.
|
|
138
|
+
* @returns A Constructor that produces an h3 middleware.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* import { application, middleware } from "serverstruct";
|
|
143
|
+
*
|
|
144
|
+
* class AuthService {
|
|
145
|
+
* validateToken(token: string) { return token === "valid"; }
|
|
146
|
+
* }
|
|
147
|
+
*
|
|
148
|
+
* // Define a middleware
|
|
149
|
+
* const authMiddleware = middleware((event, next, box) => {
|
|
150
|
+
* const authService = box.get(AuthService);
|
|
151
|
+
* const token = event.headers.get("authorization");
|
|
152
|
+
* if (!token || !authService.validateToken(token)) {
|
|
153
|
+
* throw new Error("Unauthorized");
|
|
154
|
+
* }
|
|
155
|
+
* });
|
|
156
|
+
*
|
|
157
|
+
* // Use it in your app
|
|
158
|
+
* const app = application((app, box) => {
|
|
159
|
+
* app.use(box.get(authMiddleware));
|
|
160
|
+
* app.get("/", () => "Hello world!");
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
function middleware(setup) {
|
|
165
|
+
return (0, getbox.factory)((box) => (0, h3.defineMiddleware)((event, next) => setup(event, next, box)));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* A request-scoped context store for associating values with H3 events.
|
|
169
|
+
*
|
|
170
|
+
* Each request gets its own isolated context that is automatically cleaned up
|
|
171
|
+
* when the request completes. Uses a WeakMap internally to ensure values are
|
|
172
|
+
* garbage collected with their events.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* import { application, Context } from "serverstruct";
|
|
177
|
+
*
|
|
178
|
+
* const userContext = new Context<User>();
|
|
179
|
+
*
|
|
180
|
+
* const app = application((app) => {
|
|
181
|
+
* app.use((event) => {
|
|
182
|
+
* userContext.set(event, { id: "123", name: "Alice" });
|
|
183
|
+
* });
|
|
184
|
+
* app.get("/user", (event) => {
|
|
185
|
+
* const user = userContext.get(event);
|
|
186
|
+
* return user;
|
|
187
|
+
* });
|
|
188
|
+
* });
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
var Context = class {
|
|
192
|
+
#map = /* @__PURE__ */ new WeakMap();
|
|
193
|
+
/**
|
|
194
|
+
* Sets a value for the given event.
|
|
195
|
+
*/
|
|
196
|
+
set(event, value) {
|
|
197
|
+
this.#map.set(event, value);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Gets the value for the given event.
|
|
201
|
+
* @throws Error if no value is set for the event.
|
|
202
|
+
*/
|
|
203
|
+
get(event) {
|
|
204
|
+
if (this.#map.has(event)) return this.#map.get(event);
|
|
205
|
+
throw new Error("context not found");
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Gets the value for the given event, or undefined if not set.
|
|
209
|
+
*/
|
|
210
|
+
lookup(event) {
|
|
211
|
+
return this.#map.get(event);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Creates a request-scoped context store for associating values with H3 events.
|
|
216
|
+
*
|
|
217
|
+
* Each request gets its own isolated context that is automatically cleaned up
|
|
218
|
+
* when the request completes. Uses a WeakMap internally to ensure values are
|
|
219
|
+
* garbage collected with their events.
|
|
220
|
+
*
|
|
221
|
+
* @returns A Context instance.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* import { application, context } from "serverstruct";
|
|
226
|
+
*
|
|
227
|
+
* const userContext = context<User>();
|
|
228
|
+
*
|
|
229
|
+
* const app = application((app) => {
|
|
230
|
+
* app.use((event) => {
|
|
231
|
+
* userContext.set(event, { id: "123", name: "Alice" });
|
|
232
|
+
* });
|
|
233
|
+
* app.get("/user", (event) => {
|
|
234
|
+
* const user = userContext.get(event);
|
|
235
|
+
* return user;
|
|
236
|
+
* });
|
|
73
237
|
* });
|
|
74
238
|
* ```
|
|
75
239
|
*/
|
|
76
|
-
function
|
|
77
|
-
return
|
|
240
|
+
function context() {
|
|
241
|
+
return new Context();
|
|
78
242
|
}
|
|
79
243
|
|
|
80
244
|
//#endregion
|
|
245
|
+
exports.Context = Context;
|
|
81
246
|
exports.application = application;
|
|
82
|
-
exports.
|
|
247
|
+
exports.context = context;
|
|
248
|
+
exports.controller = controller;
|
|
249
|
+
exports.eventHandler = eventHandler;
|
|
250
|
+
exports.handler = handler;
|
|
251
|
+
exports.middleware = middleware;
|