@crowdedkingdoms/crowdyjs 18.5.0-dev.1 → 18.7.0-dev.1
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/MIGRATION.md +118 -0
- package/README.md +109 -4
- package/dist/binary-wire.d.ts +30 -2
- package/dist/binary-wire.d.ts.map +1 -1
- package/dist/binary-wire.js +61 -3
- package/dist/crowdy-client.d.ts +3 -0
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +2 -0
- package/dist/domains/appAccess.d.ts +32 -1
- package/dist/domains/appAccess.d.ts.map +1 -1
- package/dist/domains/appAccess.js +49 -1
- package/dist/domains/apps.d.ts +7 -1
- package/dist/domains/apps.d.ts.map +1 -1
- package/dist/domains/apps.js +7 -1
- package/dist/domains/channels.d.ts +8 -3
- package/dist/domains/channels.d.ts.map +1 -1
- package/dist/domains/channels.js +8 -3
- package/dist/domains/exec.d.ts +14 -0
- package/dist/domains/exec.d.ts.map +1 -1
- package/dist/domains/exec.js +13 -1
- package/dist/domains/grids.d.ts +1 -0
- package/dist/domains/grids.d.ts.map +1 -1
- package/dist/domains/grids.js +1 -0
- package/dist/domains/inputLog.d.ts +74 -0
- package/dist/domains/inputLog.d.ts.map +1 -0
- package/dist/domains/inputLog.js +74 -0
- package/dist/domains/portal.d.ts +18 -0
- package/dist/domains/portal.d.ts.map +1 -1
- package/dist/domains/portal.js +1 -1
- package/dist/domains/udp.d.ts +27 -8
- package/dist/domains/udp.d.ts.map +1 -1
- package/dist/domains/udp.js +39 -9
- package/dist/domains/users.d.ts +23 -2
- package/dist/domains/users.d.ts.map +1 -1
- package/dist/domains/users.js +34 -2
- package/dist/domains/voxels.d.ts +4 -3
- package/dist/domains/voxels.d.ts.map +1 -1
- package/dist/domains/voxels.js +4 -3
- package/dist/errors.d.ts +52 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +74 -0
- package/dist/generated/graphql-schema.d.ts +576 -49
- package/dist/generated/graphql-schema.d.ts.map +1 -1
- package/dist/generated/graphql-schema.js +30 -1
- package/dist/generated/graphql.d.ts +232 -17
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +30 -21
- package/dist/grid-mods/grid-host-calls.d.ts +34 -0
- package/dist/grid-mods/grid-host-calls.d.ts.map +1 -1
- package/dist/grid-mods/grid-host-calls.js +28 -5
- package/dist/grid-mods/index.d.ts +1 -1
- package/dist/grid-mods/index.d.ts.map +1 -1
- package/dist/grid-mods/index.js +1 -1
- package/dist/grid-scope.d.ts +3 -0
- package/dist/grid-scope.d.ts.map +1 -1
- package/dist/grid-scope.js +6 -0
- package/dist/index.d.ts +11 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/media/voice-frames.d.ts +258 -0
- package/dist/media/voice-frames.d.ts.map +1 -0
- package/dist/media/voice-frames.js +424 -0
- package/dist/metrics.d.ts +1 -1
- package/dist/realtime.d.ts +19 -3
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +8 -0
- package/dist/stores/actors.d.ts +3 -1
- package/dist/stores/actors.d.ts.map +1 -1
- package/dist/stores/chunks.d.ts +65 -6
- package/dist/stores/chunks.d.ts.map +1 -1
- package/dist/stores/chunks.js +161 -19
- package/dist/stores/index.d.ts +2 -2
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js +1 -1
- package/dist/stores/keys.d.ts +5 -0
- package/dist/stores/keys.d.ts.map +1 -1
- package/dist/stores/keys.js +7 -0
- package/dist/stores/session.d.ts +1 -1
- package/dist/stores/session.d.ts.map +1 -1
- package/dist/stores/session.js +2 -0
- package/dist/types.d.ts +49 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/MIGRATION.md
CHANGED
|
@@ -120,6 +120,124 @@ super-admin's session). There is no SDK replacement.
|
|
|
120
120
|
`dev`'s SDL after #417 merged (`npm run schema:sync:paths -- --schema <that schema.gql>`, then
|
|
121
121
|
`npm run codegen`).
|
|
122
122
|
|
|
123
|
+
## 18.7.0: voice helpers, channel audio, opcode 140 on the relay, wide voxels, self-echo, pause and access refusals
|
|
124
|
+
|
|
125
|
+
Additive, with reads that change for values they used to get wrong (the wide-voxel item) and one
|
|
126
|
+
new floor: **the token mutations (`portal.mintAppToken`, `exchangeCode`, `refresh`) select
|
|
127
|
+
`runtimeGate` and the `udpNotifications` subscription selects `ChannelAudioNotification`, so
|
|
128
|
+
18.7.0 needs the ck-api release after v2.39.0 that carries both** (an older one refuses the
|
|
129
|
+
selections). Channel audio and the voxel echo need Buddy v0.37.0.
|
|
130
|
+
|
|
131
|
+
- **Voice helpers** (`media/voice-frames.ts`, exported from the package entry): an optional
|
|
132
|
+
convention for what an audio payload carries. A 10-byte header, little-endian, goes in front of
|
|
133
|
+
each codec frame: version 1, codec (0 raw, 1 Opus 48 kHz mono, 2 G.711 µ-law 8 kHz), `u16` seq,
|
|
134
|
+
`u32` timestamp in codec samples (milliseconds for raw), the frame's duration in ms, and flags
|
|
135
|
+
(bit 0 the first packet after silence, bit 1 the last before it). `encodeVoiceHeader` /
|
|
136
|
+
`encodeVoicePacket` write it; `decodeVoicePacket` returns `null` for a packet shorter than
|
|
137
|
+
10 bytes or of another version and never throws. `VoicePacketizer` numbers one sender's frames
|
|
138
|
+
across the seq and timestamp wraps and sets the flags (`packetize(frame, { last })`, `skip()`
|
|
139
|
+
for silence). `VoiceJitterBuffer` takes `push(key, packet, nowMs)` per sender key and returns
|
|
140
|
+
the due frames from `pull(key, nowMs)` / `poll(nowMs)`: in seq order, `targetDelayMs` (60) after
|
|
141
|
+
a talk spurt's first packet, a gap (`frame: null`) for each one that never came, late packets
|
|
142
|
+
dropped, at most `maxFrames` (64) a sender, starting over on a talk spurt or `resetAfterMs`
|
|
143
|
+
(200) of silence. A spurt that starts while the one before still has frames waiting drops
|
|
144
|
+
them. CrowdyCPP 0.60.0 has the same helpers and replays `test/unit/fixtures/voice-frames.json`.
|
|
145
|
+
No codec ships: a browser encodes Opus with WebCodecs (the module doc has the settings). A game
|
|
146
|
+
with a voice format of its own keeps it; positioning a voice stays the game's.
|
|
147
|
+
- **`genericSpatial`.** Opcode 140 (`GENERIC_SPATIAL_1`), an app-defined spatial payload such as
|
|
148
|
+
CrowdyCPP's `Connection::sendGenericSpatial`, reaches the new `genericSpatial` handler of
|
|
149
|
+
`udp.subscribe` (and `any`) as a `GenericSpatialNotification`: the spatial header fields and a
|
|
150
|
+
base64 `payload`. The World Stores bus has a `genericSpatial` key. **Binary relay only**
|
|
151
|
+
(`realtime: { binaryTransport: true }`): the GraphQL `udpNotifications` union has no member for
|
|
152
|
+
140, so the proxy drops it and a client on the GraphQL transport never sees one. `UdpNotification`
|
|
153
|
+
gains the member, so an exhaustive `switch` over `__typename` needs the new case.
|
|
154
|
+
- **`ChunkStore` keeps wide voxel types and other addresses.** Positions and types are the app's
|
|
155
|
+
signed 16-bit values, which the platform does not check. An edit the 16×16×16 one-byte grid
|
|
156
|
+
cannot hold (a type outside 0-255, a position outside 0-15) — a realtime update, a hydrated
|
|
157
|
+
`voxelStates` entry, or a local `setVoxel` — is kept whole in the new `CachedChunk.overlay`
|
|
158
|
+
(`ChunkOverlayVoxel`: `x`, `y`, `z`, `voxelType`, `state`; keyed by `voxelKey(x, y, z)`), and
|
|
159
|
+
`voxelTypeAt` / `voxelStateAt` return it. What changes: a type outside 0-255 is no longer stored
|
|
160
|
+
truncated (300 used to read as 44, -1 as 255); a position outside 0-15 no longer lands on
|
|
161
|
+
another voxel (`(16, 0, 0)` used to overwrite `(0, 1, 0)`), and reading one returns the overlay's
|
|
162
|
+
or nothing; and code that walks `chunk.voxels` itself sees 0 where an in-grid voxel's type is in
|
|
163
|
+
the overlay. The store is a 16×16×16 helper; a game with other addressing reads the raw
|
|
164
|
+
`voxelUpdate` events and `chunks.get`'s `voxelStates`.
|
|
165
|
+
- **`createGridHostCalls({ voxelBounds })`** sets the positions and types a CLIENT half's
|
|
166
|
+
`voxel_set` may write, for a world that uses other signed 16-bit values. The default,
|
|
167
|
+
`DEFAULT_GRID_VOXEL_BOUNDS`, is today's: positions 0-15, types 0-255. Bounds that are not
|
|
168
|
+
integer ranges within -32768 to 32767 throw `RangeError` when the host calls are created.
|
|
169
|
+
- **Channel audio** (Buddy v0.37.0). `udp.sendChannelAudio({ channelId, uuid, payload,
|
|
170
|
+
sequenceNumber? })` sends opcode 35 (opcode 17's layout and signing) on the binary relay, else
|
|
171
|
+
the `sendChannelAudio` mutation; `payload` is base64, at most 1,024 bytes, and the server
|
|
172
|
+
refuses it with `UNAUTHORIZED` (7) without the channel's `send_voice` and the app's
|
|
173
|
+
`use_voice_chat`. There is no echo to the sender. Other members' frames arrive as opcode 36,
|
|
174
|
+
standalone or bundled, as a `ChannelAudioNotification` (`channelId`, `uuid`, `audioData`
|
|
175
|
+
base64, `sequenceNumber`, `epochMillis`) on the new `channelAudio` handler of `udp.subscribe`
|
|
176
|
+
(and `any`) and the World Stores bus key `channelAudio`, on the binary relay and on the GraphQL
|
|
177
|
+
transport alike (the `udpNotifications` subscription selects the union's
|
|
178
|
+
`ChannelAudioNotification`, so it too needs that ck-api release). `channels.create` /
|
|
179
|
+
`grids.createChannel` take `membersCanSpeak` (default false: the member role gets
|
|
180
|
+
`send_voice`); `GridScope.channels` has `sendAudio(channelId, uuid, audioBase64)`;
|
|
181
|
+
`serializeChannelAudio` is exported. The voice helpers are the payload: see the README.
|
|
182
|
+
- **UDP error 33, `APP_PAUSED`**: the replication server refuses a paused app's sends.
|
|
183
|
+
`UDP_ERROR_NAMES[33]` and the generated `UdpErrorCode.AppPaused` name it.
|
|
184
|
+
- **Voxel edits are int16 and their state at most 1,024 bytes.** `udp.sendVoxelUpdate` and
|
|
185
|
+
`ChunkStore.setVoxel` throw `RangeError` (nothing sent) for a position or type outside
|
|
186
|
+
-32768..32767 or a state over 1,024 bytes (`assertVoxelEdit`, `VOXEL_STATE_MAX_BYTES`); the
|
|
187
|
+
server answers those with `INVALID_REQUEST` (15). The 0-15 / 0-255 ranges in the docs were
|
|
188
|
+
never enforced and are gone.
|
|
189
|
+
- **The echo of your own voxel edit.** Buddy v0.37.0 delivers every accepted edit back to its
|
|
190
|
+
sender as a `VoxelUpdateNotification`. `ChunkStore` records each `setVoxel` (uuid, sequence,
|
|
191
|
+
voxel) for 10 s and does not apply its echo again, so a local edit fires `onChunkChanged` once;
|
|
192
|
+
it applies the echo only when another client's edit of the voxel arrived in between (the server
|
|
193
|
+
ordered yours last) and no newer local edit of it is pending. A game reading `voxelUpdate`
|
|
194
|
+
itself sees its own edits there now: compare the `uuid` and `sequenceNumber` with the send's.
|
|
195
|
+
- **Pause and access refusals.** `isAppPaused(gate)` reads `AppTokenResponse.runtimeGate` and
|
|
196
|
+
`GameClientBootstrap.runtimeGate` (`{ status, reason }`; anything but `ACTIVE` is paused; a
|
|
197
|
+
paused app still mints, so check before entering). `appPausedOf(err)` reads `APP_PAUSED`
|
|
198
|
+
(`reason`), `accessRefusalOf(err)` `ACCESS_REVOKED` / `ACCESS_SUSPENDED` (`suspendedUntil`) /
|
|
199
|
+
`ACCESS_NOT_GRANTED`, `actorExistsOf(err)` `ACTOR_EXISTS` (`ownedByCaller`), with their
|
|
200
|
+
`*_CODE` constants.
|
|
201
|
+
- **New API wraps**: `users.playerProfile(userId)` and `users.playerProfiles(userIds)` (at most
|
|
202
|
+
`PLAYER_PROFILES_MAX`, 100; `RangeError` above) for public `{ userId, gamertag, disambiguation }`;
|
|
203
|
+
`users.get` documents that another user's private fields come back null.
|
|
204
|
+
`appAccess.suspend(appId, userId, until, idempotencyKey?)`, `unsuspend`,
|
|
205
|
+
`resyncTierGridPermissions` (`manage_access_tiers`); `suspendedUntil` on every access record.
|
|
206
|
+
`exec.restartType(appId, nodeType)` → `{ nodeType, stopped }` (`manage_compute`);
|
|
207
|
+
`exec.status` adds `budgetPauseReason`, `maxInstances`, `maxReservedMb`, `instanceLimit`,
|
|
208
|
+
`instances`, `reservedMb`. `apps.get` / `apps.update` carry `claimOwnerKeys`;
|
|
209
|
+
`chunks.get` / `getByDistance` carry `voxelStatesTruncated`; `gameClientBootstrap` carries
|
|
210
|
+
`runtimeGate` and `wildernessWritesOpen`.
|
|
211
|
+
|
|
212
|
+
## 18.6.0: the input log
|
|
213
|
+
|
|
214
|
+
Additive. An app with replay logging on has its client inputs recorded, and `client.inputLog`
|
|
215
|
+
reads them back on the app-scoped client:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const { edges, pageInfo } = await game.inputLog.sessions(appId, { first: 20 });
|
|
219
|
+
let after: string | undefined;
|
|
220
|
+
do {
|
|
221
|
+
const page = await game.inputLog.messages(appId, edges[0].node.gameTokenId, { first: 200, after });
|
|
222
|
+
for (const { node } of page.edges) handle(node.messageType, decodeBase64(node.body));
|
|
223
|
+
after = page.pageInfo.endCursor ?? undefined;
|
|
224
|
+
if (!page.pageInfo.hasNextPage) break;
|
|
225
|
+
} while (after);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
A player reads only the sessions and inputs they sent; a holder of `manage_apps` on the app reads
|
|
229
|
+
every session. Keep paging while `hasNextPage` is true: a messages page can be short, or empty,
|
|
230
|
+
when it stopped at the server's time or scan limit. Inputs are kept for the published retention,
|
|
231
|
+
so an old session can still be listed after its inputs are gone. Both calls throw
|
|
232
|
+
`INPUT_LOG_UNAVAILABLE` on a deployment without input logging, and `messages` throws it, retryable
|
|
233
|
+
with the same cursor, when the log cannot be read right now.
|
|
234
|
+
|
|
235
|
+
`App.replayLoggingEnabled` is selected on every app read and set with `apps.update(appId,
|
|
236
|
+
{ replayLoggingEnabled: true })` (`manage_apps`). Turning it on is refused with
|
|
237
|
+
`INPUT_LOG_FUNDS_NEEDED` unless the org's wallet has a spendable balance or the org is exempt from
|
|
238
|
+
billing, because stored input logs are billed (crowdedkingdoms.com/pricing). It needs ck-api with
|
|
239
|
+
the input log (`inputLogSessions`, `inputLogMessages`).
|
|
240
|
+
|
|
123
241
|
## 18.5.0: channel messages limited by distance
|
|
124
242
|
|
|
125
243
|
Additive. `client.udp.sendRangedChannelMessage(input)` publishes to a channel like
|
package/README.md
CHANGED
|
@@ -234,7 +234,7 @@ never told about, so a native refresh without it is a re-placement.
|
|
|
234
234
|
| Sub-client | What it does |
|
|
235
235
|
|---|---|
|
|
236
236
|
| `client.auth` | Sign-in: `login` / `register` (email + password), magic link, social/OIDC. Passwords: `requestPasswordReset` / `resetPassword`, `changePassword`, and `setInitialPassword` for an account created by magic link or a social provider (added in 15.1.0). Log out, and linked identities (`myIdentities`, `linkIdentity`/`unlinkIdentity`). **No dev bypass** — `devLogin` was removed in 15.0.0 and `DEV_AUTH_BYPASS` is gone from every tier. |
|
|
237
|
-
| `client.users` | `me`, `updateGamertag`, profile reads
|
|
237
|
+
| `client.users` | `me`, `updateGamertag`, profile reads; `playerProfile` / `playerProfiles` (up to 100) for other players' public `{ userId, gamertag, disambiguation }`. |
|
|
238
238
|
| `client.session` | Token store, `restore()`, `getToken()`, manual `setToken()`. |
|
|
239
239
|
| `client.portal` | App-scoped token minting (`mintAppToken`) and the cross-origin PKCE entry flow (`beginEntry` / `handleAuthorizeRequest` / `completeEntry` / `refresh`). |
|
|
240
240
|
| `client.hosting` | Third-party hosting on Crowdy Games (17.2.0): `claim` a slug for an app, `beginPublish` / `completePublish` / `abandonPublish` a built bundle, `setEnabled`; public `game(slug)` / `listed()`. Mutations need an identity session with `manage_apps`. `@crowdedkingdoms/crowdyjs/hosting` exports `publishDirectory(client, { dir, slug })`, the Node helper that does the whole publish for a `dist/`. |
|
|
@@ -243,8 +243,9 @@ never told about, so a native refresh without it is a re-placement.
|
|
|
243
243
|
| `client.chunks`, `client.voxels`, `client.actors`, `client.avatars`, `client.state` | World data reads + writes: terrain/LODs, voxel edit + history/rollback, durable actors, avatars, per-user app state blobs. |
|
|
244
244
|
| `client.host` | Game-host election (`get`, `amIHost`) + actor liveness `heartbeat`. `amIHost` is UI convenience only — a hub decides host-only actions from its caller. |
|
|
245
245
|
| `client.teleport` | Teleport requests. |
|
|
246
|
+
| `client.inputLog` | The input log (18.6.0): `sessions(appId)` and `messages(appId, gameTokenId)` read the client inputs recorded for an app with replay logging on (`apps.update(appId, { replayLoggingEnabled: true })`). A player reads their own; `manage_apps` reads every session. Keep paging while `hasNextPage` is true. |
|
|
246
247
|
| `client.channels`, `client.teams` | Messaging channels and app-scoped player teams (membership + roles). |
|
|
247
|
-
| `client.exec` | **ck-exec:** an app's server code as hubs and spokes. `connect(appId, { nodeType, key })` opens a player's connection to an execution host; the `ExecConnection` it returns has `call`, `callRaw`, `subscribe`, `ping`, `onReconnect` and `close`, with MessagePack payloads, and it reconnects and renews subscriptions by itself. `starters` / `build` / `deploy` build and deploy an app (`manage_compute`); `logs`, `instances`, `versions`, `activateVersion` and `
|
|
248
|
+
| `client.exec` | **ck-exec:** an app's server code as hubs and spokes. `connect(appId, { nodeType, key })` opens a player's connection to an execution host; the `ExecConnection` it returns has `call`, `callRaw`, `subscribe`, `ping`, `onReconnect` and `close`, with MessagePack payloads, and it reconnects and renews subscriptions by itself. `starters` / `build` / `deploy` build and deploy an app (`manage_compute`); `logs`, `instances`, `versions`, `activateVersion`, `setEnabled`, `restartType` and `status` operate it; `mod*` are players' mods on grids they own, and `modClient*`, `gridClientMods`, `consentClientMod`, `trustAuthor`, `revokeClientModConsent` and `revokeAuthorTrust` their CLIENT halves. See [ck-exec](#ck-exec). |
|
|
248
249
|
| `client.playerWallet` | Player spend: balance, ledger, hourly charges, spend caps, card setup, auto-recharge. A ck-exec mod's compute is billed here, to its owner. |
|
|
249
250
|
| `client.marketplace` | Player-authorized grid claims (`claimGridOwnership`, `claimGridChunk`, `releaseClaimedGrid`, requests and invites) and studio moderation of player code (admission queue, listing administration, claim policy). Mods publish and install through `client.exec`. |
|
|
250
251
|
| `client.crowdyStudio` | Cloud project, personal-library, and common-file APIs for Crowdy Studio: target-scoped files, metadata/module names, optimistic revisions, copy-by-value imports, atomic saves. |
|
|
@@ -263,7 +264,7 @@ grouped under `client.admin` and mirrored at the top level):
|
|
|
263
264
|
|---|---|
|
|
264
265
|
| `client.organizations` | Orgs, members, RBAC roles, org API tokens. |
|
|
265
266
|
| `client.apps` | App registry, discovery + routing (`create`, `routeFor`, `marketplace`), visibility, and player-code admission mode / allow-list administration. |
|
|
266
|
-
| `client.appAccess` | Access tiers + per-user grants, and the feature keys a tier grants (`defineFeature`, `grantTierFeature`, `tierFeatures`, …), which a hub checks with the node API's `players.features`. |
|
|
267
|
+
| `client.appAccess` | Access tiers + per-user grants, and the feature keys a tier grants (`defineFeature`, `grantTierFeature`, `tierFeatures`, …), which a hub checks with the node API's `players.features`; timed bans (`suspend`, `unsuspend`) and `resyncTierGridPermissions`. |
|
|
267
268
|
| `client.billing` | Org wallet + per-app spend budgets. |
|
|
268
269
|
| `client.payments` | Payment checkouts (wallet top-ups, plan purchases). |
|
|
269
270
|
| `client.quotas` | Usage quotas at the org/app scope. |
|
|
@@ -345,6 +346,10 @@ const unsubscribe = client.udp.subscribe(
|
|
|
345
346
|
},
|
|
346
347
|
clientEvent: (event) => { /* ... */ },
|
|
347
348
|
serverEvent: (event) => { /* ... */ },
|
|
349
|
+
genericSpatial: (event) => {
|
|
350
|
+
// An app-defined spatial payload (opcode 140): binary relay only, see below.
|
|
351
|
+
console.log(event.uuid, event.payload); // payload is base64
|
|
352
|
+
},
|
|
348
353
|
singleActorMessage: (event) => {
|
|
349
354
|
// A direct actor-to-actor message addressed to you.
|
|
350
355
|
console.log(event.uuid, event.payload); // payload is base64
|
|
@@ -385,6 +390,13 @@ while `AUTH_REQUIRED` / `APP_ID_REQUIRED` must be fixed by the caller first.
|
|
|
385
390
|
Unsubscribing stops delivery only; call `client.udp.disconnect()` to close the
|
|
386
391
|
UDP proxy session.
|
|
387
392
|
|
|
393
|
+
`genericSpatial` receives opcode 140 (`GENERIC_SPATIAL_1`), an app-defined spatial payload the
|
|
394
|
+
server fans out without reading — what CrowdyCPP's `Connection::sendGenericSpatial` sends. It
|
|
395
|
+
arrives only on the binary relay (`realtime: { binaryTransport: true }`): the GraphQL
|
|
396
|
+
`udpNotifications` union has no member for it, so the GraphQL proxy drops it and a client on that
|
|
397
|
+
transport never sees one. A World Stores session carries it on its bus too:
|
|
398
|
+
`session.context.on('genericSpatial', …)`.
|
|
399
|
+
|
|
388
400
|
### Surviving the loss of an instance (direct connect)
|
|
389
401
|
|
|
390
402
|
**If your environment uses direct connect, set `realtime.discoveryUrl`.** Under
|
|
@@ -449,6 +461,12 @@ with a live actor within `maxDistance` chunks (straight-line distance between
|
|
|
449
461
|
chunk coordinates) of `chunk` receive it; they get the same `channelMessage`
|
|
450
462
|
notification.
|
|
451
463
|
|
|
464
|
+
`sendVoxelUpdate` takes the app's signed 16-bit positions and type and a state of
|
|
465
|
+
at most 1,024 bytes (`RangeError` otherwise, nothing sent). Buddy v0.37.0 echoes
|
|
466
|
+
every accepted voxel edit back to its sender as a `voxelUpdate`, so a game reading
|
|
467
|
+
those sees its own edits; World Stores' `ChunkStore` applies that echo once. A
|
|
468
|
+
paused app's sends are refused with UDP error 33, `APP_PAUSED`.
|
|
469
|
+
|
|
452
470
|
### Bundled sends on the binary relay
|
|
453
471
|
|
|
454
472
|
With `realtime: { binaryTransport: true }` the SDK signs each message itself
|
|
@@ -476,6 +494,76 @@ await client.udp.sendSingleActorMessage({
|
|
|
476
494
|
});
|
|
477
495
|
```
|
|
478
496
|
|
|
497
|
+
### Voice payloads
|
|
498
|
+
|
|
499
|
+
`sendAudioPacket` carries whatever bytes it is given, and a game with a voice format of its own
|
|
500
|
+
keeps it. The voice helpers are an optional one that both SDKs share (CrowdyCPP's
|
|
501
|
+
`crowdy/media/voice_frames.hpp`, held to the same cases in `test/unit/fixtures/voice-frames.json`):
|
|
502
|
+
a 10-byte header in front of each codec frame, little-endian — the version (1), the codec (0 raw,
|
|
503
|
+
1 Opus 48 kHz mono, 2 G.711 µ-law 8 kHz), a `u16` seq, a `u32` timestamp in codec samples, the
|
|
504
|
+
frame's duration in milliseconds and two talk-spurt flags (bit 0 the first packet after silence,
|
|
505
|
+
bit 1 the last before it). A reader refuses a packet shorter than the header or of another
|
|
506
|
+
version. `VoicePacketizer` numbers one sender's frames; `VoiceJitterBuffer` puts each sender's
|
|
507
|
+
packets back in order, plays them out 60 ms (`targetDelayMs`) after the first packet of a talk
|
|
508
|
+
spurt arrived, reports a frame that never came as a gap, drops one that arrives after its
|
|
509
|
+
playout time, and holds at most 64 frames a sender.
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
import {
|
|
513
|
+
VoiceCodec, VoiceJitterBuffer, VoicePacketizer, decodeBase64, encodeBase64,
|
|
514
|
+
} from '@crowdedkingdoms/crowdyjs';
|
|
515
|
+
|
|
516
|
+
const packetizer = new VoicePacketizer({ codec: VoiceCodec.OPUS, frameMs: 20 });
|
|
517
|
+
// Every 20 ms while the player talks (`opusFrame` from a WebCodecs AudioEncoder):
|
|
518
|
+
await client.udp.sendAudioPacket({
|
|
519
|
+
appId, chunk, uuid: me.uuid,
|
|
520
|
+
audioData: encodeBase64(packetizer.packetize(opusFrame, { last: talkKeyReleased })),
|
|
521
|
+
});
|
|
522
|
+
// ...and packetizer.skip() for every 20 ms of silence that is not sent.
|
|
523
|
+
|
|
524
|
+
const voices = new VoiceJitterBuffer();
|
|
525
|
+
client.udp.subscribe({
|
|
526
|
+
audio: (n) => voices.push(n.uuid, decodeBase64(n.audioData), performance.now()),
|
|
527
|
+
actorLeft: (n) => voices.forget(n.uuid),
|
|
528
|
+
}, appId);
|
|
529
|
+
// From the audio clock, at least once a frame:
|
|
530
|
+
for (const slot of voices.poll(performance.now())) {
|
|
531
|
+
if (slot.gap) conceal(slot.key, slot.frameMs); // the frame never came
|
|
532
|
+
else play(slot.key, slot.codec, slot.frame!);
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
The SDK ships no codec. A browser encodes and decodes Opus with WebCodecs (`AudioEncoder` /
|
|
537
|
+
`AudioDecoder`, `codec: 'opus'`, 48 kHz, one channel; check `AudioEncoder.isConfigSupported`
|
|
538
|
+
first) and falls back to G.711 µ-law where it has none; `media/voice-frames.ts` has the settings.
|
|
539
|
+
Where a voice sits in the world (panning, distance attenuation) stays the game's.
|
|
540
|
+
|
|
541
|
+
#### Channel audio (party and guild voice)
|
|
542
|
+
|
|
543
|
+
`sendAudioPacket` reaches players near a chunk. `sendChannelAudio` (Buddy v0.37.0) reaches every
|
|
544
|
+
active member of a channel wherever they are: opcode 35 on the binary relay, the
|
|
545
|
+
`sendChannelAudio` mutation otherwise, at most 1,024 payload bytes. The sender needs the channel's
|
|
546
|
+
`send_voice` (`channels.create({ ..., membersCanSpeak: true })` gives it to the member role) and the
|
|
547
|
+
app's `use_voice_chat`; without them the server answers `UNAUTHORIZED` on the subscription. There is
|
|
548
|
+
no echo. Members get a `channelAudio` notification; key the jitter buffer by channel and sender so
|
|
549
|
+
one player in two channels is two streams. It arrives on the binary relay and on the GraphQL
|
|
550
|
+
transport alike.
|
|
551
|
+
|
|
552
|
+
```ts
|
|
553
|
+
const party = new VoicePacketizer({ codec: VoiceCodec.OPUS, frameMs: 20 });
|
|
554
|
+
await client.udp.sendChannelAudio({
|
|
555
|
+
channelId, uuid: me.uuid,
|
|
556
|
+
payload: encodeBase64(party.packetize(opusFrame, { last: talkKeyReleased })),
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
const partyVoices = new VoiceJitterBuffer();
|
|
560
|
+
client.udp.subscribe({
|
|
561
|
+
channelAudio: (n) =>
|
|
562
|
+
partyVoices.push(`${n.channelId}:${n.uuid}`, decodeBase64(n.audioData), performance.now()),
|
|
563
|
+
}, appId);
|
|
564
|
+
// ...poll(performance.now()) from the audio clock as above.
|
|
565
|
+
```
|
|
566
|
+
|
|
479
567
|
## World helpers
|
|
480
568
|
|
|
481
569
|
```ts
|
|
@@ -544,7 +632,9 @@ holds it to rules of its own (18.0.2): `grid_permission_check` answers only for
|
|
|
544
632
|
the player's four code-permission keys (`GRID_PERMISSION_CHECK_KEYS`) and
|
|
545
633
|
refuses any other key instead of answering false, because a game knows no other
|
|
546
634
|
key for a grid; `voxel_set` takes a voxel inside its chunk (0-15) and a type
|
|
547
|
-
0-255
|
|
635
|
+
0-255, or the ranges the game sets with `createGridHostCalls({ voxelBounds })` for a world
|
|
636
|
+
whose positions and types are other signed 16-bit values (18.7.0); and a half's spatial and
|
|
637
|
+
channel sends go out as an actor uuid the page
|
|
548
638
|
derives for the grid from the one the half names (`clientHalfActorUuid`), so a
|
|
549
639
|
half can never move the player's avatar or speak as another player. The broker
|
|
550
640
|
refuses a call that names its chunk a second way (`chunk`, `chunk_x`, …): route
|
|
@@ -613,6 +703,14 @@ another player's realtime voxel update) reaches a reload only through hydration:
|
|
|
613
703
|
returns it in `voxelStates`, and the bulk load's `voxels` never hold it. The store hydrates when
|
|
614
704
|
it has a `voxelStateCodec`; without one, set `chunks: { hydrateVoxelStates: true }`.
|
|
615
705
|
|
|
706
|
+
`chunks` is a helper for 16×16×16 chunks with one byte per voxel. Voxel positions and types are
|
|
707
|
+
the app's signed 16-bit values, which the platform does not check: an edit the dense grid cannot
|
|
708
|
+
hold (a type outside 0-255, a position outside 0-15), whether a realtime update, a hydrated
|
|
709
|
+
`voxelStates` entry or a local `setVoxel`, is kept whole in the chunk's `overlay` (keyed by
|
|
710
|
+
`voxelKey(x, y, z)`) instead of being truncated into `voxels`, and `voxelTypeAt` / `voxelStateAt`
|
|
711
|
+
return it (18.7.0). A game with other addressing reads the raw `voxelUpdate` events and
|
|
712
|
+
`chunks.get`'s `voxelStates`.
|
|
713
|
+
|
|
616
714
|
A chunk write-back the server refuses (a visitor on someone else's plot, a safe zone, a closed
|
|
617
715
|
wilderness) is dropped, not retried; one that fails for a reason that can clear is tried five
|
|
618
716
|
times. Listen with `session.chunks.onWriteBackFailed(...)` to undo or flag the edit (18.0.4).
|
|
@@ -985,6 +1083,13 @@ GraphQL errors carry a stable `extensions.code` (e.g. `UNAUTHENTICATED`,
|
|
|
985
1083
|
where applicable, `extensions.remediation` and `extensions.requiredPermission`.
|
|
986
1084
|
Branch on `error.extensions?.code` rather than parsing messages.
|
|
987
1085
|
|
|
1086
|
+
Readers for the refusals a player should be told about, each `null` for any other error:
|
|
1087
|
+
`accessRefusalOf(err)` (`ACCESS_REVOKED`, `ACCESS_SUSPENDED` with `suspendedUntil`,
|
|
1088
|
+
`ACCESS_NOT_GRANTED`), `appPausedOf(err)` (`APP_PAUSED`, with `reason`) and `actorExistsOf(err)`
|
|
1089
|
+
(`ACTOR_EXISTS`; `ownedByCaller: true` means a retried create of your own actor). A paused app
|
|
1090
|
+
still mints tokens: check `isAppPaused(token.runtimeGate)` (or the bootstrap's `runtimeGate`)
|
|
1091
|
+
before entering the world.
|
|
1092
|
+
|
|
988
1093
|
## Idempotent retries
|
|
989
1094
|
|
|
990
1095
|
Destructive game-client mutations accept an optional **idempotency key**. Pass
|
package/dist/binary-wire.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ export declare const WireMessageType: {
|
|
|
52
52
|
readonly CHANNEL_MESSAGE_REQUEST: 17;
|
|
53
53
|
readonly CHANNEL_MESSAGE_NOTIFICATION: 18;
|
|
54
54
|
readonly CHANNEL_MESSAGE_RANGED_REQUEST: 32;
|
|
55
|
+
readonly CHANNEL_AUDIO_REQUEST: 35;
|
|
56
|
+
readonly CHANNEL_AUDIO_NOTIFICATION: 36;
|
|
55
57
|
readonly ACTOR_UPDATE_REQUEST_2: 128;
|
|
56
58
|
readonly ACTOR_UPDATE_RESPONSE_2: 129;
|
|
57
59
|
readonly ACTOR_UPDATE_NOTIFICATION_2: 130;
|
|
@@ -64,6 +66,7 @@ export declare const WireMessageType: {
|
|
|
64
66
|
readonly CLIENT_TEXT_NOTIFICATION_2: 137;
|
|
65
67
|
readonly CLIENT_EVENT_NOTIFICATION_2: 138;
|
|
66
68
|
readonly SERVER_EVENT_NOTIFICATION_2: 139;
|
|
69
|
+
readonly GENERIC_SPATIAL_1: 140;
|
|
67
70
|
readonly SINGLE_ACTOR_MESSAGE: 142;
|
|
68
71
|
readonly CLIENT_VIDEO_PACKET_2: 143;
|
|
69
72
|
readonly CLIENT_VIDEO_NOTIFICATION_2: 144;
|
|
@@ -111,6 +114,23 @@ export interface SpatialSendBase {
|
|
|
111
114
|
export declare function serializeActorUpdate(ctx: RelaySignContext, input: SpatialSendBase & {
|
|
112
115
|
state: string;
|
|
113
116
|
}): Promise<Uint8Array>;
|
|
117
|
+
/** Most bytes a voxel edit's state may carry; the server refuses longer with INVALID_REQUEST. */
|
|
118
|
+
export declare const VOXEL_STATE_MAX_BYTES = 1024;
|
|
119
|
+
/**
|
|
120
|
+
* Check a voxel edit before it is sent: positions and type are app-defined
|
|
121
|
+
* signed 16-bit integers (no narrower range), and the state is at most
|
|
122
|
+
* {@link VOXEL_STATE_MAX_BYTES} decoded.
|
|
123
|
+
* @throws {RangeError} naming the field that does not fit.
|
|
124
|
+
*/
|
|
125
|
+
export declare function assertVoxelEdit(input: {
|
|
126
|
+
voxel: {
|
|
127
|
+
x: number;
|
|
128
|
+
y: number;
|
|
129
|
+
z: number;
|
|
130
|
+
};
|
|
131
|
+
voxelType: number;
|
|
132
|
+
voxelState?: string | null;
|
|
133
|
+
}): void;
|
|
114
134
|
export declare function serializeVoxelUpdate(ctx: RelaySignContext, input: SpatialSendBase & {
|
|
115
135
|
voxel: {
|
|
116
136
|
x: number;
|
|
@@ -153,12 +173,20 @@ export declare function serializeSingleActorMessage(ctx: RelaySignContext, input
|
|
|
153
173
|
* `[1B type=17][8B channelId][32B uuid][2B payloadLen][payload][1B containsAuth]
|
|
154
174
|
* [32B HMAC][8B gameTokenId][1B seq]` — HMAC over everything before it.
|
|
155
175
|
*/
|
|
156
|
-
export declare function serializeChannelMessage(ctx: RelaySignContext, input:
|
|
176
|
+
export declare function serializeChannelMessage(ctx: RelaySignContext, input: ChannelSendInput): Promise<Uint8Array>;
|
|
177
|
+
/**
|
|
178
|
+
* CHANNEL_AUDIO_REQUEST (Buddy v0.37.0): opcode 17's layout and signing with
|
|
179
|
+
* type byte 35. The payload is opaque (at most 1,024 bytes), typically one
|
|
180
|
+
* {@link VoicePacketizer} packet.
|
|
181
|
+
*/
|
|
182
|
+
export declare function serializeChannelAudio(ctx: RelaySignContext, input: ChannelSendInput): Promise<Uint8Array>;
|
|
183
|
+
/** Input shared by the channel message and channel audio uplinks (`ChannelMessageInput`). */
|
|
184
|
+
export interface ChannelSendInput {
|
|
157
185
|
channelId: string;
|
|
158
186
|
uuid: string;
|
|
159
187
|
payload?: string | null;
|
|
160
188
|
sequenceNumber?: number | null;
|
|
161
|
-
}
|
|
189
|
+
}
|
|
162
190
|
/** Largest `maxDistance` a ranged channel message may carry (the GraphQL `Int` ceiling). */
|
|
163
191
|
export declare const CHANNEL_RANGED_MAX_DISTANCE = 2147483647;
|
|
164
192
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binary-wire.d.ts","sourceRoot":"","sources":["../src/binary-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAC5C,uEAAuE;AACvE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,qEAAqE;AACrE,eAAO,MAAM,6BAA6B,QACmC,CAAC;AAE9E;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAInE;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,UAAU,CAwB5E;AAED,kEAAkE;AAClE,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"binary-wire.d.ts","sourceRoot":"","sources":["../src/binary-wire.ts"],"names":[],"mappings":"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"}
|
package/dist/binary-wire.js
CHANGED
|
@@ -89,6 +89,9 @@ export const WireMessageType = {
|
|
|
89
89
|
// Buddy v0.35.0: a channel publish only members near an origin chunk receive
|
|
90
90
|
// (they get an ordinary CHANNEL_MESSAGE_NOTIFICATION).
|
|
91
91
|
CHANNEL_MESSAGE_RANGED_REQUEST: 32,
|
|
92
|
+
// Buddy v0.37.0: channel audio, laid out exactly as 17 / 18 with their own type byte.
|
|
93
|
+
CHANNEL_AUDIO_REQUEST: 35,
|
|
94
|
+
CHANNEL_AUDIO_NOTIFICATION: 36,
|
|
92
95
|
ACTOR_UPDATE_REQUEST_2: 128,
|
|
93
96
|
ACTOR_UPDATE_RESPONSE_2: 129,
|
|
94
97
|
ACTOR_UPDATE_NOTIFICATION_2: 130,
|
|
@@ -101,6 +104,9 @@ export const WireMessageType = {
|
|
|
101
104
|
CLIENT_TEXT_NOTIFICATION_2: 137,
|
|
102
105
|
CLIENT_EVENT_NOTIFICATION_2: 138,
|
|
103
106
|
SERVER_EVENT_NOTIFICATION_2: 139,
|
|
107
|
+
// An app-defined spatial payload (CrowdyCPP `Connection::sendGenericSpatial`, a hub's
|
|
108
|
+
// emit). Parsed on the binary relay only: the GraphQL union has no member for it.
|
|
109
|
+
GENERIC_SPATIAL_1: 140,
|
|
104
110
|
SINGLE_ACTOR_MESSAGE: 142,
|
|
105
111
|
// Buddy v0.25.0: webcam video pair (audio's shape, payload = one SDK
|
|
106
112
|
// fragment, see media/video-frames.ts) and the server-only actor-left downlink.
|
|
@@ -153,6 +159,7 @@ const UDP_ERROR_NAMES = {
|
|
|
153
159
|
30: 'CANNOT_DELETE_DEFAULT_WORLD_GRID',
|
|
154
160
|
31: 'GRID_HAS_NESTED_CHILDREN',
|
|
155
161
|
32: 'TOKEN_EXPIRED',
|
|
162
|
+
33: 'APP_PAUSED',
|
|
156
163
|
};
|
|
157
164
|
const textEncoder = new TextEncoder();
|
|
158
165
|
const textDecoder = new TextDecoder();
|
|
@@ -252,6 +259,29 @@ export function serializeClientCapabilities(ctx, appId, flags = SDK_CAPABILITIES
|
|
|
252
259
|
export function serializeActorUpdate(ctx, input) {
|
|
253
260
|
return serializeSpatial(ctx, WireMessageType.ACTOR_UPDATE_REQUEST_2, input.appId, input.chunk, input.distance ?? 8, input.decayRate ?? 1, input.uuid, decodeBase64(input.state ?? ''), input.sequenceNumber ?? 0);
|
|
254
261
|
}
|
|
262
|
+
/** Most bytes a voxel edit's state may carry; the server refuses longer with INVALID_REQUEST. */
|
|
263
|
+
export const VOXEL_STATE_MAX_BYTES = 1024;
|
|
264
|
+
/**
|
|
265
|
+
* Check a voxel edit before it is sent: positions and type are app-defined
|
|
266
|
+
* signed 16-bit integers (no narrower range), and the state is at most
|
|
267
|
+
* {@link VOXEL_STATE_MAX_BYTES} decoded.
|
|
268
|
+
* @throws {RangeError} naming the field that does not fit.
|
|
269
|
+
*/
|
|
270
|
+
export function assertVoxelEdit(input) {
|
|
271
|
+
const int16 = (name, v) => {
|
|
272
|
+
if (!Number.isInteger(v) || v < -32768 || v > 32767) {
|
|
273
|
+
throw new RangeError(`${name} must be a signed 16-bit integer: ${v}`);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
int16('voxel.x', input.voxel.x);
|
|
277
|
+
int16('voxel.y', input.voxel.y);
|
|
278
|
+
int16('voxel.z', input.voxel.z);
|
|
279
|
+
int16('voxelType', input.voxelType);
|
|
280
|
+
const stateBytes = input.voxelState ? decodeBase64(input.voxelState).length : 0;
|
|
281
|
+
if (stateBytes > VOXEL_STATE_MAX_BYTES) {
|
|
282
|
+
throw new RangeError(`voxelState is ${stateBytes} bytes; at most ${VOXEL_STATE_MAX_BYTES}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
255
285
|
export function serializeVoxelUpdate(ctx, input) {
|
|
256
286
|
const voxelState = decodeBase64(input.voxelState ?? '');
|
|
257
287
|
const payload = new Uint8Array(10 + voxelState.length);
|
|
@@ -292,7 +322,18 @@ export function serializeSingleActorMessage(ctx, input) {
|
|
|
292
322
|
* `[1B type=17][8B channelId][32B uuid][2B payloadLen][payload][1B containsAuth]
|
|
293
323
|
* [32B HMAC][8B gameTokenId][1B seq]` — HMAC over everything before it.
|
|
294
324
|
*/
|
|
295
|
-
export
|
|
325
|
+
export function serializeChannelMessage(ctx, input) {
|
|
326
|
+
return serializeChannelFrame(ctx, WireMessageType.CHANNEL_MESSAGE_REQUEST, input);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* CHANNEL_AUDIO_REQUEST (Buddy v0.37.0): opcode 17's layout and signing with
|
|
330
|
+
* type byte 35. The payload is opaque (at most 1,024 bytes), typically one
|
|
331
|
+
* {@link VoicePacketizer} packet.
|
|
332
|
+
*/
|
|
333
|
+
export function serializeChannelAudio(ctx, input) {
|
|
334
|
+
return serializeChannelFrame(ctx, WireMessageType.CHANNEL_AUDIO_REQUEST, input);
|
|
335
|
+
}
|
|
336
|
+
async function serializeChannelFrame(ctx, messageType, input) {
|
|
296
337
|
const payload = input.payload ? decodeBase64(input.payload) : new Uint8Array(0);
|
|
297
338
|
if (payload.length > 1024) {
|
|
298
339
|
throw new Error(`Channel payload exceeds 1024 bytes: ${payload.length}`);
|
|
@@ -305,7 +346,7 @@ export async function serializeChannelMessage(ctx, input) {
|
|
|
305
346
|
const prefix = new Uint8Array(prefixLen);
|
|
306
347
|
const view = new DataView(prefix.buffer);
|
|
307
348
|
let off = 0;
|
|
308
|
-
view.setUint8(off,
|
|
349
|
+
view.setUint8(off, messageType);
|
|
309
350
|
off += 1;
|
|
310
351
|
view.setBigUint64(off, BigInt(input.channelId), true);
|
|
311
352
|
off += 8;
|
|
@@ -462,7 +503,8 @@ function parseOne(bytes) {
|
|
|
462
503
|
'UNKNOWN_ERROR'),
|
|
463
504
|
};
|
|
464
505
|
}
|
|
465
|
-
if (messageType === WireMessageType.CHANNEL_MESSAGE_NOTIFICATION
|
|
506
|
+
if (messageType === WireMessageType.CHANNEL_MESSAGE_NOTIFICATION ||
|
|
507
|
+
messageType === WireMessageType.CHANNEL_AUDIO_NOTIFICATION) {
|
|
466
508
|
// [1B type][8B channelId][32B senderUuid][2B payloadLen][payload][8B epochMillis][1B seq]
|
|
467
509
|
if (bytes.length < 1 + 8 + UUID_SIZE + 2)
|
|
468
510
|
return null;
|
|
@@ -480,6 +522,16 @@ function parseOne(bytes) {
|
|
|
480
522
|
const epochMillis = view.getBigUint64(off, true);
|
|
481
523
|
off += 8;
|
|
482
524
|
const sequenceNumber = view.getUint8(off);
|
|
525
|
+
if (messageType === WireMessageType.CHANNEL_AUDIO_NOTIFICATION) {
|
|
526
|
+
return {
|
|
527
|
+
__typename: 'ChannelAudioNotification',
|
|
528
|
+
channelId: channelId.toString(),
|
|
529
|
+
uuid,
|
|
530
|
+
audioData: encodeBase64(payload),
|
|
531
|
+
sequenceNumber,
|
|
532
|
+
epochMillis: epochMillis.toString(),
|
|
533
|
+
};
|
|
534
|
+
}
|
|
483
535
|
return {
|
|
484
536
|
__typename: 'ChannelMessageNotification',
|
|
485
537
|
channelId: channelId.toString(),
|
|
@@ -574,6 +626,12 @@ function parseOne(bytes) {
|
|
|
574
626
|
payload: encodeBase64(p.payload),
|
|
575
627
|
};
|
|
576
628
|
}
|
|
629
|
+
case WireMessageType.GENERIC_SPATIAL_1:
|
|
630
|
+
return {
|
|
631
|
+
__typename: 'GenericSpatialNotification',
|
|
632
|
+
...spatialCommon(p),
|
|
633
|
+
payload: encodeBase64(p.payload),
|
|
634
|
+
};
|
|
577
635
|
default:
|
|
578
636
|
return null;
|
|
579
637
|
}
|
package/dist/crowdy-client.d.ts
CHANGED
|
@@ -51,6 +51,7 @@ import { GameAppsAPI } from './domains/gameApps.js';
|
|
|
51
51
|
import { VoxelsAPI } from './domains/voxels.js';
|
|
52
52
|
import { ActorsAPI } from './domains/actors.js';
|
|
53
53
|
import { TeleportAPI } from './domains/teleport.js';
|
|
54
|
+
import { InputLogAPI } from './domains/inputLog.js';
|
|
54
55
|
import { StateAPI } from './domains/state.js';
|
|
55
56
|
import { ServerStatusAPI } from './domains/serverStatus.js';
|
|
56
57
|
import { ChannelsAPI } from './domains/channels.js';
|
|
@@ -267,6 +268,8 @@ export declare class CrowdyClient {
|
|
|
267
268
|
readonly actors: ActorsAPI;
|
|
268
269
|
/** Teleport: move an actor to a destination chunk/world. */
|
|
269
270
|
readonly teleport: TeleportAPI;
|
|
271
|
+
/** The input log: recorded client inputs of an app with replay logging on. */
|
|
272
|
+
readonly inputLog: InputLogAPI;
|
|
270
273
|
/** Per-user/per-app persisted state blobs. */
|
|
271
274
|
readonly state: StateAPI;
|
|
272
275
|
/** Server status + version discovery (UDP availability, version floors). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crowdy-client.d.ts","sourceRoot":"","sources":["../src/crowdy-client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"crowdy-client.d.ts","sourceRoot":"","sources":["../src/crowdy-client.ts"],"names":[],"mappings":"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"}
|
package/dist/crowdy-client.js
CHANGED
|
@@ -52,6 +52,7 @@ import { GameAppsAPI } from './domains/gameApps.js';
|
|
|
52
52
|
import { VoxelsAPI } from './domains/voxels.js';
|
|
53
53
|
import { ActorsAPI } from './domains/actors.js';
|
|
54
54
|
import { TeleportAPI } from './domains/teleport.js';
|
|
55
|
+
import { InputLogAPI } from './domains/inputLog.js';
|
|
55
56
|
import { StateAPI } from './domains/state.js';
|
|
56
57
|
import { ServerStatusAPI } from './domains/serverStatus.js';
|
|
57
58
|
import { ChannelsAPI } from './domains/channels.js';
|
|
@@ -203,6 +204,7 @@ export class CrowdyClient {
|
|
|
203
204
|
this.voxels = new VoxelsAPI(this.graphql);
|
|
204
205
|
this.actors = new ActorsAPI(this.graphql);
|
|
205
206
|
this.teleport = new TeleportAPI(this.graphql);
|
|
207
|
+
this.inputLog = new InputLogAPI(this.graphql);
|
|
206
208
|
this.state = new StateAPI(this.graphql);
|
|
207
209
|
this.serverStatus = new ServerStatusAPI(this.graphql);
|
|
208
210
|
this.channels = new ChannelsAPI(this.graphql);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { GraphQLClient } from '../client.js';
|
|
2
|
-
import { type DefineAppFeatureInput, type DefineAppFeatureMutation, type AppFeaturesQuery, type GrantTierFeatureInput, type GrantTierFeatureMutation, type TierFeaturesQuery, type AppAccessTiersQuery, type MyAppAccessQuery, type AppUserAccessByAppQuery, type AppUserAccessConnectionQuery, type AppUserAccessConnectionQueryVariables, type RuntimePermissionsQuery, type AppGrantMemberCandidatesQuery, type ClaimFreeAppAccessMutation, type GrantMyAppAccessMutation, type CreateAccessTierMutation, type UpdateAccessTierMutation, type ArchiveAccessTierMutation, type GrantAppAccessMutation, type RevokeAppAccessMutation, type CreateAccessTierInput, type UpdateAccessTierInput, type GrantAppAccessInput } from '../generated/graphql.js';
|
|
2
|
+
import { type SuspendAppAccessMutation, type UnsuspendAppAccessMutation, type DefineAppFeatureInput, type DefineAppFeatureMutation, type AppFeaturesQuery, type GrantTierFeatureInput, type GrantTierFeatureMutation, type TierFeaturesQuery, type AppAccessTiersQuery, type MyAppAccessQuery, type AppUserAccessByAppQuery, type AppUserAccessConnectionQuery, type AppUserAccessConnectionQueryVariables, type RuntimePermissionsQuery, type AppGrantMemberCandidatesQuery, type ClaimFreeAppAccessMutation, type GrantMyAppAccessMutation, type CreateAccessTierMutation, type UpdateAccessTierMutation, type ArchiveAccessTierMutation, type GrantAppAccessMutation, type RevokeAppAccessMutation, type CreateAccessTierInput, type UpdateAccessTierInput, type GrantAppAccessInput } from '../generated/graphql.js';
|
|
3
3
|
/**
|
|
4
4
|
* App access tiers + per-user access grants — exposed as `client.appAccess`
|
|
5
5
|
* (and grouped under `client.admin`).
|
|
@@ -137,6 +137,37 @@ export declare class AppAccessAPI {
|
|
|
137
137
|
* @returns `true` on success.
|
|
138
138
|
*/
|
|
139
139
|
revoke(appId: string, userId: string): Promise<RevokeAppAccessMutation['revokeAppAccess']>;
|
|
140
|
+
/**
|
|
141
|
+
* Suspend a player's access to an app until `until`: a timed ban that lifts by
|
|
142
|
+
* itself. Until then their gameplay tokens are refused with `ACCESS_SUSPENDED`
|
|
143
|
+
* (carrying `suspendedUntil`, see `accessRefusalOf`), and the tokens they hold
|
|
144
|
+
* for the app are deleted and their realtime sessions ended at once. `until`
|
|
145
|
+
* must be in the future and at most 365 days away; the player must have an
|
|
146
|
+
* access record. Requires the `manage_access_tiers` app permission.
|
|
147
|
+
*
|
|
148
|
+
* @param appId - Numeric app id.
|
|
149
|
+
* @param userId - Numeric id of the player to suspend.
|
|
150
|
+
* @param until - When the suspension lapses (a `Date` or ISO-8601 string).
|
|
151
|
+
* @param idempotencyKey - Optional; a replay with the same key and arguments returns the first result.
|
|
152
|
+
* @returns The access record, with `suspendedUntil` set.
|
|
153
|
+
*/
|
|
154
|
+
suspend(appId: string, userId: string, until: Date | string, idempotencyKey?: string): Promise<SuspendAppAccessMutation['suspendAppAccess']>;
|
|
155
|
+
/**
|
|
156
|
+
* Lift a player's suspension before it lapses (a no-op for a player who is
|
|
157
|
+
* not suspended). Requires the `manage_access_tiers` app permission.
|
|
158
|
+
*
|
|
159
|
+
* @param appId - Numeric app id.
|
|
160
|
+
* @param userId - Numeric id of the player whose suspension to lift.
|
|
161
|
+
* @returns The access record, with `suspendedUntil` cleared.
|
|
162
|
+
*/
|
|
163
|
+
unsuspend(appId: string, userId: string): Promise<UnsuspendAppAccessMutation['unsuspendAppAccess']>;
|
|
164
|
+
/**
|
|
165
|
+
* Re-apply every player's tier keys that follow onto the app's world grid and
|
|
166
|
+
* rebuild the world grid's permissions. Tier changes made through this API
|
|
167
|
+
* already do it; call it after a change made another way. Requires the
|
|
168
|
+
* `manage_access_tiers` app permission.
|
|
169
|
+
*/
|
|
170
|
+
resyncTierGridPermissions(appId: string): Promise<boolean>;
|
|
140
171
|
/**
|
|
141
172
|
* Define (or re-describe) a feature key for an app. Idempotent on `(appId, featureKey)`.
|
|
142
173
|
* Requires the app-admin `manage_apps` permission.
|