API-KA — plateforme centrale : collecte quotidienne des 8 services KA, historisation append-only et API publique sur www.api-ka.com
Python 60.9%
HTML 21%
TypeScript 7.3%
JavaScript 5.2%
CSS 4.8%
Shell 0.8%
1/* ============================================2 Projet : API-KA3 Fichier : src/api/web/ka/ka-shell.js4 Node : m3u96b5 Author : Simon-Pierre Boucher6 Contact : contact@spboucher.ai7 Date : 2026-08-178 ============================================9 Coquille commune Groupe KA pour les pages statiques d'API-KA :10 · footer commun .ka-footer (équivalent vanilla de ka-ui/KaFooter.tsx),11 alimenté par /ka/ecosystem.json (source de vérité unique) ;12 · cartes contact (page /contact, conteneur #ka-contacts) ;13 · état de connexion KA ID dans le header (conteneur #ka-auth). */14"use strict";1516const KA_SITE_ID = "api-ka";1718async function kaEco() {19 const r = await fetch("/ka/ecosystem.json");20 return r.json();21}2223function el(tag, cls, html) {24 const e = document.createElement(tag);25 if (cls) e.className = cls;26 if (html !== undefined) e.innerHTML = html;27 return e;28}2930function esc(s) {31 return String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");32}3334/* ---------- footer commun (structure .ka-footer de tokens.css) ---------- */35function kaRenderFooter(eco) {36 const root = document.getElementById("ka-footer-root");37 if (!root) return;38 const site = eco.sites.find((s) => s.id === KA_SITE_ID);39 const others = eco.sites.filter((s) => s.id !== KA_SITE_ID);40 const year = new Date().getFullYear();41 root.innerHTML = `42 <a class="wordmark" href="${eco.hub.url}" target="_blank" rel="noopener noreferrer"43 aria-label="Groupe KA — le portail de l'écosystème">Groupe <span class="ka">KA</span></a>44 <p class="desc">${esc(eco.org.tagline)} Des centaines de connecteurs lisent les sites à la45 source, normalisent la donnée et se resynchronisent seuls.46 ${site ? `<b style="color:var(--paper)">${esc(site.wordmark)}</b> — ${esc(site.tagline)} — est un service Groupe KA.` : ""}</p>47 <p class="notice"><b>${esc(eco.org.disclaimer)}</b></p>48 <ul class="sites">49 ${others.map((s) => `<li><a href="https://${s.domain}" target="_blank" rel="noopener noreferrer">${esc(s.wordmark)}</a></li>`).join("")}50 ${(eco.extraFooterLinks || []).map((l) => `<li><a href="${l.href}" target="_blank" rel="noopener noreferrer">${esc(l.label)}</a></li>`).join("")}51 </ul>52 <div class="contacts">53 ${eco.contacts.map((c) => `<p style="margin:0"><a href="mailto:${c.email}">${c.email}</a><span>${esc(c.role)}</span></p>`).join("")}54 </div>55 <p class="legal">© ${year} ${esc(eco.org.copyrightHolder)}56 · <a href="/doc/">Documentation</a>57 ${eco.legal.map((l) => ` · <a href="${l.href}" target="_blank" rel="noopener noreferrer">${esc(l.label)}</a>`).join("")}58 </p>`;59}6061/* ---------- cartes contact (page /contact) ---------- */62function kaRenderContacts(eco) {63 const zone = document.getElementById("ka-contacts");64 if (!zone) return;65 zone.innerHTML = eco.contacts66 .map(67 (c) => `<div class="card contact-card">68 <span class="klabel">${esc(c.role)}</span>69 <a class="contact-mail" href="mailto:${c.email}">${c.email}</a>70 </div>`71 )72 .join("");73 const hub = document.getElementById("ka-hub-link");74 if (hub) hub.href = eco.hub.url + eco.hub.loginPath;75}7677/* ---------- connexion KA ID dans le header (#ka-auth) ---------- */78async function kaRenderAuth() {79 const zone = document.getElementById("ka-auth");80 if (!zone) return;81 try {82 const r = await fetch("/api/auth/me", { headers: { Accept: "application/json" } });83 if (r.ok) {84 const u = await r.json();85 zone.innerHTML = `<span class="ka-user" title="${esc(u.email || "")}">86 ${u.picture ? `<img src="${u.picture}" alt="" class="ka-avatar">` : ""}87 <b>${esc(u.name || "membre")}</b></span>88 <button class="btn btn-ghost ka-logout" type="button">Déconnexion</button>`;89 zone.querySelector(".ka-logout").addEventListener("click", async () => {90 await fetch("/api/auth/logout", { method: "POST" });91 location.reload();92 });93 return;94 }95 } catch {}96 zone.innerHTML = `<a class="btn btn-accent ka-login" href="/api/auth/ka/login">Se connecter avec KA</a>`;97}9899(async () => {100 kaRenderAuth();101 try {102 const eco = await kaEco();103 kaRenderFooter(eco);104 kaRenderContacts(eco);105 } catch {}106})();107