@spfn/core 0.3.0-beta.3 → 0.3.0-beta.30

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 (104) hide show
  1. package/README.md +301 -10
  2. package/dist/app-config/index.d.ts +39 -1
  3. package/dist/app-config/index.js.map +1 -1
  4. package/dist/authz/index.js +47 -391
  5. package/dist/authz/index.js.map +1 -1
  6. package/dist/{boss-D16fO2oG.d.ts → boss-BiDCbbAQ.d.ts} +60 -7
  7. package/dist/codegen/index.d.ts +157 -16
  8. package/dist/codegen/index.js +772 -166
  9. package/dist/codegen/index.js.map +1 -1
  10. package/dist/config/index.js +4 -4
  11. package/dist/config/index.js.map +1 -1
  12. package/dist/contract/index.d.ts +39 -16
  13. package/dist/contract/index.js +147 -23
  14. package/dist/contract/index.js.map +1 -1
  15. package/dist/db/index.d.ts +230 -35
  16. package/dist/db/index.js +316 -160
  17. package/dist/db/index.js.map +1 -1
  18. package/dist/env/index.d.ts +6 -442
  19. package/dist/env/index.js +13 -16
  20. package/dist/env/index.js.map +1 -1
  21. package/dist/env/loader.js +24 -1
  22. package/dist/env/loader.js.map +1 -1
  23. package/dist/error-CIZlYJlL.d.ts +157 -0
  24. package/dist/errors/index.d.ts +18 -1
  25. package/dist/errors/index.js +47 -391
  26. package/dist/errors/index.js.map +1 -1
  27. package/dist/event/index.d.ts +5 -5
  28. package/dist/event/index.js +202 -3
  29. package/dist/event/index.js.map +1 -1
  30. package/dist/event/sse/client.d.ts +18 -4
  31. package/dist/event/sse/client.js +94 -18
  32. package/dist/event/sse/client.js.map +1 -1
  33. package/dist/event/sse/index.d.ts +18 -5
  34. package/dist/event/sse/index.js +452 -114
  35. package/dist/event/sse/index.js.map +1 -1
  36. package/dist/event/ws/client.d.ts +3 -2
  37. package/dist/event/ws/index.d.ts +4 -3
  38. package/dist/job/index.d.ts +48 -3
  39. package/dist/job/index.js +131 -52
  40. package/dist/job/index.js.map +1 -1
  41. package/dist/logger/index.js +0 -12
  42. package/dist/logger/index.js.map +1 -1
  43. package/dist/middleware/index.js +52 -397
  44. package/dist/middleware/index.js.map +1 -1
  45. package/dist/nextjs/index.d.ts +75 -14
  46. package/dist/nextjs/index.js +200 -84
  47. package/dist/nextjs/index.js.map +1 -1
  48. package/dist/nextjs/server.d.ts +46 -8
  49. package/dist/nextjs/server.js +15 -1
  50. package/dist/nextjs/server.js.map +1 -1
  51. package/dist/ops/index.d.ts +61 -42
  52. package/dist/ops/index.js +648 -97
  53. package/dist/ops/index.js.map +1 -1
  54. package/dist/registry-C2KQCh0m.d.ts +473 -0
  55. package/dist/route/index.d.ts +5 -2
  56. package/dist/route/index.js +107 -28
  57. package/dist/route/index.js.map +1 -1
  58. package/dist/route/types.d.ts +7 -1
  59. package/dist/{router-Cy7rAfmj.d.ts → route-builder-DRW-MSCJ.d.ts} +51 -126
  60. package/dist/router-C57y-vz1.d.ts +184 -0
  61. package/dist/router-CX5uVjmU.d.ts +406 -0
  62. package/dist/server/index.d.ts +130 -7
  63. package/dist/server/index.js +1174 -164
  64. package/dist/server/index.js.map +1 -1
  65. package/dist/state/client.d.ts +206 -0
  66. package/dist/state/client.js +678 -0
  67. package/dist/state/client.js.map +1 -0
  68. package/dist/state/index.d.ts +443 -0
  69. package/dist/state/index.js +644 -0
  70. package/dist/state/index.js.map +1 -0
  71. package/dist/state/react.d.ts +49 -0
  72. package/dist/state/react.js +50 -0
  73. package/dist/state/react.js.map +1 -0
  74. package/dist/surface/index.d.ts +115 -0
  75. package/dist/surface/index.js +1013 -0
  76. package/dist/surface/index.js.map +1 -0
  77. package/dist/token-manager-Ckjt2-qq.d.ts +122 -0
  78. package/dist/{types-CfYVhIQ9.d.ts → types-5Rl11_Nb.d.ts} +43 -4
  79. package/dist/types-CKH0D3Dy.d.ts +441 -0
  80. package/dist/{types-ZQODsBft.d.ts → types-CurMab2Q.d.ts} +52 -2
  81. package/dist/{types-2AbaW4Ie.d.ts → types-DncqXfWN.d.ts} +4 -3
  82. package/docs/file-upload.md +195 -333
  83. package/package.json +39 -9
  84. package/src/cache/README.md +330 -0
  85. package/src/codegen/README.md +721 -0
  86. package/src/config/README.md +333 -0
  87. package/src/contract/README.md +442 -0
  88. package/src/db/README.md +589 -0
  89. package/src/db/manager/README.md +500 -0
  90. package/src/db/schema/README.md +354 -0
  91. package/src/db/transaction/README.md +845 -0
  92. package/src/env/README.md +787 -0
  93. package/src/errors/README.md +445 -0
  94. package/src/event/README.md +994 -0
  95. package/src/job/README.md +613 -0
  96. package/src/logger/README.md +321 -0
  97. package/src/middleware/README.md +634 -0
  98. package/src/nextjs/README.md +756 -0
  99. package/src/route/README.md +763 -0
  100. package/src/security/README.md +100 -0
  101. package/src/server/README.md +704 -0
  102. package/src/state/README.md +806 -0
  103. package/dist/token-manager-BT5EnUAR.d.ts +0 -278
  104. package/dist/types-9oszaJqp.d.ts +0 -250
@@ -1,278 +0,0 @@
1
- import { TSchema } from '@sinclair/typebox';
2
-
3
- /**
4
- * Event System Types
5
- */
6
-
7
- /**
8
- * Pub/Sub capable cache interface for multi-instance events
9
- */
10
- interface PubSubCache {
11
- /**
12
- * Publish a message to a channel
13
- */
14
- publish(channel: string, message: unknown): Promise<void>;
15
- /**
16
- * Subscribe to a channel
17
- */
18
- subscribe(channel: string, handler: (message: unknown) => void | Promise<void>): Promise<void>;
19
- }
20
- /**
21
- * Event handler function type
22
- */
23
- type EventHandler<TPayload> = (payload: TPayload) => void | Promise<void>;
24
- /**
25
- * Job queue sender function type (used by job module)
26
- */
27
- type JobQueueSender = (queueName: string, payload: unknown) => Promise<void>;
28
- /**
29
- * Event definition interface
30
- */
31
- interface EventDef<TPayload = void> {
32
- /**
33
- * Unique event name
34
- */
35
- readonly name: string;
36
- /**
37
- * TypeBox payload schema (optional)
38
- */
39
- readonly schema?: TSchema;
40
- /**
41
- * Subscribe to this event (in-memory handler)
42
- */
43
- subscribe: (handler: EventHandler<TPayload>) => () => void;
44
- /**
45
- * Unsubscribe all handlers
46
- */
47
- unsubscribeAll: () => void;
48
- /**
49
- * Emit the event (triggers all subscribers and queued jobs)
50
- */
51
- emit: TPayload extends void ? () => Promise<void> : (payload: TPayload) => Promise<void>;
52
- /**
53
- * Enable cache-based pub/sub for multi-instance support
54
- * Must await before emitting events to ensure subscription is ready
55
- */
56
- useCache: (cache: PubSubCache) => Promise<EventDef<TPayload>>;
57
- /**
58
- * Internal: Register a job queue to receive this event
59
- * Called by job registration system
60
- */
61
- _registerJobQueue: (queueName: string, sender: JobQueueSender) => void;
62
- /**
63
- * Internal: Drop the cache binding (cache + subscribed flag).
64
- * Called by the event cache transport on shutdown so a later useCache can
65
- * rebind a fresh cache in the same process.
66
- */
67
- _resetCache: () => void;
68
- /**
69
- * Type inference helper
70
- */
71
- _payload: TPayload;
72
- }
73
- /**
74
- * Infer payload type from EventDef
75
- */
76
- type InferEventPayload$1<TEvent> = TEvent extends EventDef<infer TPayload> ? TPayload : never;
77
-
78
- /**
79
- * Event Router
80
- *
81
- * Type-safe event router for SSE subscription
82
- *
83
- * @example
84
- * ```typescript
85
- * import { defineEvent, defineEventRouter } from '@spfn/core/event';
86
- * import { Type } from '@sinclair/typebox';
87
- *
88
- * const userCreated = defineEvent('user.created', Type.Object({
89
- * userId: Type.String(),
90
- * }));
91
- *
92
- * const orderPlaced = defineEvent('order.placed', Type.Object({
93
- * orderId: Type.String(),
94
- * amount: Type.Number(),
95
- * }));
96
- *
97
- * export const eventRouter = defineEventRouter({
98
- * userCreated,
99
- * orderPlaced,
100
- * });
101
- *
102
- * export type EventRouter = typeof eventRouter;
103
- * ```
104
- */
105
-
106
- /**
107
- * Event Router Definition
108
- */
109
- interface EventRouterDef<TEvents extends Record<string, EventDef<any>>> {
110
- /**
111
- * Event definitions
112
- */
113
- readonly events: TEvents;
114
- /**
115
- * Event names as array
116
- */
117
- readonly eventNames: (keyof TEvents)[];
118
- /**
119
- * Type inference helper - payload types by event name
120
- */
121
- readonly _types: {
122
- [K in keyof TEvents]: TEvents[K]['_payload'];
123
- };
124
- }
125
- /**
126
- * Infer event names from EventRouter
127
- */
128
- type InferEventNames<T> = T extends EventRouterDef<infer E> ? keyof E & string : never;
129
- /**
130
- * Infer payload type for specific event
131
- */
132
- type InferEventPayload<T extends EventRouterDef<any>, K extends InferEventNames<T>> = T['_types'][K];
133
- /**
134
- * Infer all event payloads map
135
- */
136
- type InferEventPayloads<T extends EventRouterDef<any>> = T['_types'];
137
- /**
138
- * Define an event router for SSE subscription
139
- *
140
- * @example
141
- * ```typescript
142
- * export const eventRouter = defineEventRouter({
143
- * userCreated,
144
- * orderPlaced,
145
- * });
146
- *
147
- * // Type inference
148
- * type Names = InferEventNames<typeof eventRouter>;
149
- * // 'userCreated' | 'orderPlaced'
150
- *
151
- * type Payload = InferEventPayload<typeof eventRouter, 'userCreated'>;
152
- * // { userId: string }
153
- * ```
154
- */
155
- declare function defineEventRouter<TEvents extends Record<string, EventDef<any>>>(events: TEvents): EventRouterDef<TEvents>;
156
-
157
- /**
158
- * SSE Token Manager
159
- *
160
- * Auth-agnostic token issuance and verification for SSE connections.
161
- * Issues one-time-use tokens with TTL for Token Exchange pattern.
162
- *
163
- * @example
164
- * ```typescript
165
- * const manager = new SSETokenManager({ ttl: 30000 });
166
- *
167
- * // Issue token for authenticated user
168
- * const token = await manager.issue('user-123');
169
- *
170
- * // Verify and consume token (one-time use)
171
- * const subject = await manager.verify(token); // 'user-123'
172
- * const again = await manager.verify(token); // null (already consumed)
173
- *
174
- * // Cleanup on shutdown
175
- * manager.destroy();
176
- * ```
177
- */
178
- /**
179
- * Minimal cache client interface (compatible with ioredis Redis | Cluster)
180
- */
181
- type CacheClient = {
182
- set(key: string, value: string, ...args: any[]): Promise<any>;
183
- getdel?(key: string): Promise<string | null>;
184
- get(key: string): Promise<string | null>;
185
- del(...keys: string[]): Promise<number>;
186
- };
187
- /**
188
- * Stored SSE token data
189
- */
190
- interface SSEToken {
191
- subject: string;
192
- expiresAt: number;
193
- }
194
- /**
195
- * Token storage interface
196
- *
197
- * Implement this for custom storage backends (e.g., Redis for multi-instance).
198
- */
199
- interface SSETokenStore {
200
- /** Store a token */
201
- set(token: string, data: SSEToken): Promise<void>;
202
- /** Get and delete a token (one-time use) */
203
- consume(token: string): Promise<SSEToken | null>;
204
- /** Remove expired tokens */
205
- cleanup(): Promise<void>;
206
- }
207
- /**
208
- * SSETokenManager configuration
209
- */
210
- interface SSETokenManagerConfig {
211
- /**
212
- * Token time-to-live in milliseconds
213
- * @default 30000
214
- */
215
- ttl?: number;
216
- /**
217
- * Custom token store (default: in-memory Map)
218
- */
219
- store?: SSETokenStore;
220
- /**
221
- * Cleanup interval in milliseconds
222
- * @default 60000
223
- */
224
- cleanupInterval?: number;
225
- }
226
- /**
227
- * Redis/Valkey-backed token store for multi-instance deployments.
228
- *
229
- * Uses SET EX for automatic TTL expiry and GETDEL for atomic one-time consumption.
230
- * No cleanup needed — Redis handles expiration automatically.
231
- *
232
- * @example
233
- * ```typescript
234
- * import { getCache } from '@spfn/core/cache';
235
- *
236
- * const cache = getCache();
237
- * if (cache) {
238
- * const store = new CacheTokenStore(cache);
239
- * const manager = new SSETokenManager({ store });
240
- * }
241
- * ```
242
- */
243
- declare class CacheTokenStore implements SSETokenStore {
244
- private cache;
245
- private prefix;
246
- constructor(cache: CacheClient);
247
- set(token: string, data: SSEToken): Promise<void>;
248
- consume(token: string): Promise<SSEToken | null>;
249
- cleanup(): Promise<void>;
250
- }
251
- declare class SSETokenManager {
252
- private store;
253
- private ttl;
254
- private cleanupTimer;
255
- constructor(config?: SSETokenManagerConfig);
256
- /**
257
- * How long an issued token stays valid, in milliseconds.
258
- *
259
- * Exposed so a caller that has to report an expiry to its client computes the same
260
- * number this manager stamps on the token, instead of assuming the default.
261
- */
262
- get ttlMs(): number;
263
- /**
264
- * Issue a new one-time-use token for the given subject
265
- */
266
- issue(subject: string): Promise<string>;
267
- /**
268
- * Verify and consume a token
269
- * @returns subject string if valid, null if invalid/expired/already consumed
270
- */
271
- verify(token: string): Promise<string | null>;
272
- /**
273
- * Cleanup timer and resources
274
- */
275
- destroy(): void;
276
- }
277
-
278
- export { CacheTokenStore as C, type EventDef as E, type InferEventNames as I, type JobQueueSender as J, type PubSubCache as P, SSETokenManager as S, type EventHandler as a, type EventRouterDef as b, type InferEventPayload$1 as c, type InferEventPayloads as d, type InferEventPayload as e, defineEventRouter as f, type SSEToken as g, type SSETokenManagerConfig as h, type SSETokenStore as i };
@@ -1,250 +0,0 @@
1
- import { TSchema, Static } from '@sinclair/typebox';
2
- import { ErrorRegistry, ErrorRegistryInput } from '@spfn/core/errors';
3
- import { RouteDef, RouteInput } from '@spfn/core/route';
4
-
5
- /**
6
- * Convert File types in schema to actual File for client usage
7
- *
8
- * TypeBox File schemas become actual File objects on the client side.
9
- */
10
- type ConvertFileTypes<T> = T extends File ? File : T extends File[] ? File[] : T;
11
- /**
12
- * Extract form data input type with File support
13
- *
14
- * Maps schema types to runtime types, converting FileSchema to File.
15
- */
16
- type FormDataInput<T> = {
17
- [K in keyof T]: ConvertFileTypes<T[K]>;
18
- };
19
- /**
20
- * Extract structured input from RouteInput
21
- *
22
- * Converts TypeBox schemas to their static types for each input field.
23
- */
24
- type StructuredInput<TInput extends RouteInput> = {
25
- params: TInput['params'] extends TSchema ? Static<TInput['params']> : {};
26
- query: TInput['query'] extends TSchema ? Static<TInput['query']> : {};
27
- body: TInput['body'] extends TSchema ? Static<TInput['body']> : {};
28
- formData: TInput['formData'] extends TSchema ? FormDataInput<Static<TInput['formData']>> : {};
29
- headers: TInput['headers'] extends TSchema ? Static<TInput['headers']> : {};
30
- cookies: TInput['cookies'] extends TSchema ? Static<TInput['cookies']> : {};
31
- };
32
- /**
33
- * Infer route input type from RouteDef
34
- *
35
- * @example
36
- * ```typescript
37
- * // Server route definition
38
- * const getUser = route.get('/users/:id')
39
- * .input({ params: Type.Object({ id: Type.String() }) })
40
- * .handler(...);
41
- *
42
- * // Client: extract input type
43
- * type Input = InferRouteInput<typeof getUser>;
44
- * // { params: { id: string }, query: {}, body: {}, ... }
45
- * ```
46
- */
47
- type InferRouteInput<TRoute> = TRoute extends RouteDef<infer TInput, any, any> ? StructuredInput<TInput> : never;
48
- /**
49
- * Infer route output type from RouteDef
50
- *
51
- * @example
52
- * ```typescript
53
- * // Server route definition
54
- * const getUser = route.get('/users/:id')
55
- * .handler(async (c) => {
56
- * return { id: '1', name: 'John' };
57
- * });
58
- *
59
- * // Client: extract output type
60
- * type Output = InferRouteOutput<typeof getUser>;
61
- * // { id: string, name: string }
62
- * ```
63
- */
64
- type InferRouteOutput<TRoute> = TRoute extends RouteDef<any, any, infer TResponse> ? TResponse : never;
65
- /**
66
- * Extract routes from Router type
67
- * Router<TRoutes> has routes in `_routes` property
68
- */
69
- type ExtractRoutes<TRouter> = TRouter extends {
70
- _routes: infer TRoutes;
71
- } ? TRoutes : TRouter;
72
- /**
73
- * Extract output type for a specific route from router
74
- *
75
- * @example
76
- * ```typescript
77
- * import type { RouterOutput } from '@spfn/core/nextjs';
78
- * import type { AppRouter } from '@/server/router';
79
- *
80
- * // Get output type for a specific route
81
- * type ListData = RouterOutput<AppRouter, 'listExamples'>;
82
- *
83
- * // Use in props
84
- * interface Props {
85
- * data: RouterOutput<AppRouter, 'listExamples'>;
86
- * }
87
- *
88
- * // Extract item type from paginated response
89
- * type Example = RouterOutput<AppRouter, 'listExamples'>['items'][number];
90
- * ```
91
- */
92
- type RouterOutput<TRouter, K extends keyof ExtractRoutes<TRouter>> = InferRouteOutput<ExtractRoutes<TRouter>[K]>;
93
- /**
94
- * Extract input type for a specific route from router
95
- *
96
- * @example
97
- * ```typescript
98
- * import type { RouterInput } from '@spfn/core/nextjs';
99
- * import type { AppRouter } from '@/server/router';
100
- *
101
- * // Get input type for a specific route
102
- * type CreateInput = RouterInput<AppRouter, 'createExample'>;
103
- *
104
- * // Use in function parameter
105
- * function submitForm(data: RouterInput<AppRouter, 'createExample'>['body']) {
106
- * // ...
107
- * }
108
- * ```
109
- */
110
- type RouterInput<TRouter, K extends keyof ExtractRoutes<TRouter>> = InferRouteInput<ExtractRoutes<TRouter>[K]>;
111
- /**
112
- * Cookie options for setCookie
113
- */
114
- interface CookieOptions {
115
- httpOnly?: boolean;
116
- secure?: boolean;
117
- sameSite?: 'strict' | 'lax' | 'none';
118
- maxAge?: number;
119
- path?: string;
120
- domain?: string;
121
- }
122
- /**
123
- * Cookie to set in response
124
- */
125
- interface SetCookie {
126
- name: string;
127
- value: string;
128
- options?: CookieOptions;
129
- }
130
- /**
131
- * Request interceptor - called before fetch
132
- */
133
- type RequestInterceptor = (url: string, init: RequestInit) => Promise<RequestInit> | RequestInit;
134
- /**
135
- * Response interceptor - called after fetch
136
- */
137
- type ResponseInterceptor = (response: Response, body: any) => Promise<{
138
- response: Response;
139
- body: any;
140
- }> | {
141
- response: Response;
142
- body: any;
143
- };
144
- /**
145
- * Client configuration
146
- */
147
- interface ApiConfig {
148
- /**
149
- * Base URL for RPC endpoint
150
- *
151
- * @default '/api/rpc'
152
- * @example '/api/rpc', 'http://localhost:3000/api/rpc'
153
- */
154
- baseUrl?: string;
155
- /**
156
- * Default headers for all requests
157
- */
158
- headers?: Record<string, string>;
159
- /**
160
- * Request timeout in milliseconds
161
- *
162
- * @default env.SERVER_TIMEOUT (120000)
163
- */
164
- timeout?: number;
165
- /**
166
- * Custom fetch implementation
167
- */
168
- fetch?: typeof fetch;
169
- /**
170
- * Global request interceptor
171
- */
172
- onRequest?: RequestInterceptor;
173
- /**
174
- * Global response interceptor
175
- */
176
- onResponse?: ResponseInterceptor;
177
- /**
178
- * Custom error registry for deserialization
179
- *
180
- * Core HTTP errors are automatically registered. Use this to add your custom application errors.
181
- *
182
- * @example
183
- * ```typescript
184
- * import { errorRegistry } from '@spfn/core/errors';
185
- * import { authErrorRegistry } from '@myapp/auth/errors';
186
- * import { PaymentFailedError } from '@/server/errors';
187
- *
188
- * const api = createApi<AppRouter>({
189
- * errorRegistry: [errorRegistry, authErrorRegistry, PaymentFailedError]
190
- * });
191
- * ```
192
- */
193
- errorRegistry?: ErrorRegistry | ErrorRegistryInput[];
194
- /**
195
- * Enable debug logging
196
- *
197
- * @default false
198
- */
199
- debug?: boolean;
200
- }
201
- /**
202
- * Per-call options
203
- */
204
- interface CallOptions {
205
- /**
206
- * Request timeout in milliseconds
207
- * Overrides the global timeout set in ApiConfig
208
- */
209
- timeout?: number;
210
- /**
211
- * Additional headers for this request
212
- */
213
- headers?: Record<string, string>;
214
- /**
215
- * Override cookies for this request
216
- *
217
- * Note: Cookies are automatically forwarded by the proxy.
218
- * Use this only when you need to override them.
219
- */
220
- cookies?: Record<string, string>;
221
- /**
222
- * Request-specific interceptor
223
- */
224
- onRequest?: RequestInterceptor;
225
- /**
226
- * Response-specific interceptor
227
- */
228
- onResponse?: ResponseInterceptor;
229
- /**
230
- * Next.js-specific fetch options
231
- *
232
- * @example
233
- * // Time-based revalidation
234
- * { next: { revalidate: 60 } }
235
- *
236
- * // Disable cache
237
- * { cache: 'no-store' }
238
- *
239
- * // Tag-based revalidation
240
- * { next: { tags: ['users'] } }
241
- */
242
- fetchOptions?: RequestInit & {
243
- next?: {
244
- revalidate?: number | false;
245
- tags?: string[];
246
- };
247
- };
248
- }
249
-
250
- export type { ApiConfig as A, CallOptions as C, InferRouteInput as I, RequestInterceptor as R, SetCookie as S, ResponseInterceptor as a, InferRouteOutput as b, CookieOptions as c, RouterInput as d, RouterOutput as e, StructuredInput as f };