Add TS CultMesh catalog factories

This commit is contained in:
Meta Vens 2026-06-16 16:18:08 +01:00
commit da48d58df7
5 changed files with 126 additions and 2 deletions

View file

@ -312,7 +312,11 @@ Current progress:
ergonomics as the other runtimes: sorted local views, direct `get(...)`
lookup, unsubscribe-able `watch(...)` callbacks for Verse and peer catalogs,
watch callbacks for authority leases and stream declarations/frame cursors,
plus lease listing and lookup beside the authority check.
plus lease listing and lookup beside the authority check. The branded
`CultMesh` facade also creates schema catalogs, built-in schema catalogs, and
shard catalogs by delegating to the existing `cultnet-ts` owners, so callers
do not have to leave the CultMesh entrypoint for schema discovery or shard
topology.
- TypeScript now also has a `CultNetSchemaCatalog` for remote schema
descriptors plus `CultNetPeer` request/fetch/sync helpers for
`cultnet.schema_catalog_request.v0` / `cultnet.schema_catalog_response.v0`.

View file

@ -32,7 +32,7 @@ CultMesh.
| --- | --- | --- | --- |
| C# | Reference implementation and production game/server substrate | CultCache typed documents and SoA, CultNet schema-v0, LiteNetLib production path with adapter profile, shared transport profiles, shared RUDP socket transport, RUDP reconnect policy/controller and reconnect-loop helper, LiteNetLib client reconnect-controller adoption, schema-client transport port for service request/response clients, CultMesh node/session/catalog/stream/simulation surfaces | No need to abandon LiteNetLib before the CultNet adapter fully owns production service adoption |
| Python | Package runtime, local daemon endpoint, raw interop peer, typed state participant | CultCache/CultNet/CultMesh package surface, schema catalogs, shard catalogs/logs, schema-transport factory for raw client request/subscription flows, local TCP CultMesh server, session/prediction/simulation fact helpers, authority leases, streams, RUDP codec/session/socket transport, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence, benchmark evidence against C# cache paths | Universal C# throughput, full C# daemon/server stack, and RUDP as the only public service pipe |
| TypeScript | Node/browser-adjacent projection and interop runtime | CultCache parity tests, CultNet schema-v0 peer, advertised schema/shard catalog wire contracts plus request/sync helpers, transport profiles, TCP-framed transport port and peer helper, shared RUDP socket transport, RUDP reconnect policy/controller, RUDP reconnect-loop helper, local CultMesh node/catalog/authority/stream ergonomics | Full C# game session/server stack |
| TypeScript | Node/browser-adjacent projection and interop runtime | CultCache parity tests, CultNet schema-v0 peer, advertised schema/shard catalog wire contracts plus request/sync helpers, transport profiles, TCP-framed transport port and peer helper, shared RUDP socket transport, RUDP reconnect policy/controller, RUDP reconnect-loop helper, branded CultMesh node/schema/shard/Verse/peer/authority/stream ergonomics | Full C# game session/server stack |
| Rust | Low-level cache/transport/runtime substrate | CultCache/CultNet interop lane, schema and shard catalog helpers, transport profiles, TCP-framed port, shared RUDP codec/session/socket transport, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence, small CultMesh facade for peer cards, authority leases, RUDP endpoint parsing, and peer-card RUDP client construction | Full CultMesh game-session/server facade, stream catalog, or production game-session server |
| Kotlin | JVM/Android client substrate | Typed MessagePack cache, built-in schema catalog advertisement, schema/shard catalogs with shared schema-message transport fetch/sync helpers, authority leases, stream catalog, branded `CultMesh` facade, WebSocket transport profile/connection helper, RUDP client/server sugar, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence | C# SoA store, full C# server daemon, or Unity hot-loop memory layout |

View file

@ -46,8 +46,29 @@ leases.upsert({
expiresAt: new Date(Date.now() + 60_000),
});
stopWatchingLeases();
const schemas = CultMesh.createBuiltInSchemaCatalog();
const shardCatalogRequest = schemas.get("cultnet.shard_catalog_request.v0");
const shards = CultMesh.createShardCatalog();
shards.upsert({
shardId: "notes-a",
ownerRuntimeId: "ts-peer",
epoch: 1,
schemaIds: ["cultmesh.note.v0"],
keyPrefix: "note:",
});
const noteShards = shards.list({
schemaIds: ["cultmesh.note.v0"],
recordKeys: ["note:intro"],
});
```
Schema and shard catalog factories delegate to `cultnet-ts`; the branded
`CultMesh` entrypoint does not create a second owner for schema discovery or
topology truth.
## Streaming Mode
CultMesh streaming mode is for audio, video, tensor, and opaque byte frames that

View file

@ -7,8 +7,12 @@ import {
} from "cultcache-ts";
import {
CultNetDocumentRegistry,
CultNetSchemaCatalog,
CultNetShardCatalog,
cultNetBuiltinSchemaRegistry,
defineCultNetDocumentBinding,
type CultNetDocumentBinding,
type CultNetSchemaCatalogOptions,
} from "cultnet-ts";
export interface CultMeshNodeOptions {
@ -470,6 +474,28 @@ export class CultMesh {
public static createStreamCatalog(): CultMeshStreamCatalog {
return new CultMeshStreamCatalog();
}
public static createSchemaCatalog(): CultNetSchemaCatalog {
return new CultNetSchemaCatalog();
}
public static createBuiltInSchemaCatalog(
options: CultNetSchemaCatalogOptions = {},
): CultNetSchemaCatalog {
const catalog = new CultNetSchemaCatalog();
catalog.applyResponse(cultNetBuiltinSchemaRegistry.createCatalogResponse({
schemaVersion: "cultnet.schema_catalog_request.v0",
messageId: "cultmesh-ts-builtins",
includeSchemaJson: options.includeSchemaJson,
schemaIds: options.schemaIds ? [...options.schemaIds] : undefined,
kinds: options.kinds ? [...options.kinds] : undefined,
}));
return catalog;
}
public static createShardCatalog(): CultNetShardCatalog {
return new CultNetShardCatalog();
}
}
function requireNonEmpty(value: string, name: string): void {

View file

@ -115,6 +115,79 @@ test("CultMesh TS local Verse catalog exposes sorted views and watch ergonomics"
);
});
test("CultMesh TS branded facade exposes schema and shard catalogs", () => {
const schemaCatalog = CultMesh.createSchemaCatalog();
const schemaUpdates: string[] = [];
const unsubscribeSchema = schemaCatalog.watch((descriptor) => {
schemaUpdates.push(descriptor.schemaId);
});
schemaCatalog.upsert({
schemaId: "cultmesh.ts.note.v1",
kind: "document_payload",
documentType: "cultmesh.ts-note",
wireContracts: ["cultnet.schema.v0"],
contentHash: "note-hash",
});
unsubscribeSchema();
schemaCatalog.upsert({
schemaId: "cultmesh.ts.other.v1",
kind: "document_payload",
documentType: "cultmesh.ts-other",
wireContracts: ["cultnet.schema.v0"],
contentHash: "other-hash",
});
assert.deepEqual(schemaUpdates, ["cultmesh.ts.note.v1"]);
assert.equal(
schemaCatalog.get("cultmesh.ts.note.v1")?.documentType,
"cultmesh.ts-note",
);
const builtIns = CultMesh.createBuiltInSchemaCatalog();
assert.equal(
builtIns.get("cultnet.shard_catalog_request.v0")?.schemaVersion,
"cultnet.shard_catalog_request.v0",
);
assert.equal(
builtIns.get("cultnet.shard_catalog_response.v0")?.kind,
"wire_message",
);
assert.equal(
builtIns.get(
"https://github.com/GameCult/cultnet-ts/contracts/cultnet.transport-profile.schema.json",
)?.schemaVersion,
"cultnet.transport_profile.v0",
);
const shardCatalog = CultMesh.createShardCatalog();
const shardUpdates: string[] = [];
const unsubscribeShard = shardCatalog.watch((descriptor) => {
shardUpdates.push(descriptor.shardId);
});
shardCatalog.upsert({
shardId: "notes-a",
ownerRuntimeId: "ts-runtime",
epoch: 7,
schemaIds: ["cultmesh.ts.note.v1"],
keyPrefix: "note:",
});
unsubscribeShard();
shardCatalog.upsert({
shardId: "notes-b",
ownerRuntimeId: "ts-runtime",
epoch: 8,
});
assert.deepEqual(shardUpdates, ["notes-a"]);
assert.equal(shardCatalog.get("notes-a")?.ownerRuntimeId, "ts-runtime");
assert.deepEqual(
shardCatalog
.list({ schemaIds: ["cultmesh.ts.note.v1"], recordKeys: ["note:1"] })
.map((shard) => shard.shardId),
["notes-a"],
);
});
test("CultMesh TS negotiates streaming frame body transports explicitly", () => {
const streams = CultMesh.createStreamCatalog();
const streamUpdates: string[] = [];