The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Mosta Net listing page.
One schema, 11 transports, 13 databases, multi-tenant auth — out of the box. Schema-driven multi-protocol API server for the @mostajs ecosystem. Built with TypeScript on Fastify, designed for polyglot consumption (14 native NetClients).
Author : Dr Hamid MADANI <drmdh@msn.com> Homepage : octonet.amia.fr · mcp.amia.fr
The socket board.
@mostajs/ormconnects to 13 databases; Octonet (@mostajs/net) re-exposes the same entities over 11 transports (REST, WebSocket, gRPC, MQTT, AMQP…); NetClient then fans out to 18 language clients — so any external app plugs into your data, in any runtime.
Octonet (@mostajs/net) is a Node.js multi-transport server that exposes a single @mostajs/orm schema as 11 different network protocols simultaneously : REST, GraphQL, WebSocket, SSE, JSON-RPC, MCP, gRPC, tRPC, OData, NATS, Arrow Flight.
The same User entity is reachable as :
Backed by @mostajs/orm (13 SGBD dialects). Backed by @mostajs/rbac + @mostajs/auth + @mostajs/api-keys for multi-tenant identity. Backed by @mostajs/mproject for multi-project routing.
Octonet is the second cerebral lobe of the @mostajs trilogy :
@mostajs/orm : data persistence (13 databases)The fastest way to test Octonet from any of the 14 runtimes :
alice-42)Your sandbox is :
User, Product, Order entitiesUse the apikey in any of the 14 NetClients :
| Tier | Cible | Auth | Quota | Use case |
|---|---|---|---|---|
T1 — Sandbox publique /try | "I want to test in 10 minutes" | alias seul (pas d'email) | 500 req/jour, TTL 7j | démo NetClients, intégration tests |
| T2 — Compte enregistré octocloud.amia.fr | "j'utilise vraiment, gratuit" | email + mot de passe | 10 000 req/jour | apps personnelles, side-projects |
T3 — Self-host npx @mostajs/net init | "tes données chez toi" | admin local | aucune | enterprise, on-premise, AGPL |
Auto-generated from your registered schemas. Toggle each via env var (default : all enabled).
| # | Transport | Endpoint | Use case | Notes |
|---|---|---|---|---|
| 1 | REST | /api/v1/{Entity} · /api/v1/{project}/{Entity} | universel | 15 routes par entité (CRUD + count + search + aggregate + bulk + relations) |
| 2 | GraphQL | /graphql (POST) | front-end riches | schéma + GraphiQL IDE auto-générés via mercurius |
| 3 | WebSocket | wss://…/ws | temps réel | events entity.created/updated/deleted/upserted broadcast |
| 4 | SSE | /events (GET stream) | mobile / browser-friendly | server-sent events |
| 5 | JSON-RPC | /rpc (POST) | EVM-adjacent, classic | JSON-RPC 2.0 + method discovery |
| 6 | MCP | /mcp (POST/GET SSE) | agents IA (Claude, ChatGPT) | 15 tools/entité auto-générés (listed on mcp.so) |
| 7 | gRPC | :50051 | inter-services low-latency | .proto auto-généré, 6 RPCs/entité |
| 8 | tRPC | /trpc/{Entity}.{op} | TypeScript fullstack | type generation côté client |
| 9 | OData | /odata/{Collection} (+ $metadata) | SAP/Microsoft Dynamics | OData v4 ($filter, $select, $orderby) |
| 10 | NATS | mostajs.{Entity}.{op} | pub/sub edge | request-reply messaging |
| 11 | Arrow Flight | /arrow/* | analytics columnaire | streaming zero-copy |
Le même schéma, 11 portes d'entrée différentes, 0 codegen.
Persistence dialects fournis par @mostajs/orm :
| Catégorie | Bases | Dialect ID |
|---|---|---|
| SQL mainstream | PostgreSQL, MySQL, MariaDB, SQLite | postgres, mysql, mariadb, sqlite |
| SQL enterprise | Oracle, SQL Server, DB2, SAP HANA, HSQLDB, Sybase | oracle, mssql, db2, hana, hsqldb, sybase |
| NewSQL / Cloud | CockroachDB, Google Cloud Spanner | cockroachdb, spanner |
| NoSQL | MongoDB | mongodb |
Switch dialect = changer 1 ligne d'env :
Octonet utilise un middleware d'authentification basé sur API keys avec scopes (orienté machine-to-machine) + RBAC pour la gestion humaine. L'orchestrateur agnostique vit dans @mostajs/auth/lib/check-request.ts.
Une apikey a la shape :
@mostajs/api-keys ne connaît PAS les noms projects/operations/transports — c'est volontaire. Chaque module enregistre ses scopes au boot via registerScope(dialect, {name, label, …}). Le check est générique : isScopeAuthorized(perms, scope, value).
| Cas | HTTP code | Body |
|---|---|---|
| Pas d'apikey | 401 | {error: {code:'UNAUTHORIZED', message:'API key required…'}} |
| Apikey invalide / révoquée | 401 | {error: {code:'UNAUTHORIZED', message:'Invalid or revoked API key'}} |
| Apikey valide hors scope | 403 | {error: {code:'FORBIDDEN', message:'API key not authorized for X="Y"'}} |
| Apikey OK | 200/201 | {status:'ok', data: …} (sanitized — no password/hash) |
L'endpoint /mcp autorise un fallback automatique sur l'apikey labelée public-default quand aucune clé n'est présentée — préserve la compat avec mcp.so / Claude Desktop. La clé publique est read-only sur le projet default uniquement → écritures bloquées.
Les champs password, hash, verifyToken, resetToken, apiKeyHash, secret, privateKey sont automatiquement strippés de toutes les réponses JSON par un middleware global. Aucun risque de leak à travers /api/v1/User?limit=1.
Le catalogue des scopes vit en base de données du projet accueillant (pas de fichier JSON, pas de constantes hardcodées) :
Chaque module enregistre ses scopes au boot :
L'admin UI charge le catalogue dynamique via GET /api/api-keys/scopes et rend une matrice (composant React ApiKeyScopeMatrix dans @mostajs/api-keys/components/).
Via @mostajs/mproject — N bases de données isolées sur le même serveur.
Persisté dans projects-tree.json (chemin : MOSTA_PROJECTS env var).
Console output :
Sépare la base système (apikeys, RBAC users, audit, plans, payments, project-life metadata) du dialect métier mutable. Sans ces variables, alias transparent vers le singleton métier (rétro-compat mono-base).
Voir section System dialect ci-dessous pour la motivation et les how-to.
@mostajs/config — supports profile cascade MOSTA_ENV=DEV)| Endpoint | Méthode | Auth | Description |
|---|---|---|---|
/health | GET | open | server status + transports + entities |
/try | GET | open | T1 sandbox provisioning HTML form |
/try | POST | open (rate-limit 10/h/IP) | crée sandbox + retourne apikey one-shot |
/api/v1/health | GET | open | health under api-versioned path |
| Endpoint | Méthode | Op | Description |
|---|---|---|---|
/api/v1/{Entity} | GET | findAll | list entities of default project |
/api/v1/{Entity}/:id | GET | findById | get one |
/api/v1/{Entity}/count | GET | count | count |
/api/v1/{Entity}/one | GET | findOne | first match |
/api/v1/{Entity}/search | GET | search | text search |
/api/v1/{Entity} | POST | create | insert |
/api/v1/{Entity}/:id | PUT | update | replace |
/api/v1/{Entity}/:id | DELETE | delete | remove |
/api/v1/{Entity}/:id/addToSet | POST | addToSet | add to array |
/api/v1/{Entity}/:id/pull | POST | pull | remove from array |
/api/v1/{Entity}/:id/increment | POST | increment | numeric add |
/api/v1/{Entity}/upsert | POST | upsert | insert or update |
/api/v1/{Entity}/aggregate | POST | aggregate | pipeline |
/api/v1/{Entity}/updateMany | POST | updateMany | bulk update |
/api/v1/{Entity}/deleteMany | POST | deleteMany | bulk delete |
/api/v1/{project}/{Entity}/… | * | * | same routes scoped to a project |
| Endpoint | Méthode | Description |
|---|---|---|
/api/upload-schemas-json | POST | push schemas at runtime (triggers reload) |
/api/apply-schema | POST | apply schema diff |
/api/compare-schema | POST | dry-run schema diff |
/api/schemas-config | GET | current registered schemas |
| Endpoint | Méthode | Description |
|---|---|---|
/api/api-keys | GET / POST | list / issue keys |
/api/api-keys/:id | PUT / DELETE | update / revoke |
/api/api-keys/scopes | GET | list registered scopes + values (for admin matrix UI) |
/api/api-keys/scopes | POST | register a new scope (admin) |
/api/api-keys/scopes/:name/values | PUT / DELETE | manage scope values |
| Endpoint | Description |
|---|---|
/graphql | GraphQL endpoint + GraphiQL IDE |
/ws | WebSocket connection (entity events) |
/events | SSE stream |
/rpc | JSON-RPC 2.0 |
/mcp | Model Context Protocol (Claude/Smithery/etc.) |
/trpc/{Entity}.{op} | tRPC procedure |
/odata/{Collection} · /odata/$metadata | OData v4 |
| Endpoint | Méthode | Description |
|---|---|---|
/api/projects | GET | list projects |
/api/projects | POST | add project |
/api/projects/:name | PUT / DELETE | edit / remove |
| Endpoint | Description |
|---|---|
/api/performance | live metrics (req/s, p50, p99) |
/api/config-tree | configuration tree (interactive) |
/api/live-log | streaming log feed |
| Module | Rôle dans Octonet |
|---|---|
@mostajs/orm | persistance (13 dialects) |
@mostajs/mproject | gestion multi-projet (default + sandbox + abonnés) |
@mostajs/rbac | identité (User, Role, Permission, Account) + AccountSchema + OCTONET_RBAC_SEED |
@mostajs/auth | checkRequest orchestrateur framework-agnostic, hashPassword |
@mostajs/api-keys | apikey CRUD + scopes (Scope/ScopeValue schemas) + checkApiKey + ApiKeyScopeMatrix admin UI |
@mostajs/config | env var helper avec cascade MOSTA_ENV |
@mostajs/cloud-middleware | quota / abonnement (optionnel — actif si Octocloud connecté) |
@mostajs/replicator | CQRS multi-replica (optionnel) |
@mostajs/project-life | persistence schemas Project (optionnel — si stockage SGBD vs JSON) |
Disponible depuis v2.7.5 — résout le bug « apikeys introuvables après
/api/change-dialect» observé en prod.
Octonet expose des routes admin qui mutent la connexion DB au runtime (/api/change-dialect, /api/reload-config, /api/reconnect) — légitime côté métier (les entités userland du projet courant peuvent migrer postgres → sqlite → mongodb selon les besoins de l'admin).
Mais les modules système (apikeys, RBAC users, audit, plans de souscription, payments, project-life metadata) doivent vivre dans une base stable qui ne suit pas ces mutations. Sinon : un changement de dialect métier rend les apikeys introuvables, l'admin se trouve verrouillé hors de l'IHM.
| Rôle | Variable env | Mutable au runtime ? | Lu par |
|---|---|---|---|
| Métier (entités userland) | DB_DIALECT + SGBD_URI | Oui (IHM admin) | EntityService, transports, routes data |
| Système (infra Octonet) | MOSTA_SYSTEM_DIALECT + MOSTA_SYSTEM_URI | Non (stable) | RBAC, apikey-middleware, account-scope, auth guards, sandbox /try |
Laisser MOSTA_SYSTEM_* vides → alias automatique vers le singleton métier (rétro-compat 100 %, comportement identique au pré-v2.7.5).
Avant v2.7.5, le 2ᵉ curl retournait 503 metadata DB unavailable ou 401 PostgreSQL not connected. Call connect() first.
Au boot d'octonet-mcp, deux logs apparaissent :
src/server.ts (pour référence)18 callers tirent désormais leur dialect via getSystemDialect() au lieu du singleton métier :
| Bloc | Sites | Caller |
|---|---|---|
| RBAC bootstrap | 1 | bootstrapRbac(systemDialect, …) |
| Scopes register | 4 | registerScope(systemDialect, …) × 3 + systemDialect.initSchema(scopeTables) |
| Middlewares globaux | 2 | createApiKeyMiddleware(() => systemDialect, …) + createAccountScopeMiddleware(() => systemDialect) |
| Middlewares per-transport | 2 | idem appliqués sur chaque transport.use(…) |
| Auth guards transports | 6 | authGuard(systemDialect, …) × 6 (SSE, GraphQL, JSON-RPC, gRPC, tRPC, OData) |
Custom /api/auth/verify | 2 | checkApiKey(systemDialect, …) + new UserRepository(systemDialect) |
Sandbox /try | 2 | registerTryRoutes({ dialect: systemDialect, … }) + startTrialCleanupJob({ dialect: systemDialect, … }) |
Le dialect métier (dialect) reste utilisé légitimement pour :
L98) + pm.setDefault('default', dialect, …) (L126, L240)/api/reconnect, /api/change-dialect, /api/reload-config, /api/test-connection, /api/truncate-tables, /api/drop-tables — toutes opérations explicitement métierEntityService qui sert les entités userland (opérations CRUD via les transports protégés)| Étape | Repo | Livré |
|---|---|---|
| 1 | @mostajs/data-plug v1.2.2-1.2.4 (API getSystemDialect + façade ORM) | npm |
| 2 | @mostajs/net v2.7.5 (bootstrapSystemDialect au démarrage) | git |
| 3 | @mostajs/api-keys 0.2.3, @mostajs/payment 0.4.1, @mostajs/project-life 0.1.3, @mostajs/subscriptions-plan 0.3.5 (WeakMap repos + façade) | npm |
| 4 | @mostajs/net v2.7.5 (consumers basculent sur getSystemDialect() — 18 sites) | git |
| 5 | Tests d'intégration scénario /api/change-dialect postgres → sqlite | ⏳ |
| 6 | Déploiement amia + smoke test MOSTA_SYSTEM_URI | ⏳ |
.env via @mostajs/config (profile cascade MOSTA_ENV)SGBD_URI)getAllSchemas() registry → schemas.json → SCHEMAS_PATH directory scan)dialect.initSchema(schemas) with strategy update/createoctonet-rbac-bootstrap.ts) :
seedRBAC(OCTONET_RBAC_SEED) — 6 categories, 25 permissions, 4 roles (admin/subscriber/trial/public)createAdmin() from OCTONET_ADMIN_EMAIL/PASSWORDtrial-playground (type='trial')public-demo (role=public)public-system (type='system')public-default scoped to default project (read-only, REST + MCP) — emitted ONCE in clearprojects (dynamic, Project.slug), operations (static : read/write/admin), transports (static : 11 values)projects-tree.json (ownerId=admin, visibility=public)projects-tree.jsoncomposeMiddleware([sanitizer, apikey], ormHandler) → protectedOrmHandlertransport.use(loggingMiddleware)transport.use(sanitizerMiddleware)transport.use(apiKeyMiddleware)transport.setHandler(ormHandler)transport.start(config)registerDynamicRestRoutes(app, protectedOrmHandler, pm) — /api/v1/...registerProjectRoutes(app, pm, protectedOrmHandler) — /:project/*registerTryRoutes(app, {dialect, pm}) — /try POSTregisterTryPage(app) — /try GET (HTML)startTrialCleanupJob({dialect, pm}) — cron horaire TTL 7jMOSTA_NET_PORT)Octonet est consommable depuis 14 runtimes natifs, avec la même apikey, la même URL :
| Runtime | Package | Registre |
|---|---|---|
| Node/TS | @mostajs/net/client (built-in) | npm |
| Java | com.mostajs:mostajs-net-client | Maven Central |
| Java + Spring Boot | com.mostajs:mostajs-net-client-spring-boot-starter | Maven Central |
| .NET | MostaJs.Net.Client | NuGet |
| Python | mostajs-net-client | PyPI |
| Go | github.com/apolocine/mosta-net-client-go | pkg.go.dev |
| Swift | mosta-net-client-swift | Swift Package Index |
| Kotlin | io.github.apolocine:mostajs-net-client-kt | Maven Central |
| Dart / Flutter | mostajs_net_client | pub.dev |
| Rust | mostajs-net-client | crates.io |
| PHP | mostajs/net-client | Packagist |
| Ruby | mostajs-net-client | RubyGems |
| Elixir | mostajs_net_client | Hex.pm |
| Lua | mostajs-net-client | LuaRocks |
| Delphi | MostaJsNetClient | GetIt |
| Unity (C#) | com.mostajs.net-client | OpenUPM |
Monorepo : github.com/apolocine/mosta-net-clients
Chaque NetClient suit le même contrat d'API :
Le déploiement de référence tourne sur octonet.amia.fr + mcp.amia.fr (alias compat) en backend PostgreSQL :
| URL | Rôle |
|---|---|
https://octonet.amia.fr | Octonet server (REST, MCP, GraphQL, WS, SSE, tRPC, OData, JSON-RPC) |
https://mcp.amia.fr | alias DNS de compatibilité — historique mcp.so |
https://octocloud.amia.fr | Octocloud — portail SaaS Next.js (subscriptions, admin UI) |
Le kit de déploiement complet est dans Entreprise/octonet-mcp/ :
apache/mcp.amia.fr.conf — vhost Apache2 (proxy SSE, WS upgrade, certs Let's Encrypt SAN)ecosystem.config.cjs — config PM2deploy.sh / install.sh / update.sh — scripts d'orchestrationtests/smoke-all.sh — suite de smoke tests (DNS, TLS, /health, SSE MCP, REST, /try, NetClient Java)AGPL-3.0-or-later — usage libre tant que le code dérivé reste open-source.
Licence commerciale disponible : drmdh@msn.com. Pricing par projet, pas par seat.
— (c) 2026 Dr Hamid MADANI <drmdh@msn.com>