@mostajs/wagon-engine 0.0.0-stage → 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/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ # Changelog — @mostajs/wagon-engine
2
+
3
+ **Auteur** : Dr Hamid MADANI <drmdh@msn.com>
4
+ Format : Keep a Changelog ; versions : SemVer.
5
+
6
+ ## [0.1.0] — 2026-10-26
7
+
8
+ ### Extrait
9
+ - Le gabarit `Entreprise/mosta-wagon` 0.11.0 devient un module, sur décision du fondateur (26/10, `saas-making/methode/IDEES-A-INSTRUIRE.md` §I-2). Trois copies identiques de `src/wagon.mjs` existaient, et la 0.11 n'avait atteint que l'une d'elles.
10
+ - `creerWagon`, `schemasWagon`, `sauvegarder` et `suivrePalette` sont repris sans changement de comportement.
11
+ - La suite de conformité (T-WAG-1 à 29) est **publiée**. Elle juge la greffe de `WAGON_GREFFE`, ou du dossier courant.
12
+
13
+ ### Ajouté
14
+ - `demarrer({ config, charge, racine })` fait tout le démarrage d'une greffe : ce que faisait chaque `server.mjs` copié.
15
+ - Les commutateurs `PAIEMENT_STRIPE`, `PAIEMENT_CHARGILY`, `PAIEMENT_SATIM` et `PAIEMENT_PAYPAL` coupent un moyen de paiement par le `.env`, comme dans RestoTrax. L'utilisateur choisit parmi les moyens actifs.
16
+
17
+ ### Changé
18
+ - Le dossier légal par défaut est celui de la greffe (`racine/legal`).
19
+ - Dépendances à jour : `wagon-ui` ^0.9.1, `markdown-html` ^0.3.0, `garde-http` ^0.2.0, `payment` ^2.6.0, `subscriptions-plan` ^0.9.0 (SATIM).
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ @mostajs/wagon-engine
2
+ Copyright (C) 2026 Dr Hamid MADANI <drmdh@msn.com>
3
+
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU Affero General Public License as published by the Free
6
+ Software Foundation, either version 3 of the License, or (at your option) any
7
+ later version.
8
+
9
+ This program is distributed in the hope that it will be useful, but WITHOUT
10
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
12
+ details.
13
+
14
+ You should have received a copy of the GNU Affero General Public License
15
+ along with this program. If not, see <https://www.gnu.org/licenses/agpl-3.0.html>.
package/README.md CHANGED
@@ -1,3 +1,65 @@
1
- # Temporary Holding Version
1
+ # @mostajs/wagon-engine
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **Auteur** : Dr Hamid MADANI <drmdh@msn.com> · AGPL-3.0-or-later · Node ≥ 20
4
+
5
+ **Le wagon d'un SaaS, une fois pour toutes.** Il fournit les comptes, la connexion (mot de passe ou code par courriel), les paliers et leurs quotas, le paiement (Stripe, Chargily, SATIM, PayPal), l'espace client, l'administration, les pages légales, le référencement, les sauvegardes, et trois langues (fr, en, ar).
6
+
7
+ Une **greffe** n'apporte que ce qu'elle vend :
8
+
9
+ | la greffe écrit | rôle |
10
+ |---|---|
11
+ | `wagon.config.mjs` | identité, couleurs, langues, paliers et prix, moyens de paiement proposés |
12
+ | `charge/index.mjs` | ses pages et son API (`routes`), ses ressources mesurées, son accueil |
13
+ | `legal/*.md` | ses textes légaux, avec des jetons `{{…}}` remplis par la configuration |
14
+ | `.env` | ses secrets et ses adresses |
15
+
16
+ ## Installer
17
+
18
+ ```bash
19
+ npm install @mostajs/wagon-engine
20
+ ```
21
+
22
+ ## Démarrer une greffe
23
+
24
+ ```js
25
+ // server.mjs
26
+ import { demarrer } from '@mostajs/wagon-engine';
27
+ import config from './wagon.config.mjs';
28
+ import charge from './charge/index.mjs';
29
+ await demarrer({ config, charge });
30
+ ```
31
+
32
+ `demarrer` lit `.env` dans le dossier courant (`@mostajs/config`, cascade `MOSTA_ENV`), monte le courriel, la base et les moyens de paiement actifs, puis écoute sur `PORT`.
33
+
34
+ | `.env` | rôle |
35
+ |---|---|
36
+ | `PORT`, `HOST` | écoute (4800, 127.0.0.1) |
37
+ | `WAGON_BASE_URL` | l'adresse publique (liens des courriels, retours de paiement) |
38
+ | `WAGON_DB_DIALECT`, `WAGON_SGBD` | la base : `sqlite` et un chemin, ou `postgres` et `postgresql://…` |
39
+ | `WAGON_EMAIL_SERVER_HOST`, `…_PORT`, `…_USER`, `…_PASSWORD`, `WAGON_EMAIL_FROM` | le courriel (SMTP) |
40
+ | `WAGON_STRIPE_SECRET_KEY`, `WAGON_STRIPE_WEBHOOK_SECRET` | Stripe |
41
+ | `CHARGILY_SECRET_KEY` · `SATIM_MERCHANT_ID`, `SATIM_PASSWORD`, `SATIM_TERMINAL_ID` · `PAYPAL_…` | les banques prépayées proposées par `config.paiement.prepaye` |
42
+ | `PAIEMENT_STRIPE=off`, `PAIEMENT_CHARGILY=off`, `PAIEMENT_SATIM=off`, `PAIEMENT_PAYPAL=off` | **coupe un moyen** sans toucher à ses clés |
43
+ | `WAGON_ADMINS` | les courriels administrateurs (confirmés par un code reçu) |
44
+
45
+ **Le paiement est au choix de l'utilisateur**, parmi les moyens actifs. Un moyen est actif quand ses clés sont dans le `.env` et que son commutateur n'est pas sur `off`. Une banque prépayée doit en plus être proposée par la configuration.
46
+
47
+ ## Juger une greffe
48
+
49
+ La suite de conformité est publiée avec le moteur. Elle juge la greffe du dossier courant, ou celle que désigne `WAGON_GREFFE` :
50
+
51
+ ```bash
52
+ npx mjs-unit node_modules/@mostajs/wagon-engine/src/conformite/conformite.test.mjs
53
+ ```
54
+
55
+ Elle contrôle les comptes, le quota, le paiement (signatures Stripe réelles, banques simulées), la sécurité (CSRF, en-têtes, cookie), l'administration, les pages légales, la sauvegarde et les permissions par page. Un essai sans objet pour une greffe est **ignoré avec son motif**, jamais compté réussi.
56
+
57
+ ## Vérifier
58
+
59
+ ```bash
60
+ node examples/verifier.mjs # une greffe de vingt lignes démarre : paiement, paliers, texte légal, quota
61
+ ```
62
+
63
+ ## Référence
64
+
65
+ L'API et le contrat complet de la charge sont dans `llms.txt`.
@@ -0,0 +1,62 @@
1
+ // @mostajs/wagon-engine — exemple de vérification (DEVRULES §12) : une greffe minimale démarre sur le moteur.
2
+ // Author: Dr Hamid MADANI <drmdh@msn.com> · AGPL-3.0-or-later
3
+ // Lancer : node examples/verifier.mjs (sort en erreur si une réponse n'est pas celle attendue)
4
+ //
5
+ // La greffe tient en trois choses : une configuration, une charge, et un .env. Elle n'écrit ni route de compte, ni
6
+ // paiement, ni page légale : le moteur les apporte. Ici, dans un dossier jetable, avec une base sqlite.
7
+ import assert from 'node:assert/strict';
8
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
9
+ import { tmpdir } from 'node:os';
10
+ import { join } from 'node:path';
11
+ import { demarrer } from '../src/index.js';
12
+
13
+ const racine = mkdtempSync(join(tmpdir(), 'greffe-'));
14
+ mkdirSync(join(racine, 'legal'));
15
+ writeFileSync(join(racine, 'legal', 'cgu.fr.md'), '# Conditions\n\n{{SERVICE}} est édité par Exemple SARL.\n');
16
+ writeFileSync(join(racine, '.env'), `PORT=0\nWAGON_SGBD=${join(racine, 'wagon.db')}\nWAGON_BASE_URL=http://127.0.0.1\nCHARGILY_SECRET_KEY=test_sk_exemple\nPAIEMENT_STRIPE=off\n`);
17
+
18
+ const config = {
19
+ marque: { nom: 'Échos', symbole: 'É', auteur: 'Exemple SARL' }, langues: ['fr', 'en', 'ar'], connexion: 'motdepasse',
20
+ paiement: { prepaye: { chargily: 'DZD' } }, legal: { EDITEUR_NOM: 'Exemple SARL' },
21
+ paliers: [
22
+ // Le visiteur sans compte : son palier, hors vente. Sans lui, la charge lui est « non comprise » (403).
23
+ { slug: 'anonyme', name: 'Anonyme', price: 0, active: false, sortOrder: -1, limits: { echosParJour: 3, maxCles: 0 } },
24
+ { slug: 'gratuit', name: 'Gratuit', price: 0, sortOrder: 0, limits: { echosParJour: 5, maxCles: 1 } },
25
+ { slug: 'pro', name: 'Pro', price: 900, sortOrder: 1, limits: { echosParJour: 500, maxCles: 3 }, prepaid: { DZD: { month: 150000, year: 1500000 } } },
26
+ ],
27
+ };
28
+ // La charge : ce que le produit vend. Ici, répéter un texte, compté par jour.
29
+ const charge = {
30
+ liens: [{ href: '/echo', libelle: { fr: 'Écho', en: 'Echo', ar: 'صدى' } }],
31
+ ressources: [{ cle: 'echo', limite: 'echosParJour', periode: 'jour', libelle: { fr: 'Échos', en: 'Echoes', ar: 'أصداء' },
32
+ parPeriode: { fr: '{n} échos par jour', en: '{n} echoes a day', ar: '{n} صدى في اليوم' } }],
33
+ async routes(req, res, ctx) {
34
+ if (ctx.chemin !== '/echo') return false;
35
+ const v = await ctx.consommer('echo');
36
+ if (!v.allowed) return ctx.refuser(v);
37
+ return ctx.json(200, { echo: new URL(req.url, 'http://x').searchParams.get('t') ?? '' });
38
+ },
39
+ };
40
+
41
+ const g = await demarrer({ config, charge, racine, journal: { log: (m) => console.log(` ${m}`), warn() {}, error() {} } });
42
+ const base = `http://127.0.0.1:${g.serveur.address().port}`;
43
+ try {
44
+ console.log(`1. greffe démarrée ; moyens de paiement actifs : ${g.moyens.join(', ')} (Stripe coupé par PAIEMENT_STRIPE=off)`);
45
+ assert.deepEqual(g.moyens, ['chargily']);
46
+ const sante = await (await fetch(`${base}/health`)).json();
47
+ assert.equal(sante.ok, true);
48
+ console.log('2. /health :', JSON.stringify({ ok: sante.ok, application: sante.application }));
49
+ const tarifs = await (await fetch(`${base}/tarifs`)).text();
50
+ assert.ok(tarifs.includes('Pro') && tarifs.includes('Gratuit'));
51
+ console.log('3. /tarifs : les paliers de la configuration sont affichés');
52
+ const cgu = await (await fetch(`${base}/cgu`)).text();
53
+ assert.ok(cgu.includes('Exemple SARL'));
54
+ console.log('4. /cgu : le texte légal de LA GREFFE, ses jetons remplis');
55
+ const e = await (await fetch(`${base}/echo?t=bonjour`)).json();
56
+ assert.equal(e.echo, 'bonjour');
57
+ console.log('5. /echo : la charge répond à un visiteur, son quota (palier anonyme, 3 par jour) est compté par le moteur');
58
+ console.log('✓ vérification réussie');
59
+ } finally {
60
+ await g.fermer();
61
+ rmSync(racine, { recursive: true, force: true });
62
+ }
package/llms.txt ADDED
@@ -0,0 +1,40 @@
1
+ # @mostajs/wagon-engine — fiche LLM
2
+
3
+ > Le wagon d'un SaaS, une fois pour toutes : comptes, connexion, paliers, quotas, paiement (Stripe, Chargily, SATIM,
4
+ > PayPal), espace client, administration, pages légales, robots/sitemap, sauvegarde, fr/en/ar. Une GREFFE n'apporte que
5
+ > wagon.config.mjs, charge/, legal/ et son .env. N2 (pack). Extrait du gabarit mosta-wagon 0.11.0 le 26/10/2026.
6
+
7
+ - Version: 0.1.0 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
8
+ - Chemin: mostajs/mosta-platform-stack/mosta-wagon-engine · gabarit d'une greffe : Entreprise/mosta-wagon
9
+
10
+ ## EXPORTS
11
+ - demarrer({ config, charge, racine = cwd, journal }) → { wagon, serveur, moyens: string[], fermer() }
12
+ - creerWagon({ config, charge, sgbd: string|{dialect,uri}, baseUrl, stripe?, webhookSecret?, transport?, journal?,
13
+ paiement?: { banques: { chargily:'DZD', … }, port? }, racine? }) → { handler, catalogue(), catalogueStripe(), fermer(), … }
14
+ - schemasWagon() (sauvegarde) · sauvegarder({ cibles, driver, seau, recipients, garder }) · suivrePalette(…)
15
+ - '@mostajs/wagon-engine/conformite' = src/conformite/conformite.test.mjs (suite mjs-unit, juge WAGON_GREFFE ou cwd)
16
+
17
+ ## .env lu par demarrer
18
+ PORT, HOST · WAGON_BASE_URL · WAGON_DB_DIALECT (sqlite|postgres…), WAGON_SGBD · WAGON_EMAIL_SERVER_HOST/PORT/USER/PASSWORD,
19
+ WAGON_EMAIL_FROM (ou WAGON_COURRIEL_FICHIER pour les essais) · WAGON_STRIPE_SECRET_KEY|RESTRICTED_KEY, WAGON_STRIPE_WEBHOOK_SECRET ·
20
+ CHARGILY_SECRET_KEY|API_KEY · SATIM_MERCHANT_ID, SATIM_PASSWORD, SATIM_TERMINAL_ID · PAYPAL_CLIENT_ID, PAYPAL_SECRET,
21
+ PAYPAL_WEBHOOK_ID · PAIEMENT_<STRIPE|CHARGILY|SATIM|PAYPAL>=off (coupe le moyen) · WAGON_ADMINS · WAGON_INDEXER.
22
+ Moyen ACTIF = clés présentes ET commutateur ≠ off (ET, pour une banque prépayée, proposée par config.paiement.prepaye).
23
+
24
+ ## CONTRAT DE LA CHARGE (charge/index.mjs)
25
+ liens · ressources (quota { cle, limite, periode } | plafond { cle, limite, plafond: true }) · accueil · textes ·
26
+ routes(req, res, ctx) (passent en premier ; true si servie) · conformite (essai de quota T-WAG-3) · amorcer() (base au
27
+ démarrage) · exporterCompte(id), effacerCompte(id) (RGPD) · sitemap() · sauvegarde() · permissions (0.11 :
28
+ { '/page': { microphone: 'self' }, '/dossier/*': … }, garde-http ≥ 0.2).
29
+ ctx : chemin, methode, lang, t, ui, page({ titre, contenu }), envoyer, json, rediriger, formulaire, corpsJson({ strict }),
30
+ compte, consommer(cle), refuser(v), palier(), plafond(cle, n), admin.
31
+
32
+ ## PIÈGES
33
+ - wagon-ui ≥ 0.9 exige config.marque.auteur.
34
+ - Sans palier « anonyme » (config.planAnonyme), un visiteur sans compte n'a droit à aucune ressource (403).
35
+ - loadEnv ne SURCHARGE pas une variable déjà dans l'environnement (l'env réel prime sur le .env).
36
+ - Base PostgreSQL : la greffe ajoute la dépendance « pg ».
37
+
38
+ ## NE FAIT PAS
39
+ ce que le produit vend (la charge) · les pages (@mostajs/wagon-ui) · comptes et clés (@mostajs/comptes) · encaisser,
40
+ compter (@mostajs/payment, @mostajs/subscriptions-plan) · en-têtes (@mostajs/garde-http).
package/package.json CHANGED
@@ -1,6 +1,109 @@
1
1
  {
2
2
  "name": "@mostajs/wagon-engine",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
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
+ "keywords": [
6
+ "mostajs",
7
+ "saas",
8
+ "wagon",
9
+ "boilerplate",
10
+ "subscriptions",
11
+ "auth",
12
+ "payment",
13
+ "chargily"
14
+ ],
15
+ "author": "Dr Hamid MADANI <drmdh@msn.com>",
16
+ "license": "AGPL-3.0-or-later",
17
+ "type": "module",
18
+ "main": "src/index.js",
19
+ "exports": {
20
+ ".": "./src/index.js",
21
+ "./conformite": "./src/conformite/conformite.test.mjs",
22
+ "./sauvegarde": "./src/sauvegarde.mjs"
23
+ },
24
+ "files": [
25
+ "src",
26
+ "examples",
27
+ "llms.txt",
28
+ "README.md",
29
+ "CHANGELOG.md",
30
+ "LICENSE"
31
+ ],
32
+ "engines": {
33
+ "node": ">=20"
34
+ },
35
+ "scripts": {
36
+ "test": "bash test-scripts/run-tests.sh"
37
+ },
38
+ "dependencies": {
39
+ "@mostajs/auth-lite": "^1.2.0",
40
+ "@mostajs/auth-plug": "^0.3.0",
41
+ "@mostajs/auth-ui": "^0.4.0",
42
+ "@mostajs/backup": "^0.5.0",
43
+ "@mostajs/blob-store": "^0.4.1",
44
+ "@mostajs/comptes": "^0.1.0",
45
+ "@mostajs/config": "^1.1.0",
46
+ "@mostajs/crypto-box": "^0.3.0",
47
+ "@mostajs/data-plug": "^1.2.6",
48
+ "@mostajs/garde-http": "^0.2.0",
49
+ "@mostajs/i18n": "^0.2.0",
50
+ "@mostajs/mailer": "^0.2.0",
51
+ "@mostajs/markdown-html": "^0.3.0",
52
+ "@mostajs/orm": "^2.12.1",
53
+ "@mostajs/payment": "^2.6.0",
54
+ "@mostajs/subscriptions-plan": "^0.9.0",
55
+ "@mostajs/wagon-ui": "^0.9.1",
56
+ "better-sqlite3": "^12.11.1",
57
+ "stripe": "^17.7.0"
58
+ },
59
+ "devDependencies": {
60
+ "@mostajs/mjs-unit": "^0.10.0"
61
+ },
62
+ "mostajs": {
63
+ "niveau": "N2",
64
+ "nature": "compose",
65
+ "reutilisabilite": "multi-domaine",
66
+ "depend_de": [
67
+ "@mostajs/auth-lite",
68
+ "@mostajs/auth-plug",
69
+ "@mostajs/auth-ui",
70
+ "@mostajs/backup",
71
+ "@mostajs/blob-store",
72
+ "@mostajs/comptes",
73
+ "@mostajs/config",
74
+ "@mostajs/crypto-box",
75
+ "@mostajs/data-plug",
76
+ "@mostajs/garde-http",
77
+ "@mostajs/i18n",
78
+ "@mostajs/mailer",
79
+ "@mostajs/markdown-html",
80
+ "@mostajs/orm",
81
+ "@mostajs/payment",
82
+ "@mostajs/subscriptions-plan",
83
+ "@mostajs/wagon-ui"
84
+ ],
85
+ "forme": "pack",
86
+ "question": "Comment transporter le service qu'on vend — comptes, connexion, paliers, paiement, pages légales, administration — sans le recoder à chaque produit ?",
87
+ "entites": [],
88
+ "verbes": [
89
+ "creerWagon",
90
+ "demarrer",
91
+ "schemasWagon",
92
+ "sauvegarder",
93
+ "suivrePalette"
94
+ ],
95
+ "interop": [
96
+ "Stripe Checkout & webhooks",
97
+ "Chargily Pay v2",
98
+ "SATIM (CIB, Edahabia)",
99
+ "Fetch Metadata / CSP (garde-http)"
100
+ ],
101
+ "ne_fait_pas": {
102
+ "ce que le produit vend": "la charge de chaque greffe (charge/)",
103
+ "les pages": "@mostajs/wagon-ui",
104
+ "les comptes et clés": "@mostajs/comptes",
105
+ "encaisser, compter un quota": "@mostajs/subscriptions-plan, @mostajs/payment",
106
+ "les en-têtes de sécurité": "@mostajs/garde-http"
107
+ }
108
+ }
109
+ }