serverstruct 1.0.0 → 1.1.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/README.md +135 -46
- 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/package.json +8 -8
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ const app = application((app) => {
|
|
|
22
22
|
app.serve({ port: 3000 });
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Apps
|
|
26
26
|
|
|
27
27
|
Create modular h3 apps and mount them together:
|
|
28
28
|
|
|
@@ -66,9 +66,26 @@ const app = application(() => {
|
|
|
66
66
|
});
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
### Accessing the Box Instance
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
The `application()` function creates a new Box instance by default and returns it along with `app` and `serve`. You can access the box instance to retrieve dependencies:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { constant } from "getbox";
|
|
75
|
+
|
|
76
|
+
const Port = constant(5000);
|
|
77
|
+
|
|
78
|
+
const { box, serve } = application((app, box) => {
|
|
79
|
+
app.get("/", () => "Hello world!");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const port = box.get(Port);
|
|
83
|
+
serve({ port });
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Controllers
|
|
87
|
+
|
|
88
|
+
Use `controller()` to create h3 app constructors:
|
|
72
89
|
|
|
73
90
|
```typescript
|
|
74
91
|
import { application, controller } from "serverstruct";
|
|
@@ -94,89 +111,161 @@ const app = application((app, box) => {
|
|
|
94
111
|
app.serve({ port: 3000 });
|
|
95
112
|
```
|
|
96
113
|
|
|
97
|
-
|
|
114
|
+
## Handlers
|
|
98
115
|
|
|
99
|
-
|
|
116
|
+
Use `handler()` to create h3 handler constructors:
|
|
100
117
|
|
|
101
|
-
|
|
118
|
+
```typescript
|
|
119
|
+
import { application, handler } from "serverstruct";
|
|
102
120
|
|
|
103
|
-
|
|
121
|
+
class UserService {
|
|
122
|
+
getUser(id: string) {
|
|
123
|
+
return { id, name: "Alice" };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
104
126
|
|
|
105
|
-
|
|
106
|
-
|
|
127
|
+
// Define a handler
|
|
128
|
+
const getUserHandler = handler((event, box) => {
|
|
129
|
+
const userService = box.get(UserService);
|
|
130
|
+
const id = event.context.params?.id;
|
|
131
|
+
return userService.getUser(id);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Use it in your app
|
|
135
|
+
const app = application((app, box) => {
|
|
136
|
+
app.get("/users/:id", box.get(getUserHandler));
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Event Handlers
|
|
141
|
+
|
|
142
|
+
Use `eventHandler()` to create h3 handlers with additional options like metadata and middleware:
|
|
107
143
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
users: User[] = [];
|
|
144
|
+
```typescript
|
|
145
|
+
import { application, eventHandler } from "serverstruct";
|
|
111
146
|
|
|
112
|
-
|
|
113
|
-
|
|
147
|
+
class UserService {
|
|
148
|
+
getUser(id: string) {
|
|
149
|
+
return { id, name: "Alice" };
|
|
150
|
+
}
|
|
114
151
|
}
|
|
115
152
|
|
|
116
|
-
//
|
|
117
|
-
const
|
|
118
|
-
|
|
153
|
+
// Define an event handler with middleware and metadata
|
|
154
|
+
const getUserHandler = eventHandler((box) => ({
|
|
155
|
+
handler(event) {
|
|
156
|
+
const userService = box.get(UserService);
|
|
157
|
+
const id = event.context.params?.id;
|
|
158
|
+
return userService.getUser(id);
|
|
159
|
+
},
|
|
160
|
+
meta: { auth: true },
|
|
161
|
+
middleware: [
|
|
162
|
+
(event) => {
|
|
163
|
+
const token = event.headers.get("authorization");
|
|
164
|
+
if (!token || token !== "secret-token") {
|
|
165
|
+
throw new Error("Unauthorized");
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
}));
|
|
119
170
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
db.addUser(body);
|
|
124
|
-
return body;
|
|
125
|
-
});
|
|
171
|
+
// Use it in your app
|
|
172
|
+
const app = application((app, box) => {
|
|
173
|
+
app.get("/users/:id", box.get(getUserHandler));
|
|
126
174
|
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Middleware
|
|
178
|
+
|
|
179
|
+
Use `middleware()` to create h3 middleware constructors:
|
|
127
180
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
181
|
+
```typescript
|
|
182
|
+
import { application, middleware } from "serverstruct";
|
|
183
|
+
|
|
184
|
+
class Logger {
|
|
185
|
+
log(message: string) {
|
|
186
|
+
console.log(message);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
131
189
|
|
|
132
|
-
|
|
190
|
+
// Define a middleware
|
|
191
|
+
const logMiddleware = middleware((event, next, box) => {
|
|
192
|
+
const logger = box.get(Logger);
|
|
193
|
+
logger.log("Request received");
|
|
133
194
|
});
|
|
134
195
|
|
|
196
|
+
// Use it in your app
|
|
135
197
|
const app = application((app, box) => {
|
|
136
|
-
app.
|
|
137
|
-
app.
|
|
198
|
+
app.use(box.get(logMiddleware));
|
|
199
|
+
app.get("/", () => "Hello world!");
|
|
138
200
|
});
|
|
139
|
-
|
|
140
|
-
await app.serve({ port: 3000 });
|
|
141
201
|
```
|
|
142
202
|
|
|
143
|
-
|
|
203
|
+
## Context
|
|
144
204
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
Use h3's native middleware with `app.use()`:
|
|
205
|
+
The `context()` function creates a request-scoped, type-safe store for per-request values. Each request gets its own isolated context that is automatically cleaned up when the request completes.
|
|
148
206
|
|
|
149
207
|
```typescript
|
|
208
|
+
import { application, context } from "serverstruct";
|
|
209
|
+
|
|
210
|
+
interface User {
|
|
211
|
+
id: string;
|
|
212
|
+
name: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Create a context store
|
|
216
|
+
const userContext = context<User>();
|
|
217
|
+
|
|
150
218
|
const app = application((app) => {
|
|
151
|
-
//
|
|
152
|
-
app.use(() =>
|
|
219
|
+
// Set context in middleware
|
|
220
|
+
app.use((event) => {
|
|
221
|
+
const user = { id: "123", name: "Alice" };
|
|
222
|
+
userContext.set(event, user);
|
|
223
|
+
});
|
|
153
224
|
|
|
154
|
-
|
|
225
|
+
// Access context in handlers
|
|
226
|
+
app.get("/profile", (event) => {
|
|
227
|
+
const user = userContext.get(event);
|
|
228
|
+
return { profile: user };
|
|
229
|
+
});
|
|
155
230
|
});
|
|
156
231
|
```
|
|
157
232
|
|
|
158
|
-
|
|
233
|
+
### Context Methods
|
|
234
|
+
|
|
235
|
+
- `set(event, value)` - Store a value for the current request
|
|
236
|
+
- `get(event)` - Retrieve the value for the current request (throws if not found)
|
|
237
|
+
- `lookup(event)` - Retrieve the value or `undefined` if not found
|
|
159
238
|
|
|
160
239
|
```typescript
|
|
161
|
-
const
|
|
162
|
-
// Runs only for routes in this controller
|
|
163
|
-
app.use(() => console.log("Users route accessed"));
|
|
240
|
+
const requestIdContext = context<string>();
|
|
164
241
|
|
|
165
|
-
|
|
166
|
-
app.
|
|
242
|
+
const app = application((app) => {
|
|
243
|
+
app.use((event) => {
|
|
244
|
+
requestIdContext.set(event, crypto.randomUUID());
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
app.get("/", (event) => {
|
|
248
|
+
// Safe access - throws if not set
|
|
249
|
+
const id = requestIdContext.get(event);
|
|
250
|
+
|
|
251
|
+
// Optional access - returns undefined if not set
|
|
252
|
+
const maybeId = requestIdContext.lookup(event);
|
|
253
|
+
|
|
254
|
+
return { requestId: id };
|
|
255
|
+
});
|
|
167
256
|
});
|
|
168
257
|
```
|
|
169
258
|
|
|
170
259
|
## Custom Box Instance
|
|
171
260
|
|
|
172
|
-
|
|
261
|
+
You can also pass your own Box instance to share dependencies across multiple applications or mock dependencies:
|
|
173
262
|
|
|
174
263
|
```typescript
|
|
175
264
|
import { Box } from "getbox";
|
|
176
265
|
|
|
177
266
|
const box = new Box();
|
|
178
267
|
|
|
179
|
-
//
|
|
268
|
+
// Mock a dependency
|
|
180
269
|
Box.mock(box, Database, new Database());
|
|
181
270
|
|
|
182
271
|
const app = application((app, box) => {
|
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;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as h30 from "h3";
|
|
2
|
+
import { EventHandlerObject, EventHandlerRequest, H3, H3Event, Middleware, serve } from "h3";
|
|
2
3
|
import { Box, Constructor } from "getbox";
|
|
3
4
|
|
|
4
5
|
//#region src/index.d.ts
|
|
6
|
+
type MaybePromise<T = unknown> = T | Promise<T>;
|
|
7
|
+
type Server = ReturnType<typeof serve>;
|
|
5
8
|
type ServeOptions = Parameters<typeof serve>[1];
|
|
6
9
|
/**
|
|
7
|
-
* Creates an h3 application
|
|
10
|
+
* Creates an h3 application.
|
|
8
11
|
*
|
|
9
|
-
* @param
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
+
* @param setup - Function that configures the app. Receives a fresh H3 instance
|
|
13
|
+
* and Box instance. Can add routes to the provided app, or create
|
|
14
|
+
* and return a new H3 instance.
|
|
12
15
|
* @param box - Optional Box instance. If not provided, creates a new one.
|
|
13
|
-
* @returns Object with `app` (H3 instance) and `serve` method.
|
|
16
|
+
* @returns Object with `app` (H3 instance), `box` (Box instance), and `serve` method.
|
|
14
17
|
*
|
|
15
18
|
* @example
|
|
16
19
|
* ```typescript
|
|
@@ -31,24 +34,29 @@ type ServeOptions = Parameters<typeof serve>[1];
|
|
|
31
34
|
* await app.serve({ port: 3000 });
|
|
32
35
|
* ```
|
|
33
36
|
*/
|
|
34
|
-
declare function application(
|
|
37
|
+
declare function application(setup: (app: H3, box: Box) => H3 | void, box?: Box): {
|
|
35
38
|
app: H3;
|
|
36
|
-
|
|
39
|
+
box: Box;
|
|
40
|
+
serve: (options?: ServeOptions) => Server;
|
|
37
41
|
};
|
|
38
42
|
/**
|
|
39
|
-
* Creates
|
|
43
|
+
* Creates an h3 app constructor.
|
|
40
44
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @param fn - Function that configures the controller.
|
|
45
|
-
* @returns A Constructor that can be resolved via `box.new(controller)`.
|
|
45
|
+
* @param setup - Function that configures the app.
|
|
46
|
+
* @returns A Constructor that produces an h3 app.
|
|
46
47
|
*
|
|
47
48
|
* @example
|
|
48
49
|
* ```typescript
|
|
50
|
+
* import { application, controller } from "serverstruct";
|
|
51
|
+
*
|
|
52
|
+
* class Database {
|
|
53
|
+
* getUsers() { return ["Alice", "Bob"]; }
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
49
56
|
* // Define a controller
|
|
50
57
|
* const usersController = controller((app, box) => {
|
|
51
|
-
*
|
|
58
|
+
* const db = box.get(Database);
|
|
59
|
+
* app.get("/", () => db.getUsers());
|
|
52
60
|
* });
|
|
53
61
|
*
|
|
54
62
|
* // Use it in your app
|
|
@@ -56,20 +64,164 @@ declare function application(fn: (app: H3, box: Box) => H3 | void, box?: Box): {
|
|
|
56
64
|
* app.mount("/users", box.new(usersController));
|
|
57
65
|
* });
|
|
58
66
|
* ```
|
|
67
|
+
*/
|
|
68
|
+
declare function controller(setup: (app: H3, box: Box) => H3 | void): Constructor<H3>;
|
|
69
|
+
/**
|
|
70
|
+
* Creates a handler constructor.
|
|
71
|
+
*
|
|
72
|
+
* @param setup - Handler function that receives the event and Box instance.
|
|
73
|
+
* @returns A Constructor that produces an h3 handler.
|
|
59
74
|
*
|
|
60
75
|
* @example
|
|
61
76
|
* ```typescript
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
77
|
+
* import { application, handler } from "serverstruct";
|
|
78
|
+
*
|
|
79
|
+
* class UserService {
|
|
80
|
+
* getUser(id: string) { return { id, name: "Alice" }; }
|
|
65
81
|
* }
|
|
66
82
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
83
|
+
* // Define a handler
|
|
84
|
+
* const getUserHandler = handler((event, box) => {
|
|
85
|
+
* const userService = box.get(UserService);
|
|
86
|
+
* const id = event.context.params?.id;
|
|
87
|
+
* return userService.getUser(id);
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* // Use it in your app
|
|
91
|
+
* const app = application((app, box) => {
|
|
92
|
+
* app.get("/users/:id", box.get(getUserHandler));
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
declare function handler<Res = unknown, Req extends EventHandlerRequest = EventHandlerRequest>(setup: (event: H3Event<Req>, box: Box) => Res): Constructor<h30.EventHandlerWithFetch<Req, Res>>;
|
|
97
|
+
/**
|
|
98
|
+
* Creates an event handler constructor from a setup function.
|
|
99
|
+
*
|
|
100
|
+
* @param setup - Function that receives Box instance and returns an event handler object.
|
|
101
|
+
* @returns A Constructor that produces an h3 event handler.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* import { application, eventHandler } from "serverstruct";
|
|
106
|
+
*
|
|
107
|
+
* class UserService {
|
|
108
|
+
* getUser(id: string) { return { id, name: "Alice" }; }
|
|
109
|
+
* }
|
|
110
|
+
*
|
|
111
|
+
* // Define an event handler
|
|
112
|
+
* const getUserHandler = eventHandler((box) => ({
|
|
113
|
+
* handler(event) {
|
|
114
|
+
* const userService = box.get(UserService);
|
|
115
|
+
* const id = event.context.params?.id;
|
|
116
|
+
* return userService.getUser(id);
|
|
117
|
+
* },
|
|
118
|
+
* meta: { auth: true }
|
|
119
|
+
* }));
|
|
120
|
+
*
|
|
121
|
+
* // Use it in your app
|
|
122
|
+
* const app = application((app, box) => {
|
|
123
|
+
* app.get("/users/:id", box.get(getUserHandler));
|
|
124
|
+
* });
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
declare function eventHandler<Res = unknown, Req extends EventHandlerRequest = EventHandlerRequest>(setup: (box: Box) => EventHandlerObject<Req, Res>): Constructor<h30.EventHandlerWithFetch<Req, Res>>;
|
|
128
|
+
/**
|
|
129
|
+
* Creates a middleware constructor.
|
|
130
|
+
*
|
|
131
|
+
* @param setup - Middleware function that receives the event, next function, and Box instance.
|
|
132
|
+
* @returns A Constructor that produces an h3 middleware.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* import { application, middleware } from "serverstruct";
|
|
137
|
+
*
|
|
138
|
+
* class AuthService {
|
|
139
|
+
* validateToken(token: string) { return token === "valid"; }
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* // Define a middleware
|
|
143
|
+
* const authMiddleware = middleware((event, next, box) => {
|
|
144
|
+
* const authService = box.get(AuthService);
|
|
145
|
+
* const token = event.headers.get("authorization");
|
|
146
|
+
* if (!token || !authService.validateToken(token)) {
|
|
147
|
+
* throw new Error("Unauthorized");
|
|
148
|
+
* }
|
|
149
|
+
* });
|
|
150
|
+
*
|
|
151
|
+
* // Use it in your app
|
|
152
|
+
* const app = application((app, box) => {
|
|
153
|
+
* app.use(box.get(authMiddleware));
|
|
154
|
+
* app.get("/", () => "Hello world!");
|
|
155
|
+
* });
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
declare function middleware(setup: (event: H3Event, next: () => MaybePromise<unknown | undefined>, box: Box) => MaybePromise<unknown | undefined>): Constructor<Middleware>;
|
|
159
|
+
/**
|
|
160
|
+
* A request-scoped context store for associating values with H3 events.
|
|
161
|
+
*
|
|
162
|
+
* Each request gets its own isolated context that is automatically cleaned up
|
|
163
|
+
* when the request completes. Uses a WeakMap internally to ensure values are
|
|
164
|
+
* garbage collected with their events.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* import { application, Context } from "serverstruct";
|
|
169
|
+
*
|
|
170
|
+
* const userContext = new Context<User>();
|
|
171
|
+
*
|
|
172
|
+
* const app = application((app) => {
|
|
173
|
+
* app.use((event) => {
|
|
174
|
+
* userContext.set(event, { id: "123", name: "Alice" });
|
|
175
|
+
* });
|
|
176
|
+
* app.get("/user", (event) => {
|
|
177
|
+
* const user = userContext.get(event);
|
|
178
|
+
* return user;
|
|
179
|
+
* });
|
|
180
|
+
* });
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
declare class Context<T> {
|
|
184
|
+
#private;
|
|
185
|
+
/**
|
|
186
|
+
* Sets a value for the given event.
|
|
187
|
+
*/
|
|
188
|
+
set(event: H3Event<any>, value: T): void;
|
|
189
|
+
/**
|
|
190
|
+
* Gets the value for the given event.
|
|
191
|
+
* @throws Error if no value is set for the event.
|
|
192
|
+
*/
|
|
193
|
+
get(event: H3Event<any>): T;
|
|
194
|
+
/**
|
|
195
|
+
* Gets the value for the given event, or undefined if not set.
|
|
196
|
+
*/
|
|
197
|
+
lookup(event: H3Event<any>): T | undefined;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Creates a request-scoped context store for associating values with H3 events.
|
|
201
|
+
*
|
|
202
|
+
* Each request gets its own isolated context that is automatically cleaned up
|
|
203
|
+
* when the request completes. Uses a WeakMap internally to ensure values are
|
|
204
|
+
* garbage collected with their events.
|
|
205
|
+
*
|
|
206
|
+
* @returns A Context instance.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* import { application, context } from "serverstruct";
|
|
211
|
+
*
|
|
212
|
+
* const userContext = context<User>();
|
|
213
|
+
*
|
|
214
|
+
* const app = application((app) => {
|
|
215
|
+
* app.use((event) => {
|
|
216
|
+
* userContext.set(event, { id: "123", name: "Alice" });
|
|
217
|
+
* });
|
|
218
|
+
* app.get("/user", (event) => {
|
|
219
|
+
* const user = userContext.get(event);
|
|
220
|
+
* return user;
|
|
221
|
+
* });
|
|
70
222
|
* });
|
|
71
223
|
* ```
|
|
72
224
|
*/
|
|
73
|
-
declare function
|
|
225
|
+
declare function context<T>(): Context<T>;
|
|
74
226
|
//#endregion
|
|
75
|
-
export { ServeOptions, application, controller };
|
|
227
|
+
export { Context, ServeOptions, Server, application, context, controller, eventHandler, handler, middleware };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import { H3, serve } from "h3";
|
|
2
1
|
import { Box, Constructor } from "getbox";
|
|
2
|
+
import * as h30 from "h3";
|
|
3
|
+
import { EventHandlerObject, EventHandlerRequest, H3, H3Event, Middleware, serve } from "h3";
|
|
3
4
|
|
|
4
5
|
//#region src/index.d.ts
|
|
6
|
+
type MaybePromise<T = unknown> = T | Promise<T>;
|
|
7
|
+
type Server = ReturnType<typeof serve>;
|
|
5
8
|
type ServeOptions = Parameters<typeof serve>[1];
|
|
6
9
|
/**
|
|
7
|
-
* Creates an h3 application
|
|
10
|
+
* Creates an h3 application.
|
|
8
11
|
*
|
|
9
|
-
* @param
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
+
* @param setup - Function that configures the app. Receives a fresh H3 instance
|
|
13
|
+
* and Box instance. Can add routes to the provided app, or create
|
|
14
|
+
* and return a new H3 instance.
|
|
12
15
|
* @param box - Optional Box instance. If not provided, creates a new one.
|
|
13
|
-
* @returns Object with `app` (H3 instance) and `serve` method.
|
|
16
|
+
* @returns Object with `app` (H3 instance), `box` (Box instance), and `serve` method.
|
|
14
17
|
*
|
|
15
18
|
* @example
|
|
16
19
|
* ```typescript
|
|
@@ -31,24 +34,29 @@ type ServeOptions = Parameters<typeof serve>[1];
|
|
|
31
34
|
* await app.serve({ port: 3000 });
|
|
32
35
|
* ```
|
|
33
36
|
*/
|
|
34
|
-
declare function application(
|
|
37
|
+
declare function application(setup: (app: H3, box: Box) => H3 | void, box?: Box): {
|
|
35
38
|
app: H3;
|
|
36
|
-
|
|
39
|
+
box: Box;
|
|
40
|
+
serve: (options?: ServeOptions) => Server;
|
|
37
41
|
};
|
|
38
42
|
/**
|
|
39
|
-
* Creates
|
|
43
|
+
* Creates an h3 app constructor.
|
|
40
44
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @param fn - Function that configures the controller.
|
|
45
|
-
* @returns A Constructor that can be resolved via `box.new(controller)`.
|
|
45
|
+
* @param setup - Function that configures the app.
|
|
46
|
+
* @returns A Constructor that produces an h3 app.
|
|
46
47
|
*
|
|
47
48
|
* @example
|
|
48
49
|
* ```typescript
|
|
50
|
+
* import { application, controller } from "serverstruct";
|
|
51
|
+
*
|
|
52
|
+
* class Database {
|
|
53
|
+
* getUsers() { return ["Alice", "Bob"]; }
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
49
56
|
* // Define a controller
|
|
50
57
|
* const usersController = controller((app, box) => {
|
|
51
|
-
*
|
|
58
|
+
* const db = box.get(Database);
|
|
59
|
+
* app.get("/", () => db.getUsers());
|
|
52
60
|
* });
|
|
53
61
|
*
|
|
54
62
|
* // Use it in your app
|
|
@@ -56,20 +64,164 @@ declare function application(fn: (app: H3, box: Box) => H3 | void, box?: Box): {
|
|
|
56
64
|
* app.mount("/users", box.new(usersController));
|
|
57
65
|
* });
|
|
58
66
|
* ```
|
|
67
|
+
*/
|
|
68
|
+
declare function controller(setup: (app: H3, box: Box) => H3 | void): Constructor<H3>;
|
|
69
|
+
/**
|
|
70
|
+
* Creates a handler constructor.
|
|
71
|
+
*
|
|
72
|
+
* @param setup - Handler function that receives the event and Box instance.
|
|
73
|
+
* @returns A Constructor that produces an h3 handler.
|
|
59
74
|
*
|
|
60
75
|
* @example
|
|
61
76
|
* ```typescript
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
77
|
+
* import { application, handler } from "serverstruct";
|
|
78
|
+
*
|
|
79
|
+
* class UserService {
|
|
80
|
+
* getUser(id: string) { return { id, name: "Alice" }; }
|
|
65
81
|
* }
|
|
66
82
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
83
|
+
* // Define a handler
|
|
84
|
+
* const getUserHandler = handler((event, box) => {
|
|
85
|
+
* const userService = box.get(UserService);
|
|
86
|
+
* const id = event.context.params?.id;
|
|
87
|
+
* return userService.getUser(id);
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* // Use it in your app
|
|
91
|
+
* const app = application((app, box) => {
|
|
92
|
+
* app.get("/users/:id", box.get(getUserHandler));
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
declare function handler<Res = unknown, Req extends EventHandlerRequest = EventHandlerRequest>(setup: (event: H3Event<Req>, box: Box) => Res): Constructor<h30.EventHandlerWithFetch<Req, Res>>;
|
|
97
|
+
/**
|
|
98
|
+
* Creates an event handler constructor from a setup function.
|
|
99
|
+
*
|
|
100
|
+
* @param setup - Function that receives Box instance and returns an event handler object.
|
|
101
|
+
* @returns A Constructor that produces an h3 event handler.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* import { application, eventHandler } from "serverstruct";
|
|
106
|
+
*
|
|
107
|
+
* class UserService {
|
|
108
|
+
* getUser(id: string) { return { id, name: "Alice" }; }
|
|
109
|
+
* }
|
|
110
|
+
*
|
|
111
|
+
* // Define an event handler
|
|
112
|
+
* const getUserHandler = eventHandler((box) => ({
|
|
113
|
+
* handler(event) {
|
|
114
|
+
* const userService = box.get(UserService);
|
|
115
|
+
* const id = event.context.params?.id;
|
|
116
|
+
* return userService.getUser(id);
|
|
117
|
+
* },
|
|
118
|
+
* meta: { auth: true }
|
|
119
|
+
* }));
|
|
120
|
+
*
|
|
121
|
+
* // Use it in your app
|
|
122
|
+
* const app = application((app, box) => {
|
|
123
|
+
* app.get("/users/:id", box.get(getUserHandler));
|
|
124
|
+
* });
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
declare function eventHandler<Res = unknown, Req extends EventHandlerRequest = EventHandlerRequest>(setup: (box: Box) => EventHandlerObject<Req, Res>): Constructor<h30.EventHandlerWithFetch<Req, Res>>;
|
|
128
|
+
/**
|
|
129
|
+
* Creates a middleware constructor.
|
|
130
|
+
*
|
|
131
|
+
* @param setup - Middleware function that receives the event, next function, and Box instance.
|
|
132
|
+
* @returns A Constructor that produces an h3 middleware.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* import { application, middleware } from "serverstruct";
|
|
137
|
+
*
|
|
138
|
+
* class AuthService {
|
|
139
|
+
* validateToken(token: string) { return token === "valid"; }
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* // Define a middleware
|
|
143
|
+
* const authMiddleware = middleware((event, next, box) => {
|
|
144
|
+
* const authService = box.get(AuthService);
|
|
145
|
+
* const token = event.headers.get("authorization");
|
|
146
|
+
* if (!token || !authService.validateToken(token)) {
|
|
147
|
+
* throw new Error("Unauthorized");
|
|
148
|
+
* }
|
|
149
|
+
* });
|
|
150
|
+
*
|
|
151
|
+
* // Use it in your app
|
|
152
|
+
* const app = application((app, box) => {
|
|
153
|
+
* app.use(box.get(authMiddleware));
|
|
154
|
+
* app.get("/", () => "Hello world!");
|
|
155
|
+
* });
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
declare function middleware(setup: (event: H3Event, next: () => MaybePromise<unknown | undefined>, box: Box) => MaybePromise<unknown | undefined>): Constructor<Middleware>;
|
|
159
|
+
/**
|
|
160
|
+
* A request-scoped context store for associating values with H3 events.
|
|
161
|
+
*
|
|
162
|
+
* Each request gets its own isolated context that is automatically cleaned up
|
|
163
|
+
* when the request completes. Uses a WeakMap internally to ensure values are
|
|
164
|
+
* garbage collected with their events.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* import { application, Context } from "serverstruct";
|
|
169
|
+
*
|
|
170
|
+
* const userContext = new Context<User>();
|
|
171
|
+
*
|
|
172
|
+
* const app = application((app) => {
|
|
173
|
+
* app.use((event) => {
|
|
174
|
+
* userContext.set(event, { id: "123", name: "Alice" });
|
|
175
|
+
* });
|
|
176
|
+
* app.get("/user", (event) => {
|
|
177
|
+
* const user = userContext.get(event);
|
|
178
|
+
* return user;
|
|
179
|
+
* });
|
|
180
|
+
* });
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
declare class Context<T> {
|
|
184
|
+
#private;
|
|
185
|
+
/**
|
|
186
|
+
* Sets a value for the given event.
|
|
187
|
+
*/
|
|
188
|
+
set(event: H3Event<any>, value: T): void;
|
|
189
|
+
/**
|
|
190
|
+
* Gets the value for the given event.
|
|
191
|
+
* @throws Error if no value is set for the event.
|
|
192
|
+
*/
|
|
193
|
+
get(event: H3Event<any>): T;
|
|
194
|
+
/**
|
|
195
|
+
* Gets the value for the given event, or undefined if not set.
|
|
196
|
+
*/
|
|
197
|
+
lookup(event: H3Event<any>): T | undefined;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Creates a request-scoped context store for associating values with H3 events.
|
|
201
|
+
*
|
|
202
|
+
* Each request gets its own isolated context that is automatically cleaned up
|
|
203
|
+
* when the request completes. Uses a WeakMap internally to ensure values are
|
|
204
|
+
* garbage collected with their events.
|
|
205
|
+
*
|
|
206
|
+
* @returns A Context instance.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* import { application, context } from "serverstruct";
|
|
211
|
+
*
|
|
212
|
+
* const userContext = context<User>();
|
|
213
|
+
*
|
|
214
|
+
* const app = application((app) => {
|
|
215
|
+
* app.use((event) => {
|
|
216
|
+
* userContext.set(event, { id: "123", name: "Alice" });
|
|
217
|
+
* });
|
|
218
|
+
* app.get("/user", (event) => {
|
|
219
|
+
* const user = userContext.get(event);
|
|
220
|
+
* return user;
|
|
221
|
+
* });
|
|
70
222
|
* });
|
|
71
223
|
* ```
|
|
72
224
|
*/
|
|
73
|
-
declare function
|
|
225
|
+
declare function context<T>(): Context<T>;
|
|
74
226
|
//#endregion
|
|
75
|
-
export { ServeOptions, application, controller };
|
|
227
|
+
export { Context, ServeOptions, Server, application, context, controller, eventHandler, handler, middleware };
|
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { H3, serve } from "h3";
|
|
2
1
|
import { Box, factory } from "getbox";
|
|
2
|
+
import { H3, defineHandler, defineMiddleware, serve } from "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 @@ import { Box, factory } from "getbox";
|
|
|
30
30
|
* await app.serve({ port: 3000 });
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
|
-
function application(
|
|
33
|
+
function application(setup, box = new Box()) {
|
|
34
34
|
const defaultApp = new H3();
|
|
35
|
-
const app =
|
|
35
|
+
const app = setup(defaultApp, box) || defaultApp;
|
|
36
36
|
return {
|
|
37
37
|
app,
|
|
38
|
+
box,
|
|
38
39
|
serve: (options) => serve(app, options)
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
42
|
-
* Creates
|
|
43
|
+
* Creates an h3 app constructor.
|
|
43
44
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* @param fn - Function that configures the controller.
|
|
48
|
-
* @returns A Constructor that can be resolved via `box.new(controller)`.
|
|
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,23 +64,182 @@ function application(fn, box = new Box()) {
|
|
|
59
64
|
* app.mount("/users", box.new(usersController));
|
|
60
65
|
* });
|
|
61
66
|
* ```
|
|
67
|
+
*/
|
|
68
|
+
function controller(setup) {
|
|
69
|
+
return 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 factory((box) => 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 factory((box) => 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 factory((box) => 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
|
|
81
|
-
export { application, controller };
|
|
245
|
+
export { Context, application, context, controller, eventHandler, handler, middleware };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "serverstruct",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Type safe and modular servers with H3",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -18,13 +18,6 @@
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "tsc && tsdown src/index.ts --format esm,cjs",
|
|
23
|
-
"release": "pnpm run build && changeset publish",
|
|
24
|
-
"watch": "vitest",
|
|
25
|
-
"test": "vitest run",
|
|
26
|
-
"test:coverage": "vitest run --coverage"
|
|
27
|
-
},
|
|
28
21
|
"keywords": [
|
|
29
22
|
"h3",
|
|
30
23
|
"server",
|
|
@@ -52,5 +45,12 @@
|
|
|
52
45
|
"peerDependencies": {
|
|
53
46
|
"getbox": ">= 1.0.0 <2.0.0",
|
|
54
47
|
"h3": ">=2.0.1-rc.6 <3.0.0"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc && tsdown src/index.ts --format esm,cjs",
|
|
51
|
+
"release": "pnpm run build && changeset publish",
|
|
52
|
+
"watch": "vitest",
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"test:coverage": "vitest run --coverage"
|
|
55
55
|
}
|
|
56
56
|
}
|