@spfn/core 0.1.0-alpha.86 → 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.
Files changed (71) hide show
  1. package/README.md +1046 -384
  2. package/dist/boss-D-fGtVgM.d.ts +187 -0
  3. package/dist/cache/index.d.ts +13 -33
  4. package/dist/cache/index.js +14 -703
  5. package/dist/cache/index.js.map +1 -1
  6. package/dist/codegen/index.d.ts +167 -17
  7. package/dist/codegen/index.js +76 -1419
  8. package/dist/codegen/index.js.map +1 -1
  9. package/dist/config/index.d.ts +1191 -0
  10. package/dist/config/index.js +264 -0
  11. package/dist/config/index.js.map +1 -0
  12. package/dist/db/index.d.ts +728 -59
  13. package/dist/db/index.js +1028 -1225
  14. package/dist/db/index.js.map +1 -1
  15. package/dist/env/index.d.ts +579 -308
  16. package/dist/env/index.js +438 -930
  17. package/dist/env/index.js.map +1 -1
  18. package/dist/errors/index.d.ts +417 -29
  19. package/dist/errors/index.js +359 -98
  20. package/dist/errors/index.js.map +1 -1
  21. package/dist/event/index.d.ts +108 -0
  22. package/dist/event/index.js +122 -0
  23. package/dist/event/index.js.map +1 -0
  24. package/dist/job/index.d.ts +172 -0
  25. package/dist/job/index.js +361 -0
  26. package/dist/job/index.js.map +1 -0
  27. package/dist/logger/index.d.ts +20 -79
  28. package/dist/logger/index.js +82 -387
  29. package/dist/logger/index.js.map +1 -1
  30. package/dist/middleware/index.d.ts +2 -11
  31. package/dist/middleware/index.js +49 -703
  32. package/dist/middleware/index.js.map +1 -1
  33. package/dist/nextjs/index.d.ts +120 -0
  34. package/dist/nextjs/index.js +416 -0
  35. package/dist/nextjs/index.js.map +1 -0
  36. package/dist/{client/nextjs/index.d.ts → nextjs/server.d.ts} +288 -262
  37. package/dist/nextjs/server.js +568 -0
  38. package/dist/nextjs/server.js.map +1 -0
  39. package/dist/route/index.d.ts +667 -25
  40. package/dist/route/index.js +437 -1287
  41. package/dist/route/index.js.map +1 -1
  42. package/dist/route/types.d.ts +38 -0
  43. package/dist/route/types.js +3 -0
  44. package/dist/route/types.js.map +1 -0
  45. package/dist/server/index.d.ts +201 -67
  46. package/dist/server/index.js +921 -3182
  47. package/dist/server/index.js.map +1 -1
  48. package/dist/types-BGl4QL1w.d.ts +77 -0
  49. package/dist/types-DRG2XMTR.d.ts +157 -0
  50. package/package.json +56 -48
  51. package/dist/auto-loader-JFaZ9gON.d.ts +0 -80
  52. package/dist/client/index.d.ts +0 -358
  53. package/dist/client/index.js +0 -357
  54. package/dist/client/index.js.map +0 -1
  55. package/dist/client/nextjs/index.js +0 -371
  56. package/dist/client/nextjs/index.js.map +0 -1
  57. package/dist/codegen/generators/index.d.ts +0 -19
  58. package/dist/codegen/generators/index.js +0 -1404
  59. package/dist/codegen/generators/index.js.map +0 -1
  60. package/dist/database-errors-BNNmLTJE.d.ts +0 -86
  61. package/dist/events/index.d.ts +0 -183
  62. package/dist/events/index.js +0 -77
  63. package/dist/events/index.js.map +0 -1
  64. package/dist/index-DHiAqhKv.d.ts +0 -101
  65. package/dist/index.d.ts +0 -8
  66. package/dist/index.js +0 -3674
  67. package/dist/index.js.map +0 -1
  68. package/dist/types/index.d.ts +0 -121
  69. package/dist/types/index.js +0 -38
  70. package/dist/types/index.js.map +0 -1
  71. package/dist/types-BXibIEyj.d.ts +0 -60
@@ -1,40 +1,682 @@
1
- export { A as AutoRouteLoader, R as RouteInfo, a as RouteStats, l as loadRoutes } from '../auto-loader-JFaZ9gON.js';
2
- import { Context, Hono, MiddlewareHandler } from 'hono';
3
- import { a as RouteContract, R as RouteContext, b as RouteHandler } from '../types-BXibIEyj.js';
4
- export { c as HeaderRecord, H as HttpMethod, I as InferContract, d as RouteMeta, i as isHttpMethod } from '../types-BXibIEyj.js';
5
- export { ApiErrorResponse, ApiErrorSchema, ApiResponse, ApiResponseSchema, ApiSuccessResponse, ApiSuccessSchema } from '../types/index.js';
6
- import 'hono/utils/http-status';
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
- * Contract-based Route Handler Wrapper
9
+ * Route Input Types
11
10
  *
12
- * Binds a contract to a route handler, providing automatic validation
13
- * and type-safe context creation.
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
- * Features:
16
- * - Automatic params/query/body validation using TypeBox
17
- * - Type-safe RouteContext with contract-based inference
18
- * - Clean separation: bind() for validation, Hono for middleware
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
- declare function bind<TContract extends RouteContract>(contract: TContract, handler: (c: RouteContext<TContract>) => Response | Promise<Response>): (rawContext: Context) => Promise<Response>;
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
- * Create App - Hono Wrapper for Contract-based Routing
173
+ * Middleware Definition Helper
24
174
  *
25
- * Provides a cleaner API for registering routes with contracts
175
+ * Provides type-safe middleware definition with name inference
26
176
  */
27
177
 
28
- type SPFNApp = Hono & {
29
- bind<TContract extends RouteContract>(contract: TContract, handler: RouteHandler<TContract>): void;
30
- bind<TContract extends RouteContract>(contract: TContract, middlewares: MiddlewareHandler[], handler: RouteHandler<TContract>): void;
31
- _contractMetas?: Map<string, RouteContract['meta']>;
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
- * Create SPFN app instance
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
- * Wraps Hono with contract-based routing support
674
+ * @example
675
+ * ```typescript
676
+ * // string | null | undefined
677
+ * lastName: OptionalNullable(Type.String())
678
+ * ```
37
679
  */
38
- declare function createApp(): SPFNApp;
680
+ declare const OptionalNullable: <T extends TSchema>(schema: T) => _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<[T, _sinclair_typebox.TNull]>>;
39
681
 
40
- export { RouteContext, RouteContract, RouteHandler, type SPFNApp, bind, createApp };
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 };