@jgengine/sql 0.18.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +504 -7
- package/package.json +2 -2
- package/skills/ce-handoff/SKILL.md +2 -2
- package/skills/jgengine/SKILL.md +28 -6
- package/skills/jgengine/api.md +139 -99
- package/skills/jgengine/capabilities.md +28 -0
- package/skills/jgengine/recipes/minimal-game.md +10 -2
- package/skills/jgengine-multiplayer/SKILL.md +3 -3
- package/skills/jgengine-multiplayer/api.md +91 -83
- package/skills/jgengine-multiplayer/reference.md +27 -3
- package/skills/jgengine-multiplayer/references/peer-worlds.md +62 -0
|
@@ -12,6 +12,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
12
12
|
|
|
13
13
|
- `collectAuthoredTriggers` (function) · `import { collectAuthoredTriggers } from "@jgengine/shell/gameKit"`
|
|
14
14
|
|
|
15
|
+
## chase-view-cycle — cycle a vehicle camera between chase, hood and cockpit views at runtime
|
|
16
|
+
|
|
17
|
+
- `nextChaseView` (function) · `import { nextChaseView } from "@jgengine/core/runtime/cameraDirector"`
|
|
18
|
+
|
|
15
19
|
## client-side — input prediction with replay reconciliation
|
|
16
20
|
|
|
17
21
|
- `createPredictionBuffer` (function) · `import { createPredictionBuffer } from "@jgengine/core/runtime/prediction"`
|
|
@@ -20,6 +24,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
20
24
|
|
|
21
25
|
- `GameContextModels` (interface) · `import { GameContextModels } from "@jgengine/core/runtime/gameContext"`
|
|
22
26
|
|
|
27
|
+
## command-number — validate finite, bounded numbers and integers at command boundaries
|
|
28
|
+
|
|
29
|
+
- `readInputNumber` (function) · `import { readInputNumber } from "@jgengine/core/runtime/commandInput"`
|
|
30
|
+
|
|
31
|
+
## command-parse — parse untrusted command input once so every command stage sees typed, bounded values
|
|
32
|
+
|
|
33
|
+
- `defineCommand` (function) · `import { defineCommand } from "@jgengine/core/runtime/commandRunner"`
|
|
34
|
+
|
|
23
35
|
## command-quantity — validate bounded whole-item counts at command boundaries
|
|
24
36
|
|
|
25
37
|
- `readQuantity` (function) · `import { readQuantity } from "@jgengine/core/runtime/commandInput"`
|
|
@@ -40,6 +52,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
40
52
|
|
|
41
53
|
- `EditorCatalogDefinition` (interface) · `import { EditorCatalogDefinition } from "@jgengine/shell/gameKit"`
|
|
42
54
|
|
|
55
|
+
## fire-input — bind a key or mouse button to a named action that runs the same-named command with the aim; repeatMs auto-fires while held
|
|
56
|
+
|
|
57
|
+
- `ActionCodesMap` (type) · `import { ActionCodesMap } from "@jgengine/core/authoring"`
|
|
58
|
+
|
|
43
59
|
## game-system — declare a composable capability with its own schedule and lifecycle
|
|
44
60
|
|
|
45
61
|
- `SystemDefinition` (interface) · `import { SystemDefinition } from "@jgengine/shell/gameKit"`
|
|
@@ -96,6 +112,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
96
112
|
|
|
97
113
|
- `createInputRecorder` (function) · `import { createInputRecorder } from "@jgengine/core/runtime/inputRecorder"`
|
|
98
114
|
|
|
115
|
+
## local-players — Couch co-op seats: devices hot-join into slots, each with its own user id and input snapshot.
|
|
116
|
+
|
|
117
|
+
- `createLocalPlayers` (function) · `import { createLocalPlayers } from "@jgengine/core/runtime/localPlayers"`
|
|
118
|
+
|
|
99
119
|
## loot-table — validate a loot table definition for use with the registry
|
|
100
120
|
|
|
101
121
|
- `lootTable` (function) · `import { lootTable } from "@jgengine/core/authoring"`
|
|
@@ -178,6 +198,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
178
198
|
|
|
179
199
|
- `defineStore` (function) · `import { defineStore } from "@jgengine/shell/gameKit"`
|
|
180
200
|
|
|
201
|
+
## warn-once — emit a dev-only warning a single time per call site
|
|
202
|
+
|
|
203
|
+
- `warnOnce` (function) · `import { warnOnce } from "@jgengine/core/devtools/warnOnce"`
|
|
204
|
+
|
|
181
205
|
## world-chunk-key — map world positions to persisted chunk keys at a declared cell size
|
|
182
206
|
|
|
183
207
|
- `chunkKeyOf` (function) · `import { chunkKeyOf } from "@jgengine/core/runtime/worldChunks"`
|
|
@@ -193,3 +217,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
193
217
|
## world-environment — compose editor/preset-derived outdoor dressing — terrain, weather, water, structures — into a legacy environment feature
|
|
194
218
|
|
|
195
219
|
- `environment` (function) · `import { environment } from "@jgengine/shell/gameKit"`
|
|
220
|
+
|
|
221
|
+
## world-item-pickup — pick up dropped items: ctx.scene.worldItem nearestInRadius → pickup into the player's inventory
|
|
222
|
+
|
|
223
|
+
- `SceneWorldItemContext` (interface) · `import { SceneWorldItemContext } from "@jgengine/core/runtime/gameContext"`
|
|
@@ -6,6 +6,11 @@ authored scene edited in the browser, one system, one store slot, an empty-canva
|
|
|
6
6
|
and a win condition. Every new game starts here; add combat, multiplayer, or deeper
|
|
7
7
|
world features only after this loop plays.
|
|
8
8
|
|
|
9
|
+
Every extension follows the [framework-first decision](../SKILL.md#framework-first-decisions):
|
|
10
|
+
compose an installed SDK capability, improve its upstream contract if needed, then
|
|
11
|
+
remove superseded game glue after published adoption. The game owns its rules and art;
|
|
12
|
+
it should not recreate input, model lifecycle, storage or UI accessibility machinery.
|
|
13
|
+
|
|
9
14
|
## 1. Scaffold
|
|
10
15
|
|
|
11
16
|
`npx jgengine create <name>` (inside the engine monorepo: `bun run new:game "<id-or-title>"`).
|
|
@@ -45,6 +50,9 @@ spatial place. When the game *is* a place, declare only substrate + laws with `w
|
|
|
45
50
|
`@jgengine/core/world/place` (e.g. `{ id, ground: { mode: "flat", size: { x: Infinity, z: Infinity } }, physics: { gravity: -24 } }`,
|
|
46
51
|
or `mode: "board"` for 2D). Never seed, sky, or vegetation in `world` — the engine renders its
|
|
47
52
|
default sky until you author one in the editor, and foliage is editor scatter over the ground.
|
|
53
|
+
A created 3D game instead ships hills as a terrain sculpt in `editor.scene.json` and a `world.ts`
|
|
54
|
+
that consumes it with `environment({ sculpt })` via `environmentContentFromDocument`; the file
|
|
55
|
+
holds only the ground palette. Reshape the hills in the editor, not in code.
|
|
48
56
|
|
|
49
57
|
|
|
50
58
|
```ts
|
|
@@ -77,8 +85,8 @@ direction. Compose the shipped building blocks the moment you need them (`StatBa
|
|
|
77
85
|
`Coins`, `InventoryGrid`, `CharacterSheet`, window shells from `jgengine-ui`), then reskin via
|
|
78
86
|
`HudTheme` tokens. Reaching for those is using the engine correctly, not incomplete work. What
|
|
79
87
|
the engine does not ship is a whole finished game *face* or genre theme preset — do not leave an
|
|
80
|
-
unarranged, unskinned generic dashboard as the product.
|
|
81
|
-
|
|
88
|
+
unarranged, unskinned generic dashboard as the product. Custom markup can use headless
|
|
89
|
+
SDK behavior; a missing reusable behavior is an upstream gap (see `jgengine-ui`).
|
|
82
90
|
|
|
83
91
|
## 3. Author, play, win
|
|
84
92
|
|
|
@@ -20,7 +20,7 @@ description: Design authority, transport, replication, sessions, and host persis
|
|
|
20
20
|
|
|
21
21
|
This skill owns network topology, authority, transports, sessions/presence, replication/projection, reconnect, hosted runners, and persistence adapters. Serializable game state and save semantics stay in `jgengine-gameplay`.
|
|
22
22
|
|
|
23
|
-
Use [capabilities.md](capabilities.md) for intent-to-import discovery, [api.md](api.md) for signatures, and [reference.md](reference.md) for transport, host, projection, persistence, and deployment recipes.
|
|
23
|
+
Use [capabilities.md](capabilities.md) for intent-to-import discovery, [api.md](api.md) for signatures, and [reference.md](reference.md) for transport, host, projection, persistence, and deployment recipes. See [playable peer worlds](references/peer-worlds.md) for authoritative browser co-op bootstrap and its release barrier.
|
|
24
24
|
|
|
25
25
|
## Canonical workflow
|
|
26
26
|
|
|
@@ -55,7 +55,7 @@ Use [capabilities.md](capabilities.md) for intent-to-import discovery, [api.md](
|
|
|
55
55
|
|
|
56
56
|
Use `createGameServerFunctions({ topology: "shared", runtimes })` for one persistent world. Shared topology defaults to singleton matchmaking. Capacity is not a throughput guarantee; verify the command and subscription read sets under crowd load. Subscribe to `getServerCapacity` for shared membership/status without volatile world revision reads.
|
|
57
57
|
|
|
58
|
-
Every gameplay command declares `scope(input)`: use `{ players: "actor", chunkKeys: [] }` for player-only work and `chunkKeysAround(position, 1)` for spatial work. The omitted-command default is actor-only with no chunks; an explicit `{}` requests the whole world and needs a justified bounded workload. Hosts use `helpers.runCommand` and its `beforePersist` callback to pair game writes with membership and revision checks in one transaction. Never copy that check/apply/persist loop into a game.
|
|
58
|
+
Every gameplay command declares `scope(input)`: use `{ players: "actor", chunkKeys: [] }` for player-only work and `chunkKeysAround(position, 1)` for spatial work. The omitted-command default is actor-only with no chunks; an explicit `{}` requests the whole world and needs a justified bounded workload. Hosts use `helpers.runCommand` and its `beforePersist` callback to pair game writes with membership and revision checks in one transaction. Never copy that check/apply/persist loop into a game. Declare commands with `defineCommand({ parse, scope, validate, apply })` and build `parse` from the `readInput*` readers in `@jgengine/core/runtime/commandInput` (finite, bounded numbers and points, capped strings and arrays): the runner refuses malformed input before `scope`, `validate` or `apply` run, so those stages never re-parse or trust raw values. Treat every field of a command's `input` as client-controlled: a command whose input carries facts only the host may decide (unlock state, prices, multipliers, whether a target exists) declares `access: "server"`, so the public `runCommand` and WebSocket clients are refused and only a host mutation calling `helpers.runCommand` (or `host.runCommand({ trusted: true })`) runs it. Read time from the `nowMs` argument, never from `input`.
|
|
59
59
|
|
|
60
60
|
Every presence query is neighborhood-scoped. Pass `PresenceSession.viewerChunkKey` through `createConvexPresenceTransport`. Hosts with custom authentication, bot ownership, or spawn policy use `createWorldPresenceStore` from `@jgengine/convex/worldPresence`: resolve trusted identities and access first, then call `ensure`, `sync`, `revoke`, `active`, `nearby`, and `reap`. Store rows in `jgPoses`, never a game-owned presence table. Optional snapshot callbacks persist game-owned last-position fields at the store's cadence. Bot identity may differ from its authorized owner; preserve that mapping explicitly. Resident rows implement `PresenceResidentRow.actorExternalId` and `ownerActorId` exactly.
|
|
61
61
|
|
|
@@ -67,6 +67,6 @@ A cron never collects a whole table. Use presence-gated `forEachOnlinePlayer` wi
|
|
|
67
67
|
|
|
68
68
|
Pass runtimes to `jgengineCronSpecs` so no tick cron registers when no runtime declares `onTick`; set per-spec `intervalSeconds` deliberately. Retention sweeps and one-shot backfills are bounded, report `remaining`, and stop at convergence. Delete completed migration crons instead of leaving hourly table scans installed forever.
|
|
69
69
|
|
|
70
|
-
Join failures return typed `full`, `closed`, or `unauthorized` outcomes. Surface them through a retry gate; returning a rejection without visible UI is unfinished. Browser adapters leave sessions on `pagehide`.
|
|
70
|
+
Join failures return typed `full`, `closed`, or `unauthorized` outcomes. Surface them through a retry gate; returning a rejection without visible UI is unfinished. Browser adapters leave sessions on `pagehide`. Membership is per client session: pass a fresh `sessionId` (`createTransportSessionId`) to each `joinServer` and its matching `leaveServer`, so a closed tab or a disposed mount never evicts a live one. A host mutation acting for a user who may have no live session calls `helpers.ensureJoined` before `helpers.runCommand`.
|
|
71
71
|
|
|
72
72
|
For the explicit shared-builder composition, `jgengine create "World Name" --shape shared-world-builder` generates the connected Convex shell, runtime scope declarations, claim/accrual examples, chat, indexed presence, and an online batch pipeline. The generated README owns setup; replace the demonstration economy and author buildable world content in the editor.
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
- `ConvexBackend` (type): type ConvexBackend<TPresenceRow = unknown, TPresenceLocation = unknown, TGameId extends string = string> = LiveGameBackend<TPresenceRow, TPresenceLocation, TGameId> & { leaderboard: ConvexLeaderboardReads; } — ⚠ undocumented
|
|
8
8
|
- `ConvexBackendOptions` (type): type ConvexBackendOptions<TRawPresenceRow extends { actorExternalId: string }, TPresenceRow> = { client: ConvexReactClient; gameId: string; userId: string; api?: ConvexGameApi; poseTuning?: PoseSyncTuning; presence?: { functions: ConvexPresenceFunctions; mapRow: (row: TRawPresenceRow) => TPresenceRo… — ⚠ undocumented
|
|
9
|
-
- `ConvexChatFunctions` (interface): interface ConvexChatFunctions — ⚠ undocumented
|
|
10
|
-
- `ConvexGameApi` (type): type ConvexGameApi = { runtime: { joinServer: FunctionReference< "mutation", "public", { gameId: string; serverId?: string; mode?: string; visibility?: "public" | "private"; joinCode?: string; externalId?: string; }, JoinServerOutcome >; leaveServer: FunctionReference<"mutation"
|
|
9
|
+
- `ConvexChatFunctions` (interface): interface ConvexChatFunctions { messages: FunctionReference<"query">; sendMessage: FunctionReference<"mutation"> } — ⚠ undocumented · used by `createConvexChatTransport`: Wires a game's Convex chat functions into the engine's ChatTransport contract: one live query per subscribed channel (the channel's recent h…
|
|
10
|
+
- `ConvexGameApi` (type): type ConvexGameApi = { runtime: { joinServer: FunctionReference< "mutation", "public", { gameId: string; serverId?: string; mode?: string; visibility?: "public" | "private"; joinCode?: string; externalId?: string; sessionId?: string; }, JoinServerOutcome >; leaveServer: FunctionReference<"mutation",… — ⚠ undocumented
|
|
11
11
|
- `ConvexGameClient` (type): type ConvexGameClient = Pick<ConvexReactClient, "mutation" | "watchQuery"> — Structural client seam avoids requiring the engine and game to share a class instance type.
|
|
12
12
|
- `ConvexGameTransportConfig` (type): type ConvexGameTransportConfig = { gameId: string; userId?: string; } — ⚠ undocumented
|
|
13
13
|
- `ConvexLeaderboardReads` (type): type ConvexLeaderboardReads = ReturnType<typeof createConvexLeaderboardReads> — ⚠ undocumented
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
- `ConvexSaveFunctions` (interface): interface ConvexSaveFunctions — The three Convex functions a save backend calls — a `query` that returns the stored string (or `null`) and two `mutation`s. Point them at your app's own module, or lean on the default `saves.*` convention.
|
|
17
17
|
- `DEFAULT_CONVEX_POSE_RULES` (const): const DEFAULT_CONVEX_POSE_RULES: PoseSyncRules — ⚠ undocumented
|
|
18
18
|
- `DEFAULT_MAX_SERVERS_PER_TICK` (const): const DEFAULT_MAX_SERVERS_PER_TICK: 32 — How many running servers one `tickActiveServers` transaction may hydrate, tick, and persist.
|
|
19
|
+
- `EnsureJoinedOutcome` (type): type EnsureJoinedOutcome = | { ok: true; serverId: GenericId<"jgGameServers">; isNew: boolean } | { ok: false; reason: "full" | "closed" | "unauthorized" } — Outcome of a join: the server joined and whether the player's profile was created, or why it was refused.
|
|
19
20
|
- `GameServerHelpers` (type): type GameServerHelpers = { ensureServer: (ctx: JGMutationCtx, gameId: string) => Promise<ServerDoc>; loadSnapshot: ( ctx: JGMutationCtx, serverId: string, scope?: LoadSnapshotScope, ) => Promise<LoadedServerSnapshot | null>; applyCommand: (args: { gameId: string; loadedRevision: number; currentRevis… — The plain-function half of {@link createGameServerFunctions}, bound to the same runtime registry and auth mode as its mutations. Reach for it when a host mutation must pair snapshot work with its own table writes in one transaction, which a pre-registered mutation cannot do.
|
|
20
21
|
- `HostedGameConfig` (interface): interface HostedGameConfig — One game the hosted path can serve, bound per `gameId`: its definition plus content lookup.
|
|
21
22
|
- `HostedWorldInvocation` (interface): interface HostedWorldInvocation<T> — Everything one stateless invocation reconstructs a hosted world from: the persisted record via `store`, plus the member roster and held inputs the snapshot doesn't carry, and the op to apply to the fresh session.
|
|
@@ -31,6 +32,8 @@
|
|
|
31
32
|
- `LoadSnapshotScope` (type): type LoadSnapshotScope = CommandScope — How much of a server to hydrate. Both fields default to "everything", which is a document read per member plus one per chunk — the cost that makes a large shared world unaffordable per mutation. Narrow them when the caller knows what it will touch: a command that only moves the actor's own state needs `players: [actorUserId]`, and a spatial edit needs only the chunk keys it writes (`chunkKeysInRadius` from `@jgengine/core/runtime/worldChunks`).
|
|
32
33
|
- `LoadedServerSnapshot` (type): type LoadedServerSnapshot = { server: ServerDoc; runtime: GameRuntime; snapshot: GameRuntimeSnapshot; } — A server resolved for runtime work: its row, its registered runtime, and its hydrated snapshot.
|
|
33
34
|
- `MAX_CHUNKS_PER_QUERY` (const): const MAX_CHUNKS_PER_QUERY: 64 — How many chunk rows one `getChunks` call may return.
|
|
35
|
+
- `MAX_MEMBER_SESSIONS` (const): const MAX_MEMBER_SESSIONS: 16 — Most live client sessions one shared-topology membership remembers; the oldest drop first.
|
|
36
|
+
- `MAX_SESSION_ID_LENGTH` (const): const MAX_SESSION_ID_LENGTH: 128 — Longest accepted client `sessionId`.
|
|
34
37
|
- `MatchmakingMode` (type): type MatchmakingMode = "auto" | "singleton" — How auto-match behaves when no `serverId` is supplied.
|
|
35
38
|
- `OnlinePlayer` (type): type OnlinePlayer = { serverId: string; userId: string; homeGameId?: string } — One active player delivered to an online-system batch.
|
|
36
39
|
- `PresenceListRow` (type): type PresenceListRow = { userId: string; sessionId?: string; kind?: string; label?: string; position: { x: number; y: number; z: number }; rotationY: number; rotationPitch: number; lastSeenAt: number; } — One member's pose as `list` reports it.
|
|
@@ -67,7 +70,7 @@
|
|
|
67
70
|
|
|
68
71
|
## @jgengine/convex/convexChatTransport
|
|
69
72
|
|
|
70
|
-
- `ConvexChatFunctions` (interface): interface ConvexChatFunctions — ⚠ undocumented
|
|
73
|
+
- `ConvexChatFunctions` (interface): interface ConvexChatFunctions { messages: FunctionReference<"query">; sendMessage: FunctionReference<"mutation"> } — ⚠ undocumented · used by `createConvexChatTransport`: Wires a game's Convex chat functions into the engine's ChatTransport contract: one live query per subscribed channel (the channel's recent h…
|
|
71
74
|
- `createConvexChatTransport` (function): function createConvexChatTransport<TRawRow = ChatMessage>(functions: ConvexChatFunctions, options?: { mapRow?: (row: TRawRow) => ChatMessage; extraArgs?: Record<string, unknown>; }): ChatTransport — Wires a game's Convex chat functions into the engine's ChatTransport contract: one live query per subscribed channel (the channel's recent history, newest last) and one send mutation. mapRow converts backend rows into ChatMessage (defaults to structural passthrough); extraArgs is spread into both calls for games that scope chat by server or world.
|
|
72
75
|
|
|
73
76
|
## @jgengine/convex/convexPresenceTransport
|
|
@@ -91,7 +94,7 @@
|
|
|
91
94
|
|
|
92
95
|
## @jgengine/convex/createConvexGameTransport
|
|
93
96
|
|
|
94
|
-
- `ConvexGameApi` (type): type ConvexGameApi = { runtime: { joinServer: FunctionReference< "mutation", "public", { gameId: string; serverId?: string; mode?: string; visibility?: "public" | "private"; joinCode?: string; externalId?: string; }, JoinServerOutcome >; leaveServer: FunctionReference<"mutation"
|
|
97
|
+
- `ConvexGameApi` (type): type ConvexGameApi = { runtime: { joinServer: FunctionReference< "mutation", "public", { gameId: string; serverId?: string; mode?: string; visibility?: "public" | "private"; joinCode?: string; externalId?: string; sessionId?: string; }, JoinServerOutcome >; leaveServer: FunctionReference<"mutation",… — ⚠ undocumented
|
|
95
98
|
- `ConvexGameClient` (type): type ConvexGameClient = Pick<ConvexReactClient, "mutation" | "watchQuery"> — Structural client seam avoids requiring the engine and game to share a class instance type.
|
|
96
99
|
- `ConvexGameTransportConfig` (type): type ConvexGameTransportConfig = { gameId: string; userId?: string; } — ⚠ undocumented
|
|
97
100
|
- `createConvexChatSync` (function): function createConvexChatSync(client: ConvexGameClient, api: ConvexGameApi, config: ConvexGameTransportConfig, serverId: string): ChatSync — ⚠ undocumented
|
|
@@ -123,6 +126,7 @@
|
|
|
123
126
|
|
|
124
127
|
- `DEFAULT_CONVEX_POSE_RULES` (const): const DEFAULT_CONVEX_POSE_RULES: PoseSyncRules — ⚠ undocumented
|
|
125
128
|
- `DEFAULT_MAX_SERVERS_PER_TICK` (const): const DEFAULT_MAX_SERVERS_PER_TICK: 32 — How many running servers one `tickActiveServers` transaction may hydrate, tick, and persist.
|
|
129
|
+
- `EnsureJoinedOutcome` (type): type EnsureJoinedOutcome = | { ok: true; serverId: GenericId<"jgGameServers">; isNew: boolean } | { ok: false; reason: "full" | "closed" | "unauthorized" } — Outcome of a join: the server joined and whether the player's profile was created, or why it was refused.
|
|
126
130
|
- `GameServerHelpers` (type): type GameServerHelpers = { ensureServer: (ctx: JGMutationCtx, gameId: string) => Promise<ServerDoc>; loadSnapshot: ( ctx: JGMutationCtx, serverId: string, scope?: LoadSnapshotScope, ) => Promise<LoadedServerSnapshot | null>; applyCommand: (args: { gameId: string; loadedRevision: number; currentRevis… — The plain-function half of {@link createGameServerFunctions}, bound to the same runtime registry and auth mode as its mutations. Reach for it when a host mutation must pair snapshot work with its own table writes in one transaction, which a pre-registered mutation cannot do.
|
|
127
131
|
- `JGDataModel` (type): type JGDataModel = DataModelFromSchemaDefinition<typeof schemaForTypes> — Data model of the {@link jgengineTables} schema — the shape a host's own Convex ctx must satisfy to call the exported persistence helpers.
|
|
128
132
|
- `JGMutationCtx` (type): type JGMutationCtx = GenericMutationCtx<JGDataModel> — Mutation ctx accepted by {@link loadServerSnapshot} / {@link persistServerSnapshot}.
|
|
@@ -134,6 +138,8 @@
|
|
|
134
138
|
- `LoadSnapshotScope` (type): type LoadSnapshotScope = CommandScope — How much of a server to hydrate. Both fields default to "everything", which is a document read per member plus one per chunk — the cost that makes a large shared world unaffordable per mutation. Narrow them when the caller knows what it will touch: a command that only moves the actor's own state needs `players: [actorUserId]`, and a spatial edit needs only the chunk keys it writes (`chunkKeysInRadius` from `@jgengine/core/runtime/worldChunks`).
|
|
135
139
|
- `LoadedServerSnapshot` (type): type LoadedServerSnapshot = { server: ServerDoc; runtime: GameRuntime; snapshot: GameRuntimeSnapshot; } — A server resolved for runtime work: its row, its registered runtime, and its hydrated snapshot.
|
|
136
140
|
- `MAX_CHUNKS_PER_QUERY` (const): const MAX_CHUNKS_PER_QUERY: 64 — How many chunk rows one `getChunks` call may return.
|
|
141
|
+
- `MAX_MEMBER_SESSIONS` (const): const MAX_MEMBER_SESSIONS: 16 — Most live client sessions one shared-topology membership remembers; the oldest drop first.
|
|
142
|
+
- `MAX_SESSION_ID_LENGTH` (const): const MAX_SESSION_ID_LENGTH: 128 — Longest accepted client `sessionId`.
|
|
137
143
|
- `MatchmakingMode` (type): type MatchmakingMode = "auto" | "singleton" — How auto-match behaves when no `serverId` is supplied.
|
|
138
144
|
- `OnlinePlayer` (type): type OnlinePlayer = { serverId: string; userId: string; homeGameId?: string } — One active player delivered to an online-system batch.
|
|
139
145
|
- `PresenceListRow` (type): type PresenceListRow = { userId: string; sessionId?: string; kind?: string; label?: string; position: { x: number; y: number; z: number }; rotationY: number; rotationPitch: number; lastSeenAt: number; } — One member's pose as `list` reports it.
|
|
@@ -166,32 +172,32 @@
|
|
|
166
172
|
|
|
167
173
|
## @jgengine/core/multiplayer
|
|
168
174
|
|
|
169
|
-
- `AuthSession` (interface): interface AuthSession — ⚠ undocumented
|
|
170
|
-
- `BoardSnapshot` (interface): interface BoardSnapshot — ⚠ undocumented
|
|
171
|
-
- `ChatActions` (interface): interface ChatActions — ⚠ undocumented
|
|
172
|
-
- `ChatSendOutcome` (interface): interface ChatSendOutcome — ⚠ undocumented
|
|
175
|
+
- `AuthSession` (interface): interface AuthSession { userId: string; displayName?: string; avatarUrl?: string; email?: string; isNew?: boolean } — ⚠ undocumented
|
|
176
|
+
- `BoardSnapshot` (interface): interface BoardSnapshot { ownerId: string; units: readonly SnapshotUnit[]; stats: Readonly<Record<string, number>>; seed: number; capturedAt: number } — ⚠ undocumented
|
|
177
|
+
- `ChatActions` (interface): interface ChatActions { sendMessage(args: ChatSendArgs): Promise<ChatSendOutcome> } — ⚠ undocumented
|
|
178
|
+
- `ChatSendOutcome` (interface): interface ChatSendOutcome { ok: boolean; reason?: string } — ⚠ undocumented · used by `sendChatMessage` (@jgengine/convex): Write validated chat in a host transaction after the caller resolves its actor and world.
|
|
173
179
|
- `ChatSync` (interface): interface ChatSync — Callback seam for backends that cannot host React hooks (e.g. the ws client): subscribe delivers the channel's recent history on every change; send resolves with the host's verdict.
|
|
174
180
|
- `ChatTransport` (interface): interface ChatTransport — Backend seam for remote text chat, mirroring PresenceTransport: the use* members are called as React hooks by consumers, so a mounted transport must never change identity — remount the subtree to switch backends. useMessages returns undefined while the subscription is loading and the channel's recent history once live.
|
|
175
|
-
- `EnsurePresenceResult` (interface): interface EnsurePresenceResult — ⚠ undocumented
|
|
181
|
+
- `EnsurePresenceResult` (interface): interface EnsurePresenceResult { presenceId: string; position: PresencePosition; rotationY: number } — ⚠ undocumented
|
|
176
182
|
- `FeedWriteGate` (type): type FeedWriteGate = { allowedActions: readonly string[]; } — ⚠ undocumented
|
|
177
|
-
- `MatchFilter` (interface): interface MatchFilter — ⚠ undocumented
|
|
178
|
-
- `PlayerIdentity` (interface): interface PlayerIdentity — ⚠ undocumented
|
|
179
|
-
- `PlayerPose` (interface): interface PlayerPose — ⚠ undocumented
|
|
180
|
-
- `PoseSyncRules` (interface): interface PoseSyncRules — ⚠ undocumented
|
|
181
|
-
- `PoseSyncTuning` (interface): interface PoseSyncTuning — ⚠ undocumented
|
|
182
|
-
- `PresenceActions` (interface): interface PresenceActions<TGameId extends string = string> — ⚠ undocumented
|
|
183
|
-
- `PresenceFeeds` (interface): interface PresenceFeeds<TRow, TLocation> — ⚠ undocumented
|
|
184
|
-
- `PresencePoseState` (interface): interface PresencePoseState — ⚠ undocumented
|
|
185
|
-
- `PresenceSession` (interface): interface PresenceSession<TGameId extends string = string> — ⚠ undocumented
|
|
183
|
+
- `MatchFilter` (interface): interface MatchFilter { mode?: string; tags?: readonly string[]; query?: string; notFull?: boolean; status?: readonly SessionStatus[]; includePrivate?: boolean } — ⚠ undocumented · used by `useWorldBrowser` (@jgengine/react): Polls a host-supplied session fetcher (e.g.
|
|
184
|
+
- `PlayerIdentity` (interface): interface PlayerIdentity { userId: string; isNew: boolean } — ⚠ undocumented
|
|
185
|
+
- `PlayerPose` (interface): interface PlayerPose { x: number; y: number; z: number; rotationY: number; rotationPitch: number; appearance?: Record<string, string> } — ⚠ undocumented
|
|
186
|
+
- `PoseSyncRules` (interface): interface PoseSyncRules { maxSpeed: number; minIntervalMs?: number; maxVerticalOffset: number; floorY?: number; minElapsedSec: number; maxElapsedSec: number; keepAliveRefreshMs: number } — ⚠ undocumented · used by `DEFAULT_POSE_SYNC_RULES` (@jgengine/core/multiplayer/presenceModel): Canonical client-authoritative pose-sync tuning shared by every host transport (WS, Convex).
|
|
187
|
+
- `PoseSyncTuning` (interface): interface PoseSyncTuning { minIntervalMs: number; heartbeatMs: number; positionEpsilon: number; verticalEpsilon: number; rotationEpsilon: number } — ⚠ undocumented · used by `DEFAULT_POSE_SYNC_TUNING` (@jgengine/core/multiplayer/poseSyncGate): Default ten-hertz client pose gate with a five-second heartbeat.
|
|
188
|
+
- `PresenceActions` (interface): interface PresenceActions<TGameId extends string = string> { ensurePresence(args: EnsurePresenceArgs<TGameId>): Promise<EnsurePresenceResult | null>; leavePresence(args: LeavePresenceArgs<TGameId>): Promise<{left: boolean}>; syncPose(pose: PresencePose): void } — ⚠ undocumented
|
|
189
|
+
- `PresenceFeeds` (interface): interface PresenceFeeds<TRow, TLocation> { myPresenceLocation: TLocation | null | undefined; onlinePresences: readonly TRow[] | undefined; dormantPresences: readonly TRow[] | undefined } — ⚠ undocumented
|
|
190
|
+
- `PresencePoseState` (interface): interface PresencePoseState { position: {x: number; y: number; z: number}; rotationY: number; rotationPitch?: number; lastSeenAtMs?: number; appearance?: Record<string, string> } — ⚠ undocumented
|
|
191
|
+
- `PresenceSession` (interface): interface PresenceSession<TGameId extends string = string> { homeGameId: TGameId; externalId: string; viewerChunkKey?: string } — ⚠ undocumented
|
|
186
192
|
- `PresenceTransport` (interface): interface PresenceTransport<TRow, TLocation, TGameId extends string = string> — Backend seam for multiplayer presence. Feeds are reactive data and change identity whenever any player's pose updates; actions MUST be identity-stable for the lifetime of a mounted session so join/leave lifecycle effects can depend on them without re-running per pose tick. The use* members are called as React hooks by consumers, so a mounted transport must never change identity — remount the subtree to switch backends.
|
|
187
193
|
- `PushToTalkMode` (type): type PushToTalkMode = "hold" | "toggle" | "openMic" — ⚠ undocumented
|
|
188
194
|
- `PushToTalkStatus` (type): type PushToTalkStatus = "idle" | "keyed" | "open" — ⚠ undocumented
|
|
189
195
|
- `ReplicationPolicy` (interface): interface ReplicationPolicy — Host-side interest/privacy policy — how the authoritative world projects to each viewer over the wire. Unset (the default) means every client receives the whole world, exactly as before. Enabling a field changes only what each client *sees*, never how the host simulates: the game plays identically. The core replication modules read this to attach a {@link SnapshotModule.project} without the engine growing a per-feature branch.
|
|
190
|
-
- `SessionListing` (interface): interface SessionListing — ⚠ undocumented
|
|
191
|
-
- `SessionVisibility` (type): type SessionVisibility = "public" | "private" — ⚠ undocumented
|
|
192
|
-
- `Vec3` (interface): interface Vec3 — ⚠ undocumented
|
|
193
|
-
- `VoiceParticipant` (interface): interface VoiceParticipant — ⚠ undocumented
|
|
194
|
-
- `VoiceRoute` (interface): interface VoiceRoute — ⚠ undocumented
|
|
196
|
+
- `SessionListing` (interface): interface SessionListing { serverId: string; gameId: string; status: SessionStatus; visibility: SessionVisibility; memberCount: number; slotsPerServer: number; label?: string; mode?: string; joinCode?: string; tags?: readonly string[]; updatedAt: number } — ⚠ undocumented · used by `useWorldBrowser` (@jgengine/react): Polls a host-supplied session fetcher (e.g.
|
|
197
|
+
- `SessionVisibility` (type): type SessionVisibility = "public" | "private" — ⚠ undocumented · used by `isAutoJoinCandidate` (@jgengine/core/runtime/hostPolicy): Auto-match candidate when no `serverId` is supplied: already a member, or a public room with free capacity.
|
|
198
|
+
- `Vec3` (interface): interface Vec3 { x: number; y: number; z: number } — ⚠ undocumented · used by `coverPoints` (@jgengine/core/ai/tacticalQueries): Returns boundary locations that are hidden from a threat.
|
|
199
|
+
- `VoiceParticipant` (interface): interface VoiceParticipant { userId: string; streamId?: string } — ⚠ undocumented
|
|
200
|
+
- `VoiceRoute` (interface): interface VoiceRoute { fromUserId: string; channelId: string; gain: number } — ⚠ undocumented
|
|
195
201
|
- `VoiceTransport` (interface): interface VoiceTransport — Signaling seam for voice: who is in a channel and which media stream descriptor they published. The media plane (WebRTC, SFU, or anything else that moves audio bytes) stays behind this seam, host-supplied — the engine never touches it. subscribers delivers the channel roster on every change, starting with the current roster.
|
|
196
202
|
- `browseSessions` (function): function browseSessions(listings: readonly SessionListing[], filter: MatchFilter = {}, options: BrowseOptions = {}): SessionListing[] — ⚠ undocumented
|
|
197
203
|
- `createFeedWriteGate` (function): function createFeedWriteGate(allowedActions: readonly string[] = []): FeedWriteGate — ⚠ undocumented
|
|
@@ -209,22 +215,22 @@
|
|
|
209
215
|
|
|
210
216
|
## @jgengine/core/multiplayer/chatContract
|
|
211
217
|
|
|
212
|
-
- `ChatActions` (interface): interface ChatActions — ⚠ undocumented
|
|
213
|
-
- `ChatSendArgs` (interface): interface ChatSendArgs — ⚠ undocumented
|
|
214
|
-
- `ChatSendOutcome` (interface): interface ChatSendOutcome — ⚠ undocumented
|
|
218
|
+
- `ChatActions` (interface): interface ChatActions { sendMessage(args: ChatSendArgs): Promise<ChatSendOutcome> } — ⚠ undocumented
|
|
219
|
+
- `ChatSendArgs` (interface): interface ChatSendArgs { channelId: string; body: string } — ⚠ undocumented
|
|
220
|
+
- `ChatSendOutcome` (interface): interface ChatSendOutcome { ok: boolean; reason?: string } — ⚠ undocumented · used by `sendChatMessage` (@jgengine/convex): Write validated chat in a host transaction after the caller resolves its actor and world.
|
|
215
221
|
- `ChatSync` (interface): interface ChatSync — Callback seam for backends that cannot host React hooks (e.g. the ws client): subscribe delivers the channel's recent history on every change; send resolves with the host's verdict.
|
|
216
222
|
- `ChatTransport` (interface): interface ChatTransport — Backend seam for remote text chat, mirroring PresenceTransport: the use* members are called as React hooks by consumers, so a mounted transport must never change identity — remount the subtree to switch backends. useMessages returns undefined while the subscription is loading and the channel's recent history once live.
|
|
217
223
|
- `createLocalChatTransport` (function): function createLocalChatTransport(options?: { userId?: string; historyLimit?: number; now?: () => number; }): { transport: ChatTransport; sync: ChatSync; actions: ChatActions; } — ⚠ undocumented
|
|
218
224
|
|
|
219
225
|
## @jgengine/core/multiplayer/combatSnapshot
|
|
220
226
|
|
|
221
|
-
- `BoardSnapshot` (interface): interface BoardSnapshot — ⚠ undocumented
|
|
222
|
-
- `CombatRules` (interface): interface CombatRules — ⚠ undocumented
|
|
227
|
+
- `BoardSnapshot` (interface): interface BoardSnapshot { ownerId: string; units: readonly SnapshotUnit[]; stats: Readonly<Record<string, number>>; seed: number; capturedAt: number } — ⚠ undocumented
|
|
228
|
+
- `CombatRules` (interface): interface CombatRules { attackStat: string; healthStat: string; maxRounds?: number; critChance?: number; critMultiplier?: number } — ⚠ undocumented
|
|
223
229
|
- `CombatSide` (type): type CombatSide = "a" | "b" | "draw" — ⚠ undocumented
|
|
224
|
-
- `ReplayBlow` (interface): interface ReplayBlow — ⚠ undocumented
|
|
225
|
-
- `ReplayResult` (interface): interface ReplayResult — ⚠ undocumented
|
|
226
|
-
- `SerializeBoardArgs` (interface): interface SerializeBoardArgs — ⚠ undocumented
|
|
227
|
-
- `SnapshotUnit` (interface): interface SnapshotUnit — ⚠ undocumented
|
|
230
|
+
- `ReplayBlow` (interface): interface ReplayBlow { round: number; attacker: CombatSide; attackerUnit: string; defenderUnit: string; damage: number; crit: boolean; defenderHealthAfter: number } — ⚠ undocumented
|
|
231
|
+
- `ReplayResult` (interface): interface ReplayResult { winner: CombatSide; rounds: number; blows: readonly ReplayBlow[]; survivorsA: readonly string[]; survivorsB: readonly string[] } — ⚠ undocumented
|
|
232
|
+
- `SerializeBoardArgs` (interface): interface SerializeBoardArgs { ownerId: string; units: readonly SnapshotUnit[]; stats?: Readonly<Record<string, number>>; seed?: number; capturedAt?: number } — ⚠ undocumented
|
|
233
|
+
- `SnapshotUnit` (interface): interface SnapshotUnit { id: string; stats: Readonly<Record<string, number>> } — ⚠ undocumented
|
|
228
234
|
|
|
229
235
|
## @jgengine/core/multiplayer/feedWriteGate
|
|
230
236
|
|
|
@@ -234,27 +240,27 @@
|
|
|
234
240
|
|
|
235
241
|
## @jgengine/core/multiplayer/identity
|
|
236
242
|
|
|
237
|
-
- `AuthSession` (interface): interface AuthSession — ⚠ undocumented
|
|
238
|
-
- `PlayerIdentity` (interface): interface PlayerIdentity — ⚠ undocumented
|
|
243
|
+
- `AuthSession` (interface): interface AuthSession { userId: string; displayName?: string; avatarUrl?: string; email?: string; isNew?: boolean } — ⚠ undocumented
|
|
244
|
+
- `PlayerIdentity` (interface): interface PlayerIdentity { userId: string; isNew: boolean } — ⚠ undocumented
|
|
239
245
|
- `resolveGuestSession` (function): function resolveGuestSession(seed?: string): AuthSession — ⚠ undocumented
|
|
240
246
|
- `sessionPlayer` (function): function sessionPlayer(session: AuthSession): PlayerIdentity — ⚠ undocumented
|
|
241
247
|
|
|
242
248
|
## @jgengine/core/multiplayer/lagCompensation
|
|
243
249
|
|
|
244
|
-
- `HitscanHit` (interface): interface HitscanHit — ⚠ undocumented
|
|
245
|
-
- `HitscanRay` (interface): interface HitscanRay — ⚠ undocumented
|
|
246
|
-
- `HitscanTarget` (interface): interface HitscanTarget — ⚠ undocumented
|
|
247
|
-
- `PositionHistoryConfig` (interface): interface PositionHistoryConfig — ⚠ undocumented
|
|
248
|
-
- `PositionSample` (interface): interface PositionSample extends Vec3 — ⚠ undocumented
|
|
249
|
-
- `Vec3` (interface): interface Vec3 — ⚠ undocumented
|
|
250
|
+
- `HitscanHit` (interface): interface HitscanHit { entityId: string; distance: number; point: Vec3 } — ⚠ undocumented
|
|
251
|
+
- `HitscanRay` (interface): interface HitscanRay { origin: Vec3; direction: Vec3; maxDistance?: number } — ⚠ undocumented
|
|
252
|
+
- `HitscanTarget` (interface): interface HitscanTarget { entityId: string; radius: number } — ⚠ undocumented
|
|
253
|
+
- `PositionHistoryConfig` (interface): interface PositionHistoryConfig { historyMs: number; maxSamples?: number } — ⚠ undocumented
|
|
254
|
+
- `PositionSample` (interface): interface PositionSample extends Vec3 { t: number } — ⚠ undocumented
|
|
255
|
+
- `Vec3` (interface): interface Vec3 { x: number; y: number; z: number } — ⚠ undocumented · used by `coverPoints` (@jgengine/core/ai/tacticalQueries): Returns boundary locations that are hidden from a threat.
|
|
250
256
|
|
|
251
257
|
## @jgengine/core/multiplayer/matchmaking
|
|
252
258
|
|
|
253
|
-
- `BrowseOptions` (interface): interface BrowseOptions — ⚠ undocumented
|
|
254
|
-
- `MatchFilter` (interface): interface MatchFilter — ⚠ undocumented
|
|
255
|
-
- `SessionListing` (interface): interface SessionListing — ⚠ undocumented
|
|
259
|
+
- `BrowseOptions` (interface): interface BrowseOptions { limit?: number } — ⚠ undocumented
|
|
260
|
+
- `MatchFilter` (interface): interface MatchFilter { mode?: string; tags?: readonly string[]; query?: string; notFull?: boolean; status?: readonly SessionStatus[]; includePrivate?: boolean } — ⚠ undocumented · used by `useWorldBrowser` (@jgengine/react): Polls a host-supplied session fetcher (e.g.
|
|
261
|
+
- `SessionListing` (interface): interface SessionListing { serverId: string; gameId: string; status: SessionStatus; visibility: SessionVisibility; memberCount: number; slotsPerServer: number; label?: string; mode?: string; joinCode?: string; tags?: readonly string[]; updatedAt: number } — ⚠ undocumented · used by `useWorldBrowser` (@jgengine/react): Polls a host-supplied session fetcher (e.g.
|
|
256
262
|
- `SessionStatus` (type): type SessionStatus = "open" | "running" | "closed" — ⚠ undocumented
|
|
257
|
-
- `SessionVisibility` (type): type SessionVisibility = "public" | "private" — ⚠ undocumented
|
|
263
|
+
- `SessionVisibility` (type): type SessionVisibility = "public" | "private" — ⚠ undocumented · used by `isAutoJoinCandidate` (@jgengine/core/runtime/hostPolicy): Auto-match candidate when no `serverId` is supplied: already a member, or a public room with free capacity.
|
|
258
264
|
- `browseSessions` (function): function browseSessions(listings: readonly SessionListing[], filter: MatchFilter = {}, options: BrowseOptions = {}): SessionListing[] — ⚠ undocumented
|
|
259
265
|
- `findByJoinCode` (function): function findByJoinCode(listings: readonly SessionListing[], code: string): SessionListing | null — ⚠ undocumented
|
|
260
266
|
- `generateJoinCode` (function): function generateJoinCode(random: () => number, length = 6): string — ⚠ undocumented
|
|
@@ -266,49 +272,49 @@
|
|
|
266
272
|
## @jgengine/core/multiplayer/poseSyncGate
|
|
267
273
|
|
|
268
274
|
- `DEFAULT_POSE_SYNC_TUNING` (const): const DEFAULT_POSE_SYNC_TUNING: PoseSyncTuning — Default ten-hertz client pose gate with a five-second heartbeat.
|
|
269
|
-
- `PlayerPose` (interface): interface PlayerPose — ⚠ undocumented
|
|
270
|
-
- `PoseSyncGate` (interface): interface PoseSyncGate — ⚠ undocumented
|
|
271
|
-
- `PoseSyncTuning` (interface): interface PoseSyncTuning — ⚠ undocumented
|
|
275
|
+
- `PlayerPose` (interface): interface PlayerPose { x: number; y: number; z: number; rotationY: number; rotationPitch: number; appearance?: Record<string, string> } — ⚠ undocumented
|
|
276
|
+
- `PoseSyncGate` (interface): interface PoseSyncGate { evaluate(pose: PlayerPose, nowMs: number): boolean } — ⚠ undocumented
|
|
277
|
+
- `PoseSyncTuning` (interface): interface PoseSyncTuning { minIntervalMs: number; heartbeatMs: number; positionEpsilon: number; verticalEpsilon: number; rotationEpsilon: number } — ⚠ undocumented · used by `DEFAULT_POSE_SYNC_TUNING`: Default ten-hertz client pose gate with a five-second heartbeat.
|
|
272
278
|
- `createPoseSyncGate` (function): function createPoseSyncGate(tuning: PoseSyncTuning = DEFAULT_POSE_SYNC_TUNING): PoseSyncGate — ⚠ undocumented
|
|
273
279
|
|
|
274
280
|
## @jgengine/core/multiplayer/presenceContract
|
|
275
281
|
|
|
276
|
-
- `EnsurePresenceArgs` (interface): interface EnsurePresenceArgs<TGameId extends string = string> — ⚠ undocumented
|
|
277
|
-
- `EnsurePresenceResult` (interface): interface EnsurePresenceResult — ⚠ undocumented
|
|
278
|
-
- `LeavePresenceArgs` (interface): interface LeavePresenceArgs<TGameId extends string = string> — ⚠ undocumented
|
|
279
|
-
- `PresenceActions` (interface): interface PresenceActions<TGameId extends string = string> — ⚠ undocumented
|
|
280
|
-
- `PresenceFeeds` (interface): interface PresenceFeeds<TRow, TLocation> — ⚠ undocumented
|
|
281
|
-
- `PresencePose` (interface): interface PresencePose — ⚠ undocumented
|
|
282
|
-
- `PresencePosition` (interface): interface PresencePosition — ⚠ undocumented
|
|
282
|
+
- `EnsurePresenceArgs` (interface): interface EnsurePresenceArgs<TGameId extends string = string> { gameId: TGameId; externalId: string } — ⚠ undocumented
|
|
283
|
+
- `EnsurePresenceResult` (interface): interface EnsurePresenceResult { presenceId: string; position: PresencePosition; rotationY: number } — ⚠ undocumented
|
|
284
|
+
- `LeavePresenceArgs` (interface): interface LeavePresenceArgs<TGameId extends string = string> { gameId: TGameId; externalId: string } — ⚠ undocumented
|
|
285
|
+
- `PresenceActions` (interface): interface PresenceActions<TGameId extends string = string> { ensurePresence(args: EnsurePresenceArgs<TGameId>): Promise<EnsurePresenceResult | null>; leavePresence(args: LeavePresenceArgs<TGameId>): Promise<{left: boolean}>; syncPose(pose: PresencePose): void } — ⚠ undocumented
|
|
286
|
+
- `PresenceFeeds` (interface): interface PresenceFeeds<TRow, TLocation> { myPresenceLocation: TLocation | null | undefined; onlinePresences: readonly TRow[] | undefined; dormantPresences: readonly TRow[] | undefined } — ⚠ undocumented
|
|
287
|
+
- `PresencePose` (interface): interface PresencePose { position: {x: number; y?: number; z: number}; rotationY?: number; rotationPitch?: number; externalId?: string } — ⚠ undocumented
|
|
288
|
+
- `PresencePosition` (interface): interface PresencePosition { x: number; y: number; z: number } — ⚠ undocumented
|
|
283
289
|
- `PresenceResidentRow` (interface): interface PresenceResidentRow — Resident identity used to suppress offline actors while their owner is online.
|
|
284
|
-
- `PresenceSession` (interface): interface PresenceSession<TGameId extends string = string> — ⚠ undocumented
|
|
290
|
+
- `PresenceSession` (interface): interface PresenceSession<TGameId extends string = string> { homeGameId: TGameId; externalId: string; viewerChunkKey?: string } — ⚠ undocumented
|
|
285
291
|
- `PresenceTransport` (interface): interface PresenceTransport<TRow, TLocation, TGameId extends string = string> — Backend seam for multiplayer presence. Feeds are reactive data and change identity whenever any player's pose updates; actions MUST be identity-stable for the lifetime of a mounted session so join/leave lifecycle effects can depend on them without re-running per pose tick. The use* members are called as React hooks by consumers, so a mounted transport must never change identity — remount the subtree to switch backends.
|
|
286
292
|
- `createLocalPresenceTransport` (function): function createLocalPresenceTransport<TRow, TLocation, TGameId extends string = string>(): { transport: PresenceTransport<TRow, TLocation, TGameId>; actions: PresenceActions<TGameId>; } — ⚠ undocumented
|
|
287
293
|
|
|
288
294
|
## @jgengine/core/multiplayer/presenceModel
|
|
289
295
|
|
|
290
|
-
- `ActivePresenceResolution` (interface): interface ActivePresenceResolution<T> — ⚠ undocumented
|
|
296
|
+
- `ActivePresenceResolution` (interface): interface ActivePresenceResolution<T> { active: T | null; extras: T[] } — ⚠ undocumented
|
|
291
297
|
- `DEFAULT_POSE_SYNC_RULES` (const): const DEFAULT_POSE_SYNC_RULES: PoseSyncRules — Canonical client-authoritative pose-sync tuning shared by every host transport (WS, Convex).
|
|
292
298
|
- `DEFAULT_SPAWN_ORIGIN` (const): const DEFAULT_SPAWN_ORIGIN: { readonly x: 0; readonly y: 0; readonly z: 0; } — ⚠ undocumented
|
|
293
|
-
- `IncomingPose` (interface): interface IncomingPose — ⚠ undocumented
|
|
294
|
-
- `PoseSyncDecision` (interface): interface PoseSyncDecision — ⚠ undocumented
|
|
295
|
-
- `PoseSyncRules` (interface): interface PoseSyncRules — ⚠ undocumented
|
|
296
|
-
- `PresencePoseState` (interface): interface PresencePoseState — ⚠ undocumented
|
|
299
|
+
- `IncomingPose` (interface): interface IncomingPose { position: {x: number; z: number; y?: number}; rotationY?: number; rotationPitch?: number; appearance?: Record<string, string> } — ⚠ undocumented
|
|
300
|
+
- `PoseSyncDecision` (interface): interface PoseSyncDecision { position: {x: number; y: number; z: number}; rotationY: number; rotationPitch: number; appearance?: Record<string, string>; changed: boolean; refreshKeepAlive: boolean } — ⚠ undocumented
|
|
301
|
+
- `PoseSyncRules` (interface): interface PoseSyncRules { maxSpeed: number; minIntervalMs?: number; maxVerticalOffset: number; floorY?: number; minElapsedSec: number; maxElapsedSec: number; keepAliveRefreshMs: number } — ⚠ undocumented · used by `DEFAULT_POSE_SYNC_RULES`: Canonical client-authoritative pose-sync tuning shared by every host transport (WS, Convex).
|
|
302
|
+
- `PresencePoseState` (interface): interface PresencePoseState { position: {x: number; y: number; z: number}; rotationY: number; rotationPitch?: number; lastSeenAtMs?: number; appearance?: Record<string, string> } — ⚠ undocumented
|
|
297
303
|
|
|
298
304
|
## @jgengine/core/multiplayer/simultaneousCommit
|
|
299
305
|
|
|
300
306
|
- `CommitPhase` (type): type CommitPhase = "collecting" | "revealed" — ⚠ undocumented
|
|
301
|
-
- `CommitRoundConfig` (interface): interface CommitRoundConfig — ⚠ undocumented
|
|
307
|
+
- `CommitRoundConfig` (interface): interface CommitRoundConfig { participants: readonly string[]; allowReseal?: boolean } — ⚠ undocumented
|
|
302
308
|
- `SealResult` (type): type SealResult = | { ok: true; allSealed: boolean } | { ok: false; reason: "unknown_participant" | "already_sealed" | "already_revealed" } — ⚠ undocumented
|
|
303
|
-
- `SealedCommit` (interface): interface SealedCommit<TAction> — ⚠ undocumented
|
|
309
|
+
- `SealedCommit` (interface): interface SealedCommit<TAction> { playerId: string; action: TAction; sealedAt: number } — ⚠ undocumented
|
|
304
310
|
|
|
305
311
|
## @jgengine/core/multiplayer/voiceContract
|
|
306
312
|
|
|
307
|
-
- `PushToTalk` (interface): interface PushToTalk — ⚠ undocumented
|
|
313
|
+
- `PushToTalk` (interface): interface PushToTalk { mode(): PushToTalkMode; setMode(mode: PushToTalkMode): void; keyDown(): void; keyUp(): void; muted(): boolean; setMuted(muted: boolean): void; status(): PushToTalkStatus; transmitting(): boolean } — ⚠ undocumented
|
|
308
314
|
- `PushToTalkMode` (type): type PushToTalkMode = "hold" | "toggle" | "openMic" — ⚠ undocumented
|
|
309
315
|
- `PushToTalkStatus` (type): type PushToTalkStatus = "idle" | "keyed" | "open" — ⚠ undocumented
|
|
310
|
-
- `VoiceParticipant` (interface): interface VoiceParticipant — ⚠ undocumented
|
|
311
|
-
- `VoiceRoute` (interface): interface VoiceRoute — ⚠ undocumented
|
|
316
|
+
- `VoiceParticipant` (interface): interface VoiceParticipant { userId: string; streamId?: string } — ⚠ undocumented
|
|
317
|
+
- `VoiceRoute` (interface): interface VoiceRoute { fromUserId: string; channelId: string; gain: number } — ⚠ undocumented
|
|
312
318
|
- `VoiceTransport` (interface): interface VoiceTransport — Signaling seam for voice: who is in a channel and which media stream descriptor they published. The media plane (WebRTC, SFU, or anything else that moves audio bytes) stays behind this seam, host-supplied — the engine never touches it. subscribers delivers the channel roster on every change, starting with the current roster.
|
|
313
319
|
- `createLocalVoiceTransport` (function): function createLocalVoiceTransport(options?: { userId?: string }): { transport: VoiceTransport; participants(channelId: string): readonly VoiceParticipant[]; } — ⚠ undocumented
|
|
314
320
|
- `createPushToTalk` (function): function createPushToTalk(config?: { mode?: PushToTalkMode; onChange?: (transmitting: boolean) => void; }): PushToTalk — ⚠ undocumented
|
|
@@ -326,7 +332,7 @@
|
|
|
326
332
|
- `GameHostOptions` (type): type GameHostOptions = { runtimes?: GameRuntime[]; persistence: HostPersistence; tickMs?: number; slotsPerServer?: number; now?: () => number; createServerId?: () => string; allowedFeedActions?: readonly string[]; } — Configuration for {@link createGameHost}, including persistence, tick rate, and game runtimes.
|
|
327
333
|
- `GameSocketIoServer` (type): type GameSocketIoServer = { rewind: (args: { serverId: string; atMs: number }) => RewoundPosition[]; close: () => void; } — ⚠ undocumented
|
|
328
334
|
- `GameSocketIoServerOptions` (type): type GameSocketIoServerOptions = HostRouterOptions & { io: SocketIoLikeServer } — ⚠ undocumented
|
|
329
|
-
- `GameWsServer` (type): type GameWsServer = { wss: WebSocketServer; port: () => number; rewind: (args: { serverId: string; atMs: number }) => RewoundPosition[]; close: () =>
|
|
335
|
+
- `GameWsServer` (type): type GameWsServer = { wss: WebSocketServer; port: () => number; rewind: (args: { serverId: string; atMs: number }) => RewoundPosition[]; /** Fence new messages, drain accepted router work, and close sockets. Repeated calls share completion; host persistence remains caller-owned. */ close: () => Prom… — ⚠ undocumented
|
|
330
336
|
- `GameWsServerOptions` (type): type GameWsServerOptions = HostRouterOptions & { server?: HttpServer; port?: number; path?: string; /** Per-message payload cap in bytes. Defaults to {@link DEFAULT_MAX_PAYLOAD_BYTES}. */ maxPayloadBytes?: number; /** Max concurrent sockets accepted; connections beyond this are closed immediately. D… — ⚠ undocumented
|
|
331
337
|
- `HostChangeEvent` (type): type HostChangeEvent = { type: "server"; serverId: string; } | { type: "player"; serverId: string; userId: string; } | { type: "feed"; serverId: string; action: string; } — A change notification emitted by a `GameHost` for a server, player, or feed mutation.
|
|
332
338
|
- `HostedGameDefinition` (interface): interface HostedGameDefinition — A game the world server can host — its authoritative {@link GameDefinition} and the content lookup a `GameContext` reads.
|
|
@@ -432,7 +438,7 @@
|
|
|
432
438
|
- `DEFAULT_HEARTBEAT_INTERVAL_MS` (const): const DEFAULT_HEARTBEAT_INTERVAL_MS: 30000 — Default ping/pong interval; a socket that misses one round-trip is terminated.
|
|
433
439
|
- `DEFAULT_MAX_CONNECTIONS` (const): const DEFAULT_MAX_CONNECTIONS: 10000 — Default max concurrent sockets this server accepts before rejecting new ones.
|
|
434
440
|
- `DEFAULT_MAX_PAYLOAD_BYTES` (const): const DEFAULT_MAX_PAYLOAD_BYTES: 1048576 — Default per-message payload cap (bytes) — `ws` closes the socket with 1009 past this.
|
|
435
|
-
- `GameWsServer` (type): type GameWsServer = { wss: WebSocketServer; port: () => number; rewind: (args: { serverId: string; atMs: number }) => RewoundPosition[]; close: () =>
|
|
441
|
+
- `GameWsServer` (type): type GameWsServer = { wss: WebSocketServer; port: () => number; rewind: (args: { serverId: string; atMs: number }) => RewoundPosition[]; /** Fence new messages, drain accepted router work, and close sockets. Repeated calls share completion; host persistence remains caller-owned. */ close: () => Prom… — ⚠ undocumented
|
|
436
442
|
- `GameWsServerOptions` (type): type GameWsServerOptions = HostRouterOptions & { server?: HttpServer; port?: number; path?: string; /** Per-message payload cap in bytes. Defaults to {@link DEFAULT_MAX_PAYLOAD_BYTES}. */ maxPayloadBytes?: number; /** Max concurrent sockets accepted; connections beyond this are closed immediately. D… — ⚠ undocumented
|
|
437
443
|
- `RewoundPosition` (type): type RewoundPosition = { userId: string; x: number; y: number; z: number; } — A player's interpolated position sampled from history at a past timestamp.
|
|
438
444
|
- `createGameWsServer` (function): function createGameWsServer(options: GameWsServerOptions): GameWsServer — ⚠ undocumented
|
|
@@ -442,7 +448,7 @@
|
|
|
442
448
|
- `SqlPool` (type): type SqlPool = SqlQueryable & { connect: () => Promise<SqlPoolClient>; } — ⚠ undocumented
|
|
443
449
|
- `SqlPoolClient` (type): type SqlPoolClient = SqlQueryable & { release: () => void; } — ⚠ undocumented
|
|
444
450
|
- `SqlQueryResult` (type): type SqlQueryResult = { rows: Record<string, unknown>[] } — ⚠ undocumented
|
|
445
|
-
- `SqlQueryable` (type): type SqlQueryable = { query: (text: string, params?: unknown[]) => Promise<SqlQueryResult>; } — ⚠ undocumented
|
|
451
|
+
- `SqlQueryable` (type): type SqlQueryable = { query: (text: string, params?: unknown[]) => Promise<SqlQueryResult>; } — ⚠ undocumented · used by `sqlWorldStore`: Create an asynchronous hosted-world store backed by one JSONB row.
|
|
446
452
|
- `ensureSchema` (function): function ensureSchema(pool: SqlQueryable): Promise<void> — ⚠ undocumented
|
|
447
453
|
- `sqlPersistence` (function): function sqlPersistence(pool: SqlPool, now: () => number = Date.now): HostPersistence — ⚠ undocumented
|
|
448
454
|
- `sqlWorldStore` (function): function sqlWorldStore(pool: SqlQueryable, worldId: string): HostedWorldStore — Create an asynchronous hosted-world store backed by one JSONB row.
|
|
@@ -452,7 +458,7 @@
|
|
|
452
458
|
- `SqlPool` (type): type SqlPool = SqlQueryable & { connect: () => Promise<SqlPoolClient>; } — ⚠ undocumented
|
|
453
459
|
- `SqlPoolClient` (type): type SqlPoolClient = SqlQueryable & { release: () => void; } — ⚠ undocumented
|
|
454
460
|
- `SqlQueryResult` (type): type SqlQueryResult = { rows: Record<string, unknown>[] } — ⚠ undocumented
|
|
455
|
-
- `SqlQueryable` (type): type SqlQueryable = { query: (text: string, params?: unknown[]) => Promise<SqlQueryResult>; } — ⚠ undocumented
|
|
461
|
+
- `SqlQueryable` (type): type SqlQueryable = { query: (text: string, params?: unknown[]) => Promise<SqlQueryResult>; } — ⚠ undocumented · used by `sqlWorldStore` (@jgengine/sql): Create an asynchronous hosted-world store backed by one JSONB row.
|
|
456
462
|
- `ensureSchema` (function): function ensureSchema(pool: SqlQueryable): Promise<void> — ⚠ undocumented
|
|
457
463
|
- `sqlPersistence` (function): function sqlPersistence(pool: SqlPool, now: () => number = Date.now): HostPersistence — ⚠ undocumented
|
|
458
464
|
|
|
@@ -479,7 +485,7 @@
|
|
|
479
485
|
- `GameHostOptions` (type): type GameHostOptions = { runtimes?: GameRuntime[]; persistence: HostPersistence; tickMs?: number; slotsPerServer?: number; now?: () => number; createServerId?: () => string; allowedFeedActions?: readonly string[]; } — Configuration for {@link createGameHost}, including persistence, tick rate, and game runtimes.
|
|
480
486
|
- `HostChangeEvent` (type): type HostChangeEvent = | { type: "server"; serverId: string } | { type: "player"; serverId: string; userId: string } | { type: "feed"; serverId: string; action: string } — A change notification emitted by a `GameHost` for a server, player, or feed mutation.
|
|
481
487
|
- `HostCommandOp` (type): type HostCommandOp = "pose" | "runCommand" | "join" | "browse" | "voice" — A host-side op the command middleware pipeline can gate: pose sync, `runCommand`, join/joinByCode, browse, or voice join/leave/publish.
|
|
482
|
-
- `HostRouter` (type): type HostRouter = { connect: (transport: HostRouterTransport) => HostRouterConnection; rewind: (args: { serverId: string; atMs: number }) => RewoundPosition[]; close: () => void;
|
|
488
|
+
- `HostRouter` (type): type HostRouter = { connect: (transport: HostRouterTransport) => HostRouterConnection; rewind: (args: { serverId: string; atMs: number }) => RewoundPosition[]; close: () => void; /** Wait for accepted message handlers and subscription reads to settle. Close first to prevent new work. */ drain: () =>… — ⚠ undocumented
|
|
483
489
|
- `HostRouterAuthenticate` (type): type HostRouterAuthenticate = (args: { userId: string; token?: string; }) => Promise<string | null> | string | null — ⚠ undocumented
|
|
484
490
|
- `HostRouterConnection` (type): type HostRouterConnection = { handleRaw: (raw: unknown) => void; close: () => void; } — ⚠ undocumented
|
|
485
491
|
- `HostRouterOptions` (type): type HostRouterOptions = { host: GameHost; authenticate?: HostRouterAuthenticate; allowAnonymous?: boolean; singleSession?: boolean; poseRules?: PoseSyncRules; positionHistoryMs?: number; chatRateLimit?: ChatRateLimit; chatHistoryLimit?: number; chatMaxBodyLength?: number; /** Per-op rate limits for… — ⚠ undocumented
|
|
@@ -492,6 +498,7 @@
|
|
|
492
498
|
- `MAX_FEED_ACTION_LENGTH` (const): const MAX_FEED_ACTION_LENGTH: 256 — Max length of a `pushFeed` action name, in UTF-16 code units.
|
|
493
499
|
- `MAX_FEED_ENTRY_BYTES` (const): const MAX_FEED_ENTRY_BYTES: 65536 — Max serialized size of a `pushFeed` entry payload, in bytes.
|
|
494
500
|
- `MAX_QUEUED_MESSAGES` (const): const MAX_QUEUED_MESSAGES: 64 — Cap on frames queued behind a connection's in-flight message; beyond this a flood gets rejected instead of piling up unbounded promises.
|
|
501
|
+
- `MAX_SESSION_ID_LENGTH` (const): const MAX_SESSION_ID_LENGTH: 128 — Max length of a join/leave `sessionId`, in UTF-16 code units.
|
|
495
502
|
- `OP_LEDGER_LIMIT` (const): const OP_LEDGER_LIMIT: 64 — Max recently-applied `runCommand` op IDs retained per (serverId, userId), oldest evicted first.
|
|
496
503
|
- `PeerGuest` (type): type PeerGuest = { backend: WsBackend; offer: () => Promise<string>; connect: (answerCode: string) => Promise<void>; close: () => void; } — ⚠ undocumented
|
|
497
504
|
- `PeerGuestOptions` (type): type PeerGuestOptions = { userId: string; token?: string; rtc?: PeerRtcOptions; } — ⚠ undocumented
|
|
@@ -510,14 +517,14 @@
|
|
|
510
517
|
- `TransportPipe` (type): type TransportPipe = { send: (data: string) => void; close: () => void; } — ⚠ undocumented
|
|
511
518
|
- `TransportPipeFactory` (type): type TransportPipeFactory = (handlers: TransportPipeHandlers) => TransportPipe — ⚠ undocumented
|
|
512
519
|
- `TransportPipeHandlers` (type): type TransportPipeHandlers = { onOpen: () => void; onMessage: (data: string) => void; onClose: () => void; } — ⚠ undocumented
|
|
513
|
-
- `VoiceChannelDef` (interface): interface VoiceChannelDef — ⚠ undocumented
|
|
520
|
+
- `VoiceChannelDef` (interface): interface VoiceChannelDef { id: VoiceChannelId; positional: boolean; falloff?: AudioFalloffConfig; gain?: number } — ⚠ undocumented
|
|
514
521
|
- `VoiceChannelId` (type): type VoiceChannelId = string — ⚠ undocumented
|
|
515
|
-
- `VoiceChannelRouter` (interface): interface VoiceChannelRouter — ⚠ undocumented
|
|
522
|
+
- `VoiceChannelRouter` (interface): interface VoiceChannelRouter { registerChannel(def: VoiceChannelDef): void; join(userId: VoiceMemberId, channelId: VoiceChannelId): void; leave(userId: VoiceMemberId, channelId: VoiceChannelId): void; leaveAll(userId: VoiceMemberId): void; updatePosition(userId: VoiceM… — ⚠ undocumented
|
|
516
523
|
- `VoiceMemberId` (type): type VoiceMemberId = string — ⚠ undocumented
|
|
517
|
-
- `VoicePosition` (interface): interface VoicePosition — ⚠ undocumented
|
|
518
|
-
- `VoiceRoute` (interface): interface VoiceRoute — ⚠ undocumented
|
|
524
|
+
- `VoicePosition` (interface): interface VoicePosition { x: number; y: number; z: number } — ⚠ undocumented
|
|
525
|
+
- `VoiceRoute` (interface): interface VoiceRoute { fromUserId: VoiceMemberId; channelId: VoiceChannelId; gain: number } — ⚠ undocumented
|
|
519
526
|
- `WS_PROTOCOL_VERSION` (const): const WS_PROTOCOL_VERSION: 1 — ⚠ undocumented
|
|
520
|
-
- `WorldGameHost` (interface): interface WorldGameHost extends GameHost — A {@link GameHost}
|
|
527
|
+
- `WorldGameHost` (interface): interface WorldGameHost extends GameHost — A {@link GameHost} backed by `HostedWorldSession`s; `tick` advances worlds and `unload` explicitly saves and releases idle world references.
|
|
521
528
|
- `WorldGameHostOptions` (interface): interface WorldGameHostOptions — Config for {@link createWorldGameHost}: how to resolve a hosted world's authoritative session per server.
|
|
522
529
|
- `WsAppearance` (type): type WsAppearance = Record<string, string | number | boolean> — Client-set cosmetic/state tags carried alongside a pose (skin, mount, emote, ...). Primitive values only.
|
|
523
530
|
- `WsBackend` (type): type WsBackend = GameBackend & { rtt: { sampleMs: number; smoothedMs: number }; pushFeedEntry: (args: { serverId: string; action: string; entry: unknown }) => Promise<void>; browse: (args: { gameId: string; filter?: MatchFilter; limit?: number }) => Promise<SessionListing[]>; joinByCode: (args: { ga… — ⚠ undocumented
|
|
@@ -526,7 +533,7 @@
|
|
|
526
533
|
- `WsChannel` (type): type WsChannel = "server" | "player" | "feed" | "presence" | "chat" | "voice" — ⚠ undocumented
|
|
527
534
|
- `WsChatMessage` (type): type WsChatMessage = { id: string; channelId: string; fromUserId: string; body: string; at: number; } — ⚠ undocumented
|
|
528
535
|
- `WsChatSync` (type): type WsChatSync = { subscribe: ( serverId: string, channelId: string, onChange: (messages: WsChatMessage[]) => void, ) => () => void; send: (serverId: string, channelId: string, body: string) => Promise<ChatSendOutcome>; } — ⚠ undocumented
|
|
529
|
-
- `WsClientMessage` (type): type WsClientMessage = | { v: 1; t: "ping"; id: number; at: number } | { v: 1; t: "hello"; id: number; userId: string; token?: string } | { v: 1; t: "join"; id: number; gameId: string; serverId?: string; attributes?: SessionAttributes; code?: string; role?: "player" | "spectator";
|
|
536
|
+
- `WsClientMessage` (type): type WsClientMessage = | { v: 1; t: "ping"; id: number; at: number } | { v: 1; t: "hello"; id: number; userId: string; token?: string } | { v: 1; t: "join"; id: number; gameId: string; serverId?: string; attributes?: SessionAttributes; code?: string; role?: "player" | "spectator"; /** Client session… — ⚠ undocumented
|
|
530
537
|
- `WsDecodeFailure` (type): type WsDecodeFailure = { reason: string; id?: number; } — ⚠ undocumented
|
|
531
538
|
- `WsJoinByCodeResult` (type): type WsJoinByCodeResult = JoinServerResult | null — ⚠ undocumented
|
|
532
539
|
- `WsJoinResult` (type): type WsJoinResult = JoinServerResult — ⚠ undocumented
|
|
@@ -602,7 +609,7 @@
|
|
|
602
609
|
|
|
603
610
|
- `DEFAULT_GRACE_MS` (const): const DEFAULT_GRACE_MS: 15000 — Default reconnect grace period for hosted socket sessions.
|
|
604
611
|
- `DEFAULT_POSE_RULES` (const): const DEFAULT_POSE_RULES: PoseSyncRules — ⚠ undocumented
|
|
605
|
-
- `HostRouter` (type): type HostRouter = { connect: (transport: HostRouterTransport) => HostRouterConnection; rewind: (args: { serverId: string; atMs: number }) => RewoundPosition[]; close: () => void;
|
|
612
|
+
- `HostRouter` (type): type HostRouter = { connect: (transport: HostRouterTransport) => HostRouterConnection; rewind: (args: { serverId: string; atMs: number }) => RewoundPosition[]; close: () => void; /** Wait for accepted message handlers and subscription reads to settle. Close first to prevent new work. */ drain: () =>… — ⚠ undocumented
|
|
606
613
|
- `HostRouterAuthenticate` (type): type HostRouterAuthenticate = (args: { userId: string; token?: string; }) => Promise<string | null> | string | null — ⚠ undocumented
|
|
607
614
|
- `HostRouterConnection` (type): type HostRouterConnection = { handleRaw: (raw: unknown) => void; close: () => void; } — ⚠ undocumented
|
|
608
615
|
- `HostRouterOptions` (type): type HostRouterOptions = { host: GameHost; authenticate?: HostRouterAuthenticate; allowAnonymous?: boolean; singleSession?: boolean; poseRules?: PoseSyncRules; positionHistoryMs?: number; chatRateLimit?: ChatRateLimit; chatHistoryLimit?: number; chatMaxBodyLength?: number; /** Per-op rate limits for… — ⚠ undocumented
|
|
@@ -649,12 +656,13 @@
|
|
|
649
656
|
- `MAX_COMMAND_LENGTH` (const): const MAX_COMMAND_LENGTH: 4096 — Max length of a `runCommand` command name, in UTF-16 code units.
|
|
650
657
|
- `MAX_FEED_ACTION_LENGTH` (const): const MAX_FEED_ACTION_LENGTH: 256 — Max length of a `pushFeed` action name, in UTF-16 code units.
|
|
651
658
|
- `MAX_FEED_ENTRY_BYTES` (const): const MAX_FEED_ENTRY_BYTES: 65536 — Max serialized size of a `pushFeed` entry payload, in bytes.
|
|
659
|
+
- `MAX_SESSION_ID_LENGTH` (const): const MAX_SESSION_ID_LENGTH: 128 — Max length of a join/leave `sessionId`, in UTF-16 code units.
|
|
652
660
|
- `WS_PROTOCOL_VERSION` (const): const WS_PROTOCOL_VERSION: 1 — ⚠ undocumented
|
|
653
661
|
- `WsAppearance` (type): type WsAppearance = Record<string, string | number | boolean> — Client-set cosmetic/state tags carried alongside a pose (skin, mount, emote, ...). Primitive values only.
|
|
654
662
|
- `WsBrowseResult` (type): type WsBrowseResult = SessionListing[] — ⚠ undocumented
|
|
655
663
|
- `WsChannel` (type): type WsChannel = "server" | "player" | "feed" | "presence" | "chat" | "voice" — ⚠ undocumented
|
|
656
664
|
- `WsChatMessage` (type): type WsChatMessage = { id: string; channelId: string; fromUserId: string; body: string; at: number; } — ⚠ undocumented
|
|
657
|
-
- `WsClientMessage` (type): type WsClientMessage = | { v: 1; t: "ping"; id: number; at: number } | { v: 1; t: "hello"; id: number; userId: string; token?: string } | { v: 1; t: "join"; id: number; gameId: string; serverId?: string; attributes?: SessionAttributes; code?: string; role?: "player" | "spectator";
|
|
665
|
+
- `WsClientMessage` (type): type WsClientMessage = | { v: 1; t: "ping"; id: number; at: number } | { v: 1; t: "hello"; id: number; userId: string; token?: string } | { v: 1; t: "join"; id: number; gameId: string; serverId?: string; attributes?: SessionAttributes; code?: string; role?: "player" | "spectator"; /** Client session… — ⚠ undocumented
|
|
658
666
|
- `WsDecodeFailure` (type): type WsDecodeFailure = { reason: string; id?: number; } — ⚠ undocumented
|
|
659
667
|
- `WsJoinByCodeResult` (type): type WsJoinByCodeResult = JoinServerResult | null — ⚠ undocumented
|
|
660
668
|
- `WsJoinResult` (type): type WsJoinResult = JoinServerResult — ⚠ undocumented
|
|
@@ -682,17 +690,17 @@
|
|
|
682
690
|
|
|
683
691
|
## @jgengine/ws/voiceChannel
|
|
684
692
|
|
|
685
|
-
- `VoiceChannelDef` (interface): interface VoiceChannelDef — ⚠ undocumented
|
|
693
|
+
- `VoiceChannelDef` (interface): interface VoiceChannelDef { id: VoiceChannelId; positional: boolean; falloff?: AudioFalloffConfig; gain?: number } — ⚠ undocumented
|
|
686
694
|
- `VoiceChannelId` (type): type VoiceChannelId = string — ⚠ undocumented
|
|
687
|
-
- `VoiceChannelRouter` (interface): interface VoiceChannelRouter — ⚠ undocumented
|
|
695
|
+
- `VoiceChannelRouter` (interface): interface VoiceChannelRouter { registerChannel(def: VoiceChannelDef): void; join(userId: VoiceMemberId, channelId: VoiceChannelId): void; leave(userId: VoiceMemberId, channelId: VoiceChannelId): void; leaveAll(userId: VoiceMemberId): void; updatePosition(userId: VoiceM… — ⚠ undocumented
|
|
688
696
|
- `VoiceMemberId` (type): type VoiceMemberId = string — ⚠ undocumented
|
|
689
|
-
- `VoicePosition` (interface): interface VoicePosition — ⚠ undocumented
|
|
690
|
-
- `VoiceRoute` (interface): interface VoiceRoute — ⚠ undocumented
|
|
697
|
+
- `VoicePosition` (interface): interface VoicePosition { x: number; y: number; z: number } — ⚠ undocumented
|
|
698
|
+
- `VoiceRoute` (interface): interface VoiceRoute { fromUserId: VoiceMemberId; channelId: VoiceChannelId; gain: number } — ⚠ undocumented
|
|
691
699
|
- `computeVoiceGain` (function): function computeVoiceGain(def: VoiceChannelDef, distance: number | null): number — ⚠ undocumented
|
|
692
700
|
- `createVoiceChannelRouter` (function): function createVoiceChannelRouter(channels?: readonly VoiceChannelDef[]): VoiceChannelRouter — ⚠ undocumented
|
|
693
701
|
|
|
694
702
|
## @jgengine/ws/worldHost
|
|
695
703
|
|
|
696
|
-
- `WorldGameHost` (interface): interface WorldGameHost extends GameHost — A {@link GameHost}
|
|
704
|
+
- `WorldGameHost` (interface): interface WorldGameHost extends GameHost — A {@link GameHost} backed by `HostedWorldSession`s; `tick` advances worlds and `unload` explicitly saves and releases idle world references.
|
|
697
705
|
- `WorldGameHostOptions` (interface): interface WorldGameHostOptions — Config for {@link createWorldGameHost}: how to resolve a hosted world's authoritative session per server.
|
|
698
706
|
- `createWorldGameHost` (function): function createWorldGameHost(options: WorldGameHostOptions): WorldGameHost — The GameContext-loop counterpart of the reducer `createGameHost`: a structural {@link GameHost} that serves each world's full `WorldSnapshot` as `serverState`, so the existing ws router, `createWsBackend`, and the shell's `attachWorldSync` carry host-authoritative GameContext worlds with zero changes to any of them. The harness owns the tick cadence (call {@link WorldGameHost.tick} on an interval); commands and joins broadcast immediately.
|