@next-feature/client 0.1.0-beta → 0.1.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/.babelrc +12 -12
- package/README.md +7 -518
- package/eslint.config.mjs +12 -12
- package/{jest.config.ts → jest.config.cts} +10 -10
- package/package.json +6 -4
- package/project.json +32 -32
- package/src/components/api-error-boundary.tsx +58 -58
- package/src/hooks/use-api-error.tsx +39 -39
- package/src/index.ts +30 -6
- package/src/lib/client.ts +431 -431
- package/src/lib/error.ts +169 -166
- package/src/lib/types/index.ts +13 -13
- package/src/lib/utils/error.ts +136 -136
- package/src/lib/utils/helper.ts +20 -20
- package/tsconfig.json +20 -20
- package/tsconfig.lib.json +29 -28
- package/tsconfig.spec.json +23 -22
- package/vite.config.ts +51 -48
package/.babelrc
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
{
|
|
2
|
-
"presets": [
|
|
3
|
-
[
|
|
4
|
-
"@nx/react/babel",
|
|
5
|
-
{
|
|
6
|
-
"runtime": "automatic",
|
|
7
|
-
"useBuiltIns": "usage"
|
|
8
|
-
}
|
|
9
|
-
]
|
|
10
|
-
],
|
|
11
|
-
"plugins": []
|
|
12
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"presets": [
|
|
3
|
+
[
|
|
4
|
+
"@nx/react/babel",
|
|
5
|
+
{
|
|
6
|
+
"runtime": "automatic",
|
|
7
|
+
"useBuiltIns": "usage"
|
|
8
|
+
}
|
|
9
|
+
]
|
|
10
|
+
],
|
|
11
|
+
"plugins": []
|
|
12
|
+
}
|
package/README.md
CHANGED
|
@@ -1,518 +1,7 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **ApiClient** - Axios wrapper with JWT/refresh token handling and retry logic
|
|
10
|
-
- **ApiError** - Custom error class with status helpers and validation support
|
|
11
|
-
- **Error Utilities** - Formatting, extraction, and handling functions
|
|
12
|
-
- **React Hooks** - `useApiError` for error state management
|
|
13
|
-
- **Error Boundary** - React component for error handling
|
|
14
|
-
- **Type Definitions** - Full TypeScript support
|
|
15
|
-
|
|
16
|
-
## Quick Start
|
|
17
|
-
|
|
18
|
-
### Installation
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install @next-feature/client
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Basic Usage
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
import { ApiClient, ApiError, type ApiResponse } from '@next-feature/client';
|
|
28
|
-
|
|
29
|
-
// Create client
|
|
30
|
-
const apiClient = new ApiClient({
|
|
31
|
-
baseURL: process.env.NEXT_PUBLIC_API_URL
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Use in server actions
|
|
35
|
-
export async function getUser(id: string): Promise<ApiResponse<User>> {
|
|
36
|
-
try {
|
|
37
|
-
const user = await apiClient.get<User>(`/users/${id}`);
|
|
38
|
-
return { success: true, data: user };
|
|
39
|
-
} catch (error) {
|
|
40
|
-
const apiError = ApiError.of(error);
|
|
41
|
-
return {
|
|
42
|
-
success: false,
|
|
43
|
-
message: apiError.message,
|
|
44
|
-
error: apiError.problemDetail
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Features
|
|
51
|
-
|
|
52
|
-
### 🔐 Token Management
|
|
53
|
-
|
|
54
|
-
Automatic JWT/refresh token handling with pending request queue:
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
const apiClient = new ApiClient({
|
|
58
|
-
baseURL: 'https://api.example.com',
|
|
59
|
-
enableRefreshToken: true,
|
|
60
|
-
onRefreshToken: async () => {
|
|
61
|
-
const response = await fetch('/api/refresh');
|
|
62
|
-
return (await response.json()).token;
|
|
63
|
-
},
|
|
64
|
-
onUnauthorized: async () => {
|
|
65
|
-
// Redirect to login
|
|
66
|
-
window.location.href = '/login';
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### 🔄 Retry Logic
|
|
72
|
-
|
|
73
|
-
Automatic retry with exponential backoff:
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
const apiClient = new ApiClient({
|
|
77
|
-
baseURL: 'https://api.example.com',
|
|
78
|
-
maxRetries: 3, // Retry up to 3 times
|
|
79
|
-
retryDelay: 1000 // Start with 1 second delay
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Automatically retries on:
|
|
83
|
-
// - Network errors
|
|
84
|
-
// - 5xx server errors
|
|
85
|
-
// - 429 (Too Many Requests)
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 🎯 Error Handling
|
|
89
|
-
|
|
90
|
-
Custom `ApiError` class with helpers:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
import { ApiError } from '@next-feature/client';
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
await apiClient.get('/users');
|
|
97
|
-
} catch (error) {
|
|
98
|
-
const apiError = ApiError.of(error);
|
|
99
|
-
|
|
100
|
-
if (apiError.isUnauthorized) {
|
|
101
|
-
// Handle 401 Unauthorized
|
|
102
|
-
} else if (apiError.isServerError) {
|
|
103
|
-
// Handle 5xx
|
|
104
|
-
} else if (apiError.isNotFound) {
|
|
105
|
-
// Handle 404
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
console.error(apiError.message);
|
|
109
|
-
console.error(apiError.problemDetail);
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### ✓ Zod Validation Errors
|
|
114
|
-
|
|
115
|
-
Convert form validation errors automatically:
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
import { z } from 'zod';
|
|
119
|
-
import { ApiError } from '@next-feature/client';
|
|
120
|
-
|
|
121
|
-
const schema = z.object({
|
|
122
|
-
email: z.string().email(),
|
|
123
|
-
password: z.string().min(8)
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const result = schema.safeParse(formData);
|
|
127
|
-
|
|
128
|
-
if (!result.success) {
|
|
129
|
-
// Convert Zod errors to ApiError with validation details
|
|
130
|
-
const apiError = ApiError.fromZodError(result.error);
|
|
131
|
-
|
|
132
|
-
// apiError.problemDetail.errors:
|
|
133
|
-
// { 'email': ['Invalid email'], 'password': ['Too short'] }
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 🎨 Spring Boot Integration
|
|
138
|
-
|
|
139
|
-
Compatible with Spring Boot `ProblemDetail` error responses:
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
// Backend returns:
|
|
143
|
-
{
|
|
144
|
-
"type": "https://example.com/probs/invalid-request",
|
|
145
|
-
"title": "Invalid Request",
|
|
146
|
-
"status": 400,
|
|
147
|
-
"detail": "The request contained invalid data",
|
|
148
|
-
"errors": {
|
|
149
|
-
"email": ["Invalid email format"]
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Automatically parsed into:
|
|
154
|
-
const apiError = ApiError.of(error);
|
|
155
|
-
console.log(apiError.problemDetail.errors); // { email: ['Invalid...'] }
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
## HTTP Methods
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
// GET
|
|
162
|
-
const data = await apiClient.get<T>('/endpoint');
|
|
163
|
-
|
|
164
|
-
// POST
|
|
165
|
-
const data = await apiClient.post<T>('/endpoint', { body });
|
|
166
|
-
|
|
167
|
-
// PUT
|
|
168
|
-
const data = await apiClient.put<T>('/endpoint', { body });
|
|
169
|
-
|
|
170
|
-
// PATCH
|
|
171
|
-
const data = await apiClient.patch<T>('/endpoint', { body });
|
|
172
|
-
|
|
173
|
-
// DELETE
|
|
174
|
-
const data = await apiClient.delete<T>('/endpoint');
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## Interceptors
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
const apiClient = new ApiClient({ baseURL: '...' });
|
|
181
|
-
|
|
182
|
-
// Request interceptor
|
|
183
|
-
apiClient.getAxiosInstance().interceptors.request.use((config) => {
|
|
184
|
-
// Add custom headers
|
|
185
|
-
config.headers['X-Custom-Header'] = 'value';
|
|
186
|
-
return config;
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// Response interceptor
|
|
190
|
-
apiClient.getAxiosInstance().interceptors.response.use(
|
|
191
|
-
(response) => response,
|
|
192
|
-
(error) => {
|
|
193
|
-
// Global error handling
|
|
194
|
-
console.error(error);
|
|
195
|
-
return Promise.reject(error);
|
|
196
|
-
}
|
|
197
|
-
);
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Error Utilities
|
|
201
|
-
|
|
202
|
-
### getErrorMessage()
|
|
203
|
-
|
|
204
|
-
Extract user-friendly error message:
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
import { getErrorMessage } from '@next-feature/client';
|
|
208
|
-
|
|
209
|
-
const message = getErrorMessage(error);
|
|
210
|
-
toast.error(message);
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### formatProblemDetail()
|
|
214
|
-
|
|
215
|
-
Format error for display:
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
import { formatProblemDetail } from '@next-feature/client';
|
|
219
|
-
|
|
220
|
-
const formatted = formatProblemDetail(apiError);
|
|
221
|
-
console.log(formatted);
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
### isHttpStatus()
|
|
225
|
-
|
|
226
|
-
Check specific HTTP status:
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
import { isHttpStatus } from '@next-feature/client';
|
|
230
|
-
|
|
231
|
-
if (isHttpStatus(error, 401)) {
|
|
232
|
-
redirectToLogin();
|
|
233
|
-
}
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### handleApiError()
|
|
237
|
-
|
|
238
|
-
Global error handler:
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
import { handleApiError } from '@next-feature/client';
|
|
242
|
-
|
|
243
|
-
try {
|
|
244
|
-
await apiClient.get('/data');
|
|
245
|
-
} catch (error) {
|
|
246
|
-
handleApiError(error); // Logs appropriate messages
|
|
247
|
-
}
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### extractValidationErrors()
|
|
251
|
-
|
|
252
|
-
Extract form field errors:
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
255
|
-
import { extractValidationErrors } from '@next-feature/client';
|
|
256
|
-
|
|
257
|
-
const fieldErrors = extractValidationErrors(apiError);
|
|
258
|
-
// { email: ['Invalid email'], password: ['Too short'] }
|
|
259
|
-
|
|
260
|
-
// Use with forms
|
|
261
|
-
Object.entries(fieldErrors).forEach(([field, messages]) => {
|
|
262
|
-
showFieldError(field, messages[0]);
|
|
263
|
-
});
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## React Integration
|
|
267
|
-
|
|
268
|
-
### useApiError Hook
|
|
269
|
-
|
|
270
|
-
Manage API error state in components:
|
|
271
|
-
|
|
272
|
-
```typescript
|
|
273
|
-
'use client';
|
|
274
|
-
|
|
275
|
-
import { useApiError } from '@next-feature/client';
|
|
276
|
-
|
|
277
|
-
export function MyComponent() {
|
|
278
|
-
const { error, setError, clearError } = useApiError();
|
|
279
|
-
|
|
280
|
-
const handleSubmit = async (data) => {
|
|
281
|
-
try {
|
|
282
|
-
const result = await myAction(data);
|
|
283
|
-
if (!result.success) {
|
|
284
|
-
setError(result.error);
|
|
285
|
-
}
|
|
286
|
-
} catch (err) {
|
|
287
|
-
setError(ApiError.of(err));
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
return (
|
|
292
|
-
<>
|
|
293
|
-
{error && (
|
|
294
|
-
<div className="error-alert">
|
|
295
|
-
<p>{error.message}</p>
|
|
296
|
-
<button onClick={clearError}>Dismiss</button>
|
|
297
|
-
</div>
|
|
298
|
-
)}
|
|
299
|
-
{/* Form JSX */}
|
|
300
|
-
</>
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### ApiErrorBoundary Component
|
|
306
|
-
|
|
307
|
-
Error boundary for API errors:
|
|
308
|
-
|
|
309
|
-
```typescript
|
|
310
|
-
import { ApiErrorBoundary } from '@next-feature/client';
|
|
311
|
-
|
|
312
|
-
export function App() {
|
|
313
|
-
return (
|
|
314
|
-
<ApiErrorBoundary
|
|
315
|
-
fallback={(error, reset) => (
|
|
316
|
-
<div className="error-page">
|
|
317
|
-
<h1>Something went wrong</h1>
|
|
318
|
-
<p>{error.message}</p>
|
|
319
|
-
<button onClick={reset}>Try again</button>
|
|
320
|
-
</div>
|
|
321
|
-
)}
|
|
322
|
-
>
|
|
323
|
-
<YourContent />
|
|
324
|
-
</ApiErrorBoundary>
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
## Type Definitions
|
|
330
|
-
|
|
331
|
-
### ApiResponse<T>
|
|
332
|
-
|
|
333
|
-
Standard API response envelope:
|
|
334
|
-
|
|
335
|
-
```typescript
|
|
336
|
-
interface ApiResponse<T> {
|
|
337
|
-
success: boolean;
|
|
338
|
-
data?: T;
|
|
339
|
-
error?: ProblemDetail | null;
|
|
340
|
-
message?: string;
|
|
341
|
-
}
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
### ProblemDetail
|
|
345
|
-
|
|
346
|
-
Error detail structure:
|
|
347
|
-
|
|
348
|
-
```typescript
|
|
349
|
-
interface ProblemDetail {
|
|
350
|
-
type: string;
|
|
351
|
-
title: string;
|
|
352
|
-
status: number;
|
|
353
|
-
detail?: string;
|
|
354
|
-
instance?: string;
|
|
355
|
-
errors?: Record<string, unknown>;
|
|
356
|
-
[key: string]: unknown;
|
|
357
|
-
}
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
### ApiClientConfig
|
|
361
|
-
|
|
362
|
-
Client configuration:
|
|
363
|
-
|
|
364
|
-
```typescript
|
|
365
|
-
interface ApiClientConfig {
|
|
366
|
-
baseURL: string;
|
|
367
|
-
timeout?: number; // Default: 30000ms
|
|
368
|
-
enableRefreshToken?: boolean; // Default: true
|
|
369
|
-
maxRetries?: number; // Default: 3
|
|
370
|
-
retryDelay?: number; // Default: 1000ms
|
|
371
|
-
onAuthenticated?: (config) => void | Promise<void>;
|
|
372
|
-
onUnauthorized?: () => void | Promise<void>;
|
|
373
|
-
onRefreshTokenExpired?: () => void | Promise<void>;
|
|
374
|
-
onRefreshToken?: () => string | Promise<string>;
|
|
375
|
-
}
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
## Integration with next-feature
|
|
379
|
-
|
|
380
|
-
This library is designed to work seamlessly with the **next-feature generator plugin**:
|
|
381
|
-
|
|
382
|
-
```bash
|
|
383
|
-
# Actions automatically import from this library
|
|
384
|
-
npx nx g next-feature:action --name=getUser --projectName=myapp
|
|
385
|
-
|
|
386
|
-
# Generated action will use:
|
|
387
|
-
import { ApiError, type ApiResponse } from '@next-feature/client';
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
Generated client configurations use this library:
|
|
391
|
-
|
|
392
|
-
```bash
|
|
393
|
-
# Client-config generator creates lib/client/config.ts
|
|
394
|
-
npx nx g next-feature:client-config --projectName=myapp
|
|
395
|
-
|
|
396
|
-
# Which imports and uses:
|
|
397
|
-
import { ApiClient, ApiError } from '@next-feature/client';
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
## Testing
|
|
401
|
-
|
|
402
|
-
```bash
|
|
403
|
-
npm test
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
Run tests with coverage:
|
|
407
|
-
|
|
408
|
-
```bash
|
|
409
|
-
npm test -- --coverage
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
## Development
|
|
413
|
-
|
|
414
|
-
### Build
|
|
415
|
-
|
|
416
|
-
```bash
|
|
417
|
-
npm run build
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
### Lint
|
|
421
|
-
|
|
422
|
-
```bash
|
|
423
|
-
npm run lint
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### Format
|
|
427
|
-
|
|
428
|
-
```bash
|
|
429
|
-
npm run format
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
## Examples
|
|
433
|
-
|
|
434
|
-
### Form Submission with Validation
|
|
435
|
-
|
|
436
|
-
```typescript
|
|
437
|
-
'use server';
|
|
438
|
-
|
|
439
|
-
import { z } from 'zod';
|
|
440
|
-
import { ApiError, type ApiResponse } from '@next-feature/client';
|
|
441
|
-
import apiClient from './config';
|
|
442
|
-
|
|
443
|
-
const schema = z.object({
|
|
444
|
-
email: z.string().email(),
|
|
445
|
-
password: z.string().min(8)
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
export async function loginAction(
|
|
449
|
-
formData: FormData
|
|
450
|
-
): Promise<ApiResponse<{ token: string }>> {
|
|
451
|
-
const email = formData.get('email');
|
|
452
|
-
const password = formData.get('password');
|
|
453
|
-
|
|
454
|
-
const result = schema.safeParse({ email, password });
|
|
455
|
-
|
|
456
|
-
if (!result.success) {
|
|
457
|
-
const apiError = ApiError.fromZodError(result.error);
|
|
458
|
-
return {
|
|
459
|
-
success: false,
|
|
460
|
-
message: apiError.message,
|
|
461
|
-
error: apiError.problemDetail
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
const token = await apiClient.post<{ token: string }>('/auth/login', result.data);
|
|
467
|
-
return { success: true, data: token };
|
|
468
|
-
} catch (error) {
|
|
469
|
-
const apiError = ApiError.of(error);
|
|
470
|
-
return {
|
|
471
|
-
success: false,
|
|
472
|
-
message: apiError.message,
|
|
473
|
-
error: apiError.problemDetail
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
### API Data Fetching
|
|
480
|
-
|
|
481
|
-
```typescript
|
|
482
|
-
export async function getProduct(id: string): Promise<ApiResponse<Product>> {
|
|
483
|
-
try {
|
|
484
|
-
const product = await apiClient.get<Product>(`/products/${id}`);
|
|
485
|
-
return { success: true, data: product };
|
|
486
|
-
} catch (error) {
|
|
487
|
-
const apiError = ApiError.of(error);
|
|
488
|
-
return {
|
|
489
|
-
success: false,
|
|
490
|
-
message: `Failed to fetch product: ${apiError.message}`,
|
|
491
|
-
error: apiError.problemDetail
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
## Troubleshooting
|
|
498
|
-
|
|
499
|
-
### Request not retried
|
|
500
|
-
|
|
501
|
-
Check `enableRefreshToken` and `maxRetries` configuration.
|
|
502
|
-
|
|
503
|
-
### Token not refreshed
|
|
504
|
-
|
|
505
|
-
Ensure `onRefreshToken` is implemented and returns valid token string.
|
|
506
|
-
|
|
507
|
-
### Type mismatches
|
|
508
|
-
|
|
509
|
-
Ensure your `ProblemDetail` shape matches your backend error responses.
|
|
510
|
-
|
|
511
|
-
## License
|
|
512
|
-
|
|
513
|
-
MIT
|
|
514
|
-
|
|
515
|
-
## See Also
|
|
516
|
-
|
|
517
|
-
- [next-feature Plugin](../../next-feature/README.md) - Generator plugin using this library
|
|
518
|
-
- [NextFeature](../../README.md) - Complete ecosystem overview
|
|
1
|
+
# client
|
|
2
|
+
|
|
3
|
+
This library was generated with [Nx](https://nx.dev).
|
|
4
|
+
|
|
5
|
+
## Running unit tests
|
|
6
|
+
|
|
7
|
+
Run `nx test client` to execute the unit tests via [Vitest](https://vitest.dev/).
|
package/eslint.config.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import nx from '@nx/eslint-plugin';
|
|
2
|
-
import baseConfig from '../../eslint.config.mjs';
|
|
3
|
-
|
|
4
|
-
export default [
|
|
5
|
-
...baseConfig,
|
|
6
|
-
...nx.configs['flat/react'],
|
|
7
|
-
{
|
|
8
|
-
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
9
|
-
// Override or add rules here
|
|
10
|
-
rules: {},
|
|
11
|
-
},
|
|
12
|
-
];
|
|
1
|
+
import nx from '@nx/eslint-plugin';
|
|
2
|
+
import baseConfig from '../../eslint.config.mjs';
|
|
3
|
+
|
|
4
|
+
export default [
|
|
5
|
+
...baseConfig,
|
|
6
|
+
...nx.configs['flat/react'],
|
|
7
|
+
{
|
|
8
|
+
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
9
|
+
// Override or add rules here
|
|
10
|
+
rules: {},
|
|
11
|
+
},
|
|
12
|
+
];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
displayName: 'client',
|
|
3
|
-
preset: '../../jest.preset.js',
|
|
4
|
-
transform: {
|
|
5
|
-
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
|
6
|
-
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
|
|
7
|
-
},
|
|
8
|
-
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
|
9
|
-
coverageDirectory: '../../coverage/clients/client',
|
|
10
|
-
};
|
|
1
|
+
module.exports = {
|
|
2
|
+
displayName: 'client',
|
|
3
|
+
preset: '../../jest.preset.js',
|
|
4
|
+
transform: {
|
|
5
|
+
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
|
6
|
+
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
|
|
7
|
+
},
|
|
8
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
|
9
|
+
coverageDirectory: '../../coverage/clients/client',
|
|
10
|
+
};
|
package/package.json
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@next-feature/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"main": "./index.js",
|
|
5
5
|
"types": "./index.d.ts",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
8
|
"import": "./index.mjs",
|
|
9
9
|
"require": "./index.js"
|
|
10
|
+
},
|
|
11
|
+
"./server": {
|
|
12
|
+
"types": "./dist/server.d.ts",
|
|
13
|
+
"import": "./dist/server.js",
|
|
14
|
+
"default": "./dist/server.js"
|
|
10
15
|
}
|
|
11
|
-
},
|
|
12
|
-
"publishConfig": {
|
|
13
|
-
"access": "public"
|
|
14
16
|
}
|
|
15
17
|
}
|
package/project.json
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "client",
|
|
3
|
-
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"sourceRoot": "clients/client/src",
|
|
5
|
-
"projectType": "library",
|
|
6
|
-
"tags": [],
|
|
7
|
-
"targets": {
|
|
8
|
-
"build": {
|
|
9
|
-
"executor": "@nx/vite:build",
|
|
10
|
-
"outputs": ["{options.outputPath}"],
|
|
11
|
-
"defaultConfiguration": "production",
|
|
12
|
-
"options": {
|
|
13
|
-
"outputPath": "dist/clients/client"
|
|
14
|
-
},
|
|
15
|
-
"configurations": {
|
|
16
|
-
"development": {
|
|
17
|
-
"mode": "development"
|
|
18
|
-
},
|
|
19
|
-
"production": {
|
|
20
|
-
"mode": "production"
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
"test": {
|
|
25
|
-
"executor": "@nx/jest:jest",
|
|
26
|
-
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
27
|
-
"options": {
|
|
28
|
-
"jestConfig": "clients/client/jest.config.
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "client",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "clients/client/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": [],
|
|
7
|
+
"targets": {
|
|
8
|
+
"build": {
|
|
9
|
+
"executor": "@nx/vite:build",
|
|
10
|
+
"outputs": ["{options.outputPath}"],
|
|
11
|
+
"defaultConfiguration": "production",
|
|
12
|
+
"options": {
|
|
13
|
+
"outputPath": "dist/clients/client"
|
|
14
|
+
},
|
|
15
|
+
"configurations": {
|
|
16
|
+
"development": {
|
|
17
|
+
"mode": "development"
|
|
18
|
+
},
|
|
19
|
+
"production": {
|
|
20
|
+
"mode": "production"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"test": {
|
|
25
|
+
"executor": "@nx/jest:jest",
|
|
26
|
+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
27
|
+
"options": {
|
|
28
|
+
"jestConfig": "clients/client/jest.config.cts"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|