@mostajs/aop-clients 0.1.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/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # @mostajs/aop-clients
2
+
3
+ **Auteur** : Dr Hamid MADANI <drmdh@msn.com> · AGPL-3.0-or-later
4
+
5
+ **Clients** de l agence + **Veilles** spécifiques (ORM-first). Une Veille est compatible avec l orchestrateur `@mostajs/aop-scheduler` (active/run/markRun) et réutilise le matching `@mostajs/aop-alerts`. Stack `mosta-aop-stack`.
package/llms.txt ADDED
@@ -0,0 +1,7 @@
1
+ # @mostajs/aop-clients — fiche LLM
2
+ > Clients de l agence + Veilles spécifiques (ORM-first). La Veille pilote l orchestrateur aop-scheduler.
3
+
4
+ ## EXPORTS
5
+ ClientSchema, VeilleSchema · createClients({repositories:{clients}}) · createVeilles({repositories:{veilles},now}) · createMemoryRepositories()
6
+ Veille.criteria = forme aop-alerts. createVeilles expose active()/run(veille,tenders)/markRun(id) → COMPATIBLE aop-scheduler.alerts.
7
+ propose(d)->status proposed · activate(id) · pause(id) · byClient(clientId). Stack mosta-aop-stack.
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@mostajs/aop-clients",
3
+ "version": "0.1.0",
4
+ "description": "Clients de l'agence + Veilles spécifiques (ORM-first). La Veille est compatible avec l'orchestrateur aop-scheduler (active/run/markRun). Réutilise aop-alerts (matching).",
5
+ "author": "Dr Hamid MADANI <drmdh@msn.com>",
6
+ "license": "AGPL-3.0-or-later",
7
+ "type": "module",
8
+ "main": "src/index.js",
9
+ "exports": {
10
+ ".": "./src/index.js"
11
+ },
12
+ "files": [
13
+ "src",
14
+ "README.md",
15
+ "llms.txt"
16
+ ],
17
+ "dependencies": {
18
+ "@mostajs/aop-alerts": "^0.1.0"
19
+ },
20
+ "devDependencies": {
21
+ "@mostajs/mjs-unit": "^0.3.0"
22
+ },
23
+ "scripts": {
24
+ "test": "node test-scripts/unit/aop-clients.test.mjs && node examples/run.mjs"
25
+ }
26
+ }
@@ -0,0 +1,31 @@
1
+ // @mostajs/aop-clients — services Clients & Veilles (ORM-first). La Veille est compatible avec
2
+ // l'interface `alerts` de @mostajs/aop-scheduler (active/run/markRun). @author Dr Hamid MADANI <drmdh@msn.com>
3
+ import { matchAlert, nextRun } from '@mostajs/aop-alerts';
4
+
5
+ export function createClients({ repositories } = {}) {
6
+ if (!repositories?.clients) throw new Error('aop-clients: repositories.clients requis');
7
+ const repo = repositories.clients;
8
+ return {
9
+ create: (d) => repo.create(d), get: (id) => repo.get(id), list: () => repo.list(),
10
+ update: (id, p) => repo.update(id, p), find: (p) => repo.find(p),
11
+ active: () => repo.find((c) => c.isActive),
12
+ };
13
+ }
14
+
15
+ export function createVeilles({ repositories, now = () => new Date() } = {}) {
16
+ if (!repositories?.veilles) throw new Error('aop-clients: repositories.veilles requis');
17
+ const repo = repositories.veilles;
18
+ async function create(d) { return repo.create({ ...d, nextRunAt: nextRun(d, now()).toISOString() }); }
19
+ return {
20
+ create, get: (id) => repo.get(id), list: () => repo.list(),
21
+ update: (id, p) => repo.update(id, p), find: (p) => repo.find(p),
22
+ byClient: (clientId) => repo.find((v) => v.clientId === clientId),
23
+ propose: (d) => create({ ...d, status: 'proposed' }),
24
+ activate: (id) => repo.update(id, { status: 'active' }),
25
+ pause: (id) => repo.update(id, { status: 'paused' }),
26
+ // ── Interface compatible aop-scheduler (alerts) ──
27
+ active: () => repo.find((v) => v.status === 'active'),
28
+ run: (veille, tenders) => tenders.map((t) => ({ tender: t, ...matchAlert(veille, t) })).filter((r) => r.matches).sort((a, b) => b.score - a.score),
29
+ async markRun(id) { const v = await repo.get(id); if (!v) return null; return repo.update(id, { lastRunAt: now().toISOString(), nextRunAt: nextRun(v, now()).toISOString() }); },
30
+ };
31
+ }
package/src/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { ClientSchema, VeilleSchema } from './schemas.js';
2
+ export { createClients, createVeilles } from './aop-clients.js';
3
+ export { createMemoryRepositories } from './memory-repo.js';
@@ -0,0 +1,2 @@
1
+ function coll(){const m=new Map();let s=0;return{create:async d=>{const id=String(++s),r={id,...d};m.set(id,r);return r;},get:async id=>m.get(id)||null,list:async()=>[...m.values()],find:async p=>[...m.values()].filter(p),update:async(id,patch)=>{const r=m.get(id);const u={...r,...patch};m.set(id,u);return u;}};}
2
+ export function createMemoryRepositories(){return{clients:coll(),veilles:coll()};}
package/src/schemas.js ADDED
@@ -0,0 +1,29 @@
1
+ // @mostajs/aop-clients — Client (de l'agence) + Veille (surveillance spécifique). @author Dr Hamid MADANI <drmdh@msn.com>
2
+ export const ClientSchema = {
3
+ name: 'Client', collection: 'aop_clients', timestamps: true,
4
+ fields: {
5
+ name: { type: 'string', required: true },
6
+ contactName: { type: 'string', default: '' }, contactEmail: { type: 'string', default: '' },
7
+ sector: { type: 'string', default: '' },
8
+ defaultKeywords: { type: 'array', default: [] },
9
+ notifyChannels: { type: 'array', default: ['email'] },
10
+ isActive: { type: 'boolean', default: true },
11
+ },
12
+ indexes: [{ fields: { name: 'asc' } }, { fields: { isActive: 'asc' } }],
13
+ };
14
+ // Une Veille = surveillance spécifique d'un client. `criteria` = même forme que aop-alerts (matchAlert).
15
+ export const VeilleSchema = {
16
+ name: 'Veille', collection: 'aop_veilles', timestamps: true,
17
+ fields: {
18
+ clientId: { type: 'string', required: true },
19
+ name: { type: 'string', required: true }, description: { type: 'text', default: '' },
20
+ criteria: { type: 'json', default: {} }, // { keywords, excludeKeywords, cpvCodes, budget, types, procedures, location }
21
+ sourceCodes: { type: 'array', default: [] }, // sources à surveiller (codes aop-sources)
22
+ notifications: { type: 'json', default: { frequency: 'daily', channels: ['email'] } },
23
+ status: { type: 'string', enum: ['proposed', 'active', 'paused'], default: 'proposed' }, // proposée → activée
24
+ proposedBy: { type: 'string', default: null }, // utilisateur agence
25
+ stats: { type: 'json', default: { matchCount: 0 } },
26
+ lastRunAt: { type: 'date', default: null }, nextRunAt: { type: 'date', default: null },
27
+ },
28
+ indexes: [{ fields: { clientId: 'asc' } }, { fields: { status: 'asc' } }],
29
+ };