@spfn/core 0.2.0-beta.67 → 0.2.0-beta.68
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 +309 -116
- package/dist/authz/index.js +398 -3
- package/dist/authz/index.js.map +1 -1
- package/dist/codegen/index.d.ts +114 -8
- package/dist/codegen/index.js +162 -3
- package/dist/codegen/index.js.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/contract/index.d.ts +288 -0
- package/dist/contract/index.js +534 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/{define-middleware-DuXD8Hvu.d.ts → define-middleware-B9bFuXVU.d.ts} +1 -1
- package/dist/errors/index.js +398 -3
- package/dist/errors/index.js.map +1 -1
- package/dist/event/index.d.ts +3 -3
- package/dist/event/sse/client.d.ts +2 -2
- package/dist/event/sse/index.d.ts +4 -4
- package/dist/event/sse/index.js +9 -0
- package/dist/event/sse/index.js.map +1 -1
- package/dist/event/ws/client.d.ts +2 -2
- package/dist/event/ws/index.d.ts +3 -3
- package/dist/middleware/index.d.ts +108 -11
- package/dist/middleware/index.js +769 -632
- package/dist/middleware/index.js.map +1 -1
- package/dist/route/index.d.ts +8 -552
- package/dist/route/index.js +36 -0
- package/dist/route/index.js.map +1 -1
- package/dist/router-DhvbMhef.d.ts +641 -0
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.js +9 -0
- package/dist/server/index.js.map +1 -1
- package/dist/{token-manager-jKD_EsSE.d.ts → token-manager-vZeqBbtA.d.ts} +7 -0
- package/dist/{types-DVjf37yO.d.ts → types-CF-37KAG.d.ts} +1 -1
- package/dist/{types-BFB72jbM.d.ts → types-D9uMxeQS.d.ts} +1 -1
- package/package.json +11 -9
package/dist/route/index.d.ts
CHANGED
|
@@ -1,555 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { ContentfulStatusCode, RedirectStatusCode } from 'hono/utils/http-status';
|
|
5
|
-
import { N as NamedMiddleware } from '../define-middleware-DuXD8Hvu.js';
|
|
6
|
-
export { E as ExtractMiddlewareNames, b as NamedMiddlewareFactory, d as defineMiddleware, a as defineMiddlewareFactory } from '../define-middleware-DuXD8Hvu.js';
|
|
1
|
+
import { R as RouteDef, a as Router } from '../router-DhvbMhef.js';
|
|
2
|
+
export { M as MergedInput, P as PaginatedResult, f as RouteAuthProfile, c as RouteBuilderContext, e as RouteContract, d as RouteHandlerFn, b as RouteInput, g as defineRouter, r as route } from '../router-DhvbMhef.js';
|
|
3
|
+
import { Hono, MiddlewareHandler } from 'hono';
|
|
7
4
|
import { HttpMethod } from './types.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* Defines the structure for route input validation schemas
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Route input schemas
|
|
17
|
-
*
|
|
18
|
-
* Defines validation schemas for different parts of an HTTP request
|
|
19
|
-
*/
|
|
20
|
-
type RouteInput = {
|
|
21
|
-
/** Path parameters (e.g., /users/:id) */
|
|
22
|
-
params?: TSchema;
|
|
23
|
-
/** Query string parameters (e.g., ?page=1&limit=20) */
|
|
24
|
-
query?: TSchema;
|
|
25
|
-
/** Request body (JSON) */
|
|
26
|
-
body?: TSchema;
|
|
27
|
-
/** Form data (multipart/form-data) for file uploads */
|
|
28
|
-
formData?: TSchema;
|
|
29
|
-
/** HTTP headers */
|
|
30
|
-
headers?: TSchema;
|
|
31
|
-
/** Cookies */
|
|
32
|
-
cookies?: TSchema;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Route Builder Context
|
|
37
|
-
*
|
|
38
|
-
* Provides structured input access and response helpers for route handlers
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Paginated response structure
|
|
43
|
-
*/
|
|
44
|
-
type PaginatedResult<T> = {
|
|
45
|
-
items: T[];
|
|
46
|
-
pagination: {
|
|
47
|
-
page: number;
|
|
48
|
-
limit: number;
|
|
49
|
-
total: number;
|
|
50
|
-
totalPages: number;
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* Merge input with interceptor-injected fields
|
|
55
|
-
* Server receives both client input and interceptor-injected fields
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```ts
|
|
59
|
-
* type ClientInput = { body: { email: string, password: string } };
|
|
60
|
-
* type InterceptorInput = { body: { publicKey: string, keyId: string } };
|
|
61
|
-
* // MergedInput = { body: { email: string, password: string, publicKey: string, keyId: string } }
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
64
|
-
type MergedInput<TInput extends RouteInput, TInterceptor extends RouteInput> = {
|
|
65
|
-
params: (TInput['params'] extends TSchema ? Static<TInput['params']> : {}) & (TInterceptor['params'] extends TSchema ? Static<TInterceptor['params']> : {});
|
|
66
|
-
query: (TInput['query'] extends TSchema ? Static<TInput['query']> : {}) & (TInterceptor['query'] extends TSchema ? Static<TInterceptor['query']> : {});
|
|
67
|
-
body: (TInput['body'] extends TSchema ? Static<TInput['body']> : {}) & (TInterceptor['body'] extends TSchema ? Static<TInterceptor['body']> : {});
|
|
68
|
-
formData: (TInput['formData'] extends TSchema ? Static<TInput['formData']> : {}) & (TInterceptor['formData'] extends TSchema ? Static<TInterceptor['formData']> : {});
|
|
69
|
-
headers: (TInput['headers'] extends TSchema ? Static<TInput['headers']> : {}) & (TInterceptor['headers'] extends TSchema ? Static<TInterceptor['headers']> : {});
|
|
70
|
-
cookies: (TInput['cookies'] extends TSchema ? Static<TInput['cookies']> : {}) & (TInterceptor['cookies'] extends TSchema ? Static<TInterceptor['cookies']> : {});
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* RouteBuilderContext - define-route dedicated context
|
|
74
|
-
*
|
|
75
|
-
* Provides structured input access through data() method
|
|
76
|
-
*/
|
|
77
|
-
type RouteBuilderContext<TInput extends RouteInput = RouteInput, TInterceptor extends RouteInput = {}> = {
|
|
78
|
-
/**
|
|
79
|
-
* Get structured input data
|
|
80
|
-
*
|
|
81
|
-
* Returns an object with separate params, query, body, headers, cookies
|
|
82
|
-
* If interceptor fields are defined, they are merged with input fields
|
|
83
|
-
*
|
|
84
|
-
* @example
|
|
85
|
-
* ```ts
|
|
86
|
-
* // GET /users/:id?page=1
|
|
87
|
-
* const { params, query } = await c.data();
|
|
88
|
-
* // params = { id: string }
|
|
89
|
-
* // query = { page: number }
|
|
90
|
-
*
|
|
91
|
-
* // POST /users with headers
|
|
92
|
-
* const { body, headers } = await c.data();
|
|
93
|
-
* // body = { name: string }
|
|
94
|
-
* // headers = { authorization: string }
|
|
95
|
-
*
|
|
96
|
-
* // With interceptor-injected fields
|
|
97
|
-
* const { body } = await c.data();
|
|
98
|
-
* // body = { email: string, password: string, publicKey: string, keyId: string }
|
|
99
|
-
* ```
|
|
100
|
-
*/
|
|
101
|
-
data(): Promise<MergedInput<TInput, TInterceptor>>;
|
|
102
|
-
/**
|
|
103
|
-
* Return JSON response with custom status and headers
|
|
104
|
-
*
|
|
105
|
-
* @example
|
|
106
|
-
* ```ts
|
|
107
|
-
* return c.json({ message: 'Custom response' }, 200);
|
|
108
|
-
* ```
|
|
109
|
-
*/
|
|
110
|
-
json(data: unknown, status?: ContentfulStatusCode, headers?: Record<string, string | string[]>): Response;
|
|
111
|
-
/**
|
|
112
|
-
* Return 201 Created response with optional Location header
|
|
113
|
-
* Returns data directly for type inference
|
|
114
|
-
*
|
|
115
|
-
* @example
|
|
116
|
-
* ```ts
|
|
117
|
-
* const user = await createUser(body);
|
|
118
|
-
* return c.created(user, `/users/${user.id}`);
|
|
119
|
-
* // Response: 201 Created
|
|
120
|
-
* // Header: Location: /users/123
|
|
121
|
-
* // Body: { id: '123', name: 'John' }
|
|
122
|
-
* // Type: User (inferred from data)
|
|
123
|
-
* ```
|
|
124
|
-
*/
|
|
125
|
-
created<T>(data: T, location?: string): T;
|
|
126
|
-
/**
|
|
127
|
-
* Return 202 Accepted response
|
|
128
|
-
* Returns data directly for type inference
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* ```ts
|
|
132
|
-
* // With data
|
|
133
|
-
* return c.accepted({ jobId: '123' });
|
|
134
|
-
* // Response: 202 Accepted, Body: { jobId: '123' }
|
|
135
|
-
* // Type: { jobId: string }
|
|
136
|
-
*
|
|
137
|
-
* // Without data
|
|
138
|
-
* return c.accepted();
|
|
139
|
-
* // Response: 202 Accepted, Body: (empty)
|
|
140
|
-
* // Type: void
|
|
141
|
-
* ```
|
|
142
|
-
*/
|
|
143
|
-
accepted(): void;
|
|
144
|
-
accepted<T>(data: T): T;
|
|
145
|
-
/**
|
|
146
|
-
* Return 204 No Content response (empty body)
|
|
147
|
-
*
|
|
148
|
-
* @example
|
|
149
|
-
* ```ts
|
|
150
|
-
* await deleteUser(id);
|
|
151
|
-
* return c.noContent();
|
|
152
|
-
* // Response: 204 No Content, Body: (empty)
|
|
153
|
-
* // Type: void
|
|
154
|
-
* ```
|
|
155
|
-
*/
|
|
156
|
-
noContent(): void;
|
|
157
|
-
/**
|
|
158
|
-
* Return 304 Not Modified response (empty body)
|
|
159
|
-
*
|
|
160
|
-
* @example
|
|
161
|
-
* ```ts
|
|
162
|
-
* if (etag === requestEtag) {
|
|
163
|
-
* return c.notModified();
|
|
164
|
-
* }
|
|
165
|
-
* // Response: 304 Not Modified, Body: (empty)
|
|
166
|
-
* // Type: void
|
|
167
|
-
* ```
|
|
168
|
-
*/
|
|
169
|
-
notModified(): void;
|
|
170
|
-
/**
|
|
171
|
-
* Return paginated response with metadata
|
|
172
|
-
* Returns `{ items: [...], pagination: {...} }` format with type inference
|
|
173
|
-
*
|
|
174
|
-
* @example
|
|
175
|
-
* ```ts
|
|
176
|
-
* const users = await getUsers(page, limit);
|
|
177
|
-
* const total = await countUsers();
|
|
178
|
-
* return c.paginated(users, page, limit, total);
|
|
179
|
-
* // Response: {
|
|
180
|
-
* // items: [...],
|
|
181
|
-
* // pagination: {
|
|
182
|
-
* // page: 1,
|
|
183
|
-
* // limit: 20,
|
|
184
|
-
* // total: 100,
|
|
185
|
-
* // totalPages: 5
|
|
186
|
-
* // }
|
|
187
|
-
* // }
|
|
188
|
-
* // Type: PaginatedResult<User>
|
|
189
|
-
* ```
|
|
190
|
-
*/
|
|
191
|
-
paginated<T>(data: T[], page: number, limit: number, total: number): PaginatedResult<T>;
|
|
192
|
-
/**
|
|
193
|
-
* Redirect to another URL
|
|
194
|
-
*
|
|
195
|
-
* @param url - Target URL to redirect to
|
|
196
|
-
* @param status - HTTP status code (301, 302, 303, 307, 308). Default: 302
|
|
197
|
-
*
|
|
198
|
-
* @example
|
|
199
|
-
* ```ts
|
|
200
|
-
* // Temporary redirect (302)
|
|
201
|
-
* return c.redirect('/login');
|
|
202
|
-
*
|
|
203
|
-
* // Permanent redirect (301)
|
|
204
|
-
* return c.redirect('/new-path', 301);
|
|
205
|
-
*
|
|
206
|
-
* // See Other (303) - useful after POST
|
|
207
|
-
* return c.redirect('/success', 303);
|
|
208
|
-
* ```
|
|
209
|
-
*/
|
|
210
|
-
redirect(url: string, status?: RedirectStatusCode): Response;
|
|
211
|
-
raw: Context;
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Route Builder
|
|
216
|
-
*
|
|
217
|
-
* Provides tRPC-style chainable API for route definition
|
|
218
|
-
*/
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Route handler function
|
|
222
|
-
*/
|
|
223
|
-
type RouteHandlerFn<TInput extends RouteInput = RouteInput, TInterceptor extends RouteInput = {}, TResponse = unknown> = (c: RouteBuilderContext<TInput, TInterceptor>) => Response | Promise<Response> | TResponse | Promise<TResponse>;
|
|
224
|
-
/**
|
|
225
|
-
* Route definition result
|
|
226
|
-
*
|
|
227
|
-
* Contains all information needed for type inference and registration
|
|
228
|
-
*/
|
|
229
|
-
type RouteDef<TInput extends RouteInput = RouteInput, TInterceptor extends RouteInput = {}, TResponse = unknown> = {
|
|
230
|
-
method?: HttpMethod;
|
|
231
|
-
path?: string;
|
|
232
|
-
input?: TInput;
|
|
233
|
-
interceptor?: TInterceptor;
|
|
234
|
-
middlewares?: (MiddlewareHandler | NamedMiddleware<string>)[];
|
|
235
|
-
skipMiddlewares?: string[] | '*';
|
|
236
|
-
handler: RouteHandlerFn<TInput, TInterceptor, TResponse>;
|
|
237
|
-
_input: TInput;
|
|
238
|
-
_interceptor: TInterceptor;
|
|
239
|
-
_response: TResponse;
|
|
240
|
-
};
|
|
241
|
-
/**
|
|
242
|
-
* Route builder with chainable API (tRPC-style)
|
|
243
|
-
*/
|
|
244
|
-
declare class RouteBuilder<TInput extends RouteInput = {}, TInterceptor extends RouteInput = {}, TResponse = never> {
|
|
245
|
-
_method?: HttpMethod;
|
|
246
|
-
_path?: string;
|
|
247
|
-
_input?: TInput;
|
|
248
|
-
_interceptor?: TInterceptor;
|
|
249
|
-
_middlewares?: (MiddlewareHandler | NamedMiddleware<string>)[];
|
|
250
|
-
_skipMiddlewares?: string[] | '*';
|
|
251
|
-
/**
|
|
252
|
-
* Create a new RouteBuilder with copied properties and optional overrides
|
|
253
|
-
*/
|
|
254
|
-
private clone;
|
|
255
|
-
/**
|
|
256
|
-
* Define input schemas
|
|
257
|
-
*
|
|
258
|
-
* @example
|
|
259
|
-
* ```ts
|
|
260
|
-
* route.get('/users/:id')
|
|
261
|
-
* .input({
|
|
262
|
-
* params: Type.Object({ id: Type.String() }),
|
|
263
|
-
* query: Type.Object({ page: Type.Number() }),
|
|
264
|
-
* headers: Type.Object({ authorization: Type.String() })
|
|
265
|
-
* })
|
|
266
|
-
* .handler(async (c) => {
|
|
267
|
-
* const { params, query, headers } = await c.data();
|
|
268
|
-
* // params = { id: string }
|
|
269
|
-
* // query = { page: number }
|
|
270
|
-
* // headers = { authorization: string }
|
|
271
|
-
* })
|
|
272
|
-
* ```
|
|
273
|
-
*/
|
|
274
|
-
input<TNewInput extends RouteInput>(input: TNewInput): RouteBuilder<TNewInput, TInterceptor, TResponse>;
|
|
275
|
-
/**
|
|
276
|
-
* Define fields injected by interceptors
|
|
277
|
-
*
|
|
278
|
-
* These fields are:
|
|
279
|
-
* - Available in the handler (merged with input)
|
|
280
|
-
* - Excluded from client types (codegen uses only input)
|
|
281
|
-
* - Not validated by route input schema (injected by middleware)
|
|
282
|
-
*
|
|
283
|
-
* Use this when middleware/interceptors add fields to the request
|
|
284
|
-
* before it reaches the handler.
|
|
285
|
-
*
|
|
286
|
-
* @example
|
|
287
|
-
* ```ts
|
|
288
|
-
* // Auth interceptor injects crypto key fields
|
|
289
|
-
* route.post('/_auth/login')
|
|
290
|
-
* .input({
|
|
291
|
-
* body: Type.Object({
|
|
292
|
-
* email: Type.String(),
|
|
293
|
-
* password: Type.String()
|
|
294
|
-
* })
|
|
295
|
-
* })
|
|
296
|
-
* .interceptor({
|
|
297
|
-
* body: Type.Object({
|
|
298
|
-
* publicKey: Type.String(),
|
|
299
|
-
* keyId: Type.String(),
|
|
300
|
-
* fingerprint: Type.String()
|
|
301
|
-
* })
|
|
302
|
-
* })
|
|
303
|
-
* .handler(async (c) => {
|
|
304
|
-
* const { body } = await c.data();
|
|
305
|
-
* // body type: { email, password, publicKey, keyId, fingerprint }
|
|
306
|
-
* // Client only sees: { email, password }
|
|
307
|
-
* return loginService(body);
|
|
308
|
-
* });
|
|
309
|
-
* ```
|
|
310
|
-
*/
|
|
311
|
-
interceptor<TNewInterceptor extends RouteInput>(interceptor: TNewInterceptor): RouteBuilder<TInput, TNewInterceptor, TResponse>;
|
|
312
|
-
/**
|
|
313
|
-
* Add middlewares to the route
|
|
314
|
-
*
|
|
315
|
-
* Accepts both regular middleware handlers and named middlewares (NamedMiddleware).
|
|
316
|
-
* Named middlewares that are already registered globally will be automatically
|
|
317
|
-
* deduplicated to prevent double execution.
|
|
318
|
-
*
|
|
319
|
-
* @example
|
|
320
|
-
* ```ts
|
|
321
|
-
* import { authenticate } from '@spfn/auth/server/middleware';
|
|
322
|
-
*
|
|
323
|
-
* // With NamedMiddleware (auto-deduped if registered globally)
|
|
324
|
-
* route.get('/users')
|
|
325
|
-
* .use([authenticate, RateLimitMiddleware()])
|
|
326
|
-
*
|
|
327
|
-
* // With regular middleware handlers
|
|
328
|
-
* route.get('/users')
|
|
329
|
-
* .use([AuthMiddleware(), RateLimitMiddleware()])
|
|
330
|
-
* ```
|
|
331
|
-
*/
|
|
332
|
-
middleware(middlewares: (MiddlewareHandler | NamedMiddleware<string>)[]): RouteBuilder<TInput, TInterceptor, TResponse>;
|
|
333
|
-
/**
|
|
334
|
-
* Add middlewares to the route (alias for `.middleware()`)
|
|
335
|
-
*
|
|
336
|
-
* Accepts both regular middleware handlers and named middlewares (NamedMiddleware).
|
|
337
|
-
* Named middlewares that are already registered globally will be automatically
|
|
338
|
-
* deduplicated to prevent double execution.
|
|
339
|
-
*
|
|
340
|
-
* @example
|
|
341
|
-
* ```ts
|
|
342
|
-
* import { authenticate } from '@spfn/auth/server/middleware';
|
|
343
|
-
*
|
|
344
|
-
* // With NamedMiddleware (auto-deduped if registered globally)
|
|
345
|
-
* route.get('/users')
|
|
346
|
-
* .use([authenticate, RateLimitMiddleware()])
|
|
347
|
-
*
|
|
348
|
-
* // With regular middleware handlers
|
|
349
|
-
* route.get('/users')
|
|
350
|
-
* .use([AuthMiddleware(), RateLimitMiddleware()])
|
|
351
|
-
* ```
|
|
352
|
-
*/
|
|
353
|
-
use(middlewares: (MiddlewareHandler | NamedMiddleware<string>)[]): RouteBuilder<TInput, TInterceptor, TResponse>;
|
|
354
|
-
/**
|
|
355
|
-
* Skip server-level named middlewares
|
|
356
|
-
*
|
|
357
|
-
* Useful for public endpoints that should bypass auth or rate limiting
|
|
358
|
-
*
|
|
359
|
-
* @param middlewareNames - Array of middleware names to skip, or '*' to skip all
|
|
360
|
-
*
|
|
361
|
-
* @example
|
|
362
|
-
* ```ts
|
|
363
|
-
* // Skip specific middlewares
|
|
364
|
-
* route.get('/health')
|
|
365
|
-
* .skip(['auth', 'rateLimit'])
|
|
366
|
-
* .handler(async (c) => c.json({ status: 'ok' }));
|
|
367
|
-
*
|
|
368
|
-
* // Skip only auth (still apply rate limiting)
|
|
369
|
-
* route.get('/public-data')
|
|
370
|
-
* .skip(['auth'])
|
|
371
|
-
* .handler(async (c) => { ... });
|
|
372
|
-
*
|
|
373
|
-
* // Skip all middlewares
|
|
374
|
-
* route.get('/public-health')
|
|
375
|
-
* .skip('*')
|
|
376
|
-
* .handler(async (c) => c.json({ status: 'ok' }));
|
|
377
|
-
* ```
|
|
378
|
-
*/
|
|
379
|
-
skip(middlewareNames: string[] | '*'): RouteBuilder<TInput, TInterceptor, TResponse>;
|
|
380
|
-
/**
|
|
381
|
-
* Define handler function
|
|
382
|
-
*
|
|
383
|
-
* Response type is automatically inferred from the return value.
|
|
384
|
-
* Use helper methods like `c.created()`, `c.paginated()` for proper type inference.
|
|
385
|
-
*
|
|
386
|
-
* @example
|
|
387
|
-
* ```ts
|
|
388
|
-
* // Direct return - type inferred from data
|
|
389
|
-
* route.get('/users/:id')
|
|
390
|
-
* .input({ params: Type.Object({ id: Type.String() }) })
|
|
391
|
-
* .handler(async (c) => {
|
|
392
|
-
* const { params } = await c.data();
|
|
393
|
-
* return await getUser(params.id); // Type: User
|
|
394
|
-
* })
|
|
395
|
-
*
|
|
396
|
-
* // Using c.created() - returns data with 201 status, type preserved
|
|
397
|
-
* route.post('/users')
|
|
398
|
-
* .input({ body: Type.Object({ name: Type.String() }) })
|
|
399
|
-
* .handler(async (c) => {
|
|
400
|
-
* const { body } = await c.data();
|
|
401
|
-
* return c.created(await createUser(body)); // Type: User
|
|
402
|
-
* })
|
|
403
|
-
*
|
|
404
|
-
* // Using c.paginated() - returns PaginatedResult<T>
|
|
405
|
-
* route.get('/users')
|
|
406
|
-
* .handler(async (c) => {
|
|
407
|
-
* const users = await getUsers();
|
|
408
|
-
* return c.paginated(users, 1, 20, 100); // Type: PaginatedResult<User>
|
|
409
|
-
* })
|
|
410
|
-
*
|
|
411
|
-
* // Using c.noContent() - returns void
|
|
412
|
-
* route.delete('/users/:id')
|
|
413
|
-
* .handler(async (c) => {
|
|
414
|
-
* await deleteUser(params.id);
|
|
415
|
-
* return c.noContent(); // Type: void
|
|
416
|
-
* })
|
|
417
|
-
*
|
|
418
|
-
* // Using c.json() - returns Response (type inference lost)
|
|
419
|
-
* // Use only when you need custom status codes not covered by helpers
|
|
420
|
-
* route.get('/custom')
|
|
421
|
-
* .handler(async (c) => {
|
|
422
|
-
* return c.json({ data }, 418); // Type: Response
|
|
423
|
-
* })
|
|
424
|
-
* ```
|
|
425
|
-
*/
|
|
426
|
-
handler<THandlerResponse>(fn: RouteHandlerFn<TInput, TInterceptor, THandlerResponse>): RouteDef<TInput, TInterceptor, THandlerResponse>;
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Route builder entry point
|
|
430
|
-
*
|
|
431
|
-
* @example
|
|
432
|
-
* ```ts
|
|
433
|
-
* // GET request
|
|
434
|
-
* export const getUser = route.get('/users/:id')
|
|
435
|
-
* .input({ params: Type.Object({ id: Type.String() }) })
|
|
436
|
-
* .handler(async (c) => {
|
|
437
|
-
* const { params } = await c.data();
|
|
438
|
-
* return await db.user.findUnique({ where: { id: params.id } });
|
|
439
|
-
* });
|
|
440
|
-
*
|
|
441
|
-
* // POST request
|
|
442
|
-
* export const createUser = route.post('/users')
|
|
443
|
-
* .input({ body: Type.Object({ name: Type.String(), email: Type.String() }) })
|
|
444
|
-
* .handler(async (c) => {
|
|
445
|
-
* const { body } = await c.data();
|
|
446
|
-
* return c.created(await db.user.create({ data: body }));
|
|
447
|
-
* });
|
|
448
|
-
* ```
|
|
449
|
-
*/
|
|
450
|
-
declare const route: {
|
|
451
|
-
get: (path: string) => RouteBuilder;
|
|
452
|
-
post: (path: string) => RouteBuilder;
|
|
453
|
-
put: (path: string) => RouteBuilder;
|
|
454
|
-
patch: (path: string) => RouteBuilder;
|
|
455
|
-
delete: (path: string) => RouteBuilder;
|
|
456
|
-
};
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Router Definition
|
|
460
|
-
*
|
|
461
|
-
* Provides router composition and middleware management
|
|
462
|
-
*/
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Router definition - holds all routes
|
|
466
|
-
*/
|
|
467
|
-
interface Router<TRoutes extends Record<string, RouteDef<any, any, any> | Router<any>>> {
|
|
468
|
-
routes: TRoutes;
|
|
469
|
-
_routes: TRoutes;
|
|
470
|
-
_packageRouters: Router<any>[];
|
|
471
|
-
_globalMiddlewares: NamedMiddleware<string>[];
|
|
472
|
-
/**
|
|
473
|
-
* Register package routers (type-hidden)
|
|
474
|
-
*
|
|
475
|
-
* Package routes are:
|
|
476
|
-
* - Recognized by RPC proxy and backend
|
|
477
|
-
* - NOT exposed in client types (use package's own API like authApi, cmsApi)
|
|
478
|
-
*
|
|
479
|
-
* @example
|
|
480
|
-
* ```ts
|
|
481
|
-
* import { authRouter } from '@spfn/auth/server';
|
|
482
|
-
* import { cmsAppRouter } from '@spfn/cms/server';
|
|
483
|
-
*
|
|
484
|
-
* export const appRouter = defineRouter({
|
|
485
|
-
* getRoot,
|
|
486
|
-
* getHealth,
|
|
487
|
-
* })
|
|
488
|
-
* .packages([authRouter, cmsAppRouter]);
|
|
489
|
-
*
|
|
490
|
-
* // Client usage:
|
|
491
|
-
* // api.getRoot.call({}) - app routes
|
|
492
|
-
* // authApi.login.call({}) - package API
|
|
493
|
-
* ```
|
|
494
|
-
*/
|
|
495
|
-
packages(routers: Router<any>[]): Router<TRoutes>;
|
|
496
|
-
/**
|
|
497
|
-
* Register global middlewares
|
|
498
|
-
*
|
|
499
|
-
* Applied to all routes unless explicitly skipped via .skip()
|
|
500
|
-
*
|
|
501
|
-
* @example
|
|
502
|
-
* ```ts
|
|
503
|
-
* import { authMiddleware, loggingMiddleware } from './middlewares';
|
|
504
|
-
*
|
|
505
|
-
* export const appRouter = defineRouter({
|
|
506
|
-
* getRoot,
|
|
507
|
-
* getHealth,
|
|
508
|
-
* })
|
|
509
|
-
* .packages([authRouter])
|
|
510
|
-
* .use([authMiddleware, loggingMiddleware]);
|
|
511
|
-
* ```
|
|
512
|
-
*/
|
|
513
|
-
use(middlewares: NamedMiddleware<string>[]): Router<TRoutes>;
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Define a router with multiple routes (tRPC-style)
|
|
517
|
-
*
|
|
518
|
-
* Supports chainable API for packages and middlewares:
|
|
519
|
-
*
|
|
520
|
-
* @example
|
|
521
|
-
* ```ts
|
|
522
|
-
* // Basic usage
|
|
523
|
-
* export const appRouter = defineRouter({
|
|
524
|
-
* getRoot,
|
|
525
|
-
* getHealth,
|
|
526
|
-
* listExamples,
|
|
527
|
-
* });
|
|
528
|
-
*
|
|
529
|
-
* // With package routers (type-hidden)
|
|
530
|
-
* export const appRouter = defineRouter({
|
|
531
|
-
* getRoot,
|
|
532
|
-
* getHealth,
|
|
533
|
-
* })
|
|
534
|
-
* .packages([authRouter, cmsAppRouter]);
|
|
535
|
-
*
|
|
536
|
-
* // With global middlewares
|
|
537
|
-
* export const appRouter = defineRouter({
|
|
538
|
-
* getRoot,
|
|
539
|
-
* getHealth,
|
|
540
|
-
* })
|
|
541
|
-
* .packages([authRouter])
|
|
542
|
-
* .use([authMiddleware, loggingMiddleware]);
|
|
543
|
-
*
|
|
544
|
-
* export type AppRouter = typeof appRouter;
|
|
545
|
-
* ```
|
|
546
|
-
*
|
|
547
|
-
* Package routes:
|
|
548
|
-
* - Recognized by RPC proxy and backend for routing
|
|
549
|
-
* - NOT included in AppRouter type (use authApi, cmsApi instead)
|
|
550
|
-
* - Prevents confusion between app API and package APIs
|
|
551
|
-
*/
|
|
552
|
-
declare function defineRouter<TRoutes extends Record<string, RouteDef<any, any, any> | Router<any>>>(routes: TRoutes): Router<TRoutes>;
|
|
5
|
+
export { E as ExtractMiddlewareNames, b as NamedMiddleware, N as NamedMiddlewareFactory, d as defineMiddleware, a as defineMiddlewareFactory } from '../define-middleware-B9bFuXVU.js';
|
|
6
|
+
import * as _sinclair_typebox from '@sinclair/typebox';
|
|
7
|
+
import { TSchema, Kind } from '@sinclair/typebox';
|
|
8
|
+
import 'hono/utils/http-status';
|
|
553
9
|
|
|
554
10
|
/**
|
|
555
11
|
* Route Registration for define-route style routing
|
|
@@ -749,4 +205,4 @@ declare function getFileOptions(schema: TSchema): FileSchemaOptions | FileArrayS
|
|
|
749
205
|
*/
|
|
750
206
|
declare function formatFileSize(bytes: number): string;
|
|
751
207
|
|
|
752
|
-
export { FileArraySchema, type FileArraySchemaOptions, type FileArraySchemaType, FileSchema, type FileSchemaOptions, type FileSchemaType, HttpMethod,
|
|
208
|
+
export { FileArraySchema, type FileArraySchemaOptions, type FileArraySchemaType, FileSchema, type FileSchemaOptions, type FileSchemaType, HttpMethod, Nullable, OptionalFileSchema, OptionalNullable, type RegisteredRoute, RouteDef, Router, formatFileSize, getFileOptions, isFileArraySchema, isFileSchema, isHttpMethod, registerRoutes };
|
package/dist/route/index.js
CHANGED
|
@@ -11,6 +11,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
11
11
|
_interceptor;
|
|
12
12
|
_middlewares;
|
|
13
13
|
_skipMiddlewares;
|
|
14
|
+
_contract;
|
|
14
15
|
/**
|
|
15
16
|
* Create a new RouteBuilder with copied properties and optional overrides
|
|
16
17
|
*/
|
|
@@ -22,6 +23,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
22
23
|
builder._interceptor = overrides?.interceptor ?? this._interceptor;
|
|
23
24
|
builder._middlewares = overrides?.middlewares ?? this._middlewares;
|
|
24
25
|
builder._skipMiddlewares = overrides?.skipMiddlewares ?? this._skipMiddlewares;
|
|
26
|
+
builder._contract = overrides?.contract ?? this._contract;
|
|
25
27
|
return builder;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
@@ -159,6 +161,39 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
159
161
|
skip(middlewareNames) {
|
|
160
162
|
return this.clone({ skipMiddlewares: middlewareNames });
|
|
161
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Publish this route as a versioned contract operation
|
|
166
|
+
*
|
|
167
|
+
* Marks the route as a promise to clients that are compiled and deployed
|
|
168
|
+
* separately from the server — a mobile app, an external API consumer.
|
|
169
|
+
* The `@spfn/core:contract` generator writes every contracted route into
|
|
170
|
+
* `contracts/current.json`, and the build refuses a change that would break
|
|
171
|
+
* an already-released client.
|
|
172
|
+
*
|
|
173
|
+
* Routes without `.contract()` are unaffected: they simply do not appear in
|
|
174
|
+
* the contract. A web client needs nothing here — it derives its types from
|
|
175
|
+
* the router in the same build.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* export const getUser = route.get('/users/:id')
|
|
180
|
+
* .input({ params: Type.Object({ id: Type.String() }) })
|
|
181
|
+
* .contract({
|
|
182
|
+
* since: '1.2.0',
|
|
183
|
+
* auth: 'clientProofV1',
|
|
184
|
+
* requiresSession: true,
|
|
185
|
+
* response: Type.Object({
|
|
186
|
+
* id: Type.String(),
|
|
187
|
+
* name: Type.String(),
|
|
188
|
+
* email: Type.Optional(Type.String()),
|
|
189
|
+
* }),
|
|
190
|
+
* })
|
|
191
|
+
* .handler(async (c) => { ... });
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
contract(contract) {
|
|
195
|
+
return this.clone({ contract });
|
|
196
|
+
}
|
|
162
197
|
/**
|
|
163
198
|
* Define handler function
|
|
164
199
|
*
|
|
@@ -213,6 +248,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
213
248
|
interceptor: this._interceptor,
|
|
214
249
|
middlewares: this._middlewares,
|
|
215
250
|
skipMiddlewares: this._skipMiddlewares,
|
|
251
|
+
contract: this._contract,
|
|
216
252
|
handler: fn,
|
|
217
253
|
_input: {},
|
|
218
254
|
_interceptor: {},
|