@neta-art/cohub 4.8.0 → 4.9.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.
@@ -985,6 +985,98 @@ Before publishing your Work, verify each item:
985
985
 
986
986
  ---
987
987
 
988
+ ## Realtime rooms in a Work
989
+
990
+ Realtime rooms are available through `client.work.realtime` and use the Work
991
+ runtime identity automatically. They do not require a viewer scope or an
992
+ additional consent dialog.
993
+
994
+ ```js
995
+ const room = await client.work.realtime.createRoom({
996
+ code: "TEAM-ALPHA",
997
+ maxParticipants: 64,
998
+ expiresInSeconds: 2 * 60 * 60,
999
+ });
1000
+
1001
+ const stop = room.subscribe("shared.state.updated", (event) => {
1002
+ console.log(event.sequence, event.data);
1003
+ });
1004
+
1005
+ await room.publish("shared.state.updated", { value: 42 });
1006
+ await room.leave();
1007
+ stop();
1008
+ ```
1009
+
1010
+ A Work can join an existing room with `client.work.realtime.joinRoom({ code })`.
1011
+ Room codes are scoped to the Work and are case-insensitive. They identify a
1012
+ room but are not credentials; the runtime Work session and the short-lived
1013
+ room admission ticket provide authorization.
1014
+
1015
+ `expiresInSeconds` is an absolute lifetime measured from server-side creation.
1016
+ Activity never extends it, and the maximum lifetime is 24 hours. The room is
1017
+ logically expired at `expiresAt`; connected clients receive a closed state and
1018
+ new publishes or joins fail.
1019
+
1020
+ Each Work can hold up to 512 active rooms at once. Expired rooms free their slot
1021
+ automatically, and `createRoom` fails with HTTP 429 and `ROOM_QUOTA_EXCEEDED`
1022
+ when the limit is reached.
1023
+
1024
+ Events are generic JSON payloads. The SDK does not define business event names,
1025
+ and the Work should define its own event map in TypeScript. Events are ordered
1026
+ and acknowledged while a connection is live. Events missed during a disconnect
1027
+ are not replayed, so applications should publish a current state snapshot after
1028
+ rejoining when needed. Payloads are transient and are not stored in the Work.
1029
+
1030
+ ### High-frequency events
1031
+
1032
+ `publish` waits for a server ack, so a loop that awaits every call is capped at
1033
+ roughly `1000 / rtt` events per second. For input frames and other high-rate
1034
+ traffic use `send`, which skips the ack:
1035
+
1036
+ ```js
1037
+ // 30 input frames per second, no per-event round trip
1038
+ room.send("input.frame", { frame, pad });
1039
+
1040
+ room.onSendError((error) => console.warn("dropped frame", error.message));
1041
+ room.onStateChange((state) => { if (state !== "joined") pauseSimulation(); });
1042
+ ```
1043
+
1044
+ Ordering is still guaranteed by the server. Failures (rate limit, membership lost)
1045
+ arrive through `onSendError` for the room that failed, and calls while the room is
1046
+ not joined are dropped rather than queued. An invalid event name, an oversized
1047
+ payload, or data JSON cannot encode (`undefined`, a function, a symbol) is rejected
1048
+ locally before reaching the server. Use `publish` when a specific event must be
1049
+ confirmed, and `send` for the steady stream.
1050
+
1051
+ ### Seats and participant identity
1052
+
1053
+ By default every connection is its own participant, so a viewer who opens the
1054
+ Work in two tabs appears twice. This suits presence-style features such as
1055
+ multiple cursors. Each member also carries an opaque `userKey` that is stable per
1056
+ room and viewer, so an application can group or de-duplicate participants without
1057
+ seeing the underlying account.
1058
+
1059
+ A room created with `seatPerUser: true` instead gives each viewer at most one
1060
+ seat:
1061
+
1062
+ ```js
1063
+ const room = await client.work.realtime.createRoom({
1064
+ maxParticipants: 2,
1065
+ seatPerUser: true,
1066
+ });
1067
+ ```
1068
+
1069
+ Joining then takes over the seat the viewer already holds instead of consuming
1070
+ another one. This matters for small fixed-size rooms: after an unclean disconnect
1071
+ (a killed tab, a dropped network, a sleeping laptop) the previous seat stays
1072
+ leased for up to a minute, and in a two-seat room that would otherwise block the
1073
+ viewer from rejoining. A clean close releases the seat immediately either way.
1074
+
1075
+ On takeover the server keeps the existing participant id, so peers see no churn,
1076
+ and `room.participantId` reflects the server value rather than the id issued at
1077
+ admission. The superseded connection is closed with reason `superseded` and emits
1078
+ no leave event, because the participant is still present.
1079
+
988
1080
  ## 8. Publishing a Work (API/SDK)
989
1081
 
990
1082
  Before creating a Work through the API, ensure the owner has a username and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neta-art/cohub",
3
- "version": "4.8.0",
3
+ "version": "4.9.0",
4
4
  "description": "Cohub SDK for spaces, sessions, boards, and realtime agent collaboration.",
5
5
  "license": "Apache-2.0",
6
6
  "private": false,