@mostajs/audit 1.0.0 → 1.0.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.
package/README.md CHANGED
@@ -5,7 +5,23 @@
5
5
  [![npm version](https://img.shields.io/npm/v/@mostajs/audit.svg)](https://www.npmjs.com/package/@mostajs/audit)
6
6
  [![license](https://img.shields.io/npm/l/@mostajs/audit.svg)](LICENSE)
7
7
 
8
- Part of the [@mosta suite](https://mostajs.dev).
8
+ Part of the [@mosta suite](https://mostajs.dev). Depend de `@mostajs/orm` pour l'abstraction multi-dialecte (MongoDB, PostgreSQL, MySQL, SQLite, etc.).
9
+
10
+ ---
11
+
12
+ ## Table des matieres
13
+
14
+ 1. [Installation](#installation)
15
+ 2. [Quick Start](#quick-start)
16
+ 3. [Integration complete dans une nouvelle app](#integration-complete)
17
+ 4. [logAudit — Journalisation fire-and-forget](#logaudit)
18
+ 5. [getAuditUser — Extraction session](#getaudituser)
19
+ 6. [AuditLogRepository — Requetes avancees](#auditlogrepository)
20
+ 7. [createAuditHandlers — Route API factory](#createaudithandlers)
21
+ 8. [Schema et indexes](#schema-et-indexes)
22
+ 9. [Cas d'usage courants](#cas-dusage-courants)
23
+ 10. [API Reference](#api-reference)
24
+ 11. [Architecture](#architecture)
9
25
 
10
26
  ---
11
27
 
@@ -15,57 +31,624 @@ Part of the [@mosta suite](https://mostajs.dev).
15
31
  npm install @mostajs/audit @mostajs/orm
16
32
  ```
17
33
 
18
- ## Quick Start
19
-
20
- ### 1. Register the schema
34
+ `@mostajs/orm` est la seule dependance requise. Elle gere la connexion DB et les operations CRUD quel que soit le dialecte (MongoDB, PostgreSQL, MySQL, SQLite, etc.).
21
35
 
22
- ```typescript
23
- import { registerSchema } from '@mostajs/orm'
24
- import { AuditLogSchema } from '@mostajs/audit'
25
-
26
- registerSchema(AuditLogSchema)
27
- ```
36
+ ---
28
37
 
29
- ### 2. Log an audit event
38
+ ## Quick Start
30
39
 
31
40
  ```typescript
32
41
  import { logAudit } from '@mostajs/audit'
33
42
 
43
+ // Fire-and-forget — ne throw jamais, ne bloque jamais
34
44
  await logAudit({
35
- userId: session.user.id,
36
- userName: session.user.name,
45
+ userId: '507f1f77bcf86cd799439011',
46
+ userName: 'Dr Madani',
37
47
  userRole: 'admin',
38
48
  action: 'create',
39
49
  module: 'users',
40
50
  resource: 'User',
41
- resourceId: newUser.id,
51
+ resourceId: 'abc123',
52
+ details: { email: 'new@example.com' },
53
+ })
54
+ ```
55
+
56
+ C'est tout. Le schema est auto-enregistre dans l'ORM, la table/collection est creee automatiquement.
57
+
58
+ ---
59
+
60
+ ## Integration complete
61
+
62
+ Guide pas-a-pas pour integrer `@mostajs/audit` dans une nouvelle application Next.js.
63
+
64
+ ### Etape 1 — Installer les packages
65
+
66
+ ```bash
67
+ npm install @mostajs/audit @mostajs/orm
68
+ ```
69
+
70
+ ### Etape 2 — Configurer la connexion DB
71
+
72
+ L'ORM doit etre configure avant d'utiliser audit. Dans votre `.env.local` :
73
+
74
+ ```env
75
+ DATABASE_URL=mongodb://localhost:27017/myapp
76
+ # ou: DATABASE_URL=postgres://user:pass@localhost:5432/myapp
77
+ # ou: DATABASE_URL=sqlite:./data/myapp.db
78
+ ```
79
+
80
+ Initialiser l'ORM (une seule fois, au demarrage) :
81
+
82
+ ```typescript
83
+ // src/lib/db.ts
84
+ import { initDialect } from '@mostajs/orm'
85
+
86
+ let initialized = false
87
+
88
+ export async function ensureDB() {
89
+ if (initialized) return
90
+ await initDialect(process.env.DATABASE_URL!)
91
+ initialized = true
92
+ }
93
+ ```
94
+
95
+ ### Etape 3 — Utiliser logAudit dans vos routes API
96
+
97
+ ```typescript
98
+ // src/app/api/products/route.ts
99
+ import { NextRequest, NextResponse } from 'next/server'
100
+ import { logAudit, getAuditUser } from '@mostajs/audit/lib/audit'
101
+ import { ensureDB } from '@/lib/db'
102
+ import { getServerSession } from 'next-auth'
103
+
104
+ export async function POST(req: NextRequest) {
105
+ await ensureDB()
106
+ const session = await getServerSession()
107
+ if (!session) {
108
+ return NextResponse.json({ error: 'Non autorise' }, { status: 401 })
109
+ }
110
+
111
+ const body = await req.json()
112
+
113
+ // ... creer le produit dans la DB ...
114
+ const product = { id: 'prod_123', name: body.name }
115
+
116
+ // Journaliser l'action — fire-and-forget
117
+ await logAudit({
118
+ ...getAuditUser(session),
119
+ action: 'create',
120
+ module: 'products',
121
+ resource: 'Product',
122
+ resourceId: product.id,
123
+ details: { name: product.name },
124
+ })
125
+
126
+ return NextResponse.json({ data: product })
127
+ }
128
+ ```
129
+
130
+ ### Etape 4 — Route de consultation des logs
131
+
132
+ ```typescript
133
+ // src/app/api/admin/audit/route.ts
134
+ import { createAuditHandlers } from '@mostajs/audit/api/route'
135
+ import { checkPermission } from '@/lib/auth'
136
+
137
+ export const { GET } = createAuditHandlers('audit:view', checkPermission)
138
+ ```
139
+
140
+ Cette route expose `GET /api/admin/audit` avec pagination et filtres automatiques.
141
+
142
+ ### Etape 5 — Page d'administration (frontend)
143
+
144
+ ```tsx
145
+ 'use client'
146
+ import { useState, useEffect } from 'react'
147
+
148
+ interface AuditLog {
149
+ id: string
150
+ userName: string
151
+ action: string
152
+ module: string
153
+ resource: string
154
+ timestamp: string
155
+ status: 'success' | 'failure'
156
+ }
157
+
158
+ export default function AuditPage() {
159
+ const [logs, setLogs] = useState<AuditLog[]>([])
160
+ const [meta, setMeta] = useState({ total: 0, page: 1, pages: 1 })
161
+ const [module, setModule] = useState('')
162
+
163
+ async function fetchLogs(page = 1) {
164
+ const params = new URLSearchParams({ page: String(page), limit: '20' })
165
+ if (module) params.set('module', module)
166
+
167
+ const res = await fetch(`/api/admin/audit?${params}`)
168
+ const json = await res.json()
169
+ setLogs(json.data)
170
+ setMeta(json.meta)
171
+ }
172
+
173
+ useEffect(() => { fetchLogs() }, [module])
174
+
175
+ return (
176
+ <div>
177
+ <h1>Journal d'audit</h1>
178
+
179
+ {/* Filtre par module */}
180
+ <select value={module} onChange={e => setModule(e.target.value)}>
181
+ <option value="">Tous les modules</option>
182
+ <option value="users">Utilisateurs</option>
183
+ <option value="products">Produits</option>
184
+ <option value="orders">Commandes</option>
185
+ </select>
186
+
187
+ {/* Table des logs */}
188
+ <table>
189
+ <thead>
190
+ <tr>
191
+ <th>Date</th>
192
+ <th>Utilisateur</th>
193
+ <th>Action</th>
194
+ <th>Module</th>
195
+ <th>Ressource</th>
196
+ <th>Statut</th>
197
+ </tr>
198
+ </thead>
199
+ <tbody>
200
+ {logs.map(log => (
201
+ <tr key={log.id}>
202
+ <td>{new Date(log.timestamp).toLocaleString()}</td>
203
+ <td>{log.userName}</td>
204
+ <td>{log.action}</td>
205
+ <td>{log.module}</td>
206
+ <td>{log.resource}</td>
207
+ <td>{log.status}</td>
208
+ </tr>
209
+ ))}
210
+ </tbody>
211
+ </table>
212
+
213
+ {/* Pagination */}
214
+ <div>
215
+ <button
216
+ disabled={meta.page <= 1}
217
+ onClick={() => fetchLogs(meta.page - 1)}
218
+ >Precedent</button>
219
+ <span>Page {meta.page} / {meta.pages} ({meta.total} total)</span>
220
+ <button
221
+ disabled={meta.page >= meta.pages}
222
+ onClick={() => fetchLogs(meta.page + 1)}
223
+ >Suivant</button>
224
+ </div>
225
+ </div>
226
+ )
227
+ }
228
+ ```
229
+
230
+ ### Etape 6 — Verification
231
+
232
+ ```bash
233
+ # Demarrer l'app
234
+ npm run dev
235
+
236
+ # Creer un produit (declenche un audit log)
237
+ curl -X POST http://localhost:3000/api/products \
238
+ -H 'Content-Type: application/json' \
239
+ -d '{"name": "Widget"}'
240
+
241
+ # Consulter les logs
242
+ curl 'http://localhost:3000/api/admin/audit?limit=5'
243
+ ```
244
+
245
+ Reponse attendue :
246
+
247
+ ```json
248
+ {
249
+ "data": [
250
+ {
251
+ "id": "...",
252
+ "userName": "Dr Madani",
253
+ "userRole": "admin",
254
+ "action": "create",
255
+ "module": "products",
256
+ "resource": "Product",
257
+ "resourceId": "prod_123",
258
+ "details": { "name": "Widget" },
259
+ "status": "success",
260
+ "timestamp": "2026-03-05T14:30:00.000Z"
261
+ }
262
+ ],
263
+ "meta": { "total": 1, "page": 1, "limit": 5, "pages": 1 }
264
+ }
265
+ ```
266
+
267
+ ---
268
+
269
+ ## logAudit
270
+
271
+ ```typescript
272
+ import { logAudit } from '@mostajs/audit/lib/audit'
273
+ ```
274
+
275
+ Journalise une action. **Fire-and-forget** : ne throw jamais, ne bloque jamais. Si l'ecriture echoue, l'erreur est loggee dans la console sans interrompre le flux.
276
+
277
+ ```typescript
278
+ await logAudit({
279
+ userId: '507f1f77bcf86cd799439011',
280
+ userName: 'Alice',
281
+ userRole: 'manager',
282
+ action: 'update',
283
+ module: 'clients',
284
+ resource: 'Client',
285
+ resourceId: 'cli_456',
286
+ details: { field: 'status', oldValue: 'active', newValue: 'suspended' },
287
+ ipAddress: '192.168.1.100',
288
+ status: 'success', // 'success' | 'failure' (defaut: 'success')
289
+ })
290
+ ```
291
+
292
+ ### Parametres (AuditParams)
293
+
294
+ | Champ | Type | Requis | Description |
295
+ |-------|------|--------|-------------|
296
+ | `userId` | `string` | oui | ID de l'utilisateur |
297
+ | `userName` | `string` | oui | Nom affichable |
298
+ | `userRole` | `string` | oui | Role (admin, manager, etc.) |
299
+ | `action` | `string` | oui | Action effectuee (create, update, delete, login, etc.) |
300
+ | `module` | `string` | oui | Module concerne (users, clients, lockers, etc.) |
301
+ | `resource` | `string` | non | Type de ressource (User, Client, etc.) |
302
+ | `resourceId` | `string` | non | ID de la ressource |
303
+ | `details` | `Record<string, any>` | non | Donnees supplementaires |
304
+ | `ipAddress` | `string` | non | Adresse IP du client |
305
+ | `status` | `'success' \| 'failure'` | non | Resultat (defaut: `'success'`) |
306
+
307
+ ---
308
+
309
+ ## getAuditUser
310
+
311
+ ```typescript
312
+ import { getAuditUser } from '@mostajs/audit/lib/audit'
313
+ ```
314
+
315
+ Extrait `userId`, `userName` et `userRole` d'une session NextAuth. Compatible avec tout objet session ayant `session.user.id`, `session.user.name` et `session.user.role`.
316
+
317
+ ```typescript
318
+ const session = await getServerSession()
319
+
320
+ await logAudit({
321
+ ...getAuditUser(session), // { userId, userName, userRole }
322
+ action: 'delete',
323
+ module: 'products',
324
+ resourceId: productId,
325
+ })
326
+ ```
327
+
328
+ Le helper gere les cas :
329
+ - `session.user.role` (string) → utilise directement
330
+ - `session.user.roles` (array) → joint avec `, `
331
+ - Ni l'un ni l'autre → `'unknown'`
332
+ - `session.user.name` absent → utilise `session.user.email`
333
+
334
+ ---
335
+
336
+ ## AuditLogRepository
337
+
338
+ ```typescript
339
+ import { AuditLogRepository } from '@mostajs/audit'
340
+ import { getDialect } from '@mostajs/orm'
341
+
342
+ const repo = new AuditLogRepository(await getDialect())
343
+ ```
344
+
345
+ ### findPaginated(filters)
346
+
347
+ Recherche paginee avec filtres optionnels.
348
+
349
+ ```typescript
350
+ const { data, total } = await repo.findPaginated({
351
+ module: 'users', // Filtrer par module
352
+ action: 'delete', // Filtrer par action (regex, case-insensitive)
353
+ userId: '507f1f77...', // Filtrer par utilisateur
354
+ status: 'failure', // Filtrer par statut
355
+ from: new Date('2026-01-01'), // Date debut
356
+ to: new Date('2026-03-01'), // Date fin
357
+ page: 2, // Page (defaut: 1)
358
+ limit: 20, // Limite (defaut: 50)
42
359
  })
360
+
361
+ console.log(`${total} logs trouves, page 2`)
362
+ data.forEach(log => console.log(log.action, log.module, log.timestamp))
363
+ ```
364
+
365
+ ### findByResource(resourceId, modules?)
366
+
367
+ Tous les logs lies a une ressource specifique.
368
+
369
+ ```typescript
370
+ // Tous les logs du client CLI_123
371
+ const logs = await repo.findByResource('CLI_123')
372
+
373
+ // Logs du client CLI_123 dans les modules 'clients' et 'lockers'
374
+ const filtered = await repo.findByResource('CLI_123', ['clients', 'lockers'])
375
+ ```
376
+
377
+ ### deleteOlderThan(days)
378
+
379
+ Nettoyage des anciens logs. Utile en cron job ou maintenance.
380
+
381
+ ```typescript
382
+ // Supprimer les logs de plus de 90 jours
383
+ const deleted = await repo.deleteOlderThan(90)
384
+ console.log(`${deleted} logs supprimes`)
385
+ ```
386
+
387
+ ---
388
+
389
+ ## createAuditHandlers
390
+
391
+ ```typescript
392
+ import { createAuditHandlers } from '@mostajs/audit/api/route'
43
393
  ```
44
394
 
45
- ### 3. Query audit logs (API route)
395
+ Factory pour creer une route `GET` paginee avec controle d'acces.
46
396
 
47
397
  ```typescript
48
- import { createAuditHandlers } from '@mostajs/audit'
398
+ // src/app/api/admin/audit/route.ts
399
+ import { createAuditHandlers } from '@mostajs/audit/api/route'
49
400
  import { checkPermission } from '@/lib/auth'
50
401
 
51
402
  export const { GET } = createAuditHandlers('audit:view', checkPermission)
52
403
  ```
53
404
 
405
+ ### Signature du checkPermission attendu
406
+
407
+ ```typescript
408
+ type PermissionChecker = (permission: string) => Promise<{
409
+ error: NextResponse | null // null = autorise
410
+ session: any // session utilisateur
411
+ }>
412
+ ```
413
+
414
+ ### Query params supportes
415
+
416
+ | Param | Type | Description |
417
+ |-------|------|-------------|
418
+ | `module` | string | Filtrer par module |
419
+ | `action` | string | Filtrer par action (regex) |
420
+ | `userId` | string | Filtrer par utilisateur |
421
+ | `status` | `success \| failure` | Filtrer par statut |
422
+ | `from` | ISO date | Date debut |
423
+ | `to` | ISO date | Date fin |
424
+ | `page` | number | Numero de page (defaut: 1) |
425
+ | `limit` | number | Elements par page (defaut: 50) |
426
+
427
+ ### Exemples de requetes
428
+
429
+ ```bash
430
+ # Tous les logs, page 1
431
+ GET /api/admin/audit
432
+
433
+ # Logs du module 'users', page 2, 20 par page
434
+ GET /api/admin/audit?module=users&page=2&limit=20
435
+
436
+ # Logs en echec du dernier mois
437
+ GET /api/admin/audit?status=failure&from=2026-02-01&to=2026-03-01
438
+
439
+ # Logs d'un utilisateur specifique
440
+ GET /api/admin/audit?userId=507f1f77bcf86cd799439011
441
+ ```
442
+
443
+ ---
444
+
445
+ ## Schema et indexes
446
+
447
+ La collection/table `auditlogs` est creee automatiquement avec le schema suivant :
448
+
449
+ | Champ | Type | Requis | Defaut |
450
+ |-------|------|--------|--------|
451
+ | `userId` | relation → User | oui | — |
452
+ | `userName` | string | oui | — |
453
+ | `userRole` | string | oui | — |
454
+ | `action` | string | oui | — |
455
+ | `module` | string | oui | — |
456
+ | `resource` | string | non | `''` |
457
+ | `resourceId` | string | non | `''` |
458
+ | `details` | json | non | — |
459
+ | `ipAddress` | string | non | `''` |
460
+ | `status` | enum: success, failure | non | `'success'` |
461
+ | `timestamp` | date | non | `now` |
462
+
463
+ ### Indexes
464
+
465
+ | Index | Champs | Usage |
466
+ |-------|--------|-------|
467
+ | 1 | `{ timestamp: desc }` | Tri chronologique |
468
+ | 2 | `{ module: asc, timestamp: desc }` | Filtrage par module |
469
+ | 3 | `{ userId: asc, timestamp: desc }` | Historique utilisateur |
470
+
471
+ Compatible avec tous les dialectes supportes par `@mostajs/orm` (MongoDB, PostgreSQL, MySQL, SQLite, MariaDB, MSSQL, Oracle, etc.).
472
+
473
+ ---
474
+
475
+ ## Cas d'usage courants
476
+
477
+ ### Auditer les operations CRUD
478
+
479
+ ```typescript
480
+ // Dans chaque route API
481
+ export async function POST(req: NextRequest) {
482
+ const { error, session } = await checkPermission(PERMISSIONS.CLIENT_CREATE)
483
+ if (error) return error
484
+
485
+ const data = await req.json()
486
+ const client = await clientRepo.create(data)
487
+
488
+ // Audit
489
+ await logAudit({
490
+ ...getAuditUser(session),
491
+ action: 'create',
492
+ module: 'clients',
493
+ resource: 'Client',
494
+ resourceId: client.id,
495
+ details: { firstName: data.firstName, lastName: data.lastName },
496
+ })
497
+
498
+ return NextResponse.json({ data: client })
499
+ }
500
+ ```
501
+
502
+ ### Auditer les connexions
503
+
504
+ ```typescript
505
+ // Dans le callback NextAuth signIn
506
+ import { logAudit } from '@mostajs/audit/lib/audit'
507
+
508
+ callbacks: {
509
+ async signIn({ user }) {
510
+ await logAudit({
511
+ userId: user.id,
512
+ userName: user.name || user.email,
513
+ userRole: user.role || 'user',
514
+ action: 'login',
515
+ module: 'auth',
516
+ })
517
+ return true
518
+ }
519
+ }
520
+ ```
521
+
522
+ ### Auditer les echecs
523
+
524
+ ```typescript
525
+ try {
526
+ await dangerousOperation()
527
+ await logAudit({ ...getAuditUser(session), action: 'export_data', module: 'reports', status: 'success' })
528
+ } catch (err) {
529
+ await logAudit({ ...getAuditUser(session), action: 'export_data', module: 'reports', status: 'failure', details: { error: err.message } })
530
+ throw err
531
+ }
532
+ ```
533
+
534
+ ### Nettoyage automatique (cron)
535
+
536
+ ```typescript
537
+ // src/app/api/cron/cleanup-audit/route.ts
538
+ import { AuditLogRepository } from '@mostajs/audit'
539
+ import { getDialect } from '@mostajs/orm'
540
+
541
+ export async function POST() {
542
+ const repo = new AuditLogRepository(await getDialect())
543
+ const deleted = await repo.deleteOlderThan(180) // 6 mois
544
+ return Response.json({ data: { deleted } })
545
+ }
546
+ ```
547
+
548
+ ### Historique d'une ressource
549
+
550
+ ```typescript
551
+ // src/app/api/clients/[id]/history/route.ts
552
+ import { AuditLogRepository } from '@mostajs/audit'
553
+ import { getDialect } from '@mostajs/orm'
554
+
555
+ export async function GET(req: Request, { params }: { params: { id: string } }) {
556
+ const repo = new AuditLogRepository(await getDialect())
557
+ const logs = await repo.findByResource(params.id, ['clients', 'lockers', 'rfid'])
558
+ return Response.json({ data: logs })
559
+ }
560
+ ```
561
+
562
+ ---
563
+
54
564
  ## API Reference
55
565
 
56
- | Export | Description |
57
- |--------|-------------|
58
- | `logAudit(params)` | Fire-and-forget audit entry |
59
- | `getAuditUser(session)` | Extract user info from NextAuth session |
60
- | `AuditLogRepository` | Repository with `findPaginated()`, `findByResource()`, `deleteOlderThan()` |
61
- | `AuditLogSchema` | Entity schema for registration |
62
- | `createAuditHandlers()` | API route factory for paginated consultation |
566
+ ### Core
567
+
568
+ | Export | Import | Description |
569
+ |--------|--------|-------------|
570
+ | `logAudit(params)` | `@mostajs/audit/lib/audit` | Fire-and-forget audit logging |
571
+ | `getAuditUser(session)` | `@mostajs/audit/lib/audit` | Extraire userId/userName/userRole |
572
+
573
+ ### Data Layer
63
574
 
64
- ## Related Packages
575
+ | Export | Import | Description |
576
+ |--------|--------|-------------|
577
+ | `AuditLogRepository` | `@mostajs/audit` | Repository avec findPaginated, findByResource, deleteOlderThan |
578
+ | `AuditLogSchema` | `@mostajs/audit` | Schema d'entite ORM |
579
+
580
+ ### Route Factory
581
+
582
+ | Export | Import | Description |
583
+ |--------|--------|-------------|
584
+ | `createAuditHandlers(perm, checker)` | `@mostajs/audit/api/route` | Factory GET pagine avec auth |
585
+
586
+ ### Types
587
+
588
+ | Type | Description |
589
+ |------|-------------|
590
+ | `AuditParams` | Parametres de logAudit() |
591
+ | `AuditFilters` | Filtres pour findPaginated() |
592
+ | `AuditLogDTO` | Objet retourne (id, userName, action, module, timestamp, ...) |
593
+ | `MostaAuditConfig` | Config optionnelle (modules, actions connus) |
594
+
595
+ ---
65
596
 
66
- - [@mostajs/orm](https://www.npmjs.com/package/@mostajs/orm) — Multi-dialect ORM (required)
67
- - [@mostajs/auth](https://www.npmjs.com/package/@mostajs/auth) — Authentication & RBAC
597
+ ## Architecture
598
+
599
+ ```
600
+ @mostajs/audit
601
+ ├── lib/
602
+ │ └── audit.ts # logAudit() + getAuditUser()
603
+ ├── api/
604
+ │ └── route.ts # createAuditHandlers() factory
605
+ ├── repositories/
606
+ │ └── audit-log.repository.ts # findPaginated, findByResource, deleteOlderThan
607
+ ├── schemas/
608
+ │ └── audit-log.schema.ts # EntitySchema ORM (collection: auditlogs)
609
+ ├── types/
610
+ │ └── index.ts # AuditParams, AuditFilters, AuditLogDTO
611
+ └── index.ts # Barrel exports
612
+
613
+ Dependances :
614
+ @mostajs/orm (required — abstraction DB multi-dialecte)
615
+ next >= 14 (peer, optionnel — pour createAuditHandlers)
616
+ ```
617
+
618
+ ### Pattern d'injection
619
+
620
+ ```
621
+ ┌─────────────────────┐ inject permission ┌──────────────────────┐
622
+ │ @mostajs/audit │ ◄───────────────────────── │ Votre app │
623
+ │ │ │ │
624
+ │ createAuditHandlers(│ │ 'audit:view', │
625
+ │ permission, │ │ checkPermission │
626
+ │ checkPermission │ │ │
627
+ │ ) │ │ │
628
+ └─────────────────────┘ └──────────────────────┘
629
+
630
+ ┌─────────────────────┐ call anywhere ┌──────────────────────┐
631
+ │ logAudit({...}) │ ◄───────────────────────── │ Route API, callback, │
632
+ │ fire-and-forget │ │ middleware, cron... │
633
+ └─────────────────────┘ └──────────────────────┘
634
+ ```
635
+
636
+ Modifications effectuees :
637
+
638
+ 1. README.md — Tutoriel complet avec :
639
+ - Integration pas-a-pas dans une nouvelle app (6 etapes)
640
+ - Documentation detaillee de logAudit, getAuditUser, AuditLogRepository,
641
+ createAuditHandlers
642
+ - Schema et indexes documentes
643
+ - 5 cas d'usage courants (CRUD, login, echecs, cron cleanup, historique
644
+ ressource)
645
+ - API Reference, architecture ASCII, pattern d'injection
646
+ 2. package.json — Ajout des subpath exports manquants : ./lib/*, ./api/*, ./types
647
+ (corrige l'import @mostajs/audit/lib/audit utilise dans 15 routes de l'app)
648
+
649
+
650
+ ---
68
651
 
69
652
  ## License
70
653
 
71
- MIT — © 2025 Dr Hamid MADANI <drmdh@msn.com>
654
+ MIT — Dr Hamid MADANI <drmdh@msn.com>
package/dist/api/route.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  // @mosta/audit — API Route template
3
2
  // Author: Dr Hamid MADANI drmdh@msn.com
4
3
  //
@@ -7,15 +6,13 @@
7
6
  // import { createAuditHandlers } from '@mosta/audit/api/route'
8
7
  // import { checkPermission } from '@mosta/auth'
9
8
  // export const { GET } = createAuditHandlers('audit:view', checkPermission)
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.createAuditHandlers = createAuditHandlers;
12
- const server_1 = require("next/server");
13
- const orm_1 = require("@mostajs/orm");
14
- const audit_log_repository_1 = require("../repositories/audit-log.repository");
9
+ import { NextResponse } from 'next/server';
10
+ import { getDialect } from '@mostajs/orm';
11
+ import { AuditLogRepository } from '../repositories/audit-log.repository';
15
12
  /**
16
13
  * Creates a GET handler for paginated audit log consultation.
17
14
  */
18
- function createAuditHandlers(permission, checkPermission) {
15
+ export function createAuditHandlers(permission, checkPermission) {
19
16
  async function GET(req) {
20
17
  const { error } = await checkPermission(permission);
21
18
  if (error)
@@ -31,9 +28,9 @@ function createAuditHandlers(permission, checkPermission) {
31
28
  page: parseInt(url.searchParams.get('page') || '1', 10),
32
29
  limit: parseInt(url.searchParams.get('limit') || '50', 10),
33
30
  };
34
- const repo = new audit_log_repository_1.AuditLogRepository(await (0, orm_1.getDialect)());
31
+ const repo = new AuditLogRepository(await getDialect());
35
32
  const { data, total } = await repo.findPaginated(filters);
36
- return server_1.NextResponse.json({
33
+ return NextResponse.json({
37
34
  data,
38
35
  meta: {
39
36
  total,
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { logAudit, getAuditUser } from './lib/audit';
2
2
  export { AuditLogRepository } from './repositories/audit-log.repository';
3
3
  export { AuditLogSchema } from './schemas/audit-log.schema';
4
4
  export { createAuditHandlers } from './api/route';
5
- export type { MostaAuditConfig, AuditParams, AuditFilters, AuditLogDTO, } from './types';
5
+ export type { MostaAuditConfig, AuditParams, AuditFilters, AuditLogDTO, } from './types/index';
package/dist/index.js CHANGED
@@ -1,17 +1,9 @@
1
- "use strict";
2
1
  // @mosta/audit — Barrel exports
3
2
  // Author: Dr Hamid MADANI drmdh@msn.com
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.createAuditHandlers = exports.AuditLogSchema = exports.AuditLogRepository = exports.getAuditUser = exports.logAudit = void 0;
6
3
  // Core
7
- var audit_1 = require("./lib/audit");
8
- Object.defineProperty(exports, "logAudit", { enumerable: true, get: function () { return audit_1.logAudit; } });
9
- Object.defineProperty(exports, "getAuditUser", { enumerable: true, get: function () { return audit_1.getAuditUser; } });
4
+ export { logAudit, getAuditUser } from './lib/audit';
10
5
  // Repository & Schema
11
- var audit_log_repository_1 = require("./repositories/audit-log.repository");
12
- Object.defineProperty(exports, "AuditLogRepository", { enumerable: true, get: function () { return audit_log_repository_1.AuditLogRepository; } });
13
- var audit_log_schema_1 = require("./schemas/audit-log.schema");
14
- Object.defineProperty(exports, "AuditLogSchema", { enumerable: true, get: function () { return audit_log_schema_1.AuditLogSchema; } });
6
+ export { AuditLogRepository } from './repositories/audit-log.repository';
7
+ export { AuditLogSchema } from './schemas/audit-log.schema';
15
8
  // API helpers
16
- var route_1 = require("./api/route");
17
- Object.defineProperty(exports, "createAuditHandlers", { enumerable: true, get: function () { return route_1.createAuditHandlers; } });
9
+ export { createAuditHandlers } from './api/route';
@@ -1,4 +1,4 @@
1
- import type { AuditParams } from '../types';
1
+ import type { AuditParams } from '../types/index';
2
2
  /**
3
3
  * Log an audit entry. Fire-and-forget — never throws, never blocks.
4
4
  */
package/dist/lib/audit.js CHANGED
@@ -1,17 +1,16 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.logAudit = logAudit;
4
- exports.getAuditUser = getAuditUser;
5
1
  // @mosta/audit — Core audit functions
6
2
  // Author: Dr Hamid MADANI drmdh@msn.com
7
- const orm_1 = require("@mostajs/orm");
8
- const audit_log_repository_1 = require("../repositories/audit-log.repository");
3
+ import { getDialect, registerSchemas } from '@mostajs/orm';
4
+ import { AuditLogRepository } from '../repositories/audit-log.repository';
5
+ import { AuditLogSchema } from '../schemas/audit-log.schema';
6
+ // Auto-register audit schema into ORM registry (idempotent)
7
+ registerSchemas([AuditLogSchema]);
9
8
  /**
10
9
  * Log an audit entry. Fire-and-forget — never throws, never blocks.
11
10
  */
12
- async function logAudit(params) {
11
+ export async function logAudit(params) {
13
12
  try {
14
- const repo = new audit_log_repository_1.AuditLogRepository(await (0, orm_1.getDialect)());
13
+ const repo = new AuditLogRepository(await getDialect());
15
14
  await repo.create({
16
15
  userId: params.userId,
17
16
  userName: params.userName,
@@ -33,7 +32,7 @@ async function logAudit(params) {
33
32
  /**
34
33
  * Extract audit user info from a NextAuth-style session.
35
34
  */
36
- function getAuditUser(session) {
35
+ export function getAuditUser(session) {
37
36
  const { role, roles } = session.user;
38
37
  return {
39
38
  userId: session.user.id,
@@ -1,6 +1,6 @@
1
1
  import { BaseRepository } from '@mostajs/orm';
2
2
  import type { IDialect, QueryOptions } from '@mostajs/orm';
3
- import type { AuditLogDTO, AuditFilters } from '../types';
3
+ import type { AuditLogDTO, AuditFilters } from '../types/index';
4
4
  export declare class AuditLogRepository extends BaseRepository<AuditLogDTO> {
5
5
  constructor(dialect: IDialect);
6
6
  /** Find paginated audit logs with optional filters */
@@ -1,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AuditLogRepository = void 0;
4
1
  // @mosta/audit — AuditLogRepository
5
2
  // Author: Dr Hamid MADANI drmdh@msn.com
6
- const orm_1 = require("@mostajs/orm");
7
- const audit_log_schema_1 = require("../schemas/audit-log.schema");
8
- class AuditLogRepository extends orm_1.BaseRepository {
3
+ import { BaseRepository } from '@mostajs/orm';
4
+ import { AuditLogSchema } from '../schemas/audit-log.schema';
5
+ export class AuditLogRepository extends BaseRepository {
9
6
  constructor(dialect) {
10
- super(audit_log_schema_1.AuditLogSchema, dialect);
7
+ super(AuditLogSchema, dialect);
11
8
  }
12
9
  /** Find paginated audit logs with optional filters */
13
10
  async findPaginated(filters = {}, options) {
@@ -50,4 +47,3 @@ class AuditLogRepository extends orm_1.BaseRepository {
50
47
  return this.deleteMany({ timestamp: { $lt: cutoff } });
51
48
  }
52
49
  }
53
- exports.AuditLogRepository = AuditLogRepository;
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AuditLogSchema = void 0;
4
- exports.AuditLogSchema = {
1
+ export const AuditLogSchema = {
5
2
  name: 'AuditLog',
6
3
  collection: 'auditlogs',
7
4
  timestamps: false,
@@ -1,8 +1,4 @@
1
1
  export interface MostaAuditConfig {
2
- /** Collection/table name (default: 'auditlogs') */
3
- collection?: string;
4
- /** Retention in days, 0 = unlimited (default: 0) */
5
- retentionDays?: number;
6
2
  /** Known modules for UI filters */
7
3
  modules?: string[];
8
4
  /** Known actions for UI filters */
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  // @mosta/audit — Types
3
2
  // Author: Dr Hamid MADANI drmdh@msn.com
4
- Object.defineProperty(exports, "__esModule", { value: true });
3
+ export {};
package/package.json CHANGED
@@ -1,30 +1,54 @@
1
1
  {
2
2
  "name": "@mostajs/audit",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Reusable audit logging module — fire-and-forget logAudit() with paginated consultation",
5
5
  "author": "Dr Hamid MADANI <drmdh@msn.com>",
6
6
  "license": "MIT",
7
+ "type": "module",
7
8
  "main": "dist/index.js",
8
9
  "types": "dist/index.d.ts",
9
10
  "exports": {
10
11
  ".": {
11
12
  "types": "./dist/index.d.ts",
12
13
  "import": "./dist/index.js",
13
- "require": "./dist/index.js",
14
14
  "default": "./dist/index.js"
15
15
  },
16
+ "./lib/audit": {
17
+ "types": "./dist/lib/audit.d.ts",
18
+ "import": "./dist/lib/audit.js",
19
+ "default": "./dist/lib/audit.js"
20
+ },
16
21
  "./api/route": {
17
22
  "types": "./dist/api/route.d.ts",
18
23
  "import": "./dist/api/route.js",
19
- "require": "./dist/api/route.js",
20
24
  "default": "./dist/api/route.js"
25
+ },
26
+ "./types": {
27
+ "types": "./dist/types/index.d.ts",
28
+ "import": "./dist/types/index.js",
29
+ "default": "./dist/types/index.js"
21
30
  }
22
31
  },
23
- "files": ["dist", "LICENSE", "README.md"],
24
- "keywords": ["audit", "audit-log", "logging", "nextjs", "mosta"],
25
- "repository": { "type": "git", "url": "https://github.com/apolocine/mosta-audit" },
32
+ "files": [
33
+ "dist",
34
+ "LICENSE",
35
+ "README.md"
36
+ ],
37
+ "keywords": [
38
+ "audit",
39
+ "audit-log",
40
+ "logging",
41
+ "nextjs",
42
+ "mosta"
43
+ ],
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "https://github.com/apolocine/mosta-audit"
47
+ },
26
48
  "homepage": "https://mostajs.dev/packages/audit",
27
- "engines": { "node": ">=18.0.0" },
49
+ "engines": {
50
+ "node": ">=18.0.0"
51
+ },
28
52
  "scripts": {
29
53
  "build": "tsc",
30
54
  "prepublishOnly": "npm run build"
@@ -37,12 +61,16 @@
37
61
  "react": ">=18"
38
62
  },
39
63
  "peerDependenciesMeta": {
40
- "next": { "optional": true },
41
- "react": { "optional": true }
64
+ "next": {
65
+ "optional": true
66
+ },
67
+ "react": {
68
+ "optional": true
69
+ }
42
70
  },
43
71
  "devDependencies": {
44
72
  "@types/react": "^19.0.0",
45
- "next": "^15.0.0",
73
+ "next": "^16.1.6",
46
74
  "react": "^19.0.0",
47
75
  "typescript": "^5.6.0"
48
76
  }