@nolag/collab 0.1.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 ADDED
@@ -0,0 +1,191 @@
1
+ # @nolag/collab
2
+
3
+ Real-time collaboration SDK for [NoLag](https://nolag.app) — live cursors, operations, and user awareness.
4
+
5
+ ## How It Works with NoLag
6
+
7
+ NoLag is a real-time messaging platform that handles WebSocket connections, message routing, persistence, and scaling. This SDK wraps the low-level [@nolag/js-sdk](https://www.npmjs.com/package/@nolag/js-sdk) and gives you a purpose-built collaboration API — broadcast editing operations, show live cursor positions, and track user awareness — without managing topics or subscriptions yourself.
8
+
9
+ ### Getting Your Token
10
+
11
+ 1. Sign up at [nolag.app](https://nolag.app)
12
+ 2. Create a new **project** in the portal
13
+ 3. Choose the **Collab** blueprint when creating an app — this pre-configures the topics (`operations`, `_cursors`) and settings your collaborative editor needs
14
+ 4. Go to the app's **Tokens** page and generate an **actor token**
15
+ 5. Use that token when connecting with this SDK
16
+
17
+ Each token identifies a unique collaborator (actor) in NoLag. The blueprint handles all the infrastructure setup — you just build your editor UI.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npm install @nolag/js-sdk @nolag/collab
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```typescript
28
+ import { NoLagCollab } from "@nolag/collab";
29
+
30
+ const collab = new NoLagCollab("YOUR_ACTOR_TOKEN", {
31
+ username: "Alice",
32
+ color: "#FF6B6B",
33
+ });
34
+
35
+ await collab.connect();
36
+
37
+ const doc = collab.joinDocument("readme.md");
38
+
39
+ // Send an editing operation
40
+ doc.sendOperation("insert", {
41
+ position: 42,
42
+ content: "Hello, world!",
43
+ path: "/content",
44
+ });
45
+
46
+ // Listen for operations from other users
47
+ doc.on("operation", (op) => {
48
+ console.log(`${op.username} ${op.type}d at position ${op.position}`);
49
+ applyOperation(op);
50
+ });
51
+
52
+ // Live cursors
53
+ doc.updateCursor({ line: 10, column: 5, path: "/content" });
54
+
55
+ doc.on("cursorMoved", (cursor) => {
56
+ renderCursor(cursor.userId, cursor.line, cursor.column, cursor.color);
57
+ });
58
+
59
+ // User awareness
60
+ doc.on("awarenessChanged", (users) => {
61
+ updatePresenceList(users);
62
+ });
63
+
64
+ doc.on("userJoined", (user) => {
65
+ console.log(`${user.username} started editing`);
66
+ });
67
+ ```
68
+
69
+ ## API Reference
70
+
71
+ ### `NoLagCollab`
72
+
73
+ #### Constructor
74
+
75
+ ```typescript
76
+ const collab = new NoLagCollab(token: string, options: NoLagCollabOptions);
77
+ ```
78
+
79
+ **Options:**
80
+
81
+ | Option | Type | Default | Description |
82
+ |--------|------|---------|-------------|
83
+ | `username` | `string` | *required* | Display name |
84
+ | `avatar` | `string` | — | Avatar URL |
85
+ | `color` | `string` | — | Cursor/highlight colour |
86
+ | `metadata` | `Record<string, unknown>` | — | Custom data |
87
+ | `documents` | `string[]` | — | Auto-join these documents on connect |
88
+ | `maxOperationCache` | `number` | `1000` | Max operations kept in memory |
89
+ | `idleTimeout` | `number` | `60000` | Ms before user is marked idle |
90
+ | `cursorThrottle` | `number` | `50` | Ms between cursor updates |
91
+ | `debug` | `boolean` | `false` | Enable debug logging |
92
+ | `reconnect` | `boolean` | `true` | Auto-reconnect on disconnect |
93
+
94
+ #### Methods
95
+
96
+ | Method | Returns | Description |
97
+ |--------|---------|-------------|
98
+ | `connect()` | `Promise<void>` | Connect to NoLag |
99
+ | `disconnect()` | `void` | Disconnect |
100
+ | `joinDocument(name)` | `CollabDocument` | Join a document |
101
+ | `leaveDocument(name)` | `void` | Leave a document |
102
+ | `getDocuments()` | `CollabDocument[]` | Get all joined documents |
103
+ | `getOnlineUsers()` | `CollabUser[]` | Get online users |
104
+
105
+ #### Events
106
+
107
+ | Event | Payload | Description |
108
+ |-------|---------|-------------|
109
+ | `connected` | — | Connected |
110
+ | `disconnected` | — | Disconnected |
111
+ | `reconnected` | — | Reconnected |
112
+ | `error` | `Error` | Error |
113
+ | `userOnline` | `CollabUser` | User came online |
114
+ | `userOffline` | `CollabUser` | User went offline |
115
+
116
+ ### `CollabDocument`
117
+
118
+ #### Methods
119
+
120
+ | Method | Returns | Description |
121
+ |--------|---------|-------------|
122
+ | `sendOperation(type, options?)` | `CollabOperation` | Send an editing operation |
123
+ | `getOperations()` | `CollabOperation[]` | Get cached operations |
124
+ | `updateCursor(options)` | `void` | Broadcast cursor position |
125
+ | `getCursors()` | `CursorPosition[]` | Get all cursor positions |
126
+ | `getCursor(userId)` | `CursorPosition \| undefined` | Get a user's cursor |
127
+ | `setStatus(status)` | `void` | Set status: `'active'`, `'idle'`, `'viewing'` |
128
+ | `getUsers()` | `CollabUser[]` | Get users in this document |
129
+ | `getUser(userId)` | `CollabUser \| undefined` | Get a specific user |
130
+
131
+ #### Events
132
+
133
+ | Event | Payload | Description |
134
+ |-------|---------|-------------|
135
+ | `operation` | `CollabOperation` | Operation received |
136
+ | `cursorMoved` | `CursorPosition` | Cursor position changed |
137
+ | `userJoined` | `CollabUser` | User joined document |
138
+ | `userLeft` | `CollabUser` | User left document |
139
+ | `awarenessChanged` | `CollabUser[]` | User statuses changed |
140
+ | `replayStart` / `replayEnd` | — | Operation replay |
141
+
142
+ ## Types
143
+
144
+ ```typescript
145
+ interface CollabOperation {
146
+ id: string;
147
+ type: OperationType;
148
+ path?: string;
149
+ position?: number;
150
+ length?: number;
151
+ content?: string;
152
+ data?: Record<string, unknown>;
153
+ userId: string;
154
+ username: string;
155
+ timestamp: number;
156
+ isReplay: boolean;
157
+ }
158
+
159
+ type OperationType = "insert" | "delete" | "replace" | "format" | "custom";
160
+
161
+ interface CursorPosition {
162
+ userId: string;
163
+ username: string;
164
+ color?: string;
165
+ x?: number;
166
+ y?: number;
167
+ line?: number;
168
+ column?: number;
169
+ selection?: unknown;
170
+ path?: string;
171
+ timestamp: number;
172
+ }
173
+
174
+ interface CollabUser {
175
+ userId: string;
176
+ actorTokenId: string;
177
+ username: string;
178
+ avatar?: string;
179
+ color?: string;
180
+ status: UserStatus;
181
+ metadata?: Record<string, unknown>;
182
+ joinedAt: number;
183
+ isLocal: boolean;
184
+ }
185
+
186
+ type UserStatus = "active" | "idle" | "viewing";
187
+ ```
188
+
189
+ ## License
190
+
191
+ MIT
@@ -0,0 +1,51 @@
1
+ import type { CursorPosition, UserStatus } from './types';
2
+ /**
3
+ * AwarenessManager — cursor tracking and idle detection per user.
4
+ *
5
+ * Tracks cursor positions for all connected users and manages per-user
6
+ * idle timers that fire a callback when a user has been inactive.
7
+ */
8
+ export declare class AwarenessManager {
9
+ private _cursors;
10
+ private _statuses;
11
+ private _idleTimers;
12
+ private _localUserId;
13
+ constructor(localUserId: string);
14
+ /**
15
+ * Update the cursor position for a user and reset their idle timer.
16
+ */
17
+ updateCursor(userId: string, position: CursorPosition): void;
18
+ /**
19
+ * Get the last known cursor position for a user.
20
+ */
21
+ getCursor(userId: string): CursorPosition | undefined;
22
+ /**
23
+ * Get all cursor positions except the local user's.
24
+ */
25
+ getCursors(): CursorPosition[];
26
+ /**
27
+ * Set the activity status for a user.
28
+ */
29
+ setStatus(userId: string, status: UserStatus): void;
30
+ /**
31
+ * Get the current activity status for a user (defaults to 'active').
32
+ */
33
+ getStatus(userId: string): UserStatus;
34
+ /**
35
+ * Start an idle timer for a user. If the timer fires, onIdle is called
36
+ * and the user's status is set to 'idle'. Calling updateCursor resets it.
37
+ */
38
+ startIdleTracking(userId: string, timeout: number, onIdle: () => void): void;
39
+ /**
40
+ * Cancel the idle timer for a user without firing the callback.
41
+ */
42
+ stopIdleTracking(userId: string): void;
43
+ /**
44
+ * Remove all cursor data for a user.
45
+ */
46
+ removeCursor(userId: string): void;
47
+ /**
48
+ * Dispose — clear all timers and state.
49
+ */
50
+ dispose(): void;
51
+ }
@@ -0,0 +1,81 @@
1
+ import type { RoomContext } from '@nolag/js-sdk';
2
+ import { EventEmitter } from './EventEmitter';
3
+ import type { CollabDocumentEvents, CollabOperation, CollabUser, CollabPresenceData, CursorPosition, CursorUpdateOptions, OperationType, SendOperationOptions, UserStatus, ResolvedCollabOptions } from './types';
4
+ /**
5
+ * CollabDocument — a single collaborative document room.
6
+ *
7
+ * Created via `NoLagCollab.joinDocument(name)`. Do not instantiate directly.
8
+ *
9
+ * Subscribes to 'operations' and '_cursors' topics and exposes a clean API
10
+ * for sending operations, broadcasting cursor positions, and managing
11
+ * user awareness (idle detection, status).
12
+ */
13
+ export declare class CollabDocument extends EventEmitter<CollabDocumentEvents> {
14
+ /** Document name */
15
+ readonly name: string;
16
+ private _roomContext;
17
+ private _localUser;
18
+ private _options;
19
+ private _presenceManager;
20
+ private _operationStore;
21
+ private _awarenessManager;
22
+ private _log;
23
+ /** Throttle state for cursor updates */
24
+ private _cursorThrottleTimer;
25
+ private _pendingCursorUpdate;
26
+ /** @internal */
27
+ constructor(name: string, roomContext: RoomContext, localUser: CollabUser, options: ResolvedCollabOptions, log: (...args: unknown[]) => void);
28
+ /** All remote users currently in this document */
29
+ get users(): Map<string, CollabUser>;
30
+ /**
31
+ * Send an operation to all collaborators in this document.
32
+ * Returns the operation that was created and broadcast.
33
+ */
34
+ sendOperation(type: OperationType, opts?: SendOperationOptions): CollabOperation;
35
+ /**
36
+ * Get all cached operations for this document, in timestamp order.
37
+ */
38
+ getOperations(): CollabOperation[];
39
+ /**
40
+ * Broadcast a cursor position update. Calls are throttled by the
41
+ * cursorThrottle option (default 50 ms) to avoid flooding.
42
+ */
43
+ updateCursor(opts: CursorUpdateOptions): void;
44
+ /**
45
+ * Get all remote cursor positions.
46
+ */
47
+ getCursors(): CursorPosition[];
48
+ /**
49
+ * Update the local user's activity status and broadcast it.
50
+ */
51
+ setStatus(status: UserStatus): void;
52
+ /**
53
+ * Get all remote users currently in the document.
54
+ */
55
+ getUsers(): CollabUser[];
56
+ /**
57
+ * Get a specific user by userId.
58
+ */
59
+ getUser(userId: string): CollabUser | undefined;
60
+ /** @internal Subscribe to operations and cursors topics and attach listeners */
61
+ _subscribe(): void;
62
+ /** @internal Set presence and fetch current room members */
63
+ _activate(): void;
64
+ /** @internal Re-set presence after reconnect */
65
+ _updateLocalPresence(): void;
66
+ /** @internal Handle a presence:join event */
67
+ _handlePresenceJoin(actorTokenId: string, presenceData: CollabPresenceData): void;
68
+ /** @internal Handle a presence:leave event */
69
+ _handlePresenceLeave(actorTokenId: string): void;
70
+ /** @internal Handle a presence:update event */
71
+ _handlePresenceUpdate(actorTokenId: string, presenceData: CollabPresenceData): void;
72
+ /** @internal Replay operations from another source (e.g. history fetch) */
73
+ _replayOperations(ops: CollabOperation[]): void;
74
+ /** @internal Unsubscribe and clean up */
75
+ _cleanup(): void;
76
+ private _handleIncomingOperation;
77
+ private _handleIncomingCursor;
78
+ private _flushCursorUpdate;
79
+ private _setPresence;
80
+ private _startUserIdleTracking;
81
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Tiny typed event emitter — framework-agnostic base for NoLag SDKs.
3
+ *
4
+ * EventMap is a record of event name → tuple of handler arguments.
5
+ */
6
+ export declare class EventEmitter<EventMap extends {
7
+ [K in keyof EventMap]: unknown[];
8
+ }> {
9
+ private _handlers;
10
+ on<K extends keyof EventMap>(event: K, handler: (...args: EventMap[K]) => void): this;
11
+ off<K extends keyof EventMap>(event: K, handler?: (...args: EventMap[K]) => void): this;
12
+ removeAllListeners(): this;
13
+ protected emit<K extends keyof EventMap>(event: K, ...args: EventMap[K]): void;
14
+ listenerCount<K extends keyof EventMap>(event: K): number;
15
+ }
@@ -0,0 +1,81 @@
1
+ import { EventEmitter } from './EventEmitter';
2
+ import { CollabDocument } from './CollabDocument';
3
+ import type { NoLagCollabOptions, CollabClientEvents, CollabUser } from './types';
4
+ /**
5
+ * NoLagCollab — high-level real-time collaboration SDK built on @nolag/js-sdk.
6
+ *
7
+ * Provides document-scoped operations, cursor broadcasting, and user awareness
8
+ * (idle detection, status tracking) — all framework-agnostic via events.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { NoLagCollab } from '@nolag/collab';
13
+ *
14
+ * const collab = new NoLagCollab(token, { username: 'Alice', debug: true });
15
+ *
16
+ * collab.on('connected', () => console.log('Connected!'));
17
+ * collab.on('userOnline', (user) => console.log(user.username, 'is online'));
18
+ *
19
+ * await collab.connect();
20
+ *
21
+ * const doc = collab.joinDocument('my-doc');
22
+ * doc.on('operation', (op) => applyOp(op));
23
+ * doc.sendOperation('insert', { position: 0, content: 'Hello' });
24
+ * ```
25
+ */
26
+ export declare class NoLagCollab extends EventEmitter<CollabClientEvents> {
27
+ private _token;
28
+ private _options;
29
+ private _client;
30
+ private _localUser;
31
+ private _documents;
32
+ private _lobby;
33
+ private _onlineUsers;
34
+ private _actorToUserId;
35
+ private _userId;
36
+ private _log;
37
+ constructor(token: string, options: NoLagCollabOptions);
38
+ /** Whether the underlying connection is established */
39
+ get connected(): boolean;
40
+ /** The local user's info (available after connect) */
41
+ get localUser(): CollabUser | null;
42
+ /** All currently joined documents */
43
+ get documents(): Map<string, CollabDocument>;
44
+ /**
45
+ * Connect to NoLag and set up global presence.
46
+ */
47
+ connect(): Promise<void>;
48
+ /**
49
+ * Disconnect from NoLag and clean up all documents.
50
+ */
51
+ disconnect(): void;
52
+ /**
53
+ * Join a collaborative document. Creates, subscribes, and activates it.
54
+ * Returns an existing document if already joined.
55
+ */
56
+ joinDocument(name: string): CollabDocument;
57
+ /**
58
+ * Leave a collaborative document. Fully unsubscribes and removes it.
59
+ */
60
+ leaveDocument(name: string): void;
61
+ /**
62
+ * Get all joined documents.
63
+ */
64
+ getDocuments(): CollabDocument[];
65
+ /**
66
+ * Get all users currently online across all documents.
67
+ */
68
+ getOnlineUsers(): CollabUser[];
69
+ private _subscribeDocument;
70
+ private _handleRoomPresenceJoin;
71
+ private _handleRoomPresenceLeave;
72
+ private _handleRoomPresenceUpdate;
73
+ private _setupLobby;
74
+ private _handleLobbyJoin;
75
+ private _handleLobbyLeave;
76
+ private _handleLobbyUpdate;
77
+ private _hydrateOnlineUsers;
78
+ private _presenceToUser;
79
+ private _findUserIdByActorId;
80
+ private _restoreDocuments;
81
+ }
@@ -0,0 +1,39 @@
1
+ import type { CollabOperation } from './types';
2
+ /**
3
+ * Ordered, deduplicated operation log bounded by maxOperationCache.
4
+ *
5
+ * Operations are stored sorted by timestamp ascending. Duplicate IDs are
6
+ * silently ignored. When the cache exceeds its limit the oldest entries
7
+ * are evicted.
8
+ */
9
+ export declare class OperationStore {
10
+ private _ops;
11
+ private _ids;
12
+ private _maxSize;
13
+ constructor(maxSize: number);
14
+ /**
15
+ * Add an operation to the store.
16
+ * Returns true if the operation was added, false if it was a duplicate.
17
+ */
18
+ add(op: CollabOperation): boolean;
19
+ /**
20
+ * Get all stored operations in timestamp order.
21
+ */
22
+ getAll(): CollabOperation[];
23
+ /**
24
+ * Get all operations sent by a specific user.
25
+ */
26
+ getByUser(userId: string): CollabOperation[];
27
+ /**
28
+ * Check whether an operation ID is already stored.
29
+ */
30
+ has(id: string): boolean;
31
+ /**
32
+ * Number of operations currently stored.
33
+ */
34
+ get size(): number;
35
+ /**
36
+ * Clear all stored operations.
37
+ */
38
+ clear(): void;
39
+ }
@@ -0,0 +1,44 @@
1
+ import type { CollabUser, CollabPresenceData, UserStatus } from './types';
2
+ /**
3
+ * PresenceManager — maps actorTokenId ↔ CollabUser, filtering self.
4
+ */
5
+ export declare class PresenceManager {
6
+ private _users;
7
+ private _actorToUserId;
8
+ private _localActorId;
9
+ constructor(localActorId: string);
10
+ /**
11
+ * Add or update a user from presence data.
12
+ * Returns the CollabUser if it is a remote user, null if it is self.
13
+ */
14
+ addFromPresence(actorTokenId: string, presence: CollabPresenceData, joinedAt?: number): CollabUser | null;
15
+ /**
16
+ * Remove a user by actorTokenId.
17
+ * Returns the removed CollabUser, or null if not found / is self.
18
+ */
19
+ removeByActorId(actorTokenId: string): CollabUser | null;
20
+ /**
21
+ * Update only the status field for an existing user.
22
+ */
23
+ updateStatus(actorTokenId: string, status: UserStatus): CollabUser | null;
24
+ /**
25
+ * Get a user by userId.
26
+ */
27
+ getUser(userId: string): CollabUser | undefined;
28
+ /**
29
+ * Get a user by actorTokenId.
30
+ */
31
+ getUserByActorId(actorTokenId: string): CollabUser | undefined;
32
+ /**
33
+ * Get all remote users.
34
+ */
35
+ getAll(): CollabUser[];
36
+ /**
37
+ * Get the users Map (readonly view).
38
+ */
39
+ get users(): Map<string, CollabUser>;
40
+ /**
41
+ * Clear all tracked users.
42
+ */
43
+ clear(): void;
44
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @nolag/collab — Browser entry point
3
+ */
4
+ export { NoLagCollab } from './NoLagCollab';
5
+ export { CollabDocument } from './CollabDocument';
6
+ export { EventEmitter } from './EventEmitter';
7
+ export type { NoLagCollabOptions, ResolvedCollabOptions, OperationType, UserStatus, CollabOperation, SendOperationOptions, CursorPosition, CursorUpdateOptions, CollabUser, CollabPresenceData, CollabClientEvents, CollabDocumentEvents, } from './types';
@@ -0,0 +1,2 @@
1
+ import{NoLag as e}from"@nolag/js-sdk";class t{constructor(){this._handlers=new Map}on(e,t){return this._handlers.has(e)||this._handlers.set(e,new Set),this._handlers.get(e).add(t),this}off(e,t){return t?this._handlers.get(e)?.delete(t):this._handlers.delete(e),this}removeAllListeners(){return this._handlers.clear(),this}emit(e,...t){const s=this._handlers.get(e);if(s)for(const r of s)try{r(...t)}catch(t){console.error(`Error in ${String(e)} handler:`,t)}}listenerCount(e){return this._handlers.get(e)?.size??0}}class s{constructor(e){this._users=new Map,this._actorToUserId=new Map,this._localActorId=e}addFromPresence(e,t,s){if(e===this._localActorId)return null;const r=this._actorToUserId.get(e),o=t.userId||r||e,n={userId:o,actorTokenId:e,username:t.username,avatar:t.avatar,color:t.color,status:t.status??"active",metadata:t.metadata,joinedAt:s??Date.now(),isLocal:!1};return this._users.set(o,n),this._actorToUserId.set(e,o),n}removeByActorId(e){if(e===this._localActorId)return null;const t=this._actorToUserId.get(e);if(!t)return null;const s=this._users.get(t)??null;return this._users.delete(t),this._actorToUserId.delete(e),s}updateStatus(e,t){const s=this._actorToUserId.get(e);if(!s)return null;const r=this._users.get(s);if(!r)return null;const o={...r,status:t};return this._users.set(s,o),o}getUser(e){return this._users.get(e)}getUserByActorId(e){const t=this._actorToUserId.get(e);return t?this._users.get(t):void 0}getAll(){return Array.from(this._users.values())}get users(){return this._users}clear(){this._users.clear(),this._actorToUserId.clear()}}class r{constructor(e){this._ops=[],this._ids=new Set,this._maxSize=e}add(e){if(this._ids.has(e.id))return!1;for(this._ids.add(e.id),this._ops.push(e),this._ops.sort((e,t)=>e.timestamp-t.timestamp);this._ops.length>this._maxSize;){const e=this._ops.shift();e&&this._ids.delete(e.id)}return!0}getAll(){return[...this._ops]}getByUser(e){return this._ops.filter(t=>t.userId===e)}has(e){return this._ids.has(e)}get size(){return this._ops.length}clear(){this._ops=[],this._ids.clear()}}class o{constructor(e){this._cursors=new Map,this._statuses=new Map,this._idleTimers=new Map,this._localUserId=e}updateCursor(e,t){if(this._cursors.set(e,t),this._idleTimers.has(e)){const t=this._idleTimers.get(e);clearTimeout(t),this._idleTimers.delete(e)}}getCursor(e){return this._cursors.get(e)}getCursors(){return Array.from(this._cursors.values()).filter(e=>e.userId!==this._localUserId)}setStatus(e,t){this._statuses.set(e,t)}getStatus(e){return this._statuses.get(e)??"active"}startIdleTracking(e,t,s){this.stopIdleTracking(e);const r=setTimeout(()=>{this._idleTimers.delete(e),this._statuses.set(e,"idle"),s()},t);this._idleTimers.set(e,r)}stopIdleTracking(e){const t=this._idleTimers.get(e);void 0!==t&&(clearTimeout(t),this._idleTimers.delete(e))}removeCursor(e){this._cursors.delete(e),this._statuses.delete(e),this.stopIdleTracking(e)}dispose(){for(const e of this._idleTimers.values())clearTimeout(e);this._idleTimers.clear(),this._cursors.clear(),this._statuses.clear()}}function n(){return"undefined"!=typeof crypto&&"function"==typeof crypto.randomUUID?crypto.randomUUID():"xxxx-xxxx-xxxx-xxxx".replace(/x/g,()=>Math.floor(16*Math.random()).toString(16))}function i(e,t){return t?(...t)=>{console.log(`[${e}]`,...t)}:(...e)=>{}}const a="operations",c="_cursors";class h extends t{constructor(e,t,n,i,a){super(),this._cursorThrottleTimer=null,this._pendingCursorUpdate=null,this.name=e,this._roomContext=t,this._localUser=n,this._options=i,this._log=a,this._presenceManager=new s(n.actorTokenId),this._operationStore=new r(i.maxOperationCache),this._awarenessManager=new o(n.userId)}get users(){return this._presenceManager.users}sendOperation(e,t={}){const s={id:n(),type:e,path:t.path,position:t.position,length:t.length,content:t.content,data:t.data,userId:this._localUser.userId,username:this._localUser.username,timestamp:Date.now(),isReplay:!1};return this._log("Sending operation:",e,s.id),this._operationStore.add(s),this._roomContext.emit(a,s,{echo:!1}),s}getOperations(){return this._operationStore.getAll()}updateCursor(e){this._pendingCursorUpdate=e,null===this._cursorThrottleTimer&&(this._flushCursorUpdate(),this._cursorThrottleTimer=setTimeout(()=>{this._cursorThrottleTimer=null,this._pendingCursorUpdate&&this._flushCursorUpdate()},this._options.cursorThrottle))}getCursors(){return this._awarenessManager.getCursors()}setStatus(e){this._localUser={...this._localUser,status:e},this._setPresence(),this._log("Status updated:",e)}getUsers(){return this._presenceManager.getAll()}getUser(e){return this._presenceManager.getUser(e)}_subscribe(){this._log("Document subscribe:",this.name),this._roomContext.subscribe(a),this._roomContext.subscribe(c),this._roomContext.on(a,e=>{this._handleIncomingOperation(e)}),this._roomContext.on(c,e=>{this._handleIncomingCursor(e)})}_activate(){this._log("Document activate:",this.name),this._setPresence(),this._roomContext.fetchPresence().then(e=>{this._log("Document presence fetched:",this.name,e.length,"actors");for(const t of e)if(t.presence){const e=this._presenceManager.addFromPresence(t.actorTokenId,t.presence,t.joinedAt);e&&(this._awarenessManager.setStatus(e.userId,e.status),this.emit("userJoined",e))}}).catch(e=>{this._log("Failed to fetch document presence:",e)})}_updateLocalPresence(){this._setPresence()}_handlePresenceJoin(e,t){const s=this._presenceManager.addFromPresence(e,t);s&&(this._log("User joined document:",this.name,s.userId),this._awarenessManager.setStatus(s.userId,s.status),this._startUserIdleTracking(s),this.emit("userJoined",s))}_handlePresenceLeave(e){const t=this._presenceManager.removeByActorId(e);t&&(this._log("User left document:",this.name,t.userId),this._awarenessManager.removeCursor(t.userId),this.emit("userLeft",t))}_handlePresenceUpdate(e,t){const s=this._presenceManager.addFromPresence(e,t);s&&this._awarenessManager.setStatus(s.userId,s.status)}_replayOperations(e){const t=e.filter(e=>!this._operationStore.has(e.id));if(0===t.length)return;this._log("Replaying",t.length,"operations"),this.emit("replayStart",{count:t.length});let s=0;for(const e of t){const t={...e,isReplay:!0};this._operationStore.add(t)&&(this.emit("operation",t),s++)}this.emit("replayEnd",{replayed:s})}_cleanup(){this._log("Document cleanup:",this.name),null!==this._cursorThrottleTimer&&(clearTimeout(this._cursorThrottleTimer),this._cursorThrottleTimer=null),this._roomContext.unsubscribe(a),this._roomContext.unsubscribe(c),this._roomContext.off(a),this._roomContext.off(c),this._awarenessManager.dispose(),this._presenceManager.clear(),this._operationStore.clear(),this.removeAllListeners()}_handleIncomingOperation(e){const t=e;if(this._operationStore.has(t.id))return;const s={...t,isReplay:!1};this._operationStore.add(s),this._log("Received operation:",t.type,t.id,"from",t.userId),this.emit("operation",s)}_handleIncomingCursor(e){const t=e;if(t.userId===this._localUser.userId)return;this._awarenessManager.updateCursor(t.userId,t);const s=this._presenceManager.getUser(t.userId);s&&this._startUserIdleTracking(s),this._log("Cursor moved:",t.userId),this.emit("cursorMoved",t)}_flushCursorUpdate(){if(!this._pendingCursorUpdate)return;const e=this._pendingCursorUpdate;this._pendingCursorUpdate=null;const t={userId:this._localUser.userId,username:this._localUser.username,color:this._localUser.color,timestamp:Date.now(),...e};this._awarenessManager.updateCursor(this._localUser.userId,t),this._roomContext.emit(c,t,{echo:!1})}_setPresence(){const e={userId:this._localUser.userId,username:this._localUser.username,avatar:this._localUser.avatar,color:this._localUser.color,status:this._localUser.status,metadata:this._localUser.metadata};this._roomContext.setPresence(e)}_startUserIdleTracking(e){"active"!==this._awarenessManager.getStatus(e.userId)&&this._awarenessManager.setStatus(e.userId,"active"),this._awarenessManager.startIdleTracking(e.userId,this._options.idleTimeout,()=>{this._log("User went idle:",e.userId),this.emit("awarenessChanged",{userId:e.userId,status:"idle"})})}}class l extends t{constructor(e,t){super(),this._client=null,this._localUser=null,this._documents=new Map,this._lobby=null,this._onlineUsers=new Map,this._actorToUserId=new Map,this._token=e,this._userId=n(),this._options={username:t.username,avatar:t.avatar,color:t.color,metadata:t.metadata,appName:t.appName??"collab",url:t.url,maxOperationCache:t.maxOperationCache??1e3,idleTimeout:t.idleTimeout??6e4,cursorThrottle:t.cursorThrottle??50,debug:t.debug??!1,reconnect:t.reconnect??!0,documents:t.documents??[]},this._log=i("NoLagCollab",this._options.debug)}get connected(){return this._client?.connected??!1}get localUser(){return this._localUser}get documents(){return this._documents}async connect(){this._log("Connecting...");const t={debug:this._options.debug,reconnect:this._options.reconnect};this._options.url&&(t.url=this._options.url),this._client=e(this._token,t),this._client.on("connect",()=>{this._log("Connected"),this._documents.size>0&&(this._log("Reconnected — restoring documents..."),this._restoreDocuments(),this.emit("reconnected"))}),this._client.on("disconnect",e=>{this._log("Disconnected:",e),this.emit("disconnected",e)}),this._client.on("reconnect",()=>{this._log("Reconnecting...")}),this._client.on("error",e=>{this._log("Error:",e),this.emit("error",e)}),await this._client.connect(),this._client.on("presence:join",e=>{this._handleRoomPresenceJoin(e)}),this._client.on("presence:leave",e=>{this._handleRoomPresenceLeave(e)}),this._client.on("presence:update",e=>{this._handleRoomPresenceUpdate(e)}),this._localUser={userId:this._userId,actorTokenId:this._client.actorId,username:this._options.username,avatar:this._options.avatar,color:this._options.color,status:"active",metadata:this._options.metadata,joinedAt:Date.now(),isLocal:!0},this._log("Local user:",this._localUser.userId,"→",this._localUser.actorTokenId),await this._setupLobby(),this.emit("connected");for(const e of this._options.documents)this.joinDocument(e);setTimeout(()=>{this._lobby&&this._client?.connected&&this._lobby.fetchPresence().then(e=>{this._hydrateOnlineUsers(e)}).catch(()=>{})},2e3)}disconnect(){this._log("Disconnecting...");for(const e of[...this._documents.keys()])this.leaveDocument(e);this._lobby?.unsubscribe(),this._lobby=null,this._client?.disconnect(),this._client=null,this._onlineUsers.clear(),this._actorToUserId.clear(),this._localUser=null}joinDocument(e){if(!this._client||!this._localUser)throw new Error("Not connected — call connect() first");let t=this._documents.get(e);return t||(t=this._subscribeDocument(e),t._activate()),t}leaveDocument(e){const t=this._documents.get(e);t&&(this._log("Leaving document:",e),t._cleanup(),this._documents.delete(e))}getDocuments(){return Array.from(this._documents.values())}getOnlineUsers(){return Array.from(this._onlineUsers.values())}_subscribeDocument(e){if(!this._client||!this._localUser)throw new Error("Not connected — call connect() first");this._log("Subscribing document:",e);const t=this._client.setApp(this._options.appName).setRoom(e),s=new h(e,t,this._localUser,this._options,i(`CollabDocument:${e}`,this._options.debug));return this._documents.set(e,s),s._subscribe(),s}_handleRoomPresenceJoin(e){if(e.actorTokenId===this._localUser?.actorTokenId)return;const t=e.presence;if(!t?.userId)return;const s=this._presenceToUser(e.actorTokenId,t);this._actorToUserId.set(e.actorTokenId,s.userId),this._onlineUsers.has(s.userId)||(this._onlineUsers.set(s.userId,s),this.emit("userOnline",s));for(const s of this._documents.values())s._handlePresenceJoin(e.actorTokenId,t)}_handleRoomPresenceLeave(e){if(e.actorTokenId!==this._localUser?.actorTokenId)for(const t of this._documents.values())t._handlePresenceLeave(e.actorTokenId)}_handleRoomPresenceUpdate(e){if(e.actorTokenId===this._localUser?.actorTokenId)return;const t=e.presence;if(t?.userId){if(this._onlineUsers.has(t.userId)){const s=this._presenceToUser(e.actorTokenId,t);this._onlineUsers.set(s.userId,s)}for(const s of this._documents.values())s._handlePresenceUpdate(e.actorTokenId,t)}}async _setupLobby(){if(!this._client)return;this._lobby=this._client.setApp(this._options.appName).setLobby("online");const e=e=>t=>{const s=t;"join"===e?this._handleLobbyJoin(s):"leave"===e?this._handleLobbyLeave(s):this._handleLobbyUpdate(s)};this._client.on("lobbyPresence:join",e("join")),this._client.on("lobbyPresence:leave",e("leave")),this._client.on("lobbyPresence:update",e("update"));try{const e=await this._lobby.subscribe();this._hydrateOnlineUsers(e),this._log("Lobby subscribed, online users:",this._onlineUsers.size)}catch(e){this._log("Lobby subscription failed:",e)}}_handleLobbyJoin(e){const{actorId:t,data:s}=e;if(t===this._localUser?.actorTokenId)return;const r=s;if(!r.userId)return;const o=this._presenceToUser(t,r);this._actorToUserId.set(t,o.userId),this._onlineUsers.has(o.userId)||(this._onlineUsers.set(o.userId,o),this.emit("userOnline",o))}_handleLobbyLeave(e){const{actorId:t,data:s}=e;if(t===this._localUser?.actorTokenId)return;const r=s,o=r?.userId||this._actorToUserId.get(t)||this._findUserIdByActorId(t);if(o){const e=this._onlineUsers.get(o);e&&(this._onlineUsers.delete(o),this._actorToUserId.delete(t),this.emit("userOffline",e))}}_handleLobbyUpdate(e){const{actorId:t,data:s}=e;if(t===this._localUser?.actorTokenId)return;const r=s;if(!r.userId)return;const o=this._presenceToUser(t,r);this._onlineUsers.set(o.userId,o)}_hydrateOnlineUsers(e){for(const t of Object.keys(e)){const s=e[t];for(const e of Object.keys(s)){if(e===this._localUser?.actorTokenId)continue;const t=s[e],r=t?.presence??t;if(r?.userId){const t=this._presenceToUser(e,r);this._actorToUserId.set(e,t.userId),this._onlineUsers.has(t.userId)||(this._onlineUsers.set(t.userId,t),this.emit("userOnline",t))}}}}_presenceToUser(e,t){return{userId:t.userId,actorTokenId:e,username:t.username,avatar:t.avatar,color:t.color,status:t.status??"active",metadata:t.metadata,joinedAt:Date.now(),isLocal:!1}}_findUserIdByActorId(e){for(const t of this._onlineUsers.values())if(t.actorTokenId===e)return t.userId}_restoreDocuments(){for(const e of this._documents.values())e._updateLocalPresence();this._lobby?.fetchPresence().then(e=>{this._onlineUsers.clear(),this._actorToUserId.clear(),this._hydrateOnlineUsers(e)}).catch(e=>{this._log("Failed to re-fetch lobby presence:",e)})}}export{h as CollabDocument,t as EventEmitter,l as NoLagCollab};
2
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sources":["../src/EventEmitter.ts","../src/PresenceManager.ts","../src/OperationStore.ts","../src/AwarenessManager.ts","../src/utils.ts","../src/constants.ts","../src/CollabDocument.ts","../src/NoLagCollab.ts"],"sourcesContent":[null,null,null,null,null,null,null,null],"names":["EventEmitter","constructor","this","_handlers","Map","on","event","handler","has","set","Set","get","add","off","delete","removeAllListeners","clear","emit","args","handlers","e","console","error","String","listenerCount","size","PresenceManager","localActorId","_users","_actorToUserId","_localActorId","addFromPresence","actorTokenId","presence","joinedAt","existing","userId","user","username","avatar","color","status","metadata","Date","now","isLocal","removeByActorId","updateStatus","updated","getUser","getUserByActorId","undefined","getAll","Array","from","values","users","OperationStore","maxSize","_ops","_ids","_maxSize","op","id","push","sort","a","b","timestamp","length","evicted","shift","getByUser","filter","AwarenessManager","localUserId","_cursors","_statuses","_idleTimers","_localUserId","updateCursor","position","timer","clearTimeout","getCursor","getCursors","c","setStatus","getStatus","startIdleTracking","timeout","onIdle","stopIdleTracking","setTimeout","removeCursor","dispose","generateId","crypto","randomUUID","replace","Math","floor","random","toString","createLogger","prefix","enabled","log","_args","TOPIC_OPERATIONS","TOPIC_CURSORS","CollabDocument","name","roomContext","localUser","options","super","_cursorThrottleTimer","_pendingCursorUpdate","_roomContext","_localUser","_options","_log","_presenceManager","_operationStore","maxOperationCache","_awarenessManager","sendOperation","type","opts","path","content","data","isReplay","echo","getOperations","_flushCursorUpdate","cursorThrottle","_setPresence","getUsers","_subscribe","subscribe","_handleIncomingOperation","_handleIncomingCursor","_activate","fetchPresence","then","actors","actor","catch","err","_updateLocalPresence","_handlePresenceJoin","presenceData","_startUserIdleTracking","_handlePresenceLeave","_handlePresenceUpdate","_replayOperations","ops","pending","count","replayed","replayOp","_cleanup","unsubscribe","stored","cursor","setPresence","idleTimeout","NoLagCollab","token","_client","_documents","_lobby","_onlineUsers","_token","_userId","appName","url","debug","reconnect","documents","connected","connect","clientOptions","NoLag","_restoreDocuments","reason","_handleRoomPresenceJoin","_handleRoomPresenceLeave","_handleRoomPresenceUpdate","actorId","_setupLobby","docName","joinDocument","state","_hydrateOnlineUsers","disconnect","keys","leaveDocument","Error","doc","_subscribeDocument","getDocuments","getOnlineUsers","setApp","setRoom","_presenceToUser","setLobby","lobbyHandler","_handleLobbyJoin","_handleLobbyLeave","_handleLobbyUpdate","initialState","_findUserIdByActorId","roomId","Object","roomPresence","raw"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /** Default app name for NoLag collab SDK */
2
+ export declare const DEFAULT_APP_NAME = "collab";
3
+ /** Maximum number of operations to keep in the cache */
4
+ export declare const DEFAULT_MAX_OPERATION_CACHE = 1000;
5
+ /** Idle timeout in milliseconds before a user is marked idle */
6
+ export declare const DEFAULT_IDLE_TIMEOUT = 60000;
7
+ /** Cursor throttle in milliseconds — minimum interval between cursor updates */
8
+ export declare const DEFAULT_CURSOR_THROTTLE = 50;
9
+ /** Topic name for operation messages within a document */
10
+ export declare const TOPIC_OPERATIONS = "operations";
11
+ /** Topic name for cursor presence messages within a document */
12
+ export declare const TOPIC_CURSORS = "_cursors";
13
+ /** Lobby ID for global online presence */
14
+ export declare const LOBBY_ID = "online";