From 286a9af38969708c5e0e1e41dafbfbd90bd91de4 Mon Sep 17 00:00:00 2001 From: Libby Date: Sat, 7 Nov 2026 16:25:10 +0000 Subject: [PATCH] npm: scope cultnet-ts, cultmesh-ts and cultmesh-browser under @gamecult 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 --- docs/start/README.md | 4 +-- docs/start/io-game.md | 10 +++--- docs/start/io-game/client.ts | 2 +- docs/start/io-game/server.ts | 4 +-- package-lock.json | 33 ++++++++++--------- packages/cultmesh-browser/CHANGELOG.md | 8 ++++- packages/cultmesh-browser/README.md | 4 +-- packages/cultmesh-browser/package.json | 6 ++-- packages/cultmesh-browser/src/content.ts | 4 +-- packages/cultmesh-browser/src/index.ts | 6 ++-- .../cultmesh-browser/test/content.test.ts | 2 +- .../test/cultmesh-browser.test.ts | 4 +-- .../test/interop/content-https-provider.ts | 4 +-- .../test/interop/content-https-reader.ts | 2 +- .../test/interop/content-https.test.ts | 2 +- .../test/payload-type.test.ts | 4 +-- packages/cultmesh-py/README.md | 2 +- packages/cultmesh-ts/CHANGELOG.md | 3 +- packages/cultmesh-ts/README.md | 18 +++++----- packages/cultmesh-ts/package.json | 4 +-- packages/cultmesh-ts/src/content.ts | 2 +- packages/cultmesh-ts/src/index.ts | 4 +-- .../src/provider-rudp-transport.ts | 4 +-- .../src/provider-session-broker.ts | 4 +-- .../cultmesh-ts/src/provider-session-wire.ts | 4 +-- packages/cultmesh-ts/src/realtime-quic.ts | 4 +-- packages/cultmesh-ts/src/realtime-wire.ts | 4 +-- .../cultmesh-ts/test/codec-documents.test.ts | 2 +- packages/cultmesh-ts/test/content.test.ts | 2 +- packages/cultmesh-ts/test/cultmesh.test.ts | 4 +-- .../test/interop/cultmesh-quic-peer.ts | 4 +-- .../cultmesh-ts/test/payload-type.test.ts | 4 +-- .../test/provider-rudp-transport.test.ts | 4 +-- .../test/provider-session-wire.test.ts | 2 +- .../test/realtime-quic-consumer.test.ts | 4 +-- .../realtime-quic-session-manager.test.ts | 4 +-- .../rudp-document-server-send-failure.test.ts | 4 +-- packages/cultnet-py/README.md | 2 +- packages/cultnet-rs/README.md | 4 +-- packages/cultnet-ts/CHANGELOG.md | 3 +- packages/cultnet-ts/README.md | 18 +++++----- packages/cultnet-ts/package.json | 2 +- packages/cultnet-ts/src/cultmesh-authority.ts | 4 +-- packages/cultnet-ts/test/first-call.test.ts | 4 +-- .../test/idunn-runtime-authority.test.ts | 6 ++-- samples/eve-browser-network/README.md | 2 +- samples/eve-browser-network/browser/main.ts | 2 +- samples/eve-two-runtime/sample.mjs | 2 +- scripts/run-typescript-workspaces.mjs | 2 +- scripts/test-typescript-package-closure.mjs | 14 ++++---- scripts/verify-eve-browser-network.mjs | 4 +-- .../docs/browser-verse-transport.md | 12 +++---- .../03-publish-an-eve-surface.md | 2 +- .../docs/reliability-migration-plan.md | 2 +- src/GameCult.Networking/README.md | 2 +- 55 files changed, 142 insertions(+), 131 deletions(-) diff --git a/docs/start/README.md b/docs/start/README.md index 42adc5d9..e033c935 100644 --- a/docs/start/README.md +++ b/docs/start/README.md @@ -284,7 +284,7 @@ public static class CultNetFirstCall Source: [`packages/cultnet-ts/test/first-call.test.ts`](../../packages/cultnet-ts/test/first-call.test.ts), run by `npm test` in `packages/cultnet-ts` (build `packages/cultcache-ts` first: `npm run build` there). The test imports -from `../src` where the block reads `cultnet-ts`. More: `packages/cultnet-ts/README.md`. +from `../src` where the block reads `@gamecult/cultnet-ts`. More: `packages/cultnet-ts/README.md`. ```ts import { createServer, connect } from "node:net"; @@ -294,7 +294,7 @@ import { CultNetDocumentRegistry, createTcpFramedCultNetPeer, defineCultNetDocumentBinding, -} from "cultnet-ts"; +} from "@gamecult/cultnet-ts"; const noteDocument = defineDocumentType({ type: "note", diff --git a/docs/start/io-game.md b/docs/start/io-game.md index 4781d9bf..e7f701a7 100644 --- a/docs/start/io-game.md +++ b/docs/start/io-game.md @@ -9,7 +9,7 @@ leave because both lease the same document. | Piece | Status | | --- | --- | -| Two clients, real WebSockets, real `cultmesh-browser` client, one arena: join, see each other, move, leave | **tested** (`arena.test.ts`) | +| Two clients, real WebSockets, real `@gamecult/cultmesh-browser` client, one arena: join, see each other, move, leave | **tested** (`arena.test.ts`) | | Edge clamp, and the source below matching the files that ran | **tested** | | Browser bundle builds and the page is served | **tested** (HTTP fetch only) | | The page running in a real browser, two windows | **not yet**: no browser on the host that built this recipe | @@ -19,7 +19,7 @@ leave because both lease the same document. | Dropped players: a closed tab that never sent `leave` stays in the arena | **not yet**: operations do not carry a connection identity to the authority | | `CultCache` in the browser | **not yet**: the `@gamecult/cultcache-ts` entry imports Node built-ins, so the client keeps the decoded document in a variable and only `./document` is imported | -No `cultmesh-ts` or `cultnet-ts` TypeScript authority server exists. The server below is the CultNet +No `@gamecult/cultmesh-ts` or `@gamecult/cultnet-ts` TypeScript authority server exists. The server below is the CultNet message handling a provider owes, written in this recipe with the `ws` package. ## Run it @@ -61,8 +61,8 @@ export const arenaSize = 100; import { createServer, type RequestListener, type Server } from "node:http"; import { CultCache } from "@gamecult/cultcache-ts"; import { defineDocumentRegistry } from "@gamecult/cultcache-ts/document"; -import { decodeWireValue, encodeWireValue } from "cultnet-ts/wire"; -import { encodeCultNetMessageForWire, parseCultNetMessage, type CultNetMessage } from "cultnet-ts/contracts"; +import { decodeWireValue, encodeWireValue } from "@gamecult/cultnet-ts/wire"; +import { encodeCultNetMessageForWire, parseCultNetMessage, type CultNetMessage } from "@gamecult/cultnet-ts/contracts"; import { WebSocketServer, type WebSocket } from "ws"; import { arenaDocument, arenaKey, arenaSize, authorityRuntimeId, verseId, type ArenaState } from "./schema.ts"; @@ -163,7 +163,7 @@ export async function startArena(port = 0, host = "127.0.0.1", onRequest?: Reque ## client.ts ```ts -import { CultMeshBrowserClient, CultMeshBrowserOdinRendezvous, decodeCultNetOperationPayload, decodeCultNetPayload } from "cultmesh-browser"; +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. diff --git a/docs/start/io-game/client.ts b/docs/start/io-game/client.ts index 8493e23c..10c4b4cd 100644 --- a/docs/start/io-game/client.ts +++ b/docs/start/io-game/client.ts @@ -1,4 +1,4 @@ -import { CultMeshBrowserClient, CultMeshBrowserOdinRendezvous, decodeCultNetOperationPayload, decodeCultNetPayload } from "cultmesh-browser"; +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. diff --git a/docs/start/io-game/server.ts b/docs/start/io-game/server.ts index 39a1a618..7ef552b9 100644 --- a/docs/start/io-game/server.ts +++ b/docs/start/io-game/server.ts @@ -1,8 +1,8 @@ import { createServer, type RequestListener, type Server } from "node:http"; import { CultCache } from "@gamecult/cultcache-ts"; import { defineDocumentRegistry } from "@gamecult/cultcache-ts/document"; -import { decodeWireValue, encodeWireValue } from "cultnet-ts/wire"; -import { encodeCultNetMessageForWire, parseCultNetMessage, type CultNetMessage } from "cultnet-ts/contracts"; +import { decodeWireValue, encodeWireValue } from "@gamecult/cultnet-ts/wire"; +import { encodeCultNetMessageForWire, parseCultNetMessage, type CultNetMessage } from "@gamecult/cultnet-ts/contracts"; import { WebSocketServer, type WebSocket } from "ws"; import { arenaDocument, arenaKey, arenaSize, authorityRuntimeId, verseId, type ArenaState } from "./schema.ts"; diff --git a/package-lock.json b/package-lock.json index 9100d8db..abc8f6d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -482,6 +482,18 @@ "resolved": "packages/cultcache-ts", "link": true }, + "node_modules/@gamecult/cultmesh-browser": { + "resolved": "packages/cultmesh-browser", + "link": true + }, + "node_modules/@gamecult/cultmesh-ts": { + "resolved": "packages/cultmesh-ts", + "link": true + }, + "node_modules/@gamecult/cultnet-ts": { + "resolved": "packages/cultnet-ts", + "link": true + }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", @@ -865,18 +877,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/cultmesh-browser": { - "resolved": "packages/cultmesh-browser", - "link": true - }, - "node_modules/cultmesh-ts": { - "resolved": "packages/cultmesh-ts", - "link": true - }, - "node_modules/cultnet-ts": { - "resolved": "packages/cultnet-ts", - "link": true - }, "node_modules/esbuild": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", @@ -1200,15 +1200,16 @@ } }, "packages/cultmesh-browser": { + "name": "@gamecult/cultmesh-browser", "version": "0.4.0", "license": "MIT", "dependencies": { "@gamecult/cultcache-ts": "^0.14.0", - "cultnet-ts": "^0.3.0" + "@gamecult/cultnet-ts": "^0.3.0" }, "devDependencies": { + "@gamecult/cultmesh-ts": "^0.2.0", "@types/node": "^24.0.0", - "cultmesh-ts": "^0.2.0", "typescript": "^5.9.0" }, "engines": { @@ -1216,11 +1217,12 @@ } }, "packages/cultmesh-ts": { + "name": "@gamecult/cultmesh-ts", "version": "0.2.0", "license": "MIT", "dependencies": { "@gamecult/cultcache-ts": "^0.14.0", - "cultnet-ts": "^0.3.0", + "@gamecult/cultnet-ts": "^0.3.0", "koffi": "3.3.0" }, "devDependencies": { @@ -1233,6 +1235,7 @@ } }, "packages/cultnet-ts": { + "name": "@gamecult/cultnet-ts", "version": "0.3.0", "license": "MIT", "dependencies": { diff --git a/packages/cultmesh-browser/CHANGELOG.md b/packages/cultmesh-browser/CHANGELOG.md index 0093ccf0..ccda16a0 100644 --- a/packages/cultmesh-browser/CHANGELOG.md +++ b/packages/cultmesh-browser/CHANGELOG.md @@ -1,8 +1,14 @@ # Changelog -All notable changes to `cultmesh-browser` are recorded here, following +All notable changes to `@gamecult/cultmesh-browser` are recorded here, following [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## Unreleased + +### Breaking + +- The package is renamed `cultmesh-browser` to `@gamecult/cultmesh-browser` (the repo already scopes `@gamecult/cultcache-ts`), so the unscoped name cannot be claimed by someone else. Import from `@gamecult/cultmesh-browser` and its subpaths; the API is unchanged. Depends on `@gamecult/cultnet-ts`; the interop test uses `@gamecult/cultmesh-ts`. + ## [0.4.0] ### Added diff --git a/packages/cultmesh-browser/README.md b/packages/cultmesh-browser/README.md index ab29d65f..500b858b 100644 --- a/packages/cultmesh-browser/README.md +++ b/packages/cultmesh-browser/README.md @@ -1,6 +1,6 @@ # CultMesh Browser -`cultmesh-browser` is the browser-safe CultMesh client boundary. It owns one +`@gamecult/cultmesh-browser` is the browser-safe CultMesh client boundary. It owns one WebSocket session for a stable Verse/authority-runtime target, retains explicit raw document leases across route replacement, and correlates typed CultNet operations with provider receipts. @@ -95,7 +95,7 @@ WebCrypto `crypto.subtle`; without WebCrypto it fails with endpoint CultMesh resolved is the only host the reader trusts. ```ts -import { fetchVerifiedContent } from "cultmesh-browser"; +import { fetchVerifiedContent } from "@gamecult/cultmesh-browser"; const bytes = await fetchVerifiedContent(endpoint, manifest, { signal: AbortSignal.timeout(30_000), diff --git a/packages/cultmesh-browser/package.json b/packages/cultmesh-browser/package.json index 6d52c9bf..480fb07e 100644 --- a/packages/cultmesh-browser/package.json +++ b/packages/cultmesh-browser/package.json @@ -1,5 +1,5 @@ { - "name": "cultmesh-browser", + "name": "@gamecult/cultmesh-browser", "version": "0.4.0", "description": "Browser-safe CultMesh document leases and typed operations over CultNet WebSocket transport.", "type": "module", @@ -42,11 +42,11 @@ }, "dependencies": { "@gamecult/cultcache-ts": "^0.14.0", - "cultnet-ts": "^0.3.0" + "@gamecult/cultnet-ts": "^0.3.0" }, "devDependencies": { "@types/node": "^24.0.0", - "cultmesh-ts": "^0.2.0", + "@gamecult/cultmesh-ts": "^0.2.0", "typescript": "^5.9.0" } } diff --git a/packages/cultmesh-browser/src/content.ts b/packages/cultmesh-browser/src/content.ts index d9e09b4f..c41fc904 100644 --- a/packages/cultmesh-browser/src/content.ts +++ b/packages/cultmesh-browser/src/content.ts @@ -3,8 +3,8 @@ // The response's declared length and coding are never consulted (Fetch decodes codings; the bytes received are the evidence). // Hashing, hex rules, record keys, the loopback rule and manifest validation belong to cultnet-ts and are only called here. -import { EMPTY_SHA256, chunkRecordKey, parseSha256Hex, sha256Hex, validateManifest, type CultMeshCdnArtifactManifest } from "cultnet-ts/content"; -import { isLoopbackEndpoint } from "cultnet-ts/authority"; +import { EMPTY_SHA256, chunkRecordKey, parseSha256Hex, sha256Hex, validateManifest, type CultMeshCdnArtifactManifest } from "@gamecult/cultnet-ts/content"; +import { isLoopbackEndpoint } from "@gamecult/cultnet-ts/authority"; export type CultMeshContentErrorCode = | "manifest-invalid" | "too-large" | "insecure-endpoint" | "webcrypto-unavailable" | "network" diff --git a/packages/cultmesh-browser/src/index.ts b/packages/cultmesh-browser/src/index.ts index beae9e36..3852615e 100644 --- a/packages/cultmesh-browser/src/index.ts +++ b/packages/cultmesh-browser/src/index.ts @@ -1,6 +1,6 @@ import { decodeDocumentPayload } from "@gamecult/cultcache-ts/document"; import type { AnyCultCacheDocumentDefinition, CultCacheDocumentValue } from "@gamecult/cultcache-ts"; -import { decodeWireValue, encodeWireValue } from "cultnet-ts/wire"; +import { decodeWireValue, encodeWireValue } from "@gamecult/cultnet-ts/wire"; import { encodeCultNetMessageForWire, parseCultNetMessage, @@ -16,7 +16,7 @@ import { type CultMeshVerseCatalogResponseMessage, type CultMeshSessionAcceptedMessage, type CultMeshSessionOpenMessage, -} from "cultnet-ts/contracts"; +} from "@gamecult/cultnet-ts/contracts"; import { base64ToBytes, bytesToBase64, @@ -31,7 +31,7 @@ import { type CultMeshAuthorityTrustMode, type CultMeshAuthorityTrustPolicy, type CultMeshP256PublicKey, -} from "cultnet-ts/authority"; +} from "@gamecult/cultnet-ts/authority"; export * from "./content.js"; export type CultMeshBrowserIdentity = CultMeshAuthorityIdentity; diff --git a/packages/cultmesh-browser/test/content.test.ts b/packages/cultmesh-browser/test/content.test.ts index cc0bb322..d4ec4d6e 100644 --- a/packages/cultmesh-browser/test/content.test.ts +++ b/packages/cultmesh-browser/test/content.test.ts @@ -11,7 +11,7 @@ import { gzipSync } from "node:zlib"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { build } from "esbuild"; -import { EMPTY_SHA256, packContent, sha256Hex, type CultMeshCdnArtifactManifest } from "cultnet-ts/content"; +import { EMPTY_SHA256, packContent, sha256Hex, type CultMeshCdnArtifactManifest } from "@gamecult/cultnet-ts/content"; import { CultMeshContentError, fetchVerifiedChunk, fetchVerifiedContent, type CultMeshContentErrorCode } from "../src/content.js"; diff --git a/packages/cultmesh-browser/test/cultmesh-browser.test.ts b/packages/cultmesh-browser/test/cultmesh-browser.test.ts index 1206b32d..17ffbc02 100644 --- a/packages/cultmesh-browser/test/cultmesh-browser.test.ts +++ b/packages/cultmesh-browser/test/cultmesh-browser.test.ts @@ -2,7 +2,7 @@ import assert from "node:assert/strict"; import test from "node:test"; import { codecs, defineDocumentType, documentPayloadFromBytes } from "@gamecult/cultcache-ts"; -import { decodeWireValue, encodeWireValue } from "cultnet-ts/wire"; +import { decodeWireValue, encodeWireValue } from "@gamecult/cultnet-ts/wire"; import { encodeCultNetMessageForWire, parseCultNetMessage, @@ -12,7 +12,7 @@ import { type CultNetRawDocumentRecord, type CultMeshVerseCatalogResponseMessage, type CultMeshSessionOpenMessage, -} from "cultnet-ts/contracts"; +} from "@gamecult/cultnet-ts/contracts"; import { CultMeshBrowserClient, diff --git a/packages/cultmesh-browser/test/interop/content-https-provider.ts b/packages/cultmesh-browser/test/interop/content-https-provider.ts index 50b5f223..f4b15aae 100644 --- a/packages/cultmesh-browser/test/interop/content-https-provider.ts +++ b/packages/cultmesh-browser/test/interop/content-https-provider.ts @@ -5,8 +5,8 @@ import { readFileSync } from "node:fs"; import { createServer } from "node:https"; import type { AddressInfo } from "node:net"; import { createInterface } from "node:readline"; -import { chunkRecordKey } from "cultnet-ts/content"; -import { createContentChunkHandler, createDirectoryChunkStore, toNodeListener, type ContentChunkAnswer, type ContentChunkRequest } from "cultmesh-ts/content"; +import { chunkRecordKey } from "@gamecult/cultnet-ts/content"; +import { createContentChunkHandler, createDirectoryChunkStore, toNodeListener, type ContentChunkAnswer, type ContentChunkRequest } from "@gamecult/cultmesh-ts/content"; const [storeDir, corruptDir, keyPem, certPem, escapeKey] = process.argv.slice(2) as [string, string, string, string, string]; const say = (line: object): void => { process.stdout.write(`${JSON.stringify(line)}\n`); }; diff --git a/packages/cultmesh-browser/test/interop/content-https-reader.ts b/packages/cultmesh-browser/test/interop/content-https-reader.ts index 693b22a8..fab02066 100644 --- a/packages/cultmesh-browser/test/interop/content-https-reader.ts +++ b/packages/cultmesh-browser/test/interop/content-https-reader.ts @@ -3,7 +3,7 @@ import { createHash } from "node:crypto"; import { readFileSync } from "node:fs"; import { join } from "node:path"; -import { decodeManifest } from "cultnet-ts/content"; +import { decodeManifest } from "@gamecult/cultnet-ts/content"; import { fetchVerifiedChunk, fetchVerifiedContent, CultMeshContentError } from "../../src/content.js"; const [endpointsJson, manifestsDir, only] = process.argv.slice(2) as [string, string, string | undefined]; diff --git a/packages/cultmesh-browser/test/interop/content-https.test.ts b/packages/cultmesh-browser/test/interop/content-https.test.ts index c86cf6ae..b26621eb 100644 --- a/packages/cultmesh-browser/test/interop/content-https.test.ts +++ b/packages/cultmesh-browser/test/interop/content-https.test.ts @@ -12,7 +12,7 @@ import { tmpdir } from "node:os"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { promisify } from "node:util"; -import { EMPTY_SHA256, encodeManifest, packContent } from "cultnet-ts/content"; +import { EMPTY_SHA256, encodeManifest, packContent } from "@gamecult/cultnet-ts/content"; const execFileAsync = promisify(execFile); const here = dirname(fileURLToPath(import.meta.url)); // dist-test/test/interop diff --git a/packages/cultmesh-browser/test/payload-type.test.ts b/packages/cultmesh-browser/test/payload-type.test.ts index 9cc95632..bdc6f250 100644 --- a/packages/cultmesh-browser/test/payload-type.test.ts +++ b/packages/cultmesh-browser/test/payload-type.test.ts @@ -2,8 +2,8 @@ import assert from "node:assert/strict"; import test from "node:test"; import { documentPayloadBytes, documentPayloadFromBytes, type DocumentPayload } from "@gamecult/cultcache-ts"; -import { decodeWireValue } from "cultnet-ts/wire"; -import type { CultNetRawDocumentRecord } from "cultnet-ts/contracts"; +import { decodeWireValue } from "@gamecult/cultnet-ts/wire"; +import type { CultNetRawDocumentRecord } from "@gamecult/cultnet-ts/contracts"; import { decodeCultNetPayload } from "../src/index.js"; diff --git a/packages/cultmesh-py/README.md b/packages/cultmesh-py/README.md index 4a048dcc..6a5339a5 100644 --- a/packages/cultmesh-py/README.md +++ b/packages/cultmesh-py/README.md @@ -7,7 +7,7 @@ game sessions with prediction reconciliation, committed simulation facts, the local TCP/RUDP server, and a package daemon. It depends on `cultcache-py` and `cultnet-py`, mirroring `cultmesh-rs` and -`cultmesh-ts`. The Verse catalog, peer exchange, authority lease, stream +`@gamecult/cultmesh-ts`. The Verse catalog, peer exchange, authority lease, stream negotiation, and simulation fact contracts are defined in `cultnet_py.cultmesh_contracts` and re-exported here. diff --git a/packages/cultmesh-ts/CHANGELOG.md b/packages/cultmesh-ts/CHANGELOG.md index 8b4e0ab5..9f66293c 100644 --- a/packages/cultmesh-ts/CHANGELOG.md +++ b/packages/cultmesh-ts/CHANGELOG.md @@ -1,12 +1,13 @@ # Changelog -All notable changes to `cultmesh-ts` are recorded here, following +All notable changes to `@gamecult/cultmesh-ts` are recorded here, following [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## Unreleased ### Breaking +- The package is renamed `cultmesh-ts` to `@gamecult/cultmesh-ts` (the repo already scopes `@gamecult/cultcache-ts`), so the unscoped name cannot be claimed by someone else. Import from `@gamecult/cultmesh-ts` and its subpaths; the API is unchanged. Depends on `@gamecult/cultnet-ts`. - `asSchemaAlias` is removed from `CultMeshDocumentHandle`, `CultMeshCollectionHandle` and their bound forms. Read the handle by the schema you mean. - `CultMeshDocumentCatalog` (`document`, `tryDocument`, `latest`, `replace`, `submitPrediction`, `authoritativeWriter`, `predictionWriter`, `watch`) and `CultMeshCollectionCatalog` (`collection`, `tryCollection`, `latest`, `watchChanges`) take `` and yield `CultMeshCatalogValue`: an explicit type argument wins, a CultCache document definition names its own value type, and a bare schema descriptor yields `unknown`. A value type is no longer inferred from a value or an expected result. The `parse` option is removed from these calls, and a lookup by type answers with that type's handle or none, not an alias of a compatible schema. - Adding a document or collection to a catalog under a schema id or schema name another type already holds is refused with `SchemaConflictError`. diff --git a/packages/cultmesh-ts/README.md b/packages/cultmesh-ts/README.md index 2f9eda51..9ec9e029 100644 --- a/packages/cultmesh-ts/README.md +++ b/packages/cultmesh-ts/README.md @@ -1,6 +1,6 @@ # CultMesh TS -`cultmesh-ts` is the TypeScript projection of CultMesh contracts for local +`@gamecult/cultmesh-ts` is the TypeScript projection of CultMesh contracts for local tools and browser-adjacent runtimes. The C# `GameCult.Mesh` package owns the native CultMesh stream implementation used by Mimir and Fensalir; this package mirrors the typed declaration and negotiation shapes without owning the hot @@ -21,7 +21,7 @@ WASM route. Runtime code can ask for a whole XY rect, then adapt it to the current wire schema at the edge: ```ts -import { CultMesh } from "cultmesh-ts"; +import { CultMesh } from "@gamecult/cultmesh-ts"; const viewport = CultMesh.rectFromBounds(-500, -300, 500, 300); const request = CultMesh.viewportRequest(viewport, [3, 8]); @@ -215,7 +215,7 @@ const stopFeed = viewportFeed.watch(request, "browser-starfire", render); ``` ```ts -import { CultMesh } from "cultmesh-ts"; +import { CultMesh } from "@gamecult/cultmesh-ts"; const verses = CultMesh.createVerseCatalog<{ verseId: string; label: string }>(); const stopWatching = verses.watch((verse) => { @@ -274,7 +274,7 @@ const noteShards = shards.list({ }); ``` -Schema and shard catalog factories delegate to `cultnet-ts`; the branded +Schema and shard catalog factories delegate to `@gamecult/cultnet-ts`; the branded `CultMesh` entrypoint does not create a second owner for schema discovery or topology truth. @@ -290,7 +290,7 @@ command transactions; the injected transport owns CultNet wire details. import { CultMeshProviderRudpTransport, CultMeshProviderSession, -} from "cultmesh-ts"; +} from "@gamecult/cultmesh-ts"; const odinTransport = new CultMeshProviderRudpTransport({ endpoint: "rudp://127.0.0.1:17871", @@ -347,7 +347,7 @@ evidence for the requested provider identity. Node runtimes can build the shared CultNet reliable-UDP transport from the branded CultMesh entrypoint while the transport semantics stay owned by -`cultnet-ts`: +`@gamecult/cultnet-ts`: ```ts const server = await CultMesh.createRudpServer("ts-server", 0x1020_3040); @@ -472,7 +472,7 @@ The split is deliberate: The mirrored API shape is `CultMeshStreamCatalog`: ```ts -import { CultMesh } from "cultmesh-ts"; +import { CultMesh } from "@gamecult/cultmesh-ts"; const streams = CultMesh.createStreamCatalog(); const stopWatchingStreams = streams.watch((stream) => { @@ -533,7 +533,7 @@ nonlocal fallback. ## Content Chunks over HTTP(S) -`cultmesh-ts/content` answers the C# HTTPS connector's request, `GET` or `HEAD` +`@gamecult/cultmesh-ts/content` answers the C# HTTPS connector's request, `GET` or `HEAD` `?chunkHash=&recordKey=`. The mount path is the host's; the handler reads only the query. Every chunk is hashed against its name before a byte is sent, so a corrupt or swapped file answers 500 and never leaves the @@ -550,7 +550,7 @@ host store may reuse its buffer). `onServerFault` reports every 500 (`hash-misma ```ts import { readFileSync } from "node:fs"; import { createServer } from "node:https"; -import { createContentChunkHandler, createDirectoryChunkStore, toNodeListener } from "cultmesh-ts/content"; +import { createContentChunkHandler, createDirectoryChunkStore, toNodeListener } from "@gamecult/cultmesh-ts/content"; const handler = createContentChunkHandler(createDirectoryChunkStore("/srv/content"), { onServerFault: fault => console.error("chunk fault", fault.kind, fault.chunkHash), diff --git a/packages/cultmesh-ts/package.json b/packages/cultmesh-ts/package.json index f6559fba..1ccaa421 100644 --- a/packages/cultmesh-ts/package.json +++ b/packages/cultmesh-ts/package.json @@ -1,5 +1,5 @@ { - "name": "cultmesh-ts", + "name": "@gamecult/cultmesh-ts", "version": "0.2.0", "description": "CultMesh local typed state and mesh catalog primitives for TypeScript runtimes.", "main": "dist/index.js", @@ -49,7 +49,7 @@ }, "dependencies": { "@gamecult/cultcache-ts": "^0.14.0", - "cultnet-ts": "^0.3.0", + "@gamecult/cultnet-ts": "^0.3.0", "koffi": "3.3.0" }, "devDependencies": { diff --git a/packages/cultmesh-ts/src/content.ts b/packages/cultmesh-ts/src/content.ts index a0f3f06d..b463f5b6 100644 --- a/packages/cultmesh-ts/src/content.ts +++ b/packages/cultmesh-ts/src/content.ts @@ -2,7 +2,7 @@ import { constants } from "node:fs"; import { open } from "node:fs/promises"; import type { IncomingMessage, ServerResponse } from "node:http"; import { join } from "node:path"; -import { DEFAULT_CHUNK_SIZE_BYTES, EMPTY_SHA256, chunkRecordKey, isNullOrWhiteSpaceCSharp, parseSha256Hex, sha256Hex } from "cultnet-ts/content"; +import { DEFAULT_CHUNK_SIZE_BYTES, EMPTY_SHA256, chunkRecordKey, isNullOrWhiteSpaceCSharp, parseSha256Hex, sha256Hex } from "@gamecult/cultnet-ts/content"; /** What the provider reads of a request. The path and the headers are never read: the route is the query alone. */ export interface ContentChunkRequest { method: string; url: string; } diff --git a/packages/cultmesh-ts/src/index.ts b/packages/cultmesh-ts/src/index.ts index 90331655..3e15eaac 100644 --- a/packages/cultmesh-ts/src/index.ts +++ b/packages/cultmesh-ts/src/index.ts @@ -1,5 +1,5 @@ import { createSocket, type Socket } from "node:dgram"; -import { decodeWireValue, encodeWireValue } from "cultnet-ts/wire"; +import { decodeWireValue, encodeWireValue } from "@gamecult/cultnet-ts/wire"; import { CultCache, @@ -40,7 +40,7 @@ import { type CultNetSchemaCatalogOptions, type CultNetSnapshotResponseRawMessage, type CultNetWireContract, -} from "cultnet-ts"; +} from "@gamecult/cultnet-ts"; import { CultMeshQuicRealtimeConnector, diff --git a/packages/cultmesh-ts/src/provider-rudp-transport.ts b/packages/cultmesh-ts/src/provider-rudp-transport.ts index fc0d75c0..b193825f 100644 --- a/packages/cultmesh-ts/src/provider-rudp-transport.ts +++ b/packages/cultmesh-ts/src/provider-rudp-transport.ts @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; import { createSocket, type Socket } from "node:dgram"; import { documentPayloadFromBytes } from "@gamecult/cultcache-ts"; -import { encodeWireValue } from "cultnet-ts/wire"; +import { encodeWireValue } from "@gamecult/cultnet-ts/wire"; import { CultNetPeer, CultNetRudpSocketTransportConnection, @@ -9,7 +9,7 @@ import { type CultNetOperationRequestMessage, type CultNetOperationResponseMessage, type CultNetRawDocumentRecord, -} from "cultnet-ts"; +} from "@gamecult/cultnet-ts"; import type { CultMeshProviderCommand, diff --git a/packages/cultmesh-ts/src/provider-session-broker.ts b/packages/cultmesh-ts/src/provider-session-broker.ts index 75240a14..c427b83a 100644 --- a/packages/cultmesh-ts/src/provider-session-broker.ts +++ b/packages/cultmesh-ts/src/provider-session-broker.ts @@ -1,11 +1,11 @@ import { encodeDocumentPayload } from "@gamecult/cultcache-ts"; -import { encodeWireValue } from "cultnet-ts/wire"; +import { encodeWireValue } from "@gamecult/cultnet-ts/wire"; import type { CultNetDocumentPutRawMessage, CultNetOperationRequestMessage, CultNetOperationResponseMessage, CultNetRawDocumentRecord, -} from "cultnet-ts"; +} from "@gamecult/cultnet-ts"; import type { CultMeshRudpServerSession } from "./index"; import { diff --git a/packages/cultmesh-ts/src/provider-session-wire.ts b/packages/cultmesh-ts/src/provider-session-wire.ts index d4884694..3cffb13e 100644 --- a/packages/cultmesh-ts/src/provider-session-wire.ts +++ b/packages/cultmesh-ts/src/provider-session-wire.ts @@ -1,6 +1,6 @@ import { decodeDocumentPayload, defineDocumentType } from "@gamecult/cultcache-ts"; -import { decodeWireValue, encodeWireValue } from "cultnet-ts/wire"; -import type { CultNetRawDocumentRecord } from "cultnet-ts"; +import { decodeWireValue, encodeWireValue } from "@gamecult/cultnet-ts/wire"; +import type { CultNetRawDocumentRecord } from "@gamecult/cultnet-ts"; export const CULTMESH_PROVIDER_SESSION_SERVICE_ID = "gamecult.mesh.provider_session"; diff --git a/packages/cultmesh-ts/src/realtime-quic.ts b/packages/cultmesh-ts/src/realtime-quic.ts index c368c96f..32b500d2 100644 --- a/packages/cultmesh-ts/src/realtime-quic.ts +++ b/packages/cultmesh-ts/src/realtime-quic.ts @@ -21,8 +21,8 @@ import { trimCSharp, verifyAuthorityRoute, type CultMeshAuthorityTrustPolicy, -} from "cultnet-ts"; -import type { CultMeshVerseDescriptorMessage } from "cultnet-ts/contracts"; +} from "@gamecult/cultnet-ts"; +import type { CultMeshVerseDescriptorMessage } from "@gamecult/cultnet-ts/contracts"; import { decodeRealtimeFrame, diff --git a/packages/cultmesh-ts/src/realtime-wire.ts b/packages/cultmesh-ts/src/realtime-wire.ts index 9fc99789..e87df641 100644 --- a/packages/cultmesh-ts/src/realtime-wire.ts +++ b/packages/cultmesh-ts/src/realtime-wire.ts @@ -16,7 +16,7 @@ // agree with itself. import { documentPayloadBytes, documentPayloadFromBytes, type DocumentPayload } from "@gamecult/cultcache-ts"; -import { isNullOrWhiteSpaceCSharp } from "cultnet-ts"; +import { isNullOrWhiteSpaceCSharp } from "@gamecult/cultnet-ts"; /** `CultMeshRealtimeWireProtocol.ApplicationProtocolName`: the QUIC ALPN. */ export const CULTMESH_REALTIME_ALPN = "cultmesh-state-v1"; @@ -70,7 +70,7 @@ const INT64_MAX = 2n ** 63n - 1n; * `CultMeshRealtimeFrame.Validate`. The C# reading of "non-empty" is * `string.IsNullOrWhiteSpace`, whose whitespace set is not * `String.prototype.trim`'s, so this borrows the one TypeScript implementation - * of that set from `cultnet-ts` rather than keeping a second reading here. + * of that set from `@gamecult/cultnet-ts` rather than keeping a second reading here. * * The range check has no C# counterpart because `long` gives it for free; a * `bigint` does not, and a `DataView` would otherwise throw a bare `RangeError` diff --git a/packages/cultmesh-ts/test/codec-documents.test.ts b/packages/cultmesh-ts/test/codec-documents.test.ts index 58c05568..eadc1d2f 100644 --- a/packages/cultmesh-ts/test/codec-documents.test.ts +++ b/packages/cultmesh-ts/test/codec-documents.test.ts @@ -19,7 +19,7 @@ import { CultNetDocumentRegistry, defineCultNetDocumentBinding, type CultNetPeer, -} from "cultnet-ts"; +} from "@gamecult/cultnet-ts"; import { CultMesh, cultMeshDocumentFromSingleFile, type CultMeshRudpDocumentPut } from "../src/index"; // A document written in the reference's positional shape, and a plain map document beside it. Every mesh reader of a diff --git a/packages/cultmesh-ts/test/content.test.ts b/packages/cultmesh-ts/test/content.test.ts index 9662bb86..7e3a357a 100644 --- a/packages/cultmesh-ts/test/content.test.ts +++ b/packages/cultmesh-ts/test/content.test.ts @@ -8,7 +8,7 @@ import { join } from "node:path"; import test, { mock } from "node:test"; import { execFileSync } from "node:child_process"; -import { EMPTY_SHA256, chunkRecordKey, packContent, sha256Hex } from "cultnet-ts/content"; +import { EMPTY_SHA256, chunkRecordKey, packContent, sha256Hex } from "@gamecult/cultnet-ts/content"; import { closeSync, constants as fsConstants, openSync, symlinkSync } from "node:fs"; import { diff --git a/packages/cultmesh-ts/test/cultmesh.test.ts b/packages/cultmesh-ts/test/cultmesh.test.ts index eccb4545..924ab697 100644 --- a/packages/cultmesh-ts/test/cultmesh.test.ts +++ b/packages/cultmesh-ts/test/cultmesh.test.ts @@ -4,7 +4,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import test from "node:test"; import assert from "node:assert/strict"; -import { decodeWireValue, encodeWireValue } from "cultnet-ts/wire"; +import { decodeWireValue, encodeWireValue } from "@gamecult/cultnet-ts/wire"; import { z } from "zod"; import { SchemaConflictError, defineDocumentType, documentPayloadBytes, documentPayloadFromBytes } from "@gamecult/cultcache-ts"; import { @@ -19,7 +19,7 @@ import { type CultNetRudpPacket, type CultNetMessage, type CultNetSnapshotResponseRawMessage, -} from "cultnet-ts"; +} from "@gamecult/cultnet-ts"; import { CultMesh, CultMeshRudpUnservableDocumentError } from "../src/index"; // A record's payload as the bytes a peer would put on the wire. diff --git a/packages/cultmesh-ts/test/interop/cultmesh-quic-peer.ts b/packages/cultmesh-ts/test/interop/cultmesh-quic-peer.ts index e7e04c1a..f22d5af3 100644 --- a/packages/cultmesh-ts/test/interop/cultmesh-quic-peer.ts +++ b/packages/cultmesh-ts/test/interop/cultmesh-quic-peer.ts @@ -18,8 +18,8 @@ // harness can dial a peer late and exercise Cut C's retained-state seed // instead of the provider always tearing down the moment it is done sending. // -// Neither mode imports `cultmesh-ts` itself (the harness drives processes, -// and the dependency direction is `cultmesh-ts` -> `cultnet-ts`, never the +// Neither mode imports `@gamecult/cultmesh-ts` itself (the harness drives processes, +// and the dependency direction is `@gamecult/cultmesh-ts` -> `@gamecult/cultnet-ts`, never the // reverse); this script reaches the provider/connector through its own // package's `src/`. diff --git a/packages/cultmesh-ts/test/payload-type.test.ts b/packages/cultmesh-ts/test/payload-type.test.ts index cdba3505..f04541da 100644 --- a/packages/cultmesh-ts/test/payload-type.test.ts +++ b/packages/cultmesh-ts/test/payload-type.test.ts @@ -8,8 +8,8 @@ import { documentPayloadFromBytes, type DocumentPayload, } from "@gamecult/cultcache-ts"; -import { decodeWireValue } from "cultnet-ts/wire"; -import type { CultNetRawDocumentRecord } from "cultnet-ts"; +import { decodeWireValue } from "@gamecult/cultnet-ts/wire"; +import type { CultNetRawDocumentRecord } from "@gamecult/cultnet-ts"; import type { CultMeshRudpDocumentPut } from "../src/index"; import { decodeRealtimeFrame, encodeRealtimeFrame, type CultMeshRealtimeFrame } from "../src/realtime-wire"; diff --git a/packages/cultmesh-ts/test/provider-rudp-transport.test.ts b/packages/cultmesh-ts/test/provider-rudp-transport.test.ts index e9a9f1c5..d73ec1bd 100644 --- a/packages/cultmesh-ts/test/provider-rudp-transport.test.ts +++ b/packages/cultmesh-ts/test/provider-rudp-transport.test.ts @@ -2,7 +2,7 @@ import test from "node:test"; import assert from "node:assert/strict"; import { createSocket } from "node:dgram"; import { documentPayloadBytes } from "@gamecult/cultcache-ts"; -import { decodeWireValue } from "cultnet-ts/wire"; +import { decodeWireValue } from "@gamecult/cultnet-ts/wire"; import { CultNetDocumentRegistry, CultNetRudpSession, @@ -10,7 +10,7 @@ import { encodeRudpPacket, type CultNetOperationRequestMessage, type CultNetRudpPacket, -} from "cultnet-ts"; +} from "@gamecult/cultnet-ts"; import { CultMesh, diff --git a/packages/cultmesh-ts/test/provider-session-wire.test.ts b/packages/cultmesh-ts/test/provider-session-wire.test.ts index ee196f41..4905f161 100644 --- a/packages/cultmesh-ts/test/provider-session-wire.test.ts +++ b/packages/cultmesh-ts/test/provider-session-wire.test.ts @@ -2,7 +2,7 @@ import test from "node:test"; import assert from "node:assert/strict"; import { documentPayloadBytes, documentPayloadFromBytes, encodeDocumentPayload, type DocumentPayload } from "@gamecult/cultcache-ts"; -import { encodeWireValue } from "cultnet-ts/wire"; +import { encodeWireValue } from "@gamecult/cultnet-ts/wire"; import { cultMeshProviderSessionSchemas, diff --git a/packages/cultmesh-ts/test/realtime-quic-consumer.test.ts b/packages/cultmesh-ts/test/realtime-quic-consumer.test.ts index acf06a41..f48dec74 100644 --- a/packages/cultmesh-ts/test/realtime-quic-consumer.test.ts +++ b/packages/cultmesh-ts/test/realtime-quic-consumer.test.ts @@ -21,8 +21,8 @@ import { type CultMeshAuthorityRouteView, type CultMeshAuthorityTrustPolicy, type CultMeshP256PublicKey, -} from "cultnet-ts"; -import type { CultMeshAuthorityRouteMessage, CultMeshVerseDescriptorMessage } from "cultnet-ts/contracts"; +} from "@gamecult/cultnet-ts"; +import type { CultMeshAuthorityRouteMessage, CultMeshVerseDescriptorMessage } from "@gamecult/cultnet-ts/contracts"; import { CultMeshQuicNativeRuntime, diff --git a/packages/cultmesh-ts/test/realtime-quic-session-manager.test.ts b/packages/cultmesh-ts/test/realtime-quic-session-manager.test.ts index e1843466..f636fc95 100644 --- a/packages/cultmesh-ts/test/realtime-quic-session-manager.test.ts +++ b/packages/cultmesh-ts/test/realtime-quic-session-manager.test.ts @@ -14,8 +14,8 @@ import assert from "node:assert/strict"; import test from "node:test"; -import type { CultMeshAuthorityTrustPolicy } from "cultnet-ts"; -import type { CultMeshAuthorityRouteMessage, CultMeshVerseDescriptorMessage } from "cultnet-ts/contracts"; +import type { CultMeshAuthorityTrustPolicy } from "@gamecult/cultnet-ts"; +import type { CultMeshAuthorityRouteMessage, CultMeshVerseDescriptorMessage } from "@gamecult/cultnet-ts/contracts"; import { CultMeshQuicRealtimeSessionManager, diff --git a/packages/cultmesh-ts/test/rudp-document-server-send-failure.test.ts b/packages/cultmesh-ts/test/rudp-document-server-send-failure.test.ts index 713a3bee..c26c5a82 100644 --- a/packages/cultmesh-ts/test/rudp-document-server-send-failure.test.ts +++ b/packages/cultmesh-ts/test/rudp-document-server-send-failure.test.ts @@ -6,14 +6,14 @@ import assert from "node:assert/strict"; import { createSocket, type RemoteInfo, type Socket } from "node:dgram"; import test from "node:test"; import { documentPayloadFromBytes } from "@gamecult/cultcache-ts"; -import { encodeWireValue } from "cultnet-ts/wire"; +import { encodeWireValue } from "@gamecult/cultnet-ts/wire"; import { CultNetDocumentRegistry, CultNetRudpSession, decodeRudpPacket, encodeRudpPacket, type CultNetPeer, -} from "cultnet-ts"; +} from "@gamecult/cultnet-ts"; import { CultMesh } from "../src/index"; async function waitFor(predicate: () => boolean, description: string): Promise { diff --git a/packages/cultnet-py/README.md b/packages/cultnet-py/README.md index cca39ba7..98a6db93 100644 --- a/packages/cultnet-py/README.md +++ b/packages/cultnet-py/README.md @@ -8,7 +8,7 @@ wire contracts that both a node and a bare peer have to agree on. It depends on `cultcache-py` and `msgpack`; AES-GCM helpers on `CultNetSecret` light up with the optional `crypto` extra. `cultmesh-py` builds on it. The -layering mirrors `cultnet-rs` and `cultnet-ts`. +layering mirrors `cultnet-rs` and `@gamecult/cultnet-ts`. ## Example diff --git a/packages/cultnet-rs/README.md b/packages/cultnet-rs/README.md index 48ac2dd3..c356b97b 100644 --- a/packages/cultnet-rs/README.md +++ b/packages/cultnet-rs/README.md @@ -1,6 +1,6 @@ # CultNet RS -`cultnet-rs` is the Rust sibling of `cultnet-ts`: typed MessagePack messages, +`cultnet-rs` is the Rust sibling of `@gamecult/cultnet-ts`: typed MessagePack messages, 4-byte length-prefixed direct-pipe framing, CultLib-shaped security helpers, and CultCache replication without making callers paw through raw envelopes like we lost a bet. @@ -100,7 +100,7 @@ game-session authority remain separate responsibilities. ## Local Fast Lane -`cultnet-rs` now mirrors the raw replication seam from `cultnet-ts`: +`cultnet-rs` now mirrors the raw replication seam from `@gamecult/cultnet-ts`: - `cultnet.document_put_raw.v0` - `cultnet.snapshot_response_raw.v0` diff --git a/packages/cultnet-ts/CHANGELOG.md b/packages/cultnet-ts/CHANGELOG.md index a5b8bc4e..b2a16456 100644 --- a/packages/cultnet-ts/CHANGELOG.md +++ b/packages/cultnet-ts/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -All notable changes to `cultnet-ts` are recorded here, following +All notable changes to `@gamecult/cultnet-ts` are recorded here, following [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## Unreleased @@ -13,6 +13,7 @@ All notable changes to `cultnet-ts` are recorded here, following ### Breaking +- The package is renamed `cultnet-ts` to `@gamecult/cultnet-ts` (the repo already scopes `@gamecult/cultcache-ts`), so the unscoped name cannot be claimed by someone else. Import from `@gamecult/cultnet-ts` and its subpaths; the API is unchanged. - `CultNetErrorMessage` carries `routingHint`, `code` and `details` (null when absent), as the reference writes them and `cultnet.error.schema.json` requires; the interface previously dropped them. New `CultNetErrorCode`, `CultNetErrorDetails` and `CultNetShardRoutingHint` types. - `CultMeshCdnChunkRef` carries `id` (slot 4), the reference's element id. `encodeManifest` writes five-slot chunk references and `packContent` sets the decimal offset as the id, as the reference does; a manifest written before ids reads `""` and is rewritten with the slot. Content vectors regenerated from the reference. diff --git a/packages/cultnet-ts/README.md b/packages/cultnet-ts/README.md index acbf5a6a..1fb37a3f 100644 --- a/packages/cultnet-ts/README.md +++ b/packages/cultnet-ts/README.md @@ -1,6 +1,6 @@ # CultNet TS -`cultnet-ts` is the TypeScript port of the useful shape of GameCult's +`@gamecult/cultnet-ts` is the TypeScript port of the useful shape of GameCult's networking layer: typed MessagePack messages, direct-pipe framing, CultLib-style security/session helpers, and state replication that hands typed values into a `CultCache` instead of making consumer code paw raw database envelopes. @@ -42,7 +42,7 @@ We want: So the split is: - `cultcache-ts`: typed local persistence -- `cultnet-ts`: typed transport, auth, and state replication +- `@gamecult/cultnet-ts`: typed transport, auth, and state replication Same family. Different organs. Nobody needs a second spine growing out of the transport layer. @@ -80,7 +80,7 @@ CultNet without inventing a second ontology first. ## Generated Swarm Contracts -`cultnet-ts` can consume canonical JSON Schema files and generate: +`@gamecult/cultnet-ts` can consume canonical JSON Schema files and generate: - TypeScript contract classes/interfaces - runtime schema verifiers @@ -111,7 +111,7 @@ which exports: ## Wire Contracts -`cultnet-ts` does not sniff random payloads and pretend that counts as rigor. +`@gamecult/cultnet-ts` does not sniff random payloads and pretend that counts as rigor. You choose the contract explicitly. Current wire-contract options: @@ -129,7 +129,7 @@ away from the C# lineage. ## Content -`cultnet-ts/content` owns the TypeScript shapes of the CultMesh CDN +`@gamecult/cultnet-ts/content` owns the TypeScript shapes of the CultMesh CDN (`src/content.ts`, the twin of `CultMeshCdn.cs`): the artifact manifest and chunk reference, their MessagePack form, hash normalization, both record-key grammars, SHA-256 hashing through WebCrypto, and `packContent`. It is browser-safe: it @@ -160,7 +160,7 @@ imports no `node:` module, so a browser bundle can take it. ## Local Fast Lane For direct-pipe neighbors that already share the same CultCache formatter -contract, `cultnet-ts` now has a raw replication lane: +contract, `@gamecult/cultnet-ts` now has a raw replication lane: - `cultnet.document_put_raw.v0` - `cultnet.snapshot_response_raw.v0` @@ -185,7 +185,7 @@ cuts out the dumbest part of the trip. Apps sharing a CultNet space should be able to ask each other what they can exchange without resorting to folklore. -`cultnet-ts` now includes: +`@gamecult/cultnet-ts` now includes: - `cultnet.schema_catalog_request.v0` - `cultnet.schema_catalog_response.v0` @@ -232,7 +232,7 @@ import { createTcpFramedCultNetPeer, defineCultNetDocumentBinding, ghostlightAgentStateGeneratedContract, -} from "cultnet-ts"; +} from "@gamecult/cultnet-ts"; const ghostlightStateDefinition = defineDocumentType({ type: "ghostlight.agent-state", @@ -270,7 +270,7 @@ That means a TypeScript runtime can follow the same cryptographic and session story as the C# version instead of inventing one more house religion around "trust me, this pipe is probably fine." -For the legacy `gamecult.networking.v0` contract, `cultnet-ts` normalizes the +For the legacy `gamecult.networking.v0` contract, `@gamecult/cultnet-ts` normalizes the encrypted binary fields as base64url strings in the ergonomic TS surface and maps them back to the exact C# union payload shape at the wire boundary. diff --git a/packages/cultnet-ts/package.json b/packages/cultnet-ts/package.json index 1fc6abed..ebafac78 100644 --- a/packages/cultnet-ts/package.json +++ b/packages/cultnet-ts/package.json @@ -1,5 +1,5 @@ { - "name": "cultnet-ts", + "name": "@gamecult/cultnet-ts", "version": "0.3.0", "description": "CultNet-style typed direct-pipe messaging and state replication for TypeScript runtimes.", "main": "dist/index.js", diff --git a/packages/cultnet-ts/src/cultmesh-authority.ts b/packages/cultnet-ts/src/cultmesh-authority.ts index c260cf70..9d1c7438 100644 --- a/packages/cultnet-ts/src/cultmesh-authority.ts +++ b/packages/cultnet-ts/src/cultmesh-authority.ts @@ -39,8 +39,8 @@ export interface CultMeshAuthorityRouteCertificate { /** * Maps an advertised route's wire-shaped certificate to the view * `verifyAuthorityRoute` and the transports consume. Shared by the QUIC - * realtime session manager (`cultmesh-ts`) and the browser WebSocket client - * (`cultmesh-browser`), which advertise the same `CultMeshAuthorityRouteMessage` + * realtime session manager (`@gamecult/cultmesh-ts`) and the browser WebSocket client + * (`@gamecult/cultmesh-browser`), which advertise the same `CultMeshAuthorityRouteMessage` * certificate shape and were computing this mapping independently. */ export function routeCertificateView( diff --git a/packages/cultnet-ts/test/first-call.test.ts b/packages/cultnet-ts/test/first-call.test.ts index b389ca95..977a6e5b 100644 --- a/packages/cultnet-ts/test/first-call.test.ts +++ b/packages/cultnet-ts/test/first-call.test.ts @@ -6,7 +6,7 @@ import test from "node:test"; // The TypeScript CultNet first-call snippet that docs/start/README.md shows: define a typed document, send it // over a loopback TCP pipe as a cultnet.document_put_raw.v0 message, receive it into a second cache. The docs show // the region between the `snippet` markers verbatim, except that the package import reads -// "cultnet-ts" where this file reads "../src"; the docs test below fails when they differ. +// "@gamecult/cultnet-ts" where this file reads "../src"; the docs test below fails when they differ. // snippet:begin import { createServer, connect } from "node:net"; import { z } from "zod"; @@ -72,7 +72,7 @@ test("docs show the tested snippet", async () => { const snippet = source .split("// snippet:begin\n")[1] .split("// snippet:end\n")[0] - .replace('"../src"', '"cultnet-ts"'); + .replace('"../src"', '"@gamecult/cultnet-ts"'); const docs = (await readFile(join(__dirname, "..", "..", "..", "..", "docs", "start", "README.md"), "utf8")).replace(/\r\n/g, "\n"); assert.ok(docs.includes("```ts\n" + snippet + "```"), "docs/start/README.md no longer shows test/first-call.test.ts"); }); diff --git a/packages/cultnet-ts/test/idunn-runtime-authority.test.ts b/packages/cultnet-ts/test/idunn-runtime-authority.test.ts index cf1e4a26..2b45e3b1 100644 --- a/packages/cultnet-ts/test/idunn-runtime-authority.test.ts +++ b/packages/cultnet-ts/test/idunn-runtime-authority.test.ts @@ -461,13 +461,13 @@ function loadUnderDgramStub(modulePath: string): string { } test("the idunn-runtime subpath loads the signer and loader without loading dgram; the package root does load it", () => { - const subpath = require.resolve("cultnet-ts/idunn-runtime"); + const subpath = require.resolve("@gamecult/cultnet-ts/idunn-runtime"); assert.equal(loadUnderDgramStub(subpath), "loaded"); - assert.equal(loadUnderDgramStub(require.resolve("cultnet-ts")), "failed: dgram was loaded"); + assert.equal(loadUnderDgramStub(require.resolve("@gamecult/cultnet-ts")), "failed: dgram was loaded"); const exported = require(subpath) as Record; assert.equal(typeof exported.createIdunnRuntimeSigner, "function"); assert.equal(typeof exported.loadIdunnRuntimeAuthorityFromEnvironment, "function"); assert.equal(exported.createIdunnRuntimePresencePublisher, undefined); assert.equal(exported.signIdunnRuntimePresence, undefined); - assert.equal((require("cultnet-ts") as Record).signIdunnRuntimePresence, undefined); + assert.equal((require("@gamecult/cultnet-ts") as Record).signIdunnRuntimePresence, undefined); }); diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index 445bfb9d..62a7980b 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -4,7 +4,7 @@ This is the real-process continuation of `samples/eve-two-runtime`: - one C# provider owns a durable `.cc` counter, the Eve surface, command idempotency, and canonical receipts; -- one real Chromium page leases both documents through `cultmesh-browser` and +- one real Chromium page leases both documents through `@gamecult/cultmesh-browser` and lowers the provider-owned Eve surface; - one retained C# headless client discovers the provider through the same Odin identity, observes the typed counter and canonical receipt ids, survives the diff --git a/samples/eve-browser-network/browser/main.ts b/samples/eve-browser-network/browser/main.ts index fc57e364..76f8817a 100644 --- a/samples/eve-browser-network/browser/main.ts +++ b/samples/eve-browser-network/browser/main.ts @@ -5,7 +5,7 @@ import { CultMeshBrowserOdinRendezvous, decodeCultNetOperationPayload, decodeCultNetPayload, -} from "cultmesh-browser"; +} from "@gamecult/cultmesh-browser"; import { defineDocumentType } from "@gamecult/cultcache-ts/document"; // A payload is read through the definition that says how its bytes are laid out. These are plain-map definitions: the diff --git a/samples/eve-two-runtime/sample.mjs b/samples/eve-two-runtime/sample.mjs index 93ed1dc8..e7dc56c5 100644 --- a/samples/eve-two-runtime/sample.mjs +++ b/samples/eve-two-runtime/sample.mjs @@ -5,7 +5,7 @@ import { join } from "node:path"; import { JSDOM } from "jsdom"; import { z } from "zod"; import { defineDocumentType } from "@gamecult/cultcache-ts"; -import { CultMesh } from "cultmesh-ts"; +import { CultMesh } from "@gamecult/cultmesh-ts"; import { parseEveCommandReceipt, parseEveSurfaceDocument, diff --git a/scripts/run-typescript-workspaces.mjs b/scripts/run-typescript-workspaces.mjs index 0ef34005..3ed4514c 100644 --- a/scripts/run-typescript-workspaces.mjs +++ b/scripts/run-typescript-workspaces.mjs @@ -11,7 +11,7 @@ const npmCli = process.env.npm_execpath ?? // moves when a package is scoped: `8cb3b72` renamed `cultcache-ts` to // `@gamecult/cultcache-ts` and left this entry behind, which broke `build:ts` and // `test:ts` for every workspace from that commit on. -const workspaces = ["@gamecult/cultcache-ts", "cultnet-ts", "cultmesh-ts", "cultmesh-browser"]; +const workspaces = ["@gamecult/cultcache-ts", "@gamecult/cultnet-ts", "@gamecult/cultmesh-ts", "@gamecult/cultmesh-browser"]; const childEnv = process.platform === "win32" ? { ...process.env, diff --git a/scripts/test-typescript-package-closure.mjs b/scripts/test-typescript-package-closure.mjs index 6b0d7661..1fb6c140 100644 --- a/scripts/test-typescript-package-closure.mjs +++ b/scripts/test-typescript-package-closure.mjs @@ -79,8 +79,8 @@ try { const assert = require("node:assert/strict"); const cache = require("@gamecult/cultcache-ts"); const documentEntry = require("@gamecult/cultcache-ts/document"); -const net = require("cultnet-ts"); -const mesh = require("cultmesh-ts"); +const net = require("@gamecult/cultnet-ts"); +const mesh = require("@gamecult/cultmesh-ts"); assert.equal(typeof cache.defineDocumentType, "function"); // The document owner is also an entry of its own, which the browser client imports without the Node-only cache. assert.equal(documentEntry.decodeDocumentPayload, cache.decodeDocumentPayload); @@ -147,8 +147,8 @@ assert.deepEqual(mesh.CultMesh.vec2(3, 4), { x: 3, y: 4 }); writeFileSync(join(consumerRoot, "browser-runtime-smoke.mjs"), ` import assert from "node:assert/strict"; -import { CultMeshBrowserClient, decodeCultNetPayload } from "cultmesh-browser"; -import { parseCultNetMessage } from "cultnet-ts/contracts"; +import { CultMeshBrowserClient, decodeCultNetPayload } from "@gamecult/cultmesh-browser"; +import { parseCultNetMessage } from "@gamecult/cultnet-ts/contracts"; assert.equal(typeof CultMeshBrowserClient.connect, "function"); assert.equal(typeof decodeCultNetPayload, "function"); assert.equal(typeof parseCultNetMessage, "function"); @@ -159,14 +159,14 @@ assert.equal("putDocument" in CultMeshBrowserClient.prototype, false); writeFileSync(join(consumerRoot, "types-smoke.ts"), ` import { defineDocumentType } from "@gamecult/cultcache-ts"; import { decodeDocumentPayload, type DocumentPayload } from "@gamecult/cultcache-ts/document"; -import { CultNetPeer } from "cultnet-ts"; +import { CultNetPeer } from "@gamecult/cultnet-ts"; import { CultMesh, CultMeshProviderSession, type CultMeshProviderIdentity, type CultMeshProviderTransport, type CultMeshVec2, -} from "cultmesh-ts"; +} from "@gamecult/cultmesh-ts"; const point: CultMeshVec2 = CultMesh.vec2(3, 4); const defineDocument: typeof defineDocumentType = defineDocumentType; @@ -209,7 +209,7 @@ import { CultMeshBrowserClient, type CultMeshBrowserIdentity, type CultMeshRawDocumentLeaseOptions, -} from "cultmesh-browser"; +} from "@gamecult/cultmesh-browser"; const identity: CultMeshBrowserIdentity = { verseId: "smoke", diff --git a/scripts/verify-eve-browser-network.mjs b/scripts/verify-eve-browser-network.mjs index 401e4afb..998ee52c 100644 --- a/scripts/verify-eve-browser-network.mjs +++ b/scripts/verify-eve-browser-network.mjs @@ -46,8 +46,8 @@ try { const moduleMap = { "@gamecult/eve-contracts": join(eveRoot, "packages", "eve-contracts", "src", "index.ts"), "@gamecult/eve-browser-lowering": join(eveRoot, "packages", "eve-browser-lowering", "src", "index.ts"), - "cultmesh-browser": join(repoRoot, "packages", "cultmesh-browser", "src", "index.ts"), - "cultnet-ts/contracts": join(repoRoot, "packages", "cultnet-ts", "src", "contracts.ts"), + "@gamecult/cultmesh-browser": join(repoRoot, "packages", "cultmesh-browser", "src", "index.ts"), + "@gamecult/cultnet-ts/contracts": join(repoRoot, "packages", "cultnet-ts", "src", "contracts.ts"), }; const sampleTsconfig = join(workRoot, "tsconfig.json"); await writeFile(sampleTsconfig, JSON.stringify({ diff --git a/src/GameCult.Mesh/docs/browser-verse-transport.md b/src/GameCult.Mesh/docs/browser-verse-transport.md index e825a0d4..663acc06 100644 --- a/src/GameCult.Mesh/docs/browser-verse-transport.md +++ b/src/GameCult.Mesh/docs/browser-verse-transport.md @@ -19,14 +19,14 @@ standalone. The current substrate has a browser client boundary and local live proof, but not a complete public Verse proof: -- `cultmesh-ts` is a Node package and imports `node:dgram` at its root; -- `cultnet-ts/contracts` is the browser-safe contract entrypoint; the package +- `@gamecult/cultmesh-ts` is a Node package and imports `node:dgram` at its root; +- `@gamecult/cultnet-ts/contracts` is the browser-safe contract entrypoint; the package root still includes Node transport, filesystem, crypto, stream, and UDP modules and must not enter browser bundles; - C# and TypeScript now share `cultnet.database_subscribe.v0`, `cultnet.database_unsubscribe.v0`, and `cultnet.database_change_raw.v0`; - `cultmesh-browser` consumes those messages as explicit document leases; -- `cultmesh-browser` owns stable identity, route refresh, resubscription, and + `@gamecult/cultmesh-browser` consumes those messages as explicit document leases; +- `@gamecult/cultmesh-browser` owns stable identity, route refresh, resubscription, and typed operation correlation without exposing direct document writes; - `CultMeshBrowserOdinRendezvous` resolves stable Verse/provider identity with `cultmesh.verse_catalog_request.v0` and @@ -112,8 +112,8 @@ Shared paths: Deletion line: - the jsdom checkpoint remains labeled as a Node-hosted DOM proof; -- browser applications import `cultmesh-browser` and - `cultnet-ts/contracts`, never the Node-only package roots; +- browser applications import `@gamecult/cultmesh-browser` and + `@gamecult/cultnet-ts/contracts`, never the Node-only package roots; - subscription messages remain one shared schema contract across the C# and TypeScript catalogs; - the real provider adapter must consume the canonical WebSocket message lane; diff --git a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md index 49a23f79..768a31a3 100644 --- a/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md +++ b/src/GameCult.Mesh/docs/getting-started/03-publish-an-eve-surface.md @@ -101,7 +101,7 @@ The real-process C# sample is then rebuilt from that same temporary NuGet feed. The source project references in its `.csproj` are contributor convenience only and are disabled by the checkpoint; they are not the consumer contract. -The first layer builds and packs `cultcache-ts`, `cultnet-ts`, `cultmesh-ts`, +The first layer builds and packs `cultcache-ts`, `@gamecult/cultnet-ts`, `@gamecult/cultmesh-ts`, `@gamecult/eve-contracts`, and `@gamecult/eve-browser-lowering`, installs the tarballs into an empty temporary consumer, and runs `samples/eve-two-runtime/sample.mjs`. Eve's generated runtime validators reject diff --git a/src/GameCult.Mesh/docs/reliability-migration-plan.md b/src/GameCult.Mesh/docs/reliability-migration-plan.md index 47e1b190..6763080f 100644 --- a/src/GameCult.Mesh/docs/reliability-migration-plan.md +++ b/src/GameCult.Mesh/docs/reliability-migration-plan.md @@ -574,7 +574,7 @@ registration, renewal, stable publication order, reconnect and replay, duplicate receipt reuse, explicit withdrawal, and the negative stop-during- registration timeline, durable receipt replay, observer isolation, conflicting command IDs, and exception-safe shutdown. The empty-consumer tarball smoke proves the session is -present in the installable `cultmesh-ts` package. A live Odin transport adapter +present in the installable `@gamecult/cultmesh-ts` package. A live Odin transport adapter and the VoidBot migration remain required for the production proof. ## Phase 3: Authority as a Mandatory Boundary diff --git a/src/GameCult.Networking/README.md b/src/GameCult.Networking/README.md index 7347d145..dea0e411 100644 --- a/src/GameCult.Networking/README.md +++ b/src/GameCult.Networking/README.md @@ -431,7 +431,7 @@ opt-in. Text frames and messages over the configured size bound are closed before schema dispatch. The matching `CultNetWebSocketSchemaClient` is suitable for C# headless and -service consumers. Browser applications use `cultmesh-browser`, which owns +service consumers. Browser applications use `@gamecult/cultmesh-browser`, which owns stable Verse/provider identity, document leases, resubscription, and operation correlation above the raw WebSocket route. -- 2.47.3