@openlivesync/server 1.0.2 → 1.0.3
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 +9 -4
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +15 -1
- package/dist/connection.js.map +1 -1
- package/dist/protocol.d.ts +4 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/package.json +1 -1
- package/src/connection.test.ts +39 -0
- package/src/connection.ts +9 -1
- package/src/protocol.ts +4 -0
package/README.md
CHANGED
|
@@ -115,9 +115,14 @@ createWebSocketServer(httpServer, {
|
|
|
115
115
|
});
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
### Access token and OAuth
|
|
118
|
+
### Access token, identity, and OAuth
|
|
119
119
|
|
|
120
|
-
Clients can send
|
|
120
|
+
Clients can send identity in `join_room` in two ways:
|
|
121
|
+
|
|
122
|
+
- **Access token** — An optional **access token** in the `join_room` payload (`accessToken`). If the server is configured with `auth`, it will decode (and optionally verify) the JWT and attach **name**, **email**, and **provider** to the connection.
|
|
123
|
+
- **Manual fields** — Optional `name` and `email` fields in the `join_room` payload for cases where you don’t use tokens.
|
|
124
|
+
|
|
125
|
+
In all cases, the resolved identity (from token or manual fields) appears in `PresenceEntry` and in chat messages so other clients can show who is in the room.
|
|
121
126
|
|
|
122
127
|
**Supported providers:** Google, Microsoft, and custom OAuth (JWKS URL or decode-only).
|
|
123
128
|
|
|
@@ -154,7 +159,7 @@ Use the access token **only once** when the client connects; the server then rec
|
|
|
154
159
|
|
|
155
160
|
1. Use **`createTokenAuth(authOptions)`** as your `onAuth` function. It reads the token from the upgrade request (query param `access_token` or header `Authorization: Bearer <token>`), decodes it with `decodeAccessToken`, and returns `UserInfo`. The connection gets identity (userId, name, email, provider) at connect time.
|
|
156
161
|
2. **Client**: Send the token only at connect (e.g. use `getAuthToken` in client config so the token is appended to the WebSocket URL as `?access_token=...`). Do **not** pass `accessToken` to `joinRoom` or `useRoom` when using this flow.
|
|
157
|
-
3. If the connection already has identity (from `onAuth`), the server ignores any `accessToken` in `join_room` and does not overwrite it.
|
|
162
|
+
3. If the connection already has identity (from `onAuth`), the server ignores any `accessToken`/`name`/`email` in `join_room` and does not overwrite it.
|
|
158
163
|
|
|
159
164
|
Browser WebSocket cannot send custom headers, so in the browser the token is typically sent as a query param (`access_token`). The default `tokenFromRequest` in `createTokenAuth` supports both query and `Authorization` header (e.g. for Node clients or proxies).
|
|
160
165
|
|
|
@@ -293,7 +298,7 @@ Clients connect over WebSocket and send/receive JSON messages with a `type` fiel
|
|
|
293
298
|
|
|
294
299
|
| `type` | Purpose |
|
|
295
300
|
|--------|--------|
|
|
296
|
-
| `join_room` | Join a room. Payload: `{ roomId, presence?, accessToken? }`. If `accessToken` is sent and server has `auth` (or decode-only), the server decodes it and attaches name
|
|
301
|
+
| `join_room` | Join a room. Payload: `{ roomId, presence?, accessToken?, name?, email? }`. If `accessToken` is sent and server has `auth` (or decode-only), the server decodes it and attaches `name`, `email`, `provider` to the connection; these appear in presence and chat. If only `name`/`email` are provided (no token), the server uses those values directly. If both are provided, the decoded token claims take priority and manual `name`/`email` are used only as a fallback when decoding fails. |
|
|
297
302
|
| `leave_room` | Leave current room. Payload: `{ roomId? }` (optional). |
|
|
298
303
|
| `update_presence` | Update presence. Payload: `{ presence }`. Throttled per connection. |
|
|
299
304
|
| `broadcast_event` | Send collaboration event. Payload: `{ event, payload? }`. |
|
package/dist/connection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAcpC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAmBnD,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,MAAM,CAAS;gBAEX,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB;IAerD,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,aAAa;YA+BP,QAAQ;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAcpC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAmBnD,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,MAAM,CAAS;gBAEX,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB;IAerD,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,aAAa;YA+BP,QAAQ;IAwFtB,OAAO,CAAC,WAAW;CAQpB"}
|
package/dist/connection.js
CHANGED
|
@@ -84,7 +84,7 @@ export class Connection {
|
|
|
84
84
|
async dispatch(clientMsg) {
|
|
85
85
|
switch (clientMsg.type) {
|
|
86
86
|
case MSG_JOIN_ROOM: {
|
|
87
|
-
const { roomId, presence, accessToken } = clientMsg.payload;
|
|
87
|
+
const { roomId, presence, accessToken, name, email } = clientMsg.payload;
|
|
88
88
|
if (accessToken && this.userId === undefined) {
|
|
89
89
|
const decoded = await decodeAccessToken(accessToken, this.auth);
|
|
90
90
|
if (decoded) {
|
|
@@ -93,6 +93,20 @@ export class Connection {
|
|
|
93
93
|
this.userEmail = decoded.email;
|
|
94
94
|
this.provider = decoded.provider;
|
|
95
95
|
}
|
|
96
|
+
else if (name || email) {
|
|
97
|
+
// Fallback to provided name/email if token decoding fails.
|
|
98
|
+
if (name && this.userName === undefined)
|
|
99
|
+
this.userName = name;
|
|
100
|
+
if (email && this.userEmail === undefined)
|
|
101
|
+
this.userEmail = email;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (!accessToken && (name || email)) {
|
|
105
|
+
// No token: allow client-provided name/email.
|
|
106
|
+
if (name && this.userName === undefined)
|
|
107
|
+
this.userName = name;
|
|
108
|
+
if (email && this.userEmail === undefined)
|
|
109
|
+
this.userEmail = email;
|
|
96
110
|
}
|
|
97
111
|
if (this.currentRoomId) {
|
|
98
112
|
const room = this.roomManager.get(this.currentRoomId);
|
package/dist/connection.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -22,6 +22,10 @@ export interface JoinRoomPayload {
|
|
|
22
22
|
presence?: Presence;
|
|
23
23
|
/** Optional OAuth/OpenID access token; server decodes to get name, email, provider. */
|
|
24
24
|
accessToken?: string;
|
|
25
|
+
/** Optional display name if not using accessToken. */
|
|
26
|
+
name?: string;
|
|
27
|
+
/** Optional email if not using accessToken. */
|
|
28
|
+
email?: string;
|
|
25
29
|
}
|
|
26
30
|
export interface LeaveRoomPayload {
|
|
27
31
|
roomId?: string;
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uFAAuF;AACvF,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/C,iEAAiE;AACjE,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID,eAAO,MAAM,aAAa,cAAc,CAAC;AACzC,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AACrD,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AACrD,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,uFAAuF;IACvF,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH,4CAA4C;AAE5C,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AACzC,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAC3C,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AACrD,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH,4CAA4C;AAE5C,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AACzC,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAC3C,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AACrD,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AAuCzC,4CAA4C;AAE5C,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAC;AAC7C,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CAAC;AACvD,MAAM,CAAC,MAAM,yBAAyB,GAAG,iBAAiB,CAAC;AAC3D,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAC/C,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC"}
|
package/package.json
CHANGED
package/src/connection.test.ts
CHANGED
|
@@ -299,6 +299,45 @@ describe("Connection", () => {
|
|
|
299
299
|
});
|
|
300
300
|
});
|
|
301
301
|
|
|
302
|
+
it("join_room with manual name/email shares them in presence when no accessToken", async () => {
|
|
303
|
+
new Connection(mock.ws as import("ws").WebSocket, {
|
|
304
|
+
connectionId: "c1",
|
|
305
|
+
presenceThrottleMs: 0,
|
|
306
|
+
roomManager,
|
|
307
|
+
});
|
|
308
|
+
mock.emitMessage(
|
|
309
|
+
JSON.stringify({
|
|
310
|
+
type: MSG_JOIN_ROOM,
|
|
311
|
+
payload: {
|
|
312
|
+
roomId: "r1",
|
|
313
|
+
presence: {},
|
|
314
|
+
name: "Manual User",
|
|
315
|
+
email: "manual@example.com",
|
|
316
|
+
},
|
|
317
|
+
})
|
|
318
|
+
);
|
|
319
|
+
await vi.waitFor(() => {
|
|
320
|
+
expect(
|
|
321
|
+
mock.sent.some((m: { type?: string }) => m?.type === MSG_ROOM_JOINED)
|
|
322
|
+
).toBe(true);
|
|
323
|
+
});
|
|
324
|
+
const roomJoined = mock.sent.find(
|
|
325
|
+
(m: { type?: string }) => m?.type === MSG_ROOM_JOINED
|
|
326
|
+
) as {
|
|
327
|
+
payload?: {
|
|
328
|
+
presence?: Record<
|
|
329
|
+
string,
|
|
330
|
+
{ userId?: string; name?: string; email?: string; provider?: string }
|
|
331
|
+
>;
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
const selfEntry = roomJoined?.payload?.presence?.["c1"];
|
|
335
|
+
expect(selfEntry?.userId).toBeUndefined();
|
|
336
|
+
expect(selfEntry?.name).toBe("Manual User");
|
|
337
|
+
expect(selfEntry?.email).toBe("manual@example.com");
|
|
338
|
+
expect(selfEntry?.provider).toBeUndefined();
|
|
339
|
+
});
|
|
340
|
+
|
|
302
341
|
it("join_room with accessToken sets userId, name, email, provider from decoded token", async () => {
|
|
303
342
|
const secret = new TextEncoder().encode("auth-secret");
|
|
304
343
|
const token = await new SignJWT({
|
package/src/connection.ts
CHANGED
|
@@ -116,7 +116,7 @@ export class Connection {
|
|
|
116
116
|
private async dispatch(clientMsg: ClientMessage): Promise<void> {
|
|
117
117
|
switch (clientMsg.type) {
|
|
118
118
|
case MSG_JOIN_ROOM: {
|
|
119
|
-
const { roomId, presence, accessToken } = clientMsg.payload;
|
|
119
|
+
const { roomId, presence, accessToken, name, email } = clientMsg.payload;
|
|
120
120
|
if (accessToken && this.userId === undefined) {
|
|
121
121
|
const decoded = await decodeAccessToken(accessToken, this.auth);
|
|
122
122
|
if (decoded) {
|
|
@@ -124,7 +124,15 @@ export class Connection {
|
|
|
124
124
|
this.userName = decoded.name;
|
|
125
125
|
this.userEmail = decoded.email;
|
|
126
126
|
this.provider = decoded.provider;
|
|
127
|
+
} else if (name || email) {
|
|
128
|
+
// Fallback to provided name/email if token decoding fails.
|
|
129
|
+
if (name && this.userName === undefined) this.userName = name;
|
|
130
|
+
if (email && this.userEmail === undefined) this.userEmail = email;
|
|
127
131
|
}
|
|
132
|
+
} else if (!accessToken && (name || email)) {
|
|
133
|
+
// No token: allow client-provided name/email.
|
|
134
|
+
if (name && this.userName === undefined) this.userName = name;
|
|
135
|
+
if (email && this.userEmail === undefined) this.userEmail = email;
|
|
128
136
|
}
|
|
129
137
|
if (this.currentRoomId) {
|
|
130
138
|
const room = this.roomManager.get(this.currentRoomId);
|
package/src/protocol.ts
CHANGED
|
@@ -28,6 +28,10 @@ export interface JoinRoomPayload {
|
|
|
28
28
|
presence?: Presence;
|
|
29
29
|
/** Optional OAuth/OpenID access token; server decodes to get name, email, provider. */
|
|
30
30
|
accessToken?: string;
|
|
31
|
+
/** Optional display name if not using accessToken. */
|
|
32
|
+
name?: string;
|
|
33
|
+
/** Optional email if not using accessToken. */
|
|
34
|
+
email?: string;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export interface LeaveRoomPayload {
|