npm.io
0.0.0 • Published 2d ago

@game-infra/shared-utils

Licence
Version
0.0.0
Deps
1
Size
35 kB
Vulns
0
Weekly
0

@game-infra/shared-utils

Small runtime-agnostic utilities shared across game tooling and services: Zstd compression with base64 transport encoding, JSON-serializability validation, and a seedable mulberry32 RNG for reproducible game sessions. Works in browsers, Node, and Workers; the only runtime dependency is the @hpcc-js/wasm-zstd WASM module.

Linking

This package is consumed as source from a sibling game-infra checkout, not from the npm registry.

pnpm:

"dependencies": {
  "@game-infra/shared-utils": "link:../../../game-infra/packages/shared-utils"
}

npm:

"dependencies": {
  "@game-infra/shared-utils": "file:../../../game-infra/packages/shared-utils"
}

Usage

Compress a payload for transport
import { compressString, decompressString } from "@game-infra/shared-utils";

const packed = await compressString(JSON.stringify(payload));
// ... send over the wire as a base64 string ...
const restored = JSON.parse(await decompressString(packed));

decompressString also accepts URL-safe base64 (-/_) and unpadded input, so responses from servers that URL-safe-encode work without preprocessing. Raw byte variants compress/decompress skip the base64 step. Call initCompression() once at startup if you want the WASM load out of the hot path; otherwise it loads lazily on first use.

Validate that data survives JSON serialization
import { validateSerializable } from "@game-infra/shared-utils";

const check = validateSerializable(saveGameState);
if (!check.valid) {
  // e.g. "Data loss during serialization at root.inventory (Map not serializable)"
  throw new Error(check.error);
}

deepCompare(before, after) is the underlying primitive: it returns the path to the first difference between two values, flagging Map, Set, Date, function, RegExp, and Error values that JSON.stringify silently mangles.

Reproducible randomness
import { SeededRNG } from "@game-infra/shared-utils";

const rng = new SeededRNG(12345);
rng.randomInt(1, 6); // die roll, deterministic per seed
rng.weightedPick(["rare", "common"], [1, 9]);

// Persist and replay
const state = rng.getState();
const replay = new SeededRNG(rng.seed);
replay.setState(state);

Dependencies

No internal (@game-infra/*) dependencies. External: @hpcc-js/wasm-zstd.

Consumers

Planned consumers from later extraction phases: balance-tool, event-editor, sync-utils, and the backend services.