routesync 1.0.36 → 1.0.40
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/README.md +90 -43
- package/dist/cli.js +625 -389
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ RouteSync does all of that. You point it at `routes/api.php` and it generates th
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
# Step 1 — in your Laravel folder
|
|
17
|
+
npx routesync annotate --input routes/api.php # auto-inject #[Response] to controllers
|
|
17
18
|
npx routesync scan --input routes/api.php --models
|
|
18
19
|
|
|
19
20
|
# Step 2 — in your frontend folder
|
|
@@ -21,6 +22,8 @@ npx routesync generate --manifest routesync.manifest.json --output src/api --nex
|
|
|
21
22
|
```
|
|
22
23
|
|
|
23
24
|
```
|
|
25
|
+
✔ Annotated 12 method(s) across 6 controller file(s)
|
|
26
|
+
|
|
24
27
|
✔ Found 35 routes, 19 models → routesync.manifest.json
|
|
25
28
|
|
|
26
29
|
✔ SDK generated → src/api
|
|
@@ -65,7 +68,35 @@ npm install routesync zod
|
|
|
65
68
|
|
|
66
69
|
## Full Workflow (Laravel + Next.js)
|
|
67
70
|
|
|
68
|
-
### 1.
|
|
71
|
+
### 1. Auto-annotate controllers (one-time setup)
|
|
72
|
+
|
|
73
|
+
Run this from your **Laravel project root** to auto-inject `#[Response]` attributes into every controller method:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx routesync annotate --input routes/api.php
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
| Option | Description |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `--input <file>` | Path to routes file (default: `routes/api.php`) |
|
|
82
|
+
| `--dry-run` | Preview what would be injected without writing files |
|
|
83
|
+
| `--force` | Re-annotate methods that already have `#[Response]` |
|
|
84
|
+
|
|
85
|
+
This command:
|
|
86
|
+
- Detects `return new XxxResource(...)` / `XxxResource::collection(...)` / `response()->json(new XxxResource(...))` in each controller method
|
|
87
|
+
- Resolves the model from the Resource's `@mixin` docblock (or strips the `Resource` suffix as fallback)
|
|
88
|
+
- Injects `#[Response(Model::class)]` or `#[Response(Model::class, collection: true)]` above the method
|
|
89
|
+
- Adds `use App\Attributes\Response;` to controller imports automatically
|
|
90
|
+
- Creates `app/Attributes/Response.php` if it doesn't exist yet
|
|
91
|
+
|
|
92
|
+
> **Tip:** Preview first with `--dry-run`:
|
|
93
|
+
> ```bash
|
|
94
|
+
> npx routesync annotate --input routes/api.php --dry-run
|
|
95
|
+
> ```
|
|
96
|
+
|
|
97
|
+
You only need to run this once, or again when you add new endpoints.
|
|
98
|
+
|
|
99
|
+
### 2. Scan routes & models
|
|
69
100
|
|
|
70
101
|
Run this from your **Laravel project root**:
|
|
71
102
|
|
|
@@ -92,28 +123,24 @@ npx routesync scan --input routes/api.php --models
|
|
|
92
123
|
> cp ../backend/routesync.manifest.json .
|
|
93
124
|
> ```
|
|
94
125
|
|
|
95
|
-
###
|
|
126
|
+
### 3. Generate the SDK
|
|
96
127
|
|
|
97
128
|
Run this from your **frontend project root**:
|
|
98
129
|
|
|
99
130
|
```bash
|
|
100
|
-
npx routesync generate
|
|
101
|
-
--manifest routesync.manifest.json \
|
|
102
|
-
--output src/api \
|
|
103
|
-
--next-actions \
|
|
104
|
-
--zod
|
|
131
|
+
npx routesync generate --manifest routesync.manifest.json --output src/api --next-actions --zod
|
|
105
132
|
```
|
|
106
133
|
|
|
107
134
|
| Option | Default | Description |
|
|
108
135
|
|---|---|---|
|
|
109
|
-
| `--manifest` | `routesync.manifest.json` | Path to manifest from step
|
|
136
|
+
| `--manifest` | `routesync.manifest.json` | Path to manifest from step 2 |
|
|
110
137
|
| `--output` | `src/api` | Output folder |
|
|
111
138
|
| `--next-actions` | off | Generate `actions.ts` (Next.js Server Actions) |
|
|
112
139
|
| `--zod` | off | Generate `schemas.ts` (Zod validation) |
|
|
113
140
|
| `--no-hooks` | off | Skip generating `hooks.ts` |
|
|
114
141
|
| `--msw` | off | Generate MSW mock handlers |
|
|
115
142
|
|
|
116
|
-
> **Windows PowerShell note:** Do not use backslash `\` for line continuation
|
|
143
|
+
> **Windows PowerShell note:** Do not use backslash `\` for line continuation. Run the command on a single line:
|
|
117
144
|
>
|
|
118
145
|
> ```powershell
|
|
119
146
|
> npx routesync generate --manifest routesync.manifest.json --output src/api --next-actions --zod
|
|
@@ -133,7 +160,7 @@ src/api/
|
|
|
133
160
|
└── models.ts ← Raw Eloquent model interfaces (when --models used)
|
|
134
161
|
```
|
|
135
162
|
|
|
136
|
-
###
|
|
163
|
+
### 4. Initialize the client
|
|
137
164
|
|
|
138
165
|
Call `createClient` once at app startup (e.g. in your layout or provider):
|
|
139
166
|
|
|
@@ -147,7 +174,7 @@ createClient({
|
|
|
147
174
|
})
|
|
148
175
|
```
|
|
149
176
|
|
|
150
|
-
###
|
|
177
|
+
### 5. Use in components
|
|
151
178
|
|
|
152
179
|
```tsx
|
|
153
180
|
import { useApiQuery, useApiMutation } from 'routesync/react'
|
|
@@ -181,10 +208,9 @@ function AddToCart({ produkItemId }: { produkItemId: string }) {
|
|
|
181
208
|
}
|
|
182
209
|
```
|
|
183
210
|
|
|
184
|
-
###
|
|
211
|
+
### 6. Use Server Actions (Next.js)
|
|
185
212
|
|
|
186
213
|
```ts
|
|
187
|
-
// In a Server Component or form action
|
|
188
214
|
import { produkGetAction, cartPostItemsAction } from '@/api/actions'
|
|
189
215
|
|
|
190
216
|
// GET — no params needed
|
|
@@ -216,14 +242,14 @@ Stage 1: PHP 8 #[RouteSyncResponse] attribute on method ← most explicit
|
|
|
216
242
|
Stage 2: return new UserResource($user) in method body
|
|
217
243
|
│ ├─ Stage 2a: #[RouteSyncResponse] on Resource class
|
|
218
244
|
│ ├─ Stage 2b: @mixin \App\Models\User docblock
|
|
219
|
-
│ ├─ Stage 2c: __construct(User $user) type hint
|
|
220
|
-
│ ├─ Stage 2d: @var User $resource docblock
|
|
221
|
-
│ ├─ Stage 2e: Strip "Resource" suffix → App\Models\*
|
|
222
|
-
│ └─ Stage 2f: toArray() keys vs DB column matching
|
|
245
|
+
│ ├─ Stage 2c: __construct(User $user) type hint
|
|
246
|
+
│ ├─ Stage 2d: @var User $resource docblock
|
|
247
|
+
│ ├─ Stage 2e: Strip "Resource" suffix → App\Models\*
|
|
248
|
+
│ └─ Stage 2f: toArray() keys vs DB column matching
|
|
223
249
|
│
|
|
224
250
|
▼
|
|
225
251
|
Stage 3: response()->json([...]) inline array
|
|
226
|
-
keys matched against DB columns (min score 2)
|
|
252
|
+
keys matched against DB columns (min score 2)
|
|
227
253
|
│
|
|
228
254
|
▼
|
|
229
255
|
response: unknown ← annotate manually if all stages fail
|
|
@@ -247,9 +273,23 @@ public function index(): JsonResponse
|
|
|
247
273
|
}
|
|
248
274
|
```
|
|
249
275
|
|
|
250
|
-
###
|
|
276
|
+
### Auto-annotate with CLI (recommended)
|
|
251
277
|
|
|
252
|
-
|
|
278
|
+
Instead of adding `#[Response]` by hand, let the CLI do it:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# Preview first
|
|
282
|
+
npx routesync annotate --input routes/api.php --dry-run
|
|
283
|
+
|
|
284
|
+
# Apply
|
|
285
|
+
npx routesync annotate --input routes/api.php
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
This scans every controller method, detects which Resource it returns, resolves the model, and injects `#[Response(Model::class)]` automatically. See [Auto-annotate controllers](#1-auto-annotate-controllers-one-time-setup) for details.
|
|
289
|
+
|
|
290
|
+
### Manual annotation with PHP 8 Attribute
|
|
291
|
+
|
|
292
|
+
Use `#[RouteSyncResponse]` when auto-inference fails — for example when the Resource name doesn't match the model, or the response is a DTO/custom shape.
|
|
253
293
|
|
|
254
294
|
**Step 1 — Create the attribute class** (`app/Attributes/RouteSyncResponse.php`):
|
|
255
295
|
|
|
@@ -278,17 +318,14 @@ use App\Models\User;
|
|
|
278
318
|
|
|
279
319
|
class AuthController extends Controller
|
|
280
320
|
{
|
|
281
|
-
// Single object response
|
|
282
321
|
#[RouteSyncResponse(model: User::class)]
|
|
283
322
|
public function register(RegisterRequest $request): JsonResponse
|
|
284
323
|
{
|
|
285
324
|
$user = User::create($request->validated());
|
|
286
325
|
$token = $user->createToken('auth')->plainTextToken;
|
|
287
|
-
|
|
288
326
|
return response()->json(['token' => $token, 'user' => new UserResource($user)]);
|
|
289
327
|
}
|
|
290
328
|
|
|
291
|
-
// Collection response
|
|
292
329
|
#[RouteSyncResponse(model: User::class, collection: true)]
|
|
293
330
|
public function index(): JsonResponse
|
|
294
331
|
{
|
|
@@ -308,11 +345,7 @@ class UserResource extends JsonResource
|
|
|
308
345
|
{
|
|
309
346
|
public function toArray($request): array
|
|
310
347
|
{
|
|
311
|
-
return [
|
|
312
|
-
'id' => $this->id,
|
|
313
|
-
'name' => $this->name,
|
|
314
|
-
'email' => $this->email,
|
|
315
|
-
];
|
|
348
|
+
return ['id' => $this->id, 'name' => $this->name, 'email' => $this->email];
|
|
316
349
|
}
|
|
317
350
|
}
|
|
318
351
|
```
|
|
@@ -356,13 +389,10 @@ import { defineApi, endpoint, resource } from 'routesync'
|
|
|
356
389
|
createClient({ baseURL: 'https://api.myapp.com/api' })
|
|
357
390
|
|
|
358
391
|
export const api = defineApi({
|
|
359
|
-
// Basic endpoint
|
|
360
392
|
auth: {
|
|
361
393
|
login: endpoint<{ token: string }>({ method: 'POST', path: '/login' }),
|
|
362
394
|
logout: endpoint({ method: 'POST', path: '/logout', auth: true }),
|
|
363
395
|
},
|
|
364
|
-
|
|
365
|
-
// With path params
|
|
366
396
|
produk: {
|
|
367
397
|
list: endpoint<ProdukItem[]>({ method: 'GET', path: '/produk' }),
|
|
368
398
|
detail: endpoint<ProdukItem, { id: string }>({ method: 'GET', path: '/produk/:id' }),
|
|
@@ -370,8 +400,6 @@ export const api = defineApi({
|
|
|
370
400
|
method: 'POST', path: '/produk', auth: true
|
|
371
401
|
}),
|
|
372
402
|
},
|
|
373
|
-
|
|
374
|
-
// resource() — shared auth/headers for a group
|
|
375
403
|
cart: resource({
|
|
376
404
|
auth: true,
|
|
377
405
|
endpoints: {
|
|
@@ -420,7 +448,7 @@ import { api } from '@/api/api'
|
|
|
420
448
|
// GET
|
|
421
449
|
const { data, isLoading } = useApiQuery(api.orders.get)
|
|
422
450
|
|
|
423
|
-
// GET with params
|
|
451
|
+
// GET with params
|
|
424
452
|
const { data } = useApiQuery(api.orders.getId, { params: { id: '1' } })
|
|
425
453
|
|
|
426
454
|
// Mutation
|
|
@@ -433,8 +461,7 @@ mutation.mutate({ body: { produk_item_id: '5', qty: 1 } })
|
|
|
433
461
|
```ts
|
|
434
462
|
import { generateHooks } from 'routesync'
|
|
435
463
|
|
|
436
|
-
const
|
|
437
|
-
const { useOrdersGet, useCartPostItems } = hooks
|
|
464
|
+
const { useOrdersGet, useCartPostItems } = generateHooks(api)
|
|
438
465
|
// GET/DELETE → useQuery, everything else → useMutation
|
|
439
466
|
```
|
|
440
467
|
|
|
@@ -443,8 +470,7 @@ const { useOrdersGet, useCartPostItems } = hooks
|
|
|
443
470
|
```ts
|
|
444
471
|
import { createHooks } from 'routesync/react'
|
|
445
472
|
|
|
446
|
-
const
|
|
447
|
-
const { usePostItems, usePatchItemsProdukItemId } = cartHooks
|
|
473
|
+
const { usePostItems, usePatchItemsProdukItemId } = createHooks(api.cart)
|
|
448
474
|
```
|
|
449
475
|
|
|
450
476
|
---
|
|
@@ -470,6 +496,15 @@ When using `--zod` with `routesync generate`, `schemas.ts` is generated from you
|
|
|
470
496
|
## CLI Reference
|
|
471
497
|
|
|
472
498
|
```bash
|
|
499
|
+
# Auto-inject #[Response] attributes into controller methods
|
|
500
|
+
npx routesync annotate --input routes/api.php
|
|
501
|
+
|
|
502
|
+
# Preview without writing files
|
|
503
|
+
npx routesync annotate --input routes/api.php --dry-run
|
|
504
|
+
|
|
505
|
+
# Re-annotate already-annotated methods
|
|
506
|
+
npx routesync annotate --input routes/api.php --force
|
|
507
|
+
|
|
473
508
|
# Scan Laravel routes only
|
|
474
509
|
npx routesync scan --input routes/api.php
|
|
475
510
|
|
|
@@ -492,16 +527,28 @@ npx routesync watch --input routes/api.php --output src/api
|
|
|
492
527
|
|
|
493
528
|
```
|
|
494
529
|
routes/api.php + app/Models/
|
|
495
|
-
|
|
530
|
+
│
|
|
531
|
+
▼
|
|
532
|
+
npx routesync annotate ← inject #[Response] into controllers
|
|
533
|
+
│
|
|
534
|
+
▼
|
|
535
|
+
npx routesync scan --models ← read routes + DB columns → manifest
|
|
536
|
+
│
|
|
537
|
+
▼
|
|
496
538
|
routesync.manifest.json
|
|
497
|
-
|
|
539
|
+
│
|
|
540
|
+
▼
|
|
541
|
+
npx routesync generate ← generate SDK from manifest
|
|
542
|
+
│
|
|
543
|
+
▼
|
|
498
544
|
src/api/
|
|
499
|
-
├── api.ts ← defineApi + endpoints
|
|
545
|
+
├── api.ts ← defineApi + endpoints + Contract types
|
|
500
546
|
├── types.ts ← interfaces from DB columns
|
|
501
547
|
├── hooks.ts ← TanStack Query hooks
|
|
502
548
|
├── actions.ts ← Next.js Server Actions
|
|
503
549
|
└── schemas.ts ← Zod schemas
|
|
504
|
-
|
|
550
|
+
│
|
|
551
|
+
▼
|
|
505
552
|
React / Vue / Next.js
|
|
506
553
|
```
|
|
507
554
|
|
|
@@ -512,7 +559,7 @@ The CLI parses your route file via PHP reflection (using Laravel's own bootstrap
|
|
|
512
559
|
## Requirements
|
|
513
560
|
|
|
514
561
|
- Node.js >= 20
|
|
515
|
-
- PHP available in PATH (for `scan --models`)
|
|
562
|
+
- PHP available in PATH (for `scan --models` and `annotate`)
|
|
516
563
|
- Laravel project with database accessible (for `scan --models`)
|
|
517
564
|
|
|
518
565
|
## License
|