Construire un module

Démarrage rapide

Construisez et installez un module en local. Chaque module est autonome : il tire ses dépendances partagées depuis des git-tags et des paquets npm, sans avoir besoin des dépôts voisins.

1. Cloner et construire #

git clone https://github.com/kubuno/calendar && cd calendar
cargo build --release
(cd frontend && npm ci && npm run build)

2. Empaqueter et installer #

bash build_deb.sh --install     # → dist/kubuno-<id>_*.deb puis apt install local
Note

Le layout installé est /usr/lib/kubuno/modules/<id>/…. Un module doit avoir été installé une fois pour exister dans ce répertoire.

3. Boucle de dev rapide #

Pour itérer sans reconstruire un .deb :

bash _tools/deploy_local.sh <module>             # backend + frontend
bash _tools/deploy_local.sh <module> --frontend  # frontend seul (le plus rapide)

Votre premier endpoint — au choix du langage #

Un module n'est qu'un service HTTP local que le core proxifie. Le core supervise nativement les runtimes Rust et Python, mais n'importe quel langage qui parle HTTP peut être un module : déclarez runtime = "binary" dans le manifeste et fournissez l'exécutable. Voici le même endpoint /ping dans cinq langages :

// Rust — Axum
use axum::{routing::get, Json, Router};
use serde_json::json;

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/ping", get(|| async { Json(json!({ "ok": true })) }));
    let l = tokio::net::TcpListener::bind("127.0.0.1:3120").await.unwrap();
    axum::serve(l, app).await.unwrap();
}
<?php
// PHP — lancé avec : php -S 127.0.0.1:3120 router.php
header('Content-Type: application/json');
if (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) === '/ping') {
    echo json_encode(['ok' => true]);
    exit;
}
http_response_code(404);
# Python — Flask
from flask import Flask, jsonify

app = Flask(__name__)

@app.get("/ping")
def ping():
    return jsonify(ok=True)

app.run(host="127.0.0.1", port=3120)
// Go — net/http
package main

import (
    "encoding/json"
    "net/http"
)

func main() {
    http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
        json.NewEncoder(w).Encode(map[string]bool{"ok": true})
    })
    http.ListenAndServe("127.0.0.1:3120", nil)
}
# Perl — Mojolicious::Lite
use Mojolicious::Lite -signatures;

get '/ping' => sub ($c) {
    $c->render(json => { ok => \1 });
};

app->start('daemon', '-l', 'http://127.0.0.1:3120');
Note

Le port (ici 3120) doit correspondre à celui déclaré dans [server] du module.toml. Le module n'écoute que sur 127.0.0.1 : c'est le core qui l'expose.

4. Checklist de fin de tâche #

  • cargo build --release (+ SQLX_OFFLINE=true si cache .sqlx).
  • cd frontend && npm run build puis tsc -b.
  • Tester réellement (curl, navigateur) — pas seulement compiler.
  • cargo clean après un build lourd.
Important

Si vous touchez à une crate partagée ou à une lib @kubuno/*, prévoyez un nouveau tag / version npm puis bumpez la dépendance dans les modules.