@spfn/core 0.2.0-beta.2 → 0.2.0-beta.21

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 +179 -5
  5. package/dist/codegen/index.js.map +1 -1
  6. package/dist/config/index.d.ts +204 -6
  7. package/dist/config/index.js +44 -11
  8. package/dist/config/index.js.map +1 -1
  9. package/dist/db/index.d.ts +13 -0
  10. package/dist/db/index.js +92 -33
  11. package/dist/db/index.js.map +1 -1
  12. package/dist/env/index.d.ts +83 -3
  13. package/dist/env/index.js +83 -15
  14. package/dist/env/index.js.map +1 -1
  15. package/dist/env/loader.d.ts +95 -0
  16. package/dist/env/loader.js +78 -0
  17. package/dist/env/loader.js.map +1 -0
  18. package/dist/event/index.d.ts +29 -70
  19. package/dist/event/index.js +15 -1
  20. package/dist/event/index.js.map +1 -1
  21. package/dist/event/sse/client.d.ts +157 -0
  22. package/dist/event/sse/client.js +169 -0
  23. package/dist/event/sse/client.js.map +1 -0
  24. package/dist/event/sse/index.d.ts +46 -0
  25. package/dist/event/sse/index.js +205 -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 +124 -11
  31. package/dist/middleware/index.js +41 -7
  32. package/dist/middleware/index.js.map +1 -1
  33. package/dist/nextjs/index.d.ts +2 -2
  34. package/dist/nextjs/index.js +37 -5
  35. package/dist/nextjs/index.js.map +1 -1
  36. package/dist/nextjs/server.d.ts +45 -24
  37. package/dist/nextjs/server.js +87 -66
  38. package/dist/nextjs/server.js.map +1 -1
  39. package/dist/route/index.d.ts +207 -14
  40. package/dist/route/index.js +304 -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 +321 -10
  45. package/dist/server/index.js +798 -189
  46. package/dist/server/index.js.map +1 -1
  47. package/dist/{types-DRG2XMTR.d.ts → types-7Mhoxnnt.d.ts} +97 -4
  48. package/dist/types-DHQMQlcb.d.ts +305 -0
  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 +499 -0
  54. package/docs/errors.md +319 -0
  55. package/docs/event.md +432 -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 +247 -0
  61. package/docs/repository.md +496 -0
  62. package/docs/route.md +497 -0
  63. package/docs/server.md +429 -0
  64. package/package.json +19 -3
package/docs/nextjs.md ADDED
@@ -0,0 +1,247 @@
1
+ # Next.js Integration
2
+
3
+ RPC proxy and type-safe API client for Next.js.
4
+
5
+ ## Setup
6
+
7
+ ### 1. Create RPC Proxy
8
+
9
+ ```typescript
10
+ // app/api/rpc/[routeName]/route.ts
11
+ import '@spfn/auth/nextjs/api';
12
+ import { createRpcProxy } from '@spfn/core/nextjs/server';
13
+ import { authRouteMap } from '@spfn/auth';
14
+ import { eventRouteMap } from '@spfn/core/event';
15
+ import { routeMap } from '@/generated/route-map';
16
+
17
+ export const { GET, POST } = createRpcProxy({
18
+ routeMap: { ...routeMap, ...authRouteMap, ...eventRouteMap },
19
+ });
20
+ ```
21
+
22
+ ### 2. Create API Client
23
+
24
+ ```typescript
25
+ // src/lib/api.ts
26
+ import { createApi } from '@spfn/core/nextjs';
27
+ import type { AppRouter } from '@/server/server.config';
28
+
29
+ export const api = createApi<AppRouter>();
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### Server Components
35
+
36
+ ```typescript
37
+ // app/users/[id]/page.tsx
38
+ import { api } from '@/lib/api';
39
+
40
+ export default async function UserPage({ params }: { params: { id: string } })
41
+ {
42
+ const user = await api.getUser.call({
43
+ params: { id: params.id }
44
+ });
45
+
46
+ return <div>{user.name}</div>;
47
+ }
48
+ ```
49
+
50
+ ### Client Components
51
+
52
+ ```typescript
53
+ 'use client';
54
+
55
+ import { api } from '@/lib/api';
56
+ import { useState } from 'react';
57
+
58
+ export function CreateUserForm()
59
+ {
60
+ const [loading, setLoading] = useState(false);
61
+
62
+ async function handleSubmit(formData: FormData)
63
+ {
64
+ setLoading(true);
65
+ try
66
+ {
67
+ await api.createUser.call({
68
+ body: {
69
+ email: formData.get('email') as string,
70
+ name: formData.get('name') as string
71
+ }
72
+ });
73
+ }
74
+ finally
75
+ {
76
+ setLoading(false);
77
+ }
78
+ }
79
+
80
+ return (
81
+ <form action={handleSubmit}>
82
+ {/* ... */}
83
+ </form>
84
+ );
85
+ }
86
+ ```
87
+
88
+ ### Server Actions
89
+
90
+ ```typescript
91
+ // app/actions.ts
92
+ 'use server';
93
+
94
+ import { api } from '@/lib/api';
95
+
96
+ export async function createUser(formData: FormData)
97
+ {
98
+ const user = await api.createUser.call({
99
+ body: {
100
+ email: formData.get('email') as string,
101
+ name: formData.get('name') as string
102
+ }
103
+ });
104
+
105
+ return user;
106
+ }
107
+ ```
108
+
109
+ ## API Client Methods
110
+
111
+ ```typescript
112
+ // Call with params
113
+ const user = await api.getUser.call({
114
+ params: { id: '123' }
115
+ });
116
+
117
+ // Call with query
118
+ const users = await api.getUsers.call({
119
+ query: { page: 1, limit: 20, search: 'john' }
120
+ });
121
+
122
+ // Call with body
123
+ const created = await api.createUser.call({
124
+ body: { email: 'user@example.com', name: 'User' }
125
+ });
126
+
127
+ // Call with multiple inputs
128
+ const updated = await api.updateUser.call({
129
+ params: { id: '123' },
130
+ body: { name: 'Updated Name' }
131
+ });
132
+ ```
133
+
134
+ ## Interceptors
135
+
136
+ ### Request Interceptor
137
+
138
+ ```typescript
139
+ export const { GET, POST } = createRpcProxy({
140
+ routeMap: { ...routeMap, ...authRouteMap },
141
+ apiUrl: process.env.SPFN_API_URL,
142
+ interceptors: {
143
+ request: async (request, context) => {
144
+ // Add auth header
145
+ const token = cookies().get('token')?.value;
146
+ if (token)
147
+ {
148
+ request.headers.set('Authorization', `Bearer ${token}`);
149
+ }
150
+ return request;
151
+ }
152
+ }
153
+ });
154
+ ```
155
+
156
+ ### Response Interceptor
157
+
158
+ ```typescript
159
+ interceptors: {
160
+ response: async (response, context) => {
161
+ // Handle Set-Cookie from API
162
+ const setCookie = response.headers.get('set-cookie');
163
+ if (setCookie)
164
+ {
165
+ cookies().set(parseCookie(setCookie));
166
+ }
167
+ return response;
168
+ }
169
+ }
170
+ ```
171
+
172
+ ## Cookie Handling
173
+
174
+ The RPC proxy automatically handles HttpOnly cookies:
175
+
176
+ ```typescript
177
+ // Server sets cookie
178
+ c.header('Set-Cookie', 'session=abc; HttpOnly; Secure');
179
+
180
+ // Proxy forwards to browser
181
+ // Browser stores HttpOnly cookie
182
+ // Subsequent requests include cookie automatically
183
+ ```
184
+
185
+ ## Error Handling
186
+
187
+ ```typescript
188
+ try
189
+ {
190
+ const user = await api.getUser.call({ params: { id: '123' } });
191
+ }
192
+ catch (error)
193
+ {
194
+ if (error.status === 404)
195
+ {
196
+ // Not found
197
+ }
198
+ else if (error.status === 401)
199
+ {
200
+ // Unauthorized
201
+ }
202
+ }
203
+ ```
204
+
205
+ ## Environment Variables
206
+
207
+ ```bash
208
+ # API server URL
209
+ SPFN_API_URL=http://localhost:8790
210
+
211
+ # For production
212
+ SPFN_API_URL=https://api.example.com
213
+
214
+ # RPC proxy timeout (AbortController, default: 120s)
215
+ # Should be shorter than FETCH_HEADERS_TIMEOUT for meaningful 504 responses
216
+ RPC_PROXY_TIMEOUT=120000
217
+ ```
218
+
219
+ ## Best Practices
220
+
221
+ ```typescript
222
+ // 1. Create single api instance
223
+ // src/lib/api.ts
224
+ export const api = createApi<AppRouter>();
225
+
226
+ // 2. Use in Server Components for SSR
227
+ export default async function Page() {
228
+ const data = await api.getData.call({}); // SSR
229
+ return <div>{data}</div>;
230
+ }
231
+
232
+ // 3. Handle loading states in Client Components
233
+ const [loading, setLoading] = useState(false);
234
+
235
+ // 4. Use Server Actions for mutations
236
+ 'use server';
237
+ export async function createItem(formData: FormData) {
238
+ return api.createItem.call({ body: { ... } });
239
+ }
240
+
241
+ // 5. Type-safe error handling
242
+ try {
243
+ await api.getUser.call({ params: { id } });
244
+ } catch (e) {
245
+ if (e.status === 404) redirect('/not-found');
246
+ }
247
+ ```