@spfn/core 0.1.0-alpha.88 → 0.2.0-beta.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/README.md +1046 -384
- package/dist/boss-D-fGtVgM.d.ts +187 -0
- package/dist/cache/index.d.ts +13 -33
- package/dist/cache/index.js +14 -703
- package/dist/cache/index.js.map +1 -1
- package/dist/codegen/index.d.ts +167 -17
- package/dist/codegen/index.js +76 -1419
- package/dist/codegen/index.js.map +1 -1
- package/dist/config/index.d.ts +1191 -0
- package/dist/config/index.js +264 -0
- package/dist/config/index.js.map +1 -0
- package/dist/db/index.d.ts +728 -59
- package/dist/db/index.js +1028 -1225
- package/dist/db/index.js.map +1 -1
- package/dist/env/index.d.ts +579 -308
- package/dist/env/index.js +438 -930
- package/dist/env/index.js.map +1 -1
- package/dist/errors/index.d.ts +417 -29
- package/dist/errors/index.js +359 -98
- package/dist/errors/index.js.map +1 -1
- package/dist/event/index.d.ts +108 -0
- package/dist/event/index.js +122 -0
- package/dist/event/index.js.map +1 -0
- package/dist/job/index.d.ts +172 -0
- package/dist/job/index.js +361 -0
- package/dist/job/index.js.map +1 -0
- package/dist/logger/index.d.ts +20 -79
- package/dist/logger/index.js +82 -387
- package/dist/logger/index.js.map +1 -1
- package/dist/middleware/index.d.ts +2 -11
- package/dist/middleware/index.js +49 -703
- package/dist/middleware/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +120 -0
- package/dist/nextjs/index.js +416 -0
- package/dist/nextjs/index.js.map +1 -0
- package/dist/{client/nextjs/index.d.ts → nextjs/server.d.ts} +288 -262
- package/dist/nextjs/server.js +568 -0
- package/dist/nextjs/server.js.map +1 -0
- package/dist/route/index.d.ts +667 -25
- package/dist/route/index.js +437 -1287
- package/dist/route/index.js.map +1 -1
- package/dist/route/types.d.ts +38 -0
- package/dist/route/types.js +3 -0
- package/dist/route/types.js.map +1 -0
- package/dist/server/index.d.ts +201 -67
- package/dist/server/index.js +921 -3182
- package/dist/server/index.js.map +1 -1
- package/dist/types-BGl4QL1w.d.ts +77 -0
- package/dist/types-DRG2XMTR.d.ts +157 -0
- package/package.json +52 -47
- package/dist/auto-loader-JFaZ9gON.d.ts +0 -80
- package/dist/client/index.d.ts +0 -358
- package/dist/client/index.js +0 -357
- package/dist/client/index.js.map +0 -1
- package/dist/client/nextjs/index.js +0 -371
- package/dist/client/nextjs/index.js.map +0 -1
- package/dist/codegen/generators/index.d.ts +0 -19
- package/dist/codegen/generators/index.js +0 -1404
- package/dist/codegen/generators/index.js.map +0 -1
- package/dist/database-errors-BNNmLTJE.d.ts +0 -86
- package/dist/events/index.d.ts +0 -183
- package/dist/events/index.js +0 -77
- package/dist/events/index.js.map +0 -1
- package/dist/index-DHiAqhKv.d.ts +0 -101
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -3674
- package/dist/index.js.map +0 -1
- package/dist/types/index.d.ts +0 -121
- package/dist/types/index.js +0 -38
- package/dist/types/index.js.map +0 -1
- package/dist/types-BXibIEyj.d.ts +0 -60
package/dist/route/index.d.ts
CHANGED
|
@@ -1,40 +1,682 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import '@sinclair/typebox';
|
|
1
|
+
import * as _sinclair_typebox from '@sinclair/typebox';
|
|
2
|
+
import { TSchema, Static } from '@sinclair/typebox';
|
|
3
|
+
import { Context, MiddlewareHandler, Hono } from 'hono';
|
|
4
|
+
import { ContentfulStatusCode } from 'hono/utils/http-status';
|
|
5
|
+
import { HttpMethod } from './types.js';
|
|
6
|
+
export { HeaderRecord, InferResponseData, RouteMeta, RouteMetadata, RouterMetadata } from './types.js';
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
|
-
*
|
|
9
|
+
* Route Input Types
|
|
11
10
|
*
|
|
12
|
-
*
|
|
13
|
-
|
|
11
|
+
* Defines the structure for route input validation schemas
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Route input schemas
|
|
16
|
+
*
|
|
17
|
+
* Defines validation schemas for different parts of an HTTP request
|
|
18
|
+
*/
|
|
19
|
+
type RouteInput = {
|
|
20
|
+
/** Path parameters (e.g., /users/:id) */
|
|
21
|
+
params?: TSchema;
|
|
22
|
+
/** Query string parameters (e.g., ?page=1&limit=20) */
|
|
23
|
+
query?: TSchema;
|
|
24
|
+
/** Request body (JSON) */
|
|
25
|
+
body?: TSchema;
|
|
26
|
+
/** HTTP headers */
|
|
27
|
+
headers?: TSchema;
|
|
28
|
+
/** Cookies */
|
|
29
|
+
cookies?: TSchema;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Route Builder Context
|
|
34
|
+
*
|
|
35
|
+
* Provides structured input access and response helpers for route handlers
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Merge input with interceptor-injected fields
|
|
40
|
+
* Server receives both client input and interceptor-injected fields
|
|
14
41
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* type ClientInput = { body: { email: string, password: string } };
|
|
45
|
+
* type InterceptorInput = { body: { publicKey: string, keyId: string } };
|
|
46
|
+
* // MergedInput = { body: { email: string, password: string, publicKey: string, keyId: string } }
|
|
47
|
+
* ```
|
|
19
48
|
*/
|
|
20
|
-
|
|
49
|
+
type MergedInput<TInput extends RouteInput, TInterceptor extends RouteInput> = {
|
|
50
|
+
params: (TInput['params'] extends TSchema ? Static<TInput['params']> : {}) & (TInterceptor['params'] extends TSchema ? Static<TInterceptor['params']> : {});
|
|
51
|
+
query: (TInput['query'] extends TSchema ? Static<TInput['query']> : {}) & (TInterceptor['query'] extends TSchema ? Static<TInterceptor['query']> : {});
|
|
52
|
+
body: (TInput['body'] extends TSchema ? Static<TInput['body']> : {}) & (TInterceptor['body'] extends TSchema ? Static<TInterceptor['body']> : {});
|
|
53
|
+
headers: (TInput['headers'] extends TSchema ? Static<TInput['headers']> : {}) & (TInterceptor['headers'] extends TSchema ? Static<TInterceptor['headers']> : {});
|
|
54
|
+
cookies: (TInput['cookies'] extends TSchema ? Static<TInput['cookies']> : {}) & (TInterceptor['cookies'] extends TSchema ? Static<TInterceptor['cookies']> : {});
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* RouteBuilderContext - define-route dedicated context
|
|
58
|
+
*
|
|
59
|
+
* Provides structured input access through data() method
|
|
60
|
+
*/
|
|
61
|
+
type RouteBuilderContext<TInput extends RouteInput = RouteInput, TInterceptor extends RouteInput = {}> = {
|
|
62
|
+
/**
|
|
63
|
+
* Get structured input data
|
|
64
|
+
*
|
|
65
|
+
* Returns an object with separate params, query, body, headers, cookies
|
|
66
|
+
* If interceptor fields are defined, they are merged with input fields
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* // GET /users/:id?page=1
|
|
71
|
+
* const { params, query } = await c.data();
|
|
72
|
+
* // params = { id: string }
|
|
73
|
+
* // query = { page: number }
|
|
74
|
+
*
|
|
75
|
+
* // POST /users with headers
|
|
76
|
+
* const { body, headers } = await c.data();
|
|
77
|
+
* // body = { name: string }
|
|
78
|
+
* // headers = { authorization: string }
|
|
79
|
+
*
|
|
80
|
+
* // With interceptor-injected fields
|
|
81
|
+
* const { body } = await c.data();
|
|
82
|
+
* // body = { email: string, password: string, publicKey: string, keyId: string }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
data(): Promise<MergedInput<TInput, TInterceptor>>;
|
|
86
|
+
/**
|
|
87
|
+
* Return JSON response with custom status and headers
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* return c.json({ message: 'Custom response' }, 200);
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
json(data: unknown, status?: ContentfulStatusCode, headers?: Record<string, string | string[]>): Response;
|
|
95
|
+
/**
|
|
96
|
+
* Return 201 Created response with optional Location header
|
|
97
|
+
* Returns data directly (no wrapper)
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* const user = await createUser(body);
|
|
102
|
+
* return c.created(user, `/users/${user.id}`);
|
|
103
|
+
* // Response: 201 Created
|
|
104
|
+
* // Header: Location: /users/123
|
|
105
|
+
* // Body: { id: '123', name: 'John' }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
created(data: unknown, location?: string): Response;
|
|
109
|
+
/**
|
|
110
|
+
* Return 202 Accepted response
|
|
111
|
+
* Returns data directly (no wrapper), or empty body if no data
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* // With data
|
|
116
|
+
* return c.accepted({ jobId: '123' });
|
|
117
|
+
* // Response: 202 Accepted, Body: { jobId: '123' }
|
|
118
|
+
*
|
|
119
|
+
* // Without data
|
|
120
|
+
* return c.accepted();
|
|
121
|
+
* // Response: 202 Accepted, Body: (empty)
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
accepted(data?: unknown): Response;
|
|
125
|
+
/**
|
|
126
|
+
* Return 204 No Content response (empty body)
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* await deleteUser(id);
|
|
131
|
+
* return c.noContent();
|
|
132
|
+
* // Response: 204 No Content, Body: (empty)
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
noContent(): Response;
|
|
136
|
+
/**
|
|
137
|
+
* Return 304 Not Modified response (empty body)
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* if (etag === requestEtag) {
|
|
142
|
+
* return c.notModified();
|
|
143
|
+
* }
|
|
144
|
+
* // Response: 304 Not Modified, Body: (empty)
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
notModified(): Response;
|
|
148
|
+
/**
|
|
149
|
+
* Return paginated response with metadata
|
|
150
|
+
* Returns `{ items: [...], pagination: {...} }` format
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* const users = await getUsers(page, limit);
|
|
155
|
+
* const total = await countUsers();
|
|
156
|
+
* return c.paginated(users, page, limit, total);
|
|
157
|
+
* // Response: {
|
|
158
|
+
* // items: [...],
|
|
159
|
+
* // pagination: {
|
|
160
|
+
* // page: 1,
|
|
161
|
+
* // limit: 20,
|
|
162
|
+
* // total: 100,
|
|
163
|
+
* // totalPages: 5
|
|
164
|
+
* // }
|
|
165
|
+
* // }
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
paginated(data: unknown[], page: number, limit: number, total: number): Response;
|
|
169
|
+
raw: Context;
|
|
170
|
+
};
|
|
21
171
|
|
|
22
172
|
/**
|
|
23
|
-
*
|
|
173
|
+
* Middleware Definition Helper
|
|
24
174
|
*
|
|
25
|
-
* Provides
|
|
175
|
+
* Provides type-safe middleware definition with name inference
|
|
26
176
|
*/
|
|
27
177
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Named middleware with type inference
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* export const authMiddleware = defineMiddleware('auth', async (c, next) => {
|
|
184
|
+
* // auth logic
|
|
185
|
+
* c.set('user', { id: 1 });
|
|
186
|
+
* await next();
|
|
187
|
+
* });
|
|
188
|
+
*
|
|
189
|
+
* export const rateLimitMiddleware = defineMiddleware('rateLimit', async (c, next) => {
|
|
190
|
+
* // rate limit logic
|
|
191
|
+
* await next();
|
|
192
|
+
* });
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
type NamedMiddleware<TName extends string = string> = {
|
|
196
|
+
name: TName;
|
|
197
|
+
handler: MiddlewareHandler;
|
|
198
|
+
_name: TName;
|
|
32
199
|
};
|
|
33
200
|
/**
|
|
34
|
-
*
|
|
201
|
+
* Named middleware factory with type inference
|
|
202
|
+
*
|
|
203
|
+
* Factory function that creates middleware instances with parameters
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* export const requirePermissions = defineMiddleware('permission',
|
|
208
|
+
* (...permissions: string[]) => async (c, next) => {
|
|
209
|
+
* // permission check logic
|
|
210
|
+
* await next();
|
|
211
|
+
* }
|
|
212
|
+
* );
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
type NamedMiddlewareFactory<TName extends string = string, TArgs extends any[] = any[]> = {
|
|
216
|
+
name: TName;
|
|
217
|
+
_name: TName;
|
|
218
|
+
} & ((...args: TArgs) => MiddlewareHandler);
|
|
219
|
+
/**
|
|
220
|
+
* Define a named middleware
|
|
221
|
+
*
|
|
222
|
+
* Creates a middleware with a unique name that can be referenced
|
|
223
|
+
* in route-level skip() calls with full type safety.
|
|
224
|
+
*
|
|
225
|
+
* Supports two patterns:
|
|
226
|
+
* 1. Regular middleware: Direct middleware handler
|
|
227
|
+
* 2. Factory middleware: Function that creates middleware with parameters
|
|
228
|
+
*
|
|
229
|
+
* @param name - Unique middleware name
|
|
230
|
+
* @param handler - Middleware handler function
|
|
231
|
+
* @returns Named middleware with type inference
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* // Regular middleware
|
|
236
|
+
* export const authMiddleware = defineMiddleware('auth', async (c, next) => {
|
|
237
|
+
* const token = c.req.header('authorization');
|
|
238
|
+
* if (!token) {
|
|
239
|
+
* return c.json({ error: 'Unauthorized' }, 401);
|
|
240
|
+
* }
|
|
241
|
+
* c.set('user', await verifyToken(token));
|
|
242
|
+
* await next();
|
|
243
|
+
* });
|
|
244
|
+
*
|
|
245
|
+
* // Factory middleware
|
|
246
|
+
* export const requirePermissions = defineMiddleware('permission',
|
|
247
|
+
* (...permissions: string[]) => async (c, next) => {
|
|
248
|
+
* const user = c.get('user');
|
|
249
|
+
* if (!hasPermissions(user, permissions)) {
|
|
250
|
+
* return c.json({ error: 'Forbidden' }, 403);
|
|
251
|
+
* }
|
|
252
|
+
* await next();
|
|
253
|
+
* }
|
|
254
|
+
* );
|
|
255
|
+
*
|
|
256
|
+
* // server.config.ts
|
|
257
|
+
* export default defineServerConfig()
|
|
258
|
+
* .middlewares([authMiddleware])
|
|
259
|
+
* .routes(appRouter)
|
|
260
|
+
* .build();
|
|
261
|
+
*
|
|
262
|
+
* // routes.ts - skip by name
|
|
263
|
+
* export const publicRoute = route.get('/health')
|
|
264
|
+
* .skip(['auth']) // ✅ Type-safe! Autocomplete!
|
|
265
|
+
* .handler(async (c) => c.success({ status: 'ok' }));
|
|
266
|
+
*
|
|
267
|
+
* // Use factory middleware inline
|
|
268
|
+
* export const protectedRoute = route.get('/admin')
|
|
269
|
+
* .use([requirePermissions('admin:write')])
|
|
270
|
+
* .handler(async (c) => { ... });
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
declare function defineMiddleware<TName extends string>(name: TName, handler: MiddlewareHandler): NamedMiddleware<TName>;
|
|
274
|
+
declare function defineMiddleware<TName extends string, TArgs extends any[]>(name: TName, factory: (...args: TArgs) => MiddlewareHandler): NamedMiddlewareFactory<TName, TArgs>;
|
|
275
|
+
/**
|
|
276
|
+
* Define a middleware factory explicitly
|
|
277
|
+
*
|
|
278
|
+
* Use this when your factory function has exactly 2 parameters,
|
|
279
|
+
* which would be incorrectly detected as a regular middleware handler.
|
|
280
|
+
*
|
|
281
|
+
* @param name - Unique middleware name
|
|
282
|
+
* @param factory - Factory function that returns a middleware handler
|
|
283
|
+
* @returns Named middleware factory with type inference
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```ts
|
|
287
|
+
* // Factory with 2 params (would be misdetected by defineMiddleware)
|
|
288
|
+
* export const rateLimiter = defineMiddlewareFactory('rateLimit',
|
|
289
|
+
* (limit: number, window: number) => async (c, next) => {
|
|
290
|
+
* // rate limit logic using limit and window
|
|
291
|
+
* await next();
|
|
292
|
+
* }
|
|
293
|
+
* );
|
|
294
|
+
*
|
|
295
|
+
* // Usage
|
|
296
|
+
* route.get('/api')
|
|
297
|
+
* .use([rateLimiter(100, 60000)]) // 100 requests per minute
|
|
298
|
+
* .handler(...)
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
declare function defineMiddlewareFactory<TName extends string, TArgs extends unknown[]>(name: TName, factory: (...args: TArgs) => MiddlewareHandler): NamedMiddlewareFactory<TName, TArgs>;
|
|
302
|
+
/**
|
|
303
|
+
* Extract middleware names from an array of named middlewares
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```ts
|
|
307
|
+
* type Middlewares = [
|
|
308
|
+
* NamedMiddleware<'auth'>,
|
|
309
|
+
* NamedMiddleware<'rateLimit'>
|
|
310
|
+
* ];
|
|
311
|
+
* type Names = ExtractMiddlewareNames<Middlewares>; // 'auth' | 'rateLimit'
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
type ExtractMiddlewareNames<T extends readonly NamedMiddleware<string>[]> = T[number]['_name'];
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Route Builder
|
|
318
|
+
*
|
|
319
|
+
* Provides tRPC-style chainable API for route definition
|
|
320
|
+
*/
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Route handler function
|
|
324
|
+
*/
|
|
325
|
+
type RouteHandlerFn<TInput extends RouteInput = RouteInput, TInterceptor extends RouteInput = {}, TResponse = unknown> = (c: RouteBuilderContext<TInput, TInterceptor>) => Response | Promise<Response> | TResponse | Promise<TResponse>;
|
|
326
|
+
/**
|
|
327
|
+
* Route definition result
|
|
328
|
+
*
|
|
329
|
+
* Contains all information needed for type inference and registration
|
|
330
|
+
*/
|
|
331
|
+
type RouteDef<TInput extends RouteInput = RouteInput, TInterceptor extends RouteInput = {}, TResponse = unknown> = {
|
|
332
|
+
method?: HttpMethod;
|
|
333
|
+
path?: string;
|
|
334
|
+
input?: TInput;
|
|
335
|
+
interceptor?: TInterceptor;
|
|
336
|
+
middlewares?: (MiddlewareHandler | NamedMiddleware<string>)[];
|
|
337
|
+
skipMiddlewares?: string[] | '*';
|
|
338
|
+
handler: RouteHandlerFn<TInput, TInterceptor, TResponse>;
|
|
339
|
+
_input: TInput;
|
|
340
|
+
_interceptor: TInterceptor;
|
|
341
|
+
_response: TResponse;
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
344
|
+
* Route builder with chainable API (tRPC-style)
|
|
345
|
+
*/
|
|
346
|
+
declare class RouteBuilder<TInput extends RouteInput = {}, TInterceptor extends RouteInput = {}, TResponse = never> {
|
|
347
|
+
_method?: HttpMethod;
|
|
348
|
+
_path?: string;
|
|
349
|
+
_input?: TInput;
|
|
350
|
+
_interceptor?: TInterceptor;
|
|
351
|
+
_middlewares?: (MiddlewareHandler | NamedMiddleware<string>)[];
|
|
352
|
+
_skipMiddlewares?: string[] | '*';
|
|
353
|
+
/**
|
|
354
|
+
* Create a new RouteBuilder with copied properties and optional overrides
|
|
355
|
+
*/
|
|
356
|
+
private clone;
|
|
357
|
+
/**
|
|
358
|
+
* Define input schemas
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```ts
|
|
362
|
+
* route.get('/users/:id')
|
|
363
|
+
* .input({
|
|
364
|
+
* params: Type.Object({ id: Type.String() }),
|
|
365
|
+
* query: Type.Object({ page: Type.Number() }),
|
|
366
|
+
* headers: Type.Object({ authorization: Type.String() })
|
|
367
|
+
* })
|
|
368
|
+
* .handler(async (c) => {
|
|
369
|
+
* const { params, query, headers } = await c.data();
|
|
370
|
+
* // params = { id: string }
|
|
371
|
+
* // query = { page: number }
|
|
372
|
+
* // headers = { authorization: string }
|
|
373
|
+
* })
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
input<TNewInput extends RouteInput>(input: TNewInput): RouteBuilder<TNewInput, TInterceptor, TResponse>;
|
|
377
|
+
/**
|
|
378
|
+
* Define fields injected by interceptors
|
|
379
|
+
*
|
|
380
|
+
* These fields are:
|
|
381
|
+
* - Available in the handler (merged with input)
|
|
382
|
+
* - Excluded from client types (codegen uses only input)
|
|
383
|
+
* - Not validated by route input schema (injected by middleware)
|
|
384
|
+
*
|
|
385
|
+
* Use this when middleware/interceptors add fields to the request
|
|
386
|
+
* before it reaches the handler.
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```ts
|
|
390
|
+
* // Auth interceptor injects crypto key fields
|
|
391
|
+
* route.post('/_auth/login')
|
|
392
|
+
* .input({
|
|
393
|
+
* body: Type.Object({
|
|
394
|
+
* email: Type.String(),
|
|
395
|
+
* password: Type.String()
|
|
396
|
+
* })
|
|
397
|
+
* })
|
|
398
|
+
* .interceptor({
|
|
399
|
+
* body: Type.Object({
|
|
400
|
+
* publicKey: Type.String(),
|
|
401
|
+
* keyId: Type.String(),
|
|
402
|
+
* fingerprint: Type.String()
|
|
403
|
+
* })
|
|
404
|
+
* })
|
|
405
|
+
* .handler(async (c) => {
|
|
406
|
+
* const { body } = await c.data();
|
|
407
|
+
* // body type: { email, password, publicKey, keyId, fingerprint }
|
|
408
|
+
* // Client only sees: { email, password }
|
|
409
|
+
* return loginService(body);
|
|
410
|
+
* });
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
interceptor<TNewInterceptor extends RouteInput>(interceptor: TNewInterceptor): RouteBuilder<TInput, TNewInterceptor, TResponse>;
|
|
414
|
+
/**
|
|
415
|
+
* Add middlewares to the route
|
|
416
|
+
*
|
|
417
|
+
* Accepts both regular middleware handlers and named middlewares (NamedMiddleware).
|
|
418
|
+
* Named middlewares that are already registered globally will be automatically
|
|
419
|
+
* deduplicated to prevent double execution.
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```ts
|
|
423
|
+
* import { authenticate } from '@spfn/auth/server/middleware';
|
|
424
|
+
*
|
|
425
|
+
* // With NamedMiddleware (auto-deduped if registered globally)
|
|
426
|
+
* route.get('/users')
|
|
427
|
+
* .use([authenticate, RateLimitMiddleware()])
|
|
428
|
+
*
|
|
429
|
+
* // With regular middleware handlers
|
|
430
|
+
* route.get('/users')
|
|
431
|
+
* .use([AuthMiddleware(), RateLimitMiddleware()])
|
|
432
|
+
* ```
|
|
433
|
+
*/
|
|
434
|
+
middleware(middlewares: (MiddlewareHandler | NamedMiddleware<string>)[]): RouteBuilder<TInput, TInterceptor, TResponse>;
|
|
435
|
+
/**
|
|
436
|
+
* Add middlewares to the route (alias for `.middleware()`)
|
|
437
|
+
*
|
|
438
|
+
* Accepts both regular middleware handlers and named middlewares (NamedMiddleware).
|
|
439
|
+
* Named middlewares that are already registered globally will be automatically
|
|
440
|
+
* deduplicated to prevent double execution.
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```ts
|
|
444
|
+
* import { authenticate } from '@spfn/auth/server/middleware';
|
|
445
|
+
*
|
|
446
|
+
* // With NamedMiddleware (auto-deduped if registered globally)
|
|
447
|
+
* route.get('/users')
|
|
448
|
+
* .use([authenticate, RateLimitMiddleware()])
|
|
449
|
+
*
|
|
450
|
+
* // With regular middleware handlers
|
|
451
|
+
* route.get('/users')
|
|
452
|
+
* .use([AuthMiddleware(), RateLimitMiddleware()])
|
|
453
|
+
* ```
|
|
454
|
+
*/
|
|
455
|
+
use(middlewares: (MiddlewareHandler | NamedMiddleware<string>)[]): RouteBuilder<TInput, TInterceptor, TResponse>;
|
|
456
|
+
/**
|
|
457
|
+
* Skip server-level named middlewares
|
|
458
|
+
*
|
|
459
|
+
* Useful for public endpoints that should bypass auth or rate limiting
|
|
460
|
+
*
|
|
461
|
+
* @param middlewareNames - Array of middleware names to skip, or '*' to skip all
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```ts
|
|
465
|
+
* // Skip specific middlewares
|
|
466
|
+
* route.get('/health')
|
|
467
|
+
* .skip(['auth', 'rateLimit'])
|
|
468
|
+
* .handler(async (c) => c.json({ status: 'ok' }));
|
|
469
|
+
*
|
|
470
|
+
* // Skip only auth (still apply rate limiting)
|
|
471
|
+
* route.get('/public-data')
|
|
472
|
+
* .skip(['auth'])
|
|
473
|
+
* .handler(async (c) => { ... });
|
|
474
|
+
*
|
|
475
|
+
* // Skip all middlewares
|
|
476
|
+
* route.get('/public-health')
|
|
477
|
+
* .skip('*')
|
|
478
|
+
* .handler(async (c) => c.json({ status: 'ok' }));
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
skip(middlewareNames: string[] | '*'): RouteBuilder<TInput, TInterceptor, TResponse>;
|
|
482
|
+
/**
|
|
483
|
+
* Define handler function
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* ```ts
|
|
487
|
+
* route.get('/users/:id')
|
|
488
|
+
* .input({ params: Type.Object({ id: Type.String() }) })
|
|
489
|
+
* .handler(async (c) => {
|
|
490
|
+
* const { params } = await c.data();
|
|
491
|
+
* const user = await getUser(params.id);
|
|
492
|
+
* return user; // Type inferred!
|
|
493
|
+
* })
|
|
494
|
+
* ```
|
|
495
|
+
*/
|
|
496
|
+
handler<THandlerResponse>(fn: RouteHandlerFn<TInput, TInterceptor, THandlerResponse>): RouteDef<TInput, TInterceptor, THandlerResponse>;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Route builder entry point
|
|
500
|
+
*
|
|
501
|
+
* @example
|
|
502
|
+
* ```ts
|
|
503
|
+
* // GET request
|
|
504
|
+
* export const getUser = route.get('/users/:id')
|
|
505
|
+
* .input({ params: Type.Object({ id: Type.String() }) })
|
|
506
|
+
* .handler(async (c) => {
|
|
507
|
+
* const { params } = await c.data();
|
|
508
|
+
* return await db.user.findUnique({ where: { id: params.id } });
|
|
509
|
+
* });
|
|
510
|
+
*
|
|
511
|
+
* // POST request
|
|
512
|
+
* export const createUser = route.post('/users')
|
|
513
|
+
* .input({ body: Type.Object({ name: Type.String(), email: Type.String() }) })
|
|
514
|
+
* .handler(async (c) => {
|
|
515
|
+
* const { body } = await c.data();
|
|
516
|
+
* return c.created(await db.user.create({ data: body }));
|
|
517
|
+
* });
|
|
518
|
+
* ```
|
|
519
|
+
*/
|
|
520
|
+
declare const route: {
|
|
521
|
+
get: (path: string) => RouteBuilder;
|
|
522
|
+
post: (path: string) => RouteBuilder;
|
|
523
|
+
put: (path: string) => RouteBuilder;
|
|
524
|
+
patch: (path: string) => RouteBuilder;
|
|
525
|
+
delete: (path: string) => RouteBuilder;
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Router Definition
|
|
530
|
+
*
|
|
531
|
+
* Provides router composition and middleware management
|
|
532
|
+
*/
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Router definition - holds all routes
|
|
536
|
+
*/
|
|
537
|
+
interface Router<TRoutes extends Record<string, RouteDef<any, any, any> | Router<any>>> {
|
|
538
|
+
routes: TRoutes;
|
|
539
|
+
_routes: TRoutes;
|
|
540
|
+
_packageRouters: Router<any>[];
|
|
541
|
+
_globalMiddlewares: NamedMiddleware<string>[];
|
|
542
|
+
/**
|
|
543
|
+
* Register package routers (type-hidden)
|
|
544
|
+
*
|
|
545
|
+
* Package routes are:
|
|
546
|
+
* - Recognized by RPC proxy and backend
|
|
547
|
+
* - NOT exposed in client types (use package's own API like authApi, cmsApi)
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```ts
|
|
551
|
+
* import { authRouter } from '@spfn/auth/server';
|
|
552
|
+
* import { cmsAppRouter } from '@spfn/cms/server';
|
|
553
|
+
*
|
|
554
|
+
* export const appRouter = defineRouter({
|
|
555
|
+
* getRoot,
|
|
556
|
+
* getHealth,
|
|
557
|
+
* })
|
|
558
|
+
* .packages([authRouter, cmsAppRouter]);
|
|
559
|
+
*
|
|
560
|
+
* // Client usage:
|
|
561
|
+
* // api.getRoot.call({}) - app routes
|
|
562
|
+
* // authApi.login.call({}) - package API
|
|
563
|
+
* ```
|
|
564
|
+
*/
|
|
565
|
+
packages(routers: Router<any>[]): Router<TRoutes>;
|
|
566
|
+
/**
|
|
567
|
+
* Register global middlewares
|
|
568
|
+
*
|
|
569
|
+
* Applied to all routes unless explicitly skipped via .skip()
|
|
570
|
+
*
|
|
571
|
+
* @example
|
|
572
|
+
* ```ts
|
|
573
|
+
* import { authMiddleware, loggingMiddleware } from './middlewares';
|
|
574
|
+
*
|
|
575
|
+
* export const appRouter = defineRouter({
|
|
576
|
+
* getRoot,
|
|
577
|
+
* getHealth,
|
|
578
|
+
* })
|
|
579
|
+
* .packages([authRouter])
|
|
580
|
+
* .use([authMiddleware, loggingMiddleware]);
|
|
581
|
+
* ```
|
|
582
|
+
*/
|
|
583
|
+
use(middlewares: NamedMiddleware<string>[]): Router<TRoutes>;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Define a router with multiple routes (tRPC-style)
|
|
587
|
+
*
|
|
588
|
+
* Supports chainable API for packages and middlewares:
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* ```ts
|
|
592
|
+
* // Basic usage
|
|
593
|
+
* export const appRouter = defineRouter({
|
|
594
|
+
* getRoot,
|
|
595
|
+
* getHealth,
|
|
596
|
+
* listExamples,
|
|
597
|
+
* });
|
|
598
|
+
*
|
|
599
|
+
* // With package routers (type-hidden)
|
|
600
|
+
* export const appRouter = defineRouter({
|
|
601
|
+
* getRoot,
|
|
602
|
+
* getHealth,
|
|
603
|
+
* })
|
|
604
|
+
* .packages([authRouter, cmsAppRouter]);
|
|
605
|
+
*
|
|
606
|
+
* // With global middlewares
|
|
607
|
+
* export const appRouter = defineRouter({
|
|
608
|
+
* getRoot,
|
|
609
|
+
* getHealth,
|
|
610
|
+
* })
|
|
611
|
+
* .packages([authRouter])
|
|
612
|
+
* .use([authMiddleware, loggingMiddleware]);
|
|
613
|
+
*
|
|
614
|
+
* export type AppRouter = typeof appRouter;
|
|
615
|
+
* ```
|
|
616
|
+
*
|
|
617
|
+
* Package routes:
|
|
618
|
+
* - Recognized by RPC proxy and backend for routing
|
|
619
|
+
* - NOT included in AppRouter type (use authApi, cmsApi instead)
|
|
620
|
+
* - Prevents confusion between app API and package APIs
|
|
621
|
+
*/
|
|
622
|
+
declare function defineRouter<TRoutes extends Record<string, RouteDef<any, any, any> | Router<any>>>(routes: TRoutes): Router<TRoutes>;
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Route Registration for define-route style routing
|
|
626
|
+
*
|
|
627
|
+
* Registers routes defined with route.get()...handler() to Hono app
|
|
628
|
+
*/
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Register routes from defineRouter() to Hono app
|
|
632
|
+
*
|
|
633
|
+
* @param app - Hono app instance
|
|
634
|
+
* @param router - Router definition
|
|
635
|
+
* @param namedMiddlewares - Optional server-level named middlewares
|
|
636
|
+
*
|
|
637
|
+
* @example
|
|
638
|
+
* ```ts
|
|
639
|
+
* const appRouter = defineRouter({
|
|
640
|
+
* getUser: route.get('/users/:id')...
|
|
641
|
+
* createUser: route.post('/users')...
|
|
642
|
+
* });
|
|
643
|
+
*
|
|
644
|
+
* const app = new Hono();
|
|
645
|
+
* const namedMiddlewares = [
|
|
646
|
+
* { name: 'auth', handler: AuthMiddleware() },
|
|
647
|
+
* { name: 'rateLimit', handler: RateLimitMiddleware() },
|
|
648
|
+
* ];
|
|
649
|
+
* registerRoutes(app, appRouter, namedMiddlewares);
|
|
650
|
+
* ```
|
|
651
|
+
*/
|
|
652
|
+
declare function registerRoutes<TRoutes extends Record<string, RouteDef<any> | Router<any>>>(app: Hono, router: Router<TRoutes>, namedMiddlewares?: ReadonlyArray<{
|
|
653
|
+
name: string;
|
|
654
|
+
handler: MiddlewareHandler;
|
|
655
|
+
}>): void;
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Type guard for HttpMethod
|
|
659
|
+
*/
|
|
660
|
+
declare function isHttpMethod(value: unknown): value is HttpMethod;
|
|
661
|
+
/**
|
|
662
|
+
* Nullable - Creates a union of T | null
|
|
663
|
+
*
|
|
664
|
+
* @example
|
|
665
|
+
* ```typescript
|
|
666
|
+
* // string | null
|
|
667
|
+
* firstName: Nullable(Type.String())
|
|
668
|
+
* ```
|
|
669
|
+
*/
|
|
670
|
+
declare const Nullable: <T extends TSchema>(schema: T) => _sinclair_typebox.TUnion<[T, _sinclair_typebox.TNull]>;
|
|
671
|
+
/**
|
|
672
|
+
* OptionalNullable - Creates a union of T | null | undefined
|
|
35
673
|
*
|
|
36
|
-
*
|
|
674
|
+
* @example
|
|
675
|
+
* ```typescript
|
|
676
|
+
* // string | null | undefined
|
|
677
|
+
* lastName: OptionalNullable(Type.String())
|
|
678
|
+
* ```
|
|
37
679
|
*/
|
|
38
|
-
declare
|
|
680
|
+
declare const OptionalNullable: <T extends TSchema>(schema: T) => _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<[T, _sinclair_typebox.TNull]>>;
|
|
39
681
|
|
|
40
|
-
export {
|
|
682
|
+
export { type ExtractMiddlewareNames, HttpMethod, type MergedInput, type NamedMiddleware, type NamedMiddlewareFactory, Nullable, OptionalNullable, RouteBuilder, type RouteBuilderContext, type RouteDef, type RouteHandlerFn, type RouteInput, type Router, defineMiddleware, defineMiddlewareFactory, defineRouter, isHttpMethod, registerRoutes, route };
|