feat(schema): add OperationNodeAttrs and CallNodeAttrs TypeBox schemas

This commit is contained in:
2026-05-21 20:55:54 +00:00
parent b2691283a2
commit 5f80cd8f75
3 changed files with 173 additions and 1 deletions

131
test/schema/node.test.ts Normal file
View File

@@ -0,0 +1,131 @@
import { describe, it, expect } from "vitest";
import { Value } from "@alkdev/typebox/value";
import {
OperationNodeAttrs,
type OperationNodeAttrs as OperationNodeAttrsType,
CallNodeAttrs,
type CallNodeAttrs as CallNodeAttrsType,
} from "../../src/schema/node";
describe("OperationNodeAttrs", () => {
const valid: OperationNodeAttrsType = {
name: "classify",
namespace: "task",
version: "1.0.0",
type: "query",
inputSchema: { type: "object" },
outputSchema: { type: "object" },
};
it("accepts valid attributes without optional fields", () => {
expect(Value.Check(OperationNodeAttrs, valid)).toBe(true);
});
it("accepts valid attributes with all optional fields", () => {
const withOptional: OperationNodeAttrsType = {
...valid,
description: "Classifies input",
tags: ["ml", "nlp"],
};
expect(Value.Check(OperationNodeAttrs, withOptional)).toBe(true);
});
it("accepts all operation types", () => {
for (const type of ["query", "mutation", "subscription"] as const) {
expect(Value.Check(OperationNodeAttrs, { ...valid, type })).toBe(true);
}
});
it("rejects missing required fields", () => {
expect(Value.Check(OperationNodeAttrs, {})).toBe(false);
expect(Value.Check(OperationNodeAttrs, { name: "classify" })).toBe(false);
});
it("rejects invalid operation type", () => {
expect(
Value.Check(OperationNodeAttrs, { ...valid, type: "invalid" }),
).toBe(false);
});
it("rejects wrong types for optional tags", () => {
expect(Value.Check(OperationNodeAttrs, { ...valid, tags: [1, 2] })).toBe(
false,
);
});
});
describe("CallNodeAttrs", () => {
const valid: CallNodeAttrsType = {
requestId: "req_abc123",
operationId: "task.classify",
status: "pending",
input: { text: "hello" },
};
it("accepts valid attributes without optional fields", () => {
expect(Value.Check(CallNodeAttrs, valid)).toBe(true);
});
it("accepts valid attributes with all optional fields", () => {
const withOptional: CallNodeAttrsType = {
...valid,
parentRequestId: "req_parent",
output: { label: "greeting" },
error: {
code: "INTERNAL",
message: "Something went wrong",
details: { stack: "..." },
},
identity: {
id: "user_1",
scopes: ["read", "write"],
resources: { org: ["org_1"] },
},
startedAt: "2026-05-21T10:00:00Z",
completedAt: "2026-05-21T10:00:01Z",
};
expect(Value.Check(CallNodeAttrs, withOptional)).toBe(true);
});
it("accepts all call statuses", () => {
for (const status of ["pending", "running", "completed", "failed", "aborted"] as const) {
expect(Value.Check(CallNodeAttrs, { ...valid, status })).toBe(true);
}
});
it("accepts error without optional details", () => {
const withError: CallNodeAttrsType = {
...valid,
error: { code: "NOT_FOUND", message: "Operation not found" },
};
expect(Value.Check(CallNodeAttrs, withError)).toBe(true);
});
it("accepts identity without optional resources", () => {
const withIdentity: CallNodeAttrsType = {
...valid,
identity: { id: "user_1", scopes: ["read"] },
};
expect(Value.Check(CallNodeAttrs, withIdentity)).toBe(true);
});
it("rejects missing required fields", () => {
expect(Value.Check(CallNodeAttrs, {})).toBe(false);
expect(Value.Check(CallNodeAttrs, { requestId: "req_1" })).toBe(false);
});
it("rejects invalid call status", () => {
expect(
Value.Check(CallNodeAttrs, { ...valid, status: "idle" }),
).toBe(false);
});
it("rejects error with missing required fields", () => {
expect(
Value.Check(CallNodeAttrs, { ...valid, error: { code: "X" } }),
).toBe(false);
expect(
Value.Check(CallNodeAttrs, { ...valid, error: { message: "X" } }),
).toBe(false);
});
});