@xemahq/realtime-client 0.1.1

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.
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SseClient = void 0;
4
+ const cursor_store_1 = require("./cursor-store");
5
+ class SseClient {
6
+ options;
7
+ onEnvelope;
8
+ onControl;
9
+ onResync;
10
+ onStatus;
11
+ cursorStore;
12
+ url;
13
+ watchdogMs;
14
+ baseMs;
15
+ maxMs;
16
+ abortController = null;
17
+ watchdogTimer = null;
18
+ reconnectAttempt = 0;
19
+ stopped = false;
20
+ constructor(options, onEnvelope, onControl, onResync, cursorStore, onStatus) {
21
+ this.options = options;
22
+ this.onEnvelope = onEnvelope;
23
+ this.onControl = onControl;
24
+ this.onResync = onResync;
25
+ this.onStatus = onStatus;
26
+ this.cursorStore = cursorStore ?? new cursor_store_1.CursorStore();
27
+ this.url = options.url ?? '/realtime/stream';
28
+ this.watchdogMs = options.watchdogMs ?? 45_000;
29
+ this.baseMs = options.reconnectBaseMs ?? 1_000;
30
+ this.maxMs = options.reconnectMaxMs ?? 30_000;
31
+ }
32
+ emitStatus(status) {
33
+ if (this.onStatus)
34
+ this.onStatus(status);
35
+ }
36
+ start() {
37
+ if (this.stopped)
38
+ return;
39
+ void this.connect();
40
+ }
41
+ stop() {
42
+ this.stopped = true;
43
+ this.clearWatchdog();
44
+ if (this.abortController) {
45
+ this.abortController.abort();
46
+ this.abortController = null;
47
+ }
48
+ this.emitStatus('closed');
49
+ }
50
+ cursors() {
51
+ return this.cursorStore.get();
52
+ }
53
+ async connect() {
54
+ if (this.stopped)
55
+ return;
56
+ this.emitStatus('connecting');
57
+ const token = await this.options.tokenProvider();
58
+ const lastEventId = this.cursorStore.encodeForLastEventId();
59
+ console.log('[Realtime:SSE]', 'connect.start', {
60
+ url: this.url,
61
+ orgId: this.options.orgId,
62
+ lastEventId,
63
+ attempt: this.reconnectAttempt,
64
+ });
65
+ this.abortController = new AbortController();
66
+ const signal = this.abortController.signal;
67
+ try {
68
+ const res = await fetch(this.url, {
69
+ method: 'GET',
70
+ headers: {
71
+ Authorization: `Bearer ${token}`,
72
+ Accept: 'text/event-stream',
73
+ 'X-Org-Id': this.options.orgId,
74
+ 'Last-Event-ID': lastEventId,
75
+ },
76
+ signal,
77
+ });
78
+ if (!res.ok || !res.body) {
79
+ console.error('[Realtime:SSE]', 'connect.fail', {
80
+ url: this.url,
81
+ status: res.status,
82
+ statusText: res.statusText,
83
+ });
84
+ throw new Error(`SSE connect failed: HTTP ${res.status}`);
85
+ }
86
+ console.log('[Realtime:SSE]', 'connect.ok', {
87
+ url: this.url,
88
+ status: res.status,
89
+ });
90
+ this.reconnectAttempt = 0;
91
+ this.emitStatus('open');
92
+ this.armWatchdog();
93
+ const reader = res.body.getReader();
94
+ const decoder = new TextDecoder('utf-8');
95
+ let buffer = '';
96
+ while (!signal.aborted) {
97
+ const { done, value } = await reader.read();
98
+ if (done)
99
+ break;
100
+ buffer += decoder.decode(value, { stream: true });
101
+ this.armWatchdog();
102
+ const events = drainSseEvents(buffer);
103
+ buffer = events.remainder;
104
+ for (const evt of events.parsed)
105
+ this.handleParsed(evt);
106
+ }
107
+ console.log('[Realtime:SSE]', 'connect.closed', {
108
+ aborted: signal.aborted,
109
+ stopped: this.stopped,
110
+ });
111
+ }
112
+ catch (err) {
113
+ if (signal.aborted || this.stopped)
114
+ return;
115
+ console.error('[Realtime:SSE]', 'connect.error', {
116
+ url: this.url,
117
+ message: err instanceof Error ? err.message : String(err),
118
+ });
119
+ }
120
+ this.clearWatchdog();
121
+ if (!this.stopped) {
122
+ this.emitStatus('reconnecting');
123
+ this.scheduleReconnect();
124
+ }
125
+ }
126
+ handleParsed(evt) {
127
+ if (evt.event === 'resync') {
128
+ console.log('[Realtime:SSE]', 'frame.resync', { id: evt.id ?? null });
129
+ this.cursorStore.reset();
130
+ this.onResync();
131
+ return;
132
+ }
133
+ if (!evt.data) {
134
+ console.log('[Realtime:SSE]', 'frame.empty', {
135
+ id: evt.id ?? null,
136
+ event: evt.event ?? null,
137
+ });
138
+ return;
139
+ }
140
+ let parsed;
141
+ try {
142
+ parsed = JSON.parse(evt.data);
143
+ }
144
+ catch (err) {
145
+ console.error('[Realtime:SSE]', 'frame.json-parse-failed', {
146
+ id: evt.id ?? null,
147
+ event: evt.event ?? null,
148
+ rawLength: evt.data.length,
149
+ message: err instanceof Error ? err.message : String(err),
150
+ });
151
+ return;
152
+ }
153
+ const evtType = typeof parsed['type'] === 'string' ? parsed['type'] : '';
154
+ if (evt.event && evt.event !== 'message') {
155
+ console.log('[Realtime:SSE]', 'frame.control', {
156
+ id: evt.id ?? null,
157
+ event: evt.event,
158
+ });
159
+ this.onControl(evt.event, parsed);
160
+ this.captureControlCursors(evt.event, parsed);
161
+ return;
162
+ }
163
+ if (typeof parsed['type'] === 'string' && evtType.length > 0) {
164
+ console.log('[Realtime:SSE]', 'frame.envelope', {
165
+ id: evt.id ?? null,
166
+ type: evtType,
167
+ });
168
+ this.onEnvelope(parsed);
169
+ this.captureCursors(parsed);
170
+ }
171
+ else {
172
+ console.log('[Realtime:SSE]', 'frame.unknown-shape', {
173
+ id: evt.id ?? null,
174
+ event: evt.event ?? null,
175
+ keys: Object.keys(parsed),
176
+ });
177
+ }
178
+ }
179
+ captureCursors(envelope) {
180
+ const g = envelope['ehglobalseq'];
181
+ if (typeof g === 'string')
182
+ this.cursorStore.patchGlobal(g);
183
+ const o = envelope['ehorgseq'];
184
+ if (typeof o === 'string')
185
+ this.cursorStore.patchOrg(o);
186
+ const p = envelope['ehprojectseq'];
187
+ const pid = envelope['ehprojectid'];
188
+ if (typeof p === 'string' && typeof pid === 'string') {
189
+ this.cursorStore.patchProject(pid, p);
190
+ }
191
+ const s = envelope['ehsessionseq'];
192
+ const subject = envelope['subject'];
193
+ if (typeof s === 'string' && typeof subject === 'string') {
194
+ const prefix = 'session/';
195
+ if (subject.startsWith(prefix)) {
196
+ this.cursorStore.patchSession(subject.slice(prefix.length), s);
197
+ }
198
+ }
199
+ }
200
+ captureControlCursors(frameType, parsed) {
201
+ if (frameType !== 'connected')
202
+ return;
203
+ const c = parsed['cursors'];
204
+ if (!c || typeof c !== 'object')
205
+ return;
206
+ const obj = c;
207
+ const g = obj['global'];
208
+ if (typeof g === 'string')
209
+ this.cursorStore.patchGlobal(g);
210
+ const o = obj['org'];
211
+ if (typeof o === 'string')
212
+ this.cursorStore.patchOrg(o);
213
+ }
214
+ armWatchdog() {
215
+ this.clearWatchdog();
216
+ this.watchdogTimer = setTimeout(() => {
217
+ if (this.abortController)
218
+ this.abortController.abort();
219
+ }, this.watchdogMs);
220
+ }
221
+ clearWatchdog() {
222
+ if (this.watchdogTimer) {
223
+ clearTimeout(this.watchdogTimer);
224
+ this.watchdogTimer = null;
225
+ }
226
+ }
227
+ scheduleReconnect() {
228
+ const attempt = this.reconnectAttempt++;
229
+ const baseDelay = Math.min(this.baseMs * 2 ** attempt, this.maxMs);
230
+ const jitter = 0.5 + Math.random();
231
+ const delay = Math.round(baseDelay * jitter);
232
+ setTimeout(() => {
233
+ if (!this.stopped)
234
+ void this.connect();
235
+ }, delay);
236
+ }
237
+ }
238
+ exports.SseClient = SseClient;
239
+ function drainSseEvents(buffer) {
240
+ const events = [];
241
+ let cursor = 0;
242
+ while (true) {
243
+ const next = buffer.indexOf('\n\n', cursor);
244
+ if (next === -1)
245
+ break;
246
+ const block = buffer.slice(cursor, next);
247
+ cursor = next + 2;
248
+ const evt = {};
249
+ for (const line of block.split('\n')) {
250
+ if (!line || line.startsWith(':'))
251
+ continue;
252
+ const colon = line.indexOf(':');
253
+ const field = colon === -1 ? line : line.slice(0, colon);
254
+ const value = colon === -1
255
+ ? ''
256
+ : line[colon + 1] === ' '
257
+ ? line.slice(colon + 2)
258
+ : line.slice(colon + 1);
259
+ if (field === 'id')
260
+ evt.id = value;
261
+ else if (field === 'event')
262
+ evt.event = value;
263
+ else if (field === 'data') {
264
+ evt.data = evt.data === undefined ? value : `${evt.data}\n${value}`;
265
+ }
266
+ }
267
+ events.push(evt);
268
+ }
269
+ return { parsed: events, remainder: buffer.slice(cursor) };
270
+ }
271
+ //# sourceMappingURL=sse-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-client.js","sourceRoot":"","sources":["../../src/lib/sse-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface EventScopeOptions {
2
+ scope: 'project' | 'session';
3
+ id: string;
4
+ }
5
+ export declare function useEventScope(options: EventScopeOptions): void;
6
+ //# sourceMappingURL=use-event-scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-event-scope.d.ts","sourceRoot":"","sources":["../../src/lib/use-event-scope.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,EAAE,EAAE,MAAM,CAAC;CACZ;AAUD,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CA4C9D"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useEventScope = useEventScope;
4
+ const react_1 = require("react");
5
+ const realtime_context_1 = require("./realtime-context");
6
+ function useEventScope(options) {
7
+ const ctx = (0, realtime_context_1.useRealtimeContext)();
8
+ const ctxRef = (0, react_1.useRef)(ctx);
9
+ ctxRef.current = ctx;
10
+ (0, react_1.useEffect)(() => {
11
+ let cancelled = false;
12
+ let subscribedScope = null;
13
+ void (async () => {
14
+ const start = Date.now();
15
+ while (Date.now() - start < 5_000) {
16
+ if (cancelled)
17
+ return;
18
+ const cid = ctxRef.current.state?.connectionId;
19
+ if (cid) {
20
+ const scope = { kind: options.scope, id: options.id };
21
+ await ctxRef.current.subscribeToScope(cid, scope);
22
+ if (cancelled) {
23
+ ctxRef.current.unsubscribeFromScope(scope);
24
+ return;
25
+ }
26
+ subscribedScope = scope;
27
+ return;
28
+ }
29
+ await new Promise((r) => setTimeout(r, 100));
30
+ }
31
+ })();
32
+ return () => {
33
+ cancelled = true;
34
+ if (subscribedScope) {
35
+ ctxRef.current.unsubscribeFromScope(subscribedScope);
36
+ subscribedScope = null;
37
+ }
38
+ };
39
+ }, [options.scope, options.id]);
40
+ }
41
+ //# sourceMappingURL=use-event-scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-event-scope.js","sourceRoot":"","sources":["../../src/lib/use-event-scope.tsx"],"names":[],"mappings":";;AAiBA,sCA4CC;AA7DD,iCAA0C;AAE1C,yDAAwD;AAexD,SAAgB,aAAa,CAAC,OAA0B;IACtD,MAAM,GAAG,GAAG,IAAA,qCAAkB,GAAE,CAAC;IAMjC,MAAM,MAAM,GAAG,IAAA,cAAM,EAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC;IAErB,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,IAAI,eAAe,GAAuD,IAAI,CAAC;QAC/E,KAAK,CAAC,KAAK,IAAI,EAAE;YAIf,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,KAAK,EAAE,CAAC;gBAClC,IAAI,SAAS;oBAAE,OAAO;gBACtB,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,YAAY,CAAC;gBAC/C,IAAI,GAAG,EAAE,CAAC;oBACR,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC;oBACtD,MAAM,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;oBAClD,IAAI,SAAS,EAAE,CAAC;wBAGd,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;wBAC3C,OAAO;oBACT,CAAC;oBACD,eAAe,GAAG,KAAK,CAAC;oBACxB,OAAO;gBACT,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;YACjB,IAAI,eAAe,EAAE,CAAC;gBACpB,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC;gBACrD,eAAe,GAAG,IAAI,CAAC;YACzB,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AAClC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@xemahq/realtime-client",
3
+ "version": "0.1.1",
4
+ "publishConfig": {
5
+ "registry": "https://npm.pkg.github.com"
6
+ },
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "peerDependencies": {
13
+ "@tanstack/react-query": ">=5",
14
+ "react": "^18.3.1"
15
+ },
16
+ "dependencies": {
17
+ "@xemahq/events": "^0.1.1"
18
+ },
19
+ "devDependencies": {
20
+ "@tanstack/react-query": "^5.100.13",
21
+ "@types/jest": "^30.0.0",
22
+ "@types/node": "25.2.3",
23
+ "@types/react": "^18.3.30",
24
+ "jest": "^30.3.0",
25
+ "prettier": "3.6.2",
26
+ "react": "^19.0.0",
27
+ "ts-jest": "^29.4.9",
28
+ "typescript": "5.9.3"
29
+ },
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "xema-source": "./src/index.ts",
34
+ "default": "./dist/index.js"
35
+ },
36
+ "./dist/lib/*": {
37
+ "types": "./dist/lib/*.d.ts",
38
+ "default": "./dist/lib/*.js"
39
+ }
40
+ },
41
+ "scripts": {
42
+ "clean": "rm -rf dist",
43
+ "build": "tsc -p tsconfig.json",
44
+ "format": "prettier --write \"src/**/*.ts\"",
45
+ "typecheck": "tsc -p tsconfig.json --noEmit",
46
+ "test": "jest --config jest.config.ts"
47
+ }
48
+ }