PageSourceSearch

https://creaconnect.world/src/crea-appel-http.js

js creaconnect.world collected 2026-09-24 10:09:08 UTC 4,850 bytes, 77 lines download raw bytes

1/* ═══════════════════════════════════════════════════════════════════════════
2 * LE POSTE DE L'APPEL HTTP — LE BRAS EST AU SERVEUR, LA PAROLE EST ICI
3 * ═══════════════════════════════════════════════════════════════════════════
4 *
5 * ── CE QU'IL A FALLU NE PAS ÉCRIRE ────────────────────────────────────────
6 *
7 * J'allais écrire une passerelle sortante. Elle existait : `/api/connect`
8 * (#211), gardée par `fetchRemoteUrl` — DNS résolu, réseau interne refusé,
9 * chaque redirection rejugée sur cinq sauts — journalisée, et AUCUN outil ne
10 * la tenait. `connector_call` exige un connecteur enregistré à l'avance ;
11 * devant « appelle cette API », CRÉA n'avait donc rien, alors que le bras
12 * était posé là depuis longtemps, inutilisé.
13 *
14 * ── ET POURQUOI CE FICHIER NE `fetch` PAS L'ADRESSE ───────────────────────
15 *
16 * Appeler l'adresse depuis la page contournerait les trois gardes d'un coup :
17 * le DNS n'est pas résolu, le réseau interne redevient joignable, une
18 * redirection vers 169.254.169.254 n'est rejugée par personne. On donne
19 * l'adresse au serveur, et c'est tout ce que ce poste fait du réseau.
20 *
21 * ── CE QUI EST À LUI, ALORS ───────────────────────────────────────────────
22 *
23 * La PAROLE : ce que le modèle lit quand ça marche, et surtout quand ça ne
24 * marche pas. Un 404 ou un 401 EST le résultat — le remplacer par « échec »
25 * ferait re-tenter à l'aveugle, alors que le corps dit souvent quoi corriger.
26 * Et un refus se dit AVEC son remède : « 400 » ne s'apprend pas,
27 * « écris {{SECRET:NOM}} » se corrige au coup suivant.
28 *
29 * Le tronc, lui, garde le geste — trois lignes — comme il le fait déjà pour
30 * le pont de l'atelier.
31 */
32
33const CREA_APPEL_HTTP = (() => {
34  const METHODES = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD']
35
36  /* L'HÔTE, POUR LE DIRE À LA PERSONNE. Une adresse de 300 caractères ne se
37     lit pas dans une fenêtre d'accord ; son hôte, oui. Et une adresse illisible
38     ne fait pas tomber la phrase : on rend ce qu'on a. */
39  function hoteDe(adresse) {
40    try { return new URL(String(adresse || '')).host } catch (e) { return String(adresse || '').slice(0, 60) }
41  }
42
43  async function appeler(args, contexte) {
44    const a = args || {}
45    const ctx = contexte || {}
46    const adresse = String(a.url || '').trim()
47    if (!adresse) return "Il manque l'adresse à appeler."
48    const voulue = String(a.method || 'GET').toUpperCase()
49    const methode = METHODES.indexOf(voulue) >= 0 ? voulue : 'GET'
50    const borner = typeof ctx.borner === 'function' ? ctx.borner : ((t) => String(t).slice(0, 12000))
51    try {
52      const r = await fetch('/api/connect', {
53        method: 'POST',
54        headers: { 'Content-Type': 'application/json', ...(ctx.jeton ? { Authorization: 'Bearer ' + ctx.jeton } : {}) },
55        body: JSON.stringify({ url: adresse, method: methode, headers: a.headers || {}, body: a.body ?? null }),
56      })
57      const d = await r.json().catch(() => ({}))
58      if (d && d.raison) return 'Appel refusé (' + d.raison + ') : ' + (d.error || '') + "\nRien n'est parti."
59      /* LA PASSERELLE BRUTE EST RÉSERVÉE AU PROPRIÉTAIRE, et le dire évite de
60         re-tenter dix fois la même chose : ce n'est pas l'appel qui est
61         mauvais, c'est le compte. `connector_call` reste ouvert. */
62      if (r.status === 401 || r.status === 403) return "Appel refusé : la passerelle sortante est réservée au propriétaire du déploiement. Un connecteur nommé (connector_list / connector_call) reste possible."
63      if (!r.ok && d && d.error) return 'Appel impossible : ' + d.error
64      if (typeof d.status !== 'number') return 'Appel impossible : réponse illisible du serveur.'
65      const corps = borner(String(d.body || '(corps vide)'), { max: 12000, queue: 4000, quoi: 'Corps de la réponse' })
66      return methode + ' ' + adresse + ' → HTTP ' + d.status
67        + (d.ok ? '' : ' (le service a répondu une erreur — le corps ci-dessous dit souvent laquelle)') + ' :\n' + corps
68    } catch (e) {
69      return 'Appel impossible : ' + ((e && e.message) || 'erreur inconnue')
70    }
71  }
72
73  return { appeler, hoteDe }
74})()
75
76window.creaAppelHttp = (args, contexte) => CREA_APPEL_HTTP.appeler(args, contexte)
77window.creaAppelHttpHote = (adresse) => CREA_APPEL_HTTP.hoteDe(adresse)

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.