@currentjs/gen 0.2.2 → 0.3.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +240 -0
  2. package/README.md +256 -0
  3. package/dist/cli.js +26 -0
  4. package/dist/commands/createApp.js +2 -0
  5. package/dist/commands/generateAll.js +153 -29
  6. package/dist/commands/migrateCommit.d.ts +1 -0
  7. package/dist/commands/migrateCommit.js +201 -0
  8. package/dist/generators/controllerGenerator.d.ts +7 -0
  9. package/dist/generators/controllerGenerator.js +60 -29
  10. package/dist/generators/domainModelGenerator.d.ts +7 -0
  11. package/dist/generators/domainModelGenerator.js +57 -3
  12. package/dist/generators/serviceGenerator.d.ts +16 -1
  13. package/dist/generators/serviceGenerator.js +125 -12
  14. package/dist/generators/storeGenerator.d.ts +8 -0
  15. package/dist/generators/storeGenerator.js +133 -7
  16. package/dist/generators/templateGenerator.d.ts +19 -0
  17. package/dist/generators/templateGenerator.js +216 -11
  18. package/dist/generators/templates/appTemplates.d.ts +8 -7
  19. package/dist/generators/templates/appTemplates.js +11 -1572
  20. package/dist/generators/templates/data/appTsTemplate +39 -0
  21. package/dist/generators/templates/data/appYamlTemplate +4 -0
  22. package/dist/generators/templates/data/cursorRulesTemplate +671 -0
  23. package/dist/generators/templates/data/errorTemplate +28 -0
  24. package/dist/generators/templates/data/frontendScriptTemplate +739 -0
  25. package/dist/generators/templates/data/mainViewTemplate +16 -0
  26. package/dist/generators/templates/data/translationsTemplate +68 -0
  27. package/dist/generators/templates/data/tsConfigTemplate +19 -0
  28. package/dist/generators/templates/viewTemplates.d.ts +10 -1
  29. package/dist/generators/templates/viewTemplates.js +138 -6
  30. package/dist/generators/validationGenerator.d.ts +5 -0
  31. package/dist/generators/validationGenerator.js +51 -0
  32. package/dist/utils/constants.d.ts +3 -0
  33. package/dist/utils/constants.js +5 -2
  34. package/dist/utils/generationRegistry.js +1 -1
  35. package/dist/utils/migrationUtils.d.ts +49 -0
  36. package/dist/utils/migrationUtils.js +291 -0
  37. package/howto.md +157 -65
  38. package/package.json +3 -2
@@ -0,0 +1,671 @@
1
+ # CurrentJS Framework Rules
2
+
3
+ ## Architecture Overview
4
+ This is a CurrentJS framework application using clean architecture principles with the following layers:
5
+ - **Controllers**: Handle HTTP requests/responses and route handling
6
+ - **Services**: Contain business logic and orchestrate operations
7
+ - **Stores**: Provide data access layer and database operations
8
+ - **Domain Entities**: Core business models
9
+ - **Views**: HTML templates for server-side rendering
10
+
11
+ ## Commands
12
+
13
+ ```bash
14
+ current create module Modulename # Creates "Modulename" with default structure and yaml file
15
+ ```
16
+ ```bash
17
+ current generate Modulename # Generates all TypeScript files based on the module's yaml, and runs "npm run build"
18
+ current generate # Does the same as above, but for all modules
19
+ ```
20
+ ```bash
21
+ current commit [files...] # Commits all changes in the code, so they won't be overwritten after regeneration
22
+ current diff [module] # Show differences between generated and current code
23
+ ```
24
+
25
+ ## The flow
26
+ 1. Create an empty app (`current create app`) – this step is already done.
27
+ 2. Create a new module: `current create module Name`
28
+ 3. In the module's yaml file, define module's:
29
+ - model(s)
30
+ - routes & actions
31
+ - permissions
32
+ 4. Generate TypeScript files: `current generate Name`
33
+ 5. If required, make changes in the:
34
+ - model (i.e. some specific business rules or validations)
35
+ - views
36
+ 6. Commit those changes: `current commit`
37
+
38
+ --- If needed more than CRUD: ---
39
+
40
+ 7. Define action in the service by creating a method
41
+ 8. Describe this action in the module's yaml. Additionaly, you may define routes and permissions.
42
+ 9. `current generate Modulename`
43
+ 10. commit changes: `current commit`
44
+
45
+ ## Configuration Files
46
+
47
+ ### Application Configuration (app.yaml)
48
+
49
+ **Do not modify this file**
50
+
51
+ ### Module Configuration (modulename.yaml)
52
+
53
+ **The most work must be done in these files**
54
+
55
+ **Complete Module Example:**
56
+ ```yaml
57
+ models:
58
+ - name: Post # Entity name (capitalized)
59
+ fields:
60
+ - name: title # Field name
61
+ type: string # Field type: string, number, boolean, datetime
62
+ required: true # Validation requirement
63
+ - name: content
64
+ type: string
65
+ required: true
66
+ - name: authorId
67
+ type: number
68
+ required: true
69
+ - name: publishedAt
70
+ type: datetime
71
+ required: false
72
+ - name: status
73
+ type: string
74
+ required: true
75
+
76
+ api: # REST API configuration
77
+ prefix: /api/posts # Base URL for API endpoints
78
+ model: Post # Optional: which model this API serves (defaults to first model)
79
+ endpoints:
80
+ - method: GET # HTTP method
81
+ path: / # Relative path (becomes /api/posts/)
82
+ action: list # Action name (references actions section)
83
+ - method: GET
84
+ path: /:id # Path parameter
85
+ action: get
86
+ - method: POST
87
+ path: /
88
+ action: create
89
+ - method: PUT
90
+ path: /:id
91
+ action: update
92
+ - method: DELETE
93
+ path: /:id
94
+ action: delete
95
+ - method: POST # Custom endpoint
96
+ path: /:id/publish
97
+ action: publish
98
+ model: Post # Optional: override model for specific endpoint
99
+
100
+ routes: # Web interface configuration
101
+ prefix: /posts # Base URL for web pages
102
+ model: Post # Optional: which model this route serves (defaults to first model)
103
+ strategy: [toast, back] # Default success strategies for forms
104
+ endpoints:
105
+ - path: / # List page
106
+ action: list
107
+ view: postList # Template name
108
+ - path: /:id # Detail page
109
+ action: get
110
+ view: postDetail
111
+ - path: /create # Create form page
112
+ action: empty # No data loading action
113
+ view: postCreate
114
+ - path: /:id/edit # Edit form page
115
+ action: get # Load existing data
116
+ view: postUpdate
117
+ model: Post # Optional: override model for specific endpoint
118
+
119
+ actions: # Business logic mapping
120
+ list:
121
+ handlers: [Post:default:list] # Use built-in list handler
122
+ get:
123
+ handlers: [Post:default:get] # Use built-in get handler
124
+ create:
125
+ handlers: [Post:default:create] # Built-in create
126
+ update:
127
+ handlers: [Post:default:update]
128
+ delete:
129
+ handlers: [ # Chain multiple handlers
130
+ Post:checkCanDelete, # Custom business logic
131
+ Post:default:delete
132
+ ]
133
+ publish: # Custom action
134
+ handlers: [
135
+ Post:default:get, # Fetch entity
136
+ Post:validateForPublish, # Custom validation
137
+ Post:updatePublishStatus # Custom update logic
138
+ ]
139
+
140
+ permissions: # Role-based access control
141
+ - role: all
142
+ actions: [list, get] # Anyone (including anonymous)
143
+ - role: authenticated
144
+ actions: [create] # Must be logged in
145
+ - role: owner
146
+ actions: [update, publish] # Entity owner permissions
147
+ - role: admin
148
+ actions: [update, delete, publish] # Admin role permissions
149
+ - role: editor
150
+ actions: [publish] # Editor role permissions
151
+ ```
152
+
153
+ **Make sure no `ID`/`owner id`/`is deleted` fields are present in the model definition, since it's added automatically**
154
+
155
+ **Field Types:**
156
+ - `string` - Text data
157
+ - `number` - Numeric data (integer or float)
158
+ - `boolean` - True/false values
159
+ - `datetime` - Date and time values
160
+ - `ModelName` - Relationship to another model (e.g., `Owner`, `User`, `Post`)
161
+
162
+ **Multi-Model Endpoint Configuration:**
163
+
164
+ When working with multiple models in a single module, you have flexible options:
165
+
166
+ **Option 1: Per-Endpoint Model Override**
167
+
168
+ Specify `model` on individual endpoints to override the section default:
169
+
170
+ ```yaml
171
+ models:
172
+ - name: Cat
173
+ - name: Person
174
+
175
+ routes:
176
+ prefix: /cat
177
+ model: Cat # Default for this section
178
+ endpoints:
179
+ - path: /create
180
+ view: catCreate
181
+ # Uses Cat model
182
+
183
+ - path: /createOwner
184
+ view: ownerCreate
185
+ model: Person # Override for this endpoint
186
+ ```
187
+
188
+ **Option 2: Multiple API/Routes Sections**
189
+
190
+ Use arrays to organize endpoints by model:
191
+
192
+ ```yaml
193
+ routes:
194
+ - prefix: /cat
195
+ model: Cat
196
+ endpoints: [...]
197
+
198
+ - prefix: /person
199
+ model: Person
200
+ endpoints: [...]
201
+
202
+ # Same works for api sections
203
+ api:
204
+ - prefix: /api/cat
205
+ model: Cat
206
+ endpoints: [...]
207
+
208
+ - prefix: /api/person
209
+ model: Person
210
+ endpoints: [...]
211
+ ```
212
+
213
+ **Model Resolution Priority:**
214
+ 1. `endpoint.model` (explicit override)
215
+ 2. Inferred from action handler (e.g., `Person:default:create`)
216
+ 3. `api.model` or `routes.model` (section default)
217
+ 4. First model in `models[]` array (fallback)
218
+
219
+ **Model Relationships:**
220
+
221
+ Define relationships by using another model's name as the field type:
222
+
223
+ ```yaml
224
+ models:
225
+ - name: Owner
226
+ fields:
227
+ - name: name
228
+ type: string
229
+ required: true
230
+
231
+ - name: Cat
232
+ fields:
233
+ - name: name
234
+ type: string
235
+ required: true
236
+ - name: owner
237
+ type: Owner # Creates relationship with Owner model
238
+ required: true # Auto-generates foreign key: ownerId
239
+ displayFields: [name] # Optional: fields to show in dropdowns
240
+ ```
241
+
242
+ **Generated Behavior:**
243
+ - **Domain Model**: Rich object with `owner: Owner` (full object, not just ID)
244
+ - **DTOs**: Use `ownerId: number` for API requests
245
+ - **Database**: Stores `ownerId` foreign key column (references `Owner.id`)
246
+ - **Store**: Automatically loads the related Owner object when fetching a Cat
247
+ - **HTML Forms**: Auto-generates select dropdown with "Create New" button
248
+ - **TypeScript**: Full type safety with proper imports
249
+
250
+ **Naming Convention:**
251
+ Foreign keys are auto-generated following the pattern `fieldName + 'Id'`:
252
+ - `owner` → `ownerId`
253
+ - `author` → `authorId`
254
+ - `parentComment` → `parentCommentId`
255
+
256
+ The foreign key always references the `id` field of the related model.
257
+
258
+ **🔄 Handler vs Action Architecture:**
259
+ - **Handler**: Creates a separate service method (one handler = one service method)
260
+ - **Action**: Virtual controller concept that calls handler methods step-by-step
261
+
262
+ **Built-in Action Handlers:**
263
+ - `ModelName:default:list` - Creates service method with pagination parameters
264
+ - `ModelName:default:get` - Creates service method named `get` with ID parameter
265
+ - `ModelName:default:create` - Creates service method with DTO parameter
266
+ - `ModelName:default:update` - Creates service method with ID and DTO parameters
267
+ - `ModelName:default:delete` - Creates service method with ID parameter
268
+
269
+ **Custom Action Handlers:**
270
+ - `ModelName:customMethodName` - Creates service method that accepts `result, context` parameters
271
+ - `result`: Result from previous handler (or `null` if it's the first handler)
272
+ - `context`: The request context object
273
+ - Each handler generates a separate method in the service
274
+ - User can customize the implementation after generation
275
+
276
+ **🔗 Multiple Handlers per Action:**
277
+ When an action has multiple handlers, each handler generates a separate service method, and the controller action calls them sequentially. The action returns the result from the last handler.
278
+
279
+ **Parameter Passing Rules:**
280
+ - **Default handlers** (`:default:`): Receive standard parameters (id, pagination, DTO, etc.)
281
+ - **Custom handlers**: Receive `(result, context)` where:
282
+ - `result`: Result from previous handler, or `null` if it's the first handler
283
+ - `context`: Request context object
284
+
285
+ **Handler Format Examples:**
286
+ - `Post:default:list` - Creates Post service method `list(page, limit)`
287
+ - `Post:default:get` - Creates Post service method `get(id)`
288
+ - `Post:validateContent` - Creates Post service method `validateContent(result, context)`
289
+ - `Comment:notifySubscribers` - Creates Comment service method `notifySubscribers(result, context)`
290
+
291
+ **Strategy Options (for forms):**
292
+ - `toast` - Success toast notification
293
+ - `back` - Navigate back in browser history
294
+ - `message` - Inline success message
295
+ - `modal` - Modal success dialog
296
+ - `redirect` - Redirect to specific URL
297
+ - `refresh` - Reload current page
298
+
299
+ **Permission Roles:**
300
+ - `all` - Anyone (including anonymous users)
301
+ - `authenticated` - Any logged-in user
302
+ - `owner` - User who created the entity
303
+ - `admin`, `editor`, `user` - Custom roles from JWT token
304
+ - Multiple roles can be specified for each action
305
+
306
+ **Generated Files from Configuration:**
307
+ - Domain entity class (one per model)
308
+ - Service class (one per model)
309
+ - API controller with REST endpoints (one per model)
310
+ - Web controller with page rendering (one per model)
311
+ - Store class with database operations (one per model)
312
+ - HTML templates for all views
313
+ - TypeScript interfaces and DTOs
314
+
315
+ **Multi-Model Support:**
316
+ - Each model gets its own service, controller, and store
317
+ - Use `model` parameter in `api` and `routes` to specify which model to use (defaults to first model)
318
+ - Use `model` parameter on individual endpoints to override model for specific endpoints
319
+ - Action handlers use `modelname:action` format to specify which model's service method to call
320
+ - Controllers and services are generated per model, not per module
321
+
322
+ ## Module Structure
323
+ ```
324
+ src/modules/ModuleName/
325
+ ├── application/
326
+ │ ├── services/ModuleService.ts # Business logic
327
+ │ └── validation/ModuleValidation.ts # DTOs and validation
328
+ ├── domain/
329
+ │ └── entities/Module.ts # Domain model
330
+ ├── infrastructure/
331
+ │ ├── controllers/
332
+ │ │ ├── ModuleApiController.ts # REST API endpoints
333
+ │ │ └── ModuleWebController.ts # Web page controllers
334
+ │ ├── interfaces/StoreInterface.ts # Data access interface
335
+ │ └── stores/ModuleStore.ts # Data access implementation
336
+ ├── views/
337
+ │ ├── modulelist.html # List view template
338
+ │ ├── moduledetail.html # Detail view template
339
+ │ ├── modulecreate.html # Create form template
340
+ │ └── moduleupdate.html # Update form template
341
+ └── module.yaml # Module configuration
342
+ ```
343
+
344
+ ## Best Practices
345
+
346
+ - Use Domain Driven Design and Clean Architecture (kind of).
347
+ - Prefer declarative configuration over imperative programming: when possible, change yamls instead of writing the code. Write the code only when it's really neccessary.
348
+ - CRUD operation are autogenerated (first in module's yaml, then in the generated code).
349
+ - If some custom action is needed, then it has to be defined in the **Service** then just put this action to the module's yaml. You may also define new methods in the *Store* and its interface (if needed).
350
+ - Business rules must be defined only in models. That also applies to business rules validations (in contrast to *just* validations: e.g. if field exists and is of needed type – then validators are in use)
351
+
352
+ ## Core Package APIs (For Generated Code)
353
+
354
+ ### @currentjs/router - Controller Decorators & Context
355
+
356
+ **Decorators (in controllers):**
357
+ ```typescript
358
+ @Controller('/api/posts') // Base path for controller
359
+ @Get('/') // GET endpoint
360
+ @Get('/:id') // GET with path parameter
361
+ @Post('/') // POST endpoint
362
+ @Put('/:id') // PUT endpoint
363
+ @Delete('/:id') // DELETE endpoint
364
+ @Render('template', 'layout') // For web controllers
365
+ ```
366
+
367
+ **Context Object (in route handlers):**
368
+ ```typescript
369
+ interface IContext {
370
+ request: {
371
+ url: string;
372
+ path: string;
373
+ method: string;
374
+ parameters: Record<string, string | number>; // Path params + query params
375
+ body: any; // Parsed JSON or raw string
376
+ headers: Record<string, string | string[]>;
377
+ user?: AuthenticatedUser; // Parsed JWT user if authenticated
378
+ };
379
+ response: Record<string, any>;
380
+ }
381
+
382
+ // Usage examples
383
+ const id = parseInt(ctx.request.parameters.id as string);
384
+ const page = parseInt(ctx.request.parameters.page as string) || 1;
385
+ const payload = ctx.request.body;
386
+ const user = ctx.request.user; // If authenticated
387
+ ```
388
+
389
+ **Authentication Support:**
390
+ - JWT tokens parsed automatically from `Authorization: Bearer <token>` header
391
+ - User object available at `ctx.request.user` with `id`, `email`, `role` fields
392
+ - No manual setup required in generated code
393
+
394
+ ### @currentjs/templating - Template Syntax
395
+
396
+ **Variables & Data Access:**
397
+ ```html
398
+ {{ variableName }}
399
+ {{ object.property }}
400
+ {{ $root.arrayData }} <!-- Access root data -->
401
+ {{ $index }} <!-- Loop index -->
402
+ ```
403
+
404
+ **Control Structures:**
405
+ ```html
406
+ <!-- Loops -->
407
+ <tbody x-for="$root" x-row="item">
408
+ <tr>
409
+ <td>{{ item.name }}</td>
410
+ <td>{{ $index }}</td>
411
+ </tr>
412
+ </tbody>
413
+
414
+ <!-- Conditionals -->
415
+ <div x-if="user.isAdmin">Admin content</div>
416
+ <span x-if="errors.name">{{ errors.name }}</span>
417
+
418
+ <!-- Template includes -->
419
+ <userCard name="{{ user.name }}" role="admin" />
420
+ ```
421
+
422
+ **Layout Integration:**
423
+ - Templates use `<!-- @template name="templateName" -->` header
424
+ - Main layout gets `{{ content }}` variable
425
+ - Forms use `{{ formData.field || '' }}` for default values
426
+
427
+ ### @currentjs/provider-mysql - Database Operations
428
+
429
+ **Query Execution (in stores):**
430
+ ```typescript
431
+ // Named parameters (preferred)
432
+ const result = await this.db.query(
433
+ 'SELECT * FROM users WHERE status = :status AND age > :minAge',
434
+ { status: 'active', minAge: 18 }
435
+ );
436
+
437
+ // Result handling
438
+ if (result.success && result.data.length > 0) {
439
+ return result.data.map(row => this.rowToModel(row));
440
+ }
441
+ ```
442
+
443
+ **Common Query Patterns:**
444
+ ```typescript
445
+ // Insert with auto-generated fields
446
+ const row = { ...data, created_at: new Date(), updated_at: new Date() };
447
+ const result = await this.db.query(
448
+ `INSERT INTO table_name (\${fields.join(', ')}) VALUES (\${placeholders})`,
449
+ row
450
+ );
451
+ const newId = result.insertId;
452
+
453
+ // Update with validation
454
+ const query = `UPDATE table_name SET \${updateFields.join(', ')}, updated_at = :updated_at WHERE id = :id`;
455
+ await this.db.query(query, { ...updateData, updated_at: new Date(), id });
456
+
457
+ // Soft delete
458
+ await this.db.query(
459
+ 'UPDATE table_name SET deleted_at = :deleted_at WHERE id = :id',
460
+ { deleted_at: new Date(), id }
461
+ );
462
+ ```
463
+
464
+ **Error Handling:**
465
+ ```typescript
466
+ try {
467
+ const result = await this.db.query(query, params);
468
+ } catch (error) {
469
+ if (error instanceof MySQLConnectionError) {
470
+ throw new Error(`Database connection error: \${error.message}`);
471
+ } else if (error instanceof MySQLQueryError) {
472
+ throw new Error(`Query error: \${error.message}`);
473
+ }
474
+ throw error;
475
+ }
476
+ ```
477
+
478
+ ## Frontend System (web/app.js)
479
+
480
+ ### Translation System
481
+
482
+ **Basic Usage:**
483
+ ```javascript
484
+ // Translate strings
485
+ App.lang.t('Hello World') // Returns translated version or original
486
+ App.lang.t('Save changes')
487
+
488
+ // Set language
489
+ App.lang.set('pl') // Switch to Polish
490
+ App.lang.set('en') // Switch to English
491
+ App.lang.get() // Get current language code
492
+ ```
493
+
494
+ **Translation File (web/translations.json):**
495
+ ```json
496
+ {
497
+ "pl": {
498
+ "Hello World": "Witaj Świecie",
499
+ "Save changes": "Zapisz zmiany",
500
+ "Delete": "Usuń"
501
+ },
502
+ "ru": {
503
+ "Hello World": "Привет мир",
504
+ "Save changes": "Сохранить изменения"
505
+ }
506
+ }
507
+ ```
508
+
509
+ ### UI Feedback & Notifications
510
+
511
+ **Toast Notifications:**
512
+ ```javascript
513
+ App.ui.showToast('Success message', 'success') // Green toast
514
+ App.ui.showToast('Error occurred', 'error') // Red toast
515
+ App.ui.showToast('Information', 'info') // Blue toast
516
+ App.ui.showToast('Warning', 'warning') // Yellow toast
517
+ ```
518
+
519
+ **Inline Messages:**
520
+ ```javascript
521
+ App.ui.showMessage('messageId', 'Success!', 'success')
522
+ App.ui.showMessage('errorContainer', 'Validation failed', 'error')
523
+ ```
524
+
525
+ **Modal Dialogs:**
526
+ ```javascript
527
+ App.ui.showModal('confirmModal', 'Item saved successfully', 'success')
528
+ App.ui.showModal('errorModal', 'Operation failed', 'error')
529
+ ```
530
+
531
+ ### Navigation & Page Actions
532
+
533
+ **Navigation Functions:**
534
+ ```javascript
535
+ // SPA-style navigation
536
+ App.nav.go('/posts/123') // Loads via AJAX, updates #main
537
+
538
+ // Or use native browser APIs directly
539
+ window.history.back() // Go back in history
540
+ window.location.href = '/posts' // Full page redirect
541
+ window.location.reload() // Reload page
542
+ ```
543
+
544
+ ### Form Handling & Strategy System
545
+
546
+ **Form Strategy Configuration:**
547
+ ```html
548
+ <!-- Form with strategy attributes -->
549
+ <form data-strategy='["toast", "back"]'
550
+ data-entity-name="Post"
551
+ data-field-types='{"age": "number", "active": "boolean"}'>
552
+ <input name="title" type="text" required>
553
+ <input name="age" type="number">
554
+ <input name="active" type="checkbox">
555
+ <button type="submit">Save</button>
556
+ </form>
557
+ ```
558
+
559
+ **Available Strategies:**
560
+ - `toast` - Show success toast notification
561
+ - `back` - Navigate back using browser history
562
+ - `message` - Show inline message in specific element
563
+ - `modal` - Show modal dialog
564
+ - `redirect` - Redirect to specific URL
565
+ - `refresh` - Reload the page
566
+ - `remove` - Remove form element
567
+
568
+ **Manual Form Submission:**
569
+ ```javascript
570
+ const form = document.querySelector('#myForm');
571
+ App.nav.submit(form, ['toast', 'back'], {
572
+ entityName: 'Post',
573
+ basePath: '/posts',
574
+ messageId: 'form-message'
575
+ });
576
+ ```
577
+
578
+ ### Loading States & Utilities
579
+
580
+ **Loading Indicators:**
581
+ ```javascript
582
+ App.ui.showLoading('#form') // Show spinner on form
583
+ App.ui.hideLoading('#form') // Hide spinner
584
+ App.ui.showLoading('#main') // Show spinner on main content
585
+ ```
586
+
587
+ **Utility Functions:**
588
+ ```javascript
589
+ App.utils.debounce(searchFunction, 300) // Debounce for search inputs
590
+ App.utils.$('#selector') // Safe element selection
591
+ ```
592
+
593
+ ### Event Handling & SPA Integration
594
+
595
+ **Automatic Link Handling:**
596
+ - Internal links automatically use AJAX navigation
597
+ - External links work normally
598
+ - Links with `data-external` skip AJAX handling
599
+
600
+ **Automatic Form Handling:**
601
+ - Forms with `data-strategy` use AJAX submission
602
+ - Regular forms work normally
603
+ - Automatic JSON conversion from FormData
604
+
605
+ **Custom Event Listeners:**
606
+ ```javascript
607
+ // Re-initialize after dynamic content loading
608
+ App.utils.initializeEventListeners();
609
+
610
+ // Handle specific link navigation
611
+ document.querySelector('#myLink').addEventListener('click', (e) => {
612
+ e.preventDefault();
613
+ App.nav.go('/custom/path');
614
+ });
615
+ ```
616
+
617
+ ### Global App Object
618
+
619
+ **Accessing Functions:**
620
+ ```javascript
621
+ // All functions available under window.App
622
+ // Organized by category for better discoverability
623
+
624
+ // UI Functions
625
+ App.ui.showToast('Message', 'success');
626
+ App.ui.showMessage('elementId', 'Success!', 'success');
627
+ App.ui.showModal('modalId', 'Done!', 'success');
628
+ App.ui.showLoading('#form');
629
+ App.ui.hideLoading('#form');
630
+
631
+ // Navigation Functions
632
+ App.nav.go('/posts/123'); // SPA-style navigation with AJAX
633
+ App.nav.submit(formElement, ['toast', 'back'], options); // Submit form via AJAX
634
+
635
+ // Translation Functions
636
+ App.lang.t('Translate this'); // Translate string
637
+ App.lang.set('pl'); // Set language
638
+ App.lang.get(); // Get current language
639
+
640
+ // Utility Functions
641
+ App.utils.$('#selector'); // Safe element selection
642
+ App.utils.debounce(fn, 300); // Debounce function
643
+ App.utils.initializeEventListeners(); // Re-initialize after dynamic content
644
+
645
+ // Authentication Functions (JWT)
646
+ App.auth.setAuthToken(token); // Store JWT token
647
+ App.auth.clearAuthToken(); // Remove JWT token
648
+ App.auth.buildAuthHeaders(additionalHeaders); // Build headers with auth token
649
+ ```
650
+
651
+ ### Template Data Binding
652
+ ```html
653
+ <!-- List with pagination -->
654
+ <tbody x-for="modules" x-row="module">
655
+ <tr>
656
+ <td>{{ module.name }}</td>
657
+ <td><a href="/module/{{ module.id }}">View</a></td>
658
+ </tr>
659
+ </tbody>
660
+
661
+ <!-- Form with validation errors -->
662
+ <div x-if="errors.name" class="text-danger">{{ errors.name }}</div>
663
+ <input type="text" name="name" value="{{ formData.name || '' }}" class="form-control">
664
+
665
+ <!-- Form with strategy attributes -->
666
+ <form data-strategy='["toast", "back"]'
667
+ data-entity-name="Module"
668
+ data-field-types='{"count": "number", "active": "boolean"}'>
669
+ <!-- form fields -->
670
+ </form>
671
+ ```
@@ -0,0 +1,28 @@
1
+ <!-- @template name="error" -->
2
+ <!doctype html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Error - Your App</title>
8
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
9
+ <script src="/app.js"></script>
10
+ </head>
11
+ <body>
12
+ <div class="container-fluid">
13
+ <div class="row justify-content-center">
14
+ <div class="col-md-6">
15
+ <div class="text-center mt-5">
16
+ <div class="display-1 text-danger fw-bold mb-3">{{ statusCode }}</div>
17
+ <h2 class="mb-3">Oops! Something went wrong</h2>
18
+ <p class="text-muted mb-4">{{ error }}</p>
19
+ <div class="d-flex gap-2 justify-content-center">
20
+ <button class="btn btn-primary" onclick="window.history.back()">Go Back</button>
21
+ <a href="/" class="btn btn-outline-secondary">Home Page</a>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </body>
28
+ </html>