Normalize C# provider advertisements at Eve boundary
This commit is contained in:
parent
4338a42c6e
commit
cdea1c8f9e
4 changed files with 175 additions and 2 deletions
6
packages/eve-contracts/dist/index.d.ts
vendored
6
packages/eve-contracts/dist/index.d.ts
vendored
|
|
@ -52,3 +52,9 @@ export declare const parseEveCommandInvocation: (value: unknown) => EveCommandIn
|
|||
export declare const parseEveCommandReceipt: (value: unknown) => EveCommandReceipt;
|
||||
export declare const parseEveCommandResult: (value: unknown) => EveCommandResult;
|
||||
export declare const parseEveInputCapability: (value: unknown) => EveInputCapability;
|
||||
/**
|
||||
* Converts the canonical positional MessagePack representation used by the C#
|
||||
* Eve package into the JSON-shaped provider contract used at browser/model
|
||||
* boundaries. This is serialization lowering, not a second advertisement DTO.
|
||||
*/
|
||||
export declare function normalizeEveProviderAdvertisement(value: unknown): unknown;
|
||||
|
|
|
|||
73
packages/eve-contracts/dist/index.js
vendored
73
packages/eve-contracts/dist/index.js
vendored
|
|
@ -44,7 +44,7 @@ export const isEveCommandInvocation = (value) => isEveContract("commandInvocatio
|
|||
export const isEveCommandReceipt = (value) => isEveContract("commandReceipt", value);
|
||||
export const isEveCommandResult = (value) => isEveContract("commandResult", value);
|
||||
export const isEveInputCapability = (value) => isEveContract("inputCapability", value);
|
||||
export const parseEveProviderAdvertisement = (value) => parseEveContract("providerAdvertisement", value);
|
||||
export const parseEveProviderAdvertisement = (value) => parseEveContract("providerAdvertisement", normalizeEveProviderAdvertisement(value));
|
||||
export const parseEveSurfaceDocument = (value) => parseEveContract("surface", value);
|
||||
export const parseEveCommandDescriptor = (value) => parseEveContract("commandDescriptor", value);
|
||||
export const parseEveCommandInvocation = (value) => parseEveContract("commandInvocation", value);
|
||||
|
|
@ -62,3 +62,74 @@ function requiredValidator(schemaId) {
|
|||
throw new Error(`Eve contract schema ${schemaId} was not registered.`);
|
||||
return validator;
|
||||
}
|
||||
/**
|
||||
* Converts the canonical positional MessagePack representation used by the C#
|
||||
* Eve package into the JSON-shaped provider contract used at browser/model
|
||||
* boundaries. This is serialization lowering, not a second advertisement DTO.
|
||||
*/
|
||||
export function normalizeEveProviderAdvertisement(value) {
|
||||
if (!Array.isArray(value))
|
||||
return value;
|
||||
if (value.length < 13)
|
||||
return value;
|
||||
const [schema, providerId, serviceId, verseId, title, kind, cultMeshAddress, updatedAtUtc, freshness, schemas, witnesses, surfaces, commands, authorizedBodyProducerIds] = value;
|
||||
return {
|
||||
schema,
|
||||
providerId,
|
||||
serviceId,
|
||||
verseId,
|
||||
title,
|
||||
kind,
|
||||
cultMeshAddress,
|
||||
updatedAtUtc,
|
||||
freshness: normalizeFreshness(freshness),
|
||||
schemas,
|
||||
witnesses: Array.isArray(witnesses) ? witnesses.map(normalizeWitness) : witnesses,
|
||||
surfaces: Array.isArray(surfaces) ? surfaces.map(normalizeSurfaceAdvertisement) : surfaces,
|
||||
commands: Array.isArray(commands) ? commands.map(normalizeAdvertisedCommand) : commands,
|
||||
...(Array.isArray(authorizedBodyProducerIds) ? { authorizedBodyProducerIds } : {}),
|
||||
};
|
||||
}
|
||||
function normalizeFreshness(value) {
|
||||
return Array.isArray(value)
|
||||
? { state: value[0], lastSeenAtUtc: value[1], maxAgeMs: value[2] }
|
||||
: value;
|
||||
}
|
||||
function normalizeWitness(value) {
|
||||
return Array.isArray(value)
|
||||
? { kind: value[0], ref: value[1], summary: value[2] }
|
||||
: value;
|
||||
}
|
||||
function normalizeSurfaceAdvertisement(value) {
|
||||
if (!Array.isArray(value))
|
||||
return value;
|
||||
return {
|
||||
surfaceId: value[0],
|
||||
schema: value[1],
|
||||
recordRef: value[2],
|
||||
transport: value[3],
|
||||
status: value[4],
|
||||
surfaceKind: value[5],
|
||||
...(value[6] ? { worldInteraction: normalizeWorldInteraction(value[6]) } : {}),
|
||||
};
|
||||
}
|
||||
function normalizeWorldInteraction(value) {
|
||||
if (!Array.isArray(value))
|
||||
return value;
|
||||
return {
|
||||
projectionKind: value[0],
|
||||
stateSchemas: value[1],
|
||||
commandBoundary: value[2],
|
||||
commandRecordRef: value[3],
|
||||
receiptSchema: value[4],
|
||||
receiptRecordRef: value[5],
|
||||
assetManifestRecordRef: value[6],
|
||||
loweringTargets: value[7],
|
||||
ownership: value[8],
|
||||
};
|
||||
}
|
||||
function normalizeAdvertisedCommand(value) {
|
||||
return Array.isArray(value)
|
||||
? { command: value[0], surfaceId: value[1], transport: value[2], summary: value[3] }
|
||||
: value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ export const isEveInputCapability = (value: unknown): value is EveInputCapabilit
|
|||
isEveContract("inputCapability", value);
|
||||
|
||||
export const parseEveProviderAdvertisement = (value: unknown): EveProviderAdvertisement =>
|
||||
parseEveContract("providerAdvertisement", value);
|
||||
parseEveContract("providerAdvertisement", normalizeEveProviderAdvertisement(value));
|
||||
export const parseEveSurfaceDocument = (value: unknown): EveSurfaceDocument =>
|
||||
parseEveContract("surface", value);
|
||||
export const parseEveCommandDescriptor = (value: unknown): EveCommandDescriptor =>
|
||||
|
|
@ -114,3 +114,77 @@ function requiredValidator(schemaId: string): ValidateFunction {
|
|||
if (!validator) throw new Error(`Eve contract schema ${schemaId} was not registered.`);
|
||||
return validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the canonical positional MessagePack representation used by the C#
|
||||
* Eve package into the JSON-shaped provider contract used at browser/model
|
||||
* boundaries. This is serialization lowering, not a second advertisement DTO.
|
||||
*/
|
||||
export function normalizeEveProviderAdvertisement(value: unknown): unknown {
|
||||
if (!Array.isArray(value)) return value;
|
||||
if (value.length < 13) return value;
|
||||
const [schema, providerId, serviceId, verseId, title, kind, cultMeshAddress, updatedAtUtc,
|
||||
freshness, schemas, witnesses, surfaces, commands, authorizedBodyProducerIds] = value;
|
||||
return {
|
||||
schema,
|
||||
providerId,
|
||||
serviceId,
|
||||
verseId,
|
||||
title,
|
||||
kind,
|
||||
cultMeshAddress,
|
||||
updatedAtUtc,
|
||||
freshness: normalizeFreshness(freshness),
|
||||
schemas,
|
||||
witnesses: Array.isArray(witnesses) ? witnesses.map(normalizeWitness) : witnesses,
|
||||
surfaces: Array.isArray(surfaces) ? surfaces.map(normalizeSurfaceAdvertisement) : surfaces,
|
||||
commands: Array.isArray(commands) ? commands.map(normalizeAdvertisedCommand) : commands,
|
||||
...(Array.isArray(authorizedBodyProducerIds) ? { authorizedBodyProducerIds } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeFreshness(value: unknown): unknown {
|
||||
return Array.isArray(value)
|
||||
? { state: value[0], lastSeenAtUtc: value[1], maxAgeMs: value[2] }
|
||||
: value;
|
||||
}
|
||||
|
||||
function normalizeWitness(value: unknown): unknown {
|
||||
return Array.isArray(value)
|
||||
? { kind: value[0], ref: value[1], summary: value[2] }
|
||||
: value;
|
||||
}
|
||||
|
||||
function normalizeSurfaceAdvertisement(value: unknown): unknown {
|
||||
if (!Array.isArray(value)) return value;
|
||||
return {
|
||||
surfaceId: value[0],
|
||||
schema: value[1],
|
||||
recordRef: value[2],
|
||||
transport: value[3],
|
||||
status: value[4],
|
||||
surfaceKind: value[5],
|
||||
...(value[6] ? { worldInteraction: normalizeWorldInteraction(value[6]) } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeWorldInteraction(value: unknown): unknown {
|
||||
if (!Array.isArray(value)) return value;
|
||||
return {
|
||||
projectionKind: value[0],
|
||||
stateSchemas: value[1],
|
||||
commandBoundary: value[2],
|
||||
commandRecordRef: value[3],
|
||||
receiptSchema: value[4],
|
||||
receiptRecordRef: value[5],
|
||||
assetManifestRecordRef: value[6],
|
||||
loweringTargets: value[7],
|
||||
ownership: value[8],
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeAdvertisedCommand(value: unknown): unknown {
|
||||
return Array.isArray(value)
|
||||
? { command: value[0], surfaceId: value[1], transport: value[2], summary: value[3] }
|
||||
: value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,6 +195,28 @@ test("validates an existing canonical Eve surface fixture", async () => {
|
|||
assert.equal(parseEveSurfaceDocument(fixture).providerId, "eve.world-smoke");
|
||||
});
|
||||
|
||||
test("provider parser lowers the canonical C# MessagePack tuple without app-specific decoding", () => {
|
||||
const advertisement = parseEveProviderAdvertisement([
|
||||
"gamecult.eve.provider_advertisement.v1",
|
||||
"aetheria",
|
||||
"aetheria-daemon",
|
||||
"aetheria.local",
|
||||
"Aetheria",
|
||||
"game.runtime",
|
||||
"cultmesh://aetheria",
|
||||
"2026-08-22T00:00:00Z",
|
||||
["fresh", "2026-08-22T00:00:00Z", 15_000],
|
||||
["gamecult.eve.surface.v1"],
|
||||
[["cultcache", "aetheria.cc", "typed state"]],
|
||||
[["aetheria.hangar", "gamecult.eve.surface.v1", "eve:surface:aetheria.hangar", "cultmesh-record", "active", "interactive-world",
|
||||
["provider-authored-world-surface", ["aetheria.frame.v1"], "aetheria.daemon.commands", "eve:commands", "gamecult.eve.command_receipt.v1", "eve:receipts", "eve:assets", ["web-reference"], "provider owns truth"]]],
|
||||
[["hangar.select_verse", "aetheria.hangar", "cultmesh", "Select Verse"]],
|
||||
["aetheria-daemon.soa"],
|
||||
]);
|
||||
assert.equal(advertisement.surfaces[0].worldInteraction.commandBoundary, "aetheria.daemon.commands");
|
||||
assert.equal(advertisement.witnesses[0].ref, "aetheria.cc");
|
||||
});
|
||||
|
||||
test("command results validate persisted receipts and transient Eve projections together", () => {
|
||||
const result = parseEveCommandResult({
|
||||
schema: "gamecult.eve.command_result.v1",
|
||||
|
|
|
|||
Loading…
Reference in a new issue