@famgia/omnify-laravel 0.0.125 → 0.0.127
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/dist/{chunk-C3AGVZB4.js → chunk-IIA2I36W.js} +1 -1
- package/dist/chunk-IIA2I36W.js.map +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.js +1 -1
- package/package.json +4 -4
- package/stubs/ai-guides/README.md.stub +1 -0
- package/stubs/ai-guides/claude-omnify/schema-guide.md.stub +29 -0
- package/stubs/ai-guides/claude-rules/php-standards.md.stub +305 -0
- package/stubs/ai-guides/claude-rules/schema-yaml.md.stub +14 -0
- package/stubs/ai-guides/cursor/omnify-schema.mdc.stub +19 -0
- package/stubs/ai-guides/cursor/schema-create.mdc.stub +102 -0
- package/dist/chunk-C3AGVZB4.js.map +0 -1
package/dist/plugin.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@famgia/omnify-laravel",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.127",
|
|
4
4
|
"description": "Laravel migration and TypeScript type generator for omnify-schema",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@famgia/omnify-types": "0.0.
|
|
29
|
-
"@famgia/omnify-
|
|
30
|
-
"@famgia/omnify-
|
|
28
|
+
"@famgia/omnify-types": "0.0.116",
|
|
29
|
+
"@famgia/omnify-atlas": "0.0.112",
|
|
30
|
+
"@famgia/omnify-core": "0.0.118"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "tsup",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
├── rules/ # Must-follow rules (WHAT)
|
|
42
42
|
│ ├── security.md # Security rules
|
|
43
43
|
│ ├── performance.md # Performance & quality rules
|
|
44
|
+
│ ├── php-standards.md # PHP 8+ standards & best practices
|
|
44
45
|
│ └── naming.md # Naming conventions
|
|
45
46
|
│
|
|
46
47
|
├── guides/ # Implementation guides (REFERENCE)
|
|
@@ -67,6 +67,35 @@ propertyName:
|
|
|
67
67
|
fillable: false # Exclude from mass assignment
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
## ⚠️ Default Value Rules
|
|
71
|
+
|
|
72
|
+
**DB functions NOT allowed in default:**
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
# ❌ WRONG
|
|
76
|
+
failed_at:
|
|
77
|
+
type: Timestamp
|
|
78
|
+
default: CURRENT_TIMESTAMP # ERROR!
|
|
79
|
+
|
|
80
|
+
# ✅ CORRECT
|
|
81
|
+
failed_at:
|
|
82
|
+
type: Timestamp
|
|
83
|
+
useCurrent: true # = CURRENT_TIMESTAMP
|
|
84
|
+
|
|
85
|
+
updated_at:
|
|
86
|
+
type: Timestamp
|
|
87
|
+
useCurrent: true
|
|
88
|
+
useCurrentOnUpdate: true # ON UPDATE CURRENT_TIMESTAMP
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
| Type | Valid Default | Invalid |
|
|
92
|
+
|------|---------------|---------|
|
|
93
|
+
| Int | 0, 100, -1 | AUTO_INCREMENT, RAND() |
|
|
94
|
+
| Date | 2024-01-01 | CURRENT_DATE |
|
|
95
|
+
| Time | 14:30:00 | CURRENT_TIME |
|
|
96
|
+
| Timestamp | use `useCurrent` | CURRENT_TIMESTAMP |
|
|
97
|
+
| Uuid | static UUID | UUID() |
|
|
98
|
+
|
|
70
99
|
## Associations
|
|
71
100
|
|
|
72
101
|
```yaml
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "{{LARAVEL_ROOT}}app/**/*.php"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PHP Standards & Best Practices
|
|
7
|
+
|
|
8
|
+
> **PHP 8+ features** and coding standards for Laravel projects.
|
|
9
|
+
|
|
10
|
+
## 🔵 Strict Types
|
|
11
|
+
|
|
12
|
+
**Always declare strict types at the top of PHP files.**
|
|
13
|
+
|
|
14
|
+
```php
|
|
15
|
+
<?php
|
|
16
|
+
|
|
17
|
+
declare(strict_types=1);
|
|
18
|
+
|
|
19
|
+
namespace App\Services;
|
|
20
|
+
|
|
21
|
+
// ... class definition
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Rule | Description |
|
|
25
|
+
| ---- | ----------- |
|
|
26
|
+
| `declare(strict_types=1)` | Required in all PHP files |
|
|
27
|
+
| Place at very top | Before namespace declaration |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 🔵 Constructor Property Promotion (PHP 8.0+)
|
|
32
|
+
|
|
33
|
+
**Use constructor promotion for dependency injection.**
|
|
34
|
+
|
|
35
|
+
```php
|
|
36
|
+
// ❌ OLD STYLE: Verbose
|
|
37
|
+
class UserService
|
|
38
|
+
{
|
|
39
|
+
private UserRepository $repository;
|
|
40
|
+
private CacheManager $cache;
|
|
41
|
+
|
|
42
|
+
public function __construct(UserRepository $repository, CacheManager $cache)
|
|
43
|
+
{
|
|
44
|
+
$this->repository = $repository;
|
|
45
|
+
$this->cache = $cache;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ✅ PHP 8.0+: Constructor promotion
|
|
50
|
+
class UserService
|
|
51
|
+
{
|
|
52
|
+
public function __construct(
|
|
53
|
+
private readonly UserRepository $repository,
|
|
54
|
+
private readonly CacheManager $cache
|
|
55
|
+
) {}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
| Modifier | Usage |
|
|
60
|
+
| -------- | ----- |
|
|
61
|
+
| `private readonly` | Immutable dependencies (preferred) |
|
|
62
|
+
| `private` | Mutable internal state |
|
|
63
|
+
| `protected readonly` | For extension by subclasses |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 🔵 PHP 8+ Features
|
|
68
|
+
|
|
69
|
+
### Named Arguments
|
|
70
|
+
|
|
71
|
+
```php
|
|
72
|
+
// ✅ Clear intent
|
|
73
|
+
$this->checkEmailLockout(
|
|
74
|
+
email: $request->email,
|
|
75
|
+
checkOnly: true
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Use when function has many optional parameters
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Nullsafe Operator
|
|
82
|
+
|
|
83
|
+
```php
|
|
84
|
+
// ❌ OLD STYLE
|
|
85
|
+
$country = $user->address ? ($user->address->country ? $user->address->country->name : null) : null;
|
|
86
|
+
|
|
87
|
+
// ✅ PHP 8.0+: Nullsafe operator
|
|
88
|
+
$country = $user->address?->country?->name;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Union Types
|
|
92
|
+
|
|
93
|
+
```php
|
|
94
|
+
public function process(int|string $id): Response|RedirectResponse
|
|
95
|
+
{
|
|
96
|
+
// ...
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Match Expression
|
|
101
|
+
|
|
102
|
+
```php
|
|
103
|
+
// ❌ OLD: switch statement
|
|
104
|
+
switch ($status) {
|
|
105
|
+
case 'active': return 'Active';
|
|
106
|
+
case 'inactive': return 'Inactive';
|
|
107
|
+
default: return 'Unknown';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ✅ PHP 8.0+: match expression
|
|
111
|
+
return match($status) {
|
|
112
|
+
'active' => 'Active',
|
|
113
|
+
'inactive' => 'Inactive',
|
|
114
|
+
default => 'Unknown',
|
|
115
|
+
};
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 🔵 Constants Organization
|
|
121
|
+
|
|
122
|
+
**Use dedicated Constants classes instead of magic values.**
|
|
123
|
+
|
|
124
|
+
```php
|
|
125
|
+
// ❌ BAD: Magic strings scattered in code
|
|
126
|
+
if ($user->role === 'admin') { ... }
|
|
127
|
+
Cache::get('user:' . $id);
|
|
128
|
+
session()->get('2fa:user_id');
|
|
129
|
+
|
|
130
|
+
// ✅ GOOD: Constants in dedicated class
|
|
131
|
+
namespace App\Constants;
|
|
132
|
+
|
|
133
|
+
class TwoFactorConstants
|
|
134
|
+
{
|
|
135
|
+
public const ENABLED = true;
|
|
136
|
+
public const CODE_LENGTH = 6;
|
|
137
|
+
public const EXPIRY_MINUTES = 5;
|
|
138
|
+
|
|
139
|
+
// Session keys
|
|
140
|
+
public const SESSION_USER_ID = '2fa:user_id';
|
|
141
|
+
public const SESSION_EMAIL = '2fa:email';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Usage
|
|
145
|
+
use App\Constants\TwoFactorConstants;
|
|
146
|
+
|
|
147
|
+
if (TwoFactorConstants::ENABLED) {
|
|
148
|
+
$code = Str::random(TwoFactorConstants::CODE_LENGTH);
|
|
149
|
+
session()->put(TwoFactorConstants::SESSION_USER_ID, $user->id);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
| Location | Purpose |
|
|
154
|
+
| -------- | ------- |
|
|
155
|
+
| `app/Constants/` | Application-wide constants |
|
|
156
|
+
| Class constants | Domain-specific constants |
|
|
157
|
+
| `config/*.php` | Environment-dependent values |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 🔵 PHPDoc Standards
|
|
162
|
+
|
|
163
|
+
### Method Documentation
|
|
164
|
+
|
|
165
|
+
```php
|
|
166
|
+
/**
|
|
167
|
+
* Get user's authorization for a service.
|
|
168
|
+
*
|
|
169
|
+
* @param User $user The user to check
|
|
170
|
+
* @param Service $service The service being accessed
|
|
171
|
+
*
|
|
172
|
+
* @return array{
|
|
173
|
+
* organization_id: int,
|
|
174
|
+
* organization_slug: string,
|
|
175
|
+
* role: string,
|
|
176
|
+
* level: int
|
|
177
|
+
* }|null Returns null if user has no access
|
|
178
|
+
*
|
|
179
|
+
* @throws AuthorizationException When service is inactive
|
|
180
|
+
*/
|
|
181
|
+
public function getUserAuthorization(User $user, Service $service): ?array
|
|
182
|
+
{
|
|
183
|
+
// ...
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Array Shape Documentation
|
|
188
|
+
|
|
189
|
+
```php
|
|
190
|
+
/**
|
|
191
|
+
* @return array{
|
|
192
|
+
* id: int,
|
|
193
|
+
* name: string,
|
|
194
|
+
* email: string,
|
|
195
|
+
* roles: string[]
|
|
196
|
+
* }
|
|
197
|
+
*/
|
|
198
|
+
public function toArray(): array
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### When to Document
|
|
202
|
+
|
|
203
|
+
| Document | Don't Document |
|
|
204
|
+
| -------- | -------------- |
|
|
205
|
+
| Complex return types | Obvious getters/setters |
|
|
206
|
+
| Array shapes | Simple CRUD methods |
|
|
207
|
+
| Exception conditions | Self-explanatory code |
|
|
208
|
+
| Business logic | Framework conventions |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 🔵 Code Complexity Limits
|
|
213
|
+
|
|
214
|
+
### Method Guidelines
|
|
215
|
+
|
|
216
|
+
| Metric | Limit | Action if exceeded |
|
|
217
|
+
| ------ | ----- | ------------------ |
|
|
218
|
+
| Lines per method | Max 50 | Extract to helper/service |
|
|
219
|
+
| Parameters | Max 4 | Use DTO or config object |
|
|
220
|
+
| Cyclomatic complexity | Max 10 | Split into smaller methods |
|
|
221
|
+
| Nesting depth | Max 3 | Early return pattern |
|
|
222
|
+
|
|
223
|
+
### Class Guidelines
|
|
224
|
+
|
|
225
|
+
| Metric | Limit | Action if exceeded |
|
|
226
|
+
| ------ | ----- | ------------------ |
|
|
227
|
+
| Public methods | Max 10 | Split class (SRP violation) |
|
|
228
|
+
| Dependencies | Max 5 | Facade or aggregate service |
|
|
229
|
+
| Lines per class | Max 500 | Extract sub-classes |
|
|
230
|
+
|
|
231
|
+
### Early Return Pattern
|
|
232
|
+
|
|
233
|
+
```php
|
|
234
|
+
// ❌ BAD: Deep nesting
|
|
235
|
+
public function process($user)
|
|
236
|
+
{
|
|
237
|
+
if ($user) {
|
|
238
|
+
if ($user->isActive()) {
|
|
239
|
+
if ($user->hasPermission('edit')) {
|
|
240
|
+
// do something
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ✅ GOOD: Early returns
|
|
247
|
+
public function process($user)
|
|
248
|
+
{
|
|
249
|
+
if (!$user) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (!$user->isActive()) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (!$user->hasPermission('edit')) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// do something
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 🔵 Interface & Trait Naming
|
|
268
|
+
|
|
269
|
+
```php
|
|
270
|
+
// Interfaces: suffix with Interface
|
|
271
|
+
interface PaymentGatewayInterface
|
|
272
|
+
{
|
|
273
|
+
public function charge(int $amount): PaymentResult;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Traits: suffix with Trait (optional but recommended)
|
|
277
|
+
trait HasApiTokens
|
|
278
|
+
{
|
|
279
|
+
// ...
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Or descriptive name without suffix
|
|
283
|
+
trait Searchable
|
|
284
|
+
{
|
|
285
|
+
public function scopeSearch(Builder $query, string $term): Builder
|
|
286
|
+
{
|
|
287
|
+
// ...
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Quick Reference
|
|
295
|
+
|
|
296
|
+
| Category | Rule |
|
|
297
|
+
| -------- | ---- |
|
|
298
|
+
| **Strict** | `declare(strict_types=1)` at top |
|
|
299
|
+
| **Constructor** | Use property promotion with `readonly` |
|
|
300
|
+
| **Nullsafe** | `$obj?->prop?->value` instead of null checks |
|
|
301
|
+
| **Match** | Prefer `match` over `switch` |
|
|
302
|
+
| **Constants** | Use `App\Constants\*` classes |
|
|
303
|
+
| **Complexity** | Max 50 lines/method, 4 params, 10 complexity |
|
|
304
|
+
| **Nesting** | Max 3 levels, use early returns |
|
|
305
|
+
| **PHPDoc** | Document complex types and exceptions |
|
|
@@ -46,6 +46,20 @@ default: "'cloud'"
|
|
|
46
46
|
default: cloud
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
## ⚠️ CRITICAL: DB Functions NOT Allowed
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
# ❌ WRONG - DB functions
|
|
53
|
+
failed_at:
|
|
54
|
+
type: Timestamp
|
|
55
|
+
default: CURRENT_TIMESTAMP # ERROR!
|
|
56
|
+
|
|
57
|
+
# ✅ CORRECT - use useCurrent
|
|
58
|
+
failed_at:
|
|
59
|
+
type: Timestamp
|
|
60
|
+
useCurrent: true # = CURRENT_TIMESTAMP
|
|
61
|
+
```
|
|
62
|
+
|
|
49
63
|
## Property Types
|
|
50
64
|
|
|
51
65
|
| Type | SQL | TypeScript |
|
|
@@ -235,6 +235,25 @@ category:
|
|
|
235
235
|
relation: belongsTo # belongsTo, hasMany, hasOne, belongsToMany
|
|
236
236
|
```
|
|
237
237
|
|
|
238
|
+
### ⚠️ CRITICAL: DB Functions NOT Allowed in Default
|
|
239
|
+
|
|
240
|
+
```yaml
|
|
241
|
+
# ❌ WRONG - DB functions are NOT allowed
|
|
242
|
+
failed_at:
|
|
243
|
+
type: Timestamp
|
|
244
|
+
default: CURRENT_TIMESTAMP # ERROR!
|
|
245
|
+
|
|
246
|
+
# ✅ CORRECT - Use useCurrent option
|
|
247
|
+
failed_at:
|
|
248
|
+
type: Timestamp
|
|
249
|
+
useCurrent: true # Equivalent to CURRENT_TIMESTAMP
|
|
250
|
+
|
|
251
|
+
updated_at:
|
|
252
|
+
type: Timestamp
|
|
253
|
+
useCurrent: true
|
|
254
|
+
useCurrentOnUpdate: true # ON UPDATE CURRENT_TIMESTAMP
|
|
255
|
+
```
|
|
256
|
+
|
|
238
257
|
---
|
|
239
258
|
|
|
240
259
|
## Step 5: Run Migration 🗄️
|
|
@@ -235,6 +235,35 @@ category:
|
|
|
235
235
|
relation: belongsTo # belongsTo, hasMany, hasOne, belongsToMany
|
|
236
236
|
```
|
|
237
237
|
|
|
238
|
+
### ⚠️ CRITICAL: DB Functions NOT Allowed in Default
|
|
239
|
+
|
|
240
|
+
```yaml
|
|
241
|
+
# ❌ WRONG - DB functions are NOT allowed
|
|
242
|
+
failed_at:
|
|
243
|
+
type: Timestamp
|
|
244
|
+
default: CURRENT_TIMESTAMP # ERROR!
|
|
245
|
+
|
|
246
|
+
# ✅ CORRECT - Use useCurrent option
|
|
247
|
+
failed_at:
|
|
248
|
+
type: Timestamp
|
|
249
|
+
useCurrent: true # Equivalent to CURRENT_TIMESTAMP
|
|
250
|
+
|
|
251
|
+
updated_at:
|
|
252
|
+
type: Timestamp
|
|
253
|
+
useCurrent: true
|
|
254
|
+
useCurrentOnUpdate: true # ON UPDATE CURRENT_TIMESTAMP
|
|
255
|
+
|
|
256
|
+
# ❌ WRONG - UUID() function
|
|
257
|
+
external_id:
|
|
258
|
+
type: Uuid
|
|
259
|
+
default: UUID() # ERROR!
|
|
260
|
+
|
|
261
|
+
# ✅ CORRECT - Static value or nullable
|
|
262
|
+
external_id:
|
|
263
|
+
type: Uuid
|
|
264
|
+
nullable: true # Let application generate
|
|
265
|
+
```
|
|
266
|
+
|
|
238
267
|
---
|
|
239
268
|
|
|
240
269
|
## Step 5: Run Migration 🗄️
|
|
@@ -342,3 +371,76 @@ status:
|
|
|
342
371
|
status:
|
|
343
372
|
type: PostStatus # Reference enum schema
|
|
344
373
|
```
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## 🔌 Partial Schema (External Package Connection)
|
|
378
|
+
|
|
379
|
+
When referencing schemas from external packages that aren't loaded:
|
|
380
|
+
|
|
381
|
+
```yaml
|
|
382
|
+
# schemas/stubs/User.yaml
|
|
383
|
+
# Create stub to connect to external User schema
|
|
384
|
+
name: User
|
|
385
|
+
kind: partial
|
|
386
|
+
target: User # Same name = standalone schema
|
|
387
|
+
|
|
388
|
+
properties:
|
|
389
|
+
email:
|
|
390
|
+
type: Email
|
|
391
|
+
displayName:
|
|
392
|
+
ja: メール
|
|
393
|
+
en: Email
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Now you can use `User` in relationships:
|
|
397
|
+
|
|
398
|
+
```yaml
|
|
399
|
+
# schemas/blog/Post.yaml
|
|
400
|
+
author:
|
|
401
|
+
type: User # ✅ Works! User exists as partial
|
|
402
|
+
relation: belongsTo
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Extend Package Schema
|
|
406
|
+
|
|
407
|
+
```yaml
|
|
408
|
+
# schemas/extensions/User.yaml
|
|
409
|
+
name: User
|
|
410
|
+
kind: partial
|
|
411
|
+
target: User # Extend the User schema
|
|
412
|
+
|
|
413
|
+
properties:
|
|
414
|
+
# Add custom properties
|
|
415
|
+
avatar_url:
|
|
416
|
+
type: String
|
|
417
|
+
nullable: true
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## 📦 Register Schemas from Laravel Package
|
|
423
|
+
|
|
424
|
+
In your package's ServiceProvider:
|
|
425
|
+
|
|
426
|
+
```php
|
|
427
|
+
use App\Support\Omnify;
|
|
428
|
+
|
|
429
|
+
public function boot(): void
|
|
430
|
+
{
|
|
431
|
+
if (class_exists(Omnify::class)) {
|
|
432
|
+
Omnify::registerSchemaPath(
|
|
433
|
+
path: __DIR__ . '/../../schemas',
|
|
434
|
+
namespace: 'your-package'
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Export paths before generate:
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
php artisan omnify:sync
|
|
444
|
+
# Then
|
|
445
|
+
npx omnify generate
|
|
446
|
+
```
|