@creezio/interactive-demo 0.22.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 +138 -0
- package/dist/content.d.ts +49 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +329 -0
- package/dist/content.js.map +1 -0
- package/dist/contributions.d.ts +48 -0
- package/dist/contributions.d.ts.map +1 -0
- package/dist/contributions.js +87 -0
- package/dist/contributions.js.map +1 -0
- package/dist/generic.d.ts +32 -0
- package/dist/generic.d.ts.map +1 -0
- package/dist/generic.js +116 -0
- package/dist/generic.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +160 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +132 -0
- package/dist/types.js.map +1 -0
- package/dist-cjs/content.js +335 -0
- package/dist-cjs/content.js.map +1 -0
- package/dist-cjs/contributions.js +90 -0
- package/dist-cjs/contributions.js.map +1 -0
- package/dist-cjs/generic.js +120 -0
- package/dist-cjs/generic.js.map +1 -0
- package/dist-cjs/index.js +27 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/types.js +136 -0
- package/dist-cjs/types.js.map +1 -0
- package/package.json +67 -0
- package/ui/demo-player.tsx +563 -0
- package/ui/demo-root.tsx +312 -0
- package/ui/dom.ts +280 -0
- package/ui/fake-cursor.ts +157 -0
- package/ui/index.ts +25 -0
- package/ui/interactive-demo.css +423 -0
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# @creezio/interactive-demo
|
|
2
|
+
|
|
3
|
+
Démo interactive **native** (module OS présent dans toutes les apps Creezio) :
|
|
4
|
+
un product tour « Storylane-like » mais joué **en live dans l'app** — un faux
|
|
5
|
+
curseur animé se déplace, clique et tape réellement dans l'interface pendant
|
|
6
|
+
que des cartes de narration présentent chaque fonctionnalité.
|
|
7
|
+
|
|
8
|
+
## Ce que fournit le package
|
|
9
|
+
|
|
10
|
+
- **Types de scénario déclaratifs** (`DemoScenario` / `DemoStep`) : étapes
|
|
11
|
+
`say` (carte plein écran), `navigate`, `highlight` (spotlight + carte
|
|
12
|
+
ancrée), `click` (faux curseur + vrai clic DOM), `type` (frappe caractère
|
|
13
|
+
par caractère), `scroll`, `wait`. Format JSON-sérialisable : ajouter /
|
|
14
|
+
enlever / réordonner des étapes = éditer un tableau.
|
|
15
|
+
- **Contenu hybride DB** (ADR-module-natif-hybride) : la marque déclare ses
|
|
16
|
+
scénarios par défaut dans UN fichier explicite
|
|
17
|
+
(`server/src/electron/brand-interactive-demo-content.ts`), les overrides
|
|
18
|
+
vivent en `brand.db` (`interactive_demo_content`), le runtime sert
|
|
19
|
+
`merge(défauts, overrides)`. Le « déjà vu » par utilisateur va dans
|
|
20
|
+
`interactive_demo_preferences`.
|
|
21
|
+
- **Mount api-kernel** `/api/v1/modules/interactive-demo/*` : `GET/PUT/DELETE
|
|
22
|
+
scenarios[/:id]` + `GET/PUT preferences`.
|
|
23
|
+
- **UI React** (`@creezio/interactive-demo/ui`) : `InteractiveDemoRoot`
|
|
24
|
+
(auto-lancement première visite + lanceur flottant « Visite guidée »),
|
|
25
|
+
`DemoPlayer` (lecteur bas niveau), `startInteractiveDemo()` (déclenchement
|
|
26
|
+
programmatique), curseur/spotlight en Web Animations API + CSS
|
|
27
|
+
(`ui/interactive-demo.css`) — zéro dépendance d'animation tierce.
|
|
28
|
+
- **Scénario générique OS** : `genericOsTourScenario({ productName })` —
|
|
29
|
+
démo de base jour 1 (sidebar, tâches, mails, assistant) pour toute marque
|
|
30
|
+
sans scénario produit.
|
|
31
|
+
- **Collecteur de contributions modules** : `collectInteractiveDemoDefaults(contributions)`
|
|
32
|
+
agrège les scénarios `demo` des modules métier (validation
|
|
33
|
+
`validateDemoScenario`, dédup par id, ordre stable, erreurs agrégées
|
|
34
|
+
explicites) — la brique derrière `collectDemoScenarios()` du registre
|
|
35
|
+
`modules/index.ts` généré par la factory.
|
|
36
|
+
|
|
37
|
+
## Défauts par modules (registre — câblage cible)
|
|
38
|
+
|
|
39
|
+
Chaque module métier **doit** déclarer ≥ 1 scénario dans son
|
|
40
|
+
`server/src/electron/modules/<id>.ts` (champ `demo` du `BrandModuleDef`).
|
|
41
|
+
Inclure `genericOsTourScenario({ productName })` (id `os-tour` partagé).
|
|
42
|
+
Une app Creezio sans démo interactive est invalide. La factory câble le
|
|
43
|
+
mount, les migrations et le CSS ; `BrandChrome` monte **un** `InteractiveDemoRoot`
|
|
44
|
+
dans `SessionProvider` (`CreezioUiBoot` ne remonte plus le lecteur).
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
export const promotionsModule: BrandModuleDef = {
|
|
48
|
+
id: "promotions",
|
|
49
|
+
// entitySpecs, navItems…
|
|
50
|
+
demo: {
|
|
51
|
+
scenarios: [
|
|
52
|
+
{
|
|
53
|
+
id: "promotions-tour",
|
|
54
|
+
title: "Promotions",
|
|
55
|
+
steps: [{ id: "intro", kind: "say", title: "Créez vos promos" }],
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Le registre `modules/index.ts` (généré factory) agrège tout via
|
|
63
|
+
`collectDemoScenarios()` — le mount n'est alors qu'**une ligne** côté app :
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
// server/src/electron/brand-module-api.ts
|
|
67
|
+
import { collectDemoScenarios } from "./modules/index.js";
|
|
68
|
+
import { createInteractiveDemoMount } from "@creezio/interactive-demo";
|
|
69
|
+
|
|
70
|
+
api.registerModuleApi(
|
|
71
|
+
"interactive-demo",
|
|
72
|
+
createInteractiveDemoMount({ defaults: collectDemoScenarios() }),
|
|
73
|
+
);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`collectDemoScenarios()` délègue à `collectInteractiveDemoDefaults()` :
|
|
77
|
+
scénarios invalides ou ids en conflit entre modules = **erreur explicite au
|
|
78
|
+
boot** (liste complète module:scénario), jamais une démo tronquée servie en
|
|
79
|
+
silence.
|
|
80
|
+
|
|
81
|
+
## Un seul lecteur — dans SessionProvider
|
|
82
|
+
|
|
83
|
+
La factory pose **un** `InteractiveDemoRoot` dans `BrandChrome`, à
|
|
84
|
+
l'intérieur de `SessionProvider` (`useSession()` → `userKey` / `role`).
|
|
85
|
+
`CreezioUiBoot` ne remonte plus un second root (double curseur / Foove #101).
|
|
86
|
+
Pas de `brandDemoScenarios()` — SoT = `collectDemoScenarios()`.
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
// ui/components/brand-chrome.tsx (généré factory)
|
|
90
|
+
const { me } = useSession();
|
|
91
|
+
<InteractiveDemoRoot
|
|
92
|
+
launcher="sidebar"
|
|
93
|
+
userKey={me?.user}
|
|
94
|
+
role={me?.brandRole}
|
|
95
|
+
/>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
PR kit #109 (curseur DOM unmount après Terminer) : **reste ouvert**, non
|
|
99
|
+
fusionné ici pour ne pas mélanger le lockstep 0.10.8.
|
|
100
|
+
|
|
101
|
+
Le scénario marqué `autoStart: true` se lance automatiquement à la première
|
|
102
|
+
visite (après le setup / l'onboarding) ; « déjà vu » est persisté par
|
|
103
|
+
utilisateur (preferences + localStorage). Le lanceur flottant permet de
|
|
104
|
+
rejouer la visite à tout moment.
|
|
105
|
+
|
|
106
|
+
## Scénarios par rôle
|
|
107
|
+
|
|
108
|
+
Un scénario peut restreindre sa visibilité avec `roles?: string[]` (lanceur
|
|
109
|
+
+ autoStart ; un lancement explicite `startInteractiveDemo(id)` ignore le
|
|
110
|
+
filtre). Le rôle courant est une **donnée de session**, pas une donnée
|
|
111
|
+
métier : la marque déclare `configureAuth({ resolveBrandRole })`
|
|
112
|
+
(`@creezio/auth`, callback qui résout le rôle depuis SA db — ex. lookup
|
|
113
|
+
`user_roles`), le kit sert `brand_role` dans `/api/v1/auth/me` (la valeur
|
|
114
|
+
suit la cible en impersonation) et `useSession().me.brandRole` côté UI.
|
|
115
|
+
Sans resolver : `brandRole` est `null` → aucun filtrage (comportement
|
|
116
|
+
historique).
|
|
117
|
+
|
|
118
|
+
## Éditer la démo (ajouter / enlever des étapes)
|
|
119
|
+
|
|
120
|
+
- **Défauts** : éditer le tableau `steps` du fichier marque
|
|
121
|
+
`brand-interactive-demo-content.ts` (rebuild).
|
|
122
|
+
- **À chaud, sans code** : `PUT /api/v1/modules/interactive-demo/scenarios/<id>`
|
|
123
|
+
avec `{ "steps": [ … ] }` (remplacement complet du tableau — pas de merge
|
|
124
|
+
ambigu) ; `DELETE` pour revenir aux défauts. Un `PUT` sur un id inconnu
|
|
125
|
+
avec `title` + `steps` crée un scénario supplémentaire.
|
|
126
|
+
|
|
127
|
+
## Commandes
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npm run build -w @creezio/interactive-demo
|
|
131
|
+
node --test scripts/test-phase-interactive-demo.mjs # gate kit
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Docs
|
|
135
|
+
|
|
136
|
+
- [AGENTS.md](./AGENTS.md) — frontières et pièges (agents IA)
|
|
137
|
+
- [docs/FILES.md](./docs/FILES.md) — inventaire des fichiers
|
|
138
|
+
- ADR : [docs/adr/ADR-module-natif-hybride.md](../../docs/adr/ADR-module-natif-hybride.md)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contenu démo interactive hybride (ADR-module-natif-hybride).
|
|
3
|
+
*
|
|
4
|
+
* Le kit fournit le moteur générique : la marque déclare ses scénarios par
|
|
5
|
+
* défaut dans UN fichier explicite
|
|
6
|
+
* (`server/src/electron/brand-interactive-demo-content.ts`), les overrides
|
|
7
|
+
* vivent en `brand.db` (table `interactive_demo_content`, une ligne par
|
|
8
|
+
* scénario), et le runtime sert toujours `merge(défauts marque, overrides
|
|
9
|
+
* DB)`. Le « déjà vu » par utilisateur atterrit dans
|
|
10
|
+
* `interactive_demo_preferences` via le même mount.
|
|
11
|
+
*
|
|
12
|
+
* Zéro texte métier ici (ADR-no-brand-domain-in-native-packages) —
|
|
13
|
+
* imports type-only pour ne pas créer de cycle runtime.
|
|
14
|
+
*/
|
|
15
|
+
import type { ApiMount } from "@creezio/api-kernel";
|
|
16
|
+
import type { SqliteMigration } from "@creezio/platform-core";
|
|
17
|
+
import type { DemoScenario, DemoScenarioOverride } from "./types.js";
|
|
18
|
+
export declare const INTERACTIVE_DEMO_SCHEMA_SQL = "-- Sc\u00E9narios d\u00E9mo interactive hybride + preferences (@creezio/interactive-demo)\n\nCREATE TABLE IF NOT EXISTS interactive_demo_content (\n key TEXT PRIMARY KEY,\n value_json TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS interactive_demo_preferences (\n id TEXT PRIMARY KEY,\n user_key TEXT NOT NULL,\n key TEXT NOT NULL,\n value_json TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE(user_key, key)\n);\n";
|
|
19
|
+
/** Migrations brand.db du module (à composer dans `brand-migrations.ts` marque). */
|
|
20
|
+
export declare function interactiveDemoMigrations(): SqliteMigration[];
|
|
21
|
+
/**
|
|
22
|
+
* Merge pur défauts marque + overrides DB.
|
|
23
|
+
*
|
|
24
|
+
* - scénario par `id` : champs présents dans l'override priment ;
|
|
25
|
+
* - `steps` d'un override REMPLACE le tableau des défauts (édition
|
|
26
|
+
* explicite — pas de merge étape par étape) ;
|
|
27
|
+
* - `enabled: false` désactive un scénario par défaut sans le supprimer ;
|
|
28
|
+
* - un override inconnu des défauts portant `title` + `steps` valides est
|
|
29
|
+
* ajouté en fin (scénario créé par l'admin).
|
|
30
|
+
*/
|
|
31
|
+
export declare function mergeDemoScenarios(defaults: DemoScenario[], overrides?: DemoScenarioOverride[] | null): DemoScenario[];
|
|
32
|
+
export type InteractiveDemoMountOptions = {
|
|
33
|
+
/** Défauts marque (fichier explicite `brand-interactive-demo-content.ts`). */
|
|
34
|
+
defaults: DemoScenario[];
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Mount api-kernel `/api/v1/modules/interactive-demo/*` (dbLayer brand) :
|
|
38
|
+
*
|
|
39
|
+
* - `GET scenarios` → `{ ok, scenarios: merge(défauts, overrides), overrides: [ids] }`
|
|
40
|
+
* - `GET scenarios/:id` → `{ ok, scenario }` (mergé) ou 404
|
|
41
|
+
* - `PUT scenarios/:id` → stocke l'override (steps = remplacement), répond le scénario mergé
|
|
42
|
+
* - `DELETE scenarios/:id` → supprime l'override (retour aux défauts)
|
|
43
|
+
* - `GET preferences?user=<k>` → `{ ok, user, answers }` (clés `seen:<scenarioId>`…)
|
|
44
|
+
* - `PUT preferences` → `{ user, answers }` upsert par clé
|
|
45
|
+
*
|
|
46
|
+
* db absent → 503 `db_unavailable` ; body invalide → 400 (jamais de throw).
|
|
47
|
+
*/
|
|
48
|
+
export declare function createInteractiveDemoMount(opts: InteractiveDemoMountOptions): ApiMount;
|
|
49
|
+
//# sourceMappingURL=content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKrE,eAAO,MAAM,2BAA2B,4cAgBvC,CAAC;AAEF,oFAAoF;AACpF,wBAAgB,yBAAyB,IAAI,eAAe,EAAE,CAO7D;AAYD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,YAAY,EAAE,EACxB,SAAS,CAAC,EAAE,oBAAoB,EAAE,GAAG,IAAI,GACxC,YAAY,EAAE,CAkChB;AAiDD,MAAM,MAAM,2BAA2B,GAAG;IACxC,8EAA8E;IAC9E,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,2BAA2B,GAChC,QAAQ,CAmMV"}
|
package/dist/content.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contenu démo interactive hybride (ADR-module-natif-hybride).
|
|
3
|
+
*
|
|
4
|
+
* Le kit fournit le moteur générique : la marque déclare ses scénarios par
|
|
5
|
+
* défaut dans UN fichier explicite
|
|
6
|
+
* (`server/src/electron/brand-interactive-demo-content.ts`), les overrides
|
|
7
|
+
* vivent en `brand.db` (table `interactive_demo_content`, une ligne par
|
|
8
|
+
* scénario), et le runtime sert toujours `merge(défauts marque, overrides
|
|
9
|
+
* DB)`. Le « déjà vu » par utilisateur atterrit dans
|
|
10
|
+
* `interactive_demo_preferences` via le même mount.
|
|
11
|
+
*
|
|
12
|
+
* Zéro texte métier ici (ADR-no-brand-domain-in-native-packages) —
|
|
13
|
+
* imports type-only pour ne pas créer de cycle runtime.
|
|
14
|
+
*/
|
|
15
|
+
import { validateDemoScenario } from "./types.js";
|
|
16
|
+
/* ------------------------------------------------------------- migrations */
|
|
17
|
+
export const INTERACTIVE_DEMO_SCHEMA_SQL = `-- Scénarios démo interactive hybride + preferences (@creezio/interactive-demo)
|
|
18
|
+
|
|
19
|
+
CREATE TABLE IF NOT EXISTS interactive_demo_content (
|
|
20
|
+
key TEXT PRIMARY KEY,
|
|
21
|
+
value_json TEXT NOT NULL,
|
|
22
|
+
updated_at TEXT NOT NULL
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
CREATE TABLE IF NOT EXISTS interactive_demo_preferences (
|
|
26
|
+
id TEXT PRIMARY KEY,
|
|
27
|
+
user_key TEXT NOT NULL,
|
|
28
|
+
key TEXT NOT NULL,
|
|
29
|
+
value_json TEXT NOT NULL,
|
|
30
|
+
updated_at TEXT NOT NULL,
|
|
31
|
+
UNIQUE(user_key, key)
|
|
32
|
+
);
|
|
33
|
+
`;
|
|
34
|
+
/** Migrations brand.db du module (à composer dans `brand-migrations.ts` marque). */
|
|
35
|
+
export function interactiveDemoMigrations() {
|
|
36
|
+
return [
|
|
37
|
+
{
|
|
38
|
+
id: "interactive_demo_001_content_prefs",
|
|
39
|
+
sql: INTERACTIVE_DEMO_SCHEMA_SQL,
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
/* ------------------------------------------------------------------ merge */
|
|
44
|
+
function cloneScenario(s) {
|
|
45
|
+
return {
|
|
46
|
+
...s,
|
|
47
|
+
...(Array.isArray(s.roles) ? { roles: [...s.roles] } : {}),
|
|
48
|
+
steps: s.steps.map((st) => ({ ...st })),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Merge pur défauts marque + overrides DB.
|
|
53
|
+
*
|
|
54
|
+
* - scénario par `id` : champs présents dans l'override priment ;
|
|
55
|
+
* - `steps` d'un override REMPLACE le tableau des défauts (édition
|
|
56
|
+
* explicite — pas de merge étape par étape) ;
|
|
57
|
+
* - `enabled: false` désactive un scénario par défaut sans le supprimer ;
|
|
58
|
+
* - un override inconnu des défauts portant `title` + `steps` valides est
|
|
59
|
+
* ajouté en fin (scénario créé par l'admin).
|
|
60
|
+
*/
|
|
61
|
+
export function mergeDemoScenarios(defaults, overrides) {
|
|
62
|
+
const base = defaults.map(cloneScenario);
|
|
63
|
+
if (!Array.isArray(overrides) || overrides.length === 0)
|
|
64
|
+
return base;
|
|
65
|
+
const byId = new Map();
|
|
66
|
+
for (const o of overrides) {
|
|
67
|
+
if (o && typeof o.id === "string" && o.id)
|
|
68
|
+
byId.set(o.id, o);
|
|
69
|
+
}
|
|
70
|
+
const merged = base.map((s) => {
|
|
71
|
+
const o = byId.get(s.id);
|
|
72
|
+
if (!o)
|
|
73
|
+
return s;
|
|
74
|
+
byId.delete(s.id);
|
|
75
|
+
return {
|
|
76
|
+
...s,
|
|
77
|
+
...(typeof o.title === "string" && o.title ? { title: o.title } : {}),
|
|
78
|
+
...(typeof o.description === "string" ? { description: o.description } : {}),
|
|
79
|
+
...(typeof o.enabled === "boolean" ? { enabled: o.enabled } : {}),
|
|
80
|
+
...(typeof o.autoStart === "boolean" ? { autoStart: o.autoStart } : {}),
|
|
81
|
+
...(Array.isArray(o.roles) ? { roles: [...o.roles] } : {}),
|
|
82
|
+
...(Array.isArray(o.steps) && o.steps.length > 0
|
|
83
|
+
? { steps: o.steps.map((st) => ({ ...st })) }
|
|
84
|
+
: {}),
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
// Scénarios ajoutés par override (inconnus des défauts) : exigés complets.
|
|
88
|
+
for (const o of byId.values()) {
|
|
89
|
+
const candidate = { enabled: true, ...o };
|
|
90
|
+
if (validateDemoScenario(candidate).length === 0) {
|
|
91
|
+
merged.push(cloneScenario(candidate));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return merged;
|
|
95
|
+
}
|
|
96
|
+
/* ------------------------------------------------------------------ mount */
|
|
97
|
+
const CONTENT_PREFIX = "scenario:";
|
|
98
|
+
function nowIso() {
|
|
99
|
+
return new Date().toISOString();
|
|
100
|
+
}
|
|
101
|
+
function newId() {
|
|
102
|
+
return Date.now().toString(36) + Math.random().toString(36).slice(2, 10);
|
|
103
|
+
}
|
|
104
|
+
/** Lit tous les overrides DB (lignes illisibles ignorées — jamais de throw). */
|
|
105
|
+
function readOverrides(db) {
|
|
106
|
+
try {
|
|
107
|
+
const rows = db
|
|
108
|
+
.prepare(`SELECT key, value_json FROM interactive_demo_content
|
|
109
|
+
WHERE key LIKE ? ORDER BY key`)
|
|
110
|
+
.all(`${CONTENT_PREFIX}%`);
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const r of rows) {
|
|
113
|
+
try {
|
|
114
|
+
const parsed = JSON.parse(r.value_json);
|
|
115
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
116
|
+
const id = r.key.slice(CONTENT_PREFIX.length);
|
|
117
|
+
out.push({ ...parsed, id });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
/* ligne illisible ignorée */
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Mount api-kernel `/api/v1/modules/interactive-demo/*` (dbLayer brand) :
|
|
132
|
+
*
|
|
133
|
+
* - `GET scenarios` → `{ ok, scenarios: merge(défauts, overrides), overrides: [ids] }`
|
|
134
|
+
* - `GET scenarios/:id` → `{ ok, scenario }` (mergé) ou 404
|
|
135
|
+
* - `PUT scenarios/:id` → stocke l'override (steps = remplacement), répond le scénario mergé
|
|
136
|
+
* - `DELETE scenarios/:id` → supprime l'override (retour aux défauts)
|
|
137
|
+
* - `GET preferences?user=<k>` → `{ ok, user, answers }` (clés `seen:<scenarioId>`…)
|
|
138
|
+
* - `PUT preferences` → `{ user, answers }` upsert par clé
|
|
139
|
+
*
|
|
140
|
+
* db absent → 503 `db_unavailable` ; body invalide → 400 (jamais de throw).
|
|
141
|
+
*/
|
|
142
|
+
export function createInteractiveDemoMount(opts) {
|
|
143
|
+
const defaults = opts.defaults;
|
|
144
|
+
return {
|
|
145
|
+
dbLayer: "brand",
|
|
146
|
+
operations: [
|
|
147
|
+
{
|
|
148
|
+
id: "list-scenarios",
|
|
149
|
+
method: "GET",
|
|
150
|
+
path: "/scenarios",
|
|
151
|
+
description: "Lister les scénarios de démo interactive",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: "get-scenario",
|
|
155
|
+
method: "GET",
|
|
156
|
+
path: "/scenarios/:id",
|
|
157
|
+
description: "Lire un scénario de démo",
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: "put-scenario",
|
|
161
|
+
method: "PUT",
|
|
162
|
+
path: "/scenarios/:id",
|
|
163
|
+
description: "Écrire un override de scénario",
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
id: "delete-scenario",
|
|
167
|
+
method: "DELETE",
|
|
168
|
+
path: "/scenarios/:id",
|
|
169
|
+
description: "Supprimer un override de scénario",
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
id: "get-preferences",
|
|
173
|
+
method: "GET",
|
|
174
|
+
path: "/preferences",
|
|
175
|
+
description: "Lire les préférences démo d'un utilisateur",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "put-preferences",
|
|
179
|
+
method: "PUT",
|
|
180
|
+
path: "/preferences",
|
|
181
|
+
description: "Enregistrer les préférences démo",
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
handle: async ({ req, subPath, db }) => {
|
|
185
|
+
if (!db) {
|
|
186
|
+
return { status: 503, body: { ok: false, error: "db_unavailable" } };
|
|
187
|
+
}
|
|
188
|
+
const method = req.method.toUpperCase();
|
|
189
|
+
const parts = subPath.split("/").filter(Boolean);
|
|
190
|
+
const head = parts[0] || "";
|
|
191
|
+
if (head === "scenarios" && parts.length === 1) {
|
|
192
|
+
if (method === "GET") {
|
|
193
|
+
const overrides = readOverrides(db);
|
|
194
|
+
return {
|
|
195
|
+
status: 200,
|
|
196
|
+
body: {
|
|
197
|
+
ok: true,
|
|
198
|
+
scenarios: mergeDemoScenarios(defaults, overrides),
|
|
199
|
+
overrides: overrides.map((o) => o.id),
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return { status: 405, body: { ok: false, error: "method_not_allowed" } };
|
|
204
|
+
}
|
|
205
|
+
if (head === "scenarios" && parts.length === 2) {
|
|
206
|
+
const id = decodeURIComponent(parts[1]);
|
|
207
|
+
if (method === "GET") {
|
|
208
|
+
const merged = mergeDemoScenarios(defaults, readOverrides(db));
|
|
209
|
+
const scenario = merged.find((s) => s.id === id);
|
|
210
|
+
if (!scenario) {
|
|
211
|
+
return { status: 404, body: { ok: false, error: "not_found" } };
|
|
212
|
+
}
|
|
213
|
+
return { status: 200, body: { ok: true, scenario } };
|
|
214
|
+
}
|
|
215
|
+
if (method === "PUT") {
|
|
216
|
+
const body = req.body;
|
|
217
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
218
|
+
return { status: 400, body: { ok: false, error: "invalid_body" } };
|
|
219
|
+
}
|
|
220
|
+
const override = { ...body, id };
|
|
221
|
+
// Un scénario inconnu des défauts doit être complet et valide.
|
|
222
|
+
const isKnown = defaults.some((s) => s.id === id);
|
|
223
|
+
if (!isKnown) {
|
|
224
|
+
const errors = validateDemoScenario({ enabled: true, ...override });
|
|
225
|
+
if (errors.length > 0) {
|
|
226
|
+
return {
|
|
227
|
+
status: 400,
|
|
228
|
+
body: { ok: false, error: "scenario_invalide", details: errors },
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
else if (Array.isArray(override.steps) || override.roles !== undefined) {
|
|
233
|
+
const defaultScenario = defaults.find((s) => s.id === id);
|
|
234
|
+
const errors = validateDemoScenario({
|
|
235
|
+
...defaultScenario,
|
|
236
|
+
...override,
|
|
237
|
+
});
|
|
238
|
+
if (errors.length > 0) {
|
|
239
|
+
return {
|
|
240
|
+
status: 400,
|
|
241
|
+
body: { ok: false, error: "scenario_invalide", details: errors },
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
db
|
|
246
|
+
.prepare(`INSERT INTO interactive_demo_content (key, value_json, updated_at)
|
|
247
|
+
VALUES (?, ?, ?)
|
|
248
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
249
|
+
value_json = excluded.value_json,
|
|
250
|
+
updated_at = excluded.updated_at`)
|
|
251
|
+
.run(`${CONTENT_PREFIX}${id}`, JSON.stringify(override), nowIso());
|
|
252
|
+
const merged = mergeDemoScenarios(defaults, readOverrides(db));
|
|
253
|
+
return {
|
|
254
|
+
status: 200,
|
|
255
|
+
body: {
|
|
256
|
+
ok: true,
|
|
257
|
+
scenario: merged.find((s) => s.id === id) ?? null,
|
|
258
|
+
hasOverride: true,
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
if (method === "DELETE") {
|
|
263
|
+
db
|
|
264
|
+
.prepare(`DELETE FROM interactive_demo_content WHERE key = ?`)
|
|
265
|
+
.run(`${CONTENT_PREFIX}${id}`);
|
|
266
|
+
const merged = mergeDemoScenarios(defaults, readOverrides(db));
|
|
267
|
+
return {
|
|
268
|
+
status: 200,
|
|
269
|
+
body: {
|
|
270
|
+
ok: true,
|
|
271
|
+
scenario: merged.find((s) => s.id === id) ?? null,
|
|
272
|
+
hasOverride: false,
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
return { status: 405, body: { ok: false, error: "method_not_allowed" } };
|
|
277
|
+
}
|
|
278
|
+
if (head === "preferences" && parts.length === 1) {
|
|
279
|
+
if (method === "GET") {
|
|
280
|
+
const raw = req.query?.user;
|
|
281
|
+
const user = String(Array.isArray(raw) ? raw[0] ?? "" : raw ?? "").trim();
|
|
282
|
+
if (!user) {
|
|
283
|
+
return { status: 400, body: { ok: false, error: "user_required" } };
|
|
284
|
+
}
|
|
285
|
+
const rows = db
|
|
286
|
+
.prepare(`SELECT key, value_json FROM interactive_demo_preferences
|
|
287
|
+
WHERE user_key = ? ORDER BY key`)
|
|
288
|
+
.all(user);
|
|
289
|
+
const answers = {};
|
|
290
|
+
for (const r of rows) {
|
|
291
|
+
try {
|
|
292
|
+
answers[r.key] = JSON.parse(r.value_json);
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
answers[r.key] = r.value_json;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return { status: 200, body: { ok: true, user, answers } };
|
|
299
|
+
}
|
|
300
|
+
if (method === "PUT") {
|
|
301
|
+
const body = (req.body || {});
|
|
302
|
+
const user = String(body.user ?? "").trim();
|
|
303
|
+
const answers = body.answers;
|
|
304
|
+
if (!user || !answers || typeof answers !== "object" || Array.isArray(answers)) {
|
|
305
|
+
return { status: 400, body: { ok: false, error: "invalid_body" } };
|
|
306
|
+
}
|
|
307
|
+
const ts = nowIso();
|
|
308
|
+
let saved = 0;
|
|
309
|
+
for (const [key, value] of Object.entries(answers)) {
|
|
310
|
+
if (value === undefined)
|
|
311
|
+
continue;
|
|
312
|
+
db
|
|
313
|
+
.prepare(`INSERT INTO interactive_demo_preferences (id, user_key, key, value_json, updated_at)
|
|
314
|
+
VALUES (?, ?, ?, ?, ?)
|
|
315
|
+
ON CONFLICT(user_key, key) DO UPDATE SET
|
|
316
|
+
value_json = excluded.value_json,
|
|
317
|
+
updated_at = excluded.updated_at`)
|
|
318
|
+
.run(newId(), user, key, JSON.stringify(value), ts);
|
|
319
|
+
saved++;
|
|
320
|
+
}
|
|
321
|
+
return { status: 200, body: { ok: true, user, saved } };
|
|
322
|
+
}
|
|
323
|
+
return { status: 405, body: { ok: false, error: "method_not_allowed" } };
|
|
324
|
+
}
|
|
325
|
+
return { status: 404, body: { ok: false, error: "not_found" } };
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collecteur des contributions démo des modules métier.
|
|
3
|
+
*
|
|
4
|
+
* Chaque module du registre marque (`BrandModuleDef.demo`) peut contribuer
|
|
5
|
+
* des scénarios de démo interactive ; ce collecteur les agrège en la liste
|
|
6
|
+
* de DÉFAUTS servie par `createInteractiveDemoMount` :
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* createInteractiveDemoMount({ defaults: collectDemoScenarios() });
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* Contrat :
|
|
13
|
+
* - **validation** : chaque scénario passe `validateDemoScenario` — un
|
|
14
|
+
* scénario invalide est une erreur de module (bug), pas un cas runtime ;
|
|
15
|
+
* - **dédup par id** : un même id contribué deux fois par le MÊME module
|
|
16
|
+
* (module listé en double dans le registre) est ignoré silencieusement ;
|
|
17
|
+
* un même id contribué par DEUX modules différents est un conflit, sauf
|
|
18
|
+
* `os-tour` (`genericOsTourScenario` partagé — premier gagne) ;
|
|
19
|
+
* - **erreurs claires** : toutes les erreurs sont agrégées puis levées en
|
|
20
|
+
* UNE Error listant module + scénario + codes de validation — le boot
|
|
21
|
+
* échoue explicitement plutôt que de servir une démo tronquée ;
|
|
22
|
+
* - **ordre stable** : la sortie suit l'ordre du registre (contributions)
|
|
23
|
+
* puis l'ordre de déclaration dans chaque module — jamais de tri implicite.
|
|
24
|
+
*
|
|
25
|
+
* Zéro texte métier ici : les scénarios vivent dans les modules marque.
|
|
26
|
+
*/
|
|
27
|
+
import type { DemoScenario } from "./types.js";
|
|
28
|
+
/**
|
|
29
|
+
* Contribution démo d'un module métier — forme aplatie du champ
|
|
30
|
+
* `demo?: { scenarios: DemoScenario[] }` de `BrandModuleDef`, préfixée de
|
|
31
|
+
* l'id du module pour la dédup et les messages d'erreur.
|
|
32
|
+
*/
|
|
33
|
+
export type DemoModuleContribution = {
|
|
34
|
+
/** Id du module contributeur (clé de dédup et préfixe d'erreur). */
|
|
35
|
+
moduleId: string;
|
|
36
|
+
/** Scénarios par défaut contribués par le module. */
|
|
37
|
+
scenarios: DemoScenario[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Agrège les scénarios démo contribués par les modules métier.
|
|
41
|
+
*
|
|
42
|
+
* Renvoie les scénarios valides dans l'ordre stable contributions →
|
|
43
|
+
* déclaration. Lève une Error unique listant TOUTES les erreurs si un
|
|
44
|
+
* scénario est invalide (`validateDemoScenario`) ou si deux modules
|
|
45
|
+
* différents contribuent le même id.
|
|
46
|
+
*/
|
|
47
|
+
export declare function collectInteractiveDemoDefaults(contributions: readonly DemoModuleContribution[]): DemoScenario[];
|
|
48
|
+
//# sourceMappingURL=contributions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contributions.d.ts","sourceRoot":"","sources":["../src/contributions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,SAAS,sBAAsB,EAAE,GAC/C,YAAY,EAAE,CA0DhB"}
|