@x12i/graphenix-core
v2.17.0
Published
Graphenix core tier: format 2.1.0 JSON schema, validation, and CRUD helpers.
Maintainers
Readme
@x12i/graphenix-core
Core tier of the Graphenix ecosystem — Format 2.1.0 JSON wire layout (@x12i/graphenix-core@^2.3.0 on npm).
Execution-neutral graph description: JSON schema, TypeScript types, validation, and CRUD helpers. Profile packages build strict subtypes on top of this core via generic metadata, typed parameters, and validateGraphWithProfile().
Install
npm install @x12i/graphenix-coreValidate a graph document
import {
validateGraph,
GRAPHENIX_FORMAT_VERSION,
type GraphDocument
} from "@x12i/graphenix-core";
const doc: GraphDocument = {
formatVersion: GRAPHENIX_FORMAT_VERSION,
id: "graph:auth/user-signup",
graph: {
nodes: [],
edges: [],
inputs: [],
outputs: []
}
};
const result = validateGraph(doc);
if (!result.valid) {
console.error(result.errors);
}Each error is a GraphValidationError:
message— human-readable messagepath— JSON Pointer to the failing instancekeyword/params— from AJV when applicablesource—'graphenix'or'profile'code— optional profile-specific error code
Document fields
| Field | Required | Description |
| ----- | -------- | ----------- |
| formatVersion | yes | Must be "2.1.0" — export GRAPHENIX_FORMAT_VERSION. Persist validators reject 2.0.0, 2.1.1, and other drift (AUTHORING_FORMAT_VERSION_UNSUPPORTED); use legacy import adapters for uplift, not silent migration. |
| id | yes | Globally unique graph identifier |
| revision | no | Version of this graph document (not the format version) |
| graph | yes | Structural graph (nodes, edges, inputs, outputs) |
| metadata | no | Document metadata, extensions, summary contracts |
| types | no | Custom type definitions |
| subgraphs | no | Inlined reusable graphs |
Graph metadata (format 2.1.0)
Executable-profile graphs use first-class graph metadata fields. Core validates object shape; profile packages validate semantics.
graph.metadata
├── graphEntry entry contract, execution schema
├── graphResponse response shape, final output schema
├── modelConfig graph-wide AI model cases (profile packages validate)
└── data optional client keys (variables, presets, …){
"graph": {
"metadata": {
"modelConfig": { "cases": [] },
"data": { "variables": {} }
}
}
}Do not emit metadata.extensions on new authoring graphs. Migration from 2.0.0 layout: docs/guides/migration-tier-1-authoring.md.
Generic types for profile subtypes
import type { GraphDocument, GraphMetadata, GraphenixMetadata } from "@x12i/graphenix-core";
interface X12iGraphMetadata extends GraphMetadata {
modelConfig: { cases: unknown[] };
data?: { variables?: Record<string, unknown> };
}
type X12iNodeParameters = { skillKey: string };
type X12iExecutableGraphDocument = GraphDocument<
GraphenixMetadata,
X12iGraphMetadata,
X12iNodeParameters,
GraphenixMetadata
>;Aliases: GraphNode, GraphEdge, GraphPort, GraphType, Subgraph.
Profile validation
import {
validateGraphWithProfile,
type GraphProfileValidator,
type GraphValidationError
} from "@x12i/graphenix-core";
const validateX12iProfile: GraphProfileValidator = (doc) => {
const errors: GraphValidationError[] = [];
const modelConfig = doc.graph.metadata?.modelConfig;
if (!modelConfig || typeof modelConfig !== "object") {
errors.push({
source: "profile",
code: "GRAPHENIX_MODEL_CONFIG_MISSING",
message: "Executable profile is missing modelConfig.",
path: "/graph/metadata/modelConfig"
});
}
return { valid: errors.length === 0, errors };
};
validateGraphWithProfile(doc, validateX12iProfile);Base validation runs first; profile validation runs only when base validation passes.
Input and output contracts
Per-port input contract — graph.inputs[].contract:
{
"id": "rawRecord",
"type": "object",
"target": { "nodeId": "q1", "portId": "record" },
"contract": {
"semanticKind": "record",
"required": true,
"schema": { "type": "object" }
}
}Per-port output contract — graph.outputs[].contract:
{
"id": "graph-output:final",
"type": "builtin:object",
"source": { "nodeId": "node:finalizer", "portId": "out:final" },
"contract": {
"semanticKind": "final-output",
"required": true,
"schema": { "type": "object" }
}
}Graph-level summary contracts — complement per-port contracts:
| Layer | Purpose |
| ----- | ------- |
| graph.inputs[].contract | Contract for a specific graph input port |
| metadata.graphEntry | Summary contract for graph invocation |
| graph.outputs[].contract | Contract for a specific graph output port |
| metadata.graphResponse | Summary contract for final graph result |
Optional AJV checks against executionSchema / finalOutputSchema:
import {
validateExecutionAgainstContract,
validateFinalOutputAgainstContract
} from "@x12i/graphenix-core";See docs/interop-worox-graph.md for worox-graph interop notes.
CRUD helpers
Immutable by default; pass { mutate: true } to modify in place.
import { addNode, updateNode, removeNode, addEdge } from "@x12i/graphenix-core";- Nodes:
getNode,addNode,updateNode,removeNode - Edges:
getEdge,addEdge,updateEdge,removeEdge - Types:
getType,addType,updateType,removeType - Subgraphs:
getSubgraph,addSubgraph,updateSubgraph,removeSubgraph
Test Utilities (Golden Fixtures)
The core package provides utilities for maintaining "golden" fixtures. This is particularly useful during the authoring stage to ensure the generated documents match a stable reference, helping the user understand the structure of what they have.
import { assertGoldenFixture } from "@x12i/graphenix-core/test-utils";
const actual = { /* ... your generated graph ... */ };
const fixturePath = "./fixtures/my-graph.json";
// Asserts that 'actual' matches the JSON in 'fixturePath'.
// If the file is missing or differs, it throws an error.
// Set UPDATE_FIXTURES=true to create or update the fixture automatically.
assertGoldenFixture(actual, fixturePath, {
graphenixMasks: true // Automatically mask dynamic fields like planId, createdAt, etc.
});| Option | Purpose |
| --- | --- |
| update | If true, creates/updates the fixture file. |
| graphenixMasks | If true, masks common dynamic fields (planId, createdAt, *Hash, etc.). |
| mask | Array of additional keys to mask recursively. |
| scrub | Custom function to transform data before comparison. |
| API | Purpose |
| --- | --- |
| matchGoldenFixture | Returns a structured result (pass, wrote, actual, expected, message) |
| assertGoldenFixture | Throws an AssertionError if the match fails (and update is not enabled) |
| maskKeys | Recursive helper to replace keys with placeholders |
JSON Schema
Published at schema/graphenix-format-2.1.0.schema.json ($id: https://graphenix.dev/schema/graphenix-format-2.1.0.json). Legacy 2.0.0 schema retained for reference only.
Full field reference: GRAPHENIX-FORMAT.md.
Development
From the monorepo root:
npm install
npm run build
npm testOr from this package:
npm run build
npm testNotes
- Execution-agnostic — core defines structure only.
- Profile packages enforce execution semantics via
metadata.modelConfig, typed node parameters, and profile validators. - Client-specific fields live in
metadata.data; core validates object type only. - Task-node field names and phase vocabulary: GLOSSARY.md (monorepo root).
