{"_id":"@egen-civitas/esm-ai-memory","_rev":"3-972a38d228aec1ac799ff44761f08892","name":"@egen-civitas/esm-ai-memory","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"@egen-civitas/esm-ai-memory","version":"1.0.0","keywords":["egen","microfrontends","ai","memory","persistence"],"license":"MPL-2.0","_id":"@egen-civitas/esm-ai-memory@1.0.0","maintainers":[{"name":"egen-civitas","email":"nzilasamuel51@gmail.com"}],"homepage":"https://github.com/amourgit/Frontend-esm-framework#readme","bugs":{"url":"https://github.com/amourgit/Frontend-esm-framework/issues"},"dist":{"shasum":"b7707b774c8ff3b1a01e0184e097c40074d281c8","tarball":"https://registry.npmjs.org/@egen-civitas/esm-ai-memory/-/esm-ai-memory-1.0.0.tgz","fileCount":29,"integrity":"sha512-fiJIC3o8/olHG3ngBOMiT/se67OqpLog9Zlhgcr6s2I46KjsywVHj2UtjqjZvaQ9QcY6mJtlz9SLWf+sOL4o3Q==","signatures":[{"sig":"MEUCICK6iU3W75zqaqIcombX8DpPlJ09HWwSFCvKaio2Ed1zAiEA5acVT/tqbi0U6MCkDpcoK0L1vvcvTxsdfJd9KDmMTZ4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":114481},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.js","source":true,"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"121cd981fb513bec1dba5fd94fc2c28055ccd8df","scripts":{"lint":"eslint src --ext ts,tsx","test":"cross-env TZ=UTC vitest run --passWithNoTests","build":"rimraf dist && concurrently \"swc --strip-leading-paths src -d dist\" \"tsc --project tsconfig.build.json\"","coverage":"cross-env TZ=UTC vitest run --coverage --passWithNoTests","test:watch":"cross-env TZ=UTC vitest watch","typescript":"tsc --project tsconfig.build.json","build:development":"rimraf dist && concurrently \"swc --strip-leading-paths src -d dist\" \"tsc --project tsconfig.build.json\""},"_npmUser":{"name":"egen-civitas","email":"nzilasamuel51@gmail.com"},"repository":{"url":"git+https://github.com/amourgit/Frontend-esm-framework.git","type":"git"},"_npmVersion":"11.16.0","description":"Persistance de conversation IA EGEN — historique par utilisateur, stockage local (IndexedDB) synchronisé avec un adaptateur backend interchangeable, sans réécriture au changement de stockage.","directories":{},"_nodeVersion":"24.18.0","browserslist":["extends browserslist-config-egen"],"dependencies":{"rxjs":"^6.5.3","react":"^18.0.0","@egen-civitas/esm-api":"^1.0.0","@egen-civitas/esm-state":"^1.0.0","@egen-civitas/esm-ai-events":"^1.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^6.5.3","rimraf":"^6.1.3","vitest":"^4.1.2","@swc/cli":"0.8.1","@swc/core":"1.15.21","cross-env":"^10.1.0","@types/react":"^18.3.21","concurrently":"^9.2.1","fake-indexeddb":"^6.0.0","@vitest/coverage-v8":"^4.1.2","@egen-civitas/esm-api":"^1.0.0","@egen-civitas/esm-state":"^1.0.0","@egen-civitas/esm-ai-events":"^1.0.0"},"peerDependencies":{"rxjs":"^6.5.3","react":"^18.0.0","@egen-civitas/esm-api":"9.x","@egen-civitas/esm-state":"9.x","@egen-civitas/esm-ai-events":"1.x"},"_npmOperationalInternal":{"tmp":"tmp/esm-ai-memory_1.0.0_1786955524424_0.378518777959032","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@egen-civitas/esm-ai-memory","version":"1.0.1","keywords":["egen","microfrontends","ai","memory","persistence"],"license":"MPL-2.0","_id":"@egen-civitas/esm-ai-memory@1.0.1","maintainers":[{"name":"egen-civitas","email":"nzilasamuel51@gmail.com"}],"homepage":"https://github.com/amourgit/Frontend-esm-framework/tree/main/packages/framework/esm-ai-memory#readme","bugs":{"url":"https://github.com/amourgit/Frontend-esm-framework/issues"},"dist":{"shasum":"9000c04058c84d0d79576be7356f7108cf17edb2","tarball":"https://registry.npmjs.org/@egen-civitas/esm-ai-memory/-/esm-ai-memory-1.0.1.tgz","fileCount":29,"integrity":"sha512-iThwYuTfuW527MeMc3U2EnBL9d4Za9WSR9cptEGAo17wBYgu/uyYwKgieU0u+swCwIUuSpsSdk+SyPGvq95d8g==","signatures":[{"sig":"MEUCIQCdlskfw+22d0xB3eeimjy1miKoga1uzyHIo0sd7qisXAIgTF7Di6/45E3Ei/alMFpIJ5FOyzU7P1qoArlt9vu4MXk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":114737},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.js","source":true,"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"fe85b1db43497ad502d178da1937d8215ab7c123","scripts":{"lint":"eslint src --ext ts,tsx","test":"cross-env TZ=UTC vitest run --passWithNoTests","build":"rimraf dist && concurrently \"swc --strip-leading-paths src -d dist\" \"tsc --project tsconfig.build.json\"","coverage":"cross-env TZ=UTC vitest run --coverage --passWithNoTests","test:watch":"cross-env TZ=UTC vitest watch","typescript":"tsc --project tsconfig.build.json","build:development":"rimraf dist && concurrently \"swc --strip-leading-paths src -d dist\" \"tsc --project tsconfig.build.json\""},"_npmUser":{"name":"egen-civitas","email":"nzilasamuel51@gmail.com"},"repository":{"url":"git+https://github.com/amourgit/Frontend-esm-framework.git","type":"git","directory":"packages/framework/esm-ai-memory"},"_npmVersion":"11.16.0","description":"Persistance de conversation IA EGEN — historique par utilisateur, stockage local (IndexedDB) synchronisé avec un adaptateur backend interchangeable, sans réécriture au changement de stockage.","directories":{},"_nodeVersion":"24.18.0","browserslist":["extends browserslist-config-egen"],"dependencies":{"rxjs":"^7.8.0","react":"^18.0.0","@egen-civitas/esm-api":"^1.0.0","@egen-civitas/esm-state":"^1.0.0","@egen-civitas/esm-ai-events":"^1.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"^7.8.0","rimraf":"^6.1.3","vitest":"^4.1.2","@swc/cli":"0.8.1","@swc/core":"1.15.21","cross-env":"^10.1.0","@types/react":"^18.3.21","concurrently":"^9.2.1","fake-indexeddb":"^6.0.0","@vitest/coverage-v8":"^4.1.2","@egen-civitas/esm-api":"^1.0.0","@egen-civitas/esm-state":"^1.0.0","@egen-civitas/esm-ai-events":"^1.0.0"},"peerDependencies":{"rxjs":"7.x","react":"^18.0.0","@egen-civitas/esm-api":"9.x","@egen-civitas/esm-state":"9.x","@egen-civitas/esm-ai-events":"1.x"},"_npmOperationalInternal":{"tmp":"tmp/esm-ai-memory_1.0.1_1787341758471_0.7262711508741726","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@egen-civitas/esm-ai-memory","version":"1.0.2","license":"MPL-2.0","description":"Persistance de conversation IA EGEN — historique par utilisateur, stockage local (IndexedDB) synchronisé avec un adaptateur backend interchangeable, sans réécriture au changement de stockage.","main":"dist/index.js","module":"dist/index.js","types":"dist/index.d.ts","source":true,"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"rimraf dist && concurrently \"swc --strip-leading-paths src -d dist\" \"tsc --project tsconfig.build.json\"","build:development":"rimraf dist && concurrently \"swc --strip-leading-paths src -d dist\" \"tsc --project tsconfig.build.json\"","test":"cross-env TZ=UTC vitest run --passWithNoTests","test:watch":"cross-env TZ=UTC vitest watch","typescript":"tsc --project tsconfig.build.json","lint":"eslint src --ext ts,tsx","coverage":"cross-env TZ=UTC vitest run --coverage --passWithNoTests"},"keywords":["egen","microfrontends","ai","memory","persistence"],"browserslist":["extends browserslist-config-egen"],"repository":{"type":"git","url":"git+https://github.com/amourgit/Frontend-esm-framework.git","directory":"packages/framework/esm-ai-memory"},"publishConfig":{"access":"public"},"dependencies":{"@egen-civitas/esm-ai-events":"^1.0.0","@egen-civitas/esm-api":"^1.0.0","@egen-civitas/esm-state":"^1.0.0","react":"^18.0.0","rxjs":"^7.8.0"},"peerDependencies":{"@egen-civitas/esm-ai-events":"1.x","@egen-civitas/esm-api":"^1.0.0","@egen-civitas/esm-state":"^1.0.0","react":"^18.0.0","rxjs":"7.x"},"devDependencies":{"@egen-civitas/esm-ai-events":"^1.0.0","@egen-civitas/esm-api":"^1.0.0","@egen-civitas/esm-state":"^1.0.0","@swc/cli":"0.8.1","@swc/core":"1.15.21","@types/react":"^18.3.21","@vitest/coverage-v8":"^4.1.2","concurrently":"^9.2.1","cross-env":"^10.1.0","fake-indexeddb":"^6.0.0","rimraf":"^6.1.3","rxjs":"^7.8.0","vitest":"^4.1.2"},"bugs":{"url":"https://github.com/amourgit/Frontend-esm-framework/issues"},"homepage":"https://github.com/amourgit/Frontend-esm-framework/tree/main/packages/framework/esm-ai-memory#readme","gitHead":"0ee688b14fc421b3327d0feb4f1670b70a67330f","_id":"@egen-civitas/esm-ai-memory@1.0.2","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-AtsSM3gs0xDrv6sGE0VUR3BjD6XDJK913TzCWwcy0lHNjt6KH35YV8aV8EWJJxjz710A8oSiE5JCF0UIDEiiMA==","shasum":"addd247f6a2e20eb15bdef0e3c20e31290ab0777","tarball":"https://registry.npmjs.org/@egen-civitas/esm-ai-memory/-/esm-ai-memory-1.0.2.tgz","fileCount":29,"unpackedSize":114743,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCfzZ6wADMPOVdpfcVCcCwaKgyx2VvTMhbYFuQ2qj2vQAIhALSHUwq1jCCQUBHjqS7WQXMIIip8GRhhSOl1oNyAsFII"}]},"_npmUser":{"name":"egen-civitas","email":"nzilasamuel51@gmail.com"},"directories":{},"maintainers":[{"name":"egen-civitas","email":"nzilasamuel51@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/esm-ai-memory_1.0.2_1787547128342_0.1295450046768063"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-17T08:32:04.236Z","modified":"2026-08-24T04:52:08.728Z","1.0.0":"2026-08-17T08:32:04.734Z","1.0.1":"2026-08-21T19:49:18.636Z","1.0.2":"2026-08-24T04:52:08.561Z"},"bugs":{"url":"https://github.com/amourgit/Frontend-esm-framework/issues"},"license":"MPL-2.0","homepage":"https://github.com/amourgit/Frontend-esm-framework/tree/main/packages/framework/esm-ai-memory#readme","keywords":["egen","microfrontends","ai","memory","persistence"],"repository":{"type":"git","url":"git+https://github.com/amourgit/Frontend-esm-framework.git","directory":"packages/framework/esm-ai-memory"},"description":"Persistance de conversation IA EGEN — historique par utilisateur, stockage local (IndexedDB) synchronisé avec un adaptateur backend interchangeable, sans réécriture au changement de stockage.","maintainers":[{"name":"egen-civitas","email":"nzilasamuel51@gmail.com"}],"readme":"# @egen-civitas/esm-ai-memory\n\nPersistance de conversation pour l'assistant IA EGEN — historique complet\n(messages **et** appels de tools avec leur résultat brut, sans exception),\nscopé strictement par utilisateur authentifié, stocké localement (IndexedDB)\net synchronisé vers un backend interchangeable.\n\n## Pourquoi ce package existe\n\nSans lui, l'état de la conversation vivait uniquement dans le `useState`\nlocal du composant React affichant le widget — fermer le panneau (démontage\ndu composant) ou recharger la page effaçait tout. Ce package déplace la\nsource de vérité dans un store global persistant, indépendant du cycle de\nvie de n'importe quel composant.\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│  React (hooks.ts)                                            │\n│  useConversationMessages() / useConversationSummaries() / …  │\n└───────────────────────────┬───────────────────────────────────┘\n                             │ useSyncExternalStore-like\n┌───────────────────────────▼───────────────────────────────────┐\n│  store.ts — source de vérité réactive (survit au démontage)   │\n│  s'abonne à sessionStore (@egen-civitas/esm-api) : toute       │\n│  connexion/déconnexion/changement d'utilisateur recharge       │\n│  intégralement l'historique pour le nouvel utilisateur         │\n└──────────┬────────────────────────────────────┬────────────────┘\n           │ écrit à CHAQUE interaction          │ toutes les ~20s,\n           │ (immédiat)                          │ synchronise ce qui a\n           ▼                                     │ plus de 3 min d'attente\n┌────────────────────────┐          ┌────────────▼─────────────────┐\n│  IndexedDB (local)      │◄─────────┤  sync-orchestrator.ts         │\n│  indexeddb-adapter.ts   │  hydrate │  dirty-tracking, débounce,    │\n│  scopé par userId       │  au login│  fusion \"dernière écriture    │\n└────────────────────────┘          │  gagne\"                       │\n                                     └────────────┬───────────────────┘\n                                                  ▼\n                                     ┌────────────────────────────────┐\n                                     │  Backend (backend-adapter.ts)   │\n                                     │  REST via egenFetch — dégrade   │\n                                     │  toujours silencieusement si    │\n                                     │  absent (aujourd'hui : absent)  │\n                                     └────────────────────────────────┘\n```\n\n## Le point d'extension central : `ConversationStorageAdapter`\n\nToute la logique métier ne parle **qu'à travers** cette interface (voir\n`types.ts`) — jamais directement à IndexedDB ou à une API REST :\n\n```ts\ninterface ConversationStorageAdapter {\n  listConversations(userId: string): Promise<ConversationSummary[]>;\n  getConversation(userId: string, conversationId: string): Promise<StoredConversation | null>;\n  saveConversation(conversation: StoredConversation): Promise<void>;\n  deleteConversation(userId: string, conversationId: string): Promise<void>;\n}\n```\n\nChanger de stockage (local → un autre backend, une autre techno locale que\nIndexedDB…) = écrire un nouvel adaptateur qui implémente cette interface,\nsans toucher au reste du package. C'est ce qui rend le passage du \"tout en\nlocal aujourd'hui\" au \"local + backend une fois prêt\" possible sans\nréécriture.\n\n## Pourquoi IndexedDB et pas `localStorage`\n\n`localStorage` est limité à ~5-10 Mo par origine et son API est synchrone.\nAvec la règle \"tout est conservé, y compris le résultat brut de chaque appel\nde tool\" (voir `@egen-civitas/esm-ai-tools`, dont certains tools comme\n`inspect_interface` peuvent renvoyer des centaines de Ko par appel),\n`localStorage` saturerait vite. IndexedDB est asynchrone et dispose d'un\nquota bien plus large.\n\n## Règle de synchronisation (3 minutes)\n\n- Le **local** est mis à jour à **chaque** interaction — immédiat.\n- Le **backend** n'est sollicité qu'après qu'une conversation soit restée\n  \"dirty\" (modifiée localement, pas encore synchronisée) pendant **3\n  minutes**, pour ne pas multiplier les requêtes réseau à chaque message.\n- Un flush best-effort supplémentaire est déclenché sur `visibilitychange`\n  (onglet caché) et `pagehide` (fermeture) pour limiter la perte des toutes\n  dernières minutes.\n- À la connexion, `hydrateFromBackend()` rapatrie l'historique backend et le\n  fusionne dans le local **avant** que la conversation ne reprenne (fusion\n  \"dernière écriture gagne\" par comparaison de `updatedAt`).\n\n## Contrat REST attendu côté backend (pas encore implémenté)\n\n```\nGET    /ai/conversations         → ConversationSummary[] (utilisateur authentifié implicite)\nGET    /ai/conversations/:id     → StoredConversation\nPUT    /ai/conversations/:id     → upsert intégral, body = StoredConversation\nDELETE /ai/conversations/:id     → 204\n```\n\nTant que ce backend n'existe pas, `backend-adapter.ts` dégrade toujours\nsilencieusement (`ok: false` traité comme \"rien à faire\") — le\nfonctionnement en local seul n'est jamais interrompu.\n\n## Usage\n\n```ts\n// Une seule fois, au boot de l'app assistant :\nimport { initConversationMemory } from '@egen-civitas/esm-ai-memory';\ninitConversationMemory();\n\n// Dans les composants React :\nimport { useConversationMessages, useConversationMemoryStatus } from '@egen-civitas/esm-ai-memory';\n\nfunction ChatPanel() {\n  const messages = useConversationMessages();\n  const status = useConversationMemoryStatus();\n  // ...\n}\n\n// Mutations (typiquement depuis le hook de conversation, ex: useAIChat) :\nimport { addUserMessage, addAssistantMessage, recordToolCall, startNewConversation } from '@egen-civitas/esm-ai-memory';\n```\n\n## Tests\n\n```\nyarn workspace @egen-civitas/esm-ai-memory test\n```\n\nUtilise `fake-indexeddb` (voir `src/test-setup.ts`) pour une IndexedDB en\nmémoire fidèle à la spec, sans dépendre d'un vrai navigateur.\n","readmeFilename":"README.md"}