@crowdedkingdoms/crowdyjs 15.4.2 → 15.5.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/README.md CHANGED
@@ -174,7 +174,7 @@ never told about, so a native refresh without it is a re-placement.
174
174
  — `appId` is **required** (the SDK opens the realtime socket on demand and
175
175
  scopes it to that app).
176
176
  4. Join a chunk by sending an initial actor update.
177
- 5. Send actor, voxel, text, audio, and client-event updates through `game.udp`
177
+ 5. Send actor, voxel, text, audio, video, and client-event updates through `game.udp`
178
178
  or the higher-level `game.world(appId)` helpers.
179
179
  6. Before the app token expires, call `game.refreshGameplayToken()`.
180
180
  7. Call `client.close()` (and `game.close()`) when disposing the SDK instances.
@@ -203,7 +203,7 @@ never told about, so a native refresh without it is a re-placement.
203
203
  | `client.marketplace` | Player-code store/install/consent flows plus player-authorized grid claims (`claimGridOwnership`, `claimGridChunk`, `releaseClaimedGrid`) and client-mod artifact fetches. |
204
204
  | `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. |
205
205
  | `client.crowdyStudioAgent` | Generated, app-token Game API transport for durable agent sessions: history/session pages, descriptors/budgets, approvals, tool results, heartbeat, control mutations, ordered event subscriptions. |
206
- | `client.udp` | UDP proxy subscriptions + spatial mutations (`sendActorUpdate`, `sendVoxelUpdate`, `sendAudioPacket`, `sendTextPacket`, `sendClientEvent`, `sendSingleActorMessage`, `sendChannelMessage`). |
206
+ | `client.udp` | UDP proxy subscriptions + spatial mutations (`sendActorUpdate`, `sendVoxelUpdate`, `sendAudioPacket`, `sendVideoPacket` / `sendVideoFrame`, `sendTextPacket`, `sendClientEvent`, `sendSingleActorMessage`, `sendChannelMessage`). |
207
207
  | `client.realtime` | Connection status, manual `connect()` / `disconnect()`, `onStatus()` listener. |
208
208
  | `client.refreshGameplayToken()` | Safely rotates an active game client's app token (see [Token refresh](#token-refresh-during-gameplay)). |
209
209
  | `client.world(appId)` | Higher-level helpers for browser games (`actor.join`, `actor.sendState`, `actor.sendText`, `actor.sendToActor`). |
@@ -287,6 +287,16 @@ const unsubscribe = client.udp.subscribe(
287
287
  voxelUpdate: (event) => { /* ... */ },
288
288
  text: (event) => { /* ... */ },
289
289
  audio: (event) => { /* ... */ },
290
+ video: (event) => {
291
+ // One webcam fragment; feed a VideoFrameAssembler to get whole frames.
292
+ const frame = assembler.ingest(event.uuid, decodeBase64(event.videoData));
293
+ if (frame) drawJpeg(event.uuid, frame.bytes);
294
+ },
295
+ actorLeft: (event) => {
296
+ // The server says this actor is gone (about 5 s after its last update).
297
+ // World Stores do this for you: `session.actors.onLeave` fires at once.
298
+ removeAvatar(event.uuid);
299
+ },
290
300
  clientEvent: (event) => { /* ... */ },
291
301
  serverEvent: (event) => { /* ... */ },
292
302
  singleActorMessage: (event) => {
@@ -460,6 +470,9 @@ session.self.patchState({ x: 12.5, yaw: 1.57 });
460
470
  console.log(session.self.status, session.self.lastAck?.state);
461
471
 
462
472
  // Everyone else: typed, self-filtered, staleness-managed — render from it.
473
+ // A departure the server announces (ActorLeftNotification, Buddy v0.25.0)
474
+ // removes the actor and fires `onLeave` immediately; the 12 s reaper is the
475
+ // fallback for a lost datagram. A later update for the same uuid is a rejoin.
463
476
  for (const actor of session.actors.list()) {
464
477
  render(actor.uuid, actor.state, actor.samples); // samples → interpolation
465
478
  }
@@ -34,6 +34,9 @@ export declare const WireMessageType: {
34
34
  readonly CLIENT_EVENT_NOTIFICATION_2: 138;
35
35
  readonly SERVER_EVENT_NOTIFICATION_2: 139;
36
36
  readonly SINGLE_ACTOR_MESSAGE: 142;
37
+ readonly CLIENT_VIDEO_PACKET_2: 143;
38
+ readonly CLIENT_VIDEO_NOTIFICATION_2: 144;
39
+ readonly ACTOR_LEFT_NOTIFICATION_2: 145;
37
40
  };
38
41
  /**
39
42
  * Per-session signing context: the game token id (from the relay `ready`
@@ -73,6 +76,13 @@ export declare function serializeVoxelUpdate(ctx: RelaySignContext, input: Spati
73
76
  export declare function serializeAudioPacket(ctx: RelaySignContext, input: SpatialSendBase & {
74
77
  audioData: string;
75
78
  }): Promise<Uint8Array>;
79
+ /**
80
+ * One video FRAGMENT (header + body slice from `fragmentFrame`) as a 143 datagram.
81
+ * Defaults match audio: `distance` 1, `decayRate` 0.
82
+ */
83
+ export declare function serializeVideoPacket(ctx: RelaySignContext, input: SpatialSendBase & {
84
+ videoData: string;
85
+ }): Promise<Uint8Array>;
76
86
  export declare function serializeTextPacket(ctx: RelaySignContext, input: SpatialSendBase & {
77
87
  text: string;
78
88
  }): Promise<Uint8Array>;
@@ -1 +1 @@
1
- {"version":3,"file":"binary-wire.d.ts","sourceRoot":"","sources":["../src/binary-wire.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"binary-wire.d.ts","sourceRoot":"","sources":["../src/binary-wire.ts"],"names":[],"mappings":"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"}
@@ -34,6 +34,11 @@ export const WireMessageType = {
34
34
  CLIENT_EVENT_NOTIFICATION_2: 138,
35
35
  SERVER_EVENT_NOTIFICATION_2: 139,
36
36
  SINGLE_ACTOR_MESSAGE: 142,
37
+ // Buddy v0.25.0: webcam video pair (audio's shape, payload = one SDK
38
+ // fragment, see media/video-frames.ts) and the server-only actor-left downlink.
39
+ CLIENT_VIDEO_PACKET_2: 143,
40
+ CLIENT_VIDEO_NOTIFICATION_2: 144,
41
+ ACTOR_LEFT_NOTIFICATION_2: 145,
37
42
  };
38
43
  const SPATIAL_HEADER_SIZE = 68;
39
44
  const UUID_SIZE = 32;
@@ -174,6 +179,13 @@ export function serializeVoxelUpdate(ctx, input) {
174
179
  export function serializeAudioPacket(ctx, input) {
175
180
  return serializeSpatial(ctx, WireMessageType.CLIENT_AUDIO_PACKET_2, input.appId, input.chunk, input.distance ?? 1, input.decayRate ?? 0, input.uuid, decodeBase64(input.audioData ?? ''), input.sequenceNumber ?? 0);
176
181
  }
182
+ /**
183
+ * One video FRAGMENT (header + body slice from `fragmentFrame`) as a 143 datagram.
184
+ * Defaults match audio: `distance` 1, `decayRate` 0.
185
+ */
186
+ export function serializeVideoPacket(ctx, input) {
187
+ return serializeSpatial(ctx, WireMessageType.CLIENT_VIDEO_PACKET_2, input.appId, input.chunk, input.distance ?? 1, input.decayRate ?? 0, input.uuid, decodeBase64(input.videoData ?? ''), input.sequenceNumber ?? 0);
188
+ }
177
189
  export function serializeTextPacket(ctx, input) {
178
190
  return serializeSpatial(ctx, WireMessageType.CLIENT_TEXT_PACKET_2, input.appId, input.chunk, input.distance ?? 8, input.decayRate ?? 0, input.uuid, textEncoder.encode(input.text ?? ''), input.sequenceNumber ?? 0);
179
191
  }
@@ -375,6 +387,21 @@ function parseOne(bytes) {
375
387
  ...spatialCommon(p),
376
388
  audioData: encodeBase64(p.payload),
377
389
  };
390
+ case WireMessageType.CLIENT_VIDEO_NOTIFICATION_2:
391
+ return {
392
+ __typename: 'ClientVideoNotification',
393
+ ...spatialCommon(p),
394
+ videoData: encodeBase64(p.payload),
395
+ };
396
+ case WireMessageType.ACTOR_LEFT_NOTIFICATION_2: {
397
+ // [1B reason]; anything but 1 reads as STALE (0) per the contract.
398
+ const { decayRate: _r, ...rest } = spatialCommon(p);
399
+ return {
400
+ __typename: 'ActorLeftNotification',
401
+ ...rest,
402
+ leftReason: p.payload.length >= 1 && p.payload[0] === 1 ? 1 : 0,
403
+ };
404
+ }
378
405
  case WireMessageType.CLIENT_TEXT_NOTIFICATION_2:
379
406
  return {
380
407
  __typename: 'ClientTextNotification',
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * GENERATED — do not edit. The operator tooling's
3
- * `sync-client-origins.mjs --write --tier prod` writes this file, and
3
+ * `sync-client-origins.mjs --write --tier dev` writes this file, and
4
4
  * `check-sdk-default-origin.mjs` refuses it when it names the wrong tier or a
5
5
  * host that declaration does not carry. Regenerate; never hand-edit.
6
6
  *
@@ -10,14 +10,14 @@
10
10
  * than no default at all. Every fallback this SDK ever removed named a host that
11
11
  * was already dead. A generated file plus a gate is what makes this one different.
12
12
  *
13
- * Source: the operator's per-tier public CK API origin declaration, tier 'prod'
13
+ * Source: the operator's per-tier public CK API origin declaration, tier 'dev'
14
14
  */
15
15
  /** The tier this build of the SDK is published for. */
16
- export declare const CROWDY_DEFAULT_TIER = "prod";
16
+ export declare const CROWDY_DEFAULT_TIER = "dev";
17
17
  /** The public CK API origin for that tier. */
18
- export declare const CROWDY_DEFAULT_HTTP_ORIGIN = "https://ck.prod.crowdedkingdoms.com";
18
+ export declare const CROWDY_DEFAULT_HTTP_ORIGIN = "https://ck.dev.crowdedkingdoms.com";
19
19
  /** The same host over WebSocket. A scheme is composed; a hostname is looked up. */
20
- export declare const CROWDY_DEFAULT_WS_ORIGIN = "wss://ck.prod.crowdedkingdoms.com";
20
+ export declare const CROWDY_DEFAULT_WS_ORIGIN = "wss://ck.dev.crowdedkingdoms.com";
21
21
  /** The bare hostname, for callers that need to compare rather than dial. */
22
- export declare const CROWDY_DEFAULT_HOST = "ck.prod.crowdedkingdoms.com";
22
+ export declare const CROWDY_DEFAULT_HOST = "ck.dev.crowdedkingdoms.com";
23
23
  //# sourceMappingURL=default-origin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"default-origin.d.ts","sourceRoot":"","sources":["../src/default-origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAE1C,8CAA8C;AAC9C,eAAO,MAAM,0BAA0B,wCAAwC,CAAC;AAEhF,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,sCAAsC,CAAC;AAE5E,4EAA4E;AAC5E,eAAO,MAAM,mBAAmB,gCAAgC,CAAC"}
1
+ {"version":3,"file":"default-origin.d.ts","sourceRoot":"","sources":["../src/default-origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC,8CAA8C;AAC9C,eAAO,MAAM,0BAA0B,uCAAuC,CAAC;AAE/E,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,qCAAqC,CAAC;AAE3E,4EAA4E;AAC5E,eAAO,MAAM,mBAAmB,+BAA+B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * GENERATED — do not edit. The operator tooling's
3
- * `sync-client-origins.mjs --write --tier prod` writes this file, and
3
+ * `sync-client-origins.mjs --write --tier dev` writes this file, and
4
4
  * `check-sdk-default-origin.mjs` refuses it when it names the wrong tier or a
5
5
  * host that declaration does not carry. Regenerate; never hand-edit.
6
6
  *
@@ -10,13 +10,13 @@
10
10
  * than no default at all. Every fallback this SDK ever removed named a host that
11
11
  * was already dead. A generated file plus a gate is what makes this one different.
12
12
  *
13
- * Source: the operator's per-tier public CK API origin declaration, tier 'prod'
13
+ * Source: the operator's per-tier public CK API origin declaration, tier 'dev'
14
14
  */
15
15
  /** The tier this build of the SDK is published for. */
16
- export const CROWDY_DEFAULT_TIER = 'prod';
16
+ export const CROWDY_DEFAULT_TIER = 'dev';
17
17
  /** The public CK API origin for that tier. */
18
- export const CROWDY_DEFAULT_HTTP_ORIGIN = 'https://ck.prod.crowdedkingdoms.com';
18
+ export const CROWDY_DEFAULT_HTTP_ORIGIN = 'https://ck.dev.crowdedkingdoms.com';
19
19
  /** The same host over WebSocket. A scheme is composed; a hostname is looked up. */
20
- export const CROWDY_DEFAULT_WS_ORIGIN = 'wss://ck.prod.crowdedkingdoms.com';
20
+ export const CROWDY_DEFAULT_WS_ORIGIN = 'wss://ck.dev.crowdedkingdoms.com';
21
21
  /** The bare hostname, for callers that need to compare rather than dial. */
22
- export const CROWDY_DEFAULT_HOST = 'ck.prod.crowdedkingdoms.com';
22
+ export const CROWDY_DEFAULT_HOST = 'ck.dev.crowdedkingdoms.com';
@@ -1,8 +1,9 @@
1
1
  import type { GraphQLClient } from '../client.js';
2
2
  import type { SubscriptionManager, UdpNotificationHandlers } from '../subscriptions.js';
3
- import { type ConnectUdpProxyMutation, type UdpProxyConnectionStatusQuery, type SendActorUpdateMutationVariables, type SendVoxelUpdateMutationVariables, type SendAudioPacketMutationVariables, type SendTextPacketMutationVariables, type SendClientEventMutationVariables, type SendSingleActorMessageMutationVariables, type SendChannelMessageMutationVariables } from '../generated/graphql.js';
3
+ import { type ConnectUdpProxyMutation, type UdpProxyConnectionStatusQuery, type SendActorUpdateMutationVariables, type SendVoxelUpdateMutationVariables, type SendAudioPacketMutationVariables, type SendVideoPacketMutationVariables, type SendTextPacketMutationVariables, type SendClientEventMutationVariables, type SendSingleActorMessageMutationVariables, type SendChannelMessageMutationVariables } from '../generated/graphql.js';
4
4
  import type { RealtimeMetrics } from '../metrics.js';
5
5
  import type { SpatialNotification } from '../realtime.js';
6
+ import { type VideoCodec } from '../media/video-frames.js';
6
7
  /**
7
8
  * UDP proxy access for browser-style clients that can't open raw UDP sockets.
8
9
  * Exposed as `client.udp`; for game loops prefer the ergonomic, app-scoped
@@ -250,6 +251,51 @@ export declare class UdpAPI {
250
251
  sendAudioPacketAndWait(input: SendAudioPacketMutationVariables['input'], options?: {
251
252
  timeoutMs?: number;
252
253
  }): Promise<SpatialNotification>;
254
+ /**
255
+ * Send ONE webcam video fragment, fanned out to nearby actors as a
256
+ * `ClientVideoNotification` (Buddy v0.25.0). Fire-and-forget; opens a UDP
257
+ * proxy session automatically. Gated by the `use_video_chat` runtime
258
+ * permission at app AND grid level — without it the game server replies
259
+ * asynchronously with a `GenericErrorResponse` (`errorCode` `UNAUTHORIZED`).
260
+ * Prefer {@link sendVideoFrame}, which fragments a whole encoded frame; this is
261
+ * the single-datagram primitive beneath it.
262
+ *
263
+ * On the GraphQL proxy path this is a mutation PER FRAGMENT (30–80 a second for
264
+ * live video). Enable `binaryTransport` so video rides the relay.
265
+ *
266
+ * @param input - {@link ClientVideoPacketInput}: `videoData` is base64 of a
267
+ * 6-byte fragment header plus a slice of the encoded frame (see
268
+ * `fragmentFrame`); `distance` defaults to 1, `decayRate` to 0.
269
+ * @returns `true` when accepted for sending — **not** confirmation of delivery.
270
+ */
271
+ sendVideoPacket(input: SendVideoPacketMutationVariables['input']): Promise<boolean>;
272
+ /**
273
+ * Send one encoded webcam frame (a JPEG or WebP file) as however many
274
+ * fragments it needs (at most 16, ~17.8 KB), each a {@link sendVideoPacket}.
275
+ * Receivers reassemble with `VideoFrameAssembler`. Every receiver in range
276
+ * pays the egress bytes: keep `distance` at 0–1, frames small (≤ 8 KB) and
277
+ * the rate low (≤ 10 fps).
278
+ *
279
+ * @param input - `appId`, `chunk`, `uuid`, optional `distance` / `decayRate`,
280
+ * plus `frame` (encoded bytes), `frameId` (0–65535, +1 per frame, wraps —
281
+ * the caller keeps the counter) and `codec` (0 JPEG default, 1 WebP).
282
+ * @returns the number of fragments sent.
283
+ * @throws {RangeError} when the frame exceeds 16 fragments; nothing is sent.
284
+ */
285
+ sendVideoFrame(input: {
286
+ appId: string;
287
+ chunk: {
288
+ x: string;
289
+ y: string;
290
+ z: string;
291
+ };
292
+ uuid: string;
293
+ frame: Uint8Array;
294
+ frameId: number;
295
+ codec?: VideoCodec;
296
+ distance?: number;
297
+ decayRate?: number;
298
+ }): Promise<number>;
253
299
  /**
254
300
  * Send a spatial text/chat packet, fanned out to nearby actors as a
255
301
  * `ClientTextNotification`. Fire-and-forget; opens a UDP proxy session
@@ -1 +1 @@
1
- {"version":3,"file":"udp.d.ts","sourceRoot":"","sources":["../../src/domains/udp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"udp.d.ts","sourceRoot":"","sources":["../../src/domains/udp.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
- import { ConnectUdpProxyDocument, DisconnectUdpProxyDocument, UdpProxyConnectionStatusDocument, SendActorUpdateDocument, SendVoxelUpdateDocument, SendAudioPacketDocument, SendTextPacketDocument, SendClientEventDocument, SendSingleActorMessageDocument, SendChannelMessageDocument, } from '../generated/graphql.js';
1
+ import { ConnectUdpProxyDocument, DisconnectUdpProxyDocument, UdpProxyConnectionStatusDocument, SendActorUpdateDocument, SendVoxelUpdateDocument, SendAudioPacketDocument, SendVideoPacketDocument, SendTextPacketDocument, SendClientEventDocument, SendSingleActorMessageDocument, SendChannelMessageDocument, } from '../generated/graphql.js';
2
2
  import { payloadBytesOf } from '../metrics.js';
3
3
  import { SequenceAllocator } from '../utils.js';
4
- import { serializeActorUpdate, serializeAudioPacket, serializeChannelMessage, serializeClientEvent, serializeSingleActorMessage, serializeTextPacket, serializeVoxelUpdate, } from '../binary-wire.js';
4
+ import { serializeActorUpdate, serializeAudioPacket, serializeChannelMessage, serializeClientEvent, serializeSingleActorMessage, serializeTextPacket, serializeVideoPacket, serializeVoxelUpdate, } from '../binary-wire.js';
5
+ import { fragmentFrame } from '../media/video-frames.js';
6
+ import { encodeBase64 } from '../utils.js';
5
7
  /**
6
8
  * UDP proxy access for browser-style clients that can't open raw UDP sockets.
7
9
  * Exposed as `client.udp`; for game loops prefer the ergonomic, app-scoped
@@ -358,6 +360,61 @@ export class UdpAPI {
358
360
  await this.sendAudioPacket(request);
359
361
  return wait;
360
362
  }
363
+ /**
364
+ * Send ONE webcam video fragment, fanned out to nearby actors as a
365
+ * `ClientVideoNotification` (Buddy v0.25.0). Fire-and-forget; opens a UDP
366
+ * proxy session automatically. Gated by the `use_video_chat` runtime
367
+ * permission at app AND grid level — without it the game server replies
368
+ * asynchronously with a `GenericErrorResponse` (`errorCode` `UNAUTHORIZED`).
369
+ * Prefer {@link sendVideoFrame}, which fragments a whole encoded frame; this is
370
+ * the single-datagram primitive beneath it.
371
+ *
372
+ * On the GraphQL proxy path this is a mutation PER FRAGMENT (30–80 a second for
373
+ * live video). Enable `binaryTransport` so video rides the relay.
374
+ *
375
+ * @param input - {@link ClientVideoPacketInput}: `videoData` is base64 of a
376
+ * 6-byte fragment header plus a slice of the encoded frame (see
377
+ * `fragmentFrame`); `distance` defaults to 1, `decayRate` to 0.
378
+ * @returns `true` when accepted for sending — **not** confirmation of delivery.
379
+ */
380
+ async sendVideoPacket(input) {
381
+ const viaRelay = await this.sendViaRelay((ctx) => serializeVideoPacket(ctx, input));
382
+ if (viaRelay !== null) {
383
+ this.record('video', input);
384
+ return viaRelay;
385
+ }
386
+ const data = await this.gql.request(SendVideoPacketDocument, { input });
387
+ this.record('video', input);
388
+ return data.sendVideoPacket;
389
+ }
390
+ /**
391
+ * Send one encoded webcam frame (a JPEG or WebP file) as however many
392
+ * fragments it needs (at most 16, ~17.8 KB), each a {@link sendVideoPacket}.
393
+ * Receivers reassemble with `VideoFrameAssembler`. Every receiver in range
394
+ * pays the egress bytes: keep `distance` at 0–1, frames small (≤ 8 KB) and
395
+ * the rate low (≤ 10 fps).
396
+ *
397
+ * @param input - `appId`, `chunk`, `uuid`, optional `distance` / `decayRate`,
398
+ * plus `frame` (encoded bytes), `frameId` (0–65535, +1 per frame, wraps —
399
+ * the caller keeps the counter) and `codec` (0 JPEG default, 1 WebP).
400
+ * @returns the number of fragments sent.
401
+ * @throws {RangeError} when the frame exceeds 16 fragments; nothing is sent.
402
+ */
403
+ async sendVideoFrame(input) {
404
+ const fragments = fragmentFrame(input.frame, input.frameId, input.codec);
405
+ for (const fragment of fragments) {
406
+ await this.sendVideoPacket({
407
+ appId: input.appId,
408
+ chunk: input.chunk,
409
+ uuid: input.uuid,
410
+ videoData: encodeBase64(fragment),
411
+ distance: input.distance,
412
+ decayRate: input.decayRate,
413
+ sequenceNumber: input.frameId & 0xff,
414
+ });
415
+ }
416
+ return fragments.length;
417
+ }
361
418
  /**
362
419
  * Send a spatial text/chat packet, fanned out to nearby actors as a
363
420
  * `ClientTextNotification`. Fire-and-forget; opens a UDP proxy session