@parcae/sdk 0.4.0 → 0.4.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.
@@ -0,0 +1,866 @@
1
+ import SocketIO from 'socket.io-client';
2
+ import pako from 'pako';
3
+ import { decompress } from 'compress-json';
4
+ import { EventEmitter } from 'eventemitter3';
5
+ import ShortId from 'short-unique-id';
6
+ import { Model, FrontendAdapter } from '@parcae/model';
7
+
8
+ // src/log.ts
9
+ var isDev = typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true;
10
+ function time() {
11
+ const d = /* @__PURE__ */ new Date();
12
+ return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}:${String(d.getSeconds()).padStart(2, "0")}`;
13
+ }
14
+ var log = {
15
+ info: (...args) => isDev && console.log(`%c${time()} SDK`, "color: #6b7", ...args),
16
+ warn: (...args) => isDev && console.warn(`%c${time()} SDK`, "color: #fb3", ...args),
17
+ error: (...args) => console.error(`%c${time()} SDK`, "color: #f44", ...args),
18
+ debug: (...args) => isDev && console.debug(`%c${time()} SDK`, "color: #888", ...args)
19
+ };
20
+
21
+ // ../../node_modules/.pnpm/proxy-compare@3.0.1/node_modules/proxy-compare/dist/index.js
22
+ var TRACK_MEMO_SYMBOL = /* @__PURE__ */ Symbol();
23
+ var GET_ORIGINAL_SYMBOL = /* @__PURE__ */ Symbol();
24
+ var AFFECTED_PROPERTY = "a";
25
+ var IS_TARGET_COPIED_PROPERTY = "f";
26
+ var PROXY_PROPERTY = "p";
27
+ var PROXY_CACHE_PROPERTY = "c";
28
+ var TARGET_CACHE_PROPERTY = "t";
29
+ var HAS_KEY_PROPERTY = "h";
30
+ var ALL_OWN_KEYS_PROPERTY = "w";
31
+ var HAS_OWN_KEY_PROPERTY = "o";
32
+ var KEYS_PROPERTY = "k";
33
+ var newProxy = (target, handler) => new Proxy(target, handler);
34
+ var getProto = Object.getPrototypeOf;
35
+ var objectsToTrack = /* @__PURE__ */ new WeakMap();
36
+ var isObjectToTrack = (obj) => obj && (objectsToTrack.has(obj) ? objectsToTrack.get(obj) : getProto(obj) === Object.prototype || getProto(obj) === Array.prototype);
37
+ var isObject = (x) => typeof x === "object" && x !== null;
38
+ var needsToCopyTargetObject = (obj) => Object.values(Object.getOwnPropertyDescriptors(obj)).some((descriptor) => !descriptor.configurable && !descriptor.writable);
39
+ var copyTargetObject = (obj) => {
40
+ if (Array.isArray(obj)) {
41
+ return Array.from(obj);
42
+ }
43
+ const descriptors = Object.getOwnPropertyDescriptors(obj);
44
+ Object.values(descriptors).forEach((desc) => {
45
+ desc.configurable = true;
46
+ });
47
+ return Object.create(getProto(obj), descriptors);
48
+ };
49
+ var createProxyHandler = (origObj, isTargetCopied) => {
50
+ const state = {
51
+ [IS_TARGET_COPIED_PROPERTY]: isTargetCopied
52
+ };
53
+ let trackObject = false;
54
+ const recordUsage = (type, key) => {
55
+ if (!trackObject) {
56
+ let used = state[AFFECTED_PROPERTY].get(origObj);
57
+ if (!used) {
58
+ used = {};
59
+ state[AFFECTED_PROPERTY].set(origObj, used);
60
+ }
61
+ if (type === ALL_OWN_KEYS_PROPERTY) {
62
+ used[ALL_OWN_KEYS_PROPERTY] = true;
63
+ } else {
64
+ let set = used[type];
65
+ if (!set) {
66
+ set = /* @__PURE__ */ new Set();
67
+ used[type] = set;
68
+ }
69
+ set.add(key);
70
+ }
71
+ }
72
+ };
73
+ const recordObjectAsUsed = () => {
74
+ trackObject = true;
75
+ state[AFFECTED_PROPERTY].delete(origObj);
76
+ };
77
+ const handler = {
78
+ get(target, key) {
79
+ if (key === GET_ORIGINAL_SYMBOL) {
80
+ return origObj;
81
+ }
82
+ recordUsage(KEYS_PROPERTY, key);
83
+ return createProxy(Reflect.get(target, key), state[AFFECTED_PROPERTY], state[PROXY_CACHE_PROPERTY], state[TARGET_CACHE_PROPERTY]);
84
+ },
85
+ has(target, key) {
86
+ if (key === TRACK_MEMO_SYMBOL) {
87
+ recordObjectAsUsed();
88
+ return true;
89
+ }
90
+ recordUsage(HAS_KEY_PROPERTY, key);
91
+ return Reflect.has(target, key);
92
+ },
93
+ getOwnPropertyDescriptor(target, key) {
94
+ recordUsage(HAS_OWN_KEY_PROPERTY, key);
95
+ return Reflect.getOwnPropertyDescriptor(target, key);
96
+ },
97
+ ownKeys(target) {
98
+ recordUsage(ALL_OWN_KEYS_PROPERTY);
99
+ return Reflect.ownKeys(target);
100
+ }
101
+ };
102
+ if (isTargetCopied) {
103
+ handler.set = handler.deleteProperty = () => false;
104
+ }
105
+ return [handler, state];
106
+ };
107
+ var getOriginalObject = (obj) => (
108
+ // unwrap proxy
109
+ obj[GET_ORIGINAL_SYMBOL] || // otherwise
110
+ obj
111
+ );
112
+ var createProxy = (obj, affected, proxyCache2, targetCache) => {
113
+ if (!isObjectToTrack(obj))
114
+ return obj;
115
+ let targetAndCopied = targetCache && targetCache.get(obj);
116
+ if (!targetAndCopied) {
117
+ const target2 = getOriginalObject(obj);
118
+ if (needsToCopyTargetObject(target2)) {
119
+ targetAndCopied = [target2, copyTargetObject(target2)];
120
+ } else {
121
+ targetAndCopied = [target2];
122
+ }
123
+ targetCache === null || targetCache === void 0 ? void 0 : targetCache.set(obj, targetAndCopied);
124
+ }
125
+ const [target, copiedTarget] = targetAndCopied;
126
+ let handlerAndState = proxyCache2 && proxyCache2.get(target);
127
+ if (!handlerAndState || handlerAndState[1][IS_TARGET_COPIED_PROPERTY] !== !!copiedTarget) {
128
+ handlerAndState = createProxyHandler(target, !!copiedTarget);
129
+ handlerAndState[1][PROXY_PROPERTY] = newProxy(copiedTarget || target, handlerAndState[0]);
130
+ if (proxyCache2) {
131
+ proxyCache2.set(target, handlerAndState);
132
+ }
133
+ }
134
+ handlerAndState[1][AFFECTED_PROPERTY] = affected;
135
+ handlerAndState[1][PROXY_CACHE_PROPERTY] = proxyCache2;
136
+ handlerAndState[1][TARGET_CACHE_PROPERTY] = targetCache;
137
+ return handlerAndState[1][PROXY_PROPERTY];
138
+ };
139
+ var isAllOwnKeysChanged = (prevObj, nextObj) => {
140
+ const prevKeys = Reflect.ownKeys(prevObj);
141
+ const nextKeys = Reflect.ownKeys(nextObj);
142
+ return prevKeys.length !== nextKeys.length || prevKeys.some((k, i) => k !== nextKeys[i]);
143
+ };
144
+ var isChanged = (prevObj, nextObj, affected, cache, isEqual = Object.is) => {
145
+ if (isEqual(prevObj, nextObj)) {
146
+ return false;
147
+ }
148
+ if (!isObject(prevObj) || !isObject(nextObj))
149
+ return true;
150
+ const used = affected.get(getOriginalObject(prevObj));
151
+ if (!used)
152
+ return true;
153
+ if (cache) {
154
+ const hit = cache.get(prevObj);
155
+ if (hit === nextObj) {
156
+ return false;
157
+ }
158
+ cache.set(prevObj, nextObj);
159
+ }
160
+ let changed = null;
161
+ for (const key of used[HAS_KEY_PROPERTY] || []) {
162
+ changed = Reflect.has(prevObj, key) !== Reflect.has(nextObj, key);
163
+ if (changed)
164
+ return changed;
165
+ }
166
+ if (used[ALL_OWN_KEYS_PROPERTY] === true) {
167
+ changed = isAllOwnKeysChanged(prevObj, nextObj);
168
+ if (changed)
169
+ return changed;
170
+ } else {
171
+ for (const key of used[HAS_OWN_KEY_PROPERTY] || []) {
172
+ const hasPrev = !!Reflect.getOwnPropertyDescriptor(prevObj, key);
173
+ const hasNext = !!Reflect.getOwnPropertyDescriptor(nextObj, key);
174
+ changed = hasPrev !== hasNext;
175
+ if (changed)
176
+ return changed;
177
+ }
178
+ }
179
+ for (const key of used[KEYS_PROPERTY] || []) {
180
+ changed = isChanged(prevObj[key], nextObj[key], affected, cache, isEqual);
181
+ if (changed)
182
+ return changed;
183
+ }
184
+ if (changed === null)
185
+ throw new Error("invalid used");
186
+ return changed;
187
+ };
188
+ var getUntracked = (obj) => {
189
+ if (isObjectToTrack(obj)) {
190
+ return obj[GET_ORIGINAL_SYMBOL] || null;
191
+ }
192
+ return null;
193
+ };
194
+ var markToTrack = (obj, mark = true) => {
195
+ objectsToTrack.set(obj, mark);
196
+ };
197
+ var affectedToPathList = (obj, affected, onlyWithValues) => {
198
+ const list = [];
199
+ const seen = /* @__PURE__ */ new WeakSet();
200
+ const walk = (x, path) => {
201
+ var _a, _b, _c;
202
+ if (seen.has(x)) {
203
+ return;
204
+ }
205
+ if (isObject(x)) {
206
+ seen.add(x);
207
+ }
208
+ const used = isObject(x) && affected.get(getOriginalObject(x));
209
+ if (used) {
210
+ (_a = used[HAS_KEY_PROPERTY]) === null || _a === void 0 ? void 0 : _a.forEach((key) => {
211
+ const segment = `:has(${String(key)})`;
212
+ list.push(path ? [...path, segment] : [segment]);
213
+ });
214
+ if (used[ALL_OWN_KEYS_PROPERTY] === true) {
215
+ const segment = ":ownKeys";
216
+ list.push(path ? [...path, segment] : [segment]);
217
+ } else {
218
+ (_b = used[HAS_OWN_KEY_PROPERTY]) === null || _b === void 0 ? void 0 : _b.forEach((key) => {
219
+ const segment = `:hasOwn(${String(key)})`;
220
+ list.push(path ? [...path, segment] : [segment]);
221
+ });
222
+ }
223
+ (_c = used[KEYS_PROPERTY]) === null || _c === void 0 ? void 0 : _c.forEach((key) => {
224
+ if (!onlyWithValues || "value" in (Object.getOwnPropertyDescriptor(x, key) || {})) {
225
+ walk(x[key], path ? [...path, key] : [key]);
226
+ }
227
+ });
228
+ } else if (path) {
229
+ list.push(path);
230
+ }
231
+ };
232
+ walk(obj);
233
+ return list;
234
+ };
235
+
236
+ // ../../node_modules/.pnpm/valtio@2.3.1_@types+react@19.2.14_react@19.2.4/node_modules/valtio/esm/vanilla.mjs
237
+ var isObject2 = (x) => typeof x === "object" && x !== null;
238
+ var canProxyDefault = (x) => isObject2(x) && !refSet.has(x) && (Array.isArray(x) || !(Symbol.iterator in x)) && !(x instanceof WeakMap) && !(x instanceof WeakSet) && !(x instanceof Error) && !(x instanceof Number) && !(x instanceof Date) && !(x instanceof String) && !(x instanceof RegExp) && !(x instanceof ArrayBuffer) && !(x instanceof Promise);
239
+ var createSnapshotDefault = (target, version) => {
240
+ const cache = snapCache.get(target);
241
+ if ((cache == null ? void 0 : cache[0]) === version) {
242
+ return cache[1];
243
+ }
244
+ const snap = Array.isArray(target) ? [] : Object.create(Object.getPrototypeOf(target));
245
+ markToTrack(snap, true);
246
+ snapCache.set(target, [version, snap]);
247
+ Reflect.ownKeys(target).forEach((key) => {
248
+ if (Object.getOwnPropertyDescriptor(snap, key)) {
249
+ return;
250
+ }
251
+ const value = Reflect.get(target, key);
252
+ const { enumerable } = Reflect.getOwnPropertyDescriptor(
253
+ target,
254
+ key
255
+ );
256
+ const desc = {
257
+ value,
258
+ enumerable,
259
+ // This is intentional to avoid copying with proxy-compare.
260
+ // It's still non-writable, so it avoids assigning a value.
261
+ configurable: true
262
+ };
263
+ if (refSet.has(value)) {
264
+ markToTrack(value, false);
265
+ } else if (proxyStateMap.has(value)) {
266
+ const [target2, ensureVersion] = proxyStateMap.get(
267
+ value
268
+ );
269
+ desc.value = createSnapshotDefault(target2, ensureVersion());
270
+ }
271
+ Object.defineProperty(snap, key, desc);
272
+ });
273
+ return Object.preventExtensions(snap);
274
+ };
275
+ var createHandlerDefault = (isInitializing, addPropListener, removePropListener, notifyUpdate) => ({
276
+ deleteProperty(target, prop) {
277
+ Reflect.get(target, prop);
278
+ removePropListener(prop);
279
+ const deleted = Reflect.deleteProperty(target, prop);
280
+ if (deleted) {
281
+ notifyUpdate(void 0 );
282
+ }
283
+ return deleted;
284
+ },
285
+ set(target, prop, value, receiver) {
286
+ const hasPrevValue = !isInitializing() && Reflect.has(target, prop);
287
+ const prevValue = Reflect.get(target, prop, receiver);
288
+ if (hasPrevValue && (objectIs(prevValue, value) || proxyCache.has(value) && objectIs(prevValue, proxyCache.get(value)))) {
289
+ return true;
290
+ }
291
+ removePropListener(prop);
292
+ if (isObject2(value)) {
293
+ value = getUntracked(value) || value;
294
+ }
295
+ const nextValue = !proxyStateMap.has(value) && canProxy(value) ? proxy(value) : value;
296
+ addPropListener(prop, nextValue);
297
+ Reflect.set(target, prop, nextValue, receiver);
298
+ notifyUpdate(void 0 );
299
+ return true;
300
+ }
301
+ });
302
+ var proxyStateMap = /* @__PURE__ */ new WeakMap();
303
+ var refSet = /* @__PURE__ */ new WeakSet();
304
+ var snapCache = /* @__PURE__ */ new WeakMap();
305
+ var versionHolder = [1];
306
+ var proxyCache = /* @__PURE__ */ new WeakMap();
307
+ var objectIs = Object.is;
308
+ var newProxy2 = (target, handler) => new Proxy(target, handler);
309
+ var canProxy = canProxyDefault;
310
+ var createSnapshot = createSnapshotDefault;
311
+ var createHandler = createHandlerDefault;
312
+ function proxy(baseObject = {}) {
313
+ if (!isObject2(baseObject)) {
314
+ throw new Error("object required");
315
+ }
316
+ const found = proxyCache.get(baseObject);
317
+ if (found) {
318
+ return found;
319
+ }
320
+ let version = versionHolder[0];
321
+ const listeners = /* @__PURE__ */ new Set();
322
+ const notifyUpdate = (op, nextVersion = ++versionHolder[0]) => {
323
+ if (version !== nextVersion) {
324
+ checkVersion = version = nextVersion;
325
+ listeners.forEach((listener) => listener(op, nextVersion));
326
+ }
327
+ };
328
+ let checkVersion = version;
329
+ const ensureVersion = (nextCheckVersion = versionHolder[0]) => {
330
+ if (checkVersion !== nextCheckVersion) {
331
+ checkVersion = nextCheckVersion;
332
+ propProxyStates.forEach(([propProxyState]) => {
333
+ const propVersion = propProxyState[1](nextCheckVersion);
334
+ if (propVersion > version) {
335
+ version = propVersion;
336
+ }
337
+ });
338
+ }
339
+ return version;
340
+ };
341
+ const createPropListener = (prop) => (op, nextVersion) => {
342
+ let newOp;
343
+ if (op) {
344
+ newOp = [...op];
345
+ newOp[1] = [prop, ...newOp[1]];
346
+ }
347
+ notifyUpdate(newOp, nextVersion);
348
+ };
349
+ const propProxyStates = /* @__PURE__ */ new Map();
350
+ const addPropListener = (prop, propValue) => {
351
+ const propProxyState = !refSet.has(propValue) && proxyStateMap.get(propValue);
352
+ if (propProxyState) {
353
+ if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && propProxyStates.has(prop)) {
354
+ throw new Error("prop listener already exists");
355
+ }
356
+ if (listeners.size) {
357
+ const remove = propProxyState[2](createPropListener(prop));
358
+ propProxyStates.set(prop, [propProxyState, remove]);
359
+ } else {
360
+ propProxyStates.set(prop, [propProxyState]);
361
+ }
362
+ }
363
+ };
364
+ const removePropListener = (prop) => {
365
+ var _a;
366
+ const entry = propProxyStates.get(prop);
367
+ if (entry) {
368
+ propProxyStates.delete(prop);
369
+ (_a = entry[1]) == null ? void 0 : _a.call(entry);
370
+ }
371
+ };
372
+ const addListener = (listener) => {
373
+ listeners.add(listener);
374
+ if (listeners.size === 1) {
375
+ propProxyStates.forEach(([propProxyState, prevRemove], prop) => {
376
+ if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && prevRemove) {
377
+ throw new Error("remove already exists");
378
+ }
379
+ const remove = propProxyState[2](createPropListener(prop));
380
+ propProxyStates.set(prop, [propProxyState, remove]);
381
+ });
382
+ }
383
+ const removeListener = () => {
384
+ listeners.delete(listener);
385
+ if (listeners.size === 0) {
386
+ propProxyStates.forEach(([propProxyState, remove], prop) => {
387
+ if (remove) {
388
+ remove();
389
+ propProxyStates.set(prop, [propProxyState]);
390
+ }
391
+ });
392
+ }
393
+ };
394
+ return removeListener;
395
+ };
396
+ let initializing = true;
397
+ const handler = createHandler(
398
+ () => initializing,
399
+ addPropListener,
400
+ removePropListener,
401
+ notifyUpdate
402
+ );
403
+ const proxyObject = newProxy2(baseObject, handler);
404
+ proxyCache.set(baseObject, proxyObject);
405
+ const proxyState = [baseObject, ensureVersion, addListener];
406
+ proxyStateMap.set(proxyObject, proxyState);
407
+ Reflect.ownKeys(baseObject).forEach((key) => {
408
+ const desc = Object.getOwnPropertyDescriptor(
409
+ baseObject,
410
+ key
411
+ );
412
+ if ("value" in desc && desc.writable) {
413
+ proxyObject[key] = baseObject[key];
414
+ }
415
+ });
416
+ initializing = false;
417
+ return proxyObject;
418
+ }
419
+ function subscribe(proxyObject, callback, notifyInSync) {
420
+ const proxyState = proxyStateMap.get(proxyObject);
421
+ if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !proxyState) {
422
+ console.warn("Please use proxy object");
423
+ }
424
+ let promise;
425
+ const ops = [];
426
+ const addListener = proxyState[2];
427
+ let isListenerActive = false;
428
+ const listener = (op) => {
429
+ if (op) {
430
+ ops.push(op);
431
+ }
432
+ if (notifyInSync) {
433
+ callback(ops.splice(0));
434
+ return;
435
+ }
436
+ if (!promise) {
437
+ promise = Promise.resolve().then(() => {
438
+ promise = void 0;
439
+ if (isListenerActive) {
440
+ callback(ops.splice(0));
441
+ }
442
+ });
443
+ }
444
+ };
445
+ const removeListener = addListener(listener);
446
+ isListenerActive = true;
447
+ return () => {
448
+ isListenerActive = false;
449
+ removeListener();
450
+ };
451
+ }
452
+ function snapshot(proxyObject) {
453
+ const proxyState = proxyStateMap.get(proxyObject);
454
+ if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !proxyState) {
455
+ console.warn("Please use proxy object");
456
+ }
457
+ const [target, ensureVersion] = proxyState;
458
+ return createSnapshot(target, ensureVersion());
459
+ }
460
+
461
+ // src/auth-gate.ts
462
+ var AuthGate = class {
463
+ /** Reactive state — subscribe with valtio useSnapshot() */
464
+ state = proxy({
465
+ status: "pending",
466
+ userId: null,
467
+ version: 0
468
+ });
469
+ /** Awaitable — resolves when auth is confirmed (either way) */
470
+ ready;
471
+ _resolve = null;
472
+ constructor() {
473
+ this.ready = this._makePending();
474
+ }
475
+ /** Auth confirmed — user is authenticated */
476
+ resolve(userId) {
477
+ this.state.status = "authenticated";
478
+ log.info("auth: authenticated, userId:", userId);
479
+ this.state.userId = userId;
480
+ this.state.version++;
481
+ this._resolve?.();
482
+ this._resolve = null;
483
+ }
484
+ /** Auth confirmed — no user */
485
+ resolveUnauthenticated() {
486
+ this.state.status = "unauthenticated";
487
+ log.info("auth: unauthenticated");
488
+ this.state.userId = null;
489
+ this.state.version++;
490
+ this._resolve?.();
491
+ this._resolve = null;
492
+ }
493
+ /** Reset to pending (disconnect, token change) */
494
+ reset() {
495
+ if (this.state.status !== "pending") {
496
+ this.state.status = "pending";
497
+ log.info("auth: reset to pending");
498
+ this.state.userId = null;
499
+ this.ready = this._makePending();
500
+ }
501
+ }
502
+ _makePending() {
503
+ return new Promise((r) => {
504
+ this._resolve = r;
505
+ });
506
+ }
507
+ };
508
+ var uid = new ShortId({ length: 10 });
509
+ var SOCKETS = /* @__PURE__ */ new Map();
510
+ var SocketTransport = class extends EventEmitter {
511
+ auth = new AuthGate();
512
+ isConnected = false;
513
+ socket;
514
+ url;
515
+ version;
516
+ token;
517
+ inflight = /* @__PURE__ */ new Map();
518
+ constructor(config) {
519
+ super();
520
+ this.url = config.url;
521
+ this.version = config.version ?? "v1";
522
+ this.token = config.token;
523
+ const socketPath = config.path ?? "/ws";
524
+ const socketKey = `${this.url}:${socketPath}`;
525
+ if (SOCKETS.has(socketKey)) {
526
+ this.socket = SOCKETS.get(socketKey);
527
+ } else {
528
+ this.socket = SocketIO(this.url, {
529
+ path: socketPath,
530
+ transports: ["websocket"],
531
+ withCredentials: true
532
+ });
533
+ SOCKETS.set(socketKey, this.socket);
534
+ }
535
+ this.socket.on("connect", () => {
536
+ this.isConnected = true;
537
+ log.info("socket connected");
538
+ this._doAuth();
539
+ this.emit("connected");
540
+ });
541
+ this.socket.on("disconnect", () => {
542
+ this.isConnected = false;
543
+ log.info("socket disconnected");
544
+ this.auth.reset();
545
+ this.emit("disconnected");
546
+ });
547
+ this.socket.on("error", (err) => this.emit("error", err));
548
+ if (this.socket.connected) {
549
+ this.isConnected = true;
550
+ log.info("socket connected");
551
+ this._doAuth();
552
+ }
553
+ if (this.token === null) {
554
+ this.auth.resolveUnauthenticated();
555
+ }
556
+ }
557
+ _doAuth() {
558
+ if (this.token === void 0) return;
559
+ if (this.token === null) {
560
+ this.auth.resolveUnauthenticated();
561
+ return;
562
+ }
563
+ log.info("authenticating with token", this.token?.slice(0, 8) + "...");
564
+ this.socket.emit("authenticate", this.token, (response) => {
565
+ const userId = response?.userId ?? null;
566
+ if (userId) {
567
+ this.auth.resolve(userId);
568
+ } else {
569
+ this.auth.resolveUnauthenticated();
570
+ }
571
+ });
572
+ }
573
+ async authenticate(token) {
574
+ this.token = token;
575
+ this.auth.reset();
576
+ if (token === null) {
577
+ this.auth.resolveUnauthenticated();
578
+ return { userId: null };
579
+ }
580
+ if (!this.socket.connected) {
581
+ return new Promise((resolve) => {
582
+ const handler = () => {
583
+ this.socket.off("connect", handler);
584
+ this.socket.emit("authenticate", token, (response) => {
585
+ const userId = response?.userId ?? null;
586
+ if (userId) this.auth.resolve(userId);
587
+ else this.auth.resolveUnauthenticated();
588
+ resolve({ userId });
589
+ });
590
+ };
591
+ this.socket.once("connect", handler);
592
+ });
593
+ }
594
+ return new Promise((resolve) => {
595
+ this.socket.emit("authenticate", token, (response) => {
596
+ const userId = response?.userId ?? null;
597
+ if (userId) this.auth.resolve(userId);
598
+ else this.auth.resolveUnauthenticated();
599
+ resolve({ userId });
600
+ });
601
+ });
602
+ }
603
+ // ── Request/Response ──────────────────────────────────────────────
604
+ async fetch(method, path, data = {}) {
605
+ await this.auth.ready;
606
+ if (!this.socket.connected) {
607
+ await new Promise((resolve, reject) => {
608
+ if (this.socket.connected) return resolve();
609
+ const timeout = setTimeout(() => {
610
+ cleanup();
611
+ reject(new Error("Connection timeout"));
612
+ }, 3e4);
613
+ const onConnect = () => {
614
+ cleanup();
615
+ resolve();
616
+ };
617
+ const onError = (err) => {
618
+ cleanup();
619
+ reject(err);
620
+ };
621
+ const cleanup = () => {
622
+ clearTimeout(timeout);
623
+ this.socket.off("connect", onConnect);
624
+ this.socket.off("connect_error", onError);
625
+ };
626
+ this.socket.once("connect", onConnect);
627
+ this.socket.once("connect_error", onError);
628
+ });
629
+ }
630
+ const upper = method.toUpperCase();
631
+ if (upper === "GET") {
632
+ const dedupeKey = `${path}:${JSON.stringify(data)}`;
633
+ const existing = this.inflight.get(dedupeKey);
634
+ if (existing) return existing;
635
+ const req = this._call(method, path, data);
636
+ this.inflight.set(dedupeKey, req);
637
+ req.finally(() => this.inflight.delete(dedupeKey));
638
+ return req;
639
+ }
640
+ return this._call(method, path, data);
641
+ }
642
+ _call(method, path, data) {
643
+ const id = uid.rnd();
644
+ return new Promise((resolve, reject) => {
645
+ const timeout = setTimeout(() => {
646
+ this.socket.off(id);
647
+ reject(new Error(`RPC timeout: ${method} ${path}`));
648
+ }, 3e4);
649
+ this.socket.once(id, (msg) => {
650
+ clearTimeout(timeout);
651
+ try {
652
+ const uncompressed = pako.ungzip(msg, { to: "string" });
653
+ const parsed = decompress(JSON.parse(uncompressed));
654
+ if (parsed.success) resolve(parsed.result);
655
+ else
656
+ reject(
657
+ new Error(
658
+ parsed.message || parsed.error || `${method} ${path} failed`
659
+ )
660
+ );
661
+ } catch (err) {
662
+ reject(err);
663
+ }
664
+ });
665
+ this.socket.emit(
666
+ "call",
667
+ id,
668
+ method.toUpperCase(),
669
+ `/${this.version}${path}`,
670
+ data
671
+ );
672
+ });
673
+ }
674
+ async get(path, data) {
675
+ return this.fetch("GET", path, data);
676
+ }
677
+ async post(path, data) {
678
+ return this.fetch("POST", path, data);
679
+ }
680
+ async put(path, data) {
681
+ return this.fetch("PUT", path, data);
682
+ }
683
+ async patch(path, data) {
684
+ return this.fetch("PATCH", path, data);
685
+ }
686
+ async delete(path, data) {
687
+ return this.fetch("DELETE", path, data);
688
+ }
689
+ subscribe(event, handler) {
690
+ this.socket.on(event, handler);
691
+ return () => this.socket.off(event, handler);
692
+ }
693
+ unsubscribe(event, handler) {
694
+ this.socket.off(event, handler);
695
+ }
696
+ async send(event, ...args) {
697
+ await this.auth.ready;
698
+ this.socket.emit(event, ...args);
699
+ }
700
+ disconnect() {
701
+ this.socket.disconnect();
702
+ this.isConnected = false;
703
+ log.info("socket disconnected");
704
+ }
705
+ async reconnect() {
706
+ this.socket.connect();
707
+ }
708
+ };
709
+ var SSETransport = class extends EventEmitter {
710
+ url;
711
+ version;
712
+ apiKey;
713
+ key = null;
714
+ eventSources = /* @__PURE__ */ new Map();
715
+ isConnected = true;
716
+ // HTTP is "always connected"
717
+ isLoading = true;
718
+ loading;
719
+ constructor(config) {
720
+ super();
721
+ this.url = config.url.replace(/\/$/, "");
722
+ this.version = config.version ?? "v1";
723
+ this.apiKey = config.key ?? null;
724
+ this.loading = this.resolveKey();
725
+ }
726
+ async resolveKey() {
727
+ try {
728
+ this.key = typeof this.apiKey === "function" ? await this.apiKey() : this.apiKey;
729
+ this.isLoading = false;
730
+ this.emit("connected");
731
+ } catch (err) {
732
+ this.isLoading = false;
733
+ this.emit("error", err);
734
+ }
735
+ }
736
+ headers() {
737
+ const h = { "Content-Type": "application/json" };
738
+ if (this.key) h["Authorization"] = `Bearer ${this.key}`;
739
+ return h;
740
+ }
741
+ fullUrl(path) {
742
+ return `${this.url}/${this.version}${path}`;
743
+ }
744
+ // ── Request/Response ──────────────────────────────────────────────────
745
+ async request(method, path, data) {
746
+ await this.loading;
747
+ const isGet = method.toUpperCase() === "GET";
748
+ let url = this.fullUrl(path);
749
+ if (isGet && data) {
750
+ const params = new URLSearchParams();
751
+ for (const [k, v] of Object.entries(data)) {
752
+ params.set(k, typeof v === "object" ? JSON.stringify(v) : String(v));
753
+ }
754
+ url += `?${params.toString()}`;
755
+ }
756
+ const res = await fetch(url, {
757
+ method: method.toUpperCase(),
758
+ headers: this.headers(),
759
+ body: isGet ? void 0 : JSON.stringify(data)
760
+ });
761
+ if (!res.ok) {
762
+ const body2 = await res.json().catch(() => ({ error: res.statusText }));
763
+ throw new Error(body2.error || body2.message || `HTTP ${res.status}`);
764
+ }
765
+ const body = await res.json();
766
+ if (body.success === false) throw new Error(body.error || "Request failed");
767
+ return body.result ?? body;
768
+ }
769
+ async get(path, data) {
770
+ return this.request("GET", path, data);
771
+ }
772
+ async post(path, data) {
773
+ return this.request("POST", path, data);
774
+ }
775
+ async put(path, data) {
776
+ return this.request("PUT", path, data);
777
+ }
778
+ async patch(path, data) {
779
+ return this.request("PATCH", path, data);
780
+ }
781
+ async delete(path, data) {
782
+ return this.request("DELETE", path, data);
783
+ }
784
+ // ── Subscriptions (via Server-Sent Events) ────────────────────────────
785
+ subscribe(event, handler) {
786
+ const url = `${this.url}/${this.version}/__events/${encodeURIComponent(event)}`;
787
+ const source = new EventSource(url, { withCredentials: true });
788
+ source.onmessage = (e) => {
789
+ try {
790
+ const data = JSON.parse(e.data);
791
+ handler(data);
792
+ } catch {
793
+ handler(e.data);
794
+ }
795
+ };
796
+ source.onerror = () => {
797
+ };
798
+ this.eventSources.set(event, source);
799
+ return () => {
800
+ source.close();
801
+ this.eventSources.delete(event);
802
+ };
803
+ }
804
+ unsubscribe(event) {
805
+ const source = this.eventSources.get(event);
806
+ if (source) {
807
+ source.close();
808
+ this.eventSources.delete(event);
809
+ }
810
+ }
811
+ // ── Control messages ──────────────────────────────────────────────────
812
+ async send(event, ...args) {
813
+ await this.request("POST", "/__control", { event, args });
814
+ }
815
+ // ── Lifecycle ─────────────────────────────────────────────────────────
816
+ disconnect() {
817
+ for (const [, source] of this.eventSources) source.close();
818
+ this.eventSources.clear();
819
+ this.isConnected = false;
820
+ this.emit("disconnected");
821
+ }
822
+ async reconnect() {
823
+ this.loading = this.resolveKey();
824
+ await this.loading;
825
+ }
826
+ };
827
+ function createClient(config) {
828
+ const version = config.version ?? "v1";
829
+ let transport;
830
+ if (config.transport && typeof config.transport === "object") {
831
+ transport = config.transport;
832
+ } else if (config.transport === "sse") {
833
+ transport = new SSETransport({ url: config.url, version });
834
+ } else {
835
+ transport = new SocketTransport({
836
+ url: config.url,
837
+ version,
838
+ token: config.token
839
+ });
840
+ }
841
+ Model.use(new FrontendAdapter(transport));
842
+ return {
843
+ transport,
844
+ get: (p, d) => transport.get(p, d),
845
+ post: (p, d) => transport.post(p, d),
846
+ put: (p, d) => transport.put(p, d),
847
+ patch: (p, d) => transport.patch(p, d),
848
+ delete: (p, d) => transport.delete(p, d),
849
+ subscribe: (e, h) => transport.subscribe?.(e, h) ?? (() => {
850
+ }),
851
+ unsubscribe: (e, h) => transport.unsubscribe?.(e, h),
852
+ send: (e, ...a) => transport.send?.(e, ...a),
853
+ get isConnected() {
854
+ return transport.isConnected ?? false;
855
+ },
856
+ authenticate: (t) => transport.authenticate?.(t) ?? Promise.resolve({ userId: null }),
857
+ on: (e, h) => transport.on?.(e, h),
858
+ off: (e, h) => transport.off?.(e, h),
859
+ disconnect: () => transport.disconnect?.(),
860
+ reconnect: () => transport.reconnect?.() ?? Promise.resolve()
861
+ };
862
+ }
863
+
864
+ export { AuthGate, SSETransport, SocketTransport, affectedToPathList, createClient, createProxy, isChanged, log, snapshot, subscribe };
865
+ //# sourceMappingURL=chunk-LGUSPLZM.js.map
866
+ //# sourceMappingURL=chunk-LGUSPLZM.js.map