@numerum-tech/yeriasdk 1.0.0

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 (94) hide show
  1. package/README.md +864 -0
  2. package/dist/core/action-grid-view.d.ts +57 -0
  3. package/dist/core/action-grid-view.d.ts.map +1 -0
  4. package/dist/core/action-grid-view.js +112 -0
  5. package/dist/core/action-grid-view.js.map +1 -0
  6. package/dist/core/action-list-view.d.ts +39 -0
  7. package/dist/core/action-list-view.d.ts.map +1 -0
  8. package/dist/core/action-list-view.js +77 -0
  9. package/dist/core/action-list-view.js.map +1 -0
  10. package/dist/core/base/base-action-view.d.ts +82 -0
  11. package/dist/core/base/base-action-view.d.ts.map +1 -0
  12. package/dist/core/base/base-action-view.js +143 -0
  13. package/dist/core/base/base-action-view.js.map +1 -0
  14. package/dist/core/base-view.d.ts +105 -0
  15. package/dist/core/base-view.d.ts.map +1 -0
  16. package/dist/core/base-view.js +426 -0
  17. package/dist/core/base-view.js.map +1 -0
  18. package/dist/core/card-view.d.ts +24 -0
  19. package/dist/core/card-view.d.ts.map +1 -0
  20. package/dist/core/card-view.js +127 -0
  21. package/dist/core/card-view.js.map +1 -0
  22. package/dist/core/carousel-view.d.ts +22 -0
  23. package/dist/core/carousel-view.d.ts.map +1 -0
  24. package/dist/core/carousel-view.js +99 -0
  25. package/dist/core/carousel-view.js.map +1 -0
  26. package/dist/core/form-view.d.ts +165 -0
  27. package/dist/core/form-view.d.ts.map +1 -0
  28. package/dist/core/form-view.js +365 -0
  29. package/dist/core/form-view.js.map +1 -0
  30. package/dist/core/jsonapp.d.ts +263 -0
  31. package/dist/core/jsonapp.d.ts.map +1 -0
  32. package/dist/core/jsonapp.js +528 -0
  33. package/dist/core/jsonapp.js.map +1 -0
  34. package/dist/core/key-store.d.ts +51 -0
  35. package/dist/core/key-store.d.ts.map +1 -0
  36. package/dist/core/key-store.js +138 -0
  37. package/dist/core/key-store.js.map +1 -0
  38. package/dist/core/map-view.d.ts +45 -0
  39. package/dist/core/map-view.d.ts.map +1 -0
  40. package/dist/core/map-view.js +318 -0
  41. package/dist/core/map-view.js.map +1 -0
  42. package/dist/core/media-view.d.ts +20 -0
  43. package/dist/core/media-view.d.ts.map +1 -0
  44. package/dist/core/media-view.js +75 -0
  45. package/dist/core/media-view.js.map +1 -0
  46. package/dist/core/message-view.d.ts +53 -0
  47. package/dist/core/message-view.d.ts.map +1 -0
  48. package/dist/core/message-view.js +109 -0
  49. package/dist/core/message-view.js.map +1 -0
  50. package/dist/core/notification.d.ts +17 -0
  51. package/dist/core/notification.d.ts.map +1 -0
  52. package/dist/core/notification.js +33 -0
  53. package/dist/core/notification.js.map +1 -0
  54. package/dist/core/qr-display-view.d.ts +32 -0
  55. package/dist/core/qr-display-view.d.ts.map +1 -0
  56. package/dist/core/qr-display-view.js +66 -0
  57. package/dist/core/qr-display-view.js.map +1 -0
  58. package/dist/core/qr-scan-view.d.ts +148 -0
  59. package/dist/core/qr-scan-view.d.ts.map +1 -0
  60. package/dist/core/qr-scan-view.js +259 -0
  61. package/dist/core/qr-scan-view.js.map +1 -0
  62. package/dist/core/reader-view.d.ts +73 -0
  63. package/dist/core/reader-view.d.ts.map +1 -0
  64. package/dist/core/reader-view.js +285 -0
  65. package/dist/core/reader-view.js.map +1 -0
  66. package/dist/core/timeline-view.d.ts +16 -0
  67. package/dist/core/timeline-view.d.ts.map +1 -0
  68. package/dist/core/timeline-view.js +68 -0
  69. package/dist/core/timeline-view.js.map +1 -0
  70. package/dist/errors/index.d.ts +276 -0
  71. package/dist/errors/index.d.ts.map +1 -0
  72. package/dist/errors/index.js +431 -0
  73. package/dist/errors/index.js.map +1 -0
  74. package/dist/index.d.ts +26 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +103 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/types/index.d.ts +576 -0
  79. package/dist/types/index.d.ts.map +1 -0
  80. package/dist/types/index.js +48 -0
  81. package/dist/types/index.js.map +1 -0
  82. package/dist/utils/fileFormats.d.ts +52 -0
  83. package/dist/utils/fileFormats.d.ts.map +1 -0
  84. package/dist/utils/fileFormats.js +198 -0
  85. package/dist/utils/fileFormats.js.map +1 -0
  86. package/dist/utils/logger.d.ts +38 -0
  87. package/dist/utils/logger.d.ts.map +1 -0
  88. package/dist/utils/logger.js +109 -0
  89. package/dist/utils/logger.js.map +1 -0
  90. package/dist/utils/validators.d.ts +48 -0
  91. package/dist/utils/validators.d.ts.map +1 -0
  92. package/dist/utils/validators.js +445 -0
  93. package/dist/utils/validators.js.map +1 -0
  94. package/package.json +65 -0
package/README.md ADDED
@@ -0,0 +1,864 @@
1
+ > **Note**: This is the JavaScript/TypeScript port of the JSONApp SDK. This repository is a monorepo containing multiple language implementations. See the [root README](../README.md) for an overview.
2
+
3
+
4
+ Un SDK TypeScript moderne et optimisé pour générer des interfaces JSON dynamiques, avec support avancé pour les formulaires, la lecture de données, les actions, les QR codes, les messages et l'affichage de données.
5
+
6
+ ## 🚀 Fonctionnalités
7
+
8
+ - **Formulaires dynamiques** avec validation avancée
9
+ - **Lecteurs de données** pour afficher des informations
10
+ - **Listes d'actions** pour les menus et navigation
11
+ - **Grilles d'actions** pour les tableaux de bord
12
+ - **Scanner de QR codes** avec configuration flexible
13
+ - **Affichage de QR codes** avec validation d'images
14
+ - **Messages** pour les notifications et guides
15
+ - **Vues de données** pour l'affichage de contenu structuré
16
+ - **Cartes détaillées** pour présenter des fiches produit
17
+ - **Carrousels** pour mettre en avant plusieurs contenus
18
+ - **Timelines** pour les historiques ou étapes
19
+ - **Médias** audio/vidéo intégrés
20
+ - **Cartes interactives** pour localiser des points clés
21
+ - **Notifications** pour envoyer des messages signés aux utilisateurs via la plateforme City-Mate
22
+ - **API fluide** grâce au chaînage des méthodes
23
+ - **Validation robuste** avec règles personnalisables
24
+ - **Logging structuré** pour le débogage
25
+ - **TypeScript strict** pour la sécurité des types
26
+ - **Tests complets** avec Jest
27
+
28
+ ## 📦 Installation
29
+
30
+ ```bash
31
+ npm install @numerum-tech/yeriasdk
32
+ ```
33
+
34
+ ## 🎯 Utilisation Rapide
35
+
36
+ > **⚠️ Note Importante** :
37
+ > - **FormView** : Pour créer des formulaires interactifs avec collecte de données
38
+ > - **ReaderView** : Pour afficher du contenu riche en lecture seule (articles, guides, etc.)
39
+ > - Ces deux types de vues ont des API complètement différentes !
40
+
41
+ ### Formulaires
42
+
43
+ ```typescript
44
+ import { FormView } from '@yeria/jsonapp-sdk';
45
+
46
+ // Le titre est passé au constructeur (id, title)
47
+ const form = new FormView('user-registration', 'User Registration')
48
+ .setIntro('Please fill in your information')
49
+ // addField() utilise l'ordre: fieldType, fieldId, fieldLabel, params
50
+ .addField('text', 'name', 'Full Name', { required: true })
51
+ .addField('email', 'email', 'Email Address', { required: true })
52
+ .addField('tel', 'phone', 'Phone Number', { required: false })
53
+ .submitButton('Register', 'POST'); // Convention: POST /api/forms/{formId}
54
+
55
+ console.log(form.toJSON());
56
+
57
+ // Formulaire avec navigation (ex: multi-étapes)
58
+ const step1 = new FormView('registration-step-1', 'Personal Information')
59
+ .setIntro('Step 1 of 3')
60
+ .addTextField('firstName', 'First Name', true)
61
+ .addTextField('lastName', 'Last Name', true)
62
+ .setNext('/api/forms/registration-step-2') // Vue suivante
63
+ .submitButton('Continue', 'POST');
64
+
65
+ // Méthodes helper recommandées (plus simples et plus claires)
66
+ const formSimple = new FormView('user-registration', 'User Registration')
67
+ .setIntro('Please fill in your information')
68
+ .addTextField('name', 'Full Name', true)
69
+ .addEmailField('email', 'Email Address', true)
70
+ .addPhoneField('phone', 'Phone Number', false)
71
+ .submitButton('Register', 'POST');
72
+ ```
73
+
74
+ ### Injection de Données (Formulaires d'Édition)
75
+
76
+ ```typescript
77
+ import { FormView } from '@yeria/jsonapp-sdk';
78
+
79
+ // Méthode 1: injectData() - Injection Globale (RECOMMANDÉ)
80
+ // Parfait pour formulaires d'édition avec données depuis API/DB
81
+ const userData = {
82
+ firstName: 'John',
83
+ lastName: 'Doe',
84
+ email: 'john@example.com',
85
+ age: 30,
86
+ country: 'FR' // Pour select: met selected: true sur l'option 'FR'
87
+ };
88
+
89
+ const editForm = new FormView('edit-user', 'Edit User Profile')
90
+ .addTextField('firstName', 'First Name', true)
91
+ .addTextField('lastName', 'Last Name', true)
92
+ .addEmailField('email', 'Email', true)
93
+ .addNumberField('age', 'Age', false, 18, 120)
94
+ .addSelectField('country', 'Country', false, [
95
+ { label: 'France', value: 'FR' },
96
+ { label: 'USA', value: 'US' },
97
+ { label: 'Canada', value: 'CA' }
98
+ ])
99
+ .injectData(userData) // ✅ Injecte toutes les valeurs en une fois
100
+ .submitButton('Update Profile', 'PUT');
101
+
102
+ // JSON généré pour le select:
103
+ // {
104
+ // "fieldType": "select",
105
+ // "options": [
106
+ // { "label": "France", "value": "FR", "selected": true }, // ✅ Automatique!
107
+ // { "label": "USA", "value": "US", "selected": false },
108
+ // { "label": "Canada", "value": "CA", "selected": false }
109
+ // ]
110
+ // }
111
+
112
+ // Checkbox avec multi-sélection (value = array)
113
+ const preferencesData = {
114
+ interests: ['sports', 'music'] // Array pour checkbox multi-sélection
115
+ };
116
+
117
+ const preferencesForm = new FormView('preferences', 'Preferences')
118
+ .addCheckboxField('interests', 'Interests') // Checkbox avec options
119
+ .injectData(preferencesData);
120
+
121
+ // JSON généré pour checkbox:
122
+ // {
123
+ // "fieldType": "checkbox",
124
+ // "options": [
125
+ // { "label": "Sports", "value": "sports", "selected": true }, // ✅ Dans l'array
126
+ // { "label": "Music", "value": "music", "selected": true }, // ✅ Dans l'array
127
+ // { "label": "Reading", "value": "reading", "selected": false }
128
+ // ]
129
+ // }
130
+
131
+ // Méthode 2: setFieldValue() - Injection Individuelle
132
+ const form = new FormView('form', 'Form')
133
+ .addTextField('name', 'Name', true)
134
+ .setFieldValue('name', 'John Doe'); // ✅ Définit une valeur spécifique
135
+ ```
136
+
137
+ ### Lecteurs de Données (Contenu Riche)
138
+
139
+ ```typescript
140
+ import { ReaderView } from '@yeria/jsonapp-sdk';
141
+
142
+ // ReaderView affiche du contenu riche (pas des formulaires)
143
+ // Le titre est passé au constructeur (id, title)
144
+ const reader = new ReaderView('user-profile', 'User Profile')
145
+ .setIntro('Your profile information')
146
+ .addParagraph('Welcome to your user profile. Here you can view your personal information.')
147
+ .addSubTitle('Personal Information')
148
+ .addListField([
149
+ 'Name: John Doe',
150
+ 'Email: john@example.com',
151
+ 'Phone: +1234567890'
152
+ ])
153
+ .addSeparator()
154
+ .addSubTitle('Account Status')
155
+ .addParagraph('Your account is active and in good standing.')
156
+ .addImage('https://example.com/profile-picture.jpg', 'Profile Picture', 'Your profile photo');
157
+
158
+ console.log(reader.toJSON());
159
+
160
+ // Exemple avec Markdown
161
+ const readerMarkdown = new ReaderView('help-guide', 'Help Guide')
162
+ .setIntro('Learn how to use our platform')
163
+ .addMarkdown(`
164
+ ## Getting Started
165
+
166
+ Welcome to our platform! Here's how to get started:
167
+
168
+ 1. **Create an account** - Sign up with your email
169
+ 2. **Complete your profile** - Add your information
170
+ 3. **Explore features** - Discover what we offer
171
+
172
+ ### Need Help?
173
+ Contact our support team at support@example.com
174
+ `);
175
+
176
+ // ReaderView avec navigation (ex: tutoriel multi-pages)
177
+ const tutorial1 = new ReaderView('tutorial-1', 'Tutorial - Getting Started')
178
+ .setIntro('Welcome to the tutorial!')
179
+ .addParagraph('This tutorial will guide you through the basics.')
180
+ .setNext('/api/readers/tutorial-2') // Page suivante
181
+ .setPrev('/api/readers/welcome'); // Page précédente
182
+ ```
183
+
184
+ ### Listes d'Actions
185
+
186
+ ```typescript
187
+ import { ActionListView } from '@yeria/jsonapp-sdk';
188
+
189
+ // Le titre est passé au constructeur (viewId, viewTitle)
190
+ const actionList = new ActionListView('main-menu', 'Main Menu')
191
+ .addAction('profile', 'View Profile', 'Access your profile information', 'profile-icon.png')
192
+ .addAction('settings', 'Settings', 'Configure your preferences', 'settings-icon.png')
193
+ .addAction('help', 'Help & Support', 'Get help and contact support', 'help-icon.png');
194
+
195
+ console.log(actionList.toJSON());
196
+ ```
197
+
198
+ ### Grilles d'Actions
199
+
200
+ ```typescript
201
+ import { ActionGridView } from '@yeria/jsonapp-sdk';
202
+
203
+ // Le titre est passé au constructeur (viewId, viewTitle)
204
+ const actionGrid = new ActionGridView('dashboard', 'Dashboard')
205
+ .setColumns(3)
206
+ .setSpacing(20)
207
+ .addAction('analytics', 'Analytics', 'View your analytics', 'analytics-icon.png')
208
+ .addAction('reports', 'Reports', 'Generate reports', 'reports-icon.png')
209
+ .addAction('users', 'Users', 'Manage users', 'users-icon.png');
210
+
211
+ console.log(actionGrid.toJSON());
212
+ ```
213
+
214
+ ### Scanner de QR Codes
215
+
216
+ **Note** : Version 2.0 - API simplifiée. Le rendu mobile gère toute l'implémentation du scanner (caméra, torche, mise au point, formats).
217
+
218
+ ```typescript
219
+ import { QRScanView } from '@yeria/jsonapp-sdk';
220
+
221
+ // Auto-soumission simple (scan → POST immédiat)
222
+ const quickScan = new QRScanView('scan-ticket', 'Scan Your Ticket')
223
+ .setIntro('Point your camera at the QR code on your ticket');
224
+ // → L'utilisateur scanne "ABC123" → POST immédiat { qrData: "ABC123" }
225
+
226
+ // Avec bouton de confirmation (désactive auto-soumission)
227
+ const confirmScan = new QRScanView('verify-product', 'Verify Product')
228
+ .setIntro('Scan the product barcode')
229
+ .enablePreview(false, 'Product Code')
230
+ .submitButton('Verify Product');
231
+ // → Scanne → Affiche aperçu → Utilisateur clique "Verify Product" → POST
232
+
233
+ // Avec validation : préfixe + format numérique + longueur
234
+ const invoiceScan = new QRScanView('scan-invoice', 'Scan Invoice')
235
+ .setIntro('Scan the invoice QR code')
236
+ .setValidation('Invalid invoice format', 'number', 10, 10, 'INV-')
237
+ .submitButton('Process Invoice', 'Confirm processing?');
238
+ // → Scanne → Valide (préfixe INV-, chiffres, longueur 10) → Confirmation → POST
239
+ // Accepte : "INV-123456" (10 caractères total)
240
+
241
+ // Exemple 4 : Code PIN numérique exact
242
+ const pinScan = new QRScanView('scan-pin', 'Scan PIN')
243
+ .setIntro('Scan 6-digit PIN code')
244
+ .setValidation('PIN must be 6 digits', 'number', 6, 6);
245
+ // → Auto-submit si valide (6 chiffres)
246
+
247
+ // Exemple 5 : Email
248
+ const emailScan = new QRScanView('scan-email', 'Scan Email QR')
249
+ .setIntro('Scan email QR code')
250
+ .setValidation('Invalid email format', 'email');
251
+ // → Validation simple (contient @ et .)
252
+
253
+ // Exemple 6 : URL
254
+ const urlScan = new QRScanView('scan-url', 'Scan URL')
255
+ .setIntro('Scan URL QR code')
256
+ .setValidation('Invalid URL', 'url');
257
+ // → Validation simple (commence par http:// ou https://)
258
+
259
+ console.log(quickScan.toJSON());
260
+ ```
261
+
262
+ **Convention** : Le nom de champ est toujours `qrData` (non configurable). Données soumises : `{ qrData: "scanned-value" }`
263
+
264
+ **Formats de validation** :
265
+ - `'text'` : Aucune restriction
266
+ - `'number'` : Seulement chiffres (0-9)
267
+ - `'email'` : Validation simple (contient @ et .)
268
+ - `'url'` : Validation simple (http:// ou https://)
269
+
270
+ **IMPORTANT** : La validation mobile est **simple et permissive**. Le serveur **DOIT toujours re-valider** pour la sécurité.
271
+
272
+ ### Affichage de QR Codes
273
+
274
+ ```typescript
275
+ import { QRDisplayView } from '@yeria/jsonapp-sdk';
276
+
277
+ const qrDisplay = new QRDisplayView('qr-display', 'QR Code Display')
278
+ .setIntro('Your QR codes are ready to scan')
279
+ .addQRCodeReader(
280
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
281
+ 'Product QR Code',
282
+ 'Scan this QR code to view product details',
283
+ { size: 200, errorCorrection: 'M' }
284
+ )
285
+ .submitButton('Share QR Codes', 'POST');
286
+
287
+ console.log(qrDisplay.toJSON());
288
+ ```
289
+
290
+ ### Messages
291
+
292
+ ```typescript
293
+ import { MessageView } from '@yeria/jsonapp-sdk';
294
+
295
+ const message = new MessageView('maintenance-alert', 'Scheduled maintenance')
296
+ .setIntro('Heads up!')
297
+ .setBody('The platform will be unavailable tonight from 1:00 to 2:00 UTC while we apply upgrades.')
298
+ .setSeverity('warning')
299
+ .setPrimaryAction('OK, thanks', 'POST')
300
+ .setSecondaryAction('Remind me later', 'POST')
301
+ .setDismissible(true);
302
+
303
+ console.log(message.toJSON());
304
+ ```
305
+
306
+ ### Cartes Produit (CardView)
307
+
308
+ ```typescript
309
+ import { CardView } from '@yeria/jsonapp-sdk';
310
+
311
+ const productCard = new CardView('product-card', 'Super Gadget')
312
+ .setSubtitle('Boostez votre journée')
313
+ .setDescription('Un compagnon compact pour organiser vos tâches et automatiser vos routines quotidiennes.')
314
+ .setImage('https://cdn.example.com/gadget.jpg', 'Super Gadget')
315
+ .addStat('Prix', '49 €')
316
+ .addStat('Stock', 'Disponible')
317
+ .addSection('Points clés', 'Assistant vocal intégré, autonomie 48h, synchronisation multi-appareils.')
318
+ .addAction('Acheter maintenant', 'POST', { confirmMessage: 'Confirmez-vous votre achat ?' })
319
+ .addAction('Voir les détails', 'GET', { href: '/produits/super-gadget', variant: 'link' });
320
+
321
+ console.log(productCard.toJSON());
322
+ ```
323
+
324
+ ### Carrousels (CarouselView)
325
+
326
+ ```typescript
327
+ import { CarouselView } from '@yeria/jsonapp-sdk';
328
+
329
+ const highlights = new CarouselView('home-carousel', 'Mises en avant')
330
+ .addSlide(
331
+ highlights.createSlide('release-2-0', 'Version 2.0', 'Découvrez les nouveautés', {
332
+ imageUrl: 'https://cdn.example.com/banners/release.jpg',
333
+ badge: 'Nouveau'
334
+ })
335
+ )
336
+ .addSlide(
337
+ highlights.createSlide('case-study', 'Étude client', 'Comment ACME a doublé sa productivité', {
338
+ imageUrl: 'https://cdn.example.com/banners/case-study.jpg'
339
+ })
340
+ )
341
+ .addSlideAction('release-2-0', 'Lire l’article', 'GET', { href: '/blog/version-2-0', variant: 'link' })
342
+ .setSettings({ autoplay: true, intervalMs: 5000, loop: true });
343
+
344
+ console.log(highlights.toJSON());
345
+ ```
346
+
347
+ ### Timelines (TimelineView)
348
+
349
+ ```typescript
350
+ import { TimelineView } from '@yeria/jsonapp-sdk';
351
+
352
+ const onboarding = new TimelineView('onboarding-flow', 'Votre progression')
353
+ .setIntro('Suivez vos étapes de mise en service')
354
+ .addEvent('step-1', 'Compte créé', new Date().toISOString(), { status: 'completed' })
355
+ .addEvent('step-2', 'Télécharger vos documents', '2025-01-15T12:00:00Z', { status: 'active' })
356
+ .addEvent('step-3', 'Validation', '2025-01-20T09:00:00Z', { status: 'pending' });
357
+
358
+ console.log(onboarding.toJSON());
359
+ ```
360
+
361
+ ### Médias (MediaView)
362
+
363
+ ```typescript
364
+ import { MediaView } from '@yeria/jsonapp-sdk';
365
+
366
+ const tutorials = new MediaView('media-library', 'Tutoriels express')
367
+ .setIntro('Apprenez en quelques minutes')
368
+ .addMediaItem(
369
+ tutorials.createMedia('video-intro', 'video', 'https://cdn.example.com/videos/intro.mp4', {
370
+ type: 'video/mp4',
371
+ poster: 'https://cdn.example.com/posters/intro.jpg'
372
+ })
373
+ )
374
+ .addMediaItem({
375
+ id: 'audio-guide',
376
+ kind: 'audio',
377
+ title: 'Guide audio',
378
+ sources: [{ src: 'https://cdn.example.com/audio/guide.mp3', type: 'audio/mpeg' }]
379
+ });
380
+
381
+ console.log(tutorials.toJSON());
382
+ ```
383
+
384
+ ### Cartes interactives (MapView)
385
+
386
+ ```typescript
387
+ import { MapView } from '@yeria/jsonapp-sdk';
388
+
389
+ const storeMap = new MapView('stores-map', 'Boutiques partenaires')
390
+ .setViewport({ lat: 48.8566, lon: 2.3522 }, { zoom: 12 })
391
+ .addMarker({
392
+ id: 'store-paris',
393
+ title: 'Paris Centre',
394
+ description: 'Ouvert de 9h à 19h',
395
+ location: { lat: 48.8566, lon: 2.3522 }
396
+ })
397
+ .addMarker({
398
+ id: 'store-lyon',
399
+ title: 'Lyon République',
400
+ location: { lat: 45.7640, lon: 4.8357 }
401
+ })
402
+ .setControls({ zoom: true, userLocation: true });
403
+
404
+ console.log(storeMap.toJSON());
405
+ ```
406
+
407
+ ### Notifications
408
+
409
+ Envoyer des notifications signées aux utilisateurs via la plateforme City-Mate :
410
+
411
+ ```typescript
412
+ import { JsonApp } from 'jsonapp-js';
413
+
414
+ const jsonApp = new JsonApp({
415
+ appId: 'my-backend-service',
416
+ platformUrl: 'https://platform.yeria.com/api/notifications' // Optionnel: peut aussi être passé par appel
417
+ });
418
+
419
+ // Créer et envoyer une notification
420
+ const notification = jsonApp
421
+ .createNotification('user-123', 'Bienvenue !', 'Merci d\'avoir rejoint City-Mate')
422
+ .setLink('/welcome');
423
+
424
+ await jsonApp.sendNotification(notification);
425
+ ```
426
+
427
+ ### JsonApp sécurisé
428
+
429
+ ```typescript
430
+ import { JsonApp } from '@yeria/jsonapp-sdk';
431
+
432
+ const jsonApp = new JsonApp({
433
+ appId: 'my-backend-service',
434
+ viewExpirationMinutes: 30
435
+ });
436
+
437
+ const form = jsonApp
438
+ .createFormView('user-registration', 'User Registration')
439
+ .addTextField('email', 'Email', true)
440
+ .addPasswordField('password', 'Password', 8)
441
+ .submitButton('Register', 'POST');
442
+
443
+ const secureResponse = jsonApp.serve(form);
444
+ console.log('Signature:', secureResponse.signature);
445
+ console.log('Integrity check:', jsonApp.verifyIntegrity(secureResponse));
446
+ ```
447
+
448
+ > ℹ️ **JsonApp est stateless** : il ne conserve plus les vues créées. Gardez vos instances (ex: dans un tableau) si vous devez les servir plus tard.
449
+
450
+ Vous pouvez également signer une vue sans instancier JsonApp grâce au helper statique :
451
+
452
+ ```typescript
453
+ import { JsonApp, FormView } from '@yeria/jsonapp-sdk';
454
+
455
+ const privateKey = process.env.PRIVATE_KEY!; // clé PEM Ed25519
456
+ const publicKey = process.env.PUBLIC_KEY!;
457
+
458
+ const manualForm = new FormView('manual', 'Manual Form')
459
+ .addTextField('name', 'Name', true)
460
+ .submitButton('Save', 'POST');
461
+
462
+ const payload = manualForm.toJSON();
463
+ const signed = JsonApp.signView(payload, 'my-backend-service', privateKey);
464
+
465
+ console.log('Signature valide ?', JsonApp.verifySignature(publicKey, signed));
466
+ ```
467
+
468
+ ## 🧭 Workflows Multi-Étapes (Process Context)
469
+
470
+ Le SDK supporte les processus multi-étapes avec suivi de progression via `belongsToProcess()`.
471
+
472
+ ```typescript
473
+ import { FormView } from '@yeria/jsonapp-sdk';
474
+
475
+ // Étape 1 : Bienvenue
476
+ const step1 = new FormView('welcome', 'Welcome!', 'user-onboarding')
477
+ .belongsToProcess('user-onboarding', {
478
+ processName: 'User Onboarding',
479
+ currentStep: 1,
480
+ totalSteps: 4,
481
+ stepName: 'Welcome',
482
+ canGoBack: false,
483
+ canSkip: false
484
+ })
485
+ .setIntro('Let\'s get you started')
486
+ .addTextField('firstName', 'First Name', true, 50)
487
+ .addTextField('lastName', 'Last Name', true, 50)
488
+ .setNext('personal-info') // Relative viewId (même processus)
489
+ .submitButton('Continue');
490
+
491
+ // Étape 2 : Informations personnelles
492
+ const step2 = new FormView('personal-info', 'Personal Information', 'user-onboarding')
493
+ .belongsToProcess('user-onboarding', {
494
+ processName: 'User Onboarding',
495
+ currentStep: 2,
496
+ totalSteps: 4,
497
+ stepName: 'Personal Info',
498
+ canGoBack: true,
499
+ canSkip: false
500
+ })
501
+ .setIntro('Tell us about yourself')
502
+ .addEmailField('email', 'Email Address', true)
503
+ .addPhoneField('phone', 'Phone Number', true)
504
+ .setPrev('welcome')
505
+ .setNext('address')
506
+ .submitButton('Continue');
507
+
508
+ // Pattern d'URL : /api/processes/user-onboarding/views/welcome
509
+ // Soumission : POST /api/processes/user-onboarding/views/welcome
510
+ ```
511
+
512
+ ## 🔧 Configuration
513
+
514
+ ### Logging
515
+
516
+ The SDK provides a **flexible, pluggable logging system** that is **silent by default** in production.
517
+
518
+ #### **Silent Mode (Default - Production)**
519
+
520
+ ```typescript
521
+ import { JsonApp } from '@yeria/jsonapp-sdk';
522
+
523
+ // No logger = SilentLogger (no logs in production)
524
+ const app = new JsonApp({ appId: 'my-app' });
525
+ // Clean, professional - no console pollution
526
+ ```
527
+
528
+ #### **Console Logger (Development)**
529
+
530
+ ```typescript
531
+ import { JsonApp, ConsoleLogger } from '@yeria/jsonapp-sdk';
532
+
533
+ // Opt-in to console logging for debugging
534
+ const app = new JsonApp({
535
+ appId: 'my-app',
536
+ logger: new ConsoleLogger('info') // 'debug' | 'info' | 'warn' | 'error'
537
+ });
538
+
539
+ // Logs appear for important operations:
540
+ // [2025-10-25T10:30:00.000Z] [JsonApp INFO] JsonApp initialized
541
+ // [2025-10-25T10:30:00.001Z] [JsonApp INFO] View served securely
542
+ ```
543
+
544
+ #### **Custom Logger (Integration with Existing Systems)**
545
+
546
+ ```typescript
547
+ import { JsonApp, ILogger } from '@yeria/jsonapp-sdk';
548
+
549
+ // Integrate with Sentry, Winston, Datadog, etc.
550
+ const customLogger: ILogger = {
551
+ debug: (msg, ctx) => winston.debug(msg, ctx),
552
+ info: (msg, ctx) => winston.info(msg, ctx),
553
+ warn: (msg, ctx) => winston.warn(msg, ctx),
554
+ error: (msg, ctx) => winston.error(msg, ctx)
555
+ };
556
+
557
+ const app = new JsonApp({
558
+ appId: 'my-app',
559
+ logger: customLogger // All SDK logs use your logger
560
+ });
561
+ ```
562
+
563
+ #### **Environment-Based Logging**
564
+
565
+ ```typescript
566
+ import { JsonApp, ConsoleLogger, SilentLogger } from '@yeria/jsonapp-sdk';
567
+
568
+ const logger = process.env['NODE_ENV'] === 'development'
569
+ ? new ConsoleLogger('debug')
570
+ : new SilentLogger();
571
+
572
+ const app = new JsonApp({ appId: 'my-app', logger });
573
+ ```
574
+
575
+ #### **Legacy Logger (Backward Compatibility)**
576
+
577
+ ```typescript
578
+ import { Logger } from '@yeria/jsonapp-sdk';
579
+
580
+ // Old API still works (deprecated)
581
+ Logger.getInstance().setLogLevel('info');
582
+ Logger.info('JsonApp ready');
583
+ ```
584
+
585
+ See [LOGGER_ARCHITECTURE.md](./LOGGER_ARCHITECTURE.md) for complete documentation.
586
+
587
+ ### Validation
588
+
589
+ ```typescript
590
+ import { FieldValidator, DataSanitizer } from '@yeria/jsonapp-sdk';
591
+
592
+ // Validation de configuration de champ
593
+ const fieldCheck = FieldValidator.validateField('email', 'email', 'Email', {
594
+ required: true,
595
+ value: 'test@example.com'
596
+ });
597
+
598
+ // Nettoyage d'entrée utilisateur
599
+ const safeValue = DataSanitizer.sanitizeInput('<script>alert(1)</script>');
600
+ ```
601
+
602
+ ## 📋 Types Supportés
603
+
604
+ ### Champs de Formulaire
605
+ - `text` - Texte simple
606
+ - `email` - Adresse email
607
+ - `tel` - Numéro de téléphone
608
+ - `password` - Mot de passe
609
+ - `date` - Date
610
+ - `file` - Fichier
611
+ - `gps` - Coordonnées GPS
612
+ - `select` - Sélection
613
+ - `pluscode` - Code Plus
614
+
615
+ ### Types de Vue
616
+ - `Form` - Formulaires
617
+ - `Reader` - Lecteurs de données
618
+ - `ActionList` - Listes d'actions
619
+ - `ActionGrid` - Grilles d'actions
620
+ - `QRScan` - Scanner de QR codes
621
+ - `QRDisplay` - Affichage de QR codes
622
+ - `Message` - Messages
623
+ - `Card` - Cartes produit/profil
624
+ - `Carousel` - Carrousels d'images
625
+ - `Timeline` - Lignes temporelles
626
+ - `Media` - Lecteurs audio/vidéo
627
+ - `Map` - Cartes interactives
628
+
629
+ ## 🧪 Tests
630
+
631
+ ```bash
632
+ # Exécuter tous les tests
633
+ npm test
634
+
635
+ # Tests en mode watch
636
+ npm run test:watch
637
+
638
+ # Tests avec couverture
639
+ npm run test:coverage
640
+
641
+ # Test du SDK complet
642
+ npm run test:sdk
643
+ ```
644
+
645
+ ## 📚 API Référence
646
+
647
+ ### BaseView
648
+ Classe de base pour toutes les vues avec méthodes communes :
649
+ - `toJSON()` - Sérialisation en JSON
650
+ - `clone()` - Clonage de la vue
651
+ - `validate()` - Validation des données
652
+
653
+ ### FormView
654
+ Gestion des formulaires avec validation avancée :
655
+ - `setIntro()` - Texte d'introduction du formulaire (recommandé)
656
+ - `setNote()` - Note introductive (déprécié, utilisez `setIntro()`)
657
+ - `addField()` - Ajout de champ générique
658
+ - `addTextField()`, `addEmailField()`, `addPhoneField()`, `addPasswordField()` - Champs texte
659
+ - `addNumberField()`, `addDateField()` - Champs numériques et date
660
+ - `addSelectField()`, `addCheckboxField()` - Sélections
661
+ - `addPhotoField()`, `addFileField()` - Upload de fichiers
662
+ - `addGPSField()`, `addPlusCodeField()` - Localisation
663
+ - `injectData()` - Injection de données pour formulaires d'édition
664
+ - `setFieldValue()` - Définir la valeur d'un champ
665
+ - `submitButton()`, `updateButton()`, `deleteButton()` - Boutons d'action
666
+ - `setNext()`, `setPrev()` - Navigation multi-étapes
667
+ - `belongsToProcess()` - Associer à un processus
668
+
669
+ ### ReaderView
670
+ Affichage de contenu riche en lecture seule :
671
+ - `setIntro()` - Texte d'introduction
672
+ - `addParagraph()` - Ajout de paragraphes
673
+ - `addImage()` - Ajout d'images
674
+ - `addSubTitle()` - Ajout de sous-titres
675
+ - `addMarkdown()` - Ajout de contenu Markdown
676
+ - `addListField()` - Ajout de listes
677
+ - `addLink()` - Ajout de liens
678
+ - `addTable()` - Ajout de tableaux
679
+ - `addCodeBlock()` - Ajout de blocs de code
680
+ - `addQuote()` - Ajout de citations
681
+ - `addSeparator()` - Ajout de séparateurs
682
+ - `setNext()`, `setPrev()` - Navigation
683
+
684
+ ### ActionListView/ActionGridView
685
+ Gestion des actions et navigation :
686
+ - `addAction()` - Ajout d'actions
687
+ - `removeAction()` - Suppression d'actions
688
+ - `getActiveActions()` - Actions actives
689
+
690
+ ### QRScanView
691
+ Scanner de QR codes (v2.0 - API simplifiée) :
692
+ - `setIntro()` - Instructions pour l'utilisateur
693
+ - `submitButton()` - Bouton de confirmation (désactive auto-soumission)
694
+ - `setValidation(errorMessage, format?, minLength?, maxLength?, startsWith?)` - Règles de validation
695
+ - Formats : `'text'`, `'number'`, `'url'`, `'email'`
696
+ - `enablePreview()` / `disablePreview()` - Aperçu avant soumission
697
+ - `setAutoSubmit()` - Activer/désactiver soumission automatique
698
+ - **Convention** : Nom de champ toujours `qrData`
699
+
700
+ ### QRDisplayView
701
+ Affichage de QR codes :
702
+ - `setIntro()` - Texte d'introduction
703
+ - `addQRCodeReader(imageUrl, title, description?, options?)` - Affichage d'un QR code
704
+ - `submitButton()` - Bouton d'action (partage, etc.)
705
+
706
+ ### MessageView
707
+ Gestion des messages et notifications :
708
+ - `setIntro()` - Texte d'introduction
709
+ - `setBody()` - Définition du message principal
710
+ - `setSeverity()` - Niveau d'alerte (`'info'`, `'success'`, `'warning'`, `'error'`)
711
+ - `setPrimaryAction()` - Bouton principal (OK, Valider…)
712
+ - `setSecondaryAction()` - Bouton secondaire (Annuler, Plus tard…)
713
+ - `setDismissible()` - Autoriser la fermeture sans action
714
+ - `submitButton()` - Alias de `setPrimaryAction()`
715
+
716
+ ### CardView
717
+ Présenter des fiches riches :
718
+ - `setSubtitle()` - Sous-titre court
719
+ - `setDescription()` - Texte détaillé
720
+ - `addStat()` - Statistiques clés (prix, stock…)
721
+ - `addSection()` - Contenu structuré (atouts, détails)
722
+ - `addAction()` - Boutons d'action
723
+
724
+ ### CarouselView
725
+ Mettre en avant plusieurs contenus :
726
+ - `createSlide()` / `addSlide()` - Gestion des slides
727
+ - `addSlideAction()` - Actions par slide
728
+ - `setSettings()` - Autoplay, boucle, indicateurs
729
+
730
+ ### TimelineView
731
+ Suivre une progression :
732
+ - `setIntro()` - Contexte
733
+ - `addEvent()` / `addItem()` - Ajout d'étapes
734
+ - `setItems()` - Définir la timeline complète
735
+
736
+ ### MediaView
737
+ Lecteurs audio/vidéo :
738
+ - `setIntro()` - Présentation
739
+ - `createMedia()` - Helper pour créer une ressource
740
+ - `addMediaItem()` - Ajouter vidéos ou podcasts
741
+ - `clearItems()` - Réinitialiser la playlist
742
+
743
+ ### MapView
744
+ Afficher des emplacements :
745
+ - `setViewport()` - Définir centre et zoom
746
+ - `addMarker()` / `addMarkers()` - Ajouter des points d'intérêt
747
+ - `setControls()` - Activer zoom, boussole, localisation
748
+ - `addOverlay()` - Ajouter des zones personnalisées
749
+
750
+ ## 🎨 Guide de Sélection de Vue
751
+
752
+ ### Quand utiliser chaque type de vue ?
753
+
754
+ #### FormView
755
+ - ✅ **Collecte de données utilisateur** (inscription, connexion, profil)
756
+ - ✅ **Formulaires interactifs** avec validation
757
+ - ✅ **Soumission de données** vers un serveur
758
+ - **Méthodes** : `addTextField()`, `addEmailField()`, `addPasswordField()`, etc.
759
+
760
+ #### ReaderView
761
+ - ✅ **Affichage de contenu** (articles, guides, documentation)
762
+ - ✅ **Présentations riches** avec images, markdown, tableaux
763
+ - ✅ **Pages informatives** sans interaction
764
+ - **Méthodes** : `addParagraph()`, `addImage()`, `addMarkdown()`, `addTable()`, etc.
765
+
766
+ #### ActionListView / ActionGridView
767
+ - ✅ **Menus de navigation**
768
+ - ✅ **Listes d'options** cliquables
769
+ - ✅ **Dashboards** avec actions rapides
770
+
771
+ #### QRScanView
772
+ - ✅ **Scanner** des QR codes avec auto-soumission
773
+ - ✅ **Validation** des codes scannés (format, longueur)
774
+ - ✅ **Aperçu** et édition manuelle avant soumission
775
+ - ✅ **Workflows de confirmation** avec boutons
776
+ - **Méthodes** : `setIntro()`, `submitButton()`, `setValidation()`, `enablePreview()`
777
+
778
+ #### QRDisplayView
779
+ - ✅ **Afficher** des QR codes
780
+ - ✅ **Partage** d'informations via QR
781
+
782
+ #### MessageView
783
+ - ✅ **Boîtes de dialogue** de confirmation
784
+ - ✅ **Messages informatifs** avec bouton OK et option Annuler
785
+ - ✅ **Alertes** (succès, avertissement, erreur) nécessitant une confirmation
786
+
787
+ #### CardView
788
+ - ✅ **Fiches produit** ou profils détaillés
789
+ - ✅ **Encarts de recommandations**
790
+ - ✅ **Résumé de compte** avec statistiques
791
+
792
+ #### CarouselView
793
+ - ✅ **Page d’accueil** avec bannières
794
+ - ✅ **Promotions** ou actualités multiples
795
+ - ✅ **Guides miniatures** à feuilleter
796
+
797
+ #### TimelineView
798
+ - ✅ **Suivi de dossier** étape par étape
799
+ - ✅ **Historique d’activités**
800
+ - ✅ **Roadmaps produit**
801
+
802
+ #### MediaView
803
+ - ✅ **Tutoriels vidéo**
804
+ - ✅ **Podcasts ou messages audio**
805
+ - ✅ **Playlists courtes** au sein de l’app
806
+
807
+ #### MapView
808
+ - ✅ **Points de vente** ou agences à proximité
809
+ - ✅ **Itinéraires** et zones de livraison
810
+ - ✅ **Visualisation de capteurs** (IoT, suivi terrain)
811
+
812
+ ### Erreurs Courantes à Éviter
813
+
814
+ ❌ **Erreur** : Utiliser `addField()` sur ReaderView
815
+ ```typescript
816
+ // FAUX - addField() n'existe pas sur ReaderView
817
+ const reader = new ReaderView('profile', 'Profile')
818
+ .addField('name', 'text', 'Name', 'John'); // ❌ ERREUR
819
+ ```
820
+
821
+ ✅ **Correct** : Utiliser `addParagraph()` ou `addListField()`
822
+ ```typescript
823
+ // CORRECT
824
+ const reader = new ReaderView('profile', 'Profile')
825
+ .addParagraph('Name: John Doe') // ✅
826
+ .addListField(['Email: john@example.com', 'Phone: +123']); // ✅
827
+ ```
828
+
829
+ ❌ **Erreur** : Mauvais ordre des paramètres dans `addField()`
830
+ ```typescript
831
+ // FAUX - ordre inversé
832
+ form.addField('name', 'text', 'Full Name', true); // ❌
833
+ ```
834
+
835
+ ✅ **Correct** : fieldType en premier
836
+ ```typescript
837
+ // CORRECT
838
+ form.addField('text', 'name', 'Full Name', { required: true }); // ✅
839
+ // OU mieux : utiliser les méthodes helper
840
+ form.addTextField('name', 'Full Name', true); // ✅ Recommandé
841
+ ```
842
+
843
+ ## 🤝 Contribution
844
+
845
+ 1. Fork le projet
846
+ 2. Créez une branche feature (`git checkout -b feature/AmazingFeature`)
847
+ 3. Commit vos changements (`git commit -m 'Add some AmazingFeature'`)
848
+ 4. Push vers la branche (`git push origin feature/AmazingFeature`)
849
+ 5. Ouvrez une Pull Request
850
+
851
+ ## 📄 Licence
852
+
853
+ Ce projet est sous licence MIT. Voir le fichier `LICENSE` pour plus de détails.
854
+
855
+ ## 🆘 Support
856
+
857
+ Pour toute question ou problème :
858
+ - Ouvrez une issue sur GitHub
859
+ - Consultez la documentation
860
+ - Contactez l'équipe de développement
861
+
862
+ ---
863
+
864
+ **JSONApp SDK** - Génération d'interfaces JSON dynamiques simplifiée 🚀