feat: rebrand internal namespaces to @ocas/ scope #10
+68
-52
@@ -89,7 +89,9 @@ const { flags, positional } = parseArgs(process.argv.slice(2));
|
||||
|
||||
const defaultStorePath = join(homedir(), ".ocas");
|
||||
const storePath =
|
||||
typeof flags.store === "string" ? flags.store : defaultStorePath;
|
||||
typeof flags.store === "string"
|
||||
? flags.store
|
||||
: (process.env["OCAS_HOME"] ?? defaultStorePath);
|
||||
const compact = flags.json === true;
|
||||
|
||||
const defaultVarDbPath = join(storePath, "variables.db");
|
||||
@@ -214,11 +216,11 @@ async function cmdPut(args: string[]): Promise<void> {
|
||||
// Schema nodes: use putSchema() which validates via isValidSchema() (recursive)
|
||||
// instead of ajv against meta-schema (which can't express recursive constraints)
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"];
|
||||
const metaHash = builtinSchemas["@ocas/schema"];
|
||||
if (typeHash === metaHash) {
|
||||
try {
|
||||
const hash = await putSchema(store, payload as Record<string, unknown>);
|
||||
out(await wrapEnvelope(store, "@output/put", hash));
|
||||
out(await wrapEnvelope(store, "@ocas/output/put", hash));
|
||||
} catch (_e) {
|
||||
console.error(
|
||||
`Validation failed: payload in ${file} does not match schema ${typeHash}`,
|
||||
@@ -245,7 +247,7 @@ async function cmdPut(args: string[]): Promise<void> {
|
||||
}
|
||||
|
||||
const hash = await store.put(typeHash, payload);
|
||||
out(await wrapEnvelope(store, "@output/put", hash));
|
||||
out(await wrapEnvelope(store, "@ocas/output/put", hash));
|
||||
}
|
||||
|
||||
async function cmdGet(args: string[]): Promise<void> {
|
||||
@@ -254,14 +256,14 @@ async function cmdGet(args: string[]): Promise<void> {
|
||||
const store = await openStore();
|
||||
const node = store.get(hash);
|
||||
if (node === null) die(`Node not found: ${hash}`);
|
||||
out(await wrapEnvelope(store, "@output/get", node));
|
||||
out(await wrapEnvelope(store, "@ocas/output/get", node));
|
||||
}
|
||||
|
||||
async function cmdHas(args: string[]): Promise<void> {
|
||||
const hash = args[0];
|
||||
if (!hash) die("Usage: ocas has <hash>");
|
||||
const store = await openStore();
|
||||
out(await wrapEnvelope(store, "@output/has", store.has(hash)));
|
||||
out(await wrapEnvelope(store, "@ocas/output/has", store.has(hash)));
|
||||
}
|
||||
|
||||
async function cmdVerify(args: string[]): Promise<void> {
|
||||
@@ -277,7 +279,7 @@ async function cmdVerify(args: string[]): Promise<void> {
|
||||
} else {
|
||||
status = validate(store, node) ? "ok" : "invalid";
|
||||
}
|
||||
out(await wrapEnvelope(store, "@output/verify", status));
|
||||
out(await wrapEnvelope(store, "@ocas/output/verify", status));
|
||||
}
|
||||
|
||||
async function cmdRefs(args: string[]): Promise<void> {
|
||||
@@ -287,7 +289,7 @@ async function cmdRefs(args: string[]): Promise<void> {
|
||||
const node = store.get(hash);
|
||||
if (node === null) die(`Node not found: ${hash}`);
|
||||
const refHashes = refs(store, node);
|
||||
out(await wrapEnvelope(store, "@output/refs", refHashes));
|
||||
out(await wrapEnvelope(store, "@ocas/output/refs", refHashes));
|
||||
}
|
||||
|
||||
async function cmdWalk(args: string[]): Promise<void> {
|
||||
@@ -323,13 +325,13 @@ async function cmdWalk(args: string[]): Promise<void> {
|
||||
}
|
||||
|
||||
printNode(hash, "", true);
|
||||
out(await wrapEnvelope(store, "@output/walk", lines.join("\n")));
|
||||
out(await wrapEnvelope(store, "@ocas/output/walk", lines.join("\n")));
|
||||
} else {
|
||||
const hashes: Hash[] = [];
|
||||
walk(store, hash, (h) => {
|
||||
hashes.push(h);
|
||||
});
|
||||
out(await wrapEnvelope(store, "@output/walk", hashes));
|
||||
out(await wrapEnvelope(store, "@ocas/output/walk", hashes));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +349,7 @@ async function cmdHash(args: string[]): Promise<void> {
|
||||
const payload = isPipe ? await readStdinJson() : readJsonFile(file as string);
|
||||
const hash = await computeHash(typeHash, payload);
|
||||
const store = await openStore();
|
||||
out(await wrapEnvelope(store, "@output/hash", hash));
|
||||
out(await wrapEnvelope(store, "@ocas/output/hash", hash));
|
||||
}
|
||||
|
||||
async function cmdRender(args: string[]): Promise<void> {
|
||||
@@ -469,6 +471,10 @@ async function cmdVarSet(args: string[]): Promise<void> {
|
||||
die("Usage: ocas var set <name> <hash> [--tag <tag>...]");
|
||||
}
|
||||
|
||||
if (name.startsWith("@ocas/")) {
|
||||
die("The @ocas/ namespace is reserved and cannot be modified directly.");
|
||||
}
|
||||
|
||||
const store = await openStore();
|
||||
const varStore = createVariableStore(resolve(varDbPath), store);
|
||||
|
||||
@@ -497,7 +503,7 @@ async function cmdVarSet(args: string[]): Promise<void> {
|
||||
: undefined;
|
||||
|
||||
const variable = varStore.set(name, value, options);
|
||||
out(await wrapEnvelope(store, "@output/var-set", variable));
|
||||
out(await wrapEnvelope(store, "@ocas/output/var-set", variable));
|
||||
} catch (e) {
|
||||
if (
|
||||
e instanceof InvalidVariableNameError ||
|
||||
@@ -528,7 +534,7 @@ async function cmdVarGet(args: string[]): Promise<void> {
|
||||
if (variable === null) {
|
||||
die(`Error: Variable not found: name=${name}, schema=${schema}`);
|
||||
}
|
||||
out(await wrapEnvelope(store, "@output/var-get", variable));
|
||||
out(await wrapEnvelope(store, "@ocas/output/var-get", variable));
|
||||
} finally {
|
||||
varStore.close();
|
||||
}
|
||||
@@ -542,6 +548,10 @@ async function cmdVarDelete(args: string[]): Promise<void> {
|
||||
die("Usage: ocas var delete <name> [--schema <hash>]");
|
||||
}
|
||||
|
||||
if (name.startsWith("@ocas/")) {
|
||||
die("The @ocas/ namespace is reserved and cannot be modified directly.");
|
||||
}
|
||||
|
||||
const store = await openStore();
|
||||
const varStore = createVariableStore(resolve(varDbPath), store);
|
||||
|
||||
@@ -549,11 +559,11 @@ async function cmdVarDelete(args: string[]): Promise<void> {
|
||||
if (schema !== undefined) {
|
||||
// Precise deletion: remove specific (name, schema) variant
|
||||
const variable = varStore.remove(name, schema);
|
||||
out(await wrapEnvelope(store, "@output/var-delete", variable));
|
||||
out(await wrapEnvelope(store, "@ocas/output/var-delete", variable));
|
||||
} else {
|
||||
// Batch deletion: remove all variants for this name
|
||||
const variables = varStore.remove(name);
|
||||
out(await wrapEnvelope(store, "@output/var-delete", variables));
|
||||
out(await wrapEnvelope(store, "@ocas/output/var-delete", variables));
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof VariableNotFoundError) {
|
||||
@@ -590,7 +600,7 @@ async function cmdVarTag(args: string[]): Promise<void> {
|
||||
delete: deleteNames.length > 0 ? deleteNames : undefined,
|
||||
});
|
||||
|
||||
out(await wrapEnvelope(store, "@output/var-tag", variable));
|
||||
out(await wrapEnvelope(store, "@ocas/output/var-tag", variable));
|
||||
} catch (e) {
|
||||
if (
|
||||
e instanceof VariableNotFoundError ||
|
||||
@@ -633,7 +643,7 @@ async function cmdVarList(args: string[]): Promise<void> {
|
||||
tags: Object.keys(tags).length > 0 ? tags : undefined,
|
||||
labels: labels.length > 0 ? labels : undefined,
|
||||
});
|
||||
out(await wrapEnvelope(store, "@output/var-list", variables));
|
||||
out(await wrapEnvelope(store, "@ocas/output/var-list", variables));
|
||||
} catch (e) {
|
||||
if (e instanceof InvalidVariableNameError) {
|
||||
die(`Error: ${e.message}`);
|
||||
@@ -691,7 +701,7 @@ async function cmdTemplateSet(args: string[]): Promise<void> {
|
||||
}
|
||||
|
||||
// Store content in CAS under @string schema
|
||||
const stringHash = await resolveTypeHash("@string");
|
||||
const stringHash = await resolveTypeHash("@ocas/string");
|
||||
const contentHash = await store.put(stringHash, content);
|
||||
|
||||
// Create variable binding: @ocas/template/text/<schema-hash>
|
||||
@@ -699,7 +709,7 @@ async function cmdTemplateSet(args: string[]): Promise<void> {
|
||||
varStore.set(varName, contentHash);
|
||||
|
||||
out(
|
||||
await wrapEnvelope(store, "@output/template-set", {
|
||||
await wrapEnvelope(store, "@ocas/output/template-set", {
|
||||
schemaHash,
|
||||
contentHash,
|
||||
}),
|
||||
@@ -726,7 +736,7 @@ async function cmdTemplateGet(args: string[]): Promise<void> {
|
||||
|
||||
try {
|
||||
const varName = `@ocas/template/text/${schemaHash}`;
|
||||
const stringHash = await resolveTypeHash("@string");
|
||||
const stringHash = await resolveTypeHash("@ocas/string");
|
||||
const variable = varStore.get(varName, stringHash);
|
||||
|
||||
if (variable === null) {
|
||||
@@ -740,7 +750,11 @@ async function cmdTemplateGet(args: string[]): Promise<void> {
|
||||
}
|
||||
|
||||
out(
|
||||
await wrapEnvelope(store, "@output/template-get", node.payload as string),
|
||||
await wrapEnvelope(
|
||||
store,
|
||||
"@ocas/output/template-get",
|
||||
node.payload as string,
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
varStore.close();
|
||||
@@ -752,7 +766,7 @@ async function cmdTemplateList(_args: string[]): Promise<void> {
|
||||
const varStore = createVariableStore(resolve(varDbPath), store);
|
||||
|
||||
try {
|
||||
const stringHash = await resolveTypeHash("@string");
|
||||
const stringHash = await resolveTypeHash("@ocas/string");
|
||||
const variables = varStore.list({
|
||||
namePrefix: "@ocas/template/text/",
|
||||
schema: stringHash,
|
||||
@@ -763,7 +777,7 @@ async function cmdTemplateList(_args: string[]): Promise<void> {
|
||||
contentHash: v.value,
|
||||
}));
|
||||
|
||||
out(await wrapEnvelope(store, "@output/template-list", templates));
|
||||
out(await wrapEnvelope(store, "@ocas/output/template-list", templates));
|
||||
} finally {
|
||||
varStore.close();
|
||||
}
|
||||
@@ -781,11 +795,13 @@ async function cmdTemplateDelete(args: string[]): Promise<void> {
|
||||
|
||||
try {
|
||||
const varName = `@ocas/template/text/${schemaHash}`;
|
||||
const stringHash = await resolveTypeHash("@string");
|
||||
const stringHash = await resolveTypeHash("@ocas/string");
|
||||
varStore.remove(varName, stringHash);
|
||||
|
||||
out(
|
||||
await wrapEnvelope(store, "@output/template-delete", { deleted: true }),
|
||||
await wrapEnvelope(store, "@ocas/output/template-delete", {
|
||||
deleted: true,
|
||||
}),
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof VariableNotFoundError) {
|
||||
@@ -803,7 +819,7 @@ async function cmdGc(_args: string[]): Promise<void> {
|
||||
|
||||
try {
|
||||
const stats = gc(store, varStore);
|
||||
out(await wrapEnvelope(store, "@output/gc", stats));
|
||||
out(await wrapEnvelope(store, "@ocas/output/gc", stats));
|
||||
} finally {
|
||||
varStore.close();
|
||||
}
|
||||
@@ -816,19 +832,19 @@ async function cmdList(_args: string[]): Promise<void> {
|
||||
const typeHash = await resolveTypeHash(typeFlag);
|
||||
const store = await openStore();
|
||||
const hashes = Array.from(store.listByType(typeHash));
|
||||
out(await wrapEnvelope(store, "@output/list", hashes));
|
||||
out(await wrapEnvelope(store, "@ocas/output/list", hashes));
|
||||
}
|
||||
|
||||
async function cmdListMeta(_args: string[]): Promise<void> {
|
||||
const store = await openStore();
|
||||
const hashes = store.listMeta();
|
||||
out(await wrapEnvelope(store, "@output/list-meta", hashes));
|
||||
out(await wrapEnvelope(store, "@ocas/output/list-meta", hashes));
|
||||
}
|
||||
|
||||
async function cmdListSchema(_args: string[]): Promise<void> {
|
||||
const store = await openStore();
|
||||
const hashes = store.listSchemas();
|
||||
out(await wrapEnvelope(store, "@output/list-schema", hashes));
|
||||
out(await wrapEnvelope(store, "@ocas/output/list-schema", hashes));
|
||||
}
|
||||
|
||||
function printUsage(): void {
|
||||
@@ -836,35 +852,35 @@ function printUsage(): void {
|
||||
Usage: ocas [--store <path>] [--json] <command> [args]
|
||||
|
||||
All JSON commands emit a { type, value } envelope. The type is the hash of the
|
||||
command's @output/* schema (shown in parentheses); pipe any envelope into
|
||||
\`render -p\` to render its value (cas_ref hashes are expanded).
|
||||
command's @ocas/output/* schema (shown in parentheses); pipe any envelope into
|
||||
\`render -p\` to render its value (ocas_ref hashes are expanded).
|
||||
|
||||
Commands:
|
||||
put <type-hash> <file.json|--pipe> Store node, print envelope (value=hash) (@output/put)
|
||||
get <hash> Print node as envelope (@output/get)
|
||||
has <hash> Print envelope (value=boolean) (@output/has)
|
||||
verify <hash> Verify integrity + schema (value=ok/corrupted/invalid) (@output/verify)
|
||||
refs <hash> List direct cas_ref edges (@output/refs)
|
||||
walk <hash> [--format tree] Recursive traversal (@output/walk)
|
||||
hash <type-hash> <file.json|--pipe> Compute hash without storing (@output/hash)
|
||||
put <type-hash> <file.json|--pipe> Store node, print envelope (value=hash) (@ocas/output/put)
|
||||
get <hash> Print node as envelope (@ocas/output/get)
|
||||
has <hash> Print envelope (value=boolean) (@ocas/output/has)
|
||||
verify <hash> Verify integrity + schema (value=ok/corrupted/invalid) (@ocas/output/verify)
|
||||
refs <hash> List direct ocas_ref edges (@ocas/output/refs)
|
||||
walk <hash> [--format tree] Recursive traversal (@ocas/output/walk)
|
||||
hash <type-hash> <file.json|--pipe> Compute hash without storing (@ocas/output/hash)
|
||||
render <hash> [options] Render node as text with resolution decay (raw output)
|
||||
render --pipe/-p [options] Render { type, value } from stdin (raw output)
|
||||
list --type <hash-or-alias> List hashes for a type (value=string[]) (@output/list)
|
||||
list-meta List meta-schema hashes (value=string[]) (@output/list-meta)
|
||||
list-schema List all schema hashes (value=string[]) (@output/list-schema)
|
||||
var set <name> <hash> [--tag <tag>...] Create/update a variable (@output/var-set)
|
||||
var get <name> --schema <hash> Get a variable by name + schema (@output/var-get)
|
||||
var delete <name> [--schema <hash>] Delete variable(s) (@output/var-delete)
|
||||
var list [prefix] [--schema <hash>] [--tag <tag>...] List variables (@output/var-list)
|
||||
var tag <name> --schema <hash> <operations...> Modify tags/labels (@output/var-tag)
|
||||
template set <schema-hash> <file> | --inline <text> Set template for schema (@output/template-set)
|
||||
template get <schema-hash> Get template content (value=string) (@output/template-get)
|
||||
template list List all templates (@output/template-list)
|
||||
template delete <schema-hash> Delete template for schema (@output/template-delete)
|
||||
gc Run garbage collection (@output/gc)
|
||||
list --type <hash-or-alias> List hashes for a type (value=string[]) (@ocas/output/list)
|
||||
list-meta List meta-schema hashes (value=string[]) (@ocas/output/list-meta)
|
||||
list-schema List all schema hashes (value=string[]) (@ocas/output/list-schema)
|
||||
var set <name> <hash> [--tag <tag>...] Create/update a variable (@ocas/output/var-set)
|
||||
var get <name> --schema <hash> Get a variable by name + schema (@ocas/output/var-get)
|
||||
var delete <name> [--schema <hash>] Delete variable(s) (@ocas/output/var-delete)
|
||||
var list [prefix] [--schema <hash>] [--tag <tag>...] List variables (@ocas/output/var-list)
|
||||
var tag <name> --schema <hash> <operations...> Modify tags/labels (@ocas/output/var-tag)
|
||||
template set <schema-hash> <file> | --inline <text> Set template for schema (@ocas/output/template-set)
|
||||
template get <schema-hash> Get template content (value=string) (@ocas/output/template-get)
|
||||
template list List all templates (@ocas/output/template-list)
|
||||
template delete <schema-hash> Delete template for schema (@ocas/output/template-delete)
|
||||
gc Run garbage collection (@ocas/output/gc)
|
||||
|
||||
Flags:
|
||||
--store <path> Store directory (default: ~/.ocas)
|
||||
--store <path> Store directory (default: $OCAS_HOME or ~/.ocas)
|
||||
--var-db <path> Variable database path (default: <store>/variables.db)
|
||||
--json Compact JSON output
|
||||
--schema <hash> Schema hash filter for var get/delete/tag/list
|
||||
|
||||
@@ -10,32 +10,32 @@ exports[`Phase 7: Edge Cases 7.5 no subcommand shows help text 1`] = `
|
||||
"Usage: ocas [--store <path>] [--json] <command> [args]
|
||||
|
||||
All JSON commands emit a { type, value } envelope. The type is the hash of the
|
||||
command's @output/* schema (shown in parentheses); pipe any envelope into
|
||||
\`render -p\` to render its value (cas_ref hashes are expanded).
|
||||
command's @ocas/output/* schema (shown in parentheses); pipe any envelope into
|
||||
\`render -p\` to render its value (ocas_ref hashes are expanded).
|
||||
|
||||
Commands:
|
||||
put <type-hash> <file.json|--pipe> Store node, print envelope (value=hash) (@output/put)
|
||||
get <hash> Print node as envelope (@output/get)
|
||||
has <hash> Print envelope (value=boolean) (@output/has)
|
||||
verify <hash> Verify integrity + schema (value=ok/corrupted/invalid) (@output/verify)
|
||||
refs <hash> List direct cas_ref edges (@output/refs)
|
||||
walk <hash> [--format tree] Recursive traversal (@output/walk)
|
||||
hash <type-hash> <file.json|--pipe> Compute hash without storing (@output/hash)
|
||||
put <type-hash> <file.json|--pipe> Store node, print envelope (value=hash) (@ocas/output/put)
|
||||
get <hash> Print node as envelope (@ocas/output/get)
|
||||
has <hash> Print envelope (value=boolean) (@ocas/output/has)
|
||||
verify <hash> Verify integrity + schema (value=ok/corrupted/invalid) (@ocas/output/verify)
|
||||
refs <hash> List direct ocas_ref edges (@ocas/output/refs)
|
||||
walk <hash> [--format tree] Recursive traversal (@ocas/output/walk)
|
||||
hash <type-hash> <file.json|--pipe> Compute hash without storing (@ocas/output/hash)
|
||||
render <hash> [options] Render node as text with resolution decay (raw output)
|
||||
render --pipe/-p [options] Render { type, value } from stdin (raw output)
|
||||
list --type <hash-or-alias> List hashes for a type (value=string[]) (@output/list)
|
||||
list-meta List meta-schema hashes (value=string[]) (@output/list-meta)
|
||||
list-schema List all schema hashes (value=string[]) (@output/list-schema)
|
||||
var set <name> <hash> [--tag <tag>...] Create/update a variable (@output/var-set)
|
||||
var get <name> --schema <hash> Get a variable by name + schema (@output/var-get)
|
||||
var delete <name> [--schema <hash>] Delete variable(s) (@output/var-delete)
|
||||
var list [prefix] [--schema <hash>] [--tag <tag>...] List variables (@output/var-list)
|
||||
var tag <name> --schema <hash> <operations...> Modify tags/labels (@output/var-tag)
|
||||
template set <schema-hash> <file> | --inline <text> Set template for schema (@output/template-set)
|
||||
template get <schema-hash> Get template content (value=string) (@output/template-get)
|
||||
template list List all templates (@output/template-list)
|
||||
template delete <schema-hash> Delete template for schema (@output/template-delete)
|
||||
gc Run garbage collection (@output/gc)
|
||||
list --type <hash-or-alias> List hashes for a type (value=string[]) (@ocas/output/list)
|
||||
list-meta List meta-schema hashes (value=string[]) (@ocas/output/list-meta)
|
||||
list-schema List all schema hashes (value=string[]) (@ocas/output/list-schema)
|
||||
var set <name> <hash> [--tag <tag>...] Create/update a variable (@ocas/output/var-set)
|
||||
var get <name> --schema <hash> Get a variable by name + schema (@ocas/output/var-get)
|
||||
var delete <name> [--schema <hash>] Delete variable(s) (@ocas/output/var-delete)
|
||||
var list [prefix] [--schema <hash>] [--tag <tag>...] List variables (@ocas/output/var-list)
|
||||
var tag <name> --schema <hash> <operations...> Modify tags/labels (@ocas/output/var-tag)
|
||||
template set <schema-hash> <file> | --inline <text> Set template for schema (@ocas/output/template-set)
|
||||
template get <schema-hash> Get template content (value=string) (@ocas/output/template-get)
|
||||
template list List all templates (@ocas/output/template-list)
|
||||
template delete <schema-hash> Delete template for schema (@ocas/output/template-delete)
|
||||
gc Run garbage collection (@ocas/output/gc)
|
||||
|
||||
Flags:
|
||||
--store <path> Store directory (default: ~/.ocas)
|
||||
@@ -52,7 +52,7 @@ Flags:
|
||||
|
||||
exports[`Phase 3: Variable System 3.1 var set creates variable 1`] = `
|
||||
{
|
||||
"type": "50CG6QYD1FY8J",
|
||||
"type": "0Q5EMYK4SYSS9",
|
||||
"value": {
|
||||
"labels": [],
|
||||
"name": "myapp/config",
|
||||
@@ -65,7 +65,7 @@ exports[`Phase 3: Variable System 3.1 var set creates variable 1`] = `
|
||||
|
||||
exports[`Phase 3: Variable System 3.2 var get returns variable 1`] = `
|
||||
{
|
||||
"type": "DSXYC9DNCYAK0",
|
||||
"type": "7C75FQT98KKQD",
|
||||
"value": {
|
||||
"labels": [],
|
||||
"name": "myapp/config",
|
||||
@@ -78,7 +78,7 @@ exports[`Phase 3: Variable System 3.2 var get returns variable 1`] = `
|
||||
|
||||
exports[`Phase 3: Variable System 3.3 var list shows all variables 1`] = `
|
||||
{
|
||||
"type": "8F5ENFRC57Y7H",
|
||||
"type": "AF0XACGXHPMC1",
|
||||
"value": [
|
||||
{
|
||||
"labels": [],
|
||||
@@ -93,7 +93,7 @@ exports[`Phase 3: Variable System 3.3 var list shows all variables 1`] = `
|
||||
|
||||
exports[`Phase 3: Variable System 3.4 var list prefix filters by prefix 1`] = `
|
||||
{
|
||||
"type": "8F5ENFRC57Y7H",
|
||||
"type": "AF0XACGXHPMC1",
|
||||
"value": [
|
||||
{
|
||||
"labels": [],
|
||||
@@ -108,7 +108,7 @@ exports[`Phase 3: Variable System 3.4 var list prefix filters by prefix 1`] = `
|
||||
|
||||
exports[`Phase 3: Variable System 3.5 var set upsert updates existing variable 1`] = `
|
||||
{
|
||||
"type": "50CG6QYD1FY8J",
|
||||
"type": "0Q5EMYK4SYSS9",
|
||||
"value": {
|
||||
"labels": [],
|
||||
"name": "myapp/config",
|
||||
@@ -121,7 +121,7 @@ exports[`Phase 3: Variable System 3.5 var set upsert updates existing variable 1
|
||||
|
||||
exports[`Phase 3: Variable System 3.6 var tag adds kv tag and label 1`] = `
|
||||
{
|
||||
"type": "6D1HG60NTZY87",
|
||||
"type": "9103EYRMM949A",
|
||||
"value": {
|
||||
"labels": [
|
||||
"important",
|
||||
@@ -138,7 +138,7 @@ exports[`Phase 3: Variable System 3.6 var tag adds kv tag and label 1`] = `
|
||||
|
||||
exports[`Phase 3: Variable System 3.7 var list --tag env:prod filters by kv tag 1`] = `
|
||||
{
|
||||
"type": "8F5ENFRC57Y7H",
|
||||
"type": "AF0XACGXHPMC1",
|
||||
"value": [
|
||||
{
|
||||
"labels": [
|
||||
@@ -157,7 +157,7 @@ exports[`Phase 3: Variable System 3.7 var list --tag env:prod filters by kv tag
|
||||
|
||||
exports[`Phase 3: Variable System 3.8 var list --tag important filters by label 1`] = `
|
||||
{
|
||||
"type": "8F5ENFRC57Y7H",
|
||||
"type": "AF0XACGXHPMC1",
|
||||
"value": [
|
||||
{
|
||||
"labels": [
|
||||
@@ -176,7 +176,7 @@ exports[`Phase 3: Variable System 3.8 var list --tag important filters by label
|
||||
|
||||
exports[`Phase 3: Variable System 3.9 var tag remove deletes label 1`] = `
|
||||
{
|
||||
"type": "6D1HG60NTZY87",
|
||||
"type": "9103EYRMM949A",
|
||||
"value": {
|
||||
"labels": [],
|
||||
"name": "myapp/config",
|
||||
@@ -191,7 +191,7 @@ exports[`Phase 3: Variable System 3.9 var tag remove deletes label 1`] = `
|
||||
|
||||
exports[`Phase 3: Variable System 3.10 var delete removes variable 1`] = `
|
||||
{
|
||||
"type": "25VAMSJT0X51K",
|
||||
"type": "C3MYPR5RGQFZT",
|
||||
"value": [
|
||||
{
|
||||
"labels": [],
|
||||
@@ -210,7 +210,7 @@ exports[`Phase 3: Variable System 3.11 var get deleted variable returns not foun
|
||||
|
||||
exports[`Phase 4: Template System 4.1 template set registers template 1`] = `
|
||||
{
|
||||
"type": "7R13JNSN53R67",
|
||||
"type": "BJDHPAE4Q8TXM",
|
||||
"value": {
|
||||
"contentHash": "6WW8WNB38GTTP",
|
||||
"schemaHash": "FRBAB1BF0ZBCS",
|
||||
@@ -227,7 +227,7 @@ exports[`Phase 4: Template System 4.2 template get returns template text 1`] = `
|
||||
|
||||
exports[`Phase 4: Template System 4.3 template list shows registered templates 1`] = `
|
||||
{
|
||||
"type": "5GE3Y0EQS0HP4",
|
||||
"type": "8917JQTD1R5JF",
|
||||
"value": [
|
||||
{
|
||||
"contentHash": "6WW8WNB38GTTP",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
exports[`Phase 1: CAS Core 1.6 get returns node JSON (snapshot) 1`] = `
|
||||
{
|
||||
"type": "CCVN1ECY8JKQ0",
|
||||
"type": "FB4K0SXG68ZFS",
|
||||
"value": {
|
||||
"payload": {
|
||||
"age": 30,
|
||||
|
||||
@@ -9,7 +9,7 @@ exports[`Phase 1: CAS Core 1.9 verify returns ok for valid node 1`] = `
|
||||
|
||||
exports[`Phase 1: CAS Core 1.10 refs lists direct references (snapshot) 1`] = `
|
||||
"{
|
||||
"type": "35QJB2WESFFGQ",
|
||||
"type": "2TKP4RGBJ4V43",
|
||||
"value": []
|
||||
}"
|
||||
`;
|
||||
|
||||
@@ -75,7 +75,7 @@ describe("@ Alias Resolution - put", () => {
|
||||
|
||||
const { stdout, stderr, exitCode } = await runCliAlias(
|
||||
"put",
|
||||
"@string",
|
||||
"@ocas/string",
|
||||
payloadFile,
|
||||
);
|
||||
|
||||
@@ -93,7 +93,7 @@ describe("@ Alias Resolution - put", () => {
|
||||
|
||||
const { stdout, exitCode } = await runCliAlias(
|
||||
"put",
|
||||
"@number",
|
||||
"@ocas/number",
|
||||
payloadFile,
|
||||
);
|
||||
|
||||
@@ -109,7 +109,7 @@ describe("@ Alias Resolution - put", () => {
|
||||
|
||||
const { stdout, exitCode } = await runCliAlias(
|
||||
"put",
|
||||
"@object",
|
||||
"@ocas/object",
|
||||
payloadFile,
|
||||
);
|
||||
|
||||
@@ -157,7 +157,7 @@ describe("@ Alias Resolution - put", () => {
|
||||
|
||||
const { stdout, stderr, exitCode } = await runCliAlias(
|
||||
"put",
|
||||
"@schema",
|
||||
"@ocas/schema",
|
||||
schemaFile,
|
||||
);
|
||||
|
||||
@@ -176,7 +176,7 @@ describe("@ Alias Resolution - hash", () => {
|
||||
|
||||
const { stdout, stderr, exitCode } = await runCliAlias(
|
||||
"hash",
|
||||
"@string",
|
||||
"@ocas/string",
|
||||
payloadFile,
|
||||
);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ describe("list-meta CLI command", () => {
|
||||
test("E1. list-meta on bootstrapped store contains exactly the meta-schema hash", async () => {
|
||||
// First, get @schema hash by calling has on it (also triggers bootstrap)
|
||||
const { stdout: hashOut, exitCode: hashCode } = await runCli(
|
||||
["hash", "@schema", "--pipe"],
|
||||
["hash", "@ocas/schema", "--pipe"],
|
||||
storePath,
|
||||
);
|
||||
// ensure bootstrap by running a no-op command:
|
||||
@@ -30,7 +30,7 @@ describe("list-meta CLI command", () => {
|
||||
|
||||
// Bootstrap fully via 'list --type @schema'
|
||||
const { stdout: schemaListOut } = await runCli(
|
||||
["list", "--type", "@schema"],
|
||||
["list", "--type", "@ocas/schema"],
|
||||
storePath,
|
||||
);
|
||||
const schemaList = envValue(schemaListOut) as string[];
|
||||
@@ -85,11 +85,11 @@ describe("usage help", () => {
|
||||
});
|
||||
|
||||
describe("F1. output schemas registered", () => {
|
||||
test("@output/list-meta and @output/list-schema schemas exist", async () => {
|
||||
test("@ocas/output/list-meta and @ocas/output/list-schema schemas exist", async () => {
|
||||
const { stdout, exitCode } = await runCli(["list-meta"], storePath);
|
||||
expect(exitCode).toBe(0);
|
||||
const parsed = JSON.parse(stdout) as { type: string };
|
||||
// type hash references the @output/list-meta schema, must be retrievable
|
||||
// type hash references the @ocas/output/list-meta schema, must be retrievable
|
||||
const { stdout: getOut, exitCode: getCode } = await runCli(
|
||||
["get", parsed.type],
|
||||
storePath,
|
||||
|
||||
@@ -91,7 +91,7 @@ describe("Phase 8: Pipe Composition", () => {
|
||||
]);
|
||||
expect(putExit).toBe(0);
|
||||
|
||||
// The put envelope value is a cas_ref hash; render -p dereferences it and
|
||||
// The put envelope value is a ocas_ref hash; render -p dereferences it and
|
||||
// renders the stored node's payload.
|
||||
const { stdout, exitCode } = await runCliWithStdin(
|
||||
["render", "--pipe"],
|
||||
@@ -102,7 +102,11 @@ describe("Phase 8: Pipe Composition", () => {
|
||||
});
|
||||
|
||||
test("8.3 list --type @schema emits a parseable envelope of hashes", async () => {
|
||||
const { stdout, exitCode } = await runCli(["list", "--type", "@schema"]);
|
||||
const { stdout, exitCode } = await runCli([
|
||||
"list",
|
||||
"--type",
|
||||
"@ocas/schema",
|
||||
]);
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
// Downstream consumers (jq, etc.) read the `value` array of hashes.
|
||||
@@ -114,8 +118,12 @@ describe("Phase 8: Pipe Composition", () => {
|
||||
});
|
||||
|
||||
test("8.4 list --type @schema | render -p expands the schema list", async () => {
|
||||
const { stdout: listOut } = await runCli(["list", "--type", "@schema"]);
|
||||
// list result items are cas_ref hashes; render -p dereferences each one
|
||||
const { stdout: listOut } = await runCli([
|
||||
"list",
|
||||
"--type",
|
||||
"@ocas/schema",
|
||||
]);
|
||||
// list result items are ocas_ref hashes; render -p dereferences each one
|
||||
// and renders the schema contents.
|
||||
const { stdout, exitCode } = await runCliWithStdin(
|
||||
["render", "--pipe"],
|
||||
|
||||
@@ -179,18 +179,15 @@ describe("Suite 6: CLI Integration with Templates", () => {
|
||||
);
|
||||
const nodeHash = envValue(nodeOut) as string;
|
||||
|
||||
// Create template file (JSON-encoded string)
|
||||
const templateFile = join(tmpStore, "template.json");
|
||||
writeFileSync(templateFile, JSON.stringify("Hello {{ payload.name }}!"));
|
||||
const { stdout: tmplOut } = await runCli(
|
||||
["put", "@string", templateFile],
|
||||
tmpStore,
|
||||
);
|
||||
const tmplHash = envValue(tmplOut) as string;
|
||||
|
||||
// Register template
|
||||
// Register template via template set --inline
|
||||
await runCli(
|
||||
["var", "set", `@ocas/template/text/${schemaHash.trim()}`, tmplHash],
|
||||
[
|
||||
"template",
|
||||
"set",
|
||||
schemaHash.trim(),
|
||||
"--inline",
|
||||
"Hello {{ payload.name }}!",
|
||||
],
|
||||
tmpStore,
|
||||
);
|
||||
|
||||
@@ -221,7 +218,7 @@ describe("Suite 6: CLI Integration with Templates", () => {
|
||||
properties: {
|
||||
value: { type: "string" },
|
||||
child: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -249,21 +246,15 @@ describe("Suite 6: CLI Integration with Templates", () => {
|
||||
);
|
||||
const parentHash = envValue(parentOut) as string;
|
||||
|
||||
// Create template showing resolution (JSON-encoded string)
|
||||
const templateFile = join(tmpStore, "template.json");
|
||||
writeFileSync(
|
||||
templateFile,
|
||||
JSON.stringify("{{ payload.value }}(res={{ resolution }})"),
|
||||
);
|
||||
const { stdout: tmplOut } = await runCli(
|
||||
["put", "@string", templateFile],
|
||||
tmpStore,
|
||||
);
|
||||
const tmplHash = envValue(tmplOut) as string;
|
||||
|
||||
// Register template
|
||||
// Register template via template set --inline
|
||||
await runCli(
|
||||
["var", "set", `@ocas/template/text/${schemaHash.trim()}`, tmplHash],
|
||||
[
|
||||
"template",
|
||||
"set",
|
||||
schemaHash.trim(),
|
||||
"--inline",
|
||||
"{{ payload.value }}(res={{ resolution }})",
|
||||
],
|
||||
tmpStore,
|
||||
);
|
||||
|
||||
@@ -303,20 +294,15 @@ describe("Suite 6: CLI Integration with Templates", () => {
|
||||
);
|
||||
const nodeHash = envValue(nodeOut) as string;
|
||||
|
||||
// Create template (JSON-encoded string)
|
||||
const templateFile = join(tmpStore, "template.json");
|
||||
writeFileSync(
|
||||
templateFile,
|
||||
JSON.stringify("Greetings {{ payload.name }}!"),
|
||||
);
|
||||
const { stdout: tmplOut } = await runCli(
|
||||
["put", "@string", templateFile],
|
||||
tmpStore,
|
||||
);
|
||||
const tmplHash = envValue(tmplOut) as string;
|
||||
|
||||
// Register template via template set --inline
|
||||
await runCli(
|
||||
["var", "set", `@ocas/template/text/${schemaHash.trim()}`, tmplHash],
|
||||
[
|
||||
"template",
|
||||
"set",
|
||||
schemaHash.trim(),
|
||||
"--inline",
|
||||
"Greetings {{ payload.name }}!",
|
||||
],
|
||||
tmpStore,
|
||||
);
|
||||
|
||||
@@ -438,7 +424,7 @@ describe("Suite 6: CLI Integration with Templates", () => {
|
||||
// Get @string type hash via bootstrap
|
||||
const store = createFsStore(tmpStore);
|
||||
const types = await bootstrap(store);
|
||||
const stringType = types["@string"];
|
||||
const stringType = types["@ocas/string"];
|
||||
|
||||
// Create and store a simple string node
|
||||
const nodeFile = join(tmpStore, "test.json");
|
||||
@@ -473,7 +459,7 @@ describe("Suite 6: CLI Integration with Templates", () => {
|
||||
// Get @string type hash via bootstrap
|
||||
const store = createFsStore(tmpStore);
|
||||
const types = await bootstrap(store);
|
||||
const stringType = types["@string"];
|
||||
const stringType = types["@ocas/string"];
|
||||
|
||||
// Create envelope and pipe to render
|
||||
const envelope = JSON.stringify({ type: stringType, value: "test" });
|
||||
|
||||
@@ -142,7 +142,7 @@ describe("Issue #50: Schema Validation in put", () => {
|
||||
writeFileSync(payloadFile, JSON.stringify("hello world"));
|
||||
|
||||
const { exitCode, stdout } = await runCli(
|
||||
["put", "@string", payloadFile],
|
||||
["put", "@ocas/string", payloadFile],
|
||||
tmpStore,
|
||||
);
|
||||
|
||||
@@ -422,25 +422,25 @@ describe("Issue #50: Schema Validation in put", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("T4.2: Validation respects cas_ref format in schemas", async () => {
|
||||
test("T4.2: Validation respects ocas_ref format in schemas", async () => {
|
||||
const tmpStore = mkdtempSync(join(tmpdir(), "ocas-test-"));
|
||||
try {
|
||||
await runCli(["init"], tmpStore);
|
||||
|
||||
// Schema with cas_ref format
|
||||
// Schema with ocas_ref format
|
||||
const schemaFile = join(tmpStore, "schema.json");
|
||||
writeFileSync(
|
||||
schemaFile,
|
||||
JSON.stringify({
|
||||
type: "object",
|
||||
properties: {
|
||||
ref: { type: "string", format: "cas_ref" },
|
||||
ref: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
}),
|
||||
);
|
||||
const schemaHash = await putSchemaFile(tmpStore, schemaFile);
|
||||
|
||||
// Valid cas_ref
|
||||
// Valid ocas_ref
|
||||
const validFile = join(tmpStore, "valid.json");
|
||||
writeFileSync(validFile, JSON.stringify({ ref: "0000000000000" }));
|
||||
|
||||
@@ -450,7 +450,7 @@ describe("Issue #50: Schema Validation in put", () => {
|
||||
);
|
||||
expect(validExitCode).toBe(0);
|
||||
|
||||
// Invalid cas_ref (wrong length)
|
||||
// Invalid ocas_ref (wrong length)
|
||||
const invalidFile = join(tmpStore, "invalid.json");
|
||||
writeFileSync(invalidFile, JSON.stringify({ ref: "short" }));
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ async function runCli(...args: string[]): Promise<{
|
||||
*/
|
||||
async function getStringHash(store: Store): Promise<Hash> {
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
return builtinSchemas["@string"] ?? "";
|
||||
return builtinSchemas["@ocas/string"] ?? "";
|
||||
}
|
||||
|
||||
// ---- Tests ----
|
||||
|
||||
@@ -91,7 +91,7 @@ async function createTestNode(
|
||||
*/
|
||||
async function getBootstrapHash(store: Store): Promise<Hash> {
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
return builtinSchemas["@schema"] ?? "";
|
||||
return builtinSchemas["@ocas/schema"] ?? "";
|
||||
}
|
||||
|
||||
// ---- Tests ----
|
||||
|
||||
@@ -5,26 +5,26 @@ import { getSchema } from "./schema.js";
|
||||
import { createMemoryStore } from "./store.js";
|
||||
|
||||
const OUTPUT_ALIASES = [
|
||||
"@output/put",
|
||||
"@output/get",
|
||||
"@output/has",
|
||||
"@output/hash",
|
||||
"@output/verify",
|
||||
"@output/refs",
|
||||
"@output/walk",
|
||||
"@output/list",
|
||||
"@output/list-meta",
|
||||
"@output/list-schema",
|
||||
"@output/var-set",
|
||||
"@output/var-get",
|
||||
"@output/var-delete",
|
||||
"@output/var-tag",
|
||||
"@output/var-list",
|
||||
"@output/template-set",
|
||||
"@output/template-get",
|
||||
"@output/template-list",
|
||||
"@output/template-delete",
|
||||
"@output/gc",
|
||||
"@ocas/output/put",
|
||||
"@ocas/output/get",
|
||||
"@ocas/output/has",
|
||||
"@ocas/output/hash",
|
||||
"@ocas/output/verify",
|
||||
"@ocas/output/refs",
|
||||
"@ocas/output/walk",
|
||||
"@ocas/output/list",
|
||||
"@ocas/output/list-meta",
|
||||
"@ocas/output/list-schema",
|
||||
"@ocas/output/var-set",
|
||||
"@ocas/output/var-get",
|
||||
"@ocas/output/var-delete",
|
||||
"@ocas/output/var-tag",
|
||||
"@ocas/output/var-list",
|
||||
"@ocas/output/template-set",
|
||||
"@ocas/output/template-get",
|
||||
"@ocas/output/template-list",
|
||||
"@ocas/output/template-delete",
|
||||
"@ocas/output/gc",
|
||||
] as const;
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
@@ -37,12 +37,12 @@ describe("bootstrap - Built-in Schemas", () => {
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
|
||||
// Should return object with 6 primitive + 20 output aliases = 26
|
||||
expect(builtinSchemas).toHaveProperty("@schema");
|
||||
expect(builtinSchemas).toHaveProperty("@string");
|
||||
expect(builtinSchemas).toHaveProperty("@number");
|
||||
expect(builtinSchemas).toHaveProperty("@object");
|
||||
expect(builtinSchemas).toHaveProperty("@array");
|
||||
expect(builtinSchemas).toHaveProperty("@bool");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/schema");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/string");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/number");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/object");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/array");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/bool");
|
||||
|
||||
for (const alias of OUTPUT_ALIASES) {
|
||||
expect(builtinSchemas).toHaveProperty(alias);
|
||||
@@ -61,7 +61,7 @@ describe("bootstrap - Built-in Schemas", () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
|
||||
const metaHash = builtinSchemas["@schema"];
|
||||
const metaHash = builtinSchemas["@ocas/schema"];
|
||||
if (!metaHash) throw new Error("@schema not found");
|
||||
|
||||
const metaSchema = getSchema(store, metaHash);
|
||||
@@ -74,7 +74,7 @@ describe("bootstrap - Built-in Schemas", () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
|
||||
const stringHash = builtinSchemas["@string"];
|
||||
const stringHash = builtinSchemas["@ocas/string"];
|
||||
if (!stringHash) throw new Error("@string not found");
|
||||
|
||||
const stringSchema = getSchema(store, stringHash);
|
||||
@@ -85,7 +85,7 @@ describe("bootstrap - Built-in Schemas", () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
|
||||
const numberHash = builtinSchemas["@number"];
|
||||
const numberHash = builtinSchemas["@ocas/number"];
|
||||
if (!numberHash) throw new Error("@number not found");
|
||||
|
||||
const numberSchema = getSchema(store, numberHash);
|
||||
@@ -96,7 +96,7 @@ describe("bootstrap - Built-in Schemas", () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
|
||||
const objectHash = builtinSchemas["@object"];
|
||||
const objectHash = builtinSchemas["@ocas/object"];
|
||||
if (!objectHash) throw new Error("@object not found");
|
||||
|
||||
const objectSchema = getSchema(store, objectHash);
|
||||
@@ -107,19 +107,19 @@ describe("bootstrap - Built-in Schemas", () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
|
||||
const arrayHash = builtinSchemas["@array"];
|
||||
const arrayHash = builtinSchemas["@ocas/array"];
|
||||
if (!arrayHash) throw new Error("@array not found");
|
||||
|
||||
const arraySchema = getSchema(store, arrayHash);
|
||||
expect(arraySchema).toEqual({ type: "array" });
|
||||
});
|
||||
|
||||
test("should register @bool schema correctly", async () => {
|
||||
test("should register @ocas/bool schema correctly", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
|
||||
const boolHash = builtinSchemas["@bool"];
|
||||
if (!boolHash) throw new Error("@bool not found");
|
||||
const boolHash = builtinSchemas["@ocas/bool"];
|
||||
if (!boolHash) throw new Error("@ocas/bool not found");
|
||||
|
||||
const boolSchema = getSchema(store, boolHash);
|
||||
expect(boolSchema).toEqual({ type: "boolean" });
|
||||
@@ -133,23 +133,23 @@ describe("bootstrap - Built-in Schemas", () => {
|
||||
expect(first).toEqual(second);
|
||||
|
||||
// Verify each alias points to same hash
|
||||
expect(first["@string"]).toBe(second["@string"]);
|
||||
expect(first["@number"]).toBe(second["@number"]);
|
||||
expect(first["@object"]).toBe(second["@object"]);
|
||||
expect(first["@array"]).toBe(second["@array"]);
|
||||
expect(first["@bool"]).toBe(second["@bool"]);
|
||||
expect(first["@schema"]).toBe(second["@schema"]);
|
||||
expect(first["@ocas/string"]).toBe(second["@ocas/string"]);
|
||||
expect(first["@ocas/number"]).toBe(second["@ocas/number"]);
|
||||
expect(first["@ocas/object"]).toBe(second["@ocas/object"]);
|
||||
expect(first["@ocas/array"]).toBe(second["@ocas/array"]);
|
||||
expect(first["@ocas/bool"]).toBe(second["@ocas/bool"]);
|
||||
expect(first["@ocas/schema"]).toBe(second["@ocas/schema"]);
|
||||
});
|
||||
|
||||
test("all built-in schemas should be typed by meta-schema", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
|
||||
const metaHash = builtinSchemas["@schema"];
|
||||
const metaHash = builtinSchemas["@ocas/schema"];
|
||||
if (!metaHash) throw new Error("@schema not found");
|
||||
|
||||
for (const [alias, hash] of Object.entries(builtinSchemas)) {
|
||||
if (alias === "@schema") continue; // meta-schema is self-typed
|
||||
if (alias === "@ocas/schema") continue; // meta-schema is self-typed
|
||||
|
||||
const node = store.get(hash);
|
||||
expect(node).not.toBeNull();
|
||||
@@ -159,11 +159,11 @@ describe("bootstrap - Built-in Schemas", () => {
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
// @output/* Schema Registration Tests
|
||||
// @ocas/output/* Schema Registration Tests
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
describe("bootstrap - @output/* Schemas", () => {
|
||||
test("each @output/* schema has a title", async () => {
|
||||
describe("bootstrap - @ocas/output/* Schemas", () => {
|
||||
test("each @ocas/output/* schema has a title", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
|
||||
@@ -178,41 +178,41 @@ describe("bootstrap - @output/* Schemas", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("@output/put schema describes a cas_ref string", async () => {
|
||||
test("@ocas/output/put schema describes a ocas_ref string", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const hash = aliases["@output/put"];
|
||||
if (!hash) throw new Error("@output/put not found");
|
||||
const hash = aliases["@ocas/output/put"];
|
||||
if (!hash) throw new Error("@ocas/output/put not found");
|
||||
|
||||
const schema = getSchema(store, hash);
|
||||
expect(schema).toEqual({
|
||||
type: "string",
|
||||
format: "cas_ref",
|
||||
format: "ocas_ref",
|
||||
title: "ocas put result",
|
||||
});
|
||||
});
|
||||
|
||||
test("@output/get schema describes object with type, payload, timestamp", async () => {
|
||||
test("@ocas/output/get schema describes object with type, payload, timestamp", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const hash = aliases["@output/get"];
|
||||
if (!hash) throw new Error("@output/get not found");
|
||||
const hash = aliases["@ocas/output/get"];
|
||||
if (!hash) throw new Error("@ocas/output/get not found");
|
||||
|
||||
const schema = getSchema(store, hash) as JSONSchema;
|
||||
expect(schema.type).toBe("object");
|
||||
expect(schema.title).toBe("ocas get result");
|
||||
|
||||
const props = schema.properties as Record<string, JSONSchema>;
|
||||
expect(props.type).toEqual({ type: "string", format: "cas_ref" });
|
||||
expect(props.type).toEqual({ type: "string", format: "ocas_ref" });
|
||||
expect(props.payload).toEqual({});
|
||||
expect(props.timestamp).toEqual({ type: "number" });
|
||||
});
|
||||
|
||||
test("@output/has schema describes a boolean", async () => {
|
||||
test("@ocas/output/has schema describes a boolean", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const hash = aliases["@output/has"];
|
||||
if (!hash) throw new Error("@output/has not found");
|
||||
const hash = aliases["@ocas/output/has"];
|
||||
if (!hash) throw new Error("@ocas/output/has not found");
|
||||
|
||||
expect(getSchema(store, hash)).toEqual({
|
||||
type: "boolean",
|
||||
@@ -220,11 +220,11 @@ describe("bootstrap - @output/* Schemas", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("@output/verify schema describes enum of ok|corrupted|invalid", async () => {
|
||||
test("@ocas/output/verify schema describes enum of ok|corrupted|invalid", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const hash = aliases["@output/verify"];
|
||||
if (!hash) throw new Error("@output/verify not found");
|
||||
const hash = aliases["@ocas/output/verify"];
|
||||
if (!hash) throw new Error("@ocas/output/verify not found");
|
||||
|
||||
const schema = getSchema(store, hash);
|
||||
expect(schema).toEqual({
|
||||
@@ -234,24 +234,24 @@ describe("bootstrap - @output/* Schemas", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("@output/refs schema describes array of cas_ref strings", async () => {
|
||||
test("@ocas/output/refs schema describes array of ocas_ref strings", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const hash = aliases["@output/refs"];
|
||||
if (!hash) throw new Error("@output/refs not found");
|
||||
const hash = aliases["@ocas/output/refs"];
|
||||
if (!hash) throw new Error("@ocas/output/refs not found");
|
||||
|
||||
expect(getSchema(store, hash)).toEqual({
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
title: "ocas refs result",
|
||||
});
|
||||
});
|
||||
|
||||
test("@output/gc schema describes object with gc stats fields", async () => {
|
||||
test("@ocas/output/gc schema describes object with gc stats fields", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const hash = aliases["@output/gc"];
|
||||
if (!hash) throw new Error("@output/gc not found");
|
||||
const hash = aliases["@ocas/output/gc"];
|
||||
if (!hash) throw new Error("@ocas/output/gc not found");
|
||||
|
||||
const schema = getSchema(store, hash) as JSONSchema;
|
||||
expect(schema.type).toBe("object");
|
||||
@@ -264,11 +264,11 @@ describe("bootstrap - @output/* Schemas", () => {
|
||||
expect(props.scanned).toEqual({ type: "number" });
|
||||
});
|
||||
|
||||
test("@output/var-set schema describes a Variable object", async () => {
|
||||
test("@ocas/output/var-set schema describes a Variable object", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const hash = aliases["@output/var-set"];
|
||||
if (!hash) throw new Error("@output/var-set not found");
|
||||
const hash = aliases["@ocas/output/var-set"];
|
||||
if (!hash) throw new Error("@ocas/output/var-set not found");
|
||||
|
||||
const schema = getSchema(store, hash) as JSONSchema;
|
||||
expect(schema.type).toBe("object");
|
||||
@@ -276,15 +276,15 @@ describe("bootstrap - @output/* Schemas", () => {
|
||||
|
||||
const props = schema.properties as Record<string, JSONSchema>;
|
||||
expect(props.name).toEqual({ type: "string" });
|
||||
expect(props.schema).toEqual({ type: "string", format: "cas_ref" });
|
||||
expect(props.value).toEqual({ type: "string", format: "cas_ref" });
|
||||
expect(props.schema).toEqual({ type: "string", format: "ocas_ref" });
|
||||
expect(props.value).toEqual({ type: "string", format: "ocas_ref" });
|
||||
});
|
||||
|
||||
test("@output/var-list schema describes array of Variable objects", async () => {
|
||||
test("@ocas/output/var-list schema describes array of Variable objects", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const hash = aliases["@output/var-list"];
|
||||
if (!hash) throw new Error("@output/var-list not found");
|
||||
const hash = aliases["@ocas/output/var-list"];
|
||||
if (!hash) throw new Error("@ocas/output/var-list not found");
|
||||
|
||||
const schema = getSchema(store, hash) as JSONSchema;
|
||||
expect(schema.type).toBe("array");
|
||||
@@ -296,11 +296,11 @@ describe("bootstrap - @output/* Schemas", () => {
|
||||
expect(props.name).toEqual({ type: "string" });
|
||||
});
|
||||
|
||||
test("@output/template-delete schema describes object with deleted boolean", async () => {
|
||||
test("@ocas/output/template-delete schema describes object with deleted boolean", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const hash = aliases["@output/template-delete"];
|
||||
if (!hash) throw new Error("@output/template-delete not found");
|
||||
const hash = aliases["@ocas/output/template-delete"];
|
||||
if (!hash) throw new Error("@ocas/output/template-delete not found");
|
||||
|
||||
expect(getSchema(store, hash)).toEqual({
|
||||
type: "object",
|
||||
@@ -309,7 +309,7 @@ describe("bootstrap - @output/* Schemas", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("all @output/* schemas are distinct hashes", async () => {
|
||||
test("all @ocas/output/* schemas are distinct hashes", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
|
||||
@@ -323,7 +323,7 @@ describe("bootstrap - meta and schemas indexes (D1)", () => {
|
||||
test("listMeta contains the bootstrap meta-schema hash", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
const metaHash = aliases["@schema"];
|
||||
const metaHash = aliases["@ocas/schema"];
|
||||
expect(store.listMeta()).toContain(metaHash as string);
|
||||
});
|
||||
|
||||
|
||||
@@ -108,8 +108,8 @@ const BOOTSTRAP_PAYLOAD = {
|
||||
|
||||
const VARIABLE_PROPERTIES = {
|
||||
name: { type: "string" },
|
||||
schema: { type: "string", format: "cas_ref" },
|
||||
value: { type: "string", format: "cas_ref" },
|
||||
schema: { type: "string", format: "ocas_ref" },
|
||||
value: { type: "string", format: "ocas_ref" },
|
||||
created: { type: "number" },
|
||||
updated: { type: "number" },
|
||||
tags: { type: "object" },
|
||||
@@ -120,28 +120,28 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
readonly [alias: string, schema: Record<string, unknown>]
|
||||
> = [
|
||||
[
|
||||
"@output/put",
|
||||
{ type: "string", format: "cas_ref", title: "ocas put result" },
|
||||
"@ocas/output/put",
|
||||
{ type: "string", format: "ocas_ref", title: "ocas put result" },
|
||||
],
|
||||
[
|
||||
"@output/get",
|
||||
"@ocas/output/get",
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
type: { type: "string", format: "cas_ref" },
|
||||
type: { type: "string", format: "ocas_ref" },
|
||||
payload: {},
|
||||
timestamp: { type: "number" },
|
||||
},
|
||||
title: "ocas get result",
|
||||
},
|
||||
],
|
||||
["@output/has", { type: "boolean", title: "ocas has result" }],
|
||||
["@ocas/output/has", { type: "boolean", title: "ocas has result" }],
|
||||
[
|
||||
"@output/hash",
|
||||
{ type: "string", format: "cas_ref", title: "ocas hash result" },
|
||||
"@ocas/output/hash",
|
||||
{ type: "string", format: "ocas_ref", title: "ocas hash result" },
|
||||
],
|
||||
[
|
||||
"@output/verify",
|
||||
"@ocas/output/verify",
|
||||
{
|
||||
type: "string",
|
||||
enum: ["ok", "corrupted", "invalid"],
|
||||
@@ -149,15 +149,15 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/refs",
|
||||
"@ocas/output/refs",
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
title: "ocas refs result",
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/walk",
|
||||
"@ocas/output/walk",
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
@@ -165,31 +165,31 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/list",
|
||||
"@ocas/output/list",
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
title: "ocas list result",
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/list-meta",
|
||||
"@ocas/output/list-meta",
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
title: "ocas list-meta result",
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/list-schema",
|
||||
"@ocas/output/list-schema",
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
title: "ocas list-schema result",
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/var-set",
|
||||
"@ocas/output/var-set",
|
||||
{
|
||||
type: "object",
|
||||
properties: { ...VARIABLE_PROPERTIES },
|
||||
@@ -197,7 +197,7 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/var-get",
|
||||
"@ocas/output/var-get",
|
||||
{
|
||||
type: "object",
|
||||
properties: { ...VARIABLE_PROPERTIES },
|
||||
@@ -205,7 +205,7 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/var-delete",
|
||||
"@ocas/output/var-delete",
|
||||
{
|
||||
type: "object",
|
||||
properties: { ...VARIABLE_PROPERTIES },
|
||||
@@ -213,7 +213,7 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/var-tag",
|
||||
"@ocas/output/var-tag",
|
||||
{
|
||||
type: "object",
|
||||
properties: { ...VARIABLE_PROPERTIES },
|
||||
@@ -221,7 +221,7 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/var-list",
|
||||
"@ocas/output/var-list",
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "object", properties: { ...VARIABLE_PROPERTIES } },
|
||||
@@ -229,36 +229,36 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/template-set",
|
||||
"@ocas/output/template-set",
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
schemaHash: { type: "string", format: "cas_ref" },
|
||||
contentHash: { type: "string", format: "cas_ref" },
|
||||
schemaHash: { type: "string", format: "ocas_ref" },
|
||||
contentHash: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
title: "ocas template set result",
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/template-get",
|
||||
"@ocas/output/template-get",
|
||||
{ type: "string", title: "ocas template get result" },
|
||||
],
|
||||
[
|
||||
"@output/template-list",
|
||||
"@ocas/output/template-list",
|
||||
{
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
schemaHash: { type: "string", format: "cas_ref" },
|
||||
contentHash: { type: "string", format: "cas_ref" },
|
||||
schemaHash: { type: "string", format: "ocas_ref" },
|
||||
contentHash: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
},
|
||||
title: "ocas template list result",
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/template-delete",
|
||||
"@ocas/output/template-delete",
|
||||
{
|
||||
type: "object",
|
||||
properties: { deleted: { type: "boolean" } },
|
||||
@@ -266,7 +266,7 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
},
|
||||
],
|
||||
[
|
||||
"@output/gc",
|
||||
"@ocas/output/gc",
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
@@ -283,7 +283,7 @@ const OUTPUT_SCHEMAS: ReadonlyArray<
|
||||
/**
|
||||
* Write the meta-schema seed node into the store and register built-in schemas.
|
||||
* The returned object contains aliases for the meta-schema, 5 primitive schemas,
|
||||
* and 18 @output/* schemas (24 total).
|
||||
* and 18 @ocas/output/* schemas (24 total).
|
||||
* Idempotent: calling bootstrap multiple times returns the same hashes.
|
||||
*/
|
||||
export async function bootstrap(store: Store): Promise<Record<string, Hash>> {
|
||||
@@ -301,14 +301,14 @@ export async function bootstrap(store: Store): Promise<Record<string, Hash>> {
|
||||
const arrayHash = await store.put(metaHash, { type: "array" });
|
||||
const boolHash = await store.put(metaHash, { type: "boolean" });
|
||||
|
||||
// 3. Register @output/* schemas
|
||||
// 3. Register @ocas/output/* schemas
|
||||
const aliases: Record<string, Hash> = {
|
||||
"@schema": metaHash,
|
||||
"@string": stringHash,
|
||||
"@number": numberHash,
|
||||
"@object": objectHash,
|
||||
"@array": arrayHash,
|
||||
"@bool": boolHash,
|
||||
"@ocas/schema": metaHash,
|
||||
"@ocas/string": stringHash,
|
||||
"@ocas/number": numberHash,
|
||||
"@ocas/object": objectHash,
|
||||
"@ocas/array": arrayHash,
|
||||
"@ocas/bool": boolHash,
|
||||
};
|
||||
|
||||
for (const [alias, schema] of OUTPUT_SCHEMAS) {
|
||||
|
||||
@@ -198,16 +198,16 @@ describe("createMemoryStore – listByType", () => {
|
||||
test("bootstrap node is listed under its self type", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const hash = builtinSchemas["@schema"] ?? "";
|
||||
const hash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
|
||||
// All built-in schemas should be typed by the meta-schema
|
||||
const allTypedByMeta = store.listByType(hash);
|
||||
expect(allTypedByMeta).toContain(hash); // meta-schema itself
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@string"] ?? "");
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@number"] ?? "");
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@object"] ?? "");
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@array"] ?? "");
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@bool"] ?? "");
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@ocas/string"] ?? "");
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@ocas/number"] ?? "");
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@ocas/object"] ?? "");
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@ocas/array"] ?? "");
|
||||
expect(allTypedByMeta).toContain(builtinSchemas["@ocas/bool"] ?? "");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -268,12 +268,12 @@ describe("bootstrap", () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
|
||||
expect(builtinSchemas).toHaveProperty("@schema");
|
||||
expect(builtinSchemas).toHaveProperty("@string");
|
||||
expect(builtinSchemas).toHaveProperty("@number");
|
||||
expect(builtinSchemas).toHaveProperty("@object");
|
||||
expect(builtinSchemas).toHaveProperty("@array");
|
||||
expect(builtinSchemas).toHaveProperty("@bool");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/schema");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/string");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/number");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/object");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/array");
|
||||
expect(builtinSchemas).toHaveProperty("@ocas/bool");
|
||||
|
||||
// All values should be valid hashes
|
||||
for (const hash of Object.values(builtinSchemas)) {
|
||||
@@ -287,7 +287,7 @@ describe("bootstrap", () => {
|
||||
test("meta-schema node is stored and retrievable", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
|
||||
expect(store.has(metaHash)).toBe(true);
|
||||
const node = store.get(metaHash);
|
||||
@@ -297,7 +297,7 @@ describe("bootstrap", () => {
|
||||
test("meta-schema node is self-referencing: type === hash", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const node = store.get(metaHash) as CasNode;
|
||||
|
||||
expect(node.type).toBe(metaHash);
|
||||
@@ -306,7 +306,7 @@ describe("bootstrap", () => {
|
||||
test("bootstrap node passes verify()", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const node = store.get(metaHash) as CasNode;
|
||||
|
||||
expect(await verify(metaHash, node)).toBe(true);
|
||||
@@ -319,6 +319,6 @@ describe("bootstrap", () => {
|
||||
|
||||
expect(h1).toEqual(h2);
|
||||
// All 26 built-in schemas should be typed by the meta-schema
|
||||
expect(store.listByType(h1["@schema"] ?? "")).toHaveLength(26);
|
||||
expect(store.listByType(h1["@ocas/schema"] ?? "")).toHaveLength(26);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -78,7 +78,7 @@ describe("Suite 2: Custom {% render %} Tag Implementation", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, {
|
||||
@@ -124,7 +124,7 @@ describe("Suite 2: Custom {% render %} Tag Implementation", () => {
|
||||
properties: {
|
||||
level: { type: "number" },
|
||||
child: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -181,8 +181,8 @@ describe("Suite 2: Custom {% render %} Tag Implementation", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
left: { type: "string", format: "cas_ref" },
|
||||
right: { type: "string", format: "cas_ref" },
|
||||
left: { type: "string", format: "ocas_ref" },
|
||||
right: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, {
|
||||
@@ -228,7 +228,7 @@ describe("Suite 2: Custom {% render %} Tag Implementation", () => {
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
child: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -268,7 +268,7 @@ describe("Suite 2: Custom {% render %} Tag Implementation", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const nodeHash = await store.put(nodeSchema, {
|
||||
@@ -311,7 +311,7 @@ describe("Suite 2: Custom {% render %} Tag Implementation", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { child: childHash });
|
||||
@@ -680,7 +680,7 @@ describe("Suite 5: Decay Priority Chain", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { child: childHash });
|
||||
@@ -727,7 +727,7 @@ describe("Suite 5: Decay Priority Chain", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { child: childHash });
|
||||
@@ -774,7 +774,7 @@ describe("Suite 5: Decay Priority Chain", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { child: childHash });
|
||||
@@ -818,7 +818,7 @@ describe("Suite 6: Recursive Rendering Edge Cases", () => {
|
||||
properties: {
|
||||
level: { type: "number" },
|
||||
next: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -865,7 +865,7 @@ describe("Suite 6: Recursive Rendering Edge Cases", () => {
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
ref: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -893,7 +893,7 @@ describe("Suite 6: Recursive Rendering Edge Cases", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("6.3 Array of cas_ref with Template", async () => {
|
||||
test("6.3 Array of ocas_ref with Template", async () => {
|
||||
const { store, varStore, cleanup } = await createTempVarStore();
|
||||
|
||||
try {
|
||||
@@ -912,7 +912,7 @@ describe("Suite 6: Recursive Rendering Edge Cases", () => {
|
||||
properties: {
|
||||
items: {
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -998,7 +998,7 @@ describe("Suite 7: Error Handling & Edge Cases", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { child: childHash });
|
||||
@@ -1038,7 +1038,7 @@ describe("Suite 7: Error Handling & Edge Cases", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { child: childHash });
|
||||
@@ -1078,7 +1078,7 @@ describe("Suite 7: Error Handling & Edge Cases", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { child: childHash });
|
||||
@@ -1118,7 +1118,7 @@ describe("Suite 7: Error Handling & Edge Cases", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { child: childHash });
|
||||
@@ -1206,7 +1206,7 @@ describe("Suite 8: Performance & Scalability", () => {
|
||||
properties: {
|
||||
items: {
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1748,7 +1748,7 @@ describe("Suite 10: Context Variable Completeness", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, {
|
||||
@@ -1808,7 +1808,7 @@ describe("Suite 10: Context Variable Completeness", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
custom: { type: "string" },
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, {
|
||||
|
||||
@@ -10,24 +10,24 @@ import type { VariableStore } from "./variable-store.js";
|
||||
import { createVariableStore } from "./variable-store.js";
|
||||
|
||||
const OUTPUT_ALIASES = [
|
||||
"@output/put",
|
||||
"@output/get",
|
||||
"@output/has",
|
||||
"@output/hash",
|
||||
"@output/verify",
|
||||
"@output/refs",
|
||||
"@output/walk",
|
||||
"@output/list",
|
||||
"@output/var-set",
|
||||
"@output/var-get",
|
||||
"@output/var-delete",
|
||||
"@output/var-tag",
|
||||
"@output/var-list",
|
||||
"@output/template-set",
|
||||
"@output/template-get",
|
||||
"@output/template-list",
|
||||
"@output/template-delete",
|
||||
"@output/gc",
|
||||
"@ocas/output/put",
|
||||
"@ocas/output/get",
|
||||
"@ocas/output/has",
|
||||
"@ocas/output/hash",
|
||||
"@ocas/output/verify",
|
||||
"@ocas/output/refs",
|
||||
"@ocas/output/walk",
|
||||
"@ocas/output/list",
|
||||
"@ocas/output/var-set",
|
||||
"@ocas/output/var-get",
|
||||
"@ocas/output/var-delete",
|
||||
"@ocas/output/var-tag",
|
||||
"@ocas/output/var-list",
|
||||
"@ocas/output/template-set",
|
||||
"@ocas/output/template-get",
|
||||
"@ocas/output/template-list",
|
||||
"@ocas/output/template-delete",
|
||||
"@ocas/output/gc",
|
||||
] as const;
|
||||
|
||||
describe("registerOutputTemplates", () => {
|
||||
@@ -40,7 +40,7 @@ describe("registerOutputTemplates", () => {
|
||||
await rm(tempDir, { recursive: true });
|
||||
});
|
||||
|
||||
test("registers a template for every @output/* schema", async () => {
|
||||
test("registers a template for every @ocas/output/* schema", async () => {
|
||||
tempDir = await mkdtemp(join(tmpdir(), "ocas-tmpl-"));
|
||||
store = createMemoryStore();
|
||||
await bootstrap(store);
|
||||
@@ -63,7 +63,7 @@ describe("registerOutputTemplates", () => {
|
||||
|
||||
await registerOutputTemplates(store, varStore);
|
||||
|
||||
const stringHash = aliases["@string"];
|
||||
const stringHash = aliases["@ocas/string"];
|
||||
if (!stringHash) throw new Error("@string not found");
|
||||
|
||||
for (const alias of OUTPUT_ALIASES) {
|
||||
@@ -93,7 +93,7 @@ describe("registerOutputTemplates", () => {
|
||||
expect(first).toEqual(second);
|
||||
});
|
||||
|
||||
test("@output/put template contains payload reference", async () => {
|
||||
test("@ocas/output/put template contains payload reference", async () => {
|
||||
tempDir = await mkdtemp(join(tmpdir(), "ocas-tmpl-"));
|
||||
store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
@@ -101,14 +101,14 @@ describe("registerOutputTemplates", () => {
|
||||
|
||||
await registerOutputTemplates(store, varStore);
|
||||
|
||||
const putHash = aliases["@output/put"];
|
||||
if (!putHash) throw new Error("@output/put not found");
|
||||
const stringHash = aliases["@string"];
|
||||
const putHash = aliases["@ocas/output/put"];
|
||||
if (!putHash) throw new Error("@ocas/output/put not found");
|
||||
const stringHash = aliases["@ocas/string"];
|
||||
if (!stringHash) throw new Error("@string not found");
|
||||
|
||||
const variable = varStore.get(`@ocas/template/text/${putHash}`, stringHash);
|
||||
if (variable === null)
|
||||
throw new Error("@output/put template variable not found");
|
||||
throw new Error("@ocas/output/put template variable not found");
|
||||
|
||||
const templateNode = store.get(variable.value);
|
||||
if (templateNode === null) throw new Error("Template node not found");
|
||||
|
||||
@@ -5,55 +5,55 @@ import type { VariableStore } from "./variable-store.js";
|
||||
const DEFAULT_TEMPLATES: ReadonlyArray<
|
||||
readonly [alias: string, template: string]
|
||||
> = [
|
||||
["@output/put", "{{ payload }}"],
|
||||
["@ocas/output/put", "{{ payload }}"],
|
||||
[
|
||||
"@output/get",
|
||||
"@ocas/output/get",
|
||||
"type: {{ payload.type }}\ntimestamp: {{ payload.timestamp }}",
|
||||
],
|
||||
["@output/has", "{{ payload }}"],
|
||||
["@output/hash", "{{ payload }}"],
|
||||
["@output/verify", "{{ payload }}"],
|
||||
["@output/refs", "{% for ref in payload %}{{ ref }}\n{% endfor %}"],
|
||||
["@output/walk", "{% for item in payload %}{{ item }}\n{% endfor %}"],
|
||||
["@output/list", "{% for item in payload %}{{ item }}\n{% endfor %}"],
|
||||
["@ocas/output/has", "{{ payload }}"],
|
||||
["@ocas/output/hash", "{{ payload }}"],
|
||||
["@ocas/output/verify", "{{ payload }}"],
|
||||
["@ocas/output/refs", "{% for ref in payload %}{{ ref }}\n{% endfor %}"],
|
||||
["@ocas/output/walk", "{% for item in payload %}{{ item }}\n{% endfor %}"],
|
||||
["@ocas/output/list", "{% for item in payload %}{{ item }}\n{% endfor %}"],
|
||||
[
|
||||
"@output/var-set",
|
||||
"@ocas/output/var-set",
|
||||
"name: {{ payload.name }}\nschema: {{ payload.schema }}\nvalue: {{ payload.value }}",
|
||||
],
|
||||
[
|
||||
"@output/var-get",
|
||||
"@ocas/output/var-get",
|
||||
"name: {{ payload.name }}\nschema: {{ payload.schema }}\nvalue: {{ payload.value }}",
|
||||
],
|
||||
[
|
||||
"@output/var-delete",
|
||||
"@ocas/output/var-delete",
|
||||
"name: {{ payload.name }}\nschema: {{ payload.schema }}\nvalue: {{ payload.value }}",
|
||||
],
|
||||
[
|
||||
"@output/var-tag",
|
||||
"@ocas/output/var-tag",
|
||||
"name: {{ payload.name }}\nschema: {{ payload.schema }}\nvalue: {{ payload.value }}",
|
||||
],
|
||||
[
|
||||
"@output/var-list",
|
||||
"@ocas/output/var-list",
|
||||
"{% for v in payload %}name: {{ v.name }}\nschema: {{ v.schema }}\nvalue: {{ v.value }}\n{% endfor %}",
|
||||
],
|
||||
[
|
||||
"@output/template-set",
|
||||
"@ocas/output/template-set",
|
||||
"schemaHash: {{ payload.schemaHash }}\ncontentHash: {{ payload.contentHash }}",
|
||||
],
|
||||
["@output/template-get", "{{ payload }}"],
|
||||
["@ocas/output/template-get", "{{ payload }}"],
|
||||
[
|
||||
"@output/template-list",
|
||||
"@ocas/output/template-list",
|
||||
"{% for t in payload %}schemaHash: {{ t.schemaHash }}\ncontentHash: {{ t.contentHash }}\n{% endfor %}",
|
||||
],
|
||||
["@output/template-delete", "deleted: {{ payload.deleted }}"],
|
||||
["@ocas/output/template-delete", "deleted: {{ payload.deleted }}"],
|
||||
[
|
||||
"@output/gc",
|
||||
"@ocas/output/gc",
|
||||
"total: {{ payload.total }}\nreachable: {{ payload.reachable }}\ncollected: {{ payload.collected }}\nscanned: {{ payload.scanned }}",
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Register default LiquidJS templates for all @output/* schemas.
|
||||
* Register default LiquidJS templates for all @ocas/output/* schemas.
|
||||
* Each template is stored as a @string CAS node and bound to
|
||||
* the variable `@ocas/template/text/<schema-hash>`.
|
||||
*
|
||||
@@ -64,7 +64,7 @@ export async function registerOutputTemplates(
|
||||
varStore: VariableStore,
|
||||
): Promise<Record<string, Hash>> {
|
||||
const aliases = await bootstrap(store);
|
||||
const stringHash = aliases["@string"];
|
||||
const stringHash = aliases["@ocas/string"];
|
||||
if (stringHash === undefined) {
|
||||
throw new Error("@string schema not found in bootstrap result");
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ describe("Suite 2: Resolution Decay Model", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
title: { type: "string" },
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, {
|
||||
@@ -123,7 +123,7 @@ describe("Suite 2: Resolution Decay Model", () => {
|
||||
properties: {
|
||||
value: { type: "number" },
|
||||
next: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -159,7 +159,7 @@ describe("Suite 2: Resolution Decay Model", () => {
|
||||
properties: {
|
||||
level: { type: "number" },
|
||||
child: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -197,7 +197,7 @@ describe("Suite 2: Resolution Decay Model", () => {
|
||||
properties: {
|
||||
level: { type: "number" },
|
||||
next: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -232,7 +232,7 @@ describe("Suite 2: Resolution Decay Model", () => {
|
||||
properties: {
|
||||
level: { type: "number" },
|
||||
next: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -281,7 +281,7 @@ describe("Suite 3: Complex Graph Structures", () => {
|
||||
properties: {
|
||||
items: {
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -300,7 +300,7 @@ describe("Suite 3: Complex Graph Structures", () => {
|
||||
expect(output).toContain("item3");
|
||||
});
|
||||
|
||||
test("3.2 Object with Multiple cas_ref Fields", async () => {
|
||||
test("3.2 Object with Multiple ocas_ref Fields", async () => {
|
||||
const store = createMemoryStore();
|
||||
await bootstrap(store);
|
||||
|
||||
@@ -317,8 +317,8 @@ describe("Suite 3: Complex Graph Structures", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
left: { type: "string", format: "cas_ref" },
|
||||
right: { type: "string", format: "cas_ref" },
|
||||
left: { type: "string", format: "ocas_ref" },
|
||||
right: { type: "string", format: "ocas_ref" },
|
||||
data: { type: "string" },
|
||||
},
|
||||
});
|
||||
@@ -348,7 +348,7 @@ describe("Suite 3: Complex Graph Structures", () => {
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
ref: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -387,7 +387,7 @@ describe("Suite 3: Complex Graph Structures", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const branchA = await store.put(branchSchema, {
|
||||
@@ -402,8 +402,8 @@ describe("Suite 3: Complex Graph Structures", () => {
|
||||
const rootSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
left: { type: "string", format: "cas_ref" },
|
||||
right: { type: "string", format: "cas_ref" },
|
||||
left: { type: "string", format: "ocas_ref" },
|
||||
right: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const rootHash = await store.put(rootSchema, {
|
||||
@@ -431,10 +431,10 @@ describe("Suite 3: Complex Graph Structures", () => {
|
||||
properties: {
|
||||
value: { type: "number" },
|
||||
left: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
right: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -502,7 +502,7 @@ describe("Suite 4: Epsilon Boundary Cases", () => {
|
||||
properties: {
|
||||
level: { type: "number" },
|
||||
next: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -537,7 +537,7 @@ describe("Suite 4: Epsilon Boundary Cases", () => {
|
||||
properties: {
|
||||
level: { type: "number" },
|
||||
next: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -639,7 +639,7 @@ describe("Suite 5: YAML Output Format", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { child: childHash });
|
||||
@@ -673,7 +673,7 @@ describe("Suite 5: YAML Output Format", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
ref: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -686,7 +686,7 @@ describe("Suite 5: YAML Output Format", () => {
|
||||
});
|
||||
|
||||
describe("Suite 6: Schema Integration", () => {
|
||||
test("6.1 Detect cas_ref Fields via Schema", async () => {
|
||||
test("6.1 Detect ocas_ref Fields via Schema", async () => {
|
||||
const store = createMemoryStore();
|
||||
await bootstrap(store);
|
||||
|
||||
@@ -701,7 +701,7 @@ describe("Suite 6: Schema Integration", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
link: { type: "string", format: "cas_ref" },
|
||||
link: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, { link: childHash });
|
||||
@@ -715,7 +715,7 @@ describe("Suite 6: Schema Integration", () => {
|
||||
expect(output).toContain("child");
|
||||
});
|
||||
|
||||
test("6.2 Non-cas_ref String Not Expanded", async () => {
|
||||
test("6.2 Non-ocas_ref String Not Expanded", async () => {
|
||||
const store = createMemoryStore();
|
||||
await bootstrap(store);
|
||||
const objSchema = await putSchema(store, {
|
||||
@@ -733,7 +733,7 @@ describe("Suite 6: Schema Integration", () => {
|
||||
expect(output).not.toMatch(/cas:[0-9A-HJKMNP-TV-Z]{13}/);
|
||||
});
|
||||
|
||||
test("6.3 Array of cas_ref", async () => {
|
||||
test("6.3 Array of ocas_ref", async () => {
|
||||
const store = createMemoryStore();
|
||||
await bootstrap(store);
|
||||
|
||||
@@ -748,7 +748,7 @@ describe("Suite 6: Schema Integration", () => {
|
||||
|
||||
const arraySchema = await putSchema(store, {
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
});
|
||||
const arrayHash = await store.put(arraySchema, [item1, item2]);
|
||||
|
||||
@@ -762,7 +762,7 @@ describe("Suite 6: Schema Integration", () => {
|
||||
expect(output).toContain("item2");
|
||||
});
|
||||
|
||||
test("6.4 anyOf with cas_ref (Nullable Reference)", async () => {
|
||||
test("6.4 anyOf with ocas_ref (Nullable Reference)", async () => {
|
||||
const store = createMemoryStore();
|
||||
await bootstrap(store);
|
||||
|
||||
@@ -778,7 +778,7 @@ describe("Suite 6: Schema Integration", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
ref: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -796,7 +796,7 @@ describe("Suite 6: Schema Integration", () => {
|
||||
test("6.5 Schema-less Node (Bootstrap Node)", async () => {
|
||||
const store = createMemoryStore();
|
||||
const types = await bootstrap(store);
|
||||
const schemaHash = types["@schema"];
|
||||
const schemaHash = types["@ocas/schema"];
|
||||
|
||||
const output = render(store, schemaHash);
|
||||
|
||||
@@ -813,7 +813,7 @@ describe("Suite 7: Error Handling", () => {
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const fakeChildHash = "ZZZZZZZZZZZZZ" as Hash;
|
||||
@@ -895,7 +895,7 @@ describe("Suite 8: Performance & Edge Cases", () => {
|
||||
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
});
|
||||
const parentHash = await store.put(parentSchema, children);
|
||||
|
||||
@@ -984,7 +984,7 @@ describe("Suite 9: renderDirect (in-memory rendering)", () => {
|
||||
expect(output).toContain("active: true");
|
||||
});
|
||||
|
||||
test("9.5 Render with store expands cas_ref fields", async () => {
|
||||
test("9.5 Render with store expands ocas_ref fields", async () => {
|
||||
const store = createMemoryStore();
|
||||
await bootstrap(store);
|
||||
|
||||
@@ -995,15 +995,15 @@ describe("Suite 9: renderDirect (in-memory rendering)", () => {
|
||||
});
|
||||
const childHash = await store.put(childSchema, { msg: "inner" });
|
||||
|
||||
// Parent schema with cas_ref
|
||||
// Parent schema with ocas_ref
|
||||
const parentSchema = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
|
||||
// Render directly with store — cas_ref should expand
|
||||
// Render directly with store — ocas_ref should expand
|
||||
const output = renderDirect(
|
||||
parentSchema,
|
||||
{ child: childHash },
|
||||
@@ -1041,8 +1041,8 @@ describe("Suite 9: renderDirect (in-memory rendering)", () => {
|
||||
expect(output.trim()).toBe("null");
|
||||
});
|
||||
|
||||
test("9.9 cas_ref without store renders as cas: reference", () => {
|
||||
// Without store, can't identify cas_ref fields — hash strings stay as strings
|
||||
test("9.9 ocas_ref without store renders as cas: reference", () => {
|
||||
// Without store, can't identify ocas_ref fields — hash strings stay as strings
|
||||
const fakeTypeHash = "0000000000000" as Hash;
|
||||
const someHash = "ABCDEFGH12345" as Hash;
|
||||
const output = renderDirect(fakeTypeHash, { ref: someHash }, null, null);
|
||||
@@ -1099,7 +1099,7 @@ describe("Suite 10: Missing Root Hash Error Handling (Issue #53)", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
title: { type: "string" },
|
||||
child: { type: "string", format: "cas_ref" },
|
||||
child: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1124,7 +1124,7 @@ describe("Suite 10: Missing Root Hash Error Handling (Issue #53)", () => {
|
||||
properties: {
|
||||
level: { type: "number" },
|
||||
next: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -112,7 +112,7 @@ export async function renderAsync(
|
||||
/**
|
||||
* Render a value directly (in-memory) without requiring it to be stored.
|
||||
* Accepts a raw { type, value } pair. Store is optional and read-only —
|
||||
* used only for schema lookup and expanding nested cas_ref references.
|
||||
* used only for schema lookup and expanding nested ocas_ref references.
|
||||
* No data is written to the store.
|
||||
*/
|
||||
export function renderDirect(
|
||||
@@ -123,7 +123,7 @@ export function renderDirect(
|
||||
): string {
|
||||
const { resolution, decay, epsilon } = validateAndExtractOptions(options);
|
||||
|
||||
// Try to get schema from store to identify cas_ref fields
|
||||
// Try to get schema from store to identify ocas_ref fields
|
||||
let refSet = new Set<Hash>();
|
||||
if (store !== null) {
|
||||
const schema = getSchema(store, typeHash);
|
||||
@@ -197,7 +197,7 @@ function renderNode(
|
||||
// Calculate child resolution for next level
|
||||
const childResolution = currentResolution * decay;
|
||||
|
||||
// Render the payload with recursive expansion of cas_ref fields
|
||||
// Render the payload with recursive expansion of ocas_ref fields
|
||||
const rendered = renderValue(
|
||||
store,
|
||||
node.payload,
|
||||
@@ -229,7 +229,7 @@ function renderValue(
|
||||
|
||||
// Handle primitives
|
||||
if (typeof value === "string") {
|
||||
// Check if this string is a cas_ref
|
||||
// Check if this string is a ocas_ref
|
||||
if (refHashes.has(value as Hash)) {
|
||||
// Recursively render the referenced node
|
||||
return renderNode(
|
||||
|
||||
@@ -30,7 +30,7 @@ describe("putSchema", () => {
|
||||
test("schema node type equals the meta-schema hash", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const schemaHash = await putSchema(store, { type: "string" });
|
||||
const node = store.get(schemaHash) as CasNode;
|
||||
|
||||
@@ -78,7 +78,7 @@ describe("getSchema", () => {
|
||||
type: "object",
|
||||
required: ["id"],
|
||||
properties: {
|
||||
id: { type: "string", format: "cas_ref" },
|
||||
id: { type: "string", format: "ocas_ref" },
|
||||
label: { type: "string" },
|
||||
},
|
||||
};
|
||||
@@ -143,10 +143,10 @@ describe("validate", () => {
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
// Step 4: refs() — extract cas_ref hashes from a node's payload
|
||||
// Step 4: refs() — extract ocas_ref hashes from a node's payload
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
describe("refs", () => {
|
||||
test("returns empty array when schema has no cas_ref fields", async () => {
|
||||
test("returns empty array when schema has no ocas_ref fields", async () => {
|
||||
const store = createMemoryStore();
|
||||
const schemaHash = await putSchema(store, {
|
||||
type: "object",
|
||||
@@ -158,12 +158,12 @@ describe("refs", () => {
|
||||
expect(refs(store, node)).toEqual([]);
|
||||
});
|
||||
|
||||
test("returns the cas_ref hash values from payload", async () => {
|
||||
test("returns the ocas_ref hash values from payload", async () => {
|
||||
const store = createMemoryStore();
|
||||
const schemaHash = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
parentHash: { type: "string", format: "cas_ref" },
|
||||
parentHash: { type: "string", format: "ocas_ref" },
|
||||
label: { type: "string" },
|
||||
},
|
||||
});
|
||||
@@ -178,13 +178,13 @@ describe("refs", () => {
|
||||
expect(refs(store, node)).toEqual([targetHash]);
|
||||
});
|
||||
|
||||
test("collects multiple cas_ref fields", async () => {
|
||||
test("collects multiple ocas_ref fields", async () => {
|
||||
const store = createMemoryStore();
|
||||
const schemaHash = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
leftHash: { type: "string", format: "cas_ref" },
|
||||
rightHash: { type: "string", format: "cas_ref" },
|
||||
leftHash: { type: "string", format: "ocas_ref" },
|
||||
rightHash: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -202,12 +202,12 @@ describe("refs", () => {
|
||||
expect(result).toContain(h2);
|
||||
});
|
||||
|
||||
test("skips null/undefined cas_ref values", async () => {
|
||||
test("skips null/undefined ocas_ref values", async () => {
|
||||
const store = createMemoryStore();
|
||||
const schemaHash = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
optionalRef: { type: "string", format: "cas_ref" },
|
||||
optionalRef: { type: "string", format: "ocas_ref" },
|
||||
label: { type: "string" },
|
||||
},
|
||||
});
|
||||
@@ -231,7 +231,7 @@ describe("refs", () => {
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
// Step 5: walk() — BFS traversal via cas_ref links
|
||||
// Step 5: walk() — BFS traversal via ocas_ref links
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
describe("walk", () => {
|
||||
test("visits a single node with no refs", async () => {
|
||||
@@ -253,7 +253,7 @@ describe("walk", () => {
|
||||
const schemaHash = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
nextHash: { type: "string", format: "cas_ref" },
|
||||
nextHash: { type: "string", format: "ocas_ref" },
|
||||
val: { type: "number" },
|
||||
},
|
||||
});
|
||||
@@ -277,7 +277,7 @@ describe("walk", () => {
|
||||
const schemaHash = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
peerHash: { type: "string", format: "cas_ref" },
|
||||
peerHash: { type: "string", format: "ocas_ref" },
|
||||
val: { type: "number" },
|
||||
},
|
||||
});
|
||||
@@ -295,8 +295,8 @@ describe("walk", () => {
|
||||
const schemaHash2 = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
leftHash: { type: "string", format: "cas_ref" },
|
||||
rightHash: { type: "string", format: "cas_ref" },
|
||||
leftHash: { type: "string", format: "ocas_ref" },
|
||||
rightHash: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
const rootHash = await store.put(schemaHash2, {
|
||||
@@ -319,7 +319,7 @@ describe("walk", () => {
|
||||
const store = createMemoryStore();
|
||||
const schemaHash = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: { ref: { type: "string", format: "cas_ref" } },
|
||||
properties: { ref: { type: "string", format: "ocas_ref" } },
|
||||
});
|
||||
const nodeHash = await store.put(schemaHash, { ref: "0000000000000" });
|
||||
|
||||
@@ -357,7 +357,7 @@ describe("bootstrap meta-schema self-reference", () => {
|
||||
test("metaNode.type === metaHash (self-referencing)", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const metaNode = store.get(metaHash) as CasNode;
|
||||
|
||||
expect(metaNode.type).toBe(metaHash);
|
||||
@@ -366,7 +366,7 @@ describe("bootstrap meta-schema self-reference", () => {
|
||||
test("schema nodes have type === metaHash", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const schemaHash = await putSchema(store, { type: "string" });
|
||||
const schemaNode = store.get(schemaHash) as CasNode;
|
||||
|
||||
@@ -376,7 +376,7 @@ describe("bootstrap meta-schema self-reference", () => {
|
||||
test("data nodes have type === schemaHash (not metaHash)", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const schemaHash = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: { val: { type: "number" } },
|
||||
@@ -492,7 +492,7 @@ describe("bootstrap meta-schema self-reference", () => {
|
||||
test("bootstrap is idempotent across putSchema calls", async () => {
|
||||
const store = createMemoryStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
|
||||
await putSchema(store, { type: "string" });
|
||||
await putSchema(store, { type: "number" });
|
||||
@@ -620,7 +620,7 @@ describe("bootstrap meta-schema self-reference", () => {
|
||||
allOf: [
|
||||
{
|
||||
type: "object",
|
||||
properties: { ref: { type: "string", format: "cas_ref" } },
|
||||
properties: { ref: { type: "string", format: "ocas_ref" } },
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -638,7 +638,7 @@ describe("bootstrap meta-schema self-reference", () => {
|
||||
const schema = await putSchema(store, {
|
||||
type: "object",
|
||||
patternProperties: {
|
||||
"^ref_": { type: "string", format: "cas_ref" },
|
||||
"^ref_": { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -654,7 +654,7 @@ describe("bootstrap meta-schema self-reference", () => {
|
||||
const innerSchema = await putSchema(store, { type: "string" });
|
||||
const schema = await putSchema(store, {
|
||||
type: "array",
|
||||
prefixItems: [{ type: "string", format: "cas_ref" }, { type: "number" }],
|
||||
prefixItems: [{ type: "string", format: "ocas_ref" }, { type: "number" }],
|
||||
});
|
||||
|
||||
const targetHash = await store.put(innerSchema, "hello");
|
||||
@@ -741,7 +741,7 @@ describe("bootstrap meta-schema self-reference", () => {
|
||||
const innerSchema = await putSchema(store, { type: "string" });
|
||||
const schema = await putSchema(store, {
|
||||
type: "array",
|
||||
contains: { type: "string", format: "cas_ref" },
|
||||
contains: { type: "string", format: "ocas_ref" },
|
||||
});
|
||||
|
||||
const targetHash = await store.put(innerSchema, "hello");
|
||||
|
||||
@@ -20,7 +20,7 @@ export class SchemaValidationError extends Error {
|
||||
}
|
||||
|
||||
const ajv = new Ajv();
|
||||
ajv.addFormat("cas_ref", /^[0-9A-HJKMNP-TV-Z]{13}$/);
|
||||
ajv.addFormat("ocas_ref", /^[0-9A-HJKMNP-TV-Z]{13}$/);
|
||||
|
||||
const ALLOWED_SCHEMA_KEYS = new Set([
|
||||
"type",
|
||||
@@ -253,7 +253,7 @@ export async function putSchema(
|
||||
jsonSchema: JSONSchema,
|
||||
): Promise<Hash> {
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"];
|
||||
const metaHash = builtinSchemas["@ocas/schema"];
|
||||
if (!metaHash) {
|
||||
throw new Error("Meta-schema not found in bootstrap result");
|
||||
}
|
||||
@@ -292,7 +292,7 @@ export function validate(store: Store, node: CasNode): boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively collect values of all properties whose schema has format: 'cas_ref'.
|
||||
* Recursively collect values of all properties whose schema has format: 'ocas_ref'.
|
||||
* Handles: direct format, anyOf/allOf (combinators), oneOf, if/then/else (conditionals),
|
||||
* not, contains, items + prefixItems (arrays), properties (nested objects),
|
||||
* additionalProperties (record refs), and patternProperties (regex-keyed refs).
|
||||
@@ -300,7 +300,7 @@ export function validate(store: Store, node: CasNode): boolean {
|
||||
export function collectRefs(schema: JSONSchema, value: unknown): Hash[] {
|
||||
const result: Hash[] = [];
|
||||
|
||||
if (schema.format === "cas_ref") {
|
||||
if (schema.format === "ocas_ref") {
|
||||
if (typeof value === "string") {
|
||||
result.push(value as Hash);
|
||||
}
|
||||
@@ -413,7 +413,7 @@ export function collectRefs(schema: JSONSchema, value: unknown): Hash[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all hashes referenced by this node via cas_ref fields in its schema.
|
||||
* Return all hashes referenced by this node via ocas_ref fields in its schema.
|
||||
* Null/undefined values are skipped.
|
||||
*/
|
||||
export function refs(store: Store, node: CasNode): Hash[] {
|
||||
|
||||
@@ -4,34 +4,38 @@ import { createMemoryStore } from "./store.js";
|
||||
import { wrapEnvelope } from "./wrap-envelope.js";
|
||||
|
||||
describe("wrapEnvelope", () => {
|
||||
test("resolves @output/put alias and returns envelope", async () => {
|
||||
test("resolves @ocas/output/put alias and returns envelope", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
|
||||
const envelope = await wrapEnvelope(store, "@output/put", "AAAAAAAAAAAAA");
|
||||
const envelope = await wrapEnvelope(
|
||||
store,
|
||||
"@ocas/output/put",
|
||||
"AAAAAAAAAAAAA",
|
||||
);
|
||||
|
||||
expect(envelope.type).toBe(aliases["@output/put"]);
|
||||
expect(envelope.type).toBe(aliases["@ocas/output/put"]);
|
||||
expect(envelope.value).toBe("AAAAAAAAAAAAA");
|
||||
});
|
||||
|
||||
test("resolves @output/has alias with boolean value", async () => {
|
||||
test("resolves @ocas/output/has alias with boolean value", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
|
||||
const envelope = await wrapEnvelope(store, "@output/has", true);
|
||||
const envelope = await wrapEnvelope(store, "@ocas/output/has", true);
|
||||
|
||||
expect(envelope.type).toBe(aliases["@output/has"]);
|
||||
expect(envelope.type).toBe(aliases["@ocas/output/has"]);
|
||||
expect(envelope.value).toBe(true);
|
||||
});
|
||||
|
||||
test("resolves @output/gc alias with object value", async () => {
|
||||
test("resolves @ocas/output/gc alias with object value", async () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
|
||||
const gcStats = { total: 100, reachable: 80, collected: 20, scanned: 5 };
|
||||
const envelope = await wrapEnvelope(store, "@output/gc", gcStats);
|
||||
const envelope = await wrapEnvelope(store, "@ocas/output/gc", gcStats);
|
||||
|
||||
expect(envelope.type).toBe(aliases["@output/gc"]);
|
||||
expect(envelope.type).toBe(aliases["@ocas/output/gc"]);
|
||||
expect(envelope.value).toEqual(gcStats);
|
||||
});
|
||||
|
||||
@@ -39,9 +43,9 @@ describe("wrapEnvelope", () => {
|
||||
const store = createMemoryStore();
|
||||
const aliases = await bootstrap(store);
|
||||
|
||||
const envelope = await wrapEnvelope(store, "@string", "hello");
|
||||
const envelope = await wrapEnvelope(store, "@ocas/string", "hello");
|
||||
|
||||
expect(envelope.type).toBe(aliases["@string"]);
|
||||
expect(envelope.type).toBe(aliases["@ocas/string"]);
|
||||
expect(envelope.value).toBe("hello");
|
||||
});
|
||||
|
||||
@@ -50,15 +54,19 @@ describe("wrapEnvelope", () => {
|
||||
await bootstrap(store);
|
||||
|
||||
await expect(
|
||||
wrapEnvelope(store, "@output/nonexistent", "value"),
|
||||
).rejects.toThrow("Unknown schema alias: @output/nonexistent");
|
||||
wrapEnvelope(store, "@ocas/output/nonexistent", "value"),
|
||||
).rejects.toThrow("Unknown schema alias: @ocas/output/nonexistent");
|
||||
});
|
||||
|
||||
test("is idempotent — same alias returns same type hash", async () => {
|
||||
const store = createMemoryStore();
|
||||
|
||||
const first = await wrapEnvelope(store, "@output/verify", "ok");
|
||||
const second = await wrapEnvelope(store, "@output/verify", "corrupted");
|
||||
const first = await wrapEnvelope(store, "@ocas/output/verify", "ok");
|
||||
const second = await wrapEnvelope(
|
||||
store,
|
||||
"@ocas/output/verify",
|
||||
"corrupted",
|
||||
);
|
||||
|
||||
expect(first.type).toBe(second.type);
|
||||
expect(first.value).toBe("ok");
|
||||
@@ -78,7 +86,11 @@ describe("wrapEnvelope", () => {
|
||||
tags: { env: "prod" },
|
||||
labels: ["stable"],
|
||||
};
|
||||
const envelope = await wrapEnvelope(store, "@output/var-set", original);
|
||||
const envelope = await wrapEnvelope(
|
||||
store,
|
||||
"@ocas/output/var-set",
|
||||
original,
|
||||
);
|
||||
|
||||
expect(envelope.value).toEqual(original);
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { bootstrap } from "./bootstrap.js";
|
||||
import type { Hash, Store } from "./types.js";
|
||||
|
||||
/**
|
||||
* Resolve a schema alias (e.g. "@output/put") to its hash via bootstrap,
|
||||
* Resolve a schema alias (e.g. "@ocas/output/put") to its hash via bootstrap,
|
||||
* then return a typed envelope ready for store.put() or direct rendering.
|
||||
*/
|
||||
export async function wrapEnvelope(
|
||||
|
||||
@@ -16,7 +16,7 @@ describe("Test Suite 1: Meta-Schema Structure and Self-Validation", () => {
|
||||
test("1.1: Meta-schema is a valid JSON Schema", async () => {
|
||||
const store = new MemStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const metaNode = store.get(metaHash);
|
||||
|
||||
expect(metaNode).not.toBeNull();
|
||||
@@ -27,7 +27,7 @@ describe("Test Suite 1: Meta-Schema Structure and Self-Validation", () => {
|
||||
test("1.2: Meta-schema self-validates", async () => {
|
||||
const store = new MemStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const metaNode = store.get(metaHash);
|
||||
|
||||
expect(metaNode).not.toBeNull();
|
||||
@@ -37,7 +37,7 @@ describe("Test Suite 1: Meta-Schema Structure and Self-Validation", () => {
|
||||
test("1.3: Meta-schema defines all supported keywords", async () => {
|
||||
const store = new MemStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const metaSchema = getSchema(store, metaHash);
|
||||
|
||||
expect(metaSchema).not.toBeNull();
|
||||
@@ -61,7 +61,7 @@ describe("Test Suite 1: Meta-Schema Structure and Self-Validation", () => {
|
||||
test("1.4: Meta-schema does not include unsupported keywords", async () => {
|
||||
const store = new MemStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const metaSchema = getSchema(store, metaHash);
|
||||
|
||||
expect(metaSchema).not.toBeNull();
|
||||
@@ -99,7 +99,7 @@ describe("Test Suite 1: Meta-Schema Structure and Self-Validation", () => {
|
||||
test("1.5: Meta-schema node type equals its own hash", async () => {
|
||||
const store = new MemStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const metaNode = store.get(metaHash);
|
||||
|
||||
expect(metaNode).not.toBeNull();
|
||||
@@ -199,7 +199,7 @@ describe("Test Suite 2: putSchema Validation - Valid Schemas", () => {
|
||||
await bootstrap(store);
|
||||
const hash = await putSchema(store, {
|
||||
type: "string",
|
||||
format: "cas_ref",
|
||||
format: "ocas_ref",
|
||||
});
|
||||
expect(hash).toBeTruthy();
|
||||
});
|
||||
@@ -239,13 +239,13 @@ describe("Test Suite 2: putSchema Validation - Valid Schemas", () => {
|
||||
type: "object",
|
||||
required: ["type", "payload"],
|
||||
properties: {
|
||||
type: { type: "string", format: "cas_ref" },
|
||||
type: { type: "string", format: "ocas_ref" },
|
||||
payload: {
|
||||
anyOf: [{ type: "object" }, { type: "null" }],
|
||||
},
|
||||
refs: {
|
||||
type: "array",
|
||||
items: { type: "string", format: "cas_ref" },
|
||||
items: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
@@ -469,7 +469,7 @@ describe("Test Suite 5: Backward Compatibility and Migration", () => {
|
||||
// This is a documentation test - the old hash was different
|
||||
const store = new MemStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const newMetaHash = builtinSchemas["@schema"] ?? "";
|
||||
const newMetaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
|
||||
// The new hash should be different from the old system metadata hash
|
||||
// We just verify it's a valid hash format
|
||||
@@ -555,14 +555,14 @@ describe("Test Suite 6: Integration with Existing Functionality", () => {
|
||||
expect(validate(store, invalidNode as CasNode)).toBe(false);
|
||||
});
|
||||
|
||||
test("6.3: refs() works with validated schemas containing cas_ref", async () => {
|
||||
test("6.3: refs() works with validated schemas containing ocas_ref", async () => {
|
||||
const store = new MemStore();
|
||||
await bootstrap(store);
|
||||
|
||||
const schemaHash = await putSchema(store, {
|
||||
type: "object",
|
||||
properties: {
|
||||
ref: { type: "string", format: "cas_ref" },
|
||||
ref: { type: "string", format: "ocas_ref" },
|
||||
},
|
||||
});
|
||||
|
||||
@@ -581,7 +581,7 @@ describe("Test Suite 6: Integration with Existing Functionality", () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
next: {
|
||||
anyOf: [{ type: "string", format: "cas_ref" }, { type: "null" }],
|
||||
anyOf: [{ type: "string", format: "ocas_ref" }, { type: "null" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -612,7 +612,7 @@ describe("Test Suite 7: Meta-Schema Content Validation", () => {
|
||||
test("7.1: Meta-schema allows recursive schema definitions", async () => {
|
||||
const store = new MemStore();
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"] ?? "";
|
||||
const metaHash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
const metaSchema = getSchema(store, metaHash);
|
||||
|
||||
expect(metaSchema).not.toBeNull();
|
||||
|
||||
@@ -52,7 +52,7 @@ describe("createFsStore – init and bootstrap", () => {
|
||||
test("bootstrap returns a valid 13-char self-referencing hash", async () => {
|
||||
const store = createFsStore(dir);
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const hash = builtinSchemas["@schema"] ?? "";
|
||||
const hash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
|
||||
expect(hash).toHaveLength(13);
|
||||
expect(hash).toMatch(/^[0-9A-HJKMNP-TV-Z]{13}$/);
|
||||
@@ -67,7 +67,7 @@ describe("createFsStore – init and bootstrap", () => {
|
||||
const h2 = await bootstrap(store);
|
||||
|
||||
expect(h1).toEqual(h2);
|
||||
expect(store.listByType(h1["@schema"] ?? "")).toHaveLength(26);
|
||||
expect(store.listByType(h1["@ocas/schema"] ?? "")).toHaveLength(26);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -114,7 +114,7 @@ describe("createFsStore – persistence round-trip", () => {
|
||||
test("bootstrap survives round-trip: self-referencing node reloads correctly", async () => {
|
||||
const store1 = createFsStore(dir);
|
||||
const builtinSchemas = await bootstrap(store1);
|
||||
const hash = builtinSchemas["@schema"] ?? "";
|
||||
const hash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
|
||||
const store2 = createFsStore(dir);
|
||||
const node = store2.get(hash) as CasNode;
|
||||
@@ -262,7 +262,7 @@ describe("createFsStore – listByType", () => {
|
||||
test("bootstrap node is listed under its self type after reload", async () => {
|
||||
const store1 = createFsStore(dir);
|
||||
const builtinSchemas = await bootstrap(store1);
|
||||
const hash = builtinSchemas["@schema"] ?? "";
|
||||
const hash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
|
||||
const store2 = createFsStore(dir);
|
||||
expect(store2.listByType(hash)).toContain(hash);
|
||||
@@ -296,7 +296,7 @@ describe("createFsStore – verify on disk-loaded nodes", () => {
|
||||
test("verify passes on a disk-loaded bootstrap node", async () => {
|
||||
const store1 = createFsStore(dir);
|
||||
const builtinSchemas = await bootstrap(store1);
|
||||
const hash = builtinSchemas["@schema"] ?? "";
|
||||
const hash = builtinSchemas["@ocas/schema"] ?? "";
|
||||
|
||||
const store2 = createFsStore(dir);
|
||||
const node = store2.get(hash) as CasNode;
|
||||
@@ -376,18 +376,18 @@ describe("openStore – async with auto-bootstrap", () => {
|
||||
|
||||
// Check that bootstrap schemas exist
|
||||
const builtinSchemas = await bootstrap(store);
|
||||
const metaHash = builtinSchemas["@schema"];
|
||||
const metaHash = builtinSchemas["@ocas/schema"];
|
||||
|
||||
expect(metaHash).toBeDefined();
|
||||
expect(store.has(metaHash as string)).toBe(true);
|
||||
|
||||
// Verify all core schemas exist
|
||||
expect(store.has(builtinSchemas["@string"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@number"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@object"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@array"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@bool"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@schema"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@ocas/string"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@ocas/number"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@ocas/object"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@ocas/array"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@ocas/bool"] as string)).toBe(true);
|
||||
expect(store.has(builtinSchemas["@ocas/schema"] as string)).toBe(true);
|
||||
});
|
||||
|
||||
test("openStore bootstrap is idempotent on subsequent opens", async () => {
|
||||
@@ -426,7 +426,7 @@ describe("openStore – async with auto-bootstrap", () => {
|
||||
const store2 = await openStore(dir);
|
||||
const schemas = await bootstrap(store2);
|
||||
|
||||
expect(store2.has(schemas["@schema"] as string)).toBe(true);
|
||||
expect(store2.has(schemas["@ocas/schema"] as string)).toBe(true);
|
||||
// Old data still exists
|
||||
expect(store2.listByType(typeHash)).toHaveLength(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user