ai-flow-dev 1.0.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.
- package/LICENSE +21 -0
- package/README.md +408 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +791 -0
- package/dist/cli.js.map +1 -0
- package/dist/fs-utils.d.ts +2 -0
- package/dist/fs-utils.d.ts.map +1 -0
- package/dist/fs-utils.js +46 -0
- package/dist/fs-utils.js.map +1 -0
- package/package.json +71 -0
- package/prompts/backend/flow-dev-feature.md +1318 -0
- package/prompts/backend/flow-dev-fix.md +903 -0
- package/prompts/backend/flow-dev-refactor.md +715 -0
- package/prompts/backend/flow-dev-review.md +401 -0
- package/prompts/backend/flow-dev-work.md +1129 -0
- package/prompts/backend/flow-docs-gen-phase-0.md +1840 -0
- package/prompts/backend/flow-docs-gen-phase-1.md +435 -0
- package/prompts/backend/flow-docs-gen-phase-2.md +460 -0
- package/prompts/backend/flow-docs-gen-phase-3.md +684 -0
- package/prompts/backend/flow-docs-gen-phase-4.md +516 -0
- package/prompts/backend/flow-docs-gen-phase-5.md +637 -0
- package/prompts/backend/flow-docs-gen-phase-6.md +465 -0
- package/prompts/backend/flow-docs-gen-phase-7.md +1207 -0
- package/prompts/backend/flow-docs-gen.md +820 -0
- package/prompts/backend/flow-docs-sync.md +526 -0
- package/prompts/backend/flow-project-init.md +248 -0
- package/prompts/backend/flow-project-roadmap.md +1159 -0
- package/prompts/frontend/flow-docs-gen-phase-0.md +494 -0
- package/prompts/frontend/flow-docs-gen-phase-1.md +449 -0
- package/prompts/frontend/flow-docs-gen-phase-2.md +983 -0
- package/prompts/frontend/flow-docs-gen-phase-3.md +685 -0
- package/prompts/frontend/flow-docs-gen-phase-4.md +480 -0
- package/prompts/frontend/flow-docs-gen-phase-5.md +483 -0
- package/prompts/frontend/flow-docs-gen-phase-6.md +570 -0
- package/prompts/frontend/flow-docs-gen-phase-7.md +582 -0
- package/prompts/frontend/flow-docs-gen.md +413 -0
- package/prompts/frontend/flow-docs-sync.md +561 -0
- package/prompts/mobile/flow-docs-gen-phase-0.md +387 -0
- package/prompts/mobile/flow-docs-gen-phase-1.md +530 -0
- package/prompts/mobile/flow-docs-gen-phase-2.md +584 -0
- package/prompts/mobile/flow-docs-gen-phase-3.md +659 -0
- package/prompts/mobile/flow-docs-gen-phase-4.md +363 -0
- package/prompts/mobile/flow-docs-gen-phase-5.md +369 -0
- package/prompts/mobile/flow-docs-gen-phase-6.md +490 -0
- package/prompts/mobile/flow-docs-gen-phase-7.md +407 -0
- package/prompts/mobile/flow-docs-gen.md +430 -0
- package/prompts/mobile/flow-docs-sync.md +634 -0
- package/templates/backend/.clauderules.template +111 -0
- package/templates/backend/.cursorrules.template +102 -0
- package/templates/backend/.env.example.template +122 -0
- package/templates/backend/README.template.md +200 -0
- package/templates/backend/ai-instructions.template.md +354 -0
- package/templates/backend/copilot-instructions.template.md +160 -0
- package/templates/backend/docs/api.template.md +251 -0
- package/templates/backend/docs/architecture.template.md +612 -0
- package/templates/backend/docs/business-flows.template.md +109 -0
- package/templates/backend/docs/code-standards.template.md +828 -0
- package/templates/backend/docs/contributing.template.md +163 -0
- package/templates/backend/docs/data-model.template.md +416 -0
- package/templates/backend/docs/operations.template.md +591 -0
- package/templates/backend/docs/testing.template.md +762 -0
- package/templates/backend/project-brief.template.md +176 -0
- package/templates/backend/specs/configuration.template.md +133 -0
- package/templates/backend/specs/security.template.md +422 -0
- package/templates/frontend/README.template.md +121 -0
- package/templates/frontend/ai-instructions.template.md +368 -0
- package/templates/frontend/docs/api-integration.template.md +390 -0
- package/templates/frontend/docs/components.template.md +567 -0
- package/templates/frontend/docs/error-handling.template.md +385 -0
- package/templates/frontend/docs/operations.template.md +123 -0
- package/templates/frontend/docs/performance.template.md +140 -0
- package/templates/frontend/docs/pwa.template.md +135 -0
- package/templates/frontend/docs/state-management.template.md +394 -0
- package/templates/frontend/docs/styling.template.md +779 -0
- package/templates/frontend/docs/testing.template.md +736 -0
- package/templates/frontend/project-brief.template.md +55 -0
- package/templates/frontend/specs/accessibility.template.md +111 -0
- package/templates/frontend/specs/configuration.template.md +520 -0
- package/templates/frontend/specs/security.template.md +197 -0
- package/templates/fullstack/README.template.md +282 -0
- package/templates/fullstack/ai-instructions.template.md +487 -0
- package/templates/fullstack/project-brief.template.md +197 -0
- package/templates/fullstack/specs/configuration.template.md +380 -0
- package/templates/mobile/AGENT.template.md +251 -0
- package/templates/mobile/README.template.md +195 -0
- package/templates/mobile/ai-instructions.template.md +221 -0
- package/templates/mobile/docs/app-store.template.md +163 -0
- package/templates/mobile/docs/architecture.template.md +100 -0
- package/templates/mobile/docs/native-features.template.md +137 -0
- package/templates/mobile/docs/navigation.template.md +81 -0
- package/templates/mobile/docs/offline-strategy.template.md +90 -0
- package/templates/mobile/docs/permissions.template.md +70 -0
- package/templates/mobile/docs/state-management.template.md +116 -0
- package/templates/mobile/docs/testing.template.md +146 -0
- package/templates/mobile/project-brief.template.md +97 -0
- package/templates/mobile/specs/build-configuration.template.md +116 -0
- package/templates/mobile/specs/deployment.template.md +114 -0
- package/templates/shared/AGENT.template.md +252 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
# API Integration
|
|
2
|
+
|
|
3
|
+
> API communication patterns and best practices for {{PROJECT_NAME}}
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ๐ฏ API Integration Strategy
|
|
8
|
+
|
|
9
|
+
**Pattern:** {{API_INTEGRATION_PATTERN}}
|
|
10
|
+
**Client:** {{API_CLIENT}}
|
|
11
|
+
**Base URL:** {{API_BASE_URL}}
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ๐ก API Client Setup
|
|
16
|
+
|
|
17
|
+
### Base Configuration
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// services/api.ts
|
|
21
|
+
import axios from 'axios';
|
|
22
|
+
// or: import { createClient } from '@urql/core';
|
|
23
|
+
|
|
24
|
+
const apiClient = axios.create({
|
|
25
|
+
baseURL: import.meta.env.VITE_API_BASE_URL,
|
|
26
|
+
timeout: 30000,
|
|
27
|
+
headers: {
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Request interceptor
|
|
33
|
+
apiClient.interceptors.request.use(
|
|
34
|
+
(config) => {
|
|
35
|
+
// Add auth token
|
|
36
|
+
const token = getAuthToken();
|
|
37
|
+
if (token) {
|
|
38
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
39
|
+
}
|
|
40
|
+
return config;
|
|
41
|
+
},
|
|
42
|
+
(error) => Promise.reject(error)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Response interceptor
|
|
46
|
+
apiClient.interceptors.response.use(
|
|
47
|
+
(response) => response,
|
|
48
|
+
async (error) => {
|
|
49
|
+
// Handle 401 - Unauthorized
|
|
50
|
+
if (error.response?.status === 401) {
|
|
51
|
+
await handleUnauthorized();
|
|
52
|
+
}
|
|
53
|
+
return Promise.reject(error);
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
export default apiClient;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## ๐๏ธ API Layer Pattern
|
|
63
|
+
|
|
64
|
+
### Service Layer (Recommended)
|
|
65
|
+
|
|
66
|
+
**Structure:**
|
|
67
|
+
```
|
|
68
|
+
services/
|
|
69
|
+
โโโ api.ts # Base client configuration
|
|
70
|
+
โโโ users.ts # User endpoints
|
|
71
|
+
โโโ products.ts # Product endpoints
|
|
72
|
+
โโโ orders.ts # Order endpoints
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Example:**
|
|
76
|
+
```typescript
|
|
77
|
+
// services/users.ts
|
|
78
|
+
import apiClient from './api';
|
|
79
|
+
|
|
80
|
+
export const usersService = {
|
|
81
|
+
async getById(id: string): Promise<User> {
|
|
82
|
+
const { data } = await apiClient.get(`/users/${id}`);
|
|
83
|
+
return data;
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
async create(userData: CreateUserDto): Promise<User> {
|
|
87
|
+
const { data } = await apiClient.post('/users', userData);
|
|
88
|
+
return data;
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
async update(id: string, userData: UpdateUserDto): Promise<User> {
|
|
92
|
+
const { data } = await apiClient.put(`/users/${id}`, userData);
|
|
93
|
+
return data;
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
async delete(id: string): Promise<void> {
|
|
97
|
+
await apiClient.delete(`/users/${id}`);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Hooks/Composables Layer
|
|
103
|
+
|
|
104
|
+
**React Example:**
|
|
105
|
+
```typescript
|
|
106
|
+
// hooks/useUsers.ts
|
|
107
|
+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
108
|
+
import { usersService } from '@/services/users';
|
|
109
|
+
|
|
110
|
+
export const useUsers = () => {
|
|
111
|
+
const queryClient = useQueryClient();
|
|
112
|
+
|
|
113
|
+
const getById = (id: string) => {
|
|
114
|
+
return useQuery({
|
|
115
|
+
queryKey: ['users', id],
|
|
116
|
+
queryFn: () => usersService.getById(id),
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const create = useMutation({
|
|
121
|
+
mutationFn: usersService.create,
|
|
122
|
+
onSuccess: () => {
|
|
123
|
+
queryClient.invalidateQueries({ queryKey: ['users'] });
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return { getById, create };
|
|
128
|
+
};
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Vue Example:**
|
|
132
|
+
```typescript
|
|
133
|
+
// composables/useUsers.ts
|
|
134
|
+
import { useQuery, useMutation } from '@tanstack/vue-query';
|
|
135
|
+
import { usersService } from '@/services/users';
|
|
136
|
+
|
|
137
|
+
export const useUsers = () => {
|
|
138
|
+
const getById = (id: string) => {
|
|
139
|
+
return useQuery({
|
|
140
|
+
queryKey: ['users', id],
|
|
141
|
+
queryFn: () => usersService.getById(id),
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const create = useMutation({
|
|
146
|
+
mutationFn: usersService.create,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return { getById, create };
|
|
150
|
+
};
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## ๐ Error Handling
|
|
156
|
+
|
|
157
|
+
### Error Types
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// types/api.ts
|
|
161
|
+
export class ApiError extends Error {
|
|
162
|
+
constructor(
|
|
163
|
+
public status: number,
|
|
164
|
+
public message: string,
|
|
165
|
+
public code?: string
|
|
166
|
+
) {
|
|
167
|
+
super(message);
|
|
168
|
+
this.name = 'ApiError';
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export class NetworkError extends Error {
|
|
173
|
+
constructor(message: string) {
|
|
174
|
+
super(message);
|
|
175
|
+
this.name = 'NetworkError';
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export class TimeoutError extends Error {
|
|
180
|
+
constructor(message: string) {
|
|
181
|
+
super(message);
|
|
182
|
+
this.name = 'TimeoutError';
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Error Handling Strategy
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// utils/errorHandler.ts
|
|
191
|
+
import { ApiError, NetworkError, TimeoutError } from '@/types/api';
|
|
192
|
+
|
|
193
|
+
export function handleApiError(error: unknown): string {
|
|
194
|
+
if (error instanceof ApiError) {
|
|
195
|
+
switch (error.status) {
|
|
196
|
+
case 400:
|
|
197
|
+
return 'Invalid request. Please check your input.';
|
|
198
|
+
case 401:
|
|
199
|
+
return 'Unauthorized. Please log in again.';
|
|
200
|
+
case 403:
|
|
201
|
+
return 'Access denied. You don\'t have permission.';
|
|
202
|
+
case 404:
|
|
203
|
+
return 'Resource not found.';
|
|
204
|
+
case 500:
|
|
205
|
+
return 'Server error. Please try again later.';
|
|
206
|
+
default:
|
|
207
|
+
return 'An error occurred. Please try again.';
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (error instanceof NetworkError) {
|
|
212
|
+
return 'Network error. Please check your connection.';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (error instanceof TimeoutError) {
|
|
216
|
+
return 'Request timed out. Please try again.';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return 'An unexpected error occurred.';
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## ๐ Retry Strategy
|
|
226
|
+
|
|
227
|
+
### Automatic Retry
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// utils/retry.ts
|
|
231
|
+
export async function retryRequest<T>(
|
|
232
|
+
fn: () => Promise<T>,
|
|
233
|
+
maxRetries = 3,
|
|
234
|
+
delay = 1000
|
|
235
|
+
): Promise<T> {
|
|
236
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
237
|
+
try {
|
|
238
|
+
return await fn();
|
|
239
|
+
} catch (error) {
|
|
240
|
+
if (i === maxRetries - 1) throw error;
|
|
241
|
+
|
|
242
|
+
// Exponential backoff
|
|
243
|
+
await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i)));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
throw new Error('Max retries exceeded');
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Usage with TanStack Query
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
import { useQuery } from '@tanstack/react-query';
|
|
254
|
+
|
|
255
|
+
const { data } = useQuery({
|
|
256
|
+
queryKey: ['users', id],
|
|
257
|
+
queryFn: () => usersService.getById(id),
|
|
258
|
+
retry: 3,
|
|
259
|
+
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## ๐ Authentication
|
|
266
|
+
|
|
267
|
+
### Token Management
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// utils/auth.ts
|
|
271
|
+
const TOKEN_KEY = 'auth_token';
|
|
272
|
+
|
|
273
|
+
export function getAuthToken(): string | null {
|
|
274
|
+
// Option 1: httpOnly cookie (most secure)
|
|
275
|
+
// Token sent automatically with requests
|
|
276
|
+
|
|
277
|
+
// Option 2: localStorage (less secure)
|
|
278
|
+
return localStorage.getItem(TOKEN_KEY);
|
|
279
|
+
|
|
280
|
+
// Option 3: Memory storage (most secure, lost on refresh)
|
|
281
|
+
// Store in closure variable
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function setAuthToken(token: string): void {
|
|
285
|
+
localStorage.setItem(TOKEN_KEY, token);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function removeAuthToken(): void {
|
|
289
|
+
localStorage.removeItem(TOKEN_KEY);
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Token Refresh
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// services/auth.ts
|
|
297
|
+
let refreshTokenPromise: Promise<string> | null = null;
|
|
298
|
+
|
|
299
|
+
export async function refreshAuthToken(): Promise<string> {
|
|
300
|
+
if (refreshTokenPromise) {
|
|
301
|
+
return refreshTokenPromise;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
refreshTokenPromise = (async () => {
|
|
305
|
+
try {
|
|
306
|
+
const { data } = await apiClient.post('/auth/refresh');
|
|
307
|
+
setAuthToken(data.accessToken);
|
|
308
|
+
return data.accessToken;
|
|
309
|
+
} finally {
|
|
310
|
+
refreshTokenPromise = null;
|
|
311
|
+
}
|
|
312
|
+
})();
|
|
313
|
+
|
|
314
|
+
return refreshTokenPromise;
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## ๐ Request/Response Transformation
|
|
321
|
+
|
|
322
|
+
### Request Transformation
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
// Transform data before sending
|
|
326
|
+
apiClient.interceptors.request.use((config) => {
|
|
327
|
+
if (config.data) {
|
|
328
|
+
// Convert dates to ISO strings
|
|
329
|
+
config.data = transformDates(config.data);
|
|
330
|
+
}
|
|
331
|
+
return config;
|
|
332
|
+
});
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Response Transformation
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Transform data after receiving
|
|
339
|
+
apiClient.interceptors.response.use((response) => {
|
|
340
|
+
if (response.data) {
|
|
341
|
+
// Convert ISO strings to Date objects
|
|
342
|
+
response.data = parseDates(response.data);
|
|
343
|
+
}
|
|
344
|
+
return response;
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## ๐งช Testing API Integration
|
|
351
|
+
|
|
352
|
+
### Mocking API Calls
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
// Using MSW (Mock Service Worker)
|
|
356
|
+
import { rest } from 'msw';
|
|
357
|
+
import { setupServer } from 'msw/node';
|
|
358
|
+
|
|
359
|
+
const server = setupServer(
|
|
360
|
+
rest.get('/api/users/:id', (req, res, ctx) => {
|
|
361
|
+
return res(
|
|
362
|
+
ctx.json({
|
|
363
|
+
id: req.params.id,
|
|
364
|
+
name: 'John Doe',
|
|
365
|
+
email: 'john@example.com',
|
|
366
|
+
})
|
|
367
|
+
);
|
|
368
|
+
})
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
beforeAll(() => server.listen());
|
|
372
|
+
afterEach(() => server.resetHandlers());
|
|
373
|
+
afterAll(() => server.close());
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## ๐ Related Documents
|
|
379
|
+
|
|
380
|
+
- [State Management](state-management.md) - Server state patterns
|
|
381
|
+
- [Error Handling](error-handling.md) - Error handling strategies
|
|
382
|
+
- [Security](security.md) - Security best practices
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
**Last Updated:** {{GENERATION_DATE}}
|
|
387
|
+
|
|
388
|
+
**API Pattern:** {{API_INTEGRATION_PATTERN}}
|
|
389
|
+
**Client:** {{API_CLIENT}}
|
|
390
|
+
|