@mostajs/wagon-engine 0.4.0 → 0.5.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/CHANGELOG.md +19 -0
- package/package.json +2 -2
- package/src/wagon.mjs +22 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
**Auteur** : Dr Hamid MADANI <drmdh@msn.com>
|
|
4
4
|
Format : Keep a Changelog ; versions : SemVer.
|
|
5
5
|
|
|
6
|
+
## [0.5.0] — 2026-10-28
|
|
7
|
+
|
|
8
|
+
### Ajouté
|
|
9
|
+
- **`config.cadreWagon`** : le cadre des pages du moteur (tarifs, inscription, connexion, aide, à propos, compte,
|
|
10
|
+
déconnexion), par exemple `{ disposition: 'application', application: { retour: '/', langues: true } }`. Une greffe
|
|
11
|
+
qui vit dans la disposition « application » n'y renvoie plus la vitrine et son menu commun à tous les publics. Une
|
|
12
|
+
page de la charge qui choisit son cadre le garde. Essai T-ENG-13.
|
|
13
|
+
|
|
14
|
+
### Corrigé
|
|
15
|
+
- **Le pied de page ne liste que les textes légaux servis** (`legaux`, `@mostajs/wagon-ui` ≥ 0.11) : un texte incomplet
|
|
16
|
+
n'était pas servi (0.4) mais restait lié, d'où un 404 sur chaque page. Essai T-ENG-12.
|
|
17
|
+
|
|
18
|
+
## [0.4.1] — 2026-10-28
|
|
19
|
+
|
|
20
|
+
### Corrigé
|
|
21
|
+
- **Le prix de l'inscription suit les moyens de paiement actifs** : la monnaie de chaque banque prépayée (Chargily :
|
|
22
|
+
DZD), puis l'euro si Stripe est actif. Une école payant en dinars voyait « 19,00 €/mois » sur « Créer un compte »
|
|
23
|
+
et « 8 000 DZD » sur les tarifs (Speaking, 28/10). Demande `@mostajs/wagon-ui` ≥ 0.10.1. Essai T-ENG-11.
|
|
24
|
+
|
|
6
25
|
## [0.4.0] — 2026-10-27
|
|
7
26
|
|
|
8
27
|
### Ajouté
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostajs/wagon-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Le wagon d'un SaaS, une fois pour toutes : comptes, connexion, paliers, quotas, paiement (Stripe, Chargily, SATIM), espace client, administration, pages légales, fr/en/ar. Une greffe n'apporte que wagon.config.mjs, charge/, legal/ et son .env ; la suite de conformité publiée juge la greffe.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mostajs",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@mostajs/orm": "^2.12.1",
|
|
53
53
|
"@mostajs/payment": "^2.6.0",
|
|
54
54
|
"@mostajs/subscriptions-plan": "^0.9.0",
|
|
55
|
-
"@mostajs/wagon-ui": "^0.
|
|
55
|
+
"@mostajs/wagon-ui": "^0.11.0",
|
|
56
56
|
"better-sqlite3": "^12.11.1",
|
|
57
57
|
"stripe": "^17.7.0"
|
|
58
58
|
},
|
package/src/wagon.mjs
CHANGED
|
@@ -347,6 +347,14 @@ export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null,
|
|
|
347
347
|
return { html: complet ? mdToHtml(texte).html : '', complet };
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
+
/** 0.5 — les textes légaux servis dans une langue (lus une fois : ils ne changent qu'au redéploiement). */
|
|
351
|
+
const LEGAUX = ['mentions-legales', 'cgu', 'cgv', 'confidentialite'];
|
|
352
|
+
const servis = new Map();
|
|
353
|
+
const legauxServis = (lang) => {
|
|
354
|
+
if (!servis.has(lang)) servis.set(lang, LEGAUX.filter((doc) => documentLegal(doc, lang).complet));
|
|
355
|
+
return servis.get(lang);
|
|
356
|
+
};
|
|
357
|
+
|
|
350
358
|
async function vueEspace(compte) {
|
|
351
359
|
const actif = await facturation.activePlan(String(compte.id));
|
|
352
360
|
const quotas = {};
|
|
@@ -413,7 +421,9 @@ export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null,
|
|
|
413
421
|
const qui = s ? await comptes.qui(String(s.user ?? s.userId ?? '')) : null;
|
|
414
422
|
const estAdmin = !!(qui && await estAdministrateur(qui.utilisateur.courriel));
|
|
415
423
|
// 0.5 — `chemin` : la page réelle (canonique, liens de langue) ; `actif` reste l'onglet (wagon-ui 0.5.1).
|
|
416
|
-
|
|
424
|
+
// 0.5 — le pied de page ne liste que les textes légaux SERVIS (un lien vers un texte incomplet menait à un 404) ;
|
|
425
|
+
// `config.cadreWagon` donne le cadre des pages du moteur (une page de la charge qui choisit le sien le garde).
|
|
426
|
+
const page = (o) => ui.page({ lang, connecte: !!qui, base: origine, chemin, legaux: legauxServis(lang), ...(config.cadreWagon ?? {}), ...o });
|
|
417
427
|
const ouvrirSession = async (userId, vers = '/compte') => rediriger(vers, { 'set-cookie': cookieStrict('wagon_session', await sessions.ouvrir(userId), { maxAge: 30 * 86400, https }) });
|
|
418
428
|
|
|
419
429
|
// 0.5 — la santé : le commit EN SERVICE (fichier REVISION posé par le déployeur) et l'heure de démarrage.
|
|
@@ -602,14 +612,23 @@ export async function creerWagon({ config, charge, sgbd, baseUrl, stripe = null,
|
|
|
602
612
|
if (chemin === '/inscription') {
|
|
603
613
|
const tous = await paliersEnBase();
|
|
604
614
|
const palierDe = (slug) => tous.find((p) => p.slug === slug && p.active !== false) ?? tous.find((p) => p.slug === (config.planGratuit ?? 'gratuit'));
|
|
615
|
+
// 0.4.1 — le prix montré est celui des moyens ACTIFS : la monnaie de chaque banque prépayée, puis l'euro de Stripe
|
|
616
|
+
// (une école payant en dinars voyait l'euro de Stripe ici, et les dinars sur /tarifs).
|
|
617
|
+
const prixDe = (p) => {
|
|
618
|
+
if (!p) return null;
|
|
619
|
+
const pp = typeof p.prepaid === 'string' ? JSON.parse(p.prepaid || 'null') : p.prepaid;
|
|
620
|
+
const l = [...new Set(Object.values(banques))].filter((dv) => Number(pp?.[dv]?.month) > 0).map((dv) => ({ centimes: Number(pp[dv].month), devise: dv }));
|
|
621
|
+
if (stripe && Number(p.price) > 0) l.push({ centimes: Number(p.price), devise: 'EUR' });
|
|
622
|
+
return l.length ? l : null;
|
|
623
|
+
};
|
|
605
624
|
const suite = suiteSure(url.searchParams.get('suite'));
|
|
606
625
|
const action = avecSuite('/inscription', suite);
|
|
607
|
-
if (methode === 'GET') return envoyer(200, page({ titre: t('inscription.titre'), contenu: ui.inscription({ lang, palier: palierDe(url.searchParams.get('plan')), methode: methodeConnexion, minMotDePasse: motsDePasse.policy.minLength, action }) }));
|
|
626
|
+
if (methode === 'GET') return envoyer(200, page({ titre: t('inscription.titre'), contenu: ui.inscription({ lang, palier: palierDe(url.searchParams.get('plan')), prix: prixDe(palierDe(url.searchParams.get('plan'))), methode: methodeConnexion, minMotDePasse: motsDePasse.policy.minLength, action }) }));
|
|
608
627
|
if (!freinInscription.take(`ip:${ipClient(req)}`).ok) return envoyer(429, page({ titre: t('inscription.titre'), contenu: `<p class="msg">${esc((TEXTES_COMPTE[lang] ?? TEXTES_COMPTE.fr).trop)}</p>` }), { 'retry-after': '60' });
|
|
609
628
|
const f = await formulaire();
|
|
610
629
|
const palier = palierDe(f.plan);
|
|
611
630
|
const courriel = String(f.courriel ?? '').trim().toLowerCase();
|
|
612
|
-
const refus = (m) => envoyer(200, page({ titre: t('inscription.titre'), contenu: ui.inscription({ lang, palier, erreur: m, methode: methodeConnexion, minMotDePasse: motsDePasse.policy.minLength, action }) }));
|
|
631
|
+
const refus = (m) => envoyer(200, page({ titre: t('inscription.titre'), contenu: ui.inscription({ lang, palier, prix: prixDe(palier), erreur: m, methode: methodeConnexion, minMotDePasse: motsDePasse.policy.minLength, action }) }));
|
|
613
632
|
if (!COURRIEL.test(courriel) || !String(f.nom ?? '').trim()) return refus(t('inscription.courrielAide'));
|
|
614
633
|
if (await d.findOne(S.User, { email: courriel })) return refus(t('inscription.deja'));
|
|
615
634
|
if (methodeConnexion === 'motdepasse') {
|