Aller au contenu
CADCAMFUN
Docs

Documentation

Créer une intégration de client API

Utilisez le SDK Promise, le client de contrat Effect complet ou les adaptateurs Effect générés avec leurs entrées réelles et leur comportement d'erreur.

Traduit automatiquement de l'anglais. Voir l'original en anglais

Choisissez un client

Le référentiel comporte trois surfaces client associées. Ils partagent des déclarations de point de terminaison, mais leur construction, leurs formes d'entrée, leurs dépendances d'exécution et leurs canaux d'erreur diffèrent. Choisissez-en un délibérément et conservez ensemble des exemples de cette surface.

SurfacePoint d'entréeExécution
SDK de promesse@cadcamfun/api/sdk, exporté CadCam.makeDes promesses de résultats ordinaires ; itérables asynchrones pour SSE. Utilise une récupération fournie ou globale.
Client sous contrat completApiClient depuis @cadcamfun/apiService d'effet avec middleware de transport et de support fourni par sa couche.
Adaptateurs d'effets généréspackages/api/src/client/generated/index.tsMéthodes aplaties autour du client contractuel ; l’appelant fournit le transport et le middleware requis.

Le package API est un espace de travail privé avec des exportations de sources. Les importations ci-dessous sont destinées à ce monorepo ou à une distribution qui assure effectivement ces exportations ; cette page ne revendique pas de package npm public disponible séparément. Les clients indépendants peuvent utiliser le Document OpenAPI ou HTTP simple.

Pour une première requête sans configuration de bibliothèque client, commencez par le procédure pas à pas HTTP capturée. Il établit comment les organismes de réussite et d’échec diffèrent selon les opérations.

Résoudre la connexion

Utilisez l'URL et le jeton de support d'application appartenant au lancement actuel du sidecar. Tauri les obtient grâce à get_sidecar_endpoint. Un processus de développement manuel imprime son port attribué dans un événement prêt. L'origine doit pointer vers le sidecar ou la passerelle compagnon admise, plutôt que vers le site de documentation ou les actifs Vite.

Après un redémarrage du sidecar, résolvez à nouveau la connexion. La réutilisation du port précédent peut entraîner un refus de connexion ou aborder accidentellement un autre processus. La réutilisation d'un jeton de lancement obsolète entraîne un échec d'autorisation. Une réponse de santé publique réussie ne prouve pas qu’une demande protégée sera admise.

La sélection du compte, l'admission des applications, l'admission des appareils et l'accès des agents externes sont distincts. L'optionnel x-session-token sélectionne un compte après l’admission de la candidature. Un jeton de pont à l'échelle d'un projet est limité à ses points de terminaison de pont d'action. Un jeton téléphonique fonctionne via la liste verte de la passerelle. Suivez le référence d'authentification avant de choisir la connexion pour une intégration.

SDK de promesse

L'espace de noms exporté est CadCam, et son constructeur est make. Fournissez une URL de base et des en-têtes par défaut. Les méthodes create et get ci-dessous utilisent des champs aplatis plutôt qu'un champ imbriqué. payload ou params objet.

Dans un espace de travail consommant @cadcamfun/api
import { CadCam } from "@cadcamfun/api/sdk"

const client = CadCam.make({
  baseUrl,
  headers: { Authorization: "Bearer " + token },
})

const projects = await client.projects.list()
const created = await client.projects.create({
  name: "Fixture plate",
  description: "An integration-created project",
})
const detail = await client.projects.get({ id: created.id })
console.log(projects.length, detail.name, detail._count.drawings)

Chaque appel est directement résolu en fonction de la charge utile de réussite de ce point de terminaison. projects.list() renvoie un tableau ; projects.create() renvoie une ligne de projet. Il n'y a pas d'universel { data, error } emballage et non throwOnError option de constructeur dans ce SDK. Certaines charges utiles de point de terminaison elles-mêmes contiennent data ou success parce que c'est leur contrat HTTP.

Le SDK prépare une URL à partir du chemin du point de terminaison et de l'URL de base configurée, code les identifiants de chemin, sérialise l'entrée JSON déclarée et vérifie l'état de réussite exact déclaré de l'opération. Il analyse ensuite JSON et renvoie sa valeur saisie. Le runtime Promise n’applique pas de décodeur de schéma Effect à chaque charge utile renvoyée ; Les types de sortie TypeScript ne valident pas une implémentation de serveur arbitraire.

Erreurs déclarées et de transport

Les échecs HTTP déclarés sont rejetés avec le corps de la réponse décodé. Cette valeur peut être un objet simple balisé plutôt qu'une instance d'erreur JavaScript. Les échecs de transport et de protocole utilisent les SDK ClientError.

Gérer les deux canaux d'erreur
import { ClientError } from "@cadcamfun/api/sdk"

try {
  await client.projects.create({})
} catch (error) {
  if (error instanceof ClientError) {
    console.error(error.reason, error.message)
  } else if (error && typeof error === "object" && "message" in error) {
    console.error(String(error.message))
  } else {
    console.error("Unrecognized API failure", error)
  }
}
Raison de l'erreur clientInterprétation
TransportRécupérer l'installation, la connexion, l'abandon ou l'échec de lecture du flux. Inspectez sa cause et la connexion actuelle.
UnexpectedStatusLe serveur a renvoyé un statut en dehors des statuts de réussite et d'échec déclarés de l'opération.
UnsupportedContentTypeUne réponse de flux n'avait pas le type de contenu de flux d'événements attendu.
MalformedResponseJSON ou un flux de réponse attendu n'a pas pu être décodé.
SseEventTooLargeLe tampon du flux d'événements a dépassé la protection de trame du runtime généré.

Par exemple, un nom de projet manquant constitue un échec commercial HTTP 400 même si le type d'entrée de création autorise l'omission. Une réinitialisation de connexion lors de la création d'un projet est différente : elle laisse le client dans l'incertitude quant à la fin de l'écriture. Lisez l'état de la ressource avant de répéter une mutation. Le SDK n’ajoute pas de protocole d’idempotence à l’échelle de l’application et ne réessaye pas automatiquement chaque appel rejeté.

Annulation et en-têtes

ClientOptions accepte baseUrl, une implémentation de récupération facultative et des en-têtes par défaut. Par appel RequestOptions accepte un signal et des en-têtes supplémentaires. Pour les méthodes sans entrée de point de terminaison, les options de requête sont le premier argument ; les méthodes avec entrée prennent les options de requête après.

Annulation par appel et sélection de compte
const controller = new AbortController()
const pending = client.projects.get(
  { id: projectId },
  {
    signal: controller.signal,
    headers: { "x-session-token": accountSessionToken },
  },
)
// Call controller.abort() when the operation is no longer needed.
const project = await pending

Le générateur de requêtes applique les en-têtes par défaut, les en-têtes déclarés par le point de terminaison, puis les en-têtes par appel. Une valeur par appel peut remplacer une valeur par défaut ; évitez de remplacer accidentellement Authorization lors de l’ajout d’en-têtes de compte ou de suivi. Ne placez pas d'informations d'identification dans les URL de point de terminaison copiées dans les journaux.

Injection fetch prend en charge un transport de test en cours ou un adaptateur contrôlé. L’adaptateur doit toujours respecter les en-têtes de demande, le corps, l’annulation, les types de contenu et la sémantique de l’état de réponse. La propre intégration Effect du bureau et le transport natif épinglé du téléphone effectuent un travail supplémentaire ; la substitution d'une récupération arbitraire ne reproduit pas ces limites natives.

Client à effet complet

ApiClient.layer construit le client HttpApi complet, récupère le transport et le middleware du support. Il expose les méthodes de point de terminaison avec la forme de requête HttpApi sous-jacente. La charge utile d'une mutation diminue payload, et les valeurs du chemin passent en dessous params.

Client sous contrat complet
import { ApiClient } from "@cadcamfun/api"
import { Effect } from "effect"

const createProject = Effect.gen(function* () {
  const api = yield* ApiClient
  return yield* api.projects.create({
    payload: { name: "Fixture plate" },
  })
}).pipe(Effect.provide(ApiClient.layer({ baseUrl, token })))

const project = await Effect.runPromise(createProject)

Ce client dérive de l'ensemble de la déclaration Api et constitue l'option pour les points de terminaison omis des cibles générées. Il préserve le canal d'erreur typé et le transport sensible aux schémas d'Effet. La durée de vie des ressources, l'interruption du flux et la fourniture des couches appartiennent au programme Effect appelant ; créer un effet ne l'exécute pas.

La couche réutilisable fournit le jeton d'application. Le bureau crée sa propre couche dans apps/desktop/src/app/client.ts pour attacher l'état de session de compte facultatif et le transport injecté. Réutilisez cette intégration lorsque vous travaillez sur le bureau au lieu de créer une deuxième connexion/environnement d'exécution par composant.

Adaptateurs d'effets générés

Le client Effect généré importe les schémas réels et adapte les méthodes dans des champs aplatis. C'est CadCam.make renvoie un effet qui construit le client adapté. Il ne fournit pas sa propre couche de transport de récupération ou d'autorisation d'application, l'appelant doit donc fournir les services et middleware correspondants.

L'adaptateur d'erreur généré mappe les échecs de transport/schéma/SSE dans un ClientError tout en conservant les pannes de domaine déclarées. Cette classe d'erreur est distincte de la classe d'erreur JavaScript du SDK Promise avec un reason chaîne. La similitude des noms ne rend pas leur manipulation interchangeable.

Gardez les exemples d’entrée explicites. Les formulaires Promesse et Effet généré utilisent projects.get({ id }); le formulaire de contrat brut utilise projects.get({ params: { id } }). Évitez de transmettre l'objet d'entrée d'une surface à un autre via une assertion de type non vérifiée.

Streaming

Les opérations Promise SSE renvoient des itérables asynchrones. La configuration du réseau se produit au début de l'itération. Le moteur d'exécution vérifie l'état de réussite et le type de contenu du flux d'événements, lit les données UTF-8 incrémentielles, normalise les limites des trames et décode les trames de données en JSON. Un cadre mal formé échoue à l’itération ; le nettoyage du lecteur s'exécute à la fin ou à la sortie de l'itération.

La garde du runtime est 16 * 1024 * 1024 unités de chaîne JavaScript mises en mémoire tampon. Il limite l'accumulation avant une limite de trame ; ce n'est pas une promesse que chaque charge utile arbitraire de 16 Mo est utile ou valide pour les schémas d'événements de l'application.

Consommez les événements IA en fonction de leurs discriminateurs et préservez l'identifiant de session. Un transport terminé ne constitue pas la preuve d'un événement de conversation terminale. Utiliser Streaming et récupération de l'IA pour le comportement de file d’attente, d’abandon, d’autorisation, de question et de récupération d’état. EventSource ne remplace pas une requête POST avec des en-têtes d'autorisation et un corps JSON.

Couverture et régénération

Le générateur dispose de listes d'omission explicites pour les formes qu'il ne peut pas représenter. Les omissions partagées incluent les téléchargements de profils/plug-ins en plusieurs parties, la création de MCP avec plusieurs schémas de réussite, les noms d'entrée en collision et la diffusion du plugin avec des en-têtes de réponse sur son flux. Les omissions supplémentaires de la promesse incluent les webhooks bruts signés, l'amorçage du plugin JavaScript, le téléchargement binaire et les demandes de générateur de forme libre.

Lisez les listes actuelles exactes dans packages/api/scripts/generate-clients.ts et le Présentation de l'API. Une méthode générée absente n’établit pas que le point de terminaison du serveur est indisponible. Utilisez le contrat complet du client ou un transport de matières premières approprié pour cette opération.

Racine du référentiel
bun run generate
bun run generate:check
bun run --filter @cadcamfun/web generate:api-reference
bun run --filter @cadcamfun/web check:api-reference

La régénération du client et la régénération de la documentation sont des résultats distincts du même contrat. Gardez les deux à jour après les modifications du point de terminaison. Ne modifiez pas les corps de méthode générés pour modifier les exigences d'entrée du serveur.

Le code généré est écrit dans packages/api/src/client/generated et packages/api/src/sdk/generated. Ne modifiez pas ces fichiers à la main ; changer le contrat et régénérer.

Vérification de l'intégration

Le comportement Promise create/read/plain-result et l'échec déclaré présenté ici ont été appliqués à la véritable pile de gestionnaires sidecar à l'aide d'une base de données jetable migrée. La procédure pas à pas HTTP contient les réponses observées correspondantes. Répétez les vérifications ciblées lors de la modification des schémas du générateur, de l'authentification ou du point de terminaison.

For an integration acceptance check, verify public health; a protected request without a token; the same request with the current token; a valid create/read cycle; a declared validation failure; a cancelled request; and a stream whose terminal state is checked. Use a disposable project and never infer successful persistence from a frontend fixture alone.

Les sources de mise en œuvre sont packages/api/src/sdk/generated/client.ts, c'est client-error.ts, packages/api/src/client.ts, packages/api/src/client/generated, et packages/httpapi-codegen/src/index.ts. Le générateur et les sorties validées établissent ensemble le comportement réel du client.

Référence des options du SDK Promise

OptionOùEffect
baseUrlCadCam.makeRésolu avec new URL(path, baseUrl); inclure le schéma et le port.
fetchCadCam.makeRemplacez le transport, par exemple pour ajouter de la journalisation ou pour injecter un double de test. La valeur par défaut est globalThis.fetch.
headersCadCam.makeEnvoyé avec chaque demande. Mettre authorization ici.
signalpar appelAbandonne la demande ; le rejet est ClientError("Transport").
headerspar appelRemplacez ou ajoutez des en-têtes pour un appel, tels que x-session-token. Les valeurs par appel l'emportent sur les valeurs des clients.

Quand un corps est présent et non content-type l'en-tête a été défini, le SDK définit application/json et sérialise avec JSON.stringify. Les paramètres de chemin sont toujours transmis encodeURIComponent, donc une clé telle que docs.walkthrough.units ou un contenant / reste un seul segment.

Raisons d'erreur client

RaisonÉlevé quandRéponse typique
Transportfetch lancé (refusé, réinitialisation, DNS, abandon) ou échec de la lecture d'un fluxRésolvez à nouveau l'URL sidecar ; réessayez les lectures ; relire l'état avant de réessayer l'écriture.
UnexpectedStatusLe statut n'est ni un statut de réussite ni un statut d'erreur déclarée. La cause tient { status }.Traitez comme une incompatibilité de contrat, souvent une version de serveur différente.
UnsupportedContentTypeUne opération de flux a répondu avec autre chose que text/event-stream, ou une opération JSON avec un type non-JSONVérifiez les proxys et la version du serveur.
MalformedResponseJSON vide ou invalide, un corps manquant ou un SSE data: bloc qui n'est pas JSONEnregistrez la réponse brute ; signalez-le.
SseEventTooLargeLe tampon SSE non analysé a dépassé 16 MioL'événement est refusé ; redémarrez le flux.

Le message d'un ClientError est la raison suivie du message de cause (par exemple Transport: fetch failed), donc la journalisation error.message seul, c'est déjà un diagnostic.

Réessayer les lectures idempotentes uniquement
import { CadCam, ClientError } from "@cadcamfun/api/sdk"

async function withRetry<T>(read: () => Promise<T>, attempts = 3): Promise<T> {
  for (let attempt = 1; ; attempt++) {
    try {
      return await read()
    } catch (error) {
      const transient = error instanceof ClientError && error.reason === "Transport"
      if (!transient || attempt >= attempts) throw error
      await new Promise((resolve) => setTimeout(resolve, 250 * 2 ** attempt))
    }
  }
}

const projects = await withRetry(() => client.projects.list())

Ne réessayez pas aveuglément d'écrire

Une écriture qui a échoué avec Transport peut avoir été appliqué. Relisez la ressource et soumettez-la à nouveau uniquement lorsqu'elle n'est pas là ; the API has no idempotency keys.

Consommer un flux avec le SDK

Itérer les événements de l'assistant
const controller = new AbortController()
const events = client.ai.chatStream(
  { message: "Pocket the 40 x 30 rectangle, 3 mm deep", projectId },
  { signal: controller.signal },
)

for await (const event of events) {
  switch (event.type) {
    case "delta": render(event); break
    case "permission_request": askUser(event); break
    case "done": finish(event); break
    case "error": showError(event); break
  }
}

L'itérateur analyse chaque bloc SSE : il rejoint le data: lignes du bloc, analyse le JSON et le renvoie. Commentaires et blocages sans data: sont ignorés. Quitter la boucle plus tôt (break, une exception ou un abandon) annule le lecteur et libère la connexion. L'événement type les valeurs sont celles répertoriées dans le guide de streaming de l'assistant ; vérifier le généré AiChatStreamOutput tapez pour l’union exacte.

Exemple : préférences via le SDK

Aller-retour clé-valeur
const key = "docs.walkthrough.units"

try {
  await client.kv.get({ key })
} catch (error) {
  if ((error as { _tag?: string })._tag !== "NotFound") throw error   // first run: 404
}

const saved = await client.kv.set({ key, value: { units: "mm" } })
// saved: { key, value: { units: "mm" }, updatedAt: "2026-…" }

const { entries } = await client.kv.list({ prefix: "docs." })
await client.kv.remove({ key })   // { message: "…" }

Les clés sont limitées à 512 caractères et doivent contenir du texte autre que des espaces ; les valeurs doivent être compatibles JSON (pas de cycles, de fonctions ou de nombres non finis).

En 3D

Ce que couvrent les clients Faites glisser vers l'orbite · faites défiler pour zoomer · faites glisser vers la droite pour effectuer un panoramique
Every API group as a column, height = operations counted from the generated OpenAPI document (270 in total). Rows are the six sidebar categories; ai (34), history (22) and costs (21) are the largest groups.