@openlivesync/server 1.0.2

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.
Files changed (82) hide show
  1. package/README.md +366 -0
  2. package/dist/auth/decode-token.d.ts +40 -0
  3. package/dist/auth/decode-token.d.ts.map +1 -0
  4. package/dist/auth/decode-token.js +93 -0
  5. package/dist/auth/decode-token.js.map +1 -0
  6. package/dist/auth/index.d.ts +6 -0
  7. package/dist/auth/index.d.ts.map +1 -0
  8. package/dist/auth/index.js +6 -0
  9. package/dist/auth/index.js.map +1 -0
  10. package/dist/auth/token-auth.d.ts +18 -0
  11. package/dist/auth/token-auth.d.ts.map +1 -0
  12. package/dist/auth/token-auth.js +45 -0
  13. package/dist/auth/token-auth.js.map +1 -0
  14. package/dist/connection.d.ts +36 -0
  15. package/dist/connection.d.ts.map +1 -0
  16. package/dist/connection.js +170 -0
  17. package/dist/connection.js.map +1 -0
  18. package/dist/index.d.ts +19 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +15 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/protocol.d.ts +135 -0
  23. package/dist/protocol.d.ts.map +1 -0
  24. package/dist/protocol.js +17 -0
  25. package/dist/protocol.js.map +1 -0
  26. package/dist/room-manager.d.ts +19 -0
  27. package/dist/room-manager.d.ts.map +1 -0
  28. package/dist/room-manager.js +34 -0
  29. package/dist/room-manager.js.map +1 -0
  30. package/dist/room.d.ts +41 -0
  31. package/dist/room.d.ts.map +1 -0
  32. package/dist/room.js +150 -0
  33. package/dist/room.js.map +1 -0
  34. package/dist/server.d.ts +46 -0
  35. package/dist/server.d.ts.map +1 -0
  36. package/dist/server.js +105 -0
  37. package/dist/server.js.map +1 -0
  38. package/dist/storage/chat-storage.d.ts +19 -0
  39. package/dist/storage/chat-storage.d.ts.map +1 -0
  40. package/dist/storage/chat-storage.js +6 -0
  41. package/dist/storage/chat-storage.js.map +1 -0
  42. package/dist/storage/in-memory.d.ts +11 -0
  43. package/dist/storage/in-memory.d.ts.map +1 -0
  44. package/dist/storage/in-memory.js +35 -0
  45. package/dist/storage/in-memory.js.map +1 -0
  46. package/dist/storage/mysql.d.ts +19 -0
  47. package/dist/storage/mysql.d.ts.map +1 -0
  48. package/dist/storage/mysql.js +70 -0
  49. package/dist/storage/mysql.js.map +1 -0
  50. package/dist/storage/postgres.d.ts +21 -0
  51. package/dist/storage/postgres.d.ts.map +1 -0
  52. package/dist/storage/postgres.js +70 -0
  53. package/dist/storage/postgres.js.map +1 -0
  54. package/dist/storage/sqlite.d.ts +15 -0
  55. package/dist/storage/sqlite.d.ts.map +1 -0
  56. package/dist/storage/sqlite.js +71 -0
  57. package/dist/storage/sqlite.js.map +1 -0
  58. package/package.json +51 -0
  59. package/src/auth/decode-token.test.ts +119 -0
  60. package/src/auth/decode-token.ts +138 -0
  61. package/src/auth/index.ts +16 -0
  62. package/src/auth/token-auth.test.ts +95 -0
  63. package/src/auth/token-auth.ts +55 -0
  64. package/src/connection.test.ts +339 -0
  65. package/src/connection.ts +204 -0
  66. package/src/index.ts +80 -0
  67. package/src/protocol.test.ts +29 -0
  68. package/src/protocol.ts +137 -0
  69. package/src/room-manager.ts +45 -0
  70. package/src/room.test.ts +175 -0
  71. package/src/room.ts +207 -0
  72. package/src/server.test.ts +223 -0
  73. package/src/server.ts +153 -0
  74. package/src/storage/chat-storage.ts +23 -0
  75. package/src/storage/db-types.d.ts +43 -0
  76. package/src/storage/in-memory.test.ts +96 -0
  77. package/src/storage/in-memory.ts +52 -0
  78. package/src/storage/mysql.ts +117 -0
  79. package/src/storage/postgres.ts +117 -0
  80. package/src/storage/sqlite.ts +120 -0
  81. package/tsconfig.json +11 -0
  82. package/vitest.config.ts +32 -0
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Wraps a WebSocket: parse messages, throttle presence, dispatch to room.
3
+ */
4
+ import { MSG_JOIN_ROOM, MSG_LEAVE_ROOM, MSG_UPDATE_PRESENCE, MSG_BROADCAST_EVENT, MSG_SEND_CHAT, MSG_ERROR, } from "./protocol.js";
5
+ import { decodeAccessToken } from "./auth/index.js";
6
+ function isClientMessage(msg) {
7
+ if (msg === null || typeof msg !== "object" || !("type" in msg))
8
+ return false;
9
+ const t = msg.type;
10
+ return [
11
+ MSG_JOIN_ROOM,
12
+ MSG_LEAVE_ROOM,
13
+ MSG_UPDATE_PRESENCE,
14
+ MSG_BROADCAST_EVENT,
15
+ MSG_SEND_CHAT,
16
+ ].includes(t);
17
+ }
18
+ function send(ws, msg) {
19
+ if (ws.readyState !== ws.OPEN)
20
+ return;
21
+ ws.send(JSON.stringify(msg));
22
+ }
23
+ export class Connection {
24
+ ws;
25
+ connectionId;
26
+ userId;
27
+ userName;
28
+ userEmail;
29
+ provider;
30
+ presenceThrottleMs;
31
+ roomManager;
32
+ auth;
33
+ currentRoomId = null;
34
+ lastPresenceUpdate = 0;
35
+ closed = false;
36
+ constructor(ws, options) {
37
+ this.ws = ws;
38
+ this.connectionId = options.connectionId;
39
+ this.userId = options.userId;
40
+ this.userName = options.userName;
41
+ this.userEmail = options.userEmail;
42
+ this.provider = options.provider;
43
+ this.presenceThrottleMs = options.presenceThrottleMs;
44
+ this.roomManager = options.roomManager;
45
+ this.auth = options.auth;
46
+ this.ws.on("message", (data) => this.handleMessage(data));
47
+ this.ws.on("close", () => this.handleClose());
48
+ }
49
+ send(msg) {
50
+ send(this.ws, msg);
51
+ }
52
+ handleMessage(data) {
53
+ if (this.closed)
54
+ return;
55
+ let msg;
56
+ try {
57
+ const raw = typeof data === "string" ? data : data.toString("utf8");
58
+ msg = JSON.parse(raw);
59
+ }
60
+ catch {
61
+ this.send({
62
+ type: MSG_ERROR,
63
+ payload: { code: "INVALID_JSON", message: "Invalid JSON" },
64
+ });
65
+ return;
66
+ }
67
+ if (!isClientMessage(msg)) {
68
+ this.send({
69
+ type: MSG_ERROR,
70
+ payload: { code: "INVALID_MESSAGE", message: "Unknown or invalid message type" },
71
+ });
72
+ return;
73
+ }
74
+ this.dispatch(msg).catch((err) => {
75
+ this.send({
76
+ type: MSG_ERROR,
77
+ payload: {
78
+ code: "SERVER_ERROR",
79
+ message: err instanceof Error ? err.message : String(err),
80
+ },
81
+ });
82
+ });
83
+ }
84
+ async dispatch(clientMsg) {
85
+ switch (clientMsg.type) {
86
+ case MSG_JOIN_ROOM: {
87
+ const { roomId, presence, accessToken } = clientMsg.payload;
88
+ if (accessToken && this.userId === undefined) {
89
+ const decoded = await decodeAccessToken(accessToken, this.auth);
90
+ if (decoded) {
91
+ this.userId = decoded.sub;
92
+ this.userName = decoded.name;
93
+ this.userEmail = decoded.email;
94
+ this.provider = decoded.provider;
95
+ }
96
+ }
97
+ if (this.currentRoomId) {
98
+ const room = this.roomManager.get(this.currentRoomId);
99
+ if (room)
100
+ room.leave(this.connectionId);
101
+ this.roomManager.removeIfEmpty(this.currentRoomId);
102
+ }
103
+ this.currentRoomId = roomId;
104
+ const room = this.roomManager.getOrCreate(roomId);
105
+ const handle = {
106
+ connectionId: this.connectionId,
107
+ userId: this.userId,
108
+ name: this.userName,
109
+ email: this.userEmail,
110
+ provider: this.provider,
111
+ presence: {},
112
+ send: (m) => this.send(m),
113
+ };
114
+ await room.join(handle, presence);
115
+ break;
116
+ }
117
+ case MSG_LEAVE_ROOM: {
118
+ const roomId = clientMsg.payload?.roomId ?? this.currentRoomId;
119
+ if (roomId && this.currentRoomId === roomId) {
120
+ const room = this.roomManager.get(roomId);
121
+ if (room)
122
+ room.leave(this.connectionId);
123
+ this.roomManager.removeIfEmpty(roomId);
124
+ this.currentRoomId = null;
125
+ }
126
+ break;
127
+ }
128
+ case MSG_UPDATE_PRESENCE: {
129
+ const now = Date.now();
130
+ if (now - this.lastPresenceUpdate < this.presenceThrottleMs)
131
+ return;
132
+ this.lastPresenceUpdate = now;
133
+ if (!this.currentRoomId)
134
+ return;
135
+ const room = this.roomManager.get(this.currentRoomId);
136
+ if (room)
137
+ room.updatePresence(this.connectionId, clientMsg.payload.presence);
138
+ break;
139
+ }
140
+ case MSG_BROADCAST_EVENT: {
141
+ if (!this.currentRoomId)
142
+ return;
143
+ const room = this.roomManager.get(this.currentRoomId);
144
+ if (room) {
145
+ room.broadcastEvent(this.connectionId, clientMsg.payload.event, clientMsg.payload.payload, this.userId);
146
+ }
147
+ break;
148
+ }
149
+ case MSG_SEND_CHAT: {
150
+ if (!this.currentRoomId)
151
+ return;
152
+ const room = this.roomManager.get(this.currentRoomId);
153
+ if (room) {
154
+ await room.sendChat(this.connectionId, clientMsg.payload.message, clientMsg.payload.metadata, this.userId);
155
+ }
156
+ break;
157
+ }
158
+ }
159
+ }
160
+ handleClose() {
161
+ this.closed = true;
162
+ if (this.currentRoomId) {
163
+ const room = this.roomManager.get(this.currentRoomId);
164
+ if (room)
165
+ room.leave(this.connectionId);
166
+ this.roomManager.removeIfEmpty(this.currentRoomId);
167
+ }
168
+ }
169
+ }
170
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @openlivesync/server - Node.js package for collaboration, presence, and chat.
3
+ * Export all public API and protocol types for use in a Node.js backend.
4
+ */
5
+ export { createServer, createWebSocketServer, createWebSocketHandler, type ServerOptions, type WebSocketServerOptions, type ChatOptions, } from "./server.js";
6
+ export type { Presence, UserInfo, ClientMessage, ServerMessage, JoinRoomPayload, LeaveRoomPayload, UpdatePresencePayload, BroadcastEventPayload, SendChatPayload, PresenceEntry, RoomJoinedPayload, PresenceUpdatedPayload, BroadcastEventRelayPayload, ChatMessagePayload, StoredChatMessage, ErrorPayload, ChatMessageInput, } from "./protocol.js";
7
+ export { MSG_JOIN_ROOM, MSG_LEAVE_ROOM, MSG_UPDATE_PRESENCE, MSG_BROADCAST_EVENT, MSG_SEND_CHAT, MSG_ROOM_JOINED, MSG_PRESENCE_UPDATED, MSG_BROADCAST_EVENT_RELAY, MSG_CHAT_MESSAGE, MSG_ERROR, } from "./protocol.js";
8
+ export { decodeAccessToken, createTokenAuth } from "./auth/index.js";
9
+ export type { AuthOptions, AuthGoogleConfig, AuthMicrosoftConfig, AuthCustomConfig, CreateTokenAuthOptions, DecodedToken, } from "./auth/index.js";
10
+ export type { ChatStorage } from "./storage/chat-storage.js";
11
+ export { createInMemoryChatStorage } from "./storage/in-memory.js";
12
+ export type { InMemoryChatStorageOptions } from "./storage/in-memory.js";
13
+ export { createPostgresChatStorage } from "./storage/postgres.js";
14
+ export type { PostgresChatStorageOptions, PostgresConnectionConfig, } from "./storage/postgres.js";
15
+ export { createMySQLChatStorage } from "./storage/mysql.js";
16
+ export type { MySQLChatStorageOptions, MySQLConnectionConfig, } from "./storage/mysql.js";
17
+ export { createSQLiteChatStorage } from "./storage/sqlite.js";
18
+ export type { SQLiteChatStorageOptions, SQLiteConnectionConfig, } from "./storage/sqlite.js";
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC3B,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,sBAAsB,EACtB,0BAA0B,EAC1B,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,EAChB,SAAS,GACV,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACrE,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,YAAY,GACb,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,YAAY,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAGzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,YAAY,EACV,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,YAAY,EACV,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,YAAY,EACV,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @openlivesync/server - Node.js package for collaboration, presence, and chat.
3
+ * Export all public API and protocol types for use in a Node.js backend.
4
+ */
5
+ // Server API
6
+ export { createServer, createWebSocketServer, createWebSocketHandler, } from "./server.js";
7
+ export { MSG_JOIN_ROOM, MSG_LEAVE_ROOM, MSG_UPDATE_PRESENCE, MSG_BROADCAST_EVENT, MSG_SEND_CHAT, MSG_ROOM_JOINED, MSG_PRESENCE_UPDATED, MSG_BROADCAST_EVENT_RELAY, MSG_CHAT_MESSAGE, MSG_ERROR, } from "./protocol.js";
8
+ // Auth (decode/verify access tokens; Google, Microsoft, custom OAuth)
9
+ export { decodeAccessToken, createTokenAuth } from "./auth/index.js";
10
+ export { createInMemoryChatStorage } from "./storage/in-memory.js";
11
+ // Optional DB adapters (require pg / mysql2 / better-sqlite3 to be installed)
12
+ export { createPostgresChatStorage } from "./storage/postgres.js";
13
+ export { createMySQLChatStorage } from "./storage/mysql.js";
14
+ export { createSQLiteChatStorage } from "./storage/sqlite.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,aAAa;AACb,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,sBAAsB,GAIvB,MAAM,aAAa,CAAC;AAsBrB,OAAO,EACL,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,EAChB,SAAS,GACV,MAAM,eAAe,CAAC;AAEvB,sEAAsE;AACtE,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAYrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAGnE,8EAA8E;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAKlE,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAK5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Wire protocol types for @openlivesync.
3
+ * Shared between server and client; server handles these message types.
4
+ */
5
+ /** Generic presence payload (cursor, name, color, etc.). Server does not interpret. */
6
+ export type Presence = Record<string, unknown>;
7
+ /** User/session info attached by server from auth (optional). */
8
+ export interface UserInfo {
9
+ userId?: string;
10
+ name?: string;
11
+ email?: string;
12
+ provider?: string;
13
+ [key: string]: unknown;
14
+ }
15
+ export declare const MSG_JOIN_ROOM = "join_room";
16
+ export declare const MSG_LEAVE_ROOM = "leave_room";
17
+ export declare const MSG_UPDATE_PRESENCE = "update_presence";
18
+ export declare const MSG_BROADCAST_EVENT = "broadcast_event";
19
+ export declare const MSG_SEND_CHAT = "send_chat";
20
+ export interface JoinRoomPayload {
21
+ roomId: string;
22
+ presence?: Presence;
23
+ /** Optional OAuth/OpenID access token; server decodes to get name, email, provider. */
24
+ accessToken?: string;
25
+ }
26
+ export interface LeaveRoomPayload {
27
+ roomId?: string;
28
+ }
29
+ export interface UpdatePresencePayload {
30
+ presence: Presence;
31
+ }
32
+ export interface BroadcastEventPayload {
33
+ event: string;
34
+ payload?: unknown;
35
+ }
36
+ export interface SendChatPayload {
37
+ message: string;
38
+ /** Optional application-defined metadata */
39
+ metadata?: Record<string, unknown>;
40
+ }
41
+ export type ClientMessage = {
42
+ type: typeof MSG_JOIN_ROOM;
43
+ payload: JoinRoomPayload;
44
+ } | {
45
+ type: typeof MSG_LEAVE_ROOM;
46
+ payload?: LeaveRoomPayload;
47
+ } | {
48
+ type: typeof MSG_UPDATE_PRESENCE;
49
+ payload: UpdatePresencePayload;
50
+ } | {
51
+ type: typeof MSG_BROADCAST_EVENT;
52
+ payload: BroadcastEventPayload;
53
+ } | {
54
+ type: typeof MSG_SEND_CHAT;
55
+ payload: SendChatPayload;
56
+ };
57
+ export declare const MSG_ROOM_JOINED = "room_joined";
58
+ export declare const MSG_PRESENCE_UPDATED = "presence_updated";
59
+ export declare const MSG_BROADCAST_EVENT_RELAY = "broadcast_event";
60
+ export declare const MSG_CHAT_MESSAGE = "chat_message";
61
+ export declare const MSG_ERROR = "error";
62
+ export interface PresenceEntry {
63
+ connectionId: string;
64
+ userId?: string;
65
+ name?: string;
66
+ email?: string;
67
+ provider?: string;
68
+ presence: Presence;
69
+ }
70
+ export interface RoomJoinedPayload {
71
+ roomId: string;
72
+ connectionId: string;
73
+ presence: Record<string, PresenceEntry>;
74
+ chatHistory?: StoredChatMessage[];
75
+ }
76
+ export interface PresenceUpdatedPayload {
77
+ roomId: string;
78
+ joined?: PresenceEntry[];
79
+ left?: string[];
80
+ updated?: PresenceEntry[];
81
+ }
82
+ export interface BroadcastEventRelayPayload {
83
+ roomId: string;
84
+ connectionId: string;
85
+ userId?: string;
86
+ event: string;
87
+ payload?: unknown;
88
+ }
89
+ export interface ChatMessagePayload {
90
+ roomId: string;
91
+ connectionId: string;
92
+ userId?: string;
93
+ message: string;
94
+ metadata?: Record<string, unknown>;
95
+ id?: string;
96
+ createdAt?: number;
97
+ }
98
+ export interface StoredChatMessage {
99
+ id: string;
100
+ roomId: string;
101
+ connectionId: string;
102
+ userId?: string;
103
+ message: string;
104
+ metadata?: Record<string, unknown>;
105
+ createdAt: number;
106
+ }
107
+ export interface ErrorPayload {
108
+ code: string;
109
+ message: string;
110
+ }
111
+ export type ServerMessage = {
112
+ type: typeof MSG_ROOM_JOINED;
113
+ payload: RoomJoinedPayload;
114
+ } | {
115
+ type: typeof MSG_PRESENCE_UPDATED;
116
+ payload: PresenceUpdatedPayload;
117
+ } | {
118
+ type: typeof MSG_BROADCAST_EVENT_RELAY;
119
+ payload: BroadcastEventRelayPayload;
120
+ } | {
121
+ type: typeof MSG_CHAT_MESSAGE;
122
+ payload: ChatMessagePayload;
123
+ } | {
124
+ type: typeof MSG_ERROR;
125
+ payload: ErrorPayload;
126
+ };
127
+ /** Chat message as provided when appending (before storage adds id/createdAt). */
128
+ export interface ChatMessageInput {
129
+ roomId: string;
130
+ connectionId: string;
131
+ userId?: string;
132
+ message: string;
133
+ metadata?: Record<string, unknown>;
134
+ }
135
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Wire protocol types for @openlivesync.
3
+ * Shared between server and client; server handles these message types.
4
+ */
5
+ // ----- Client → Server message types -----
6
+ export const MSG_JOIN_ROOM = "join_room";
7
+ export const MSG_LEAVE_ROOM = "leave_room";
8
+ export const MSG_UPDATE_PRESENCE = "update_presence";
9
+ export const MSG_BROADCAST_EVENT = "broadcast_event";
10
+ export const MSG_SEND_CHAT = "send_chat";
11
+ // ----- Server → Client message types -----
12
+ export const MSG_ROOM_JOINED = "room_joined";
13
+ export const MSG_PRESENCE_UPDATED = "presence_updated";
14
+ export const MSG_BROADCAST_EVENT_RELAY = "broadcast_event";
15
+ export const MSG_CHAT_MESSAGE = "chat_message";
16
+ export const MSG_ERROR = "error";
17
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +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;AAmCzC,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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Manages rooms: get-or-create by roomId.
3
+ */
4
+ import { Room } from "./room.js";
5
+ import type { ChatStorage } from "./storage/chat-storage.js";
6
+ export interface RoomManagerOptions {
7
+ chatStorage: ChatStorage;
8
+ historyLimit: number;
9
+ }
10
+ export declare class RoomManager {
11
+ private readonly options;
12
+ private readonly rooms;
13
+ constructor(options: RoomManagerOptions);
14
+ getOrCreate(roomId: string): Room;
15
+ get(roomId: string): Room | undefined;
16
+ /** Remove room when empty (optional cleanup). */
17
+ removeIfEmpty(roomId: string): void;
18
+ }
19
+ //# sourceMappingURL=room-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-manager.d.ts","sourceRoot":"","sources":["../src/room-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;gBAErC,OAAO,EAAE,kBAAkB;IAIvC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAajC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIrC,iDAAiD;IACjD,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;CAMpC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Manages rooms: get-or-create by roomId.
3
+ */
4
+ import { Room } from "./room.js";
5
+ export class RoomManager {
6
+ options;
7
+ rooms = new Map();
8
+ constructor(options) {
9
+ this.options = options;
10
+ }
11
+ getOrCreate(roomId) {
12
+ let room = this.rooms.get(roomId);
13
+ if (!room) {
14
+ room = new Room({
15
+ roomId,
16
+ chatStorage: this.options.chatStorage,
17
+ historyLimit: this.options.historyLimit,
18
+ });
19
+ this.rooms.set(roomId, room);
20
+ }
21
+ return room;
22
+ }
23
+ get(roomId) {
24
+ return this.rooms.get(roomId);
25
+ }
26
+ /** Remove room when empty (optional cleanup). */
27
+ removeIfEmpty(roomId) {
28
+ const room = this.rooms.get(roomId);
29
+ if (room && room.connectionCount === 0) {
30
+ this.rooms.delete(roomId);
31
+ }
32
+ }
33
+ }
34
+ //# sourceMappingURL=room-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-manager.js","sourceRoot":"","sources":["../src/room-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,MAAM,OAAO,WAAW;IACL,OAAO,CAAqB;IAC5B,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;IAEjD,YAAY,OAA2B;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,WAAW,CAAC,MAAc;QACxB,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,IAAI,IAAI,CAAC;gBACd,MAAM;gBACN,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW;gBACrC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY;aACxC,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,MAAc;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,iDAAiD;IACjD,aAAa,CAAC,MAAc;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,IAAI,IAAI,IAAI,CAAC,eAAe,KAAK,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;CACF"}
package/dist/room.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * A single room: connections, presence map, broadcast, and chat.
3
+ */
4
+ import type { Presence, ServerMessage } from "./protocol.js";
5
+ import type { ChatStorage } from "./storage/chat-storage.js";
6
+ /** Handle the room uses to send messages to a connection. */
7
+ export interface RoomConnectionHandle {
8
+ connectionId: string;
9
+ userId?: string;
10
+ name?: string;
11
+ email?: string;
12
+ provider?: string;
13
+ presence: Presence;
14
+ send(msg: ServerMessage): void;
15
+ }
16
+ export interface RoomOptions {
17
+ roomId: string;
18
+ chatStorage: ChatStorage;
19
+ historyLimit: number;
20
+ }
21
+ export declare class Room {
22
+ private readonly roomId;
23
+ private readonly chatStorage;
24
+ private readonly historyLimit;
25
+ private readonly connections;
26
+ constructor(options: RoomOptions);
27
+ get connectionCount(): number;
28
+ /** Add connection to room; send room_joined to connection and presence_updated (joined) to others. */
29
+ join(handle: RoomConnectionHandle, initialPresence?: Presence): Promise<void>;
30
+ /** Remove connection and notify others. */
31
+ leave(connectionId: string): void;
32
+ /** Update presence for a connection and broadcast updated entry. */
33
+ updatePresence(connectionId: string, presence: Presence): void;
34
+ /** Relay collaboration event to other clients in the room. */
35
+ broadcastEvent(connectionId: string, event: string, payload: unknown, userId?: string): void;
36
+ /** Append chat message to storage and broadcast to all in room. */
37
+ sendChat(connectionId: string, message: string, metadata: Record<string, unknown> | undefined, userId?: string): Promise<void>;
38
+ private broadcast;
39
+ private broadcastExcept;
40
+ }
41
+ //# sourceMappingURL=room.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../src/room.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,QAAQ,EAER,aAAa,EAEd,MAAM,eAAe,CAAC;AAOvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,6DAA6D;AAC7D,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,IAAI;IACf,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2C;gBAE3D,OAAO,EAAE,WAAW;IAMhC,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,sGAAsG;IAChG,IAAI,CACR,MAAM,EAAE,oBAAoB,EAC5B,eAAe,GAAE,QAAa,GAC7B,OAAO,CAAC,IAAI,CAAC;IAyDhB,2CAA2C;IAC3C,KAAK,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAWjC,oEAAoE;IACpE,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAsB9D,8DAA8D;IAC9D,cAAc,CACZ,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,MAAM,GACd,IAAI;IAaP,mEAAmE;IAC7D,QAAQ,CACZ,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC7C,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAqBhB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,eAAe;CAOxB"}
package/dist/room.js ADDED
@@ -0,0 +1,150 @@
1
+ /**
2
+ * A single room: connections, presence map, broadcast, and chat.
3
+ */
4
+ import { MSG_CHAT_MESSAGE, MSG_PRESENCE_UPDATED, MSG_ROOM_JOINED, MSG_BROADCAST_EVENT_RELAY, } from "./protocol.js";
5
+ export class Room {
6
+ roomId;
7
+ chatStorage;
8
+ historyLimit;
9
+ connections = new Map();
10
+ constructor(options) {
11
+ this.roomId = options.roomId;
12
+ this.chatStorage = options.chatStorage;
13
+ this.historyLimit = options.historyLimit;
14
+ }
15
+ get connectionCount() {
16
+ return this.connections.size;
17
+ }
18
+ /** Add connection to room; send room_joined to connection and presence_updated (joined) to others. */
19
+ async join(handle, initialPresence = {}) {
20
+ const entry = {
21
+ ...handle,
22
+ presence: { ...initialPresence },
23
+ };
24
+ this.connections.set(handle.connectionId, entry);
25
+ const presenceMap = {};
26
+ for (const [, c] of this.connections) {
27
+ presenceMap[c.connectionId] = {
28
+ connectionId: c.connectionId,
29
+ userId: c.userId,
30
+ name: c.name,
31
+ email: c.email,
32
+ provider: c.provider,
33
+ presence: c.presence,
34
+ };
35
+ }
36
+ let chatHistory;
37
+ try {
38
+ chatHistory = await this.chatStorage.getHistory(this.roomId, this.historyLimit);
39
+ }
40
+ catch {
41
+ chatHistory = [];
42
+ }
43
+ handle.send({
44
+ type: MSG_ROOM_JOINED,
45
+ payload: {
46
+ roomId: this.roomId,
47
+ connectionId: handle.connectionId,
48
+ presence: presenceMap,
49
+ chatHistory,
50
+ },
51
+ });
52
+ this.broadcastExcept(handle.connectionId, {
53
+ type: MSG_PRESENCE_UPDATED,
54
+ payload: {
55
+ roomId: this.roomId,
56
+ joined: [
57
+ {
58
+ connectionId: handle.connectionId,
59
+ userId: handle.userId,
60
+ name: handle.name,
61
+ email: handle.email,
62
+ provider: handle.provider,
63
+ presence: entry.presence,
64
+ },
65
+ ],
66
+ },
67
+ });
68
+ }
69
+ /** Remove connection and notify others. */
70
+ leave(connectionId) {
71
+ this.connections.delete(connectionId);
72
+ this.broadcast({
73
+ type: MSG_PRESENCE_UPDATED,
74
+ payload: {
75
+ roomId: this.roomId,
76
+ left: [connectionId],
77
+ },
78
+ });
79
+ }
80
+ /** Update presence for a connection and broadcast updated entry. */
81
+ updatePresence(connectionId, presence) {
82
+ const conn = this.connections.get(connectionId);
83
+ if (!conn)
84
+ return;
85
+ conn.presence = { ...presence };
86
+ this.broadcastExcept(connectionId, {
87
+ type: MSG_PRESENCE_UPDATED,
88
+ payload: {
89
+ roomId: this.roomId,
90
+ updated: [
91
+ {
92
+ connectionId: conn.connectionId,
93
+ userId: conn.userId,
94
+ name: conn.name,
95
+ email: conn.email,
96
+ provider: conn.provider,
97
+ presence: conn.presence,
98
+ },
99
+ ],
100
+ },
101
+ });
102
+ }
103
+ /** Relay collaboration event to other clients in the room. */
104
+ broadcastEvent(connectionId, event, payload, userId) {
105
+ this.broadcastExcept(connectionId, {
106
+ type: MSG_BROADCAST_EVENT_RELAY,
107
+ payload: {
108
+ roomId: this.roomId,
109
+ connectionId,
110
+ userId,
111
+ event,
112
+ payload,
113
+ },
114
+ });
115
+ }
116
+ /** Append chat message to storage and broadcast to all in room. */
117
+ async sendChat(connectionId, message, metadata, userId) {
118
+ await this.chatStorage.append(this.roomId, {
119
+ roomId: this.roomId,
120
+ connectionId,
121
+ userId,
122
+ message,
123
+ metadata,
124
+ });
125
+ const payload = {
126
+ roomId: this.roomId,
127
+ connectionId,
128
+ userId,
129
+ message,
130
+ metadata,
131
+ };
132
+ this.broadcast({
133
+ type: MSG_CHAT_MESSAGE,
134
+ payload,
135
+ });
136
+ }
137
+ broadcast(msg) {
138
+ for (const conn of this.connections.values()) {
139
+ conn.send(msg);
140
+ }
141
+ }
142
+ broadcastExcept(exceptConnectionId, msg) {
143
+ for (const conn of this.connections.values()) {
144
+ if (conn.connectionId !== exceptConnectionId) {
145
+ conn.send(msg);
146
+ }
147
+ }
148
+ }
149
+ }
150
+ //# sourceMappingURL=room.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room.js","sourceRoot":"","sources":["../src/room.ts"],"names":[],"mappings":"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"}