@mostajs/audit 2.2.1 → 2.3.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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { logAudit, getAuditUser } from './lib/audit';
2
+ export { configureAudit, getAuditRepo, resetAuditRepo, type IAuditLogRepository } from './lib/audit-factory';
2
3
  export { dlog, dwarn, createLogger, isDebugEnabled, type ScopedLogger } from './lib/debug-log';
3
4
  export { AuditLogRepository } from './repositories/audit-log.repository';
4
5
  export { AuditLogSchema } from './schemas/audit-log.schema';
package/dist/index.js CHANGED
@@ -2,6 +2,8 @@
2
2
  // Author: Dr Hamid MADANI drmdh@msn.com
3
3
  // Core
4
4
  export { logAudit, getAuditUser } from './lib/audit';
5
+ // Configuration (DI) : l'hôte injecte son dialecte ORM (depuis son .env) — voie recommandée.
6
+ export { configureAudit, getAuditRepo, resetAuditRepo } from './lib/audit-factory';
5
7
  // Volatile debug logger (complement de logAudit pour la trace pm2/stdout)
6
8
  export { dlog, dwarn, createLogger, isDebugEnabled } from './lib/debug-log';
7
9
  // Repository & Schema
@@ -8,7 +8,16 @@ export interface IAuditLogRepository {
8
8
  findByResource(resourceId: string, modules?: string[]): Promise<AuditLogDTO[]>;
9
9
  deleteOlderThan(days: number): Promise<number>;
10
10
  }
11
- /** Get audit repository — dialect resolved by octoswitcher (ORM or NET) */
11
+ /**
12
+ * Injection de dépendance (RECOMMANDÉ) : l'application hôte fournit SON dialecte ORM, construit
13
+ * depuis SON `.env`. C'est la voie la moins dépendante et la moins risquée — aucun résolveur,
14
+ * aucune seconde instance d'ORM (donc pas de double-package). Sans injection, repli sur
15
+ * `@mostajs/data-plug` (résolution depuis le `.env` de l'hôte).
16
+ */
17
+ export declare function configureAudit(opts: {
18
+ dialect: unknown;
19
+ }): void;
20
+ /** Get audit repository — dialecte injecté (DI) sinon résolu depuis le `.env` via data-plug. */
12
21
  export declare function getAuditRepo(): Promise<IAuditLogRepository>;
13
22
  /** Reset cache (for tests) */
14
23
  export declare function resetAuditRepo(): void;
@@ -1,26 +1,44 @@
1
1
  // audit-factory.ts — Centralized repository factory
2
- // Uses @mostajs/octoswitcher to get the right dialect (ORM or NET)
3
- // Author: Dr Hamid MADANI drmdh@msn.com
4
- import { AuditLogSchema } from '../schemas/audit-log.schema.js';
2
+ // DI-first : l'application hôte injecte SON dialecte (depuis SON .env). Repli optionnel sur
3
+ // @mostajs/data-plug (remplace @mostajs/octoswitcher). Aucune dépendance dure de résolveur.
4
+ // Author: Dr Hamid MADANI <drmdh@msn.com>
5
5
  // ============================================================
6
- // Factory — dialect resolved by octoswitcher
6
+ // Factory — DI-first, repli .env via data-plug
7
7
  // ============================================================
8
8
  let _cached = null;
9
- /** Get audit repository — dialect resolved by octoswitcher (ORM or NET) */
9
+ let _injectedDialect = null;
10
+ /**
11
+ * Injection de dépendance (RECOMMANDÉ) : l'application hôte fournit SON dialecte ORM, construit
12
+ * depuis SON `.env`. C'est la voie la moins dépendante et la moins risquée — aucun résolveur,
13
+ * aucune seconde instance d'ORM (donc pas de double-package). Sans injection, repli sur
14
+ * `@mostajs/data-plug` (résolution depuis le `.env` de l'hôte).
15
+ */
16
+ export function configureAudit(opts) {
17
+ if (opts && opts.dialect) {
18
+ _injectedDialect = opts.dialect;
19
+ _cached = null;
20
+ }
21
+ }
22
+ /** Get audit repository — dialecte injecté (DI) sinon résolu depuis le `.env` via data-plug. */
10
23
  export async function getAuditRepo() {
11
24
  if (_cached)
12
25
  return _cached;
13
- const { getDialect } = await import('@mostajs/octoswitcher');
14
- const { registerSchemas } = await import('@mostajs/orm');
15
26
  const { AuditLogRepository } = await import('../repositories/audit-log.repository.js');
16
- registerSchemas([AuditLogSchema]);
17
- const dialect = await getDialect();
18
- if (typeof dialect.initSchema === 'function') {
19
- const { getAllSchemas } = await import('@mostajs/orm');
20
- await dialect.initSchema(getAllSchemas());
27
+ // 1) Dialecte injecté par l'hôte (DI) — chemin principal, zéro dépendance résolveur.
28
+ if (_injectedDialect) {
29
+ _cached = new AuditLogRepository(_injectedDialect);
30
+ return _cached;
21
31
  }
32
+ // 2) Repli : résolution depuis le `.env` de l'hôte via @mostajs/data-plug (remplace octoswitcher).
33
+ // Import par spécifieur variable → dépendance OPTIONNELLE (inutile si l'hôte injecte).
34
+ const spec = '@mostajs/data-plug';
35
+ const mod = (await import(spec));
36
+ const dialect = await mod.getDialect();
22
37
  _cached = new AuditLogRepository(dialect);
23
38
  return _cached;
24
39
  }
25
40
  /** Reset cache (for tests) */
26
- export function resetAuditRepo() { _cached = null; }
41
+ export function resetAuditRepo() {
42
+ _cached = null;
43
+ _injectedDialect = null;
44
+ }
package/llms.txt ADDED
@@ -0,0 +1,130 @@
1
+ # @mostajs/audit — fiche LLM
2
+ > Journalisation d'audit fire-and-forget : logAudit() non bloquant + consultation paginée, stats, export CSV/JSON.
3
+
4
+ - Version: 2.2.2 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
5
+ - Chemin: mostajs/mosta-audit · Statut audit: complet (dist/)
6
+
7
+ ## RÔLE
8
+ Module de journalisation d'audit de l'écosystème mostajs. Expose un `logAudit()` fire-and-forget — il ne lève jamais d'exception et ne bloque jamais le flux appelant — pour tracer les actions métier (création, modification, suppression…). Fournit la consultation paginée et filtrée des logs (handler API Next.js), un export CSV/JSON, des statistiques agrégées, une page d'administration et un logger debug volatile complémentaire (stdout/pm2). Fonctionne en mode ORM ou NET selon `MOSTA_DATA`.
9
+
10
+ ## INSTALLATION
11
+ npm i @mostajs/audit @mostajs/orm
12
+
13
+ ## EXPORTS
14
+ Point d'entrée racine (`.`) :
15
+ - Core: logAudit, getAuditUser
16
+ - Debug logger: dlog, dwarn, createLogger, isDebugEnabled
17
+ - Repository/Schéma: AuditLogRepository, AuditLogSchema
18
+ - API: createAuditHandlers, createAuditExportHandler
19
+ - Export: auditToCsv, auditToJson
20
+ - Stats: getAuditStats
21
+ - Menu/i18n/Page: auditMenuContribution, auditT, AuditPage (default)
22
+ - Types: MostaAuditConfig, AuditParams, AuditFilters, AuditLogDTO, ExportOptions, AuditStats, ScopedLogger
23
+
24
+ ## EXPORTS PAR SOUS-CHEMIN
25
+ - `./lib/audit` — logAudit, getAuditUser
26
+ - `./api/route` — createAuditHandlers
27
+ - `./types` — MostaAuditConfig, AuditParams, AuditFilters, AuditLogDTO
28
+ - `./lib/menu` — auditMenuContribution
29
+ - `./register` — register(registry)
30
+ - `./pages/AuditPage` — page d'administration
31
+ - `./lib/i18n` — t (auditT)
32
+ - `./lib/module-info` — getSchemas, moduleInfo (pour @mostajs/setup)
33
+ - `./lib/export` — auditToCsv, auditToJson ; type ExportOptions
34
+ - `./lib/audit-stats` — getAuditStats ; type AuditStats
35
+ - `./lib/handlers/audit-export` — createAuditExportHandler
36
+ - `./lib/debug-log` — dlog, dwarn, createLogger, isDebugEnabled ; type ScopedLogger
37
+ - `./schemas/audit-log.schema` — AuditLogSchema
38
+ - `./repositories/audit-log.repository` — AuditLogRepository
39
+
40
+ ## API — SIGNATURES
41
+ logAudit(params: AuditParams): Promise<void> // fire-and-forget : ne throw jamais, ne bloque jamais
42
+ getAuditUser(session: any): { userId, userName, userRole } // extrait d'une session NextAuth
43
+ createAuditHandlers(permission: string, checkPermission: PermissionChecker): { GET } // consultation paginée
44
+ createAuditExportHandler(...) // handler d'export
45
+ auditToCsv(logs: any[]): string · auditToJson(logs: any[]): string
46
+ getAuditStats(repo: any, days?: number): Promise<AuditStats>
47
+ dlog(scope, data): void // actif si MOSTAJS_DEBUG=1 ou hors prod
48
+ dwarn(scope, data): void // toujours actif
49
+ createLogger(namespace: string): ScopedLogger // { dlog, dwarn }
50
+ isDebugEnabled(): boolean
51
+
52
+ AuditLogRepository extends BaseRepository<AuditLogDTO> (dialect: IDialect) :
53
+ findPaginated(filters?: AuditFilters, options?): Promise<{ data: AuditLogDTO[], total: number }>
54
+ findByResource(resourceId, modules?, options?): Promise<AuditLogDTO[]>
55
+ deleteOlderThan(days: number): Promise<number> // rétention / purge
56
+
57
+ PermissionChecker = (permission: string) => Promise<{ error: NextResponse|null, session: any }>
58
+
59
+ ## TYPES CLÉS
60
+ AuditParams { userId, userName, userRole, action, module, resource?, resourceId?, details?:Record<string,any>, ipAddress?, status?:'success'|'failure' }
61
+ AuditLogDTO { id, userId, userName, userRole, action, module, resource, resourceId, details:Record|null, ipAddress, status:'success'|'failure', timestamp }
62
+ AuditFilters { module?, action?, userId?, status?, from?:Date, to?:Date, page?, limit? }
63
+ MostaAuditConfig { modules?:string[], actions?:string[] } // valeurs pour les filtres UI
64
+ AuditStats { totalLogs, byModule:Record<string,number>, byAction:Record<string,number>, byStatus:{success,failure}, topUsers:[{userName,count}], recentErrors[] }
65
+ ExportOptions { format:'csv'|'json', from?, to?, module?, action?, limit? }
66
+ ScopedLogger { dlog(scope,data), dwarn(scope,data) }
67
+
68
+ ## PATTERN
69
+ ```ts
70
+ // Tracer une action
71
+ import { logAudit, getAuditUser } from '@mostajs/audit'
72
+ await logAudit({
73
+ ...getAuditUser(session),
74
+ action: 'user_create',
75
+ module: 'users',
76
+ resource: 'John Doe',
77
+ resourceId: user.id,
78
+ details: { email: 'john@x.com' },
79
+ status: 'success',
80
+ })
81
+
82
+ // Route de consultation Next.js
83
+ import { createAuditHandlers } from '@mostajs/audit/api/route'
84
+ export const { GET } = createAuditHandlers('audit:view', checkPermission)
85
+ // GET /api/audit-log?page=1&limit=50&module=users&action=create
86
+
87
+ // Purge de rétention
88
+ const repo = new AuditLogRepository(await getDialect())
89
+ await repo.deleteOlderThan(90)
90
+ ```
91
+
92
+ ## INTÉGRATION (DI-first, depuis le .env de l'hôte) — depuis 2.3.0
93
+ `getAuditRepo()`/`logAudit()` résolvent le dialecte ainsi :
94
+ 1. **Injecté** par l'hôte (RECOMMANDÉ) : `configureAudit({ dialect })` — zéro résolveur, copie ORM unique.
95
+ 2. **Repli** : `@mostajs/data-plug` (`getDialect()` lit le `.env` de l'hôte) — remplace octoswitcher, optionnel.
96
+ ```ts
97
+ import { configureAudit } from '@mostajs/audit' // ou '@mostajs/audit/lib/audit-factory'
98
+ import { logAudit } from '@mostajs/audit/lib/audit'
99
+ import { AuditLogSchema } from '@mostajs/audit/schemas/audit-log.schema'
100
+ import { AuditLogRepository } from '@mostajs/audit/repositories/audit-log.repository'
101
+
102
+ // 1) Ajouter AuditLogSchema à VOS schémas (migration crée la table `auditlogs`).
103
+ // ⚠ relation `userId → User` (m2o, requise) : l'hôte DOIT exposer un schéma `name:"User"`.
104
+ // 2) Injecter VOTRE dialecte (construit depuis VOTRE .env) — une fois :
105
+ configureAudit({ dialect: await getOrm() })
106
+ // 3) Tracer (fire-and-forget) :
107
+ await logAudit({ userId, userName, userRole, action: 'order.create', module: 'commandes', resource: '2026-…' })
108
+ // 4) Consulter : new AuditLogRepository(await getOrm()).findPaginated(filters) → { data, total } ; UI native.
109
+ ```
110
+ > En test : importer par SOUS-CHEMINS (la racine charge AuditPage → lucide-react). Voir @mostajs/mjs-unit.
111
+
112
+ ## DÉPEND DE (depuis 2.3.0 — « le moins dépendant »)
113
+ - **Aucune dépendance dure** (`dependencies: {}`).
114
+ - Peers : **@mostajs/orm** (requis — l'hôte le fournit → copie unique, pas de double-package) ;
115
+ **@mostajs/data-plug** (optionnel — uniquement pour le repli `.env`) ; @mostajs/menu/socle/ui, lucide-react,
116
+ next, react (tous optionnels, UI seulement).
117
+ - ❌ Retirés : @mostajs/net (inutilisé), @mostajs/octoswitcher (→ remplacé par data-plug, optionnel).
118
+
119
+ ## PIÈGES
120
+ - logAudit est volontairement fire-and-forget : il avale ses propres erreurs (échec d'écriture audit → silencieux). Ne pas s'en servir comme garantie transactionnelle ; ne pas l'attendre comme bloquant critique.
121
+ - logAudit ≠ debug-log : `logAudit` persiste en DB ; `dlog`/`dwarn` ne font que tracer en stdout (volatile, pour pm2). dlog n'est actif que si `MOSTAJS_DEBUG=1` ou hors production ; dwarn est toujours actif.
122
+ - createAuditHandlers exige une callback `checkPermission` (typiquement fournie par `@mostajs/auth`) ; le module ne gère pas la session.
123
+ - Le mode de données (ORM/NET) est piloté par `MOSTA_DATA` ; le repo factory interne lit l'environnement automatiquement.
124
+ - getAuditUser attend une session de forme NextAuth ; si la forme diffère, fournir manuellement userId/userName/userRole.
125
+ - deleteOlderThan supprime définitivement les lignes : prévoir l'archivage avant purge si rétention légale.
126
+
127
+ ## RÉFÉRENCES
128
+ - README.md (racine du module)
129
+ - audit.wire.json, wire.json — déclaration de câblage
130
+ - LICENSE (AGPL-3.0-or-later)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/audit",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
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": "AGPL-3.0-or-later",
@@ -67,6 +67,21 @@
67
67
  "types": "./dist/lib/handlers/audit-export.d.ts",
68
68
  "import": "./dist/lib/handlers/audit-export.js",
69
69
  "default": "./dist/lib/handlers/audit-export.js"
70
+ },
71
+ "./lib/debug-log": {
72
+ "types": "./dist/lib/debug-log.d.ts",
73
+ "import": "./dist/lib/debug-log.js",
74
+ "default": "./dist/lib/debug-log.js"
75
+ },
76
+ "./schemas/audit-log.schema": {
77
+ "types": "./dist/schemas/audit-log.schema.d.ts",
78
+ "import": "./dist/schemas/audit-log.schema.js",
79
+ "default": "./dist/schemas/audit-log.schema.js"
80
+ },
81
+ "./repositories/audit-log.repository": {
82
+ "types": "./dist/repositories/audit-log.repository.d.ts",
83
+ "import": "./dist/repositories/audit-log.repository.js",
84
+ "default": "./dist/repositories/audit-log.repository.js"
70
85
  }
71
86
  },
72
87
  "files": [
@@ -75,7 +90,8 @@
75
90
  "wire.json",
76
91
  "audit.wire.json",
77
92
  "LICENSE",
78
- "README.md"
93
+ "README.md",
94
+ "llms.txt"
79
95
  ],
80
96
  "keywords": [
81
97
  "audit",
@@ -92,17 +108,15 @@
92
108
  "engines": {
93
109
  "node": ">=18.0.0"
94
110
  },
95
- "scripts": {
96
- "build": "tsc",
97
- "prepublishOnly": "npm run build"
98
- },
99
111
  "peerDependencies": {
100
112
  "@mostajs/menu": ">=1.0.2",
101
113
  "@mostajs/socle": ">=2.0.0",
102
114
  "@mostajs/ui": ">=1.0.0",
103
115
  "lucide-react": ">=0.400.0",
104
116
  "next": ">=14",
105
- "react": ">=18"
117
+ "react": ">=18",
118
+ "@mostajs/orm": ">=1.7.0",
119
+ "@mostajs/data-plug": ">=1.0.0"
106
120
  },
107
121
  "peerDependenciesMeta": {
108
122
  "next": {
@@ -119,6 +133,12 @@
119
133
  },
120
134
  "lucide-react": {
121
135
  "optional": true
136
+ },
137
+ "@mostajs/data-plug": {
138
+ "optional": true
139
+ },
140
+ "@mostajs/socle": {
141
+ "optional": true
122
142
  }
123
143
  },
124
144
  "devDependencies": {
@@ -130,15 +150,15 @@
130
150
  "lucide-react": "^0.575.0",
131
151
  "next": "^16.1.6",
132
152
  "react": "^19.0.0",
133
- "typescript": "^5.6.0"
134
- },
135
- "dependencies": {
136
- "@mostajs/net": "^2.0.0",
137
- "@mostajs/octoswitcher": "^1.0.0",
138
- "@mostajs/orm": "^1.7.0"
153
+ "typescript": "^5.6.0",
154
+ "@mostajs/mjs-unit": "^0.3.0"
139
155
  },
140
156
  "funding": {
141
157
  "type": "github",
142
158
  "url": "https://github.com/sponsors/apolocine"
159
+ },
160
+ "scripts": {
161
+ "build": "tsc",
162
+ "test": "bash test-scripts/run-tests.sh"
143
163
  }
144
- }
164
+ }