@spfn/core 0.2.0-beta.1 → 0.2.0-beta.10

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 (64) hide show
  1. package/README.md +262 -1092
  2. package/dist/{boss-D-fGtVgM.d.ts → boss-DI1r4kTS.d.ts} +68 -11
  3. package/dist/codegen/index.d.ts +55 -8
  4. package/dist/codegen/index.js +159 -5
  5. package/dist/codegen/index.js.map +1 -1
  6. package/dist/config/index.d.ts +36 -0
  7. package/dist/config/index.js +15 -6
  8. package/dist/config/index.js.map +1 -1
  9. package/dist/db/index.d.ts +13 -0
  10. package/dist/db/index.js +40 -6
  11. package/dist/db/index.js.map +1 -1
  12. package/dist/env/index.d.ts +82 -3
  13. package/dist/env/index.js +81 -14
  14. package/dist/env/index.js.map +1 -1
  15. package/dist/env/loader.d.ts +87 -0
  16. package/dist/env/loader.js +70 -0
  17. package/dist/env/loader.js.map +1 -0
  18. package/dist/event/index.d.ts +3 -70
  19. package/dist/event/index.js +10 -1
  20. package/dist/event/index.js.map +1 -1
  21. package/dist/event/sse/client.d.ts +82 -0
  22. package/dist/event/sse/client.js +115 -0
  23. package/dist/event/sse/client.js.map +1 -0
  24. package/dist/event/sse/index.d.ts +40 -0
  25. package/dist/event/sse/index.js +92 -0
  26. package/dist/event/sse/index.js.map +1 -0
  27. package/dist/job/index.d.ts +54 -8
  28. package/dist/job/index.js +61 -12
  29. package/dist/job/index.js.map +1 -1
  30. package/dist/middleware/index.d.ts +102 -11
  31. package/dist/middleware/index.js +2 -2
  32. package/dist/middleware/index.js.map +1 -1
  33. package/dist/nextjs/index.d.ts +2 -2
  34. package/dist/nextjs/index.js +36 -4
  35. package/dist/nextjs/index.js.map +1 -1
  36. package/dist/nextjs/server.d.ts +62 -15
  37. package/dist/nextjs/server.js +102 -33
  38. package/dist/nextjs/server.js.map +1 -1
  39. package/dist/route/index.d.ts +227 -15
  40. package/dist/route/index.js +307 -31
  41. package/dist/route/index.js.map +1 -1
  42. package/dist/route/types.d.ts +2 -31
  43. package/dist/router-Di7ENoah.d.ts +151 -0
  44. package/dist/server/index.d.ts +153 -6
  45. package/dist/server/index.js +216 -14
  46. package/dist/server/index.js.map +1 -1
  47. package/dist/types-B-e_f2dQ.d.ts +121 -0
  48. package/dist/{types-DRG2XMTR.d.ts → types-BOPTApC2.d.ts} +91 -3
  49. package/docs/cache.md +133 -0
  50. package/docs/codegen.md +74 -0
  51. package/docs/database.md +346 -0
  52. package/docs/entity.md +539 -0
  53. package/docs/env.md +477 -0
  54. package/docs/errors.md +319 -0
  55. package/docs/event.md +116 -0
  56. package/docs/file-upload.md +717 -0
  57. package/docs/job.md +131 -0
  58. package/docs/logger.md +108 -0
  59. package/docs/middleware.md +337 -0
  60. package/docs/nextjs.md +241 -0
  61. package/docs/repository.md +496 -0
  62. package/docs/route.md +497 -0
  63. package/docs/server.md +307 -0
  64. package/package.json +18 -3
@@ -1,9 +1,8 @@
1
1
  import * as _sinclair_typebox from '@sinclair/typebox';
2
- import { TSchema, Static } from '@sinclair/typebox';
2
+ import { TSchema, Static, Kind } from '@sinclair/typebox';
3
3
  import { Context, MiddlewareHandler, Hono } from 'hono';
4
- import { ContentfulStatusCode } from 'hono/utils/http-status';
4
+ import { ContentfulStatusCode, RedirectStatusCode } from 'hono/utils/http-status';
5
5
  import { HttpMethod } from './types.js';
6
- export { HeaderRecord, InferResponseData, RouteMeta, RouteMetadata, RouterMetadata } from './types.js';
7
6
 
8
7
  /**
9
8
  * Route Input Types
@@ -23,6 +22,8 @@ type RouteInput = {
23
22
  query?: TSchema;
24
23
  /** Request body (JSON) */
25
24
  body?: TSchema;
25
+ /** Form data (multipart/form-data) for file uploads */
26
+ formData?: TSchema;
26
27
  /** HTTP headers */
27
28
  headers?: TSchema;
28
29
  /** Cookies */
@@ -35,6 +36,18 @@ type RouteInput = {
35
36
  * Provides structured input access and response helpers for route handlers
36
37
  */
37
38
 
39
+ /**
40
+ * Paginated response structure
41
+ */
42
+ type PaginatedResult<T> = {
43
+ items: T[];
44
+ pagination: {
45
+ page: number;
46
+ limit: number;
47
+ total: number;
48
+ totalPages: number;
49
+ };
50
+ };
38
51
  /**
39
52
  * Merge input with interceptor-injected fields
40
53
  * Server receives both client input and interceptor-injected fields
@@ -50,6 +63,7 @@ type MergedInput<TInput extends RouteInput, TInterceptor extends RouteInput> = {
50
63
  params: (TInput['params'] extends TSchema ? Static<TInput['params']> : {}) & (TInterceptor['params'] extends TSchema ? Static<TInterceptor['params']> : {});
51
64
  query: (TInput['query'] extends TSchema ? Static<TInput['query']> : {}) & (TInterceptor['query'] extends TSchema ? Static<TInterceptor['query']> : {});
52
65
  body: (TInput['body'] extends TSchema ? Static<TInput['body']> : {}) & (TInterceptor['body'] extends TSchema ? Static<TInterceptor['body']> : {});
66
+ formData: (TInput['formData'] extends TSchema ? Static<TInput['formData']> : {}) & (TInterceptor['formData'] extends TSchema ? Static<TInterceptor['formData']> : {});
53
67
  headers: (TInput['headers'] extends TSchema ? Static<TInput['headers']> : {}) & (TInterceptor['headers'] extends TSchema ? Static<TInterceptor['headers']> : {});
54
68
  cookies: (TInput['cookies'] extends TSchema ? Static<TInput['cookies']> : {}) & (TInterceptor['cookies'] extends TSchema ? Static<TInterceptor['cookies']> : {});
55
69
  };
@@ -94,7 +108,7 @@ type RouteBuilderContext<TInput extends RouteInput = RouteInput, TInterceptor ex
94
108
  json(data: unknown, status?: ContentfulStatusCode, headers?: Record<string, string | string[]>): Response;
95
109
  /**
96
110
  * Return 201 Created response with optional Location header
97
- * Returns data directly (no wrapper)
111
+ * Returns data directly for type inference
98
112
  *
99
113
  * @example
100
114
  * ```ts
@@ -103,25 +117,29 @@ type RouteBuilderContext<TInput extends RouteInput = RouteInput, TInterceptor ex
103
117
  * // Response: 201 Created
104
118
  * // Header: Location: /users/123
105
119
  * // Body: { id: '123', name: 'John' }
120
+ * // Type: User (inferred from data)
106
121
  * ```
107
122
  */
108
- created(data: unknown, location?: string): Response;
123
+ created<T>(data: T, location?: string): T;
109
124
  /**
110
125
  * Return 202 Accepted response
111
- * Returns data directly (no wrapper), or empty body if no data
126
+ * Returns data directly for type inference
112
127
  *
113
128
  * @example
114
129
  * ```ts
115
130
  * // With data
116
131
  * return c.accepted({ jobId: '123' });
117
132
  * // Response: 202 Accepted, Body: { jobId: '123' }
133
+ * // Type: { jobId: string }
118
134
  *
119
135
  * // Without data
120
136
  * return c.accepted();
121
137
  * // Response: 202 Accepted, Body: (empty)
138
+ * // Type: void
122
139
  * ```
123
140
  */
124
- accepted(data?: unknown): Response;
141
+ accepted(): void;
142
+ accepted<T>(data: T): T;
125
143
  /**
126
144
  * Return 204 No Content response (empty body)
127
145
  *
@@ -130,9 +148,10 @@ type RouteBuilderContext<TInput extends RouteInput = RouteInput, TInterceptor ex
130
148
  * await deleteUser(id);
131
149
  * return c.noContent();
132
150
  * // Response: 204 No Content, Body: (empty)
151
+ * // Type: void
133
152
  * ```
134
153
  */
135
- noContent(): Response;
154
+ noContent(): void;
136
155
  /**
137
156
  * Return 304 Not Modified response (empty body)
138
157
  *
@@ -142,12 +161,13 @@ type RouteBuilderContext<TInput extends RouteInput = RouteInput, TInterceptor ex
142
161
  * return c.notModified();
143
162
  * }
144
163
  * // Response: 304 Not Modified, Body: (empty)
164
+ * // Type: void
145
165
  * ```
146
166
  */
147
- notModified(): Response;
167
+ notModified(): void;
148
168
  /**
149
169
  * Return paginated response with metadata
150
- * Returns `{ items: [...], pagination: {...} }` format
170
+ * Returns `{ items: [...], pagination: {...} }` format with type inference
151
171
  *
152
172
  * @example
153
173
  * ```ts
@@ -163,9 +183,29 @@ type RouteBuilderContext<TInput extends RouteInput = RouteInput, TInterceptor ex
163
183
  * // totalPages: 5
164
184
  * // }
165
185
  * // }
186
+ * // Type: PaginatedResult<User>
187
+ * ```
188
+ */
189
+ paginated<T>(data: T[], page: number, limit: number, total: number): PaginatedResult<T>;
190
+ /**
191
+ * Redirect to another URL
192
+ *
193
+ * @param url - Target URL to redirect to
194
+ * @param status - HTTP status code (301, 302, 303, 307, 308). Default: 302
195
+ *
196
+ * @example
197
+ * ```ts
198
+ * // Temporary redirect (302)
199
+ * return c.redirect('/login');
200
+ *
201
+ * // Permanent redirect (301)
202
+ * return c.redirect('/new-path', 301);
203
+ *
204
+ * // See Other (303) - useful after POST
205
+ * return c.redirect('/success', 303);
166
206
  * ```
167
207
  */
168
- paginated(data: unknown[], page: number, limit: number, total: number): Response;
208
+ redirect(url: string, status?: RedirectStatusCode): Response;
169
209
  raw: Context;
170
210
  };
171
211
 
@@ -482,14 +522,46 @@ declare class RouteBuilder<TInput extends RouteInput = {}, TInterceptor extends
482
522
  /**
483
523
  * Define handler function
484
524
  *
525
+ * Response type is automatically inferred from the return value.
526
+ * Use helper methods like `c.created()`, `c.paginated()` for proper type inference.
527
+ *
485
528
  * @example
486
529
  * ```ts
530
+ * // Direct return - type inferred from data
487
531
  * route.get('/users/:id')
488
532
  * .input({ params: Type.Object({ id: Type.String() }) })
489
533
  * .handler(async (c) => {
490
534
  * const { params } = await c.data();
491
- * const user = await getUser(params.id);
492
- * return user; // Type inferred!
535
+ * return await getUser(params.id); // Type: User
536
+ * })
537
+ *
538
+ * // Using c.created() - returns data with 201 status, type preserved
539
+ * route.post('/users')
540
+ * .input({ body: Type.Object({ name: Type.String() }) })
541
+ * .handler(async (c) => {
542
+ * const { body } = await c.data();
543
+ * return c.created(await createUser(body)); // Type: User
544
+ * })
545
+ *
546
+ * // Using c.paginated() - returns PaginatedResult<T>
547
+ * route.get('/users')
548
+ * .handler(async (c) => {
549
+ * const users = await getUsers();
550
+ * return c.paginated(users, 1, 20, 100); // Type: PaginatedResult<User>
551
+ * })
552
+ *
553
+ * // Using c.noContent() - returns void
554
+ * route.delete('/users/:id')
555
+ * .handler(async (c) => {
556
+ * await deleteUser(params.id);
557
+ * return c.noContent(); // Type: void
558
+ * })
559
+ *
560
+ * // Using c.json() - returns Response (type inference lost)
561
+ * // Use only when you need custom status codes not covered by helpers
562
+ * route.get('/custom')
563
+ * .handler(async (c) => {
564
+ * return c.json({ data }, 418); // Type: Response
493
565
  * })
494
566
  * ```
495
567
  */
@@ -627,6 +699,14 @@ declare function defineRouter<TRoutes extends Record<string, RouteDef<any, any,
627
699
  * Registers routes defined with route.get()...handler() to Hono app
628
700
  */
629
701
 
702
+ /**
703
+ * Registered route information for logging
704
+ */
705
+ interface RegisteredRoute {
706
+ method: HttpMethod;
707
+ path: string;
708
+ name: string;
709
+ }
630
710
  /**
631
711
  * Register routes from defineRouter() to Hono app
632
712
  *
@@ -634,6 +714,7 @@ declare function defineRouter<TRoutes extends Record<string, RouteDef<any, any,
634
714
  * @param router - Router definition
635
715
  * @param namedMiddlewares - Optional server-level named middlewares
636
716
  *
717
+ * @param collectedRoutes
637
718
  * @example
638
719
  * ```ts
639
720
  * const appRouter = defineRouter({
@@ -652,7 +733,7 @@ declare function defineRouter<TRoutes extends Record<string, RouteDef<any, any,
652
733
  declare function registerRoutes<TRoutes extends Record<string, RouteDef<any> | Router<any>>>(app: Hono, router: Router<TRoutes>, namedMiddlewares?: ReadonlyArray<{
653
734
  name: string;
654
735
  handler: MiddlewareHandler;
655
- }>): void;
736
+ }>, collectedRoutes?: RegisteredRoute[]): RegisteredRoute[];
656
737
 
657
738
  /**
658
739
  * Type guard for HttpMethod
@@ -679,4 +760,135 @@ declare const Nullable: <T extends TSchema>(schema: T) => _sinclair_typebox.TUni
679
760
  */
680
761
  declare const OptionalNullable: <T extends TSchema>(schema: T) => _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<[T, _sinclair_typebox.TNull]>>;
681
762
 
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 };
763
+ /**
764
+ * File Schema Helpers for TypeBox
765
+ *
766
+ * Provides TypeBox schema definitions for file upload handling
767
+ * with optional validation constraints.
768
+ */
769
+
770
+ /**
771
+ * File validation options
772
+ */
773
+ interface FileSchemaOptions {
774
+ /**
775
+ * Maximum file size in bytes
776
+ *
777
+ * @example 5 * 1024 * 1024 // 5MB
778
+ */
779
+ maxSize?: number;
780
+ /**
781
+ * Allowed MIME types
782
+ *
783
+ * @example ['image/jpeg', 'image/png', 'image/webp']
784
+ */
785
+ allowedTypes?: string[];
786
+ /**
787
+ * Minimum file size in bytes (optional)
788
+ *
789
+ * @example 1024 // 1KB minimum
790
+ */
791
+ minSize?: number;
792
+ }
793
+ /**
794
+ * File array validation options
795
+ */
796
+ interface FileArraySchemaOptions extends FileSchemaOptions {
797
+ /**
798
+ * Maximum number of files
799
+ *
800
+ * @example 5
801
+ */
802
+ maxFiles?: number;
803
+ /**
804
+ * Minimum number of files (optional)
805
+ *
806
+ * @example 1
807
+ */
808
+ minFiles?: number;
809
+ }
810
+ /**
811
+ * Internal schema type with file validation metadata
812
+ */
813
+ interface FileSchemaType extends TSchema {
814
+ [Kind]: 'File';
815
+ fileOptions?: FileSchemaOptions;
816
+ }
817
+ interface FileArraySchemaType extends TSchema {
818
+ [Kind]: 'FileArray';
819
+ fileOptions?: FileArraySchemaOptions;
820
+ }
821
+ /**
822
+ * Create a File schema with optional validation
823
+ *
824
+ * @example
825
+ * ```ts
826
+ * // Basic usage (no validation)
827
+ * formData: Type.Object({
828
+ * file: FileSchema()
829
+ * })
830
+ *
831
+ * // With validation
832
+ * formData: Type.Object({
833
+ * avatar: FileSchema({
834
+ * maxSize: 5 * 1024 * 1024, // 5MB
835
+ * allowedTypes: ['image/jpeg', 'image/png', 'image/webp']
836
+ * })
837
+ * })
838
+ * ```
839
+ */
840
+ declare function FileSchema(options?: FileSchemaOptions): FileSchemaType;
841
+ /**
842
+ * Create a File array schema with optional validation
843
+ *
844
+ * @example
845
+ * ```ts
846
+ * // Basic usage (no validation)
847
+ * formData: Type.Object({
848
+ * files: FileArraySchema()
849
+ * })
850
+ *
851
+ * // With validation
852
+ * formData: Type.Object({
853
+ * documents: FileArraySchema({
854
+ * maxSize: 10 * 1024 * 1024, // 10MB per file
855
+ * maxFiles: 5,
856
+ * allowedTypes: ['application/pdf', 'application/msword']
857
+ * })
858
+ * })
859
+ * ```
860
+ */
861
+ declare function FileArraySchema(options?: FileArraySchemaOptions): FileArraySchemaType;
862
+ /**
863
+ * Create an optional File schema with validation
864
+ *
865
+ * @example
866
+ * ```ts
867
+ * formData: Type.Object({
868
+ * name: Type.String(),
869
+ * avatar: OptionalFileSchema({
870
+ * maxSize: 2 * 1024 * 1024,
871
+ * allowedTypes: ['image/jpeg', 'image/png']
872
+ * })
873
+ * })
874
+ * ```
875
+ */
876
+ declare function OptionalFileSchema(options?: FileSchemaOptions): TSchema;
877
+ /**
878
+ * Check if a schema is a File schema
879
+ */
880
+ declare function isFileSchema(schema: TSchema): schema is FileSchemaType;
881
+ /**
882
+ * Check if a schema is a FileArray schema
883
+ */
884
+ declare function isFileArraySchema(schema: TSchema): schema is FileArraySchemaType;
885
+ /**
886
+ * Get file options from schema
887
+ */
888
+ declare function getFileOptions(schema: TSchema): FileSchemaOptions | FileArraySchemaOptions | undefined;
889
+ /**
890
+ * Format file size for error messages
891
+ */
892
+ declare function formatFileSize(bytes: number): string;
893
+
894
+ export { type ExtractMiddlewareNames, FileArraySchema, type FileArraySchemaOptions, type FileArraySchemaType, FileSchema, type FileSchemaOptions, type FileSchemaType, HttpMethod, type MergedInput, type NamedMiddleware, type NamedMiddlewareFactory, Nullable, OptionalFileSchema, OptionalNullable, type PaginatedResult, type RegisteredRoute, type RouteBuilderContext, type RouteDef, type RouteHandlerFn, type RouteInput, type Router, defineMiddleware, defineMiddlewareFactory, defineRouter, formatFileSize, getFileOptions, isFileArraySchema, isFileSchema, isHttpMethod, registerRoutes, route };