SDK du noyau d'ontologie
Accès typé et limité à la requête au noyau d'ontologie d'un environnement d'espace de travail Scrydon.
SDK du noyau d'ontologie
Utilisez createKernelClient depuis @scrydon/ontology-sdk/client dans les appelants côté serveur.
Le client est limité à la requête : fournissez le transport admis de l'appelant ainsi que les
en-têtes exacts de l'organisation, de l'espace de travail et de son environnement. Ne mettez jamais
en cache les en-têtes d'un utilisateur, n'exposez pas les identifiants de service au navigateur et
ne remplacez pas le tuple complet par une portée limitée à l'organisation.
import { createKernelClient } from "@scrydon/ontology-sdk/client";
const ontology = createKernelClient({
baseUrl: `${ontologyServiceUrl}/api/ontology`,
headers: () => ({
...admittedCallerHeaders(),
"x-organization-id": organizationId,
"x-workspace-id": workspaceId,
"x-workspace-environment-id": workspaceEnvironmentId,
}),
});
const result = await ontology.objects.query({
ontology: "crm",
objectTypes: ["Customer"],
limit: 50,
});Les lectures publiées résolvent la révision courante, sauf si vous fournissez un revisionId
immuable ; les lectures de branche utilisent un apiName de branche. Les écritures passent par
actions.submit avec un type d'action final tel que schema.declare, schema.publish,
branch.submit ou proposal.approve. Les erreurs sont des valeurs OntologyApiError avec un code
stable généré, un httpStatus et des détails bornés. Une réponse non-2xx dépourvue d'enveloppe
d'erreur du noyau — un 502 HTML renvoyé par un proxy, un 401 vide provenant du maillage — est elle
aussi une OntologyApiError : son code est MALFORMED_ERROR_RESPONSE, httpStatus reprend le
statut retourné et details contient le type de contenu de la réponse ainsi qu'un aperçu borné du
corps.
Client namespaces
| Namespace | Methods |
|---|---|
actions | submit |
actionTypes | get, list |
aliases | list, resolve |
bindings | count, enroll, get, instances, list, materialize, materializeByObjectType, readiness, readinessOf, resolveByObjectType, resume, table |
branches | archive, create, declare, get, list, manifest, publish, rebase, submit |
decisions | get |
extensions | apply, autoInstall, installed |
geo | layers |
graph | expand, instanceGraph, layout, layoutRun, layoutStatus, neighbors, schemaSlice, search, trail, viewport |
links | list |
linkTypes | get, list |
mappings | suggest |
objects | get, list, neighbors, query |
ontologies | list |
proposals | get, list |
rdf | export, import |
revisions | resolve |
search | query |
types | get, list |
watches | dispatches.claim, dispatches.settle, evaluate, list |
Error contract
| Typed error | HTTP |
|---|---|
APPROVAL_REQUIRED | 409 |
BRANCH_BASE_STALE | 409 |
CONFLICT_DETECTED | 409 |
EXPORT_DENIED | 403 |
FORBIDDEN | 403 |
HISTORICAL_SOURCE_UNAVAILABLE | 422 |
HUMAN_REVIEW_REQUIRED | 422 |
IDEMPOTENCY_CONFLICT | 409 |
IDEMPOTENT_REPLAY | 200 |
MIGRATION_REQUIRED | 422 |
NOT_FOUND | 404 |
PROJECTION_LAGGING | 503 |
RECOMMENDATION_STALE | 409 |
REVISION_MISMATCH | 409 |
RULES_REJECTED | 422 |
SHAPE_VIOLATION | 422 |
SOURCE_READ_UNAVAILABLE | 503 |
STALE_READ_SET | 409 |
UNAUTHORIZED | 401 |
VALIDATION_FAILED | 400 |
Capacités absentes, pannes et le « pas encore » du noyau
Trois familles de rejets se ressemblent sur le fil et doivent être traitées différemment. Le SDK
exporte un assistant par famille pour que les appelants ne redérivent jamais la règle depuis
details.
Une liaison qui ne peut pas produire de lignes
bindingReadCapabilityReason(error) répond pourquoi une lecture de liaison ne peut pas renvoyer
de page, ou null lorsque l'erreur est une vraie faute à présenter comme telle. Le verdict repose
sur details.reasonCode — jamais sur la présence éventuelle d'un details.reason lisible par un
humain :
| Forme sur le fil | Signification | L'assistant renvoie |
|---|---|---|
VALIDATION_FAILED (400) avec details.reasonCode: "BINDING_KIND_NOT_GOVERNED" | Le type de liaison n'a pas de lecteur gouverné (memex_page aujourd'hui). Permanent pour cette version ; réessayer n'aide jamais. | le message serveur — binding kind has no governed reader |
SOURCE_READ_UNAVAILABLE (503) avec details.reasonCode: "BINDING_SOURCE_NOT_PROVISIONED" (plus details.reason quand le noyau dispose d'une phrase) | La source n'est pas encore approvisionnée — p. ex. Table "aircraft_position" not registered — upload a CSV with that name in /tables. Seul un opérateur peut la corriger. | details.reason, ou le message serveur si le noyau n'a envoyé aucune phrase |
Toute autre forme, y compris un SOURCE_READ_UNAVAILABLE (503) ne portant qu'un details.reason en texte libre | Une vraie panne. Réessayez. | null |
BINDING_READ_REASON_CODES est l'objet constant exporté (KIND_NOT_GOVERNED,
SOURCE_NOT_PROVISIONED) ; branchez dessus plutôt que sur le littéral, et utilisez
isBindingReadReasonCode(value) pour restreindre un code arrivé en unknown. Une surface de
graphe ou de liste doit se dégrader autour des deux premières lignes (afficher la liaison comme
ignorée avec la raison) et ne rendre que la troisième comme une erreur.
Un 503 portant un details.reason mais aucun details.reasonCode est une panne, pas une lacune
de capacité. Les versions précédentes classaient sur la présence de la phrase : tout 503 qui
transportait par hasard un texte de diagnostic cessait d'être réessayé. Le code est le contrat ; la
phrase n'est qu'une courtoisie pour la personne qui lit l'écran.
Attendre une projection
Le noyau est event-sourced : une écriture est acquittée quand sa ligne de registre est validée, et
les lectures la voient une fois le projecteur à jour. Une lecture émise juste après une écriture
peut donc répondre NOT_FOUND ou PROJECTION_LAGGING pour une ressource qui existe.
isTransientProjectionError(error) est vrai exactement pour ces deux codes — l'ensemble est
TRANSIENT_PROJECTION_ERROR_CODES — et c'est le seul prédicat sur lequel une attente bornée doit
réessayer. REVISION_MISMATCH n'en fait délibérément pas partie : il signifie que la prémisse
de l'appelant a changé, et relire avec la même prémisse est une boucle, pas une récupération.
import { isTransientProjectionError } from "@scrydon/ontology-sdk/client";
const deadline = Date.now() + 5_000;
for (;;) {
try {
return await ontology.branches.get({ ontology, branch });
} catch (error) {
if (!isTransientProjectionError(error) || Date.now() >= deadline) throw error;
await new Promise((resolve) => setTimeout(resolve, 100));
}
}Un lien dont les arêtes sont calculées, pas stockées
Dans graph.schema, un lien avec un join déclaré n'a pas de lignes d'arêtes stockées : ses
arêtes sont jointes depuis les instances visibles au moment de la lecture. Un tel lien rapporte
edgeCount: null avec reason: GRAPH_SCHEMA_LINK_REASONS.COMPUTED_FROM_DECLARED_JOIN, jamais
edgeCount: 0 — un zéro se lirait comme « lié, mais aucune valeur de colonne ne correspond », ce
qui appelle un autre remède. Le vocabulaire complet des raisons est GRAPH_SCHEMA_LINK_REASONS ;
une lecture gouvernée en échec conserve SOURCE_COUNT_UNAVAILABLE.
Branchez sur les constantes publiées plutôt que sur les chaînes brutes — GRAPH_LINK_KIND pour
le kind d'un lien (REFERENCE / PROXIMITY) et GRAPH_DIAGNOSTIC_STATUS pour le status d'un
diagnostic de liaison (READY / NOT_READY / SKIPPED). Les deux sont exportées depuis
@scrydon/ontology-sdk/client avec leurs types dérivés GraphLinkKind / GraphDiagnosticStatus,
et le z.enum(...) du schéma de tranche de graphe lit lui-même dans ces constantes : un littéral
retapé échoue au typage au lieu de désaccorder silencieusement une branche de votre interface.
GRAPH_LINK_KIND décrit un lien sur le fil. Utilisez LINK_TYPE_KINDS de
@scrydon/sdk-authoring/ontologies quand vous discriminez un type de lien que vous avez rédigé
dans un manifeste — les deux vocabulaires épellent aujourd'hui les mêmes mots et ne sont pas
interchangeables.