svelte-reflector 1.2.0 → 1.2.2

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 (2) hide show
  1. package/README.md +395 -518
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,518 +1,395 @@
1
- # Svelte Reflector
2
-
3
- **Turn your OpenAPI into a first-class Svelte 5 DX.**
4
-
5
- Svelte Reflector is a **developer-experience-first code generator** that converts OpenAPI specs into fully typed, reactive Svelte 5 modules — ready for production, forms included.
6
-
7
- [![npm version](https://img.shields.io/npm/v/svelte-reflector.svg)](https://www.npmjs.com/package/svelte-reflector)
8
- [![npm downloads](https://img.shields.io/npm/dm/svelte-reflector.svg)](https://www.npmjs.com/package/svelte-reflector)
9
- [![npm total downloads](https://img.shields.io/npm/dt/svelte-reflector.svg)](https://www.npmjs.com/package/svelte-reflector)
10
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.9+-blue.svg)](https://www.typescriptlang.org/)
11
- [![Svelte](https://img.shields.io/badge/Svelte-5+-orange.svg)](https://svelte.dev/)
12
-
13
- A TypeScript code generator that creates type-safe Svelte 5 modules from OpenAPI specifications. It transforms your backend's OpenAPI/Swagger docs into fully-typed Svelte stores with built-in form handling, validation, and API integration.
14
-
15
- ## Features
16
-
17
- - **Automatic Type Generation** - Generates TypeScript interfaces and classes from OpenAPI schemas
18
- - **Svelte 5 Runes Integration** - Uses `$state` and `$derived` for reactive state management
19
- - **Form Handling** - Auto-generates form schemas with validation support
20
- - **Type-Safe API Calls** - Full TypeScript support for all API operations
21
- - **Query Parameter Sync** - `QueryBuilder` and `EnumQueryBuilder` keep state synced with URL searchParams
22
- - **Enum Support** - Auto-generates enum types and array enum query builders
23
- - **OpenAPI/Swagger Compatible** - Works with any backend that exposes OpenAPI specs
24
- - **Development Mode** - Smart regeneration based on environment
25
- - **Validation Ready** - Built-in support for custom field validators
26
- - **Vite Plugin** - Can be used as a Vite plugin for automatic generation on build
27
-
28
- ## Installation
29
-
30
- ```bash
31
- npm install svelte-reflector
32
- # or
33
- yarn add svelte-reflector
34
- # or
35
- pnpm add svelte-reflector
36
- ```
37
-
38
- ## Quick Start
39
-
40
- ### 1. Configure Environment Variables
41
-
42
- Create a `.env` file in your project root:
43
-
44
- ```env
45
- # Required - Your backend URL
46
- BACKEND_URL=https://api.example.com/
47
- # or
48
- PUBLIC_BACKEND=https://api.example.com/
49
-
50
- # Optional - Environment (defaults to PROD)
51
- ENVIRONMENT=DEV
52
- # or
53
- VITE_ENVIRONMENT=DEV
54
- ```
55
-
56
- ### 2. Create Reflector Config (Optional)
57
-
58
- Create a `src/reflector.config.ts` to define custom validators:
59
-
60
- ```typescript
61
- export const validators = [
62
- {
63
- fields: ["email", "userEmail"],
64
- validator: "validateEmail",
65
- },
66
- {
67
- fields: ["phone", "mobile"],
68
- validator: "validatePhone",
69
- },
70
- {
71
- fields: ["cpf", "cnpj"],
72
- validator: "validateDocument",
73
- },
74
- ];
75
- ```
76
-
77
- ### 3. Run the Generator
78
-
79
- ```bash
80
- # Manual generation (recommended for DEV environment)
81
- npx reflect
82
-
83
- # Or programmatically as a Vite plugin
84
- import { reflector } from "svelte-reflector";
85
- await reflector(true); // true = force generation
86
- ```
87
-
88
- ### 4. Use Generated Modules
89
-
90
- The generator creates files in `src/reflector/`:
91
-
92
- ```typescript
93
- import { UserModule } from "$reflector/controllers/user/user.module.svelte";
94
- import type { User } from "$reflector/schemas.svelte";
95
-
96
- // Create module instance
97
- const userModule = new UserModule();
98
-
99
- // Access reactive state
100
- console.log(userModule.loading); // $state<boolean>
101
- console.log(userModule.list); // $state<User[]>
102
-
103
- // Call API methods
104
- await userModule.listAll({
105
- behavior: {
106
- onSuccess: (response) => console.log(response),
107
- onError: (error) => console.error(error),
108
- },
109
- });
110
-
111
- // Work with forms
112
- const userForm = userModule.forms.createUser;
113
- userForm.name.value = "John Doe";
114
- userForm.email.value = "john@example.com";
115
-
116
- // Submit form
117
- await userModule.createUser();
118
- ```
119
-
120
- ## Generated Structure
121
-
122
- ```
123
- src/reflector/
124
- ├── controllers/
125
- │ └── user/
126
- │ └── user.module.svelte.ts # API module with methods
127
- ├── schemas.svelte.ts # Generated schemas & types
128
- ├── reflector.svelte.ts # Core utilities (build, isFormValid, QueryBuilder, etc.)
129
- ├── fields.ts # Field name constants
130
- ├── enums.ts # Enum type definitions
131
- ├── mocked-params.svelte.ts # Mocked path parameters ($state)
132
- └── backup.json # Cached OpenAPI spec
133
- ```
134
-
135
- ## Generated Module API
136
-
137
- Each generated module provides:
138
-
139
- ### State Properties
140
-
141
- | Property | Type | Description |
142
- |----------|------|-------------|
143
- | `loading` | `$state<boolean>` | Request loading state |
144
- | `list` | `$state<T[]>` | List results (for list endpoints) |
145
- | `forms` | `$state<Record<string, T>>` | Form instances |
146
- | `querys` | `Querys` | Query parameter state (QueryBuilder instances) |
147
- | `headers` | `Headers` | Header state |
148
- | `paths` | `Paths` | Path parameter state |
149
-
150
- ### Methods
151
-
152
- ```typescript
153
- // List all items (GET with page parameter)
154
- async listAll(params?: { behavior?: Behavior }): Promise<T[]>
155
-
156
- // Get single entity (GET without page parameter)
157
- async get(params?: { behavior?: Behavior }): Promise<T>
158
-
159
- // Create/Update (POST/PUT/PATCH)
160
- async create(params?: { behavior?: Behavior }): Promise<T>
161
- async update(params?: { behavior?: Behavior }): Promise<T>
162
-
163
- // Delete (DELETE)
164
- async delete(params?: { behavior?: Behavior }): Promise<void>
165
-
166
- // Reset all state
167
- reset(): void
168
-
169
- // Clear forms
170
- clearForms(): void
171
- ```
172
-
173
- ### QueryBuilder
174
-
175
- Query parameters are wrapped in `QueryBuilder` instances that sync with URL searchParams:
176
-
177
- ```typescript
178
- // Single value query parameter
179
- const querys = module.querys;
180
- querys.status.update("active"); // Updates URL searchParam and internal state
181
-
182
- // Array enum query parameter
183
- const enumQuery = module.querys.roles; // EnumQueryBuilder<RoleType>
184
- enumQuery.selected = "admin";
185
- enumQuery.add(); // Adds to URL searchParams
186
- enumQuery.remove(0); // Removes from URL searchParams
187
- enumQuery.values; // $derived from URL - always in sync
188
- ```
189
-
190
- ## Configuration
191
-
192
- ### Environment Variables
193
-
194
- | Variable | Required | Description |
195
- |----------|----------|-------------|
196
- | `BACKEND_URL` | Yes | Backend API URL |
197
- | `PUBLIC_BACKEND` | Yes | Alternative to BACKEND_URL |
198
- | `ENVIRONMENT` | No | DEV/PROD (defaults to PROD) |
199
- | `VITE_ENVIRONMENT` | No | Vite-specific env var |
200
- | `NODE_ENV` | No | Node environment |
201
-
202
- ### Behavior Pattern
203
-
204
- All API methods accept a `Behavior` object for callbacks:
205
-
206
- ```typescript
207
- interface Behavior<TSuccess, TError> {
208
- onSuccess?: (value: TSuccess) => Promise<void> | void;
209
- onError?: (error: TError) => Promise<void> | void;
210
- }
211
-
212
- // Usage
213
- await userModule.createUser({
214
- behavior: {
215
- onSuccess: (user) => console.log("Created:", user),
216
- onError: (err) => console.error("Failed:", err),
217
- },
218
- });
219
- ```
220
-
221
- ### Form Validation
222
-
223
- Forms use `BuildedInput` class with validation:
224
-
225
- ```typescript
226
- class BuildedInput<T> {
227
- value: T; // Current value ($state)
228
- display: T; // Display value ($state)
229
- required: boolean; // Is field required
230
- placeholder: T; // Placeholder/example value
231
- readonly kind: 'builded';
232
- validator?: (v: T) => string | null; // Validation function
233
- validate(): string | null; // Run validation
234
- }
235
-
236
- // Check if all form fields are valid
237
- import { isFormValid } from "$reflector/reflector.svelte";
238
-
239
- if (isFormValid(userModule.forms.createUser)) {
240
- await userModule.createUser();
241
- }
242
- ```
243
-
244
- ## TypeScript Configuration
245
-
246
- Add path aliases to your `tsconfig.json`:
247
-
248
- ```json
249
- {
250
- "compilerOptions": {
251
- "paths": {
252
- "$reflector/*": ["./src/reflector/*"],
253
- "$lib/*": ["./src/lib/*"]
254
- }
255
- }
256
- }
257
- ```
258
-
259
- For Vite projects, also update `vite.config.ts`:
260
-
261
- ```typescript
262
- export default defineConfig({
263
- resolve: {
264
- alias: {
265
- $reflector: path.resolve("./src/reflector"),
266
- $lib: path.resolve("./src/lib"),
267
- },
268
- },
269
- });
270
- ```
271
-
272
- ## Workflow
273
-
274
- ### Development Mode
275
-
276
- In `ENVIRONMENT=DEV`:
277
- - Schemas are **NOT** auto-regenerated on build
278
- - Use `npx reflect` to manually regenerate
279
- - Faster builds, manual control
280
-
281
- ### Production Mode
282
-
283
- In `ENVIRONMENT=PROD`:
284
- - Schemas are auto-regenerated on each build
285
- - Fresh types from latest OpenAPI spec
286
- - Fallback to `backup.json` if backend is unavailable
287
-
288
- ## Advanced Usage
289
-
290
- ### Custom Validators
291
-
292
- Define validators in `src/reflector.config.ts`:
293
-
294
- ```typescript
295
- export const validators = [
296
- {
297
- fields: ["email", "userEmail", "contactEmail"],
298
- validator: "validateEmail",
299
- },
300
- {
301
- fields: ["phone", "mobile", "whatsapp"],
302
- validator: "validatePhone",
303
- },
304
- {
305
- fields: ["cpf", "cnpj", "document"],
306
- validator: "validateDocument",
307
- },
308
- {
309
- fields: ["password", "newPassword"],
310
- validator: "validatePassword",
311
- },
312
- {
313
- fields: ["birthDate", "startDate", "endDate"],
314
- validator: "validateDate",
315
- },
316
- {
317
- fields: ["zipcode", "cep"],
318
- validator: "validateZipcode",
319
- },
320
- {
321
- fields: ["url", "website", "avatarUrl"],
322
- validator: "validateUrl",
323
- },
324
- ];
325
- ```
326
-
327
- Then implement in your app at `$lib/sanitizers/validateFormats.ts`:
328
-
329
- ```typescript
330
- // Email validation
331
- export function validateEmail(value: string): string | null {
332
- if (!value) return null; // Let required handle empty
333
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
334
- return emailRegex.test(value) ? null : "Invalid email format";
335
- }
336
-
337
- // Phone validation
338
- export function validatePhone(value: string): string | null {
339
- if (!value) return null;
340
- const phoneRegex = /^(\+?55\s?)?(\(?\d{2}\)?\s?)?(\d{4,5}-?\d{4})$/;
341
- return phoneRegex.test(value) ? null : "Invalid phone number";
342
- }
343
-
344
- // CPF/CNPJ validation (Brazilian documents)
345
- export function validateDocument(value: string): string | null {
346
- if (!value) return null;
347
- const cleaned = value.replace(/\D/g, '');
348
-
349
- if (cleaned.length === 11) {
350
- return validateCPF(cleaned) ? null : "Invalid CPF";
351
- } else if (cleaned.length === 14) {
352
- return validateCNPJ(cleaned) ? null : "Invalid CNPJ";
353
- }
354
- return "Invalid document format";
355
- }
356
-
357
- function validateCPF(cpf: string): boolean {
358
- if (/^(\d)\1{10}$/.test(cpf)) return false;
359
-
360
- let sum = 0;
361
- for (let i = 0; i < 9; i++) sum += parseInt(cpf[i]) * (10 - i);
362
- let rev = 11 - (sum % 11);
363
- if (rev === 10 || rev === 11) rev = 0;
364
- if (rev !== parseInt(cpf[9])) return false;
365
-
366
- sum = 0;
367
- for (let i = 0; i < 10; i++) sum += parseInt(cpf[i]) * (11 - i);
368
- rev = 11 - (sum % 11);
369
- if (rev === 10 || rev === 11) rev = 0;
370
- return rev === parseInt(cpf[10]);
371
- }
372
-
373
- function validateCNPJ(cnpj: string): boolean {
374
- if (/^(\d)\1{13}$/.test(cnpj)) return false;
375
-
376
- const weights1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
377
- const weights2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
378
-
379
- let sum = 0;
380
- for (let i = 0; i < 12; i++) sum += parseInt(cnpj[i]) * weights1[i];
381
- let rev = sum % 11 < 2 ? 0 : 11 - (sum % 11);
382
- if (rev !== parseInt(cnpj[12])) return false;
383
-
384
- sum = 0;
385
- for (let i = 0; i < 13; i++) sum += parseInt(cnpj[i]) * weights2[i];
386
- rev = sum % 11 < 2 ? 0 : 11 - (sum % 11);
387
- return rev === parseInt(cnpj[13]);
388
- }
389
-
390
- // Password strength validation
391
- export function validatePassword(value: string): string | null {
392
- if (!value) return null;
393
- if (value.length < 8) return "Password must be at least 8 characters";
394
- if (!/[A-Z]/.test(value)) return "Password must contain an uppercase letter";
395
- if (!/[a-z]/.test(value)) return "Password must contain a lowercase letter";
396
- if (!/[0-9]/.test(value)) return "Password must contain a number";
397
- if (!/[!@#$%^&*]/.test(value)) return "Password must contain a special character";
398
- return null;
399
- }
400
-
401
- // Date validation
402
- export function validateDate(value: string): string | null {
403
- if (!value) return null;
404
- const date = new Date(value);
405
- if (isNaN(date.getTime())) return "Invalid date";
406
- if (date > new Date()) return "Date cannot be in the future";
407
- return null;
408
- }
409
-
410
- // Brazilian ZIP code (CEP) validation
411
- export function validateZipcode(value: string): string | null {
412
- if (!value) return null;
413
- const cepRegex = /^\d{5}-?\d{3}$/;
414
- return cepRegex.test(value) ? null : "Invalid ZIP code format";
415
- }
416
-
417
- // URL validation
418
- export function validateUrl(value: string): string | null {
419
- if (!value) return null;
420
- try {
421
- new URL(value);
422
- return null;
423
- } catch {
424
- return "Invalid URL format";
425
- }
426
- }
427
-
428
- // Min/max length validator factory
429
- export function minLength(min: number) {
430
- return (value: string): string | null => {
431
- if (!value) return null;
432
- return value.length >= min ? null : `Must be at least ${min} characters`;
433
- };
434
- }
435
-
436
- export function maxLength(max: number) {
437
- return (value: string): string | null => {
438
- if (!value) return null;
439
- return value.length <= max ? null : `Must be at most ${max} characters`;
440
- };
441
- }
442
-
443
- // Number range validator factory
444
- export function numberRange(min: number, max: number) {
445
- return (value: number): string | null => {
446
- if (value === null || value === undefined) return null;
447
- return value >= min && value <= max ? null : `Must be between ${min} and ${max}`;
448
- };
449
- }
450
-
451
- // Required field validator
452
- export function required(value: string | number | boolean | null): string | null {
453
- if (value === null || value === undefined || value === '') {
454
- return "This field is required";
455
- }
456
- return null;
457
- }
458
- ```
459
-
460
- ### Manual Schema Access
461
-
462
- ```typescript
463
- import { User } from "$reflector/schemas.svelte";
464
-
465
- // Create instance
466
- const user = new User({ name: "John", email: "john@example.com" });
467
-
468
- // Get data bundle
469
- const data = user.bundle(); // { name: "John", email: "john@example.com" }
470
- ```
471
-
472
- ### Batch Query Updates
473
-
474
- ```typescript
475
- import { setQueryGroup } from "$reflector/reflector.svelte";
476
-
477
- // Update multiple query params at once
478
- setQueryGroup([
479
- { key: "page", value: 1 },
480
- { key: "status", value: "active" },
481
- { key: "roles", value: ["admin", "editor"] }, // Array params supported
482
- ]);
483
- ```
484
-
485
- ## Troubleshooting
486
-
487
- ### "BACKEND_URL vazio" Error
488
-
489
- Ensure you have set `BACKEND_URL` or `PUBLIC_BACKEND` in your `.env` file.
490
-
491
- ### Schemas Not Updating
492
-
493
- In DEV mode, run `npx reflect` manually. Check that your backend's OpenAPI spec is accessible at `{BACKEND_URL}openapi.json`.
494
-
495
- ### Type Errors After Generation
496
-
497
- 1. Restart your TypeScript language server
498
- 2. Check path aliases in `tsconfig.json`
499
- 3. Ensure `$reflector/*` alias is configured
500
-
501
- ## License
502
-
503
- MIT License - see [LICENSE](LICENSE) for details.
504
-
505
- ## Contributing
506
-
507
- Contributions are welcome! Please feel free to submit a Pull Request.
508
-
509
- ## Links
510
-
511
- - [npm](https://www.npmjs.com/package/svelte-reflector)
512
- - [GitHub](https://github.com/aleleppy/reflector)
513
- - [Svelte](https://svelte.dev/)
514
- - [OpenAPI Specification](https://swagger.io/specification/)
515
-
516
- ---
517
-
518
- Built with by the Pináculo Digital team.
1
+ # Svelte Reflector
2
+
3
+ **Turn your OpenAPI into a first-class Svelte 5 DX.**
4
+
5
+ Svelte Reflector is a **developer-experience-first code generator** that converts OpenAPI specs into fully typed, reactive Svelte 5 modules — ready for production, forms included.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/svelte-reflector.svg)](https://www.npmjs.com/package/svelte-reflector)
8
+ [![npm downloads](https://img.shields.io/npm/dm/svelte-reflector.svg)](https://www.npmjs.com/package/svelte-reflector)
9
+ [![npm total downloads](https://img.shields.io/npm/dt/svelte-reflector.svg)](https://www.npmjs.com/package/svelte-reflector)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9+-blue.svg)](https://www.typescriptlang.org/)
11
+ [![Svelte](https://img.shields.io/badge/Svelte-5+-orange.svg)](https://svelte.dev/)
12
+
13
+ ## Features
14
+
15
+ - **Automatic Type Generation** - Generates TypeScript interfaces and classes from OpenAPI schemas
16
+ - **Svelte 5 Runes Integration** - Uses `$state` and `$derived` for reactive state management
17
+ - **Abstract Modules** - Generated modules are abstract classes, ready to be extended with custom logic
18
+ - **Per-Module Schemas** - Each module gets its own schema file with only the types it needs (tree-shaking friendly)
19
+ - **Form Handling** - Auto-generates form schemas with `BuildedInput<T>` wrappers and validation support
20
+ - **Type-Safe API Calls** - Full TypeScript support for all API operations
21
+ - **Query Parameter Sync** - `QueryBuilder` and `EnumQueryBuilder` keep state synced with URL searchParams
22
+ - **Enum Support** - Auto-generates enum types and array enum query builders
23
+ - **OpenAPI/Swagger Compatible** - Works with any backend that exposes OpenAPI specs
24
+ - **Development Mode** - Smart regeneration based on environment
25
+ - **Validation Ready** - Built-in support for custom field validators
26
+ - **Vite Plugin** - Can be used as a Vite plugin for automatic generation on build
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ npm install svelte-reflector
32
+ # or
33
+ yarn add svelte-reflector
34
+ # or
35
+ pnpm add svelte-reflector
36
+ ```
37
+
38
+ > **Note:** `prettier` >= 3.0.0 is a required peer dependency. Make sure it's installed in your project.
39
+
40
+ ## Quick Start
41
+
42
+ ### 1. Configure Environment Variables
43
+
44
+ Create a `.env` file in your project root:
45
+
46
+ ```env
47
+ # Required - Your backend URL
48
+ BACKEND_URL=https://api.example.com/
49
+ # or
50
+ PUBLIC_BACKEND=https://api.example.com/
51
+
52
+ # Optional - Environment (defaults to PROD)
53
+ ENVIRONMENT=DEV
54
+ # or
55
+ VITE_ENVIRONMENT=DEV
56
+ ```
57
+
58
+ ### 2. Create Reflector Config (Optional)
59
+
60
+ Create a `src/reflector.config.ts` to define custom validators:
61
+
62
+ ```typescript
63
+ export const validators = [
64
+ {
65
+ fields: ["email", "userEmail"],
66
+ validator: "validateEmail",
67
+ },
68
+ {
69
+ fields: ["phone", "mobile"],
70
+ validator: "validatePhone",
71
+ },
72
+ ];
73
+ ```
74
+
75
+ Validators are resolved from `$lib/sanitizers/validateFormats` — you need to implement and export them in your project.
76
+
77
+ ### 3. Configure API Import Path (Optional)
78
+
79
+ Create a `reflector.json` in your project root to customize the API import path:
80
+
81
+ ```json
82
+ {
83
+ "api": "$lib/api"
84
+ }
85
+ ```
86
+
87
+ Defaults to `$lib/api` if not specified. This is the module that generated modules will import for making HTTP requests.
88
+
89
+ ### 4. Run the Generator
90
+
91
+ ```bash
92
+ # Manual generation
93
+ npx reflect
94
+
95
+ # Or programmatically as a Vite plugin
96
+ import { reflector } from "svelte-reflector";
97
+ await reflector(true); // true = force generation
98
+ ```
99
+
100
+ ### 5. Use Generated Modules
101
+
102
+ Generated modules are **abstract classes**. Extend them to add custom logic or simply to instantiate:
103
+
104
+ ```typescript
105
+ import { UserModule } from "$reflector/controllers/user/user.module.svelte";
106
+ import type { User } from "$reflector/controllers/user/user.schema.svelte";
107
+
108
+ // Extend the abstract module
109
+ class UserService extends UserModule {}
110
+
111
+ const userService = new UserService();
112
+
113
+ // Access reactive state
114
+ console.log(userService.loading); // $state<boolean>
115
+ console.log(userService.list); // $state<User[]>
116
+
117
+ // Call API methods
118
+ await userService.listAll({
119
+ behavior: {
120
+ onSuccess: (response) => console.log(response),
121
+ onError: (error) => console.error(error),
122
+ },
123
+ });
124
+
125
+ // Work with forms
126
+ const userForm = userService.forms.createUser;
127
+ userForm.name.value = "John Doe";
128
+ userForm.email.value = "john@example.com";
129
+
130
+ // Submit form
131
+ await userService.createUser();
132
+ ```
133
+
134
+ ## Generated Structure
135
+
136
+ ```
137
+ src/reflector/
138
+ ├── controllers/
139
+ │ └── user/
140
+ │ ├── user.module.svelte.ts # Abstract API module with methods
141
+ │ └── user.schema.svelte.ts # Schemas & types used by this module
142
+ ├── reflector.svelte.ts # Core utilities (build, isFormValid, QueryBuilder, etc.)
143
+ ├── fields.ts # Field name constants
144
+ ├── enums.ts # Enum type definitions
145
+ ├── mocked-params.svelte.ts # Mocked path parameters ($state)
146
+ └── backup.json # Cached OpenAPI spec
147
+ ```
148
+
149
+ Each module gets its own schema file (`*.schema.svelte.ts`) containing only the schemas it uses, with transitive dependencies automatically resolved.
150
+
151
+ ## Generated Module API
152
+
153
+ Each generated module is an **abstract class** that provides:
154
+
155
+ ### State Properties
156
+
157
+ | Property | Type | Description |
158
+ |----------|------|-------------|
159
+ | `loading` | `$state<boolean>` | Request loading state |
160
+ | `list` | `$state<T[]>` | List results (for list endpoints) |
161
+ | `forms` | `$state<Record<string, T>>` | Form instances |
162
+ | `querys` | `Querys` | Query parameter state (QueryBuilder instances) |
163
+ | `headers` | `Headers` | Header state |
164
+ | `paths` | `Paths` | Path parameter state |
165
+
166
+ ### Methods
167
+
168
+ ```typescript
169
+ // List all items (GET with page parameter)
170
+ async listAll(params?: { behavior?: Behavior }): Promise<T[]>
171
+
172
+ // Get single entity (GET without page parameter)
173
+ async get(params?: { behavior?: Behavior }): Promise<T>
174
+
175
+ // Create/Update (POST/PUT/PATCH)
176
+ async create(params?: { behavior?: Behavior }): Promise<T>
177
+ async update(params?: { behavior?: Behavior }): Promise<T>
178
+
179
+ // Delete (DELETE)
180
+ async delete(params?: { behavior?: Behavior }): Promise<void>
181
+
182
+ // Reset all state (protected)
183
+ protected reset(): void
184
+
185
+ // Clear forms (protected)
186
+ protected clearForms(): void
187
+ ```
188
+
189
+ > `reset()` and `clearForms()` are `protected` — override them in your subclass if you need custom reset behavior.
190
+
191
+ ### QueryBuilder
192
+
193
+ Query parameters are wrapped in `QueryBuilder` instances that sync with URL searchParams:
194
+
195
+ ```typescript
196
+ // Single value query parameter
197
+ const querys = module.querys;
198
+ querys.status.update("active"); // Updates URL searchParam and internal state
199
+
200
+ // Array enum query parameter
201
+ const enumQuery = module.querys.roles; // EnumQueryBuilder<RoleType>
202
+ enumQuery.selected = "admin";
203
+ enumQuery.add(); // Adds to URL searchParams
204
+ enumQuery.remove(0); // Removes from URL searchParams
205
+ enumQuery.values; // $derived from URL - always in sync
206
+ ```
207
+
208
+ ## Configuration
209
+
210
+ ### Environment Variables
211
+
212
+ | Variable | Required | Description |
213
+ |----------|----------|-------------|
214
+ | `BACKEND_URL` | Yes* | Backend API URL |
215
+ | `PUBLIC_BACKEND` | Yes* | Alternative to BACKEND_URL |
216
+ | `ENVIRONMENT` | No | DEV/PROD (defaults to PROD) |
217
+ | `VITE_ENVIRONMENT` | No | Vite-specific env var |
218
+ | `NODE_ENV` | No | Node environment |
219
+
220
+ \* At least one of `BACKEND_URL` or `PUBLIC_BACKEND` is required.
221
+
222
+ ### Behavior Pattern
223
+
224
+ All API methods accept a `Behavior` object for callbacks:
225
+
226
+ ```typescript
227
+ class Behavior<TSuccess, TError> {
228
+ onSuccess?: (value: TSuccess) => Promise<void> | void;
229
+ onError?: (error: TError) => Promise<void> | void;
230
+ }
231
+
232
+ // Usage
233
+ await userService.createUser({
234
+ behavior: {
235
+ onSuccess: (user) => console.log("Created:", user),
236
+ onError: (err) => console.error("Failed:", err),
237
+ },
238
+ });
239
+ ```
240
+
241
+ ### Form Validation
242
+
243
+ Forms use `BuildedInput` class with validation:
244
+
245
+ ```typescript
246
+ class BuildedInput<T> {
247
+ value: T; // Current value ($state)
248
+ display: T; // Display value ($state)
249
+ required: boolean; // Is field required
250
+ placeholder: T; // Placeholder/example value
251
+ readonly kind: 'builded';
252
+ validator?: (v: T) => string | null; // Validation function
253
+ validate(): string | null; // Run validation
254
+ }
255
+
256
+ // Check if all form fields are valid
257
+ import { isFormValid } from "$reflector/reflector.svelte";
258
+
259
+ if (isFormValid(userService.forms.createUser)) {
260
+ await userService.createUser();
261
+ }
262
+ ```
263
+
264
+ ## TypeScript Configuration
265
+
266
+ Add path aliases to your `tsconfig.json`:
267
+
268
+ ```json
269
+ {
270
+ "compilerOptions": {
271
+ "paths": {
272
+ "$reflector/*": ["./src/reflector/*"],
273
+ "$lib/*": ["./src/lib/*"]
274
+ }
275
+ }
276
+ }
277
+ ```
278
+
279
+ For Vite projects, also update `vite.config.ts`:
280
+
281
+ ```typescript
282
+ export default defineConfig({
283
+ resolve: {
284
+ alias: {
285
+ $reflector: path.resolve("./src/reflector"),
286
+ $lib: path.resolve("./src/lib"),
287
+ },
288
+ },
289
+ });
290
+ ```
291
+
292
+ ## Workflow
293
+
294
+ ### Development Mode
295
+
296
+ In `ENVIRONMENT=DEV`:
297
+ - Schemas are **NOT** auto-regenerated on build
298
+ - Use `npx reflect` to manually regenerate
299
+ - Faster builds, manual control
300
+
301
+ ### Production Mode
302
+
303
+ In `ENVIRONMENT=PROD`:
304
+ - Schemas are auto-regenerated on each build
305
+ - Fresh types from latest OpenAPI spec
306
+ - Fallback to `backup.json` if backend is unavailable
307
+
308
+ ## Advanced Usage
309
+
310
+ ### Extending Abstract Modules
311
+
312
+ Since modules are abstract, you can add custom logic:
313
+
314
+ ```typescript
315
+ import { UserModule } from "$reflector/controllers/user/user.module.svelte";
316
+
317
+ class UserService extends UserModule {
318
+ // Add custom computed state
319
+ get activeUsers() {
320
+ return this.list.filter(u => u.active);
321
+ }
322
+
323
+ // Override protected methods for custom behavior
324
+ protected override clearForms() {
325
+ super.clearForms();
326
+ // custom cleanup logic
327
+ }
328
+
329
+ // Add custom methods
330
+ async fetchAndFilter(status: string) {
331
+ this.querys.status.update(status);
332
+ await this.listAll();
333
+ }
334
+ }
335
+ ```
336
+
337
+ ### Manual Schema Access
338
+
339
+ ```typescript
340
+ import { User } from "$reflector/controllers/user/user.schema.svelte";
341
+
342
+ // Create instance
343
+ const user = new User({ name: "John", email: "john@example.com" });
344
+
345
+ // Get data bundle
346
+ const data = user.bundle(); // { name: "John", email: "john@example.com" }
347
+ ```
348
+
349
+ ### Batch Query Updates
350
+
351
+ ```typescript
352
+ import { setQueryGroup } from "$reflector/reflector.svelte";
353
+
354
+ // Update multiple query params at once
355
+ setQueryGroup([
356
+ { key: "page", value: 1 },
357
+ { key: "status", value: "active" },
358
+ { key: "roles", value: ["admin", "editor"] }, // Array params supported
359
+ ]);
360
+ ```
361
+
362
+ ## Troubleshooting
363
+
364
+ ### "BACKEND_URL vazio" Error
365
+
366
+ Ensure you have set `BACKEND_URL` or `PUBLIC_BACKEND` in your `.env` file.
367
+
368
+ ### Schemas Not Updating
369
+
370
+ In DEV mode, run `npx reflect` manually. Check that your backend's OpenAPI spec is accessible at `{BACKEND_URL}openapi.json`.
371
+
372
+ ### Type Errors After Generation
373
+
374
+ 1. Restart your TypeScript language server
375
+ 2. Check path aliases in `tsconfig.json`
376
+ 3. Ensure `$reflector/*` alias is configured
377
+
378
+ ## License
379
+
380
+ MIT License - see [LICENSE](LICENSE) for details.
381
+
382
+ ## Contributing
383
+
384
+ Contributions are welcome! Please feel free to submit a Pull Request.
385
+
386
+ ## Links
387
+
388
+ - [npm](https://www.npmjs.com/package/svelte-reflector)
389
+ - [GitHub](https://github.com/aleleppy/reflector)
390
+ - [Svelte](https://svelte.dev/)
391
+ - [OpenAPI Specification](https://swagger.io/specification/)
392
+
393
+ ---
394
+
395
+ Built with by the Pinaculo Digital team.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-reflector",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Reflects zod types from openAPI schemas",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",