@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.
- package/README.md +39 -0
- package/dist/chunks/http.d.ts +1 -1
- package/dist/chunks/http.js +1 -1
- package/dist/chunks/transport.js +7 -2
- package/dist/chunks/websocket.d.ts +166 -4
- package/dist/chunks/websocket.js +56 -4
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +134 -2
- package/dist/index.js +843 -223
- package/docs/work-runtime-guide.md +92 -0
- package/package.json +1 -1
|
@@ -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
|