BERKIOSDocs
Studio

Modules d'application et CetteApplication

Pour construire des applications robustes (client seul, serveur seul ou client-serveur offline-first), un projet peut contenir des modules de code et, au plus, un fichier CetteApplication. Les deux sont optionnels.

Vocabulaire. Une interface est un écran (avant v0.7.297 le dossier de projet l'appelait « module »). Un module est un fichier de code Core. Dans le compilateur, modules[] désignait déjà des fichiers Core : ils gagnent un cycle de vie, rien n'y est renommé.

Dans le Studio

  • Panneau MODULES de la barre latérale (replié par défaut) : + crée un module (nom → identifiant gestionnaire_chemins, fichier modules/<id>.bk, modèle de code valide), clic = éditeur de code, ⚙ = réglages (cible, dépendances, événements, tâches), ✎ renomme (l'identifiant reste), ✕ supprime (et retire le module des dépendances des autres). « Créer CetteApplication » ajoute le fichier unique CetteApplication.bk.
  • L'éditeur de code ouvre un module ou CetteApplication en mode Core ; Vérifier et la vérification en direct utilisent l'analyseur du compilateur (syntaxe, types, imports importer "./autre.bk"), sans Bridge. Une pastille ⚠ signale un fichier en erreur (code, dépendance inconnue, cycle, événement ou tâche sans fonction, cibles incompatibles).
  • Les modules sont enregistrés dans le projet (appModules, application) et suivent annuler / rétablir.

Dossier de projet (format 2.1)

manifest.json            { interfaces: [...], modules: [...], application: { entry } }
interfaces/<nom>.interface.json  + <nom>.bk   (code BERKIOS CODE de l'interface)
modules/<id>.bk          modules de code
CetteApplication.bk      code partagé (facultatif)

manifest.modules et manifest.application ont exactement la forme que lit loadProjectModules du compilateur. Le format 2.0 (modules/*.module.json) reste lisible. Anciens noms conservés comme alias dépréciés : moduleGraph, ModuleContract, module-contracts.ts.

Module = un fichier de code (.bk)

Déclaré dans berkios.project.json :

{
  "application": { "entry": "CetteApplication.bk" },
  "modules": [
    { "id": "connection_manager", "entry": "modules/connection_manager.bk",
      "dependencies": ["gestionnaire_chemins"],
      "target": "client",
      "events": { "reseau:change": "surChangementReseau" },
      "tasks": [{ "function": "verifierReseau", "everyMs": 5000 }] }
  ]
}
ChampRôle
id, entryidentifiant et fichier Core (obligatoires)
dependenciesmodules à démarrer avant ; inconnu ou cycle = erreur au chargement
targetclient, serveur ou les-deux (défaut). L'hôte ignore les modules d'une autre cible
eventsévénement → fonction du module appelée avec la charge utile
tasksfonctions rappelées périodiquement (≥ 100 ms), jamais en double, erreurs isolées

Cycle de vie (tout est facultatif)

initialiser() → (abonnement aux événements) → demarrer() ; à l'arrêt arreter() dans l'ordre inverse des dépendances. Noms anglais acceptés : initialize, start, stop. Ces fonctions sont réservées à l'hôte : jamais importées ni appelables de l'extérieur.

API publique

Une fonction marquée publique est appelable par l'hôte (host.call) et par les imports. Si aucune n'est marquée, toutes le sont (compatibilité) ; privée exclut. L'hôte n'expose jamais les fonctions qu'un module a importées d'un autre.

publique fonction verifierReseau() -> Texte
privée fonction aide() -> Entier

Parler aux autres : état partagé et événements

Le Core n'a pas de variables globales. Les modules partagent :

  • etat_notifier("cle", valeur) / etat_observer("cle") → {key, value, exists} (pas de valeur nulle en Core : absent = exists faux, value = "") ;
  • evenement_emettre("nom", {...}), reçu par les modules qui déclarent l'événement dans events.

Événements système : reseau:change, session:connexion, app:erreur, app:demarree.

CetteApplication = code partagé par toutes les interfaces

Fichier Core unique, optionnel. L'hôte appelle les procédures qui existent :

ProcédureMoment
configurerTheme()tout début
auDemarrage()avant les modules
quandPret()après démarrage de tous les modules
surChangementReseau(info)événement reseau:change
apresConnexion(info)événement session:connexion
surErreur(erreur)toute erreur d'un module, d'une tâche ou d'un écouteur (module, fonction, message)
avantFermeture()début de l'arrêt

Noms anglais acceptés : configureTheme, onStart, onReady, onNetworkChange, onLogin, onError, onClose.

Utiliser l'hôte

import { loadProjectModules, createApplicationHost } from './compiler/src/index.mjs';
const loaded = loadProjectModules(manifest, manifestFile, { interfaces: [] });
const host = createApplicationHost({ modules: loaded.coreModules, application: loaded.application, target: 'client', commands });
await host.start();
host.call('sync_manager', 'enregistrerEcriture', ['clients', 'upsert', { id: 1 }, 1]);
await host.stop();

commands(commande, args, {moduleId}) fournit les commandes système (réseau, SQL, disque…) : le Bridge en production, une plateforme simulée dans l'exemple. L'hôte traite lui-même evenement-emettre, etat-notifier et etat-observer.

Correctifs du langage Core livrés avec cette fonctionnalité

  • Une affectation à une variable déjà déclarée, faite dans un bloc si / pour / essayer, était perdue à la sortie du bloc. Elle est désormais conservée (un soit dans le bloc reste local).
  • retourner dans un essayer n'est plus pris pour une erreur.
  • Le mot o est un mot-clé (« ou » espagnol) : ne pas l'utiliser comme nom de variable.

Limites connues

  • Le Core est synchrone. Les commandes du Bridge sont asynchrones (HTTP) : l'hôte actuel les consomme via un adaptateur synchrone (commands). Brancher le vrai Bridge demande un exécuteur Core asynchrone, qui n'existe pas encore.
  • Pas de valeur nulle ni de variables globales en Core ; les helpers privés de deux modules importés ensemble partagent un espace de noms plat (préfixer les noms).
  • Le Studio édite et vérifie les modules mais ne les exécute pas dans l'Aperçu, et les actions des interfaces ne les appellent pas encore : l'API est host.call(...).
  • Le dossier de projet (format 2.1) n'est pas encore branché sur « Enregistrer / Ouvrir » du Studio (fonctions splitProject / assembleProject).

Exemple complet

examples/application/offline-first : client offline-first avec les modules gestionnaire_chemins, connection_manager, abonnement_manager, sync_manager, rapports et un CetteApplication.bk. node examples/application/offline-first/demo.mjs déroule un scénario hors ligne → en ligne.