@liveblocks/core 1.1.8 → 1.2.0-comments1

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/dist/index.js CHANGED
@@ -1,6 +1,12 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/version.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/version.ts
2
8
  var PKG_NAME = "@liveblocks/core";
3
- var PKG_VERSION = "1.1.8";
9
+ var PKG_VERSION = "1.2.0-comments1";
4
10
  var PKG_FORMAT = "cjs";
5
11
 
6
12
  // src/dupe-detection.ts
@@ -46,6 +52,36 @@ function detectDupes(pkgName, pkgVersion, pkgFormat) {
46
52
  }
47
53
  }
48
54
 
55
+ // src/lib/assert.ts
56
+ function assertNever(_value, errmsg) {
57
+ throw new Error(errmsg);
58
+ }
59
+ function assert(condition, errmsg) {
60
+ if (process.env.NODE_ENV !== "production") {
61
+ if (!condition) {
62
+ const err = new Error(errmsg);
63
+ err.name = "Assertion failure";
64
+ throw err;
65
+ }
66
+ }
67
+ }
68
+ function nn(value, errmsg = "Expected value to be non-nullable") {
69
+ assert(value !== null && value !== void 0, errmsg);
70
+ return value;
71
+ }
72
+
73
+ // src/lib/controlledPromise.ts
74
+ function controlledPromise() {
75
+ let flagger;
76
+ const promise = new Promise((res) => {
77
+ flagger = res;
78
+ });
79
+ if (!flagger) {
80
+ throw new Error("Should never happen");
81
+ }
82
+ return [promise, flagger];
83
+ }
84
+
49
85
  // src/lib/EventSource.ts
50
86
  function makeEventSource() {
51
87
  const _onetimeObservers = /* @__PURE__ */ new Set();
@@ -119,185 +155,14 @@ function makeEventSource() {
119
155
  };
120
156
  }
121
157
 
122
- // src/devtools/bridge.ts
123
- var _bridgeActive = false;
124
- function activateBridge(allowed) {
125
- _bridgeActive = allowed;
126
- }
127
- function sendToPanel(message, options) {
128
- if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
129
- return;
130
- }
131
- const fullMsg = {
132
- ...message,
133
- source: "liveblocks-devtools-client"
134
- };
135
- if (!(_optionalChain([options, 'optionalAccess', _3 => _3.force]) || _bridgeActive)) {
136
- return;
137
- }
138
- window.postMessage(fullMsg, "*");
139
- }
140
- var eventSource = makeEventSource();
141
- if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
142
- window.addEventListener("message", (event) => {
143
- if (event.source === window && _optionalChain([event, 'access', _4 => _4.data, 'optionalAccess', _5 => _5.source]) === "liveblocks-devtools-panel") {
144
- eventSource.notify(event.data);
145
- } else {
146
- }
147
- });
148
- }
149
- var onMessageFromPanel = eventSource.observable;
150
-
151
- // src/devtools/index.ts
152
- var VERSION = PKG_VERSION || "dev";
153
- var _devtoolsSetupHasRun = false;
154
- function setupDevTools(getAllRooms) {
155
- if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
156
- return;
157
- }
158
- if (_devtoolsSetupHasRun) {
159
- return;
160
- }
161
- _devtoolsSetupHasRun = true;
162
- onMessageFromPanel.subscribe((msg) => {
163
- switch (msg.msg) {
164
- case "connect": {
165
- activateBridge(true);
166
- for (const roomId of getAllRooms()) {
167
- sendToPanel({
168
- msg: "room::available",
169
- roomId,
170
- clientVersion: VERSION
171
- });
172
- }
173
- break;
174
- }
175
- }
176
- });
177
- sendToPanel({ msg: "wake-up-devtools" }, { force: true });
178
- }
179
- var unsubsByRoomId = /* @__PURE__ */ new Map();
180
- function stopSyncStream(roomId) {
181
- const unsubs = _nullishCoalesce(unsubsByRoomId.get(roomId), () => ( []));
182
- unsubsByRoomId.delete(roomId);
183
- for (const unsub of unsubs) {
184
- unsub();
185
- }
186
- }
187
- function startSyncStream(room) {
188
- stopSyncStream(room.id);
189
- fullSync(room);
190
- unsubsByRoomId.set(room.id, [
191
- // When the connection status changes
192
- room.events.status.subscribe(() => partialSyncConnection(room)),
193
- // When storage initializes, send the update
194
- room.events.storageDidLoad.subscribeOnce(() => partialSyncStorage(room)),
195
- // Any time storage updates, send the new storage root
196
- room.events.storage.subscribe(() => partialSyncStorage(room)),
197
- // Any time "me" or "others" updates, send the new values accordingly
198
- room.events.self.subscribe(() => partialSyncMe(room)),
199
- room.events.others.subscribe(() => partialSyncOthers(room))
200
- ]);
201
- }
202
- function partialSyncConnection(room) {
203
- sendToPanel({
204
- msg: "room::sync::partial",
205
- roomId: room.id,
206
- status: room.getStatus()
207
- });
208
- }
209
- function partialSyncStorage(room) {
210
- const root = room.getStorageSnapshot();
211
- if (root) {
212
- sendToPanel({
213
- msg: "room::sync::partial",
214
- roomId: room.id,
215
- storage: root.toTreeNode("root").payload
216
- });
217
- }
218
- }
219
- function partialSyncMe(room) {
220
- const me = room.__internal.getSelf_forDevTools();
221
- if (me) {
222
- sendToPanel({
223
- msg: "room::sync::partial",
224
- roomId: room.id,
225
- me
226
- });
227
- }
228
- }
229
- function partialSyncOthers(room) {
230
- const others = room.__internal.getOthers_forDevTools();
231
- if (others) {
232
- sendToPanel({
233
- msg: "room::sync::partial",
234
- roomId: room.id,
235
- others
236
- });
237
- }
238
- }
239
- function fullSync(room) {
240
- const root = room.getStorageSnapshot();
241
- const me = room.__internal.getSelf_forDevTools();
242
- const others = room.__internal.getOthers_forDevTools();
243
- sendToPanel({
244
- msg: "room::sync::full",
245
- roomId: room.id,
246
- status: room.getStatus(),
247
- storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _6 => _6.toTreeNode, 'call', _7 => _7("root"), 'access', _8 => _8.payload]), () => ( null)),
248
- me,
249
- others
250
- });
251
- }
252
- var roomChannelListeners = /* @__PURE__ */ new Map();
253
- function stopRoomChannelListener(roomId) {
254
- const listener = roomChannelListeners.get(roomId);
255
- roomChannelListeners.delete(roomId);
256
- if (listener) {
257
- listener();
258
- }
259
- }
260
- function linkDevTools(roomId, room) {
261
- if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
262
- return;
263
- }
264
- sendToPanel({ msg: "room::available", roomId, clientVersion: VERSION });
265
- stopRoomChannelListener(roomId);
266
- roomChannelListeners.set(
267
- roomId,
268
- // Returns the unsubscribe callback, that we store in the
269
- // roomChannelListeners registry
270
- onMessageFromPanel.subscribe((msg) => {
271
- switch (msg.msg) {
272
- case "room::subscribe": {
273
- if (msg.roomId === roomId) {
274
- startSyncStream(room);
275
- }
276
- break;
277
- }
278
- case "room::unsubscribe": {
279
- if (msg.roomId === roomId) {
280
- stopSyncStream(roomId);
281
- }
282
- break;
283
- }
284
- }
285
- })
286
- );
287
- }
288
- function unlinkDevTools(roomId) {
289
- if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
290
- return;
291
- }
292
- stopSyncStream(roomId);
293
- stopRoomChannelListener(roomId);
294
- sendToPanel({
295
- msg: "room::unavailable",
296
- roomId
297
- });
298
- }
299
-
300
158
  // src/lib/fancy-console.ts
159
+ var fancy_console_exports = {};
160
+ __export(fancy_console_exports, {
161
+ error: () => error2,
162
+ errorWithTitle: () => errorWithTitle,
163
+ warn: () => warn,
164
+ warnWithTitle: () => warnWithTitle
165
+ });
301
166
  var badge = "background:#0e0d12;border-radius:9999px;color:#fff;padding:3px 7px;font-family:sans-serif;font-weight:600;";
302
167
  var bold = "font-weight:600";
303
168
  function wrap(method) {
@@ -323,57 +188,6 @@ function wrapWithTitle(method) {
323
188
  var warnWithTitle = wrapWithTitle("warn");
324
189
  var errorWithTitle = wrapWithTitle("error");
325
190
 
326
- // src/lib/deprecation.ts
327
- var _emittedDeprecationWarnings = /* @__PURE__ */ new Set();
328
- function deprecate(message, key = message) {
329
- if (process.env.NODE_ENV !== "production") {
330
- if (!_emittedDeprecationWarnings.has(key)) {
331
- _emittedDeprecationWarnings.add(key);
332
- errorWithTitle("Deprecation warning", message);
333
- }
334
- }
335
- }
336
- function deprecateIf(condition, message, key = message) {
337
- if (process.env.NODE_ENV !== "production") {
338
- if (condition) {
339
- deprecate(message, key);
340
- }
341
- }
342
- }
343
- function throwUsageError(message) {
344
- if (process.env.NODE_ENV !== "production") {
345
- const usageError = new Error(message);
346
- usageError.name = "Usage error";
347
- errorWithTitle("Usage error", message);
348
- throw usageError;
349
- }
350
- }
351
- function errorIf(condition, message) {
352
- if (process.env.NODE_ENV !== "production") {
353
- if (condition) {
354
- throwUsageError(message);
355
- }
356
- }
357
- }
358
-
359
- // src/lib/assert.ts
360
- function assertNever(_value, errmsg) {
361
- throw new Error(errmsg);
362
- }
363
- function assert(condition, errmsg) {
364
- if (process.env.NODE_ENV !== "production") {
365
- if (!condition) {
366
- const err = new Error(errmsg);
367
- err.name = "Assertion failure";
368
- throw err;
369
- }
370
- }
371
- }
372
- function nn(value, errmsg = "Expected value to be non-nullable") {
373
- assert(value !== null && value !== void 0, errmsg);
374
- return value;
375
- }
376
-
377
191
  // src/lib/fsm.ts
378
192
  function distance(state1, state2) {
379
193
  if (state1 === state2) {
@@ -652,7 +466,7 @@ var FSM = class {
652
466
  });
653
467
  }
654
468
  getTargetFn(eventName) {
655
- return _optionalChain([this, 'access', _9 => _9.allowedTransitions, 'access', _10 => _10.get, 'call', _11 => _11(this.currentState), 'optionalAccess', _12 => _12.get, 'call', _13 => _13(eventName)]);
469
+ return _optionalChain([this, 'access', _3 => _3.allowedTransitions, 'access', _4 => _4.get, 'call', _5 => _5(this.currentState), 'optionalAccess', _6 => _6.get, 'call', _7 => _7(eventName)]);
656
470
  }
657
471
  /**
658
472
  * Exits the current state, and executes any necessary cleanup functions.
@@ -669,7 +483,7 @@ var FSM = class {
669
483
  this.currentContext.allowPatching((patchableContext) => {
670
484
  levels = _nullishCoalesce(levels, () => ( this.cleanupStack.length));
671
485
  for (let i = 0; i < levels; i++) {
672
- _optionalChain([this, 'access', _14 => _14.cleanupStack, 'access', _15 => _15.pop, 'call', _16 => _16(), 'optionalCall', _17 => _17(patchableContext)]);
486
+ _optionalChain([this, 'access', _8 => _8.cleanupStack, 'access', _9 => _9.pop, 'call', _10 => _10(), 'optionalCall', _11 => _11(patchableContext)]);
673
487
  }
674
488
  });
675
489
  }
@@ -685,7 +499,7 @@ var FSM = class {
685
499
  this.currentContext.allowPatching((patchableContext) => {
686
500
  for (const pattern of enterPatterns) {
687
501
  const enterFn = this.enterFns.get(pattern);
688
- const cleanupFn = _optionalChain([enterFn, 'optionalCall', _18 => _18(patchableContext)]);
502
+ const cleanupFn = _optionalChain([enterFn, 'optionalCall', _12 => _12(patchableContext)]);
689
503
  if (typeof cleanupFn === "function") {
690
504
  this.cleanupStack.push(cleanupFn);
691
505
  } else {
@@ -812,12 +626,51 @@ async function withTimeout(promise, millis, errmsg = "Timed out") {
812
626
  return Promise.race([promise, timer$]).finally(() => clearTimeout(timerID));
813
627
  }
814
628
 
815
- // src/connection.ts
816
- function newToLegacyStatus(status) {
817
- switch (status) {
818
- case "connecting":
819
- return "connecting";
820
- case "connected":
629
+ // src/protocol/ServerMsg.ts
630
+ var ServerMsgCode = /* @__PURE__ */ ((ServerMsgCode2) => {
631
+ ServerMsgCode2[ServerMsgCode2["UPDATE_PRESENCE"] = 100] = "UPDATE_PRESENCE";
632
+ ServerMsgCode2[ServerMsgCode2["USER_JOINED"] = 101] = "USER_JOINED";
633
+ ServerMsgCode2[ServerMsgCode2["USER_LEFT"] = 102] = "USER_LEFT";
634
+ ServerMsgCode2[ServerMsgCode2["BROADCASTED_EVENT"] = 103] = "BROADCASTED_EVENT";
635
+ ServerMsgCode2[ServerMsgCode2["ROOM_STATE"] = 104] = "ROOM_STATE";
636
+ ServerMsgCode2[ServerMsgCode2["INITIAL_STORAGE_STATE"] = 200] = "INITIAL_STORAGE_STATE";
637
+ ServerMsgCode2[ServerMsgCode2["UPDATE_STORAGE"] = 201] = "UPDATE_STORAGE";
638
+ ServerMsgCode2[ServerMsgCode2["REJECT_STORAGE_OP"] = 299] = "REJECT_STORAGE_OP";
639
+ ServerMsgCode2[ServerMsgCode2["UPDATE_YDOC"] = 300] = "UPDATE_YDOC";
640
+ return ServerMsgCode2;
641
+ })(ServerMsgCode || {});
642
+
643
+ // src/types/IWebSocket.ts
644
+ var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
645
+ WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_ABNORMAL"] = 1006] = "CLOSE_ABNORMAL";
646
+ WebsocketCloseCodes2[WebsocketCloseCodes2["UNEXPECTED_CONDITION"] = 1011] = "UNEXPECTED_CONDITION";
647
+ WebsocketCloseCodes2[WebsocketCloseCodes2["TRY_AGAIN_LATER"] = 1013] = "TRY_AGAIN_LATER";
648
+ WebsocketCloseCodes2[WebsocketCloseCodes2["INVALID_MESSAGE_FORMAT"] = 4e3] = "INVALID_MESSAGE_FORMAT";
649
+ WebsocketCloseCodes2[WebsocketCloseCodes2["NOT_ALLOWED"] = 4001] = "NOT_ALLOWED";
650
+ WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_MESSAGES_PER_SECONDS"] = 4002] = "MAX_NUMBER_OF_MESSAGES_PER_SECONDS";
651
+ WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS"] = 4003] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS";
652
+ WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP"] = 4004] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP";
653
+ WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM"] = 4005] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM";
654
+ WebsocketCloseCodes2[WebsocketCloseCodes2["TOKEN_EXPIRED"] = 4109] = "TOKEN_EXPIRED";
655
+ WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_WITHOUT_RETRY"] = 4999] = "CLOSE_WITHOUT_RETRY";
656
+ return WebsocketCloseCodes2;
657
+ })(WebsocketCloseCodes || {});
658
+ function shouldDisconnect(code) {
659
+ return code === 4999 /* CLOSE_WITHOUT_RETRY */ || code >= 4e3 && code < 4100;
660
+ }
661
+ function shouldReauth(code) {
662
+ return code >= 4100 && code < 4200;
663
+ }
664
+ function shouldRetryWithoutReauth(code) {
665
+ return code === 1013 /* TRY_AGAIN_LATER */ || code >= 4200 && code < 4300;
666
+ }
667
+
668
+ // src/connection.ts
669
+ function newToLegacyStatus(status) {
670
+ switch (status) {
671
+ case "connecting":
672
+ return "connecting";
673
+ case "connected":
821
674
  return "open";
822
675
  case "reconnecting":
823
676
  return "unavailable";
@@ -916,9 +769,6 @@ var logPermanentClose = log(
916
769
  function isCloseEvent(error3) {
917
770
  return !(error3 instanceof Error) && error3.type === "close";
918
771
  }
919
- function isCustomCloseEvent(error3) {
920
- return isCloseEvent(error3) && error3.code >= 4e3 && error3.code < 4100;
921
- }
922
772
  function enableTracing(machine) {
923
773
  const start = (/* @__PURE__ */ new Date()).getTime();
924
774
  function log2(...args) {
@@ -969,13 +819,19 @@ function defineConnectivityEvents(machine) {
969
819
  };
970
820
  }
971
821
  var assign = (patch) => (ctx) => ctx.patch(patch);
972
- function createConnectionStateMachine(delegates, enableDebugLogging) {
822
+ function createConnectionStateMachine(delegates, options) {
973
823
  const onMessage = makeEventSource();
974
824
  onMessage.pause();
975
825
  const onLiveblocksError = makeEventSource();
826
+ function fireErrorEvent(errmsg, errcode) {
827
+ return () => {
828
+ const err = new LiveblocksError(errmsg, errcode);
829
+ onLiveblocksError.notify(err);
830
+ };
831
+ }
976
832
  const initialContext = {
977
833
  successCount: 0,
978
- token: null,
834
+ authValue: null,
979
835
  socket: null,
980
836
  backoffDelay: RESET_DELAY
981
837
  };
@@ -989,9 +845,9 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
989
845
  });
990
846
  machine.onEnter("@idle.*", resetSuccessCount).addTransitions("@idle.*", {
991
847
  CONNECT: (_, ctx) => (
992
- // If we still have a known token, try to reconnect to the socket directly,
993
- // otherwise, try to obtain a new token
994
- ctx.token !== null ? "@connecting.busy" : "@auth.busy"
848
+ // If we still have a known authValue, try to reconnect to the socket directly,
849
+ // otherwise, try to obtain a new authValue
850
+ ctx.authValue !== null ? "@connecting.busy" : "@auth.busy"
995
851
  )
996
852
  });
997
853
  machine.addTransitions("@auth.backoff", {
@@ -1010,7 +866,7 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1010
866
  (okEvent) => ({
1011
867
  target: "@connecting.busy",
1012
868
  effect: assign({
1013
- token: okEvent.data,
869
+ authValue: okEvent.data,
1014
870
  backoffDelay: RESET_DELAY
1015
871
  })
1016
872
  }),
@@ -1019,7 +875,10 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1019
875
  if (failedEvent.reason instanceof StopRetrying) {
1020
876
  return {
1021
877
  target: "@idle.failed",
1022
- effect: log(2 /* ERROR */, failedEvent.reason.message)
878
+ effect: [
879
+ log(2 /* ERROR */, failedEvent.reason.message),
880
+ fireErrorEvent(failedEvent.reason.message, -1)
881
+ ]
1023
882
  };
1024
883
  }
1025
884
  return {
@@ -1069,16 +928,29 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1069
928
  let capturedPrematureEvent = null;
1070
929
  const connect$ = new Promise(
1071
930
  (resolve, rej) => {
1072
- if (ctx.token === null) {
1073
- throw new Error("No auth token");
931
+ if (ctx.authValue === null) {
932
+ throw new Error("No auth authValue");
1074
933
  }
1075
- const socket = delegates.createSocket(ctx.token);
934
+ const socket = delegates.createSocket(ctx.authValue);
1076
935
  function reject(event) {
1077
936
  capturedPrematureEvent = event;
1078
937
  socket.removeEventListener("message", onSocketMessage);
1079
938
  rej(event);
1080
939
  }
940
+ const [actor$, didReceiveActor] = controlledPromise();
941
+ if (!options.waitForActorId) {
942
+ didReceiveActor();
943
+ }
944
+ function waitForActorId(event) {
945
+ const serverMsg = tryParseJson(event.data);
946
+ if (_optionalChain([serverMsg, 'optionalAccess', _13 => _13.type]) === 104 /* ROOM_STATE */) {
947
+ didReceiveActor();
948
+ }
949
+ }
1081
950
  socket.addEventListener("message", onSocketMessage);
951
+ if (options.waitForActorId) {
952
+ socket.addEventListener("message", waitForActorId);
953
+ }
1082
954
  socket.addEventListener("error", reject);
1083
955
  socket.addEventListener("close", reject);
1084
956
  socket.addEventListener("open", () => {
@@ -1087,8 +959,11 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1087
959
  const unsub = () => {
1088
960
  socket.removeEventListener("error", reject);
1089
961
  socket.removeEventListener("close", reject);
962
+ socket.removeEventListener("message", waitForActorId);
1090
963
  };
1091
- resolve([socket, unsub]);
964
+ void actor$.then(() => {
965
+ resolve([socket, unsub]);
966
+ });
1092
967
  });
1093
968
  }
1094
969
  );
@@ -1129,24 +1004,35 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1129
1004
  if (err instanceof StopRetrying) {
1130
1005
  return {
1131
1006
  target: "@idle.failed",
1132
- effect: log(2 /* ERROR */, err.message)
1133
- };
1134
- }
1135
- if (isCloseEvent(err) && err.code === 4999) {
1136
- return {
1137
- target: "@idle.failed",
1138
- effect: log(2 /* ERROR */, err.reason)
1139
- };
1140
- }
1141
- if (isCustomCloseEvent(err) && err.code !== 4001) {
1142
- return {
1143
- target: "@connecting.backoff",
1144
1007
  effect: [
1145
- increaseBackoffDelayAggressively,
1146
- logPrematureErrorOrCloseEvent(err)
1008
+ log(2 /* ERROR */, err.message),
1009
+ fireErrorEvent(err.message, -1)
1147
1010
  ]
1148
1011
  };
1149
1012
  }
1013
+ if (isCloseEvent(err)) {
1014
+ if (err.code === 4109 /* TOKEN_EXPIRED */) {
1015
+ return "@auth.busy";
1016
+ }
1017
+ if (shouldRetryWithoutReauth(err.code)) {
1018
+ return {
1019
+ target: "@connecting.backoff",
1020
+ effect: [
1021
+ increaseBackoffDelayAggressively,
1022
+ logPrematureErrorOrCloseEvent(err)
1023
+ ]
1024
+ };
1025
+ }
1026
+ if (shouldDisconnect(err.code)) {
1027
+ return {
1028
+ target: "@idle.failed",
1029
+ effect: [
1030
+ log(2 /* ERROR */, err.reason),
1031
+ fireErrorEvent(err.reason, err.code)
1032
+ ]
1033
+ };
1034
+ }
1035
+ }
1150
1036
  return {
1151
1037
  target: "@auth.backoff",
1152
1038
  effect: [increaseBackoffDelay, logPrematureErrorOrCloseEvent(err)]
@@ -1156,7 +1042,7 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1156
1042
  const sendHeartbeat = {
1157
1043
  target: "@ok.awaiting-pong",
1158
1044
  effect: (ctx) => {
1159
- _optionalChain([ctx, 'access', _19 => _19.socket, 'optionalAccess', _20 => _20.send, 'call', _21 => _21("ping")]);
1045
+ _optionalChain([ctx, 'access', _14 => _14.socket, 'optionalAccess', _15 => _15.send, 'call', _16 => _16("ping")]);
1160
1046
  }
1161
1047
  };
1162
1048
  machine.addTimedTransition("@ok.connected", HEARTBEAT_INTERVAL, sendHeartbeat).addTransitions("@ok.connected", {
@@ -1191,7 +1077,7 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1191
1077
  // socket, or not. So always check to see if the socket is still OPEN or
1192
1078
  // not. When still OPEN, don't transition.
1193
1079
  EXPLICIT_SOCKET_ERROR: (_, context) => {
1194
- if (_optionalChain([context, 'access', _22 => _22.socket, 'optionalAccess', _23 => _23.readyState]) === 1) {
1080
+ if (_optionalChain([context, 'access', _17 => _17.socket, 'optionalAccess', _18 => _18.readyState]) === 1) {
1195
1081
  return null;
1196
1082
  }
1197
1083
  return {
@@ -1200,29 +1086,29 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1200
1086
  };
1201
1087
  },
1202
1088
  EXPLICIT_SOCKET_CLOSE: (e) => {
1203
- if (e.event.code === 4999) {
1089
+ if (shouldDisconnect(e.event.code)) {
1204
1090
  return {
1205
1091
  target: "@idle.failed",
1206
- effect: logPermanentClose
1092
+ effect: [
1093
+ logPermanentClose,
1094
+ fireErrorEvent(e.event.reason, e.event.code)
1095
+ ]
1207
1096
  };
1208
1097
  }
1209
- if (e.event.code === 4001) {
1210
- return {
1211
- target: "@auth.backoff",
1212
- effect: [increaseBackoffDelay, logCloseEvent(e.event)]
1213
- };
1098
+ if (shouldReauth(e.event.code)) {
1099
+ if (e.event.code === 4109 /* TOKEN_EXPIRED */) {
1100
+ return "@auth.busy";
1101
+ } else {
1102
+ return {
1103
+ target: "@auth.backoff",
1104
+ effect: [increaseBackoffDelay, logCloseEvent(e.event)]
1105
+ };
1106
+ }
1214
1107
  }
1215
- if (isCustomCloseEvent(e.event)) {
1108
+ if (shouldRetryWithoutReauth(e.event.code)) {
1216
1109
  return {
1217
1110
  target: "@connecting.backoff",
1218
- effect: [
1219
- increaseBackoffDelayAggressively,
1220
- logCloseEvent(e.event),
1221
- () => {
1222
- const err = new LiveblocksError(e.event.reason, e.event.code);
1223
- onLiveblocksError.notify(err);
1224
- }
1225
- ]
1111
+ effect: [increaseBackoffDelayAggressively, logCloseEvent(e.event)]
1226
1112
  };
1227
1113
  }
1228
1114
  return {
@@ -1243,17 +1129,17 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1243
1129
  machine.send({ type: "NAVIGATOR_ONLINE" });
1244
1130
  }
1245
1131
  function onVisibilityChange() {
1246
- if (_optionalChain([doc, 'optionalAccess', _24 => _24.visibilityState]) === "visible") {
1132
+ if (_optionalChain([doc, 'optionalAccess', _19 => _19.visibilityState]) === "visible") {
1247
1133
  machine.send({ type: "WINDOW_GOT_FOCUS" });
1248
1134
  }
1249
1135
  }
1250
- _optionalChain([win, 'optionalAccess', _25 => _25.addEventListener, 'call', _26 => _26("online", onNetworkBackOnline)]);
1251
- _optionalChain([win, 'optionalAccess', _27 => _27.addEventListener, 'call', _28 => _28("offline", onNetworkOffline)]);
1252
- _optionalChain([root, 'optionalAccess', _29 => _29.addEventListener, 'call', _30 => _30("visibilitychange", onVisibilityChange)]);
1136
+ _optionalChain([win, 'optionalAccess', _20 => _20.addEventListener, 'call', _21 => _21("online", onNetworkBackOnline)]);
1137
+ _optionalChain([win, 'optionalAccess', _22 => _22.addEventListener, 'call', _23 => _23("offline", onNetworkOffline)]);
1138
+ _optionalChain([root, 'optionalAccess', _24 => _24.addEventListener, 'call', _25 => _25("visibilitychange", onVisibilityChange)]);
1253
1139
  return () => {
1254
- _optionalChain([root, 'optionalAccess', _31 => _31.removeEventListener, 'call', _32 => _32("visibilitychange", onVisibilityChange)]);
1255
- _optionalChain([win, 'optionalAccess', _33 => _33.removeEventListener, 'call', _34 => _34("online", onNetworkBackOnline)]);
1256
- _optionalChain([win, 'optionalAccess', _35 => _35.removeEventListener, 'call', _36 => _36("offline", onNetworkOffline)]);
1140
+ _optionalChain([root, 'optionalAccess', _26 => _26.removeEventListener, 'call', _27 => _27("visibilitychange", onVisibilityChange)]);
1141
+ _optionalChain([win, 'optionalAccess', _28 => _28.removeEventListener, 'call', _29 => _29("online", onNetworkBackOnline)]);
1142
+ _optionalChain([win, 'optionalAccess', _30 => _30.removeEventListener, 'call', _31 => _31("offline", onNetworkOffline)]);
1257
1143
  teardownSocket(ctx.socket);
1258
1144
  };
1259
1145
  });
@@ -1261,7 +1147,7 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1261
1147
  const cleanups = [];
1262
1148
  const { statusDidChange, didConnect, didDisconnect, unsubscribe } = defineConnectivityEvents(machine);
1263
1149
  cleanups.push(unsubscribe);
1264
- if (enableDebugLogging) {
1150
+ if (options.enableDebugLogging) {
1265
1151
  cleanups.push(enableTracing(machine));
1266
1152
  }
1267
1153
  machine.start();
@@ -1279,10 +1165,10 @@ function createConnectionStateMachine(delegates, enableDebugLogging) {
1279
1165
  };
1280
1166
  }
1281
1167
  var ManagedSocket = class {
1282
- constructor(delegates, enableDebugLogging = false) {
1168
+ constructor(delegates, enableDebugLogging = false, waitForActorId = true) {
1283
1169
  const { machine, events, cleanups } = createConnectionStateMachine(
1284
1170
  delegates,
1285
- enableDebugLogging
1171
+ { waitForActorId, enableDebugLogging }
1286
1172
  );
1287
1173
  this.machine = machine;
1288
1174
  this.events = events;
@@ -1299,10 +1185,10 @@ var ManagedSocket = class {
1299
1185
  }
1300
1186
  }
1301
1187
  /**
1302
- * Returns the current auth token.
1188
+ * Returns the current auth authValue.
1303
1189
  */
1304
- get token() {
1305
- return this.machine.context.token;
1190
+ get authValue() {
1191
+ return this.machine.context.authValue;
1306
1192
  }
1307
1193
  /**
1308
1194
  * Call this method to try to connect to a WebSocket. This only has an effect
@@ -1313,7 +1199,7 @@ var ManagedSocket = class {
1313
1199
  }
1314
1200
  /**
1315
1201
  * If idle, will try to connect. Otherwise, it will attempt to reconnect to
1316
- * the socket, potentially obtaining a new token first, if needed.
1202
+ * the socket, potentially obtaining a new authValue first, if needed.
1317
1203
  */
1318
1204
  reconnect() {
1319
1205
  this.machine.send({ type: "RECONNECT" });
@@ -1342,7 +1228,7 @@ var ManagedSocket = class {
1342
1228
  * message if this is somehow impossible.
1343
1229
  */
1344
1230
  send(data) {
1345
- const socket = _optionalChain([this, 'access', _37 => _37.machine, 'access', _38 => _38.context, 'optionalAccess', _39 => _39.socket]);
1231
+ const socket = _optionalChain([this, 'access', _32 => _32.machine, 'access', _33 => _33.context, 'optionalAccess', _34 => _34.socket]);
1346
1232
  if (socket === null) {
1347
1233
  warn("Cannot send: not connected yet", data);
1348
1234
  } else if (socket.readyState !== 1) {
@@ -1360,121 +1246,632 @@ var ManagedSocket = class {
1360
1246
  }
1361
1247
  };
1362
1248
 
1363
- // src/lib/position.ts
1364
- var MIN_CODE = 32;
1365
- var MAX_CODE = 126;
1366
- var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
1367
- var ZERO = nthDigit(0);
1368
- var ONE = nthDigit(1);
1369
- var ZERO_NINE = ZERO + nthDigit(-1);
1370
- function nthDigit(n) {
1371
- const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
1372
- if (code < MIN_CODE || code > MAX_CODE) {
1373
- throw new Error(`Invalid n value: ${n}`);
1374
- }
1375
- return String.fromCharCode(code);
1249
+ // src/protocol/AuthToken.ts
1250
+ function canWriteStorage(scopes) {
1251
+ return scopes.includes("room:write" /* Write */);
1376
1252
  }
1377
- function makePosition(x, y) {
1378
- if (x !== void 0 && y !== void 0) {
1379
- return between(x, y);
1380
- } else if (x !== void 0) {
1381
- return after(x);
1382
- } else if (y !== void 0) {
1383
- return before(y);
1384
- } else {
1385
- return ONE;
1253
+ function isValidAuthTokenPayload(data) {
1254
+ return isPlainObject(data) && (data.k === "acc" /* ACCESS_TOKEN */ || data.k === "id" /* ID_TOKEN */ || data.k === "sec-legacy" /* SECRET_LEGACY */);
1255
+ }
1256
+ function parseAuthToken(rawTokenString) {
1257
+ const tokenParts = rawTokenString.split(".");
1258
+ if (tokenParts.length !== 3) {
1259
+ throw new Error("Authentication error: invalid JWT token");
1260
+ }
1261
+ const payload = tryParseJson(b64decode(tokenParts[1]));
1262
+ if (!(payload && isValidAuthTokenPayload(payload))) {
1263
+ throw new Error(
1264
+ "Authentication error: expected a valid token but did not get one. Hint: if you are using a callback, ensure the room is passed when creating the token. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientCallback"
1265
+ );
1386
1266
  }
1267
+ return {
1268
+ raw: rawTokenString,
1269
+ parsed: payload
1270
+ };
1387
1271
  }
1388
- function before(pos) {
1389
- const lastIndex = pos.length - 1;
1390
- for (let i = 0; i <= lastIndex; i++) {
1391
- const code = pos.charCodeAt(i);
1392
- if (code <= MIN_CODE) {
1393
- continue;
1272
+
1273
+ // src/auth-manager.ts
1274
+ function createAuthManager(authOptions) {
1275
+ const authentication = prepareAuthentication(authOptions);
1276
+ const tokens = [];
1277
+ const expiryTimes = [];
1278
+ const requestPromises = /* @__PURE__ */ new Map();
1279
+ function hasCorrespondingScopes(requestedScope, scopes) {
1280
+ if (requestedScope === "comments:read") {
1281
+ return scopes.includes("comments:read" /* CommentsRead */) || scopes.includes("comments:write" /* CommentsWrite */) || scopes.includes("room:read" /* Read */) || scopes.includes("room:write" /* Write */);
1282
+ } else if (requestedScope === "room:read") {
1283
+ return scopes.includes("room:read" /* Read */) || scopes.includes("room:write" /* Write */);
1394
1284
  }
1395
- if (i === lastIndex) {
1396
- if (code === MIN_CODE + 1) {
1397
- return pos.substring(0, i) + ZERO_NINE;
1398
- } else {
1399
- return pos.substring(0, i) + String.fromCharCode(code - 1);
1285
+ return false;
1286
+ }
1287
+ function getCachedToken(requestedScope, roomId) {
1288
+ const now = Math.ceil(Date.now() / 1e3);
1289
+ for (let i = tokens.length - 1; i >= 0; i--) {
1290
+ const token = tokens[i];
1291
+ const expiresAt = expiryTimes[i];
1292
+ if (expiresAt <= now) {
1293
+ tokens.splice(i, 1);
1294
+ expiryTimes.splice(i, 1);
1295
+ continue;
1296
+ }
1297
+ if (token.parsed.k === "id" /* ID_TOKEN */) {
1298
+ return token;
1299
+ } else if (token.parsed.k === "sec-legacy" /* SECRET_LEGACY */) {
1300
+ return void 0;
1301
+ } else if (token.parsed.k === "acc" /* ACCESS_TOKEN */) {
1302
+ for (const [resource, scopes] of Object.entries(token.parsed.perms)) {
1303
+ if (resource.includes("*") && roomId.startsWith(resource.replace("*", "")) || roomId === resource && hasCorrespondingScopes(requestedScope, scopes)) {
1304
+ return token;
1305
+ }
1306
+ }
1400
1307
  }
1401
- } else {
1402
- return pos.substring(0, i + 1);
1403
1308
  }
1309
+ return void 0;
1404
1310
  }
1405
- return ONE;
1406
- }
1407
- function after(pos) {
1408
- for (let i = 0; i <= pos.length - 1; i++) {
1409
- const code = pos.charCodeAt(i);
1410
- if (code >= MAX_CODE) {
1411
- continue;
1311
+ async function makeAuthRequest(roomId) {
1312
+ const fetcher = _nullishCoalesce(_optionalChain([authOptions, 'access', _35 => _35.polyfills, 'optionalAccess', _36 => _36.fetch]), () => ( (typeof window === "undefined" ? void 0 : window.fetch)));
1313
+ if (authentication.type === "private") {
1314
+ if (fetcher === void 0) {
1315
+ throw new StopRetrying(
1316
+ "To use Liveblocks client in a non-dom environment with a url as auth endpoint, you need to provide a fetch polyfill."
1317
+ );
1318
+ }
1319
+ const response = await fetchAuthEndpoint(fetcher, authentication.url, {
1320
+ room: roomId
1321
+ });
1322
+ return parseAuthToken(response.token);
1412
1323
  }
1413
- return pos.substring(0, i) + String.fromCharCode(code + 1);
1414
- }
1415
- return pos + ONE;
1416
- }
1417
- function between(lo, hi) {
1418
- if (lo < hi) {
1419
- return _between(lo, hi);
1420
- } else if (lo > hi) {
1421
- return _between(hi, lo);
1422
- } else {
1423
- throw new Error("Cannot compute value between two equal positions");
1324
+ if (authentication.type === "custom") {
1325
+ const response = await authentication.callback(roomId);
1326
+ if (!response || typeof response !== "object") {
1327
+ throw new Error(
1328
+ 'We expect the authentication callback to return a token, but it does not. Hint: the return value should look like: { token: "..." }'
1329
+ );
1330
+ }
1331
+ if (typeof response.token === "string") {
1332
+ return parseAuthToken(response.token);
1333
+ } else if (typeof response.error === "string") {
1334
+ const reason = `Authentication failed: ${"reason" in response && typeof response.reason === "string" ? response.reason : "Forbidden"}`;
1335
+ if (response.error === "forbidden") {
1336
+ throw new StopRetrying(reason);
1337
+ } else {
1338
+ throw new Error(reason);
1339
+ }
1340
+ } else {
1341
+ throw new Error(
1342
+ 'We expect the authentication callback to return a token, but it does not. Hint: the return value should look like: { token: "..." }'
1343
+ );
1344
+ }
1345
+ }
1346
+ throw new Error("Invalid Liveblocks client options");
1424
1347
  }
1425
- }
1426
- function _between(lo, hi) {
1427
- let index = 0;
1428
- const loLen = lo.length;
1429
- const hiLen = hi.length;
1430
- while (true) {
1431
- const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
1432
- const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
1433
- if (loCode === hiCode) {
1434
- index++;
1435
- continue;
1348
+ async function getAuthValue(requestedScope, roomId) {
1349
+ if (authentication.type === "public") {
1350
+ return { type: "public", publicApiKey: authentication.publicApiKey };
1436
1351
  }
1437
- if (hiCode - loCode === 1) {
1438
- const prefix = lo.substring(0, index + 1);
1439
- const suffix = lo.substring(index + 1);
1440
- const nines = "";
1441
- return prefix + _between(suffix, nines);
1442
- } else {
1443
- return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
1352
+ const cachedToken = getCachedToken(requestedScope, roomId);
1353
+ if (cachedToken !== void 0) {
1354
+ return { type: "secret", token: cachedToken };
1355
+ }
1356
+ let currentPromise = requestPromises.get(roomId);
1357
+ if (currentPromise === void 0) {
1358
+ currentPromise = makeAuthRequest(roomId);
1359
+ requestPromises.set(roomId, currentPromise);
1360
+ }
1361
+ try {
1362
+ const token = await currentPromise;
1363
+ const BUFFER = 30;
1364
+ const expiresAt = Math.floor(Date.now() / 1e3) + (token.parsed.exp - token.parsed.iat) - BUFFER;
1365
+ tokens.push(token);
1366
+ expiryTimes.push(expiresAt);
1367
+ return { type: "secret", token };
1368
+ } finally {
1369
+ requestPromises.delete(roomId);
1444
1370
  }
1445
1371
  }
1372
+ return {
1373
+ getAuthValue
1374
+ };
1446
1375
  }
1447
- function takeN(pos, n) {
1448
- return n < pos.length ? pos.substring(0, n) : pos + ZERO.repeat(n - pos.length);
1449
- }
1450
- var MIN_NON_ZERO_CODE = MIN_CODE + 1;
1451
- function isPos(str) {
1452
- if (str === "") {
1453
- return false;
1454
- }
1455
- const lastIdx = str.length - 1;
1456
- const last = str.charCodeAt(lastIdx);
1457
- if (last < MIN_NON_ZERO_CODE || last > MAX_CODE) {
1458
- return false;
1376
+ function prepareAuthentication(authOptions) {
1377
+ const { publicApiKey, authEndpoint } = authOptions;
1378
+ if (authEndpoint !== void 0 && publicApiKey !== void 0) {
1379
+ throw new Error(
1380
+ "You cannot use both publicApiKey and authEndpoint. Please use either publicApiKey or authEndpoint, but not both. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient"
1381
+ );
1459
1382
  }
1460
- for (let i = 0; i < lastIdx; i++) {
1461
- const code = str.charCodeAt(i);
1462
- if (code < MIN_CODE || code > MAX_CODE) {
1463
- return false;
1383
+ if (typeof publicApiKey === "string") {
1384
+ if (publicApiKey.startsWith("sk_")) {
1385
+ throw new Error(
1386
+ "Invalid publicApiKey. You are using the secret key which is not supported. Please use the public key instead. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientPublicKey"
1387
+ );
1388
+ } else if (!publicApiKey.startsWith("pk_")) {
1389
+ throw new Error(
1390
+ "Invalid key. Please use the public key format: pk_<public key>. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientPublicKey"
1391
+ );
1464
1392
  }
1393
+ return {
1394
+ type: "public",
1395
+ publicApiKey
1396
+ };
1465
1397
  }
1466
- return true;
1467
- }
1468
- function convertToPos(str) {
1469
- const codes = [];
1470
- for (let i = 0; i < str.length; i++) {
1471
- const code = str.charCodeAt(i);
1472
- codes.push(code < MIN_CODE ? MIN_CODE : code > MAX_CODE ? MAX_CODE : code);
1473
- }
1474
- while (codes.length > 0 && codes[codes.length - 1] === MIN_CODE) {
1475
- codes.length--;
1398
+ if (typeof authEndpoint === "string") {
1399
+ return {
1400
+ type: "private",
1401
+ url: authEndpoint
1402
+ };
1403
+ } else if (typeof authEndpoint === "function") {
1404
+ return {
1405
+ type: "custom",
1406
+ callback: authEndpoint
1407
+ };
1408
+ } else if (authEndpoint !== void 0) {
1409
+ throw new Error(
1410
+ "authEndpoint must be a string or a function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientAuthEndpoint"
1411
+ );
1476
1412
  }
1477
- return codes.length > 0 ? String.fromCharCode(...codes) : (
1413
+ throw new Error(
1414
+ "Invalid Liveblocks client options. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient"
1415
+ );
1416
+ }
1417
+ async function fetchAuthEndpoint(fetch2, endpoint, body) {
1418
+ const res = await fetch2(endpoint, {
1419
+ method: "POST",
1420
+ headers: {
1421
+ "Content-Type": "application/json"
1422
+ },
1423
+ body: JSON.stringify(body)
1424
+ });
1425
+ if (!res.ok) {
1426
+ const reason = `${(await res.text()).trim() || "reason not provided in auth response"} (${res.status} returned by POST ${endpoint})`;
1427
+ if (res.status === 401 || res.status === 403) {
1428
+ throw new StopRetrying(`Unauthorized: ${reason}`);
1429
+ } else {
1430
+ throw new Error(`Failed to authenticate: ${reason}`);
1431
+ }
1432
+ }
1433
+ let data;
1434
+ try {
1435
+ data = await res.json();
1436
+ } catch (er) {
1437
+ throw new Error(
1438
+ `Expected a JSON response when doing a POST request on "${endpoint}". ${String(
1439
+ er
1440
+ )}`
1441
+ );
1442
+ }
1443
+ if (!isPlainObject(data) || typeof data.token !== "string") {
1444
+ throw new Error(
1445
+ `Expected a JSON response of the form \`{ token: "..." }\` when doing a POST request on "${endpoint}", but got ${JSON.stringify(
1446
+ data
1447
+ )}`
1448
+ );
1449
+ }
1450
+ const { token } = data;
1451
+ return { token };
1452
+ }
1453
+
1454
+ // src/devtools/bridge.ts
1455
+ var _bridgeActive = false;
1456
+ function activateBridge(allowed) {
1457
+ _bridgeActive = allowed;
1458
+ }
1459
+ function sendToPanel(message, options) {
1460
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
1461
+ return;
1462
+ }
1463
+ const fullMsg = {
1464
+ ...message,
1465
+ source: "liveblocks-devtools-client"
1466
+ };
1467
+ if (!(_optionalChain([options, 'optionalAccess', _37 => _37.force]) || _bridgeActive)) {
1468
+ return;
1469
+ }
1470
+ window.postMessage(fullMsg, "*");
1471
+ }
1472
+ var eventSource = makeEventSource();
1473
+ if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
1474
+ window.addEventListener("message", (event) => {
1475
+ if (event.source === window && _optionalChain([event, 'access', _38 => _38.data, 'optionalAccess', _39 => _39.source]) === "liveblocks-devtools-panel") {
1476
+ eventSource.notify(event.data);
1477
+ } else {
1478
+ }
1479
+ });
1480
+ }
1481
+ var onMessageFromPanel = eventSource.observable;
1482
+
1483
+ // src/devtools/index.ts
1484
+ var VERSION = PKG_VERSION || "dev";
1485
+ var _devtoolsSetupHasRun = false;
1486
+ function setupDevTools(getAllRooms) {
1487
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
1488
+ return;
1489
+ }
1490
+ if (_devtoolsSetupHasRun) {
1491
+ return;
1492
+ }
1493
+ _devtoolsSetupHasRun = true;
1494
+ onMessageFromPanel.subscribe((msg) => {
1495
+ switch (msg.msg) {
1496
+ case "connect": {
1497
+ activateBridge(true);
1498
+ for (const roomId of getAllRooms()) {
1499
+ sendToPanel({
1500
+ msg: "room::available",
1501
+ roomId,
1502
+ clientVersion: VERSION
1503
+ });
1504
+ }
1505
+ break;
1506
+ }
1507
+ }
1508
+ });
1509
+ sendToPanel({ msg: "wake-up-devtools" }, { force: true });
1510
+ }
1511
+ var unsubsByRoomId = /* @__PURE__ */ new Map();
1512
+ function stopSyncStream(roomId) {
1513
+ const unsubs = _nullishCoalesce(unsubsByRoomId.get(roomId), () => ( []));
1514
+ unsubsByRoomId.delete(roomId);
1515
+ for (const unsub of unsubs) {
1516
+ unsub();
1517
+ }
1518
+ }
1519
+ function startSyncStream(room) {
1520
+ stopSyncStream(room.id);
1521
+ fullSync(room);
1522
+ unsubsByRoomId.set(room.id, [
1523
+ // When the connection status changes
1524
+ room.events.status.subscribe(() => partialSyncConnection(room)),
1525
+ // When storage initializes, send the update
1526
+ room.events.storageDidLoad.subscribeOnce(() => partialSyncStorage(room)),
1527
+ // Any time storage updates, send the new storage root
1528
+ room.events.storage.subscribe(() => partialSyncStorage(room)),
1529
+ // Any time "me" or "others" updates, send the new values accordingly
1530
+ room.events.self.subscribe(() => partialSyncMe(room)),
1531
+ room.events.others.subscribe(() => partialSyncOthers(room))
1532
+ ]);
1533
+ }
1534
+ function partialSyncConnection(room) {
1535
+ sendToPanel({
1536
+ msg: "room::sync::partial",
1537
+ roomId: room.id,
1538
+ status: room.getStatus()
1539
+ });
1540
+ }
1541
+ function partialSyncStorage(room) {
1542
+ const root = room.getStorageSnapshot();
1543
+ if (root) {
1544
+ sendToPanel({
1545
+ msg: "room::sync::partial",
1546
+ roomId: room.id,
1547
+ storage: root.toTreeNode("root").payload
1548
+ });
1549
+ }
1550
+ }
1551
+ function partialSyncMe(room) {
1552
+ const me = room.__internal.getSelf_forDevTools();
1553
+ if (me) {
1554
+ sendToPanel({
1555
+ msg: "room::sync::partial",
1556
+ roomId: room.id,
1557
+ me
1558
+ });
1559
+ }
1560
+ }
1561
+ function partialSyncOthers(room) {
1562
+ const others = room.__internal.getOthers_forDevTools();
1563
+ if (others) {
1564
+ sendToPanel({
1565
+ msg: "room::sync::partial",
1566
+ roomId: room.id,
1567
+ others
1568
+ });
1569
+ }
1570
+ }
1571
+ function fullSync(room) {
1572
+ const root = room.getStorageSnapshot();
1573
+ const me = room.__internal.getSelf_forDevTools();
1574
+ const others = room.__internal.getOthers_forDevTools();
1575
+ sendToPanel({
1576
+ msg: "room::sync::full",
1577
+ roomId: room.id,
1578
+ status: room.getStatus(),
1579
+ storage: _nullishCoalesce(_optionalChain([root, 'optionalAccess', _40 => _40.toTreeNode, 'call', _41 => _41("root"), 'access', _42 => _42.payload]), () => ( null)),
1580
+ me,
1581
+ others
1582
+ });
1583
+ }
1584
+ var roomChannelListeners = /* @__PURE__ */ new Map();
1585
+ function stopRoomChannelListener(roomId) {
1586
+ const listener = roomChannelListeners.get(roomId);
1587
+ roomChannelListeners.delete(roomId);
1588
+ if (listener) {
1589
+ listener();
1590
+ }
1591
+ }
1592
+ function linkDevTools(roomId, room) {
1593
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
1594
+ return;
1595
+ }
1596
+ sendToPanel({ msg: "room::available", roomId, clientVersion: VERSION });
1597
+ stopRoomChannelListener(roomId);
1598
+ roomChannelListeners.set(
1599
+ roomId,
1600
+ // Returns the unsubscribe callback, that we store in the
1601
+ // roomChannelListeners registry
1602
+ onMessageFromPanel.subscribe((msg) => {
1603
+ switch (msg.msg) {
1604
+ case "room::subscribe": {
1605
+ if (msg.roomId === roomId) {
1606
+ startSyncStream(room);
1607
+ }
1608
+ break;
1609
+ }
1610
+ case "room::unsubscribe": {
1611
+ if (msg.roomId === roomId) {
1612
+ stopSyncStream(roomId);
1613
+ }
1614
+ break;
1615
+ }
1616
+ }
1617
+ })
1618
+ );
1619
+ }
1620
+ function unlinkDevTools(roomId) {
1621
+ if (process.env.NODE_ENV === "production" || typeof window === "undefined") {
1622
+ return;
1623
+ }
1624
+ stopSyncStream(roomId);
1625
+ stopRoomChannelListener(roomId);
1626
+ sendToPanel({
1627
+ msg: "room::unavailable",
1628
+ roomId
1629
+ });
1630
+ }
1631
+
1632
+ // src/lib/deprecation.ts
1633
+ var _emittedDeprecationWarnings = /* @__PURE__ */ new Set();
1634
+ function deprecate(message, key = message) {
1635
+ if (process.env.NODE_ENV !== "production") {
1636
+ if (!_emittedDeprecationWarnings.has(key)) {
1637
+ _emittedDeprecationWarnings.add(key);
1638
+ errorWithTitle("Deprecation warning", message);
1639
+ }
1640
+ }
1641
+ }
1642
+ function deprecateIf(condition, message, key = message) {
1643
+ if (process.env.NODE_ENV !== "production") {
1644
+ if (condition) {
1645
+ deprecate(message, key);
1646
+ }
1647
+ }
1648
+ }
1649
+ function throwUsageError(message) {
1650
+ if (process.env.NODE_ENV !== "production") {
1651
+ const usageError = new Error(message);
1652
+ usageError.name = "Usage error";
1653
+ errorWithTitle("Usage error", message);
1654
+ throw usageError;
1655
+ }
1656
+ }
1657
+ function errorIf(condition, message) {
1658
+ if (process.env.NODE_ENV !== "production") {
1659
+ if (condition) {
1660
+ throwUsageError(message);
1661
+ }
1662
+ }
1663
+ }
1664
+
1665
+ // src/lib/Json.ts
1666
+ function isJsonScalar(data) {
1667
+ return data === null || typeof data === "string" || typeof data === "number" || typeof data === "boolean";
1668
+ }
1669
+ function isJsonArray(data) {
1670
+ return Array.isArray(data);
1671
+ }
1672
+ function isJsonObject(data) {
1673
+ return !isJsonScalar(data) && !isJsonArray(data);
1674
+ }
1675
+
1676
+ // src/realtime-client.ts
1677
+ function authValueToString(authValue) {
1678
+ return authValue.type === "secret" ? authValue.token.raw : authValue.publicApiKey;
1679
+ }
1680
+ function createRealtimeClient(authManager, serverEndpoint) {
1681
+ const eventHub = {
1682
+ error: makeEventSource(),
1683
+ connection: makeEventSource(),
1684
+ events: {}
1685
+ };
1686
+ let managedSocket = null;
1687
+ function createManagedSocket(roomId) {
1688
+ managedSocket = new ManagedSocket(
1689
+ {
1690
+ // TODO: We're trying to (re)connect based on the first roomId that the user is asking for
1691
+ // This is bad because the user might now have access to this room (anymore)
1692
+ // This prevent any future reconnection to the websocket server
1693
+ // We need to find a better way to handle the first (re)connection
1694
+ // (Could it be based on the current listeners)
1695
+ authenticate: () => authManager.getAuthValue("room:read", roomId),
1696
+ createSocket: (authValue) => new WebSocket(
1697
+ `${serverEndpoint}?token=${authValue.type === "secret" ? authValue.token.raw : authValue.publicApiKey}`
1698
+ )
1699
+ },
1700
+ true,
1701
+ false
1702
+ );
1703
+ managedSocket.events.statusDidChange.subscribe((status) => {
1704
+ if (status === "connected") {
1705
+ for (const roomId2 in eventHub.events) {
1706
+ const eventSource2 = eventHub.events[roomId2];
1707
+ if (eventSource2.count() > 0) {
1708
+ subscribeToRoomEvents(roomId2);
1709
+ }
1710
+ }
1711
+ }
1712
+ eventHub.connection.notify(status);
1713
+ });
1714
+ managedSocket.events.onLiveblocksError.subscribe(eventHub.error.notify);
1715
+ managedSocket.events.onMessage.subscribe((event) => {
1716
+ if (typeof event.data !== "string") {
1717
+ return;
1718
+ }
1719
+ const jsonEvent = tryParseJson(event.data);
1720
+ if (jsonEvent !== void 0 && isJsonObject(jsonEvent) && typeof jsonEvent.roomId === "string") {
1721
+ eventHub.events[jsonEvent.roomId].notify(jsonEvent);
1722
+ }
1723
+ });
1724
+ managedSocket.connect();
1725
+ }
1726
+ function getOrCreateEventSource(roomId) {
1727
+ let eventSource2 = eventHub.events[roomId];
1728
+ if (eventSource2 === void 0) {
1729
+ eventSource2 = makeEventSource();
1730
+ eventHub.events[roomId] = eventSource2;
1731
+ }
1732
+ return eventSource2;
1733
+ }
1734
+ async function subscribeToRoomEvents(roomId) {
1735
+ const authValue = await authManager.getAuthValue("room:read", roomId);
1736
+ if (managedSocket === null || managedSocket.getStatus() !== "connected") {
1737
+ return;
1738
+ }
1739
+ managedSocket.send(
1740
+ JSON.stringify({
1741
+ type: "subscribeToRooms",
1742
+ rooms: [roomId],
1743
+ token: authValueToString(authValue)
1744
+ })
1745
+ );
1746
+ }
1747
+ return {
1748
+ subscribeToEvents: (roomId, callback) => {
1749
+ if (!managedSocket) {
1750
+ createManagedSocket(roomId);
1751
+ }
1752
+ subscribeToRoomEvents(roomId);
1753
+ return getOrCreateEventSource(roomId).subscribe(callback);
1754
+ },
1755
+ error: eventHub.error.observable,
1756
+ connection: eventHub.connection.observable
1757
+ };
1758
+ }
1759
+
1760
+ // src/lib/position.ts
1761
+ var MIN_CODE = 32;
1762
+ var MAX_CODE = 126;
1763
+ var NUM_DIGITS = MAX_CODE - MIN_CODE + 1;
1764
+ var ZERO = nthDigit(0);
1765
+ var ONE = nthDigit(1);
1766
+ var ZERO_NINE = ZERO + nthDigit(-1);
1767
+ function nthDigit(n) {
1768
+ const code = MIN_CODE + (n < 0 ? NUM_DIGITS + n : n);
1769
+ if (code < MIN_CODE || code > MAX_CODE) {
1770
+ throw new Error(`Invalid n value: ${n}`);
1771
+ }
1772
+ return String.fromCharCode(code);
1773
+ }
1774
+ function makePosition(x, y) {
1775
+ if (x !== void 0 && y !== void 0) {
1776
+ return between(x, y);
1777
+ } else if (x !== void 0) {
1778
+ return after(x);
1779
+ } else if (y !== void 0) {
1780
+ return before(y);
1781
+ } else {
1782
+ return ONE;
1783
+ }
1784
+ }
1785
+ function before(pos) {
1786
+ const lastIndex = pos.length - 1;
1787
+ for (let i = 0; i <= lastIndex; i++) {
1788
+ const code = pos.charCodeAt(i);
1789
+ if (code <= MIN_CODE) {
1790
+ continue;
1791
+ }
1792
+ if (i === lastIndex) {
1793
+ if (code === MIN_CODE + 1) {
1794
+ return pos.substring(0, i) + ZERO_NINE;
1795
+ } else {
1796
+ return pos.substring(0, i) + String.fromCharCode(code - 1);
1797
+ }
1798
+ } else {
1799
+ return pos.substring(0, i + 1);
1800
+ }
1801
+ }
1802
+ return ONE;
1803
+ }
1804
+ function after(pos) {
1805
+ for (let i = 0; i <= pos.length - 1; i++) {
1806
+ const code = pos.charCodeAt(i);
1807
+ if (code >= MAX_CODE) {
1808
+ continue;
1809
+ }
1810
+ return pos.substring(0, i) + String.fromCharCode(code + 1);
1811
+ }
1812
+ return pos + ONE;
1813
+ }
1814
+ function between(lo, hi) {
1815
+ if (lo < hi) {
1816
+ return _between(lo, hi);
1817
+ } else if (lo > hi) {
1818
+ return _between(hi, lo);
1819
+ } else {
1820
+ throw new Error("Cannot compute value between two equal positions");
1821
+ }
1822
+ }
1823
+ function _between(lo, hi) {
1824
+ let index = 0;
1825
+ const loLen = lo.length;
1826
+ const hiLen = hi.length;
1827
+ while (true) {
1828
+ const loCode = index < loLen ? lo.charCodeAt(index) : MIN_CODE;
1829
+ const hiCode = index < hiLen ? hi.charCodeAt(index) : MAX_CODE;
1830
+ if (loCode === hiCode) {
1831
+ index++;
1832
+ continue;
1833
+ }
1834
+ if (hiCode - loCode === 1) {
1835
+ const prefix = lo.substring(0, index + 1);
1836
+ const suffix = lo.substring(index + 1);
1837
+ const nines = "";
1838
+ return prefix + _between(suffix, nines);
1839
+ } else {
1840
+ return takeN(lo, index) + String.fromCharCode(hiCode + loCode >> 1);
1841
+ }
1842
+ }
1843
+ }
1844
+ function takeN(pos, n) {
1845
+ return n < pos.length ? pos.substring(0, n) : pos + ZERO.repeat(n - pos.length);
1846
+ }
1847
+ var MIN_NON_ZERO_CODE = MIN_CODE + 1;
1848
+ function isPos(str) {
1849
+ if (str === "") {
1850
+ return false;
1851
+ }
1852
+ const lastIdx = str.length - 1;
1853
+ const last = str.charCodeAt(lastIdx);
1854
+ if (last < MIN_NON_ZERO_CODE || last > MAX_CODE) {
1855
+ return false;
1856
+ }
1857
+ for (let i = 0; i < lastIdx; i++) {
1858
+ const code = str.charCodeAt(i);
1859
+ if (code < MIN_CODE || code > MAX_CODE) {
1860
+ return false;
1861
+ }
1862
+ }
1863
+ return true;
1864
+ }
1865
+ function convertToPos(str) {
1866
+ const codes = [];
1867
+ for (let i = 0; i < str.length; i++) {
1868
+ const code = str.charCodeAt(i);
1869
+ codes.push(code < MIN_CODE ? MIN_CODE : code > MAX_CODE ? MAX_CODE : code);
1870
+ }
1871
+ while (codes.length > 0 && codes[codes.length - 1] === MIN_CODE) {
1872
+ codes.length--;
1873
+ }
1874
+ return codes.length > 0 ? String.fromCharCode(...codes) : (
1478
1875
  // Edge case: the str was a 0-only string, which is invalid. Default back to .1
1479
1876
  ONE
1480
1877
  );
@@ -1721,7 +2118,7 @@ var LiveRegister = class _LiveRegister extends AbstractCrdt {
1721
2118
  return [
1722
2119
  {
1723
2120
  type: 8 /* CREATE_REGISTER */,
1724
- opId: _optionalChain([pool, 'optionalAccess', _40 => _40.generateOpId, 'call', _41 => _41()]),
2121
+ opId: _optionalChain([pool, 'optionalAccess', _43 => _43.generateOpId, 'call', _44 => _44()]),
1725
2122
  id: this._id,
1726
2123
  parentId,
1727
2124
  parentKey,
@@ -1812,7 +2209,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
1812
2209
  const ops = [];
1813
2210
  const op = {
1814
2211
  id: this._id,
1815
- opId: _optionalChain([pool, 'optionalAccess', _42 => _42.generateOpId, 'call', _43 => _43()]),
2212
+ opId: _optionalChain([pool, 'optionalAccess', _45 => _45.generateOpId, 'call', _46 => _46()]),
1816
2213
  type: 2 /* CREATE_LIST */,
1817
2214
  parentId,
1818
2215
  parentKey
@@ -2080,7 +2477,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2080
2477
  _applyInsertUndoRedo(op) {
2081
2478
  const { id, parentKey: key } = op;
2082
2479
  const child = creationOpToLiveNode(op);
2083
- if (_optionalChain([this, 'access', _44 => _44._pool, 'optionalAccess', _45 => _45.getNode, 'call', _46 => _46(id)]) !== void 0) {
2480
+ if (_optionalChain([this, 'access', _47 => _47._pool, 'optionalAccess', _48 => _48.getNode, 'call', _49 => _49(id)]) !== void 0) {
2084
2481
  return { modified: false };
2085
2482
  }
2086
2483
  child._attach(id, nn(this._pool));
@@ -2088,8 +2485,8 @@ var LiveList = class _LiveList extends AbstractCrdt {
2088
2485
  const existingItemIndex = this._indexOfPosition(key);
2089
2486
  let newKey = key;
2090
2487
  if (existingItemIndex !== -1) {
2091
- const before2 = _optionalChain([this, 'access', _47 => _47._items, 'access', _48 => _48[existingItemIndex], 'optionalAccess', _49 => _49._parentPos]);
2092
- const after2 = _optionalChain([this, 'access', _50 => _50._items, 'access', _51 => _51[existingItemIndex + 1], 'optionalAccess', _52 => _52._parentPos]);
2488
+ const before2 = _optionalChain([this, 'access', _50 => _50._items, 'access', _51 => _51[existingItemIndex], 'optionalAccess', _52 => _52._parentPos]);
2489
+ const after2 = _optionalChain([this, 'access', _53 => _53._items, 'access', _54 => _54[existingItemIndex + 1], 'optionalAccess', _55 => _55._parentPos]);
2093
2490
  newKey = makePosition(before2, after2);
2094
2491
  child._setParentLink(this, newKey);
2095
2492
  }
@@ -2104,7 +2501,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2104
2501
  _applySetUndoRedo(op) {
2105
2502
  const { id, parentKey: key } = op;
2106
2503
  const child = creationOpToLiveNode(op);
2107
- if (_optionalChain([this, 'access', _53 => _53._pool, 'optionalAccess', _54 => _54.getNode, 'call', _55 => _55(id)]) !== void 0) {
2504
+ if (_optionalChain([this, 'access', _56 => _56._pool, 'optionalAccess', _57 => _57.getNode, 'call', _58 => _58(id)]) !== void 0) {
2108
2505
  return { modified: false };
2109
2506
  }
2110
2507
  this._unacknowledgedSets.set(key, nn(op.opId));
@@ -2226,7 +2623,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2226
2623
  } else {
2227
2624
  this._items[existingItemIndex]._setParentLink(
2228
2625
  this,
2229
- makePosition(newKey, _optionalChain([this, 'access', _56 => _56._items, 'access', _57 => _57[existingItemIndex + 1], 'optionalAccess', _58 => _58._parentPos]))
2626
+ makePosition(newKey, _optionalChain([this, 'access', _59 => _59._items, 'access', _60 => _60[existingItemIndex + 1], 'optionalAccess', _61 => _61._parentPos]))
2230
2627
  );
2231
2628
  const previousIndex = this._items.indexOf(child);
2232
2629
  child._setParentLink(this, newKey);
@@ -2252,7 +2649,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2252
2649
  if (existingItemIndex !== -1) {
2253
2650
  this._items[existingItemIndex]._setParentLink(
2254
2651
  this,
2255
- makePosition(newKey, _optionalChain([this, 'access', _59 => _59._items, 'access', _60 => _60[existingItemIndex + 1], 'optionalAccess', _61 => _61._parentPos]))
2652
+ makePosition(newKey, _optionalChain([this, 'access', _62 => _62._items, 'access', _63 => _63[existingItemIndex + 1], 'optionalAccess', _64 => _64._parentPos]))
2256
2653
  );
2257
2654
  }
2258
2655
  child._setParentLink(this, newKey);
@@ -2271,7 +2668,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2271
2668
  if (existingItemIndex !== -1) {
2272
2669
  this._items[existingItemIndex]._setParentLink(
2273
2670
  this,
2274
- makePosition(newKey, _optionalChain([this, 'access', _62 => _62._items, 'access', _63 => _63[existingItemIndex + 1], 'optionalAccess', _64 => _64._parentPos]))
2671
+ makePosition(newKey, _optionalChain([this, 'access', _65 => _65._items, 'access', _66 => _66[existingItemIndex + 1], 'optionalAccess', _67 => _67._parentPos]))
2275
2672
  );
2276
2673
  }
2277
2674
  child._setParentLink(this, newKey);
@@ -2299,7 +2696,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2299
2696
  if (existingItemIndex !== -1) {
2300
2697
  this._items[existingItemIndex]._setParentLink(
2301
2698
  this,
2302
- makePosition(newKey, _optionalChain([this, 'access', _65 => _65._items, 'access', _66 => _66[existingItemIndex + 1], 'optionalAccess', _67 => _67._parentPos]))
2699
+ makePosition(newKey, _optionalChain([this, 'access', _68 => _68._items, 'access', _69 => _69[existingItemIndex + 1], 'optionalAccess', _70 => _70._parentPos]))
2303
2700
  );
2304
2701
  }
2305
2702
  child._setParentLink(this, newKey);
@@ -2357,7 +2754,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2357
2754
  * @param element The element to add to the end of the LiveList.
2358
2755
  */
2359
2756
  push(element) {
2360
- _optionalChain([this, 'access', _68 => _68._pool, 'optionalAccess', _69 => _69.assertStorageIsWritable, 'call', _70 => _70()]);
2757
+ _optionalChain([this, 'access', _71 => _71._pool, 'optionalAccess', _72 => _72.assertStorageIsWritable, 'call', _73 => _73()]);
2361
2758
  return this.insert(element, this.length);
2362
2759
  }
2363
2760
  /**
@@ -2366,7 +2763,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2366
2763
  * @param index The index at which you want to insert the element.
2367
2764
  */
2368
2765
  insert(element, index) {
2369
- _optionalChain([this, 'access', _71 => _71._pool, 'optionalAccess', _72 => _72.assertStorageIsWritable, 'call', _73 => _73()]);
2766
+ _optionalChain([this, 'access', _74 => _74._pool, 'optionalAccess', _75 => _75.assertStorageIsWritable, 'call', _76 => _76()]);
2370
2767
  if (index < 0 || index > this._items.length) {
2371
2768
  throw new Error(
2372
2769
  `Cannot insert list item at index "${index}". index should be between 0 and ${this._items.length}`
@@ -2396,7 +2793,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2396
2793
  * @param targetIndex The index where the element should be after moving.
2397
2794
  */
2398
2795
  move(index, targetIndex) {
2399
- _optionalChain([this, 'access', _74 => _74._pool, 'optionalAccess', _75 => _75.assertStorageIsWritable, 'call', _76 => _76()]);
2796
+ _optionalChain([this, 'access', _77 => _77._pool, 'optionalAccess', _78 => _78.assertStorageIsWritable, 'call', _79 => _79()]);
2400
2797
  if (targetIndex < 0) {
2401
2798
  throw new Error("targetIndex cannot be less than 0");
2402
2799
  }
@@ -2454,7 +2851,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2454
2851
  * @param index The index of the element to delete
2455
2852
  */
2456
2853
  delete(index) {
2457
- _optionalChain([this, 'access', _77 => _77._pool, 'optionalAccess', _78 => _78.assertStorageIsWritable, 'call', _79 => _79()]);
2854
+ _optionalChain([this, 'access', _80 => _80._pool, 'optionalAccess', _81 => _81.assertStorageIsWritable, 'call', _82 => _82()]);
2458
2855
  if (index < 0 || index >= this._items.length) {
2459
2856
  throw new Error(
2460
2857
  `Cannot delete list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -2487,7 +2884,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2487
2884
  }
2488
2885
  }
2489
2886
  clear() {
2490
- _optionalChain([this, 'access', _80 => _80._pool, 'optionalAccess', _81 => _81.assertStorageIsWritable, 'call', _82 => _82()]);
2887
+ _optionalChain([this, 'access', _83 => _83._pool, 'optionalAccess', _84 => _84.assertStorageIsWritable, 'call', _85 => _85()]);
2491
2888
  if (this._pool) {
2492
2889
  const ops = [];
2493
2890
  const reverseOps = [];
@@ -2521,7 +2918,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2521
2918
  }
2522
2919
  }
2523
2920
  set(index, item) {
2524
- _optionalChain([this, 'access', _83 => _83._pool, 'optionalAccess', _84 => _84.assertStorageIsWritable, 'call', _85 => _85()]);
2921
+ _optionalChain([this, 'access', _86 => _86._pool, 'optionalAccess', _87 => _87.assertStorageIsWritable, 'call', _88 => _88()]);
2525
2922
  if (index < 0 || index >= this._items.length) {
2526
2923
  throw new Error(
2527
2924
  `Cannot set list item at index "${index}". index should be between 0 and ${this._items.length - 1}`
@@ -2669,7 +3066,7 @@ var LiveList = class _LiveList extends AbstractCrdt {
2669
3066
  _shiftItemPosition(index, key) {
2670
3067
  const shiftedPosition = makePosition(
2671
3068
  key,
2672
- this._items.length > index + 1 ? _optionalChain([this, 'access', _86 => _86._items, 'access', _87 => _87[index + 1], 'optionalAccess', _88 => _88._parentPos]) : void 0
3069
+ this._items.length > index + 1 ? _optionalChain([this, 'access', _89 => _89._items, 'access', _90 => _90[index + 1], 'optionalAccess', _91 => _91._parentPos]) : void 0
2673
3070
  );
2674
3071
  this._items[index]._setParentLink(this, shiftedPosition);
2675
3072
  }
@@ -2795,7 +3192,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
2795
3192
  const ops = [];
2796
3193
  const op = {
2797
3194
  id: this._id,
2798
- opId: _optionalChain([pool, 'optionalAccess', _89 => _89.generateOpId, 'call', _90 => _90()]),
3195
+ opId: _optionalChain([pool, 'optionalAccess', _92 => _92.generateOpId, 'call', _93 => _93()]),
2799
3196
  type: 7 /* CREATE_MAP */,
2800
3197
  parentId,
2801
3198
  parentKey
@@ -2942,7 +3339,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
2942
3339
  * @param value The value of the element to add. Should be serializable to JSON.
2943
3340
  */
2944
3341
  set(key, value) {
2945
- _optionalChain([this, 'access', _91 => _91._pool, 'optionalAccess', _92 => _92.assertStorageIsWritable, 'call', _93 => _93()]);
3342
+ _optionalChain([this, 'access', _94 => _94._pool, 'optionalAccess', _95 => _95.assertStorageIsWritable, 'call', _96 => _96()]);
2946
3343
  const oldValue = this._map.get(key);
2947
3344
  if (oldValue) {
2948
3345
  oldValue._detach();
@@ -2988,7 +3385,7 @@ var LiveMap = class _LiveMap extends AbstractCrdt {
2988
3385
  * @returns true if an element existed and has been removed, or false if the element does not exist.
2989
3386
  */
2990
3387
  delete(key) {
2991
- _optionalChain([this, 'access', _94 => _94._pool, 'optionalAccess', _95 => _95.assertStorageIsWritable, 'call', _96 => _96()]);
3388
+ _optionalChain([this, 'access', _97 => _97._pool, 'optionalAccess', _98 => _98.assertStorageIsWritable, 'call', _99 => _99()]);
2992
3389
  const item = this._map.get(key);
2993
3390
  if (item === void 0) {
2994
3391
  return false;
@@ -3162,7 +3559,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
3162
3559
  if (this._id === void 0) {
3163
3560
  throw new Error("Cannot serialize item is not attached");
3164
3561
  }
3165
- const opId = _optionalChain([pool, 'optionalAccess', _97 => _97.generateOpId, 'call', _98 => _98()]);
3562
+ const opId = _optionalChain([pool, 'optionalAccess', _100 => _100.generateOpId, 'call', _101 => _101()]);
3166
3563
  const ops = [];
3167
3564
  const op = parentId !== void 0 && parentKey !== void 0 ? {
3168
3565
  type: 4 /* CREATE_OBJECT */,
@@ -3443,7 +3840,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
3443
3840
  * @param value The value of the property to add
3444
3841
  */
3445
3842
  set(key, value) {
3446
- _optionalChain([this, 'access', _99 => _99._pool, 'optionalAccess', _100 => _100.assertStorageIsWritable, 'call', _101 => _101()]);
3843
+ _optionalChain([this, 'access', _102 => _102._pool, 'optionalAccess', _103 => _103.assertStorageIsWritable, 'call', _104 => _104()]);
3447
3844
  this.update({ [key]: value });
3448
3845
  }
3449
3846
  /**
@@ -3458,7 +3855,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
3458
3855
  * @param key The key of the property to delete
3459
3856
  */
3460
3857
  delete(key) {
3461
- _optionalChain([this, 'access', _102 => _102._pool, 'optionalAccess', _103 => _103.assertStorageIsWritable, 'call', _104 => _104()]);
3858
+ _optionalChain([this, 'access', _105 => _105._pool, 'optionalAccess', _106 => _106.assertStorageIsWritable, 'call', _107 => _107()]);
3462
3859
  const keyAsString = key;
3463
3860
  const oldValue = this._map.get(keyAsString);
3464
3861
  if (oldValue === void 0) {
@@ -3511,7 +3908,7 @@ var LiveObject = class _LiveObject extends AbstractCrdt {
3511
3908
  * @param patch The object used to overrides properties
3512
3909
  */
3513
3910
  update(patch) {
3514
- _optionalChain([this, 'access', _105 => _105._pool, 'optionalAccess', _106 => _106.assertStorageIsWritable, 'call', _107 => _107()]);
3911
+ _optionalChain([this, 'access', _108 => _108._pool, 'optionalAccess', _109 => _109.assertStorageIsWritable, 'call', _110 => _110()]);
3515
3912
  if (this._pool === void 0 || this._id === void 0) {
3516
3913
  for (const key in patch) {
3517
3914
  const newValue = patch[key];
@@ -3881,41 +4278,6 @@ function captureStackTrace(msg, traceRoot) {
3881
4278
  return errorLike.stack;
3882
4279
  }
3883
4280
 
3884
- // src/lib/Json.ts
3885
- function isJsonScalar(data) {
3886
- return data === null || typeof data === "string" || typeof data === "number" || typeof data === "boolean";
3887
- }
3888
- function isJsonArray(data) {
3889
- return Array.isArray(data);
3890
- }
3891
- function isJsonObject(data) {
3892
- return !isJsonScalar(data) && !isJsonArray(data);
3893
- }
3894
-
3895
- // src/protocol/AuthToken.ts
3896
- function isStringList(value) {
3897
- return Array.isArray(value) && value.every((i) => typeof i === "string");
3898
- }
3899
- function isMinimalTokenPayload(data) {
3900
- return isPlainObject(data) && typeof data.actor === "number" && (data.id === void 0 || typeof data.id === "string") && isStringList(data.scopes);
3901
- }
3902
- function parseAuthToken(rawTokenString) {
3903
- const tokenParts = rawTokenString.split(".");
3904
- if (tokenParts.length !== 3) {
3905
- throw new Error("Authentication error: invalid JWT token");
3906
- }
3907
- const payload = tryParseJson(b64decode(tokenParts[1]));
3908
- if (!(payload && isMinimalTokenPayload(payload))) {
3909
- throw new Error(
3910
- "Authentication error: we expected a room token but did not get one. Hint: if you are using a callback, ensure the room is passed when creating the token. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientCallback"
3911
- );
3912
- }
3913
- return {
3914
- raw: rawTokenString,
3915
- parsed: payload
3916
- };
3917
- }
3918
-
3919
4281
  // src/protocol/ClientMsg.ts
3920
4282
  var ClientMsgCode = /* @__PURE__ */ ((ClientMsgCode2) => {
3921
4283
  ClientMsgCode2[ClientMsgCode2["UPDATE_PRESENCE"] = 100] = "UPDATE_PRESENCE";
@@ -3927,20 +4289,6 @@ var ClientMsgCode = /* @__PURE__ */ ((ClientMsgCode2) => {
3927
4289
  return ClientMsgCode2;
3928
4290
  })(ClientMsgCode || {});
3929
4291
 
3930
- // src/protocol/ServerMsg.ts
3931
- var ServerMsgCode = /* @__PURE__ */ ((ServerMsgCode2) => {
3932
- ServerMsgCode2[ServerMsgCode2["UPDATE_PRESENCE"] = 100] = "UPDATE_PRESENCE";
3933
- ServerMsgCode2[ServerMsgCode2["USER_JOINED"] = 101] = "USER_JOINED";
3934
- ServerMsgCode2[ServerMsgCode2["USER_LEFT"] = 102] = "USER_LEFT";
3935
- ServerMsgCode2[ServerMsgCode2["BROADCASTED_EVENT"] = 103] = "BROADCASTED_EVENT";
3936
- ServerMsgCode2[ServerMsgCode2["ROOM_STATE"] = 104] = "ROOM_STATE";
3937
- ServerMsgCode2[ServerMsgCode2["INITIAL_STORAGE_STATE"] = 200] = "INITIAL_STORAGE_STATE";
3938
- ServerMsgCode2[ServerMsgCode2["UPDATE_STORAGE"] = 201] = "UPDATE_STORAGE";
3939
- ServerMsgCode2[ServerMsgCode2["REJECT_STORAGE_OP"] = 299] = "REJECT_STORAGE_OP";
3940
- ServerMsgCode2[ServerMsgCode2["UPDATE_YDOC"] = 300] = "UPDATE_YDOC";
3941
- return ServerMsgCode2;
3942
- })(ServerMsgCode || {});
3943
-
3944
4292
  // src/lib/LegacyArray.ts
3945
4293
  function asArrayWithLegacyMethods(arr) {
3946
4294
  Object.defineProperty(arr, "count", {
@@ -3992,7 +4340,19 @@ var ImmutableRef = class {
3992
4340
 
3993
4341
  // src/refs/OthersRef.ts
3994
4342
  function makeUser(conn, presence) {
3995
- return freeze(compactObject({ ...conn, presence }));
4343
+ const { connectionId, id, info } = conn;
4344
+ const canWrite = canWriteStorage(conn.scopes);
4345
+ return freeze(
4346
+ compactObject({
4347
+ connectionId,
4348
+ id,
4349
+ info,
4350
+ canWrite,
4351
+ isReadOnly: !canWrite,
4352
+ // Deprecated, kept for backward-compatibility
4353
+ presence
4354
+ })
4355
+ );
3996
4356
  }
3997
4357
  var OthersRef = class extends ImmutableRef {
3998
4358
  //
@@ -4000,50 +4360,53 @@ var OthersRef = class extends ImmutableRef {
4000
4360
  //
4001
4361
  constructor() {
4002
4362
  super();
4003
- this._connections = {};
4004
- this._presences = {};
4005
- this._users = {};
4363
+ this._connections = /* @__PURE__ */ new Map();
4364
+ this._presences = /* @__PURE__ */ new Map();
4365
+ this._users = /* @__PURE__ */ new Map();
4366
+ }
4367
+ connectionIds() {
4368
+ return this._connections.keys();
4006
4369
  }
4007
4370
  /** @internal */
4008
4371
  _toImmutable() {
4009
4372
  const users = compact(
4010
- Object.keys(this._presences).map(
4373
+ Array.from(this._presences.keys()).map(
4011
4374
  (connectionId) => this.getUser(Number(connectionId))
4012
4375
  )
4013
4376
  );
4014
4377
  return asArrayWithLegacyMethods(users);
4015
4378
  }
4016
4379
  clearOthers() {
4017
- this._connections = {};
4018
- this._presences = {};
4019
- this._users = {};
4380
+ this._connections = /* @__PURE__ */ new Map();
4381
+ this._presences = /* @__PURE__ */ new Map();
4382
+ this._users = /* @__PURE__ */ new Map();
4020
4383
  this.invalidate();
4021
4384
  }
4022
4385
  /** @internal */
4023
4386
  _getUser(connectionId) {
4024
- const conn = this._connections[connectionId];
4025
- const presence = this._presences[connectionId];
4387
+ const conn = this._connections.get(connectionId);
4388
+ const presence = this._presences.get(connectionId);
4026
4389
  if (conn !== void 0 && presence !== void 0) {
4027
4390
  return makeUser(conn, presence);
4028
4391
  }
4029
4392
  return void 0;
4030
4393
  }
4031
4394
  getUser(connectionId) {
4032
- const cachedUser = this._users[connectionId];
4395
+ const cachedUser = this._users.get(connectionId);
4033
4396
  if (cachedUser) {
4034
4397
  return cachedUser;
4035
4398
  }
4036
4399
  const computedUser = this._getUser(connectionId);
4037
4400
  if (computedUser) {
4038
- this._users[connectionId] = computedUser;
4401
+ this._users.set(connectionId, computedUser);
4039
4402
  return computedUser;
4040
4403
  }
4041
4404
  return void 0;
4042
4405
  }
4043
4406
  /** @internal */
4044
4407
  _invalidateUser(connectionId) {
4045
- if (this._users[connectionId] !== void 0) {
4046
- delete this._users[connectionId];
4408
+ if (this._users.has(connectionId)) {
4409
+ this._users.delete(connectionId);
4047
4410
  }
4048
4411
  this.invalidate();
4049
4412
  }
@@ -4051,14 +4414,17 @@ var OthersRef = class extends ImmutableRef {
4051
4414
  * Records a known connection. This records the connection ID and the
4052
4415
  * associated metadata.
4053
4416
  */
4054
- setConnection(connectionId, metaUserId, metaUserInfo, metaIsReadonly) {
4055
- this._connections[connectionId] = freeze({
4417
+ setConnection(connectionId, metaUserId, metaUserInfo, scopes) {
4418
+ this._connections.set(
4056
4419
  connectionId,
4057
- id: metaUserId,
4058
- info: metaUserInfo,
4059
- isReadOnly: metaIsReadonly
4060
- });
4061
- if (this._presences[connectionId] !== void 0) {
4420
+ freeze({
4421
+ connectionId,
4422
+ id: metaUserId,
4423
+ info: metaUserInfo,
4424
+ scopes
4425
+ })
4426
+ );
4427
+ if (this._presences.has(connectionId)) {
4062
4428
  this._invalidateUser(connectionId);
4063
4429
  }
4064
4430
  }
@@ -4067,8 +4433,8 @@ var OthersRef = class extends ImmutableRef {
4067
4433
  * the presence information.
4068
4434
  */
4069
4435
  removeConnection(connectionId) {
4070
- delete this._connections[connectionId];
4071
- delete this._presences[connectionId];
4436
+ this._connections.delete(connectionId);
4437
+ this._presences.delete(connectionId);
4072
4438
  this._invalidateUser(connectionId);
4073
4439
  }
4074
4440
  /**
@@ -4076,8 +4442,8 @@ var OthersRef = class extends ImmutableRef {
4076
4442
  * its known presence data is overwritten.
4077
4443
  */
4078
4444
  setOther(connectionId, presence) {
4079
- this._presences[connectionId] = freeze(compactObject(presence));
4080
- if (this._connections[connectionId] !== void 0) {
4445
+ this._presences.set(connectionId, freeze(compactObject(presence)));
4446
+ if (this._connections.has(connectionId)) {
4081
4447
  this._invalidateUser(connectionId);
4082
4448
  }
4083
4449
  }
@@ -4087,13 +4453,13 @@ var OthersRef = class extends ImmutableRef {
4087
4453
  * full .setOther() call first.
4088
4454
  */
4089
4455
  patchOther(connectionId, patch) {
4090
- const oldPresence = this._presences[connectionId];
4456
+ const oldPresence = this._presences.get(connectionId);
4091
4457
  if (oldPresence === void 0) {
4092
4458
  return;
4093
4459
  }
4094
4460
  const newPresence = merge(oldPresence, patch);
4095
4461
  if (oldPresence !== newPresence) {
4096
- this._presences[connectionId] = freeze(newPresence);
4462
+ this._presences.set(connectionId, freeze(newPresence));
4097
4463
  this._invalidateUser(connectionId);
4098
4464
  }
4099
4465
  }
@@ -4173,17 +4539,7 @@ function userToTreeNode(key, user) {
4173
4539
  function createRoom(options, config) {
4174
4540
  const initialPresence = typeof options.initialPresence === "function" ? options.initialPresence(config.roomId) : options.initialPresence;
4175
4541
  const initialStorage = typeof options.initialStorage === "function" ? options.initialStorage(config.roomId) : options.initialStorage;
4176
- const delegates = _nullishCoalesce(config.delegates, () => ( {
4177
- authenticate: makeAuthDelegateForRoom(
4178
- config.roomId,
4179
- config.authentication,
4180
- _optionalChain([config, 'access', _108 => _108.polyfills, 'optionalAccess', _109 => _109.fetch])
4181
- ),
4182
- createSocket: makeCreateSocketDelegateForRoom(
4183
- config.liveblocksServer,
4184
- _optionalChain([config, 'access', _110 => _110.polyfills, 'optionalAccess', _111 => _111.WebSocket])
4185
- )
4186
- }));
4542
+ const delegates = config.delegates;
4187
4543
  const managedSocket = new ManagedSocket(
4188
4544
  delegates,
4189
4545
  config.enableDebugLogging
@@ -4202,8 +4558,9 @@ function createRoom(options, config) {
4202
4558
  messages: [],
4203
4559
  storageOperations: []
4204
4560
  },
4205
- sessionInfo: new ValueRef(null),
4206
- me: new PatchableRef(initialPresence),
4561
+ staticSessionInfo: new ValueRef(null),
4562
+ dynamicSessionInfo: new ValueRef(null),
4563
+ myPresence: new PatchableRef(initialPresence),
4207
4564
  others: new OthersRef(),
4208
4565
  initialStorage,
4209
4566
  idFactory: null,
@@ -4222,18 +4579,26 @@ function createRoom(options, config) {
4222
4579
  };
4223
4580
  const doNotBatchUpdates = (cb) => cb();
4224
4581
  const batchUpdates = _nullishCoalesce(config.unstable_batchedUpdates, () => ( doNotBatchUpdates));
4225
- let lastToken;
4582
+ let lastTokenKey;
4226
4583
  function onStatusDidChange(newStatus) {
4227
- const token = _optionalChain([managedSocket, 'access', _112 => _112.token, 'optionalAccess', _113 => _113.parsed]);
4228
- if (token !== void 0 && token !== lastToken) {
4229
- context.sessionInfo.set({
4230
- userInfo: token.info,
4231
- userId: token.id,
4232
- // NOTE: In the future, these fields will get assigned in the connection phase
4233
- actor: token.actor,
4234
- isReadOnly: isStorageReadOnly(token.scopes)
4235
- });
4236
- lastToken = token;
4584
+ const authValue = managedSocket.authValue;
4585
+ if (authValue !== null) {
4586
+ const tokenKey = authValue.type === "secret" ? authValue.token.raw : authValue.publicApiKey;
4587
+ if (tokenKey !== lastTokenKey) {
4588
+ lastTokenKey = tokenKey;
4589
+ if (authValue.type === "secret") {
4590
+ const token = authValue.token.parsed;
4591
+ context.staticSessionInfo.set({
4592
+ userId: token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.id : token.uid,
4593
+ userInfo: token.k === "sec-legacy" /* SECRET_LEGACY */ ? token.info : token.ui
4594
+ });
4595
+ } else {
4596
+ context.staticSessionInfo.set({
4597
+ userId: void 0,
4598
+ userInfo: void 0
4599
+ });
4600
+ }
4601
+ }
4237
4602
  }
4238
4603
  batchUpdates(() => {
4239
4604
  eventHub.status.notify(newStatus);
@@ -4270,20 +4635,15 @@ function createRoom(options, config) {
4270
4635
  }
4271
4636
  }
4272
4637
  function onDidConnect() {
4273
- const sessionInfo = context.sessionInfo.current;
4274
- if (sessionInfo === null) {
4275
- throw new Error("Unexpected missing session info");
4276
- }
4277
4638
  context.buffer.presenceUpdates = {
4278
4639
  type: "full",
4279
4640
  data: (
4280
4641
  // Because context.me.current is a readonly object, we'll have to
4281
4642
  // make a copy here. Otherwise, type errors happen later when
4282
4643
  // "patching" my presence.
4283
- { ...context.me.current }
4644
+ { ...context.myPresence.current }
4284
4645
  )
4285
4646
  };
4286
- context.idFactory = makeIdFactory(sessionInfo.actor);
4287
4647
  if (_getStorage$ !== null) {
4288
4648
  refreshStorage({ flush: false });
4289
4649
  }
@@ -4348,7 +4708,12 @@ function createRoom(options, config) {
4348
4708
  }
4349
4709
  },
4350
4710
  assertStorageIsWritable: () => {
4351
- if (_optionalChain([context, 'access', _114 => _114.sessionInfo, 'access', _115 => _115.current, 'optionalAccess', _116 => _116.isReadOnly])) {
4711
+ const scopes = _optionalChain([context, 'access', _111 => _111.dynamicSessionInfo, 'access', _112 => _112.current, 'optionalAccess', _113 => _113.scopes]);
4712
+ if (scopes === void 0) {
4713
+ return;
4714
+ }
4715
+ const canWrite = canWriteStorage(scopes);
4716
+ if (!canWrite) {
4352
4717
  throw new Error(
4353
4718
  "Cannot write to storage with a read only user, please ensure the user has write permissions"
4354
4719
  );
@@ -4376,12 +4741,13 @@ function createRoom(options, config) {
4376
4741
  const message = JSON.stringify(messageOrMessages);
4377
4742
  if (config.unstable_fallbackToHTTP) {
4378
4743
  const size = new TextEncoder().encode(message).length;
4379
- if (size > MAX_MESSAGE_SIZE && _optionalChain([managedSocket, 'access', _117 => _117.token, 'optionalAccess', _118 => _118.raw]) && config.httpSendEndpoint) {
4744
+ if (size > MAX_MESSAGE_SIZE && // TODO: support public api key auth in REST API
4745
+ _optionalChain([managedSocket, 'access', _114 => _114.authValue, 'optionalAccess', _115 => _115.type]) === "secret" && config.httpSendEndpoint) {
4380
4746
  void httpSend(
4381
4747
  message,
4382
- managedSocket.token.raw,
4748
+ managedSocket.authValue.token.raw,
4383
4749
  config.httpSendEndpoint,
4384
- _optionalChain([config, 'access', _119 => _119.polyfills, 'optionalAccess', _120 => _120.fetch])
4750
+ _optionalChain([config, 'access', _116 => _116.polyfills, 'optionalAccess', _117 => _117.fetch])
4385
4751
  ).then((resp) => {
4386
4752
  if (!resp.ok && resp.status === 403) {
4387
4753
  managedSocket.reconnect();
@@ -4396,16 +4762,24 @@ function createRoom(options, config) {
4396
4762
  managedSocket.send(message);
4397
4763
  }
4398
4764
  const self = new DerivedRef(
4399
- context.sessionInfo,
4400
- context.me,
4401
- (info, me) => {
4402
- return info !== null ? {
4403
- connectionId: info.actor,
4404
- id: info.userId,
4405
- info: info.userInfo,
4406
- presence: me,
4407
- isReadOnly: info.isReadOnly
4408
- } : null;
4765
+ context.staticSessionInfo,
4766
+ context.dynamicSessionInfo,
4767
+ context.myPresence,
4768
+ (staticSession, dynamicSession, myPresence) => {
4769
+ if (staticSession === null || dynamicSession === null) {
4770
+ return null;
4771
+ } else {
4772
+ const canWrite = canWriteStorage(dynamicSession.scopes);
4773
+ return {
4774
+ connectionId: dynamicSession.actor,
4775
+ id: staticSession.userId,
4776
+ info: staticSession.userInfo,
4777
+ presence: myPresence,
4778
+ canWrite,
4779
+ isReadOnly: !canWrite
4780
+ // Deprecated, kept for backward-compatibility
4781
+ };
4782
+ }
4409
4783
  }
4410
4784
  );
4411
4785
  let _lastSelf;
@@ -4477,7 +4851,7 @@ function createRoom(options, config) {
4477
4851
  }
4478
4852
  if (presence) {
4479
4853
  notifySelfChanged(doNotBatchUpdates);
4480
- eventHub.myPresence.notify(context.me.current);
4854
+ eventHub.myPresence.notify(context.myPresence.current);
4481
4855
  }
4482
4856
  if (storageUpdates.size > 0) {
4483
4857
  const updates = Array.from(storageUpdates.values());
@@ -4487,7 +4861,7 @@ function createRoom(options, config) {
4487
4861
  });
4488
4862
  }
4489
4863
  function getConnectionId() {
4490
- const info = context.sessionInfo.current;
4864
+ const info = context.dynamicSessionInfo.current;
4491
4865
  if (info) {
4492
4866
  return info.actor;
4493
4867
  }
@@ -4516,9 +4890,9 @@ function createRoom(options, config) {
4516
4890
  data: {}
4517
4891
  };
4518
4892
  for (const key in op.data) {
4519
- reverse.data[key] = context.me.current[key];
4893
+ reverse.data[key] = context.myPresence.current[key];
4520
4894
  }
4521
- context.me.patch(op.data);
4895
+ context.myPresence.patch(op.data);
4522
4896
  if (context.buffer.presenceUpdates === null) {
4523
4897
  context.buffer.presenceUpdates = { type: "partial", data: op.data };
4524
4898
  } else {
@@ -4625,11 +4999,11 @@ function createRoom(options, config) {
4625
4999
  continue;
4626
5000
  }
4627
5001
  context.buffer.presenceUpdates.data[key] = overrideValue;
4628
- oldValues[key] = context.me.current[key];
5002
+ oldValues[key] = context.myPresence.current[key];
4629
5003
  }
4630
- context.me.patch(patch);
5004
+ context.myPresence.patch(patch);
4631
5005
  if (context.activeBatch) {
4632
- if (_optionalChain([options2, 'optionalAccess', _121 => _121.addToHistory])) {
5006
+ if (_optionalChain([options2, 'optionalAccess', _118 => _118.addToHistory])) {
4633
5007
  context.activeBatch.reverseOps.unshift({
4634
5008
  type: "presence",
4635
5009
  data: oldValues
@@ -4639,7 +5013,7 @@ function createRoom(options, config) {
4639
5013
  } else {
4640
5014
  flushNowOrSoon();
4641
5015
  batchUpdates(() => {
4642
- if (_optionalChain([options2, 'optionalAccess', _122 => _122.addToHistory])) {
5016
+ if (_optionalChain([options2, 'optionalAccess', _119 => _119.addToHistory])) {
4643
5017
  addToUndoStack(
4644
5018
  [{ type: "presence", data: oldValues }],
4645
5019
  doNotBatchUpdates
@@ -4649,9 +5023,6 @@ function createRoom(options, config) {
4649
5023
  });
4650
5024
  }
4651
5025
  }
4652
- function isStorageReadOnly(scopes) {
4653
- return scopes.includes("room:read" /* Read */) && scopes.includes("room:presence:write" /* PresenceWrite */) && !scopes.includes("room:write" /* Write */);
4654
- }
4655
5026
  function onUpdatePresenceMessage(message) {
4656
5027
  if (message.targetActor !== void 0) {
4657
5028
  const oldUser = context.others.getUser(message.actor);
@@ -4682,11 +5053,17 @@ function createRoom(options, config) {
4682
5053
  }
4683
5054
  return null;
4684
5055
  }
4685
- function onRoomStateMessage(message) {
4686
- for (const connectionId in context.others._connections) {
5056
+ function onRoomStateMessage(message, batchedUpdatesWrapper) {
5057
+ context.dynamicSessionInfo.set({
5058
+ actor: message.actor,
5059
+ scopes: message.scopes
5060
+ });
5061
+ context.idFactory = makeIdFactory(message.actor);
5062
+ notifySelfChanged(batchedUpdatesWrapper);
5063
+ for (const connectionId of context.others.connectionIds()) {
4687
5064
  const user = message.users[connectionId];
4688
5065
  if (user === void 0) {
4689
- context.others.removeConnection(Number(connectionId));
5066
+ context.others.removeConnection(connectionId);
4690
5067
  }
4691
5068
  }
4692
5069
  for (const key in message.users) {
@@ -4696,7 +5073,7 @@ function createRoom(options, config) {
4696
5073
  connectionId,
4697
5074
  user.id,
4698
5075
  user.info,
4699
- isStorageReadOnly(user.scopes)
5076
+ user.scopes
4700
5077
  );
4701
5078
  }
4702
5079
  return { type: "reset" };
@@ -4717,11 +5094,11 @@ function createRoom(options, config) {
4717
5094
  message.actor,
4718
5095
  message.id,
4719
5096
  message.info,
4720
- isStorageReadOnly(message.scopes)
5097
+ message.scopes
4721
5098
  );
4722
5099
  context.buffer.messages.push({
4723
5100
  type: 100 /* UPDATE_PRESENCE */,
4724
- data: context.me.current,
5101
+ data: context.myPresence.current,
4725
5102
  targetActor: message.actor
4726
5103
  });
4727
5104
  flushNowOrSoon();
@@ -4806,14 +5183,14 @@ function createRoom(options, config) {
4806
5183
  break;
4807
5184
  }
4808
5185
  case 104 /* ROOM_STATE */: {
4809
- updates.others.push(onRoomStateMessage(message));
5186
+ updates.others.push(onRoomStateMessage(message, doNotBatchUpdates));
4810
5187
  break;
4811
5188
  }
4812
5189
  case 200 /* INITIAL_STORAGE_STATE */: {
4813
5190
  const unacknowledgedOps = new Map(context.unacknowledgedOps);
4814
5191
  createOrUpdateRootFromMessage(message, doNotBatchUpdates);
4815
5192
  applyAndSendOps(unacknowledgedOps, doNotBatchUpdates);
4816
- _optionalChain([_resolveStoragePromise, 'optionalCall', _123 => _123()]);
5193
+ _optionalChain([_resolveStoragePromise, 'optionalCall', _120 => _120()]);
4817
5194
  notifyStorageStatus();
4818
5195
  eventHub.storageDidLoad.notify();
4819
5196
  break;
@@ -4836,7 +5213,7 @@ function createRoom(options, config) {
4836
5213
  if (process.env.NODE_ENV !== "production") {
4837
5214
  const traces = /* @__PURE__ */ new Set();
4838
5215
  for (const opId of message.opIds) {
4839
- const trace = _optionalChain([context, 'access', _124 => _124.opStackTraces, 'optionalAccess', _125 => _125.get, 'call', _126 => _126(opId)]);
5216
+ const trace = _optionalChain([context, 'access', _121 => _121.opStackTraces, 'optionalAccess', _122 => _122.get, 'call', _123 => _123(opId)]);
4840
5217
  if (trace) {
4841
5218
  traces.add(trace);
4842
5219
  }
@@ -5124,7 +5501,7 @@ ${Array.from(traces).join("\n\n")}`
5124
5501
  /* NOTE: Exposing __internal here only to allow testing implementation details in unit tests */
5125
5502
  __internal: {
5126
5503
  get presenceBuffer() {
5127
- return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _127 => _127.buffer, 'access', _128 => _128.presenceUpdates, 'optionalAccess', _129 => _129.data]), () => ( null)));
5504
+ return deepClone(_nullishCoalesce(_optionalChain([context, 'access', _124 => _124.buffer, 'access', _125 => _125.presenceUpdates, 'optionalAccess', _126 => _126.data]), () => ( null)));
5128
5505
  },
5129
5506
  // prettier-ignore
5130
5507
  get undoStack() {
@@ -5173,10 +5550,9 @@ ${Array.from(traces).join("\n\n")}`
5173
5550
  // Core
5174
5551
  getStatus: () => managedSocket.getStatus(),
5175
5552
  getConnectionState: () => managedSocket.getLegacyStatus(),
5176
- isSelfAware: () => context.sessionInfo.current !== null,
5177
5553
  getSelf: () => self.current,
5178
5554
  // Presence
5179
- getPresence: () => context.me.current,
5555
+ getPresence: () => context.myPresence.current,
5180
5556
  getOthers: () => context.others.current
5181
5557
  },
5182
5558
  // Explictly make the __internal field non-enumerable, to avoid aggressive
@@ -5253,139 +5629,61 @@ function makeClassicSubscribeFn(events) {
5253
5629
  } else {
5254
5630
  throw new Error("Please specify a listener callback");
5255
5631
  }
5256
- }
5257
- if (isLiveNode(first)) {
5258
- const node = first;
5259
- if (_optionalChain([options, 'optionalAccess', _130 => _130.isDeep])) {
5260
- const storageCallback = second;
5261
- return subscribeToLiveStructureDeeply(node, storageCallback);
5262
- } else {
5263
- const nodeCallback = second;
5264
- return subscribeToLiveStructureShallowly(node, nodeCallback);
5265
- }
5266
- }
5267
- throw new Error(`"${String(first)}" is not a valid event name`);
5268
- }
5269
- return subscribe;
5270
- }
5271
- function isRoomEventName(value) {
5272
- return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "history" || value === "status" || value === "storage-status" || value === "lost-connection" || value === "connection";
5273
- }
5274
- function makeCreateSocketDelegateForRoom(liveblocksServer, WebSocketPolyfill) {
5275
- return (richToken) => {
5276
- const ws = _nullishCoalesce(WebSocketPolyfill, () => ( (typeof WebSocket === "undefined" ? void 0 : WebSocket)));
5277
- if (ws === void 0) {
5278
- throw new StopRetrying(
5279
- "To use Liveblocks client in a non-dom environment, you need to provide a WebSocket polyfill."
5280
- );
5281
- }
5282
- const token = richToken.raw;
5283
- return new ws(
5284
- `${liveblocksServer}/?token=${token}&version=${PKG_VERSION || "dev"}`
5285
- );
5286
- };
5287
- }
5288
- async function httpSend(message, token, endpoint, fetchPolyfill) {
5289
- const fetcher = fetchPolyfill || /* istanbul ignore next */
5290
- fetch;
5291
- return fetcher(endpoint, {
5292
- method: "POST",
5293
- headers: {
5294
- "Content-Type": "application/json",
5295
- Authorization: `Bearer ${token}`
5296
- },
5297
- body: message
5298
- });
5299
- }
5300
- function makeAuthDelegateForRoom(roomId, authentication, fetchPolyfill) {
5301
- const fetcher = _nullishCoalesce(fetchPolyfill, () => ( (typeof window === "undefined" ? void 0 : window.fetch)));
5302
- if (authentication.type === "public") {
5303
- return async () => {
5304
- if (fetcher === void 0) {
5305
- throw new StopRetrying(
5306
- "To use Liveblocks client in a non-dom environment with a publicApiKey, you need to provide a fetch polyfill."
5307
- );
5308
- }
5309
- return fetchAuthEndpoint(fetcher, authentication.url, {
5310
- room: roomId,
5311
- publicApiKey: authentication.publicApiKey
5312
- }).then(({ token }) => parseAuthToken(token));
5313
- };
5314
- } else if (authentication.type === "private") {
5315
- return async () => {
5316
- if (fetcher === void 0) {
5317
- throw new StopRetrying(
5318
- "To use Liveblocks client in a non-dom environment with a url as auth endpoint, you need to provide a fetch polyfill."
5319
- );
5320
- }
5321
- return fetchAuthEndpoint(fetcher, authentication.url, {
5322
- room: roomId
5323
- }).then(({ token }) => parseAuthToken(token));
5324
- };
5325
- } else if (authentication.type === "custom") {
5326
- return async () => {
5327
- const response = await authentication.callback(roomId);
5328
- if (!response || typeof response !== "object") {
5329
- throw new Error(
5330
- 'We expect the authentication callback to return a token, but it does not. Hint: the return value should look like: { token: "..." }'
5331
- );
5332
- }
5333
- if (typeof response.token === "string") {
5334
- return parseAuthToken(response.token);
5335
- } else if (typeof response.error === "string") {
5336
- const reason = `Authentication failed: ${"reason" in response && typeof response.reason === "string" ? response.reason : "Forbidden"}`;
5337
- if (response.error === "forbidden") {
5338
- throw new StopRetrying(reason);
5339
- } else {
5340
- throw new Error(reason);
5341
- }
5632
+ }
5633
+ if (isLiveNode(first)) {
5634
+ const node = first;
5635
+ if (_optionalChain([options, 'optionalAccess', _127 => _127.isDeep])) {
5636
+ const storageCallback = second;
5637
+ return subscribeToLiveStructureDeeply(node, storageCallback);
5342
5638
  } else {
5343
- throw new Error(
5344
- 'We expect the authentication callback to return a token, but it does not. Hint: the return value should look like: { token: "..." }'
5345
- );
5639
+ const nodeCallback = second;
5640
+ return subscribeToLiveStructureShallowly(node, nodeCallback);
5346
5641
  }
5347
- };
5348
- } else {
5349
- throw new Error("Internal error. Unexpected authentication type");
5642
+ }
5643
+ throw new Error(`"${String(first)}" is not a valid event name`);
5350
5644
  }
5645
+ return subscribe;
5351
5646
  }
5352
- async function fetchAuthEndpoint(fetch2, endpoint, body) {
5353
- const res = await fetch2(endpoint, {
5647
+ function isRoomEventName(value) {
5648
+ return value === "my-presence" || value === "others" || value === "event" || value === "error" || value === "history" || value === "status" || value === "storage-status" || value === "lost-connection" || value === "connection";
5649
+ }
5650
+ function makeAuthDelegateForRoom(roomId, authManager) {
5651
+ return async () => {
5652
+ return authManager.getAuthValue("room:read", roomId);
5653
+ };
5654
+ }
5655
+ function makeCreateSocketDelegateForRoom(roomId, liveblocksServer, WebSocketPolyfill) {
5656
+ return (authValue) => {
5657
+ const ws = _nullishCoalesce(WebSocketPolyfill, () => ( (typeof WebSocket === "undefined" ? void 0 : WebSocket)));
5658
+ if (ws === void 0) {
5659
+ throw new StopRetrying(
5660
+ "To use Liveblocks client in a non-dom environment, you need to provide a WebSocket polyfill."
5661
+ );
5662
+ }
5663
+ const url = new URL(liveblocksServer);
5664
+ url.searchParams.set("roomId", roomId);
5665
+ if (authValue.type === "secret") {
5666
+ url.searchParams.set("tok", authValue.token.raw);
5667
+ } else if (authValue.type === "public") {
5668
+ url.searchParams.set("pubkey", authValue.publicApiKey);
5669
+ } else {
5670
+ return assertNever(authValue, "Unhandled case");
5671
+ }
5672
+ url.searchParams.set("version", PKG_VERSION || "dev");
5673
+ return new ws(url.toString());
5674
+ };
5675
+ }
5676
+ async function httpSend(message, token, endpoint, fetchPolyfill) {
5677
+ const fetcher = fetchPolyfill || /* istanbul ignore next */
5678
+ fetch;
5679
+ return fetcher(endpoint, {
5354
5680
  method: "POST",
5355
5681
  headers: {
5356
- "Content-Type": "application/json"
5682
+ "Content-Type": "application/json",
5683
+ Authorization: `Bearer ${token}`
5357
5684
  },
5358
- // Credentials are needed to support authentication with cookies
5359
- credentials: "include",
5360
- body: JSON.stringify(body)
5685
+ body: message
5361
5686
  });
5362
- if (!res.ok) {
5363
- const reason = `${(await res.text()).trim() || "reason not provided in auth response"} (${res.status} returned by POST ${endpoint})`;
5364
- if (res.status === 401 || res.status === 403) {
5365
- throw new StopRetrying(`Unauthorized: ${reason}`);
5366
- } else {
5367
- throw new Error(`Failed to authenticate: ${reason}`);
5368
- }
5369
- }
5370
- let data;
5371
- try {
5372
- data = await res.json();
5373
- } catch (er) {
5374
- throw new Error(
5375
- `Expected a JSON response when doing a POST request on "${endpoint}". ${String(
5376
- er
5377
- )}`
5378
- );
5379
- }
5380
- if (!isPlainObject(data) || typeof data.token !== "string") {
5381
- throw new Error(
5382
- `Expected a JSON response of the form \`{ token: "..." }\` when doing a POST request on "${endpoint}", but got ${JSON.stringify(
5383
- data
5384
- )}`
5385
- );
5386
- }
5387
- const { token } = data;
5388
- return { token };
5389
5687
  }
5390
5688
 
5391
5689
  // src/client.ts
@@ -5398,7 +5696,7 @@ var MAX_LOST_CONNECTION_TIMEOUT = 3e4;
5398
5696
  var DEFAULT_LOST_CONNECTION_TIMEOUT = 5e3;
5399
5697
  function getServerFromClientOptions(clientOptions) {
5400
5698
  const rawOptions = clientOptions;
5401
- return typeof rawOptions.liveblocksServer === "string" ? rawOptions.liveblocksServer : "wss://api.liveblocks.io/v6";
5699
+ return typeof rawOptions.liveblocksServer === "string" ? rawOptions.liveblocksServer : "wss://api.liveblocks.io/v7";
5402
5700
  }
5403
5701
  function createClient(options) {
5404
5702
  const clientOptions = options;
@@ -5406,6 +5704,7 @@ function createClient(options) {
5406
5704
  const lostConnectionTimeout = getLostConnectionTimeout(
5407
5705
  _nullishCoalesce(clientOptions.lostConnectionTimeout, () => ( DEFAULT_LOST_CONNECTION_TIMEOUT))
5408
5706
  );
5707
+ const authManager = createAuthManager(options);
5409
5708
  const rooms = /* @__PURE__ */ new Map();
5410
5709
  function getRoom(roomId) {
5411
5710
  const room = rooms.get(roomId);
@@ -5430,11 +5729,17 @@ function createClient(options) {
5430
5729
  throttleDelay,
5431
5730
  lostConnectionTimeout,
5432
5731
  polyfills: clientOptions.polyfills,
5433
- delegates: clientOptions.mockedDelegates,
5732
+ delegates: _nullishCoalesce(clientOptions.mockedDelegates, () => ( {
5733
+ createSocket: makeCreateSocketDelegateForRoom(
5734
+ roomId,
5735
+ getServerFromClientOptions(clientOptions),
5736
+ _optionalChain([clientOptions, 'access', _128 => _128.polyfills, 'optionalAccess', _129 => _129.WebSocket])
5737
+ ),
5738
+ authenticate: makeAuthDelegateForRoom(roomId, authManager)
5739
+ })),
5434
5740
  enableDebugLogging: clientOptions.enableDebugLogging,
5435
- unstable_batchedUpdates: _optionalChain([options2, 'optionalAccess', _131 => _131.unstable_batchedUpdates]),
5741
+ unstable_batchedUpdates: _optionalChain([options2, 'optionalAccess', _130 => _130.unstable_batchedUpdates]),
5436
5742
  liveblocksServer: getServerFromClientOptions(clientOptions),
5437
- authentication: prepareAuthentication(clientOptions, roomId),
5438
5743
  httpSendEndpoint: buildLiveblocksHttpSendEndpoint(
5439
5744
  clientOptions,
5440
5745
  roomId
@@ -5448,7 +5753,7 @@ function createClient(options) {
5448
5753
  const shouldConnect = _nullishCoalesce(options2.shouldInitiallyConnect, () => ( true));
5449
5754
  if (shouldConnect) {
5450
5755
  if (typeof atob === "undefined") {
5451
- if (_optionalChain([clientOptions, 'access', _132 => _132.polyfills, 'optionalAccess', _133 => _133.atob]) === void 0) {
5756
+ if (_optionalChain([clientOptions, 'access', _131 => _131.polyfills, 'optionalAccess', _132 => _132.atob]) === void 0) {
5452
5757
  throw new Error(
5453
5758
  "You need to polyfill atob to use the client in your environment. Please follow the instructions at https://liveblocks.io/docs/errors/liveblocks-client/atob-polyfill"
5454
5759
  );
@@ -5468,6 +5773,13 @@ function createClient(options) {
5468
5773
  }
5469
5774
  }
5470
5775
  return {
5776
+ __internal: {
5777
+ getAuthValue: authManager.getAuthValue,
5778
+ realtimeClient: createRealtimeClient(
5779
+ authManager,
5780
+ getWsEventServerEndpoint(options)
5781
+ )
5782
+ },
5471
5783
  getRoom,
5472
5784
  enter,
5473
5785
  leave
@@ -5493,48 +5805,6 @@ function getLostConnectionTimeout(value) {
5493
5805
  RECOMMENDED_MIN_LOST_CONNECTION_TIMEOUT
5494
5806
  );
5495
5807
  }
5496
- function prepareAuthentication(clientOptions, roomId) {
5497
- const { publicApiKey, authEndpoint } = clientOptions;
5498
- if (authEndpoint !== void 0 && publicApiKey !== void 0) {
5499
- throw new Error(
5500
- "You cannot use both publicApiKey and authEndpoint. Please use either publicApiKey or authEndpoint, but not both. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient"
5501
- );
5502
- }
5503
- if (typeof publicApiKey === "string") {
5504
- if (publicApiKey.startsWith("sk_")) {
5505
- throw new Error(
5506
- "Invalid publicApiKey. You are using the secret key which is not supported. Please use the public key instead. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientPublicKey"
5507
- );
5508
- } else if (!publicApiKey.startsWith("pk_")) {
5509
- throw new Error(
5510
- "Invalid key. Please use the public key format: pk_<public key>. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientPublicKey"
5511
- );
5512
- }
5513
- return {
5514
- type: "public",
5515
- publicApiKey,
5516
- url: buildLiveblocksPublicAuthorizeEndpoint(clientOptions, roomId)
5517
- };
5518
- }
5519
- if (typeof authEndpoint === "string") {
5520
- return {
5521
- type: "private",
5522
- url: authEndpoint
5523
- };
5524
- } else if (typeof authEndpoint === "function") {
5525
- return {
5526
- type: "custom",
5527
- callback: authEndpoint
5528
- };
5529
- } else if (authEndpoint !== void 0) {
5530
- throw new Error(
5531
- "authEndpoint must be a string or a function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClientAuthEndpoint"
5532
- );
5533
- }
5534
- throw new Error(
5535
- "Invalid Liveblocks client options. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient"
5536
- );
5537
- }
5538
5808
  function buildLiveblocksHttpSendEndpoint(options, roomId) {
5539
5809
  if (options.httpSendEndpoint) {
5540
5810
  return options.httpSendEndpoint.replace("{roomId}", roomId);
@@ -5543,13 +5813,11 @@ function buildLiveblocksHttpSendEndpoint(options, roomId) {
5543
5813
  roomId
5544
5814
  )}/send-message`;
5545
5815
  }
5546
- function buildLiveblocksPublicAuthorizeEndpoint(options, roomId) {
5547
- if (options.publicAuthorizeEndpoint) {
5548
- return options.publicAuthorizeEndpoint.replace("{roomId}", roomId);
5816
+ function getWsEventServerEndpoint(options) {
5817
+ if (typeof options.eventsServerEndpoint === "string") {
5818
+ return options.eventsServerEndpoint;
5549
5819
  }
5550
- return `https://api.liveblocks.io/v2/rooms/${encodeURIComponent(
5551
- roomId
5552
- )}/public/authorize`;
5820
+ return `wss://events.liveblocks.io/v1`;
5553
5821
  }
5554
5822
 
5555
5823
  // src/crdts/utils.ts
@@ -5781,12 +6049,12 @@ function legacy_patchImmutableNode(state, path, update) {
5781
6049
  }
5782
6050
  const newState = Object.assign({}, state);
5783
6051
  for (const key in update.updates) {
5784
- if (_optionalChain([update, 'access', _134 => _134.updates, 'access', _135 => _135[key], 'optionalAccess', _136 => _136.type]) === "update") {
6052
+ if (_optionalChain([update, 'access', _133 => _133.updates, 'access', _134 => _134[key], 'optionalAccess', _135 => _135.type]) === "update") {
5785
6053
  const val = update.node.get(key);
5786
6054
  if (val !== void 0) {
5787
6055
  newState[key] = lsonToJson(val);
5788
6056
  }
5789
- } else if (_optionalChain([update, 'access', _137 => _137.updates, 'access', _138 => _138[key], 'optionalAccess', _139 => _139.type]) === "delete") {
6057
+ } else if (_optionalChain([update, 'access', _136 => _136.updates, 'access', _137 => _137[key], 'optionalAccess', _138 => _138.type]) === "delete") {
5790
6058
  delete newState[key];
5791
6059
  }
5792
6060
  }
@@ -5847,12 +6115,12 @@ function legacy_patchImmutableNode(state, path, update) {
5847
6115
  }
5848
6116
  const newState = Object.assign({}, state);
5849
6117
  for (const key in update.updates) {
5850
- if (_optionalChain([update, 'access', _140 => _140.updates, 'access', _141 => _141[key], 'optionalAccess', _142 => _142.type]) === "update") {
6118
+ if (_optionalChain([update, 'access', _139 => _139.updates, 'access', _140 => _140[key], 'optionalAccess', _141 => _141.type]) === "update") {
5851
6119
  const value = update.node.get(key);
5852
6120
  if (value !== void 0) {
5853
6121
  newState[key] = lsonToJson(value);
5854
6122
  }
5855
- } else if (_optionalChain([update, 'access', _143 => _143.updates, 'access', _144 => _144[key], 'optionalAccess', _145 => _145.type]) === "delete") {
6123
+ } else if (_optionalChain([update, 'access', _142 => _142.updates, 'access', _143 => _143[key], 'optionalAccess', _144 => _144.type]) === "delete") {
5856
6124
  delete newState[key];
5857
6125
  }
5858
6126
  }
@@ -5923,18 +6191,378 @@ function shallow(a, b) {
5923
6191
  return shallowObj(a, b);
5924
6192
  }
5925
6193
 
5926
- // src/types/IWebSocket.ts
5927
- var WebsocketCloseCodes = /* @__PURE__ */ ((WebsocketCloseCodes2) => {
5928
- WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_ABNORMAL"] = 1006] = "CLOSE_ABNORMAL";
5929
- WebsocketCloseCodes2[WebsocketCloseCodes2["INVALID_MESSAGE_FORMAT"] = 4e3] = "INVALID_MESSAGE_FORMAT";
5930
- WebsocketCloseCodes2[WebsocketCloseCodes2["NOT_ALLOWED"] = 4001] = "NOT_ALLOWED";
5931
- WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_MESSAGES_PER_SECONDS"] = 4002] = "MAX_NUMBER_OF_MESSAGES_PER_SECONDS";
5932
- WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS"] = 4003] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS";
5933
- WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP"] = 4004] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP";
5934
- WebsocketCloseCodes2[WebsocketCloseCodes2["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM"] = 4005] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM";
5935
- WebsocketCloseCodes2[WebsocketCloseCodes2["CLOSE_WITHOUT_RETRY"] = 4999] = "CLOSE_WITHOUT_RETRY";
5936
- return WebsocketCloseCodes2;
5937
- })(WebsocketCloseCodes || {});
6194
+ // src/lib/AsyncCache.ts
6195
+ var noop = () => {
6196
+ };
6197
+ function isShallowEqual(a, b) {
6198
+ if (a.isLoading !== b.isLoading || a.data === void 0 !== (b.data === void 0) || a.error === void 0 !== (b.error === void 0)) {
6199
+ return false;
6200
+ } else {
6201
+ return shallow(a.data, b.data) && shallow(a.error, b.error);
6202
+ }
6203
+ }
6204
+ function createCacheItem(key, defaultAsyncFunction, options) {
6205
+ let asyncFunction = defaultAsyncFunction;
6206
+ const context = {
6207
+ isInvalid: true
6208
+ };
6209
+ let state = { isLoading: false };
6210
+ let previousState = { isLoading: false };
6211
+ const eventSource2 = makeEventSource();
6212
+ function notify() {
6213
+ const isEqual = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _145 => _145.isStateEqual]), () => ( isShallowEqual));
6214
+ if (!isEqual(previousState, state)) {
6215
+ previousState = state;
6216
+ eventSource2.notify(state);
6217
+ }
6218
+ }
6219
+ async function resolve() {
6220
+ if (!context.promise) {
6221
+ return;
6222
+ }
6223
+ try {
6224
+ const data = await context.promise;
6225
+ context.isInvalid = false;
6226
+ state = {
6227
+ isLoading: false,
6228
+ data
6229
+ };
6230
+ } catch (error3) {
6231
+ state = {
6232
+ isLoading: false,
6233
+ data: state.data,
6234
+ error: error3
6235
+ };
6236
+ }
6237
+ context.promise = void 0;
6238
+ notify();
6239
+ }
6240
+ async function revalidate() {
6241
+ context.isInvalid = true;
6242
+ return get();
6243
+ }
6244
+ async function get() {
6245
+ if (context.isInvalid) {
6246
+ if (!context.promise) {
6247
+ context.isInvalid = true;
6248
+ context.promise = asyncFunction(key);
6249
+ state = { isLoading: true, data: state.data };
6250
+ notify();
6251
+ }
6252
+ await resolve();
6253
+ }
6254
+ return getState();
6255
+ }
6256
+ function getState() {
6257
+ return state;
6258
+ }
6259
+ function setAsyncFunction(overrideAsyncFunction) {
6260
+ asyncFunction = overrideAsyncFunction;
6261
+ }
6262
+ return {
6263
+ ...eventSource2.observable,
6264
+ setAsyncFunction,
6265
+ get,
6266
+ getState,
6267
+ revalidate
6268
+ };
6269
+ }
6270
+ function createAsyncCache(asyncFunction, options) {
6271
+ const cache = /* @__PURE__ */ new Map();
6272
+ function create(key, overrideAsyncFunction) {
6273
+ let cacheItem = cache.get(key);
6274
+ if (cacheItem) {
6275
+ if (overrideAsyncFunction) {
6276
+ cacheItem.setAsyncFunction(overrideAsyncFunction);
6277
+ }
6278
+ return cacheItem;
6279
+ }
6280
+ cacheItem = createCacheItem(
6281
+ key,
6282
+ _nullishCoalesce(overrideAsyncFunction, () => ( asyncFunction)),
6283
+ options
6284
+ );
6285
+ cache.set(key, cacheItem);
6286
+ return cacheItem;
6287
+ }
6288
+ function get(key) {
6289
+ return create(key).get();
6290
+ }
6291
+ function getState(key) {
6292
+ return _optionalChain([cache, 'access', _146 => _146.get, 'call', _147 => _147(key), 'optionalAccess', _148 => _148.getState, 'call', _149 => _149()]);
6293
+ }
6294
+ function revalidate(key) {
6295
+ return create(key).revalidate();
6296
+ }
6297
+ function subscribe(key, callback) {
6298
+ return _nullishCoalesce(create(key).subscribe(callback), () => ( noop));
6299
+ }
6300
+ function subscribeOnce(key, callback) {
6301
+ return _nullishCoalesce(create(key).subscribeOnce(callback), () => ( noop));
6302
+ }
6303
+ function has(key) {
6304
+ return cache.has(key);
6305
+ }
6306
+ function clear() {
6307
+ cache.clear();
6308
+ }
6309
+ return {
6310
+ create,
6311
+ get,
6312
+ getState,
6313
+ revalidate,
6314
+ subscribe,
6315
+ subscribeOnce,
6316
+ has,
6317
+ clear
6318
+ };
6319
+ }
6320
+
6321
+ // src/lib/Poller.ts
6322
+ function makePoller(callback) {
6323
+ let context = {
6324
+ state: "stopped",
6325
+ timeoutHandle: null,
6326
+ interval: null,
6327
+ lastScheduledAt: null,
6328
+ remainingInterval: null
6329
+ };
6330
+ function poll() {
6331
+ if (context.state === "running") {
6332
+ schedule(context.interval);
6333
+ }
6334
+ callback();
6335
+ }
6336
+ function schedule(interval) {
6337
+ context = {
6338
+ state: "running",
6339
+ interval: context.state !== "stopped" ? context.interval : interval,
6340
+ lastScheduledAt: performance.now(),
6341
+ timeoutHandle: setTimeout(poll, interval),
6342
+ remainingInterval: null
6343
+ };
6344
+ }
6345
+ function scheduleRemaining(remaining) {
6346
+ if (context.state !== "paused") {
6347
+ return;
6348
+ }
6349
+ context = {
6350
+ state: "running",
6351
+ interval: context.interval,
6352
+ lastScheduledAt: context.lastScheduledAt,
6353
+ timeoutHandle: setTimeout(poll, remaining),
6354
+ remainingInterval: null
6355
+ };
6356
+ }
6357
+ function start(interval) {
6358
+ if (context.state === "running") {
6359
+ return;
6360
+ }
6361
+ schedule(interval);
6362
+ }
6363
+ function restart(interval) {
6364
+ stop();
6365
+ start(interval);
6366
+ }
6367
+ function pause() {
6368
+ if (context.state !== "running") {
6369
+ return;
6370
+ }
6371
+ clearTimeout(context.timeoutHandle);
6372
+ context = {
6373
+ state: "paused",
6374
+ interval: context.interval,
6375
+ lastScheduledAt: context.lastScheduledAt,
6376
+ timeoutHandle: null,
6377
+ remainingInterval: context.interval - (performance.now() - context.lastScheduledAt)
6378
+ };
6379
+ }
6380
+ function resume() {
6381
+ if (context.state !== "paused") {
6382
+ return;
6383
+ }
6384
+ scheduleRemaining(context.remainingInterval);
6385
+ }
6386
+ function stop() {
6387
+ if (context.state === "stopped") {
6388
+ return;
6389
+ }
6390
+ if (context.timeoutHandle) {
6391
+ clearTimeout(context.timeoutHandle);
6392
+ }
6393
+ context = {
6394
+ state: "stopped",
6395
+ interval: null,
6396
+ lastScheduledAt: null,
6397
+ timeoutHandle: null,
6398
+ remainingInterval: null
6399
+ };
6400
+ }
6401
+ return {
6402
+ start,
6403
+ restart,
6404
+ pause,
6405
+ resume,
6406
+ stop
6407
+ };
6408
+ }
6409
+
6410
+ // src/comments/index.ts
6411
+ function createCommentsApi(client, { serverEndpoint }) {
6412
+ async function fetchJson(roomId, endpoint, options) {
6413
+ const response = await fetchApi(roomId, endpoint, options);
6414
+ if (!response.ok) {
6415
+ if (response.status >= 400 && response.status < 600) {
6416
+ let errorMessage = "";
6417
+ try {
6418
+ const errorBody = await response.json();
6419
+ errorMessage = errorBody.message;
6420
+ } catch (error3) {
6421
+ errorMessage = response.statusText;
6422
+ }
6423
+ throw new Error(
6424
+ `Request failed with status ${response.status}: ${errorMessage}`
6425
+ );
6426
+ }
6427
+ }
6428
+ let body;
6429
+ try {
6430
+ body = await response.json();
6431
+ } catch (e3) {
6432
+ body = {};
6433
+ }
6434
+ return body;
6435
+ }
6436
+ async function fetchApi(roomId, endpoint, options) {
6437
+ const authValue = await client.__internal.getAuthValue(
6438
+ "comments:read",
6439
+ // TODO: Use the right scope
6440
+ roomId
6441
+ );
6442
+ if (authValue.type !== "secret") {
6443
+ throw new Error("Only secret key are supported for client.");
6444
+ }
6445
+ const url = `${serverEndpoint}/rooms/${roomId}${endpoint}`;
6446
+ return await fetch(url, {
6447
+ ...options,
6448
+ headers: {
6449
+ ..._optionalChain([options, 'optionalAccess', _150 => _150.headers]),
6450
+ Authorization: `Bearer ${authValue.token.raw}`
6451
+ }
6452
+ });
6453
+ }
6454
+ async function getThreads({
6455
+ roomId
6456
+ }) {
6457
+ const response = await fetchApi(roomId, "/threads");
6458
+ if (response.ok) {
6459
+ const json = await response.json();
6460
+ return json.data;
6461
+ } else if (response.status === 404) {
6462
+ return [];
6463
+ } else {
6464
+ throw new Error("FAIL");
6465
+ }
6466
+ }
6467
+ function createThread({
6468
+ roomId,
6469
+ metadata,
6470
+ body,
6471
+ commentId,
6472
+ threadId
6473
+ }) {
6474
+ return fetchJson(roomId, "/threads", {
6475
+ method: "POST",
6476
+ headers: {
6477
+ "Content-Type": "application/json"
6478
+ },
6479
+ body: JSON.stringify({
6480
+ id: threadId,
6481
+ comment: {
6482
+ id: commentId,
6483
+ body
6484
+ },
6485
+ metadata
6486
+ })
6487
+ });
6488
+ }
6489
+ function editThreadMetadata({
6490
+ roomId,
6491
+ metadata,
6492
+ threadId
6493
+ }) {
6494
+ return fetchJson(
6495
+ roomId,
6496
+ `/threads/${threadId}/metadata`,
6497
+ {
6498
+ method: "POST",
6499
+ headers: {
6500
+ "Content-Type": "application/json"
6501
+ },
6502
+ body: JSON.stringify(metadata)
6503
+ }
6504
+ );
6505
+ }
6506
+ function createComment({
6507
+ roomId,
6508
+ threadId,
6509
+ commentId,
6510
+ body
6511
+ }) {
6512
+ return fetchJson(roomId, `/threads/${threadId}/comments`, {
6513
+ method: "POST",
6514
+ headers: {
6515
+ "Content-Type": "application/json"
6516
+ },
6517
+ body: JSON.stringify({
6518
+ id: commentId,
6519
+ body
6520
+ })
6521
+ });
6522
+ }
6523
+ function editComment({
6524
+ roomId,
6525
+ threadId,
6526
+ commentId,
6527
+ body
6528
+ }) {
6529
+ return fetchJson(
6530
+ roomId,
6531
+ `/threads/${threadId}/comments/${commentId}`,
6532
+ {
6533
+ method: "POST",
6534
+ headers: {
6535
+ "Content-Type": "application/json"
6536
+ },
6537
+ body: JSON.stringify({
6538
+ body
6539
+ })
6540
+ }
6541
+ );
6542
+ }
6543
+ async function deleteComment({
6544
+ roomId,
6545
+ threadId,
6546
+ commentId
6547
+ }) {
6548
+ await fetchJson(roomId, `/threads/${threadId}/comments/${commentId}`, {
6549
+ method: "DELETE"
6550
+ });
6551
+ }
6552
+ return {
6553
+ getThreads,
6554
+ createThread,
6555
+ editThreadMetadata,
6556
+ createComment,
6557
+ editComment,
6558
+ deleteComment
6559
+ };
6560
+ }
6561
+
6562
+ // src/comments/utils.ts
6563
+ function isCommentBodyMention(element) {
6564
+ return "type" in element && element.type === "mention";
6565
+ }
5938
6566
 
5939
6567
  // src/index.ts
5940
6568
  detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
@@ -5974,5 +6602,11 @@ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
5974
6602
 
5975
6603
 
5976
6604
 
5977
- exports.ClientMsgCode = ClientMsgCode; exports.CrdtType = CrdtType; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.OpCode = OpCode; exports.ServerMsgCode = ServerMsgCode; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.asArrayWithLegacyMethods = asArrayWithLegacyMethods; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.b64decode = b64decode; exports.createClient = createClient; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.errorIf = errorIf; exports.freeze = freeze; exports.isChildCrdt = isChildCrdt; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isPlainObject = isPlainObject; exports.isRootCrdt = isRootCrdt; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makePosition = makePosition; exports.nn = nn; exports.patchLiveObjectKey = patchLiveObjectKey; exports.shallow = shallow; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.withTimeout = withTimeout;
6605
+
6606
+
6607
+
6608
+
6609
+
6610
+
6611
+ exports.ClientMsgCode = ClientMsgCode; exports.CrdtType = CrdtType; exports.LiveList = LiveList; exports.LiveMap = LiveMap; exports.LiveObject = LiveObject; exports.OpCode = OpCode; exports.ServerMsgCode = ServerMsgCode; exports.WebsocketCloseCodes = WebsocketCloseCodes; exports.asArrayWithLegacyMethods = asArrayWithLegacyMethods; exports.asPos = asPos; exports.assert = assert; exports.assertNever = assertNever; exports.b64decode = b64decode; exports.console = fancy_console_exports; exports.createAsyncCache = createAsyncCache; exports.createClient = createClient; exports.createCommentsApi = createCommentsApi; exports.deprecate = deprecate; exports.deprecateIf = deprecateIf; exports.detectDupes = detectDupes; exports.errorIf = errorIf; exports.freeze = freeze; exports.isChildCrdt = isChildCrdt; exports.isCommentBodyMention = isCommentBodyMention; exports.isJsonArray = isJsonArray; exports.isJsonObject = isJsonObject; exports.isJsonScalar = isJsonScalar; exports.isPlainObject = isPlainObject; exports.isRootCrdt = isRootCrdt; exports.legacy_patchImmutableObject = legacy_patchImmutableObject; exports.lsonToJson = lsonToJson; exports.makeEventSource = makeEventSource; exports.makePoller = makePoller; exports.makePosition = makePosition; exports.nn = nn; exports.patchLiveObjectKey = patchLiveObjectKey; exports.shallow = shallow; exports.throwUsageError = throwUsageError; exports.toPlainLson = toPlainLson; exports.tryParseJson = tryParseJson; exports.withTimeout = withTimeout;
5978
6612
  //# sourceMappingURL=index.js.map