Aetheria/Aetheria.Rts.Web/Electron/aetheria-cultmesh.ts
2026-07-14 16:40:48 +01:00

797 lines
28 KiB
TypeScript

import { encode } from "@msgpack/msgpack";
import { performance } from "node:perf_hooks";
import { CultMesh } from "cultmesh-ts";
import type {
CultMeshDocumentCatalog,
CultMeshDocumentPublicationSource,
CultMeshPublicationDocumentBinding,
CultMeshOperationContext,
CultMeshQueryContext,
CultMeshSurfaceCatalogIndexDiagnostic,
CultMeshVerse,
} from "cultmesh-ts";
import type {
CultNetDocumentPutRawMessage,
CultNetPeer,
} from "cultnet-ts";
import {
AetheriaRtsSchemas,
createAetheriaRuntimeGameDocuments,
createAetheriaRuntimeGameOperationHandles,
createAetheriaRuntimeGameVerseHandles,
createAetheriaRuntimeGameQueryHandles,
describeAetheriaRuntimeGameLiveFeedSurface,
describeAetheriaRuntimeGameQueryHandles,
describeAetheriaRuntimeGameSurfaceCatalog,
type AetheriaRuntimeDaemonCommandReceipt,
type AssetManifestDocument,
type AuthorityStatusDocument,
type DaemonHealthDocument,
type GravityViewportResponse,
type InventoryDocument,
type ObjectsViewportResponse,
type RenderSplatsViewportResponse,
type AetheriaRuntimeGameLiveFeedDiagnostic,
type AetheriaRuntimeGameQueryDiagnostic,
type AetheriaRuntimeGameSurfaceCatalogDiagnostic,
type AetheriaRuntimeGameOperationHandles,
type AetheriaRuntimeGameVerseHandles,
type AetheriaRuntimeGameDocuments,
type AetheriaRuntimeViewportFeedRequest,
type AetheriaRuntimeViewportFeedSnapshot,
type RtsSetMoveVectorRequest,
type RtsSetTargetRequest,
type SelectedObjectDocument,
type SelectedObjectRequest,
type StarbridgeSessionDocument,
type ViewportRequest,
type ViewportResponse,
} from "./aetheria-rts-bindings.js";
import {
readAuthorityStatusDocument,
readAssetManifestDocument,
readDaemonHealthDocument,
readGravityViewportDocument,
readInventoryDocument,
readObjectsViewportDocument,
readRenderSplatsViewportDocument,
readSelectedObjectDocument,
readStarbridgeSessionSummaryDocument,
readViewportDocument,
} from "./aetheria-rts-local-documents.js";
const connectionId = 0x43554c54;
type AetheriaPublicationDocumentSpec = CultMeshPublicationDocumentBinding & {
readonly localPath: string;
readonly remoteRecordKey?: string;
};
type AetheriaRuntimeGameQueryExecutors = {
mapViewport: (request: ViewportRequest) => Promise<ViewportResponse>;
objectsViewport: (request: ViewportRequest) => Promise<ObjectsViewportResponse>;
gravityViewport: (request: ViewportRequest) => Promise<GravityViewportResponse>;
renderSplatsViewport: (request: ViewportRequest) => Promise<RenderSplatsViewportResponse>;
selectedObject: (request: SelectedObjectRequest) => Promise<SelectedObjectDocument>;
inventory: (request: SelectedObjectRequest) => Promise<InventoryDocument>;
daemonHealth: () => Promise<DaemonHealthDocument>;
authorityStatus: () => Promise<AuthorityStatusDocument>;
starbridgeSession: () => Promise<StarbridgeSessionDocument>;
assetManifest: () => Promise<AssetManifestDocument>;
};
export type AetheriaCultMeshClientOptions = {
publicationMode?: "local" | "remote";
snapshotTimeoutMs?: number;
};
export type AetheriaCultMeshDaemonTarget = {
readonly uri: string;
readonly peerId?: string;
readonly verseId?: string;
readonly role?: string;
readonly endpoints?: readonly string[];
};
export type {
BodyView,
EntityStatus,
GravityViewportResponse,
GravityInfluence,
InventoryItem,
ObjectsViewportResponse,
AetheriaRuntimeViewportFeedRequest,
AetheriaRuntimeViewportFeedSnapshot,
RtsSetMoveVectorRequest,
RtsSetTargetRequest,
SelectedObjectDocument,
SelectedObjectRequest,
StarbridgeSessionDocument,
ViewObject,
ViewportRequest,
ViewportResponse,
} from "./aetheria-rts-bindings.js";
export class AetheriaCultMeshClient {
#peer: CultNetPeer | null = null;
private readonly verse: CultMeshVerse;
private readonly queryVerse: CultMeshVerse;
private readonly commandVerse: CultMeshVerse;
private readonly daemonTarget: Required<AetheriaCultMeshDaemonTarget>;
public constructor(
daemonTarget: string | AetheriaCultMeshDaemonTarget,
statePath: string,
private readonly runtimeId = "aetheria-electron-client",
options: AetheriaCultMeshClientOptions = {},
) {
this.daemonTarget = normalizeDaemonTarget(daemonTarget);
const publicationMode = options.publicationMode ?? "local";
this.publicationDescription = publicationMode === "remote" ? this.daemonTarget.uri : statePath;
this.verse = CultMesh.verse("aetheria.local", this.runtimeId);
this.queryVerse = publicationMode === "remote"
? this.verse.withRoute("network", this.publicationDescription)
: this.verse.withRoute("shared-memory", this.publicationDescription);
this.commandVerse = this.verse
.withRoute("network", this.daemonTarget.uri)
.withClaim("commander-control", { shardId: "aetheria.local" });
this.publications = CultMesh.documentsFromPublication(
this.createPublicationSource(publicationMode),
createAetheriaPublicationDocuments(statePath, publicationMode),
{
routeHint: this.queryVerse.context.routeHint,
timeoutMs: options.snapshotTimeoutMs,
pollMs: 50,
messageIdPrefix: `${this.runtimeId}:snapshot`,
},
);
const executors = {
mapViewport: async (request: ViewportRequest) =>
readViewportDocument(await this.fetchViewportDocument(AetheriaRtsSchemas.gameViewport, "aetheria.viewport.map", request)),
objectsViewport: async (request: ViewportRequest) =>
readObjectsViewportDocument(await this.fetchViewportDocument(AetheriaRtsSchemas.objectsViewport, "aetheria.viewport.objects", request)),
gravityViewport: async (request: ViewportRequest) =>
readGravityViewportDocument(await this.fetchViewportDocument(AetheriaRtsSchemas.gravityViewport, "aetheria.viewport.gravity", request)),
renderSplatsViewport: async (request: ViewportRequest) =>
readRenderSplatsViewportDocument(await this.fetchViewportDocument(AetheriaRtsSchemas.renderSplatsViewport, "aetheria.viewport.render_splats", request)),
selectedObject: async (request: SelectedObjectRequest) =>
readSelectedObjectDocument(await this.fetchIndexedDocument(AetheriaRtsSchemas.selectedObject, "aetheria.object.selected", request.entityIndex)),
inventory: async (request: SelectedObjectRequest) =>
readInventoryDocument(await this.fetchIndexedDocument(AetheriaRtsSchemas.inventory, "aetheria.inventory", request.entityIndex)),
daemonHealth: async () => readDaemonHealthDocument(await this.fetchDaemonHealthDocument()),
authorityStatus: async () => readAuthorityStatusDocument(await this.fetchAuthorityPolicyDocument()),
starbridgeSession: async () => readStarbridgeSessionSummaryDocument(await this.fetchStarbridgeSessionSummaryDocument()),
assetManifest: async () => readAssetManifestDocument(await this.fetchAssetManifestDocument()),
};
this.queryExecutors = executors;
this.queries = createAetheriaRuntimeGameQueryHandles(
executors,
this.queryVerse.context.routeHint,
{
objectsViewport: CultMesh.pollingQueryWatcher(executors.objectsViewport, { intervalMs: 50 }),
gravityViewport: CultMesh.pollingQueryWatcher(executors.gravityViewport, { intervalMs: 50 }),
renderSplatsViewport: CultMesh.pollingQueryWatcher(executors.renderSplatsViewport, { intervalMs: 50 }),
selectedObject: CultMesh.pollingQueryWatcher(executors.selectedObject, { intervalMs: 50 }),
inventory: CultMesh.pollingQueryWatcher(executors.inventory, { intervalMs: 50 }),
daemonHealth: CultMesh.pollingQueryWatcher(executors.daemonHealth, { intervalMs: 250 }),
authorityStatus: CultMesh.pollingQueryWatcher(executors.authorityStatus, { intervalMs: 250 }),
starbridgeSession: CultMesh.pollingQueryWatcher(executors.starbridgeSession, { intervalMs: 250 }),
assetManifest: CultMesh.pollingQueryWatcher(executors.assetManifest, { intervalMs: 1000 }),
},
);
this.documents = createAetheriaRuntimeGameDocuments(
this.queryVerse.context.routeHint,
{
daemonFrame: async () => this.fetchLatestFrameDocument(),
daemonHealth: async () => this.fetchDaemonHealthDocument(),
authorityPolicy: async () => this.fetchAuthorityPolicyDocument(),
starbridgeSession: async () => this.fetchStarbridgeSessionSummaryDocument(),
assetManifest: async () => this.fetchAssetManifestDocument(),
},
);
this.operations = createAetheriaRuntimeGameOperationHandles(
(commandId, issuedAtUtc, command, context) =>
this.sendCommandDocument(commandId, issuedAtUtc, command, context),
);
this.aetheria = createAetheriaRuntimeGameVerseHandles(
this.queryVerse.context,
this.commandVerse.context,
this.queries,
this.operations,
this.documents,
);
}
private readonly publicationDescription: string;
private readonly publications: CultMeshDocumentCatalog;
private readonly queryExecutors: AetheriaRuntimeGameQueryExecutors;
private readonly queries: ReturnType<typeof createAetheriaRuntimeGameQueryHandles>;
private readonly documents: AetheriaRuntimeGameDocuments;
private readonly operations: AetheriaRuntimeGameOperationHandles;
private readonly aetheria: AetheriaRuntimeGameVerseHandles;
public async close(): Promise<void> {
this.#peer?.close();
this.#peer = null;
}
public async waitForFrame(timeoutMs: number): Promise<void> {
const started = Date.now();
let lastError = "";
while (Date.now() - started < timeoutMs) {
try {
await this.mapViewport(CultMesh.viewportRequest(CultMesh.rectFromBounds(-1000, -1000, 1000, 1000)));
return;
} catch (error) {
lastError = error instanceof Error ? error.message : String(error);
await delay(250);
}
}
throw new Error(`Timed out waiting for Aetheria CultMesh frame at ${this.daemonTarget.uri}. ${lastError}`);
}
public async mapViewport(request: ViewportRequest): Promise<ViewportResponse> {
return this.aetheria.zone().viewport.within(request);
}
public async objectsViewport(request: ViewportRequest): Promise<ObjectsViewportResponse> {
return this.aetheria.zone().objects.visibleWithin(request);
}
public async gravityViewport(request: ViewportRequest): Promise<GravityViewportResponse> {
return this.aetheria.zone().gravity.within(request);
}
public async renderSplatsViewport(request: ViewportRequest): Promise<RenderSplatsViewportResponse> {
return this.aetheria.zone().renderSplats.within(request);
}
public async selectedObject(request: SelectedObjectRequest): Promise<SelectedObjectDocument> {
return this.aetheria.selectedObject(request.entityIndex);
}
public async inventory(request: SelectedObjectRequest): Promise<InventoryDocument> {
return this.aetheria.inventory(request.entityIndex);
}
public async daemonHealth(): Promise<DaemonHealthDocument> {
return this.aetheria.daemon.health();
}
public async authorityStatus(): Promise<AuthorityStatusDocument> {
return this.aetheria.daemon.authorityStatus();
}
public async starbridgeSession(): Promise<StarbridgeSessionDocument> {
return this.aetheria.daemon.starbridgeSession();
}
public async assetManifest(): Promise<AssetManifestDocument> {
return this.aetheria.daemon.assetManifest();
}
public queryDiagnostics(): Readonly<Record<string, AetheriaRuntimeGameQueryDiagnostic>> {
return describeAetheriaRuntimeGameQueryHandles(this.queries);
}
public liveFeedDiagnostics(): Readonly<Record<string, AetheriaRuntimeGameLiveFeedDiagnostic>> {
return {
viewportFeed: describeAetheriaRuntimeGameLiveFeedSurface(this.createViewportFeed()),
};
}
public surfaceCatalogDiagnostics(): AetheriaRuntimeGameSurfaceCatalogDiagnostic {
const catalog = describeAetheriaRuntimeGameSurfaceCatalog(this.queries, this.operations, this.documents);
return CultMesh.describeSurfaceCatalog(catalog.catalogId, [
...catalog.surfaces,
CultMesh.describeSurface(this.createViewportFeed()),
]);
}
public surfaceCatalogIndexDiagnostics(): CultMeshSurfaceCatalogIndexDiagnostic {
return CultMesh.surfaceCatalogIndex(this.surfaceCatalogDiagnostics());
}
public watchViewportFeed(
request: AetheriaRuntimeViewportFeedRequest,
callback: (snapshot: AetheriaRuntimeViewportFeedSnapshot) => void,
): () => void {
return this.createViewportFeed().watch(request, this.queryContext(), callback);
}
public async setMoveVector(request: RtsSetMoveVectorRequest): Promise<AetheriaRuntimeDaemonCommandReceipt> {
return this.aetheria.entity(request.actorEntityKey).pilot.move(
CultMesh.vec2(request.directionX, request.directionY),
{
scalar: request.scalar,
observedFrameId: request.observedFrameId,
},
);
}
public async setTarget(request: RtsSetTargetRequest): Promise<AetheriaRuntimeDaemonCommandReceipt> {
return this.aetheria.entity(request.actorEntityKey).pilot.target(request.targetEntityKey, {
observedFrameId: request.observedFrameId,
});
}
private async fetchLatestFrameDocument(): Promise<unknown> {
return this.fetchPublicationDocument(AetheriaRtsSchemas.daemonFrame);
}
private async fetchDaemonHealthDocument(): Promise<unknown> {
return this.fetchPublicationDocument(AetheriaRtsSchemas.daemonHealth);
}
private async fetchAuthorityPolicyDocument(): Promise<unknown> {
return this.fetchPublicationDocument(AetheriaRtsSchemas.verseAuthorityPolicy);
}
private async fetchStarbridgeSessionSummaryDocument(): Promise<unknown> {
return this.fetchPublicationDocument(AetheriaRtsSchemas.starbridgeSessionSummary);
}
private async fetchAssetManifestDocument(): Promise<unknown> {
return this.fetchPublicationDocument(AetheriaRtsSchemas.assetManifest);
}
private async fetchViewportDocument(
schemaId: string,
recordPrefix: string,
request: ViewportRequest,
): Promise<unknown> {
const recordKey = managedViewportRecordKey(recordPrefix, request);
const document = CultMesh.documentFromPublication(
{
kind: "peer-snapshot",
peer: () => this.peer(),
endpoint: this.resolvedRudpEndpoint(),
},
schemaId,
recordKey,
{
documentId: recordKey,
routeHint: this.queryVerse.context.routeHint,
sourceId: recordKey,
timeoutMs: 1500,
pollMs: 50,
messageIdPrefix: `${this.runtimeId}:viewport`,
},
);
return retryTransientPublicationRead(() => document.latest(this.queryContext()));
}
private async fetchIndexedDocument(
schemaId: string,
recordPrefix: string,
entityIndex: number,
): Promise<unknown> {
const recordKey = `${recordPrefix}.${Math.trunc(entityIndex)}`;
const document = CultMesh.documentFromPublication(
{
kind: "peer-snapshot",
peer: () => this.peer(),
endpoint: this.resolvedRudpEndpoint(),
},
schemaId,
recordKey,
{
documentId: recordKey,
routeHint: this.queryVerse.context.routeHint,
sourceId: recordKey,
timeoutMs: 1500,
pollMs: 50,
messageIdPrefix: `${this.runtimeId}:indexed-document`,
},
);
return retryTransientPublicationRead(() => document.latest(this.queryContext()));
}
private fetchPublicationDocument(schemaId: string): Promise<unknown> {
return retryTransientPublicationRead(() => this.publications.latest({ schemaId }, this.queryContext()));
}
private createPublicationSource(
mode: "local" | "remote",
): (binding: CultMeshPublicationDocumentBinding) => CultMeshDocumentPublicationSource {
if (mode === "remote") {
return () => ({
kind: "peer-snapshot",
peer: () => this.peer(),
endpoint: this.resolvedRudpEndpoint(),
});
}
return binding => ({
kind: "single-file",
path: (binding as AetheriaPublicationDocumentSpec).localPath,
});
}
private createViewportFeed() {
return CultMesh.liveFeed<AetheriaRuntimeViewportFeedRequest, AetheriaRuntimeViewportFeedSnapshot>(
"gamecult.aetheria.viewport_feed.v1",
async (request, context) => {
const objects = await this.queries.objectsViewport.execute(request.viewport, context);
return this.createViewportFeedSnapshot(request, objects);
},
{
sources: [
...this.queries.objectsViewport.sources,
...this.queries.gravityViewport.sources,
...this.queries.daemonHealth.sources,
...this.queries.authorityStatus.sources,
...this.queries.starbridgeSession.sources,
...this.queries.assetManifest.sources,
],
routeHint: this.queryVerse.context.routeHint,
watchFeed: (request, context, callback) => {
let disposed = false;
let sampling = false;
const unsubscribe = this.queries.objectsViewport.watch(request.viewport, context, objects => {
if (disposed || sampling) {
return;
}
sampling = true;
void this.createViewportFeedSnapshot(request, objects)
.then(snapshot => {
if (!disposed) {
callback(snapshot);
}
})
.finally(() => {
sampling = false;
});
});
return () => {
disposed = true;
unsubscribe();
};
},
},
);
}
private async createViewportFeedSnapshot(
request: AetheriaRuntimeViewportFeedRequest,
objects: ObjectsViewportResponse,
): Promise<AetheriaRuntimeViewportFeedSnapshot> {
const startedAt = performance.now();
const selectedEntityIndex = request.selectedEntityIndex ?? -1;
const [
gravity,
daemonHealth,
authorityStatus,
starbridgeSession,
assetManifest,
selectedObject,
inventory,
] = await Promise.all([
this.queryExecutors.gravityViewport(request.viewport),
this.queryExecutors.daemonHealth(),
this.queryExecutors.authorityStatus(),
this.queryExecutors.starbridgeSession(),
this.queryExecutors.assetManifest(),
selectedEntityIndex >= 0
? this.queryExecutors.selectedObject({ entityIndex: selectedEntityIndex })
: Promise.resolve(null),
selectedEntityIndex >= 0
? this.queryExecutors.inventory({ entityIndex: selectedEntityIndex })
: Promise.resolve(null),
]);
return {
viewport: composeViewport(objects, gravity),
selectedObject,
inventory,
daemonHealth,
authorityStatus,
starbridgeSession,
assetManifest,
receivedAtUtc: new Date().toISOString(),
sampleMs: performance.now() - startedAt,
};
}
private queryContext(): CultMeshQueryContext {
return this.queryVerse.queryContext();
}
private async sendCommandDocument(
commandId: string,
issuedAtUtc: string,
command: unknown[],
context: CultMeshOperationContext,
): Promise<void> {
const message: CultNetDocumentPutRawMessage = {
schemaVersion: "cultnet.document_put_raw.v0",
messageId: commandId,
document: {
schemaId: AetheriaRtsSchemas.daemonCommand,
recordKey: `daemon:commands:${stableToken(commandId)}:${AetheriaRtsSchemas.daemonCommand}`,
storedAt: issuedAtUtc,
payloadEncoding: "messagepack",
payload: encode(command),
sourceRuntimeId: context.runtimeId,
sourceRole: "aetheria-client",
tags: ["aetheria"],
},
};
const peer = await this.peer();
peer.send(message);
await delay(80);
}
private async peer(): Promise<CultNetPeer> {
if (this.#peer)
return this.#peer;
const peers = CultMesh.createPeerCatalog();
const leases = CultMesh.createAuthorityLeaseCatalog();
const leaseId = `${this.daemonTarget.peerId}:authority`;
peers.upsert({
peerId: this.daemonTarget.peerId,
verseId: this.daemonTarget.verseId,
endpoints: this.daemonTarget.endpoints,
roles: [this.daemonTarget.role],
authorityLeaseId: leaseId,
});
leases.upsert({
leaseId,
verseId: this.daemonTarget.verseId,
peerId: this.daemonTarget.peerId,
roles: [this.daemonTarget.role],
validFrom: new Date(Date.now() - 60_000),
expiresAt: new Date(Date.now() + 60_000),
});
this.#peer = await CultMesh.createRudpPeerForAuthorizedPeer(
this.runtimeId,
connectionId,
peers,
leases,
this.daemonTarget.verseId,
this.daemonTarget.role,
{
connectTimeoutMs: 2000,
maxFragmentBytes: 1200,
maxPendingReliablePackets: 512,
},
);
this.#peer.on("close", () => {
this.#peer = null;
});
return this.#peer;
}
private resolvedRudpEndpoint(): string {
const endpoint = this.daemonTarget.endpoints.find(value => value.toLowerCase().startsWith("rudp://"));
if (!endpoint) {
throw new Error(`Daemon ${this.daemonTarget.uri} has no resolved RUDP transport endpoint. Resolve it through Odin/CultMesh before opening a transport peer.`);
}
return endpoint;
}
}
function normalizeDaemonTarget(target: string | AetheriaCultMeshDaemonTarget): Required<AetheriaCultMeshDaemonTarget> {
const value = typeof target === "string"
? { uri: target }
: target;
if (!value.uri.trim()) {
throw new Error("Aetheria CultMesh daemon target URI is required.");
}
if (value.uri.toLowerCase().startsWith("rudp://")) {
throw new Error("Aetheria daemon targets must be CultMesh URIs; raw RUDP endpoints belong in resolved peer-card endpoints.");
}
return {
uri: value.uri,
peerId: value.peerId?.trim() || "aetheria-daemon",
verseId: value.verseId?.trim() || "aetheria.local",
role: value.role?.trim() || "aetheria-daemon",
endpoints: value.endpoints ?? [],
};
}
function managedViewportRecordKey(prefix: string, request: ViewportRequest): string {
const minX = Math.min(finiteNumber(request.minX), finiteNumber(request.maxX));
const minY = Math.min(finiteNumber(request.minY), finiteNumber(request.maxY));
const maxX = Math.max(finiteNumber(request.minX), finiteNumber(request.maxX));
const maxY = Math.max(finiteNumber(request.minY), finiteNumber(request.maxY));
return `${prefix}.${viewportToken(minX)}.${viewportToken(minY)}.${viewportToken(maxX)}.${viewportToken(maxY)}`;
}
function viewportToken(value: number): string {
const rounded = Math.round(value * 1000) / 1000;
return rounded
.toString()
.replace("-", "n")
.replace(".", "p");
}
function finiteNumber(value: unknown): number {
return typeof value === "number" && Number.isFinite(value) ? value : 0;
}
async function retryTransientPublicationRead<T>(read: () => Promise<T>): Promise<T> {
let lastError: unknown;
for (let attempt = 0; attempt < 40; attempt += 1) {
try {
return await read();
} catch (error) {
lastError = error;
if (!isTransientPublicationReadError(error))
throw error;
await delay(25 + attempt * 8);
}
}
throw lastError;
}
function isTransientPublicationReadError(error: unknown): boolean {
const message = error instanceof Error ? error.message : String(error);
return message.includes("EBUSY") ||
message.includes("EPERM") ||
message.includes("ENOENT") ||
message.includes("did not contain schema");
}
function stableToken(value: string): string {
return value
.replace(/[^a-zA-Z0-9]+/gu, "-")
.replace(/^-+|-+$/gu, "")
.replace(/--+/gu, "-")
.toLowerCase() || "empty";
}
function composeViewport(
objects: ObjectsViewportResponse,
gravity: GravityViewportResponse,
): ViewportResponse {
return {
schema: "gamecult.aetheria.game_viewport.v1",
frameId: objects.frameId,
publishedAtUtc: objects.publishedAtUtc,
simulationTimeSeconds: objects.simulationTimeSeconds,
runId: objects.runId,
zoneIndex: objects.zoneIndex,
zoneName: objects.zoneName,
currentEntityKey: objects.currentEntityKey,
viewport: objects.viewport,
controlledEntityIndices: objects.controlledEntityIndices,
objects: objects.objects,
gravityInfluences: gravity.gravityInfluences,
bodies: gravity.bodies,
};
}
function createAetheriaPublicationDocuments(
statePath: string,
mode: "local" | "remote",
): readonly AetheriaPublicationDocumentSpec[] {
const documents: readonly AetheriaPublicationDocumentSpec[] = [
{
...CultMesh.publicationDocument(
AetheriaRtsSchemas.daemonFrame,
"daemon:aetheria.frame.latest.v1",
{
documentId: "daemon:aetheria.frame.latest.v1",
sourceId: "daemon:aetheria.frame.latest.v1",
},
),
localPath: statePath,
},
{
...CultMesh.publicationDocument(
AetheriaRtsSchemas.daemonHealth,
"daemon:aetheria.health.latest.v1",
{
documentId: "daemon:aetheria.health.latest.v1",
sourceId: "daemon:aetheria.health.latest.v1",
},
),
localPath: statePath,
remoteRecordKey: "daemon:aetheria.health.v1",
},
{
...CultMesh.publicationDocument(
AetheriaRtsSchemas.verseAuthorityPolicy,
"daemon:aetheria.authority.policy.latest.v1",
{
documentId: "daemon:aetheria.authority.policy.latest.v1",
sourceId: "daemon:aetheria.authority.policy.latest.v1",
},
),
localPath: statePath,
remoteRecordKey: "global:aetheria.verse_authority_policy.v1",
},
{
...CultMesh.publicationDocument(
AetheriaRtsSchemas.starbridgeSessionSummary,
"daemon:aetheria.starbridge.session.latest.v1",
{
documentId: "daemon:aetheria.starbridge.session.latest.v1",
sourceId: "daemon:aetheria.starbridge.session.latest.v1",
},
),
localPath: statePath,
},
{
...CultMesh.publicationDocument(
AetheriaRtsSchemas.assetManifest,
"daemon:aetheria.asset_manifest.latest.v1",
{
documentId: "daemon:aetheria.asset_manifest.latest.v1",
sourceId: "daemon:aetheria.asset_manifest.latest.v1",
},
),
localPath: statePath,
},
];
return documents.map(document => mode === "remote" && document.remoteRecordKey
? {
...document,
recordKey: document.remoteRecordKey,
}
: document);
}
function readField(value: unknown, property: string, index: number): unknown {
if (Array.isArray(value))
return value[index];
if (value && typeof value === "object") {
const record = value as Record<string, unknown>;
if (property in record)
return record[property];
const pascal = property.charAt(0).toUpperCase() + property.slice(1);
if (pascal in record)
return record[pascal];
}
return undefined;
}
function arrayValue(value: unknown): unknown[] {
return Array.isArray(value) ? value : [];
}
function normalizeCommandPayload(payload: Record<string, unknown> | undefined): Record<string, string> {
const result: Record<string, string> = {};
for (const [key, value] of Object.entries(payload ?? {})) {
if (value == null)
continue;
result[key] = typeof value === "string" ? value : String(value);
}
return result;
}
function objectValue(value: unknown): Record<string, unknown> {
return value && typeof value === "object" && !Array.isArray(value)
? value as Record<string, unknown>
: {};
}
function stringOr(value: unknown, fallback: string): string {
return typeof value === "string" ? value : fallback;
}
function numberOr(value: unknown, fallback: number): number {
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
}
function stringRecord(value: unknown): Record<string, string> {
const source = objectValue(value);
const result: Record<string, string> = {};
for (const [key, entry] of Object.entries(source)) {
if (entry == null)
continue;
result[key] = typeof entry === "string" ? entry : String(entry);
}
return result;
}
function delay(milliseconds: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}