Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 5m49s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 36s
Unscoped npm names are unclaimed and open to dependency confusion; cultcache-ts was already @gamecult/cultcache-ts. package.json names, intra-repo dependencies, package-lock, import specifiers (src, tests, samples, docs/start, first-call docs test), the workspace list in run-typescript-workspaces, the verify-eve module map and package READMEs now use the scoped names. Directory names, workspace paths in CI and release tag prefixes are unchanged. Historical cut docs and past CHANGELOG entries keep the old names. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
28 lines
1.6 KiB
TypeScript
28 lines
1.6 KiB
TypeScript
import { CultMeshBrowserClient, CultMeshBrowserOdinRendezvous, decodeCultNetOperationPayload, decodeCultNetPayload } from "@gamecult/cultmesh-browser";
|
|
import { arenaDocument, arenaKey, authorityRuntimeId, verseId, type ArenaState } from "./schema.ts";
|
|
|
|
// Runs unchanged in a browser or in Node 22+: both have a global WebSocket.
|
|
export async function joinArena(odinUrl: string, runtimeId: string, onState: (state: ArenaState, myId: string) => void) {
|
|
const rendezvous = new CultMeshBrowserOdinRendezvous({ endpoints: [odinUrl], runtimeId: `${runtimeId}.discovery` });
|
|
const mesh = await CultMeshBrowserClient.connect({
|
|
verseId, authorityRuntimeId, runtimeId, rendezvous,
|
|
trust: { mode: "local-development" }, // loopback only; remote Verses need Odin roots
|
|
});
|
|
let latest: ArenaState | undefined; // CultCache itself pulls in Node built-ins, so the browser client keeps the decoded document
|
|
const call = async (operation: string, payload: object) =>
|
|
decodeCultNetOperationPayload<{ id?: string }>(await mesh.invoke({ serviceId: "io.arena", operation, payloadSchema: "io.request.v1", payload }));
|
|
|
|
const lease = await mesh.leaseRawDocument({ schemaId: arenaDocument.schemaId, recordKey: arenaKey });
|
|
const { id } = await call("join", {});
|
|
lease.watch(record => {
|
|
if (!record) return;
|
|
latest = decodeCultNetPayload(record, arenaDocument);
|
|
onState(latest, id!);
|
|
});
|
|
return {
|
|
id: id!,
|
|
move: (dx: number, dy: number) => call("move", { id, dx, dy }),
|
|
state: () => latest,
|
|
leave: async () => { await call("leave", { id }); lease.dispose(); await mesh.dispose(); },
|
|
};
|
|
}
|