@liveblocks/core 2.9.3-experimental1 → 2.10.1-react19

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.mjs CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
 
7
7
  // src/version.ts
8
8
  var PKG_NAME = "@liveblocks/core";
9
- var PKG_VERSION = "2.9.3-experimental1";
9
+ var PKG_VERSION = "2.10.1-react19";
10
10
  var PKG_FORMAT = "esm";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -363,10 +363,39 @@ var FSM = class {
363
363
  this.enterFns.set(nameOrPattern, enterFn);
364
364
  return this;
365
365
  }
366
- onEnterAsync(nameOrPattern, promiseFn, onOK, onError) {
366
+ /**
367
+ * Defines a promise-based state. When the state is entered, the promise is
368
+ * created. When the promise resolves, the machine will transition to the
369
+ * provided `onOK` target state. When the promise rejects, the machine will
370
+ * transition to the `onError` target state.
371
+ *
372
+ * Optionally, a `maxTimeout` can be set. If the timeout happens before the
373
+ * promise is settled, then the machine will also transition to the `onError`
374
+ * target state.
375
+ *
376
+ * @param stateOrPattern The state name, or state group pattern name.
377
+ * @param promiseFn The callback to be invoked when the state is entered.
378
+ * @param onOK The state to transition to when the promise resolves.
379
+ * @param onError The state to transition to when the promise
380
+ * rejects, or when the timeout happens before the
381
+ * promise has been settled.
382
+ * @param maxTimeout Optional timeout in milliseconds.
383
+ *
384
+ * When the promise callback function is invoked, it's provided with an
385
+ * AbortSignal (2nd argument).
386
+ * If a state transition happens while the promise is pending (for example,
387
+ * an event, or a timeout happens), then an abort signal will be used to
388
+ * indicate this. Implementers can use this abort signal to terminate the
389
+ * in-flight promise, or ignore its results, etc.
390
+ */
391
+ onEnterAsync(nameOrPattern, promiseFn, onOK, onError, maxTimeout) {
367
392
  return this.onEnter(nameOrPattern, () => {
368
393
  const abortController = new AbortController();
369
394
  const signal = abortController.signal;
395
+ const timeoutId = maxTimeout ? setTimeout(() => {
396
+ const reason = new Error("Timed out");
397
+ this.transition({ type: "ASYNC_ERROR", reason }, onError);
398
+ }, maxTimeout) : void 0;
370
399
  let done = false;
371
400
  void promiseFn(this.currentContext.current, signal).then(
372
401
  // On OK
@@ -385,6 +414,7 @@ var FSM = class {
385
414
  }
386
415
  );
387
416
  return () => {
417
+ clearTimeout(timeoutId);
388
418
  if (!done) {
389
419
  abortController.abort();
390
420
  }
@@ -457,11 +487,11 @@ var FSM = class {
457
487
  * Like `.addTransition()`, but takes an (anonymous) transition whenever the
458
488
  * timer fires.
459
489
  *
460
- * @param stateOrPattern The state name, or state group pattern name.
461
- * @param after Number of milliseconds after which to take the
462
- * transition. If in the mean time, another transition
463
- * is taken, the timer will get cancelled.
464
- * @param target The target state to go to.
490
+ * @param stateOrPattern The state name, or state group pattern name.
491
+ * @param after Number of milliseconds after which to take the
492
+ * transition. If in the mean time, another transition
493
+ * is taken, the timer will get cancelled.
494
+ * @param target The target state to go to.
465
495
  */
466
496
  addTimedTransition(stateOrPattern, after2, target) {
467
497
  return this.onEnter(stateOrPattern, () => {
@@ -1520,8 +1550,8 @@ function prepareAuthentication(authOptions) {
1520
1550
  "Invalid Liveblocks client options. Please provide either a `publicApiKey` or `authEndpoint` option. They cannot both be empty. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient"
1521
1551
  );
1522
1552
  }
1523
- async function fetchAuthEndpoint(fetch2, endpoint, body) {
1524
- const res = await fetch2(endpoint, {
1553
+ async function fetchAuthEndpoint(fetch, endpoint, body) {
1554
+ const res = await fetch(endpoint, {
1525
1555
  method: "POST",
1526
1556
  headers: {
1527
1557
  "Content-Type": "application/json"
@@ -1881,6 +1911,16 @@ function createBatchStore(batch) {
1881
1911
  cache.set(cacheKey, state);
1882
1912
  eventSource2.notify();
1883
1913
  }
1914
+ function invalidate(inputs) {
1915
+ if (Array.isArray(inputs)) {
1916
+ for (const input of inputs) {
1917
+ cache.delete(getCacheKey(input));
1918
+ }
1919
+ } else {
1920
+ cache.clear();
1921
+ }
1922
+ eventSource2.notify();
1923
+ }
1884
1924
  async function get(input) {
1885
1925
  const cacheKey = getCacheKey(input);
1886
1926
  if (cache.has(cacheKey)) {
@@ -1901,10 +1941,15 @@ function createBatchStore(batch) {
1901
1941
  const cacheKey = getCacheKey(input);
1902
1942
  return cache.get(cacheKey);
1903
1943
  }
1944
+ function _cacheKeys() {
1945
+ return [...cache.keys()];
1946
+ }
1904
1947
  return {
1905
1948
  ...eventSource2.observable,
1906
1949
  get,
1907
- getState
1950
+ getState,
1951
+ invalidate,
1952
+ _cacheKeys
1908
1953
  };
1909
1954
  }
1910
1955
 
@@ -2044,12 +2089,36 @@ function convertToInboxNotificationDeleteInfo(data) {
2044
2089
  };
2045
2090
  }
2046
2091
 
2047
- // src/http-client.ts
2048
- function getBearerTokenFromAuthValue(authValue) {
2049
- if (authValue.type === "public") {
2050
- return authValue.publicApiKey;
2051
- } else {
2052
- return authValue.token.raw;
2092
+ // src/lib/autoRetry.ts
2093
+ var HttpError = class extends Error {
2094
+ constructor(message, status, details) {
2095
+ super(message);
2096
+ this.message = message;
2097
+ this.status = status;
2098
+ this.details = details;
2099
+ }
2100
+ };
2101
+ var DONT_RETRY_4XX = (x) => x instanceof HttpError && x.status >= 400 && x.status < 500;
2102
+ async function autoRetry(promiseFn, maxTries, backoff, shouldStopRetrying = DONT_RETRY_4XX) {
2103
+ const fallbackBackoff = backoff.length > 0 ? backoff[backoff.length - 1] : 0;
2104
+ let attempt = 0;
2105
+ while (true) {
2106
+ attempt++;
2107
+ try {
2108
+ return await promiseFn();
2109
+ } catch (err) {
2110
+ if (shouldStopRetrying(err)) {
2111
+ throw err;
2112
+ }
2113
+ if (attempt >= maxTries) {
2114
+ throw new Error(`Failed after ${maxTries} attempts: ${String(err)}`);
2115
+ }
2116
+ }
2117
+ const delay = backoff[attempt - 1] ?? fallbackBackoff;
2118
+ warn(
2119
+ `Attempt ${attempt} was unsuccessful. Retrying in ${delay} milliseconds.`
2120
+ );
2121
+ await wait(delay);
2053
2122
  }
2054
2123
  }
2055
2124
 
@@ -2076,51 +2145,79 @@ function url(strings, ...values) {
2076
2145
  );
2077
2146
  }
2078
2147
 
2079
- // src/notifications.ts
2080
- function createNotificationsApi({
2081
- baseUrl,
2082
- authManager,
2083
- currentUserIdStore,
2084
- fetcher
2085
- }) {
2086
- async function fetchJson(endpoint, options, params) {
2148
+ // src/http-client.ts
2149
+ function getBearerTokenFromAuthValue(authValue) {
2150
+ if (authValue.type === "public") {
2151
+ return authValue.publicApiKey;
2152
+ } else {
2153
+ return authValue.token.raw;
2154
+ }
2155
+ }
2156
+ var HttpClient = class {
2157
+ constructor(baseUrl, fetchPolyfill, authCallback) {
2158
+ this._baseUrl = baseUrl;
2159
+ this._fetchPolyfill = fetchPolyfill;
2160
+ this._authCallback = authCallback;
2161
+ }
2162
+ // ------------------------------------------------------------------
2163
+ // Public methods
2164
+ // ------------------------------------------------------------------
2165
+ /**
2166
+ * Constructs and makes the HTTP request, but does not handle the response.
2167
+ *
2168
+ * This is what .rawFetch() does: 👈 This method!
2169
+ * 1. Set Content-Type header
2170
+ * 2. Set Authorization header
2171
+ * 3. Call the callback to obtain the `authValue` to use in the Authorization header
2172
+ *
2173
+ * This is what .fetch() does ON TOP of that:
2174
+ * 4. Parse response body as Json
2175
+ * 5. ...but silently return `{}` if that parsing fails
2176
+ * 6. Throw HttpError if response is an error
2177
+ */
2178
+ async rawFetch(endpoint, options, params) {
2087
2179
  if (!endpoint.startsWith("/v2/c/")) {
2088
- raise("Expected a /v2/c/* endpoint");
2089
- }
2090
- const authValue = await authManager.getAuthValue({
2091
- requestedScope: "comments:read"
2092
- });
2093
- if (authValue.type === "secret" && authValue.token.parsed.k === "acc" /* ACCESS_TOKEN */) {
2094
- const userId = authValue.token.parsed.uid;
2095
- currentUserIdStore.set(() => userId);
2180
+ raise("This client can only be used to make /v2/c/* requests");
2096
2181
  }
2097
- const url2 = urljoin(baseUrl, endpoint, params);
2098
- const response = await fetcher(url2.toString(), {
2182
+ const url2 = urljoin(this._baseUrl, endpoint, params);
2183
+ return await this._fetchPolyfill(url2, {
2099
2184
  ...options,
2100
2185
  headers: {
2186
+ // These headers are default, but can be overriden by custom headers
2187
+ "Content-Type": "application/json; charset=utf-8",
2188
+ // Possible header overrides
2101
2189
  ...options?.headers,
2102
- Authorization: `Bearer ${getBearerTokenFromAuthValue(authValue)}`,
2190
+ // Cannot be overriden by custom headers
2191
+ Authorization: `Bearer ${getBearerTokenFromAuthValue(await this._authCallback())}`,
2103
2192
  "X-LB-Client": PKG_VERSION || "dev"
2104
2193
  }
2105
2194
  });
2195
+ }
2196
+ /**
2197
+ * Constructs, makes the HTTP request, and handles the response by parsing
2198
+ * JSON and/or throwing an HttpError if it failed.
2199
+ *
2200
+ * This is what .rawFetch() does:
2201
+ * 1. Set Content-Type header
2202
+ * 2. Set Authorization header
2203
+ * 3. Call the callback to obtain the `authValue` to use in the Authorization header
2204
+ *
2205
+ * This is what .fetch() does ON TOP of that: 👈 This method!
2206
+ * 4. Parse response body as Json
2207
+ * 5. ...but silently return `{}` if that parsing fails (🤔)
2208
+ * 6. Throw HttpError if response is an error
2209
+ */
2210
+ async fetch(endpoint, options, params) {
2211
+ const response = await this.rawFetch(endpoint, options, params);
2106
2212
  if (!response.ok) {
2107
- if (response.status >= 400 && response.status < 600) {
2108
- let error3;
2109
- try {
2110
- const errorBody = await response.json();
2111
- error3 = new NotificationsApiError(
2112
- errorBody.message,
2113
- response.status,
2114
- errorBody
2115
- );
2116
- } catch {
2117
- error3 = new NotificationsApiError(
2118
- response.statusText,
2119
- response.status
2120
- );
2121
- }
2122
- throw error3;
2213
+ let error3;
2214
+ try {
2215
+ const errorBody = await response.json();
2216
+ error3 = new HttpError(errorBody.message, response.status, errorBody);
2217
+ } catch {
2218
+ error3 = new HttpError(response.statusText, response.status);
2123
2219
  }
2220
+ throw error3;
2124
2221
  }
2125
2222
  let body;
2126
2223
  try {
@@ -2130,9 +2227,103 @@ function createNotificationsApi({
2130
2227
  }
2131
2228
  return body;
2132
2229
  }
2230
+ /**
2231
+ * Makes a GET request and returns the raw response.
2232
+ * Won't throw if the reponse is a non-2xx.
2233
+ * @deprecated Ideally, use .get() instead.
2234
+ */
2235
+ async rawGet(endpoint, params, options) {
2236
+ return await this.rawFetch(endpoint, options, params);
2237
+ }
2238
+ /**
2239
+ * Makes a POST request and returns the raw response.
2240
+ * Won't throw if the reponse is a non-2xx.
2241
+ * @deprecated Ideally, use .post() instead.
2242
+ */
2243
+ async rawPost(endpoint, body) {
2244
+ return await this.rawFetch(endpoint, {
2245
+ method: "POST",
2246
+ body: JSON.stringify(body)
2247
+ });
2248
+ }
2249
+ /**
2250
+ * Makes a DELETE request and returns the raw response.
2251
+ * Won't throw if the reponse is a non-2xx.
2252
+ * @deprecated Ideally, use .delete() instead.
2253
+ */
2254
+ async rawDelete(endpoint) {
2255
+ return await this.rawFetch(endpoint, { method: "DELETE" });
2256
+ }
2257
+ /**
2258
+ * Makes a GET request, and return the JSON response.
2259
+ * Will throw if the reponse is a non-2xx.
2260
+ */
2261
+ async get(endpoint, params, options) {
2262
+ return await this.fetch(endpoint, options, params);
2263
+ }
2264
+ /**
2265
+ * Makes a POST request, and return the JSON response.
2266
+ * Will throw if the reponse is a non-2xx.
2267
+ */
2268
+ async post(endpoint, body, options, params) {
2269
+ return await this.fetch(
2270
+ endpoint,
2271
+ {
2272
+ ...options,
2273
+ method: "POST",
2274
+ body: JSON.stringify(body)
2275
+ },
2276
+ params
2277
+ );
2278
+ }
2279
+ /**
2280
+ * Makes a DELETE request, and return the JSON response.
2281
+ * Will throw if the reponse is a non-2xx.
2282
+ */
2283
+ async delete(endpoint) {
2284
+ return await this.fetch(endpoint, { method: "DELETE" });
2285
+ }
2286
+ /**
2287
+ * Makes a PUT request for a Blob body, and return the JSON response.
2288
+ * Will throw if the reponse is a non-2xx.
2289
+ */
2290
+ async putBlob(endpoint, blob, params, options) {
2291
+ return await this.fetch(
2292
+ endpoint,
2293
+ {
2294
+ ...options,
2295
+ method: "PUT",
2296
+ headers: {
2297
+ "Content-Type": "application/octet-stream"
2298
+ },
2299
+ body: blob
2300
+ },
2301
+ params
2302
+ );
2303
+ }
2304
+ };
2305
+
2306
+ // src/notifications.ts
2307
+ function createNotificationsApi({
2308
+ baseUrl,
2309
+ authManager,
2310
+ currentUserIdStore,
2311
+ fetchPolyfill
2312
+ }) {
2313
+ async function getAuthValue() {
2314
+ const authValue = await authManager.getAuthValue({
2315
+ requestedScope: "comments:read"
2316
+ });
2317
+ if (authValue.type === "secret" && authValue.token.parsed.k === "acc" /* ACCESS_TOKEN */) {
2318
+ const userId = authValue.token.parsed.uid;
2319
+ currentUserIdStore.set(() => userId);
2320
+ }
2321
+ return authValue;
2322
+ }
2323
+ const httpClient = new HttpClient(baseUrl, fetchPolyfill, getAuthValue);
2133
2324
  async function getInboxNotifications(options) {
2134
2325
  const PAGE_SIZE = 50;
2135
- const json = await fetchJson(url`/v2/c/inbox-notifications`, void 0, {
2326
+ const json = await httpClient.get(url`/v2/c/inbox-notifications`, {
2136
2327
  cursor: options?.cursor,
2137
2328
  limit: PAGE_SIZE
2138
2329
  });
@@ -2145,10 +2336,12 @@ function createNotificationsApi({
2145
2336
  requestedAt: new Date(json.meta.requestedAt)
2146
2337
  };
2147
2338
  }
2148
- async function getInboxNotificationsSince(since) {
2149
- const json = await fetchJson(url`/v2/c/inbox-notifications/delta`, void 0, {
2150
- since: since.toISOString()
2151
- });
2339
+ async function getInboxNotificationsSince(options) {
2340
+ const json = await httpClient.get(
2341
+ url`/v2/c/inbox-notifications/delta`,
2342
+ { since: options.since.toISOString() },
2343
+ { signal: options?.signal }
2344
+ );
2152
2345
  return {
2153
2346
  inboxNotifications: {
2154
2347
  updated: json.inboxNotifications.map(convertToInboxNotificationData),
@@ -2164,25 +2357,19 @@ function createNotificationsApi({
2164
2357
  };
2165
2358
  }
2166
2359
  async function getUnreadInboxNotificationsCount() {
2167
- const { count } = await fetchJson(url`/v2/c/inbox-notifications/count`);
2360
+ const { count } = await httpClient.get(
2361
+ url`/v2/c/inbox-notifications/count`
2362
+ );
2168
2363
  return count;
2169
2364
  }
2170
2365
  async function markAllInboxNotificationsAsRead() {
2171
- await fetchJson(url`/v2/c/inbox-notifications/read`, {
2172
- method: "POST",
2173
- headers: {
2174
- "Content-Type": "application/json"
2175
- },
2176
- body: JSON.stringify({ inboxNotificationIds: "all" })
2366
+ await httpClient.post(url`/v2/c/inbox-notifications/read`, {
2367
+ inboxNotificationIds: "all"
2177
2368
  });
2178
2369
  }
2179
2370
  async function markInboxNotificationsAsRead(inboxNotificationIds) {
2180
- await fetchJson(url`/v2/c/inbox-notifications/read`, {
2181
- method: "POST",
2182
- headers: {
2183
- "Content-Type": "application/json"
2184
- },
2185
- body: JSON.stringify({ inboxNotificationIds })
2371
+ await httpClient.post(url`/v2/c/inbox-notifications/read`, {
2372
+ inboxNotificationIds
2186
2373
  });
2187
2374
  }
2188
2375
  const batchedMarkInboxNotificationsAsRead = new Batch(
@@ -2197,14 +2384,12 @@ function createNotificationsApi({
2197
2384
  await batchedMarkInboxNotificationsAsRead.get(inboxNotificationId);
2198
2385
  }
2199
2386
  async function deleteAllInboxNotifications() {
2200
- await fetchJson(url`/v2/c/inbox-notifications`, {
2201
- method: "DELETE"
2202
- });
2387
+ await httpClient.delete(url`/v2/c/inbox-notifications`);
2203
2388
  }
2204
2389
  async function deleteInboxNotification(inboxNotificationId) {
2205
- await fetchJson(url`/v2/c/inbox-notifications/${inboxNotificationId}`, {
2206
- method: "DELETE"
2207
- });
2390
+ await httpClient.delete(
2391
+ url`/v2/c/inbox-notifications/${inboxNotificationId}`
2392
+ );
2208
2393
  }
2209
2394
  async function getUserThreads_experimental(options) {
2210
2395
  let query;
@@ -2212,7 +2397,7 @@ function createNotificationsApi({
2212
2397
  query = objectToQuery(options.query);
2213
2398
  }
2214
2399
  const PAGE_SIZE = 50;
2215
- const json = await fetchJson(url`/v2/c/threads`, void 0, {
2400
+ const json = await httpClient.get(url`/v2/c/threads`, {
2216
2401
  cursor: options.cursor,
2217
2402
  query,
2218
2403
  limit: PAGE_SIZE
@@ -2227,9 +2412,11 @@ function createNotificationsApi({
2227
2412
  };
2228
2413
  }
2229
2414
  async function getUserThreadsSince_experimental(options) {
2230
- const json = await fetchJson(url`/v2/c/threads/delta`, void 0, {
2231
- since: options.since.toISOString()
2232
- });
2415
+ const json = await httpClient.get(
2416
+ url`/v2/c/threads/delta`,
2417
+ { since: options.since.toISOString() },
2418
+ { signal: options.signal }
2419
+ );
2233
2420
  return {
2234
2421
  threads: {
2235
2422
  updated: json.threads.map(convertToThreadData),
@@ -4814,36 +5001,6 @@ function findNonSerializableValue(value, path = "") {
4814
5001
  return false;
4815
5002
  }
4816
5003
 
4817
- // src/lib/autoRetry.ts
4818
- async function autoRetry(promiseFn, maxTries, backoff, throwError) {
4819
- const fallbackBackoff = backoff.length > 0 ? backoff[backoff.length - 1] : 0;
4820
- let attempt = 0;
4821
- while (true) {
4822
- attempt++;
4823
- const promise = promiseFn();
4824
- try {
4825
- return await promise;
4826
- } catch (err) {
4827
- if (throwError?.(err) || err instanceof StopRetrying2) {
4828
- throw err;
4829
- }
4830
- if (attempt >= maxTries) {
4831
- throw new Error(`Failed after ${maxTries} attempts: ${String(err)}`);
4832
- }
4833
- }
4834
- const delay = backoff[attempt - 1] ?? fallbackBackoff;
4835
- warn(
4836
- `Attempt ${attempt} was unsuccessful. Retrying in ${delay} milliseconds.`
4837
- );
4838
- await wait(delay);
4839
- }
4840
- }
4841
- var StopRetrying2 = class extends Error {
4842
- constructor(reason) {
4843
- super(reason);
4844
- }
4845
- };
4846
-
4847
5004
  // src/lib/chunk.ts
4848
5005
  function chunk(array, size) {
4849
5006
  const chunks = [];
@@ -5301,14 +5458,6 @@ function splitFileIntoParts(file) {
5301
5458
  }
5302
5459
  return parts;
5303
5460
  }
5304
- var CommentsApiError = class extends Error {
5305
- constructor(message, status, details) {
5306
- super(message);
5307
- this.message = message;
5308
- this.status = status;
5309
- this.details = details;
5310
- }
5311
- };
5312
5461
  function createRoom(options, config) {
5313
5462
  const initialPresence = options.initialPresence;
5314
5463
  const initialStorage = options.initialStorage;
@@ -5527,114 +5676,73 @@ function createRoom(options, config) {
5527
5676
  ydoc: makeEventSource(),
5528
5677
  comments: makeEventSource()
5529
5678
  };
5530
- async function fetchClientApi(endpoint, authValue, options2, params) {
5531
- if (!endpoint.startsWith("/v2/c/rooms/")) {
5532
- raise("Expected a /v2/c/rooms/* endpoint");
5533
- }
5534
- const url2 = urljoin(config.baseUrl, endpoint, params);
5535
- const fetcher = config.polyfills?.fetch || /* istanbul ignore next */
5536
- fetch;
5537
- return await fetcher(url2, {
5538
- ...options2,
5539
- headers: {
5540
- ...options2?.headers,
5541
- Authorization: `Bearer ${getBearerTokenFromAuthValue(authValue)}`,
5542
- "X-LB-Client": PKG_VERSION || "dev"
5543
- }
5544
- });
5545
- }
5546
- async function streamFetch(authValue, roomId) {
5547
- return fetchClientApi(url`/v2/c/rooms/${roomId}/storage`, authValue, {
5548
- method: "GET",
5549
- headers: {
5550
- "Content-Type": "application/json"
5551
- }
5552
- });
5553
- }
5554
- async function httpPostToRoom(endpoint, body) {
5555
- if (!managedSocket.authValue) {
5556
- throw new Error("Not authorized");
5557
- }
5558
- return fetchClientApi(
5559
- endpoint === "/send-message" ? url`/v2/c/rooms/${config.roomId}/send-message` : url`/v2/c/rooms/${config.roomId}/text-metadata`,
5560
- managedSocket.authValue,
5561
- {
5562
- method: "POST",
5563
- headers: {
5564
- "Content-Type": "application/json"
5565
- },
5566
- body: JSON.stringify(body)
5567
- }
5568
- );
5569
- }
5679
+ const fetchPolyfill = config.polyfills?.fetch || /* istanbul ignore next */
5680
+ globalThis.fetch?.bind(globalThis);
5681
+ const httpClient1 = new HttpClient(
5682
+ config.baseUrl,
5683
+ fetchPolyfill,
5684
+ () => Promise.resolve(managedSocket.authValue ?? raise("Not authorized"))
5685
+ );
5686
+ const httpClient2 = new HttpClient(
5687
+ config.baseUrl,
5688
+ fetchPolyfill,
5689
+ () => (
5690
+ // TODO: Use the right scope
5691
+ delegates.authenticate()
5692
+ )
5693
+ );
5570
5694
  async function createTextMention(userId, mentionId) {
5571
- if (!managedSocket.authValue) {
5572
- throw new Error("Not authorized");
5573
- }
5574
- return fetchClientApi(
5575
- url`/v2/c/rooms/${config.roomId}/text-mentions`,
5576
- managedSocket.authValue,
5577
- {
5578
- method: "POST",
5579
- headers: {
5580
- "Content-Type": "application/json"
5581
- },
5582
- body: JSON.stringify({
5583
- userId,
5584
- mentionId
5585
- })
5586
- }
5587
- );
5695
+ await httpClient1.rawPost(url`/v2/c/rooms/${config.roomId}/text-mentions`, {
5696
+ userId,
5697
+ mentionId
5698
+ });
5588
5699
  }
5589
5700
  async function deleteTextMention(mentionId) {
5590
- if (!managedSocket.authValue) {
5591
- throw new Error("Not authorized");
5592
- }
5593
- return fetchClientApi(
5594
- url`/v2/c/rooms/${config.roomId}/text-mentions/${mentionId}`,
5595
- managedSocket.authValue,
5596
- {
5597
- method: "DELETE"
5598
- }
5701
+ await httpClient1.rawDelete(
5702
+ url`/v2/c/rooms/${config.roomId}/text-mentions/${mentionId}`
5599
5703
  );
5600
5704
  }
5601
5705
  async function reportTextEditor(type, rootKey) {
5602
- const authValue = await delegates.authenticate();
5603
- return fetchClientApi(
5604
- url`/v2/c/rooms/${config.roomId}/text-metadata`,
5605
- authValue,
5606
- {
5607
- method: "POST",
5608
- headers: { "Content-Type": "application/json" },
5609
- body: JSON.stringify({ type, rootKey })
5610
- }
5611
- );
5706
+ await httpClient2.rawPost(url`/v2/c/rooms/${config.roomId}/text-metadata`, {
5707
+ type,
5708
+ rootKey
5709
+ });
5612
5710
  }
5613
5711
  async function listTextVersions() {
5614
- const authValue = await delegates.authenticate();
5615
- return fetchClientApi(
5616
- url`/v2/c/rooms/${config.roomId}/versions`,
5617
- authValue,
5618
- {
5619
- method: "GET"
5620
- }
5712
+ const result = await httpClient2.get(url`/v2/c/rooms/${config.roomId}/versions`);
5713
+ return {
5714
+ versions: result.versions.map(({ createdAt, ...version }) => {
5715
+ return {
5716
+ createdAt: new Date(createdAt),
5717
+ ...version
5718
+ };
5719
+ }),
5720
+ requestedAt: new Date(result.meta.requestedAt)
5721
+ };
5722
+ }
5723
+ async function listTextVersionsSince(options2) {
5724
+ const result = await httpClient2.get(
5725
+ url`/v2/c/rooms/${config.roomId}/versions/delta`,
5726
+ { since: options2.since.toISOString() },
5727
+ { signal: options2.signal }
5621
5728
  );
5729
+ return {
5730
+ versions: result.versions.map(({ createdAt, ...version }) => {
5731
+ return {
5732
+ createdAt: new Date(createdAt),
5733
+ ...version
5734
+ };
5735
+ }),
5736
+ requestedAt: new Date(result.meta.requestedAt)
5737
+ };
5622
5738
  }
5623
5739
  async function getTextVersion(versionId) {
5624
- const authValue = await delegates.authenticate();
5625
- return fetchClientApi(
5626
- url`/v2/c/rooms/${config.roomId}/y-version/${versionId}`,
5627
- authValue,
5628
- { method: "GET" }
5740
+ return httpClient2.rawGet(
5741
+ url`/v2/c/rooms/${config.roomId}/y-version/${versionId}`
5629
5742
  );
5630
5743
  }
5631
5744
  async function createTextVersion() {
5632
- const authValue = await delegates.authenticate();
5633
- return fetchClientApi(
5634
- url`/v2/c/rooms/${config.roomId}/version`,
5635
- authValue,
5636
- { method: "POST" }
5637
- );
5745
+ await httpClient2.rawPost(url`/v2/c/rooms/${config.roomId}/version`);
5638
5746
  }
5639
5747
  function sendMessages(messages) {
5640
5748
  const serializedPayload = JSON.stringify(messages);
@@ -5642,13 +5750,14 @@ function createRoom(options, config) {
5642
5750
  if (config.unstable_fallbackToHTTP && nonce) {
5643
5751
  const size = new TextEncoder().encode(serializedPayload).length;
5644
5752
  if (size > MAX_SOCKET_MESSAGE_SIZE) {
5645
- void httpPostToRoom("/send-message", { nonce, messages }).then(
5646
- (resp) => {
5647
- if (!resp.ok && resp.status === 403) {
5648
- managedSocket.reconnect();
5649
- }
5753
+ void httpClient1.rawPost(url`/v2/c/rooms/${config.roomId}/send-message`, {
5754
+ nonce,
5755
+ messages
5756
+ }).then((resp) => {
5757
+ if (!resp.ok && resp.status === 403) {
5758
+ managedSocket.reconnect();
5650
5759
  }
5651
- );
5760
+ });
5652
5761
  warn(
5653
5762
  "Message was too large for websockets and sent over HTTP instead"
5654
5763
  );
@@ -6252,10 +6361,10 @@ ${Array.from(traces).join("\n\n")}`
6252
6361
  eventHub.storageDidLoad.notify();
6253
6362
  }
6254
6363
  async function streamStorage() {
6255
- if (!managedSocket.authValue) {
6256
- return;
6257
- }
6258
- const result = await streamFetch(managedSocket.authValue, config.roomId);
6364
+ if (!managedSocket.authValue) return;
6365
+ const result = await httpClient1.rawGet(
6366
+ url`/v2/c/rooms/${config.roomId}/storage`
6367
+ );
6259
6368
  const items = await result.json();
6260
6369
  processInitialStorage({ type: 200 /* INITIAL_STORAGE_STATE */, items });
6261
6370
  }
@@ -6464,76 +6573,25 @@ ${Array.from(traces).join("\n\n")}`
6464
6573
  ydoc: eventHub.ydoc.observable,
6465
6574
  comments: eventHub.comments.observable
6466
6575
  };
6467
- async function fetchCommentsApi(endpoint, params, options2) {
6468
- const authValue = await delegates.authenticate();
6469
- return fetchClientApi(endpoint, authValue, options2, params);
6470
- }
6471
- async function fetchCommentsJson(endpoint, options2, params) {
6472
- const response = await fetchCommentsApi(endpoint, params, options2);
6473
- if (!response.ok) {
6474
- if (response.status >= 400 && response.status < 600) {
6475
- let error3;
6476
- try {
6477
- const errorBody = await response.json();
6478
- error3 = new CommentsApiError(
6479
- errorBody.message,
6480
- response.status,
6481
- errorBody
6482
- );
6483
- } catch {
6484
- error3 = new CommentsApiError(response.statusText, response.status);
6485
- }
6486
- throw error3;
6487
- }
6488
- }
6489
- let body;
6490
- try {
6491
- body = await response.json();
6492
- } catch {
6493
- body = {};
6494
- }
6495
- return body;
6496
- }
6497
6576
  async function getThreadsSince(options2) {
6498
- const response = await fetchCommentsApi(
6577
+ const result = await httpClient2.get(
6499
6578
  url`/v2/c/rooms/${config.roomId}/threads/delta`,
6500
6579
  { since: options2?.since?.toISOString() },
6501
- {
6502
- headers: {
6503
- "Content-Type": "application/json"
6504
- }
6505
- }
6580
+ { signal: options2.signal }
6506
6581
  );
6507
- if (response.ok) {
6508
- const json = await response.json();
6509
- return {
6510
- threads: {
6511
- updated: json.data.map(convertToThreadData),
6512
- deleted: json.deletedThreads.map(convertToThreadDeleteInfo)
6513
- },
6514
- inboxNotifications: {
6515
- updated: json.inboxNotifications.map(convertToInboxNotificationData),
6516
- deleted: json.deletedInboxNotifications.map(
6517
- convertToInboxNotificationDeleteInfo
6518
- )
6519
- },
6520
- requestedAt: new Date(json.meta.requestedAt)
6521
- };
6522
- } else if (response.status === 404) {
6523
- return {
6524
- threads: {
6525
- updated: [],
6526
- deleted: []
6527
- },
6528
- inboxNotifications: {
6529
- updated: [],
6530
- deleted: []
6531
- },
6532
- requestedAt: /* @__PURE__ */ new Date()
6533
- };
6534
- } else {
6535
- throw new Error("There was an error while getting threads.");
6536
- }
6582
+ return {
6583
+ threads: {
6584
+ updated: result.data.map(convertToThreadData),
6585
+ deleted: result.deletedThreads.map(convertToThreadDeleteInfo)
6586
+ },
6587
+ inboxNotifications: {
6588
+ updated: result.inboxNotifications.map(convertToInboxNotificationData),
6589
+ deleted: result.deletedInboxNotifications.map(
6590
+ convertToInboxNotificationDeleteInfo
6591
+ )
6592
+ },
6593
+ requestedAt: new Date(result.meta.requestedAt)
6594
+ };
6537
6595
  }
6538
6596
  async function getThreads(options2) {
6539
6597
  let query;
@@ -6541,40 +6599,22 @@ ${Array.from(traces).join("\n\n")}`
6541
6599
  query = objectToQuery(options2.query);
6542
6600
  }
6543
6601
  const PAGE_SIZE = 50;
6544
- const response = await fetchCommentsApi(
6545
- url`/v2/c/rooms/${config.roomId}/threads`,
6546
- {
6547
- cursor: options2?.cursor,
6548
- query,
6549
- limit: PAGE_SIZE
6550
- },
6551
- { headers: { "Content-Type": "application/json" } }
6552
- );
6553
- if (response.ok) {
6554
- const json = await response.json();
6555
- return {
6556
- threads: json.data.map(convertToThreadData),
6557
- inboxNotifications: json.inboxNotifications.map(
6558
- convertToInboxNotificationData
6559
- ),
6560
- nextCursor: json.meta.nextCursor,
6561
- requestedAt: new Date(json.meta.requestedAt)
6562
- };
6563
- } else if (response.status === 404) {
6564
- return {
6565
- threads: [],
6566
- inboxNotifications: [],
6567
- deletedThreads: [],
6568
- deletedInboxNotifications: [],
6569
- nextCursor: null,
6570
- requestedAt: /* @__PURE__ */ new Date()
6571
- };
6572
- } else {
6573
- throw new Error("There was an error while getting threads.");
6574
- }
6602
+ const result = await httpClient2.get(url`/v2/c/rooms/${config.roomId}/threads`, {
6603
+ cursor: options2?.cursor,
6604
+ query,
6605
+ limit: PAGE_SIZE
6606
+ });
6607
+ return {
6608
+ threads: result.data.map(convertToThreadData),
6609
+ inboxNotifications: result.inboxNotifications.map(
6610
+ convertToInboxNotificationData
6611
+ ),
6612
+ nextCursor: result.meta.nextCursor,
6613
+ requestedAt: new Date(result.meta.requestedAt)
6614
+ };
6575
6615
  }
6576
6616
  async function getThread(threadId) {
6577
- const response = await fetchCommentsApi(
6617
+ const response = await httpClient2.rawGet(
6578
6618
  url`/v2/c/rooms/${config.roomId}/thread-with-notification/${threadId}`
6579
6619
  );
6580
6620
  if (response.ok) {
@@ -6599,57 +6639,42 @@ ${Array.from(traces).join("\n\n")}`
6599
6639
  threadId = createThreadId(),
6600
6640
  attachmentIds
6601
6641
  }) {
6602
- const thread = await fetchCommentsJson(
6642
+ const thread = await httpClient2.post(
6603
6643
  url`/v2/c/rooms/${config.roomId}/threads`,
6604
6644
  {
6605
- method: "POST",
6606
- headers: {
6607
- "Content-Type": "application/json"
6645
+ id: threadId,
6646
+ comment: {
6647
+ id: commentId,
6648
+ body,
6649
+ attachmentIds
6608
6650
  },
6609
- body: JSON.stringify({
6610
- id: threadId,
6611
- comment: {
6612
- id: commentId,
6613
- body,
6614
- attachmentIds
6615
- },
6616
- metadata
6617
- })
6651
+ metadata
6618
6652
  }
6619
6653
  );
6620
6654
  return convertToThreadData(thread);
6621
6655
  }
6622
6656
  async function deleteThread(threadId) {
6623
- await fetchCommentsJson(
6624
- url`/v2/c/rooms/${config.roomId}/threads/${threadId}`,
6625
- { method: "DELETE" }
6657
+ await httpClient2.delete(
6658
+ url`/v2/c/rooms/${config.roomId}/threads/${threadId}`
6626
6659
  );
6627
6660
  }
6628
6661
  async function editThreadMetadata({
6629
6662
  metadata,
6630
6663
  threadId
6631
6664
  }) {
6632
- return await fetchCommentsJson(
6665
+ return await httpClient2.post(
6633
6666
  url`/v2/c/rooms/${config.roomId}/threads/${threadId}/metadata`,
6634
- {
6635
- method: "POST",
6636
- headers: {
6637
- "Content-Type": "application/json"
6638
- },
6639
- body: JSON.stringify(metadata)
6640
- }
6667
+ metadata
6641
6668
  );
6642
6669
  }
6643
6670
  async function markThreadAsResolved(threadId) {
6644
- await fetchCommentsJson(
6645
- url`/v2/c/rooms/${config.roomId}/threads/${threadId}/mark-as-resolved`,
6646
- { method: "POST" }
6671
+ await httpClient2.post(
6672
+ url`/v2/c/rooms/${config.roomId}/threads/${threadId}/mark-as-resolved`
6647
6673
  );
6648
6674
  }
6649
6675
  async function markThreadAsUnresolved(threadId) {
6650
- await fetchCommentsJson(
6651
- url`/v2/c/rooms/${config.roomId}/threads/${threadId}/mark-as-unresolved`,
6652
- { method: "POST" }
6676
+ await httpClient2.post(
6677
+ url`/v2/c/rooms/${config.roomId}/threads/${threadId}/mark-as-unresolved`
6653
6678
  );
6654
6679
  }
6655
6680
  async function createComment({
@@ -6658,18 +6683,12 @@ ${Array.from(traces).join("\n\n")}`
6658
6683
  body,
6659
6684
  attachmentIds
6660
6685
  }) {
6661
- const comment = await fetchCommentsJson(
6686
+ const comment = await httpClient2.post(
6662
6687
  url`/v2/c/rooms/${config.roomId}/threads/${threadId}/comments`,
6663
6688
  {
6664
- method: "POST",
6665
- headers: {
6666
- "Content-Type": "application/json"
6667
- },
6668
- body: JSON.stringify({
6669
- id: commentId,
6670
- body,
6671
- attachmentIds
6672
- })
6689
+ id: commentId,
6690
+ body,
6691
+ attachmentIds
6673
6692
  }
6674
6693
  );
6675
6694
  return convertToCommentData(comment);
@@ -6680,17 +6699,11 @@ ${Array.from(traces).join("\n\n")}`
6680
6699
  body,
6681
6700
  attachmentIds
6682
6701
  }) {
6683
- const comment = await fetchCommentsJson(
6702
+ const comment = await httpClient2.post(
6684
6703
  url`/v2/c/rooms/${config.roomId}/threads/${threadId}/comments/${commentId}`,
6685
6704
  {
6686
- method: "POST",
6687
- headers: {
6688
- "Content-Type": "application/json"
6689
- },
6690
- body: JSON.stringify({
6691
- body,
6692
- attachmentIds
6693
- })
6705
+ body,
6706
+ attachmentIds
6694
6707
  }
6695
6708
  );
6696
6709
  return convertToCommentData(comment);
@@ -6699,9 +6712,8 @@ ${Array.from(traces).join("\n\n")}`
6699
6712
  threadId,
6700
6713
  commentId
6701
6714
  }) {
6702
- await fetchCommentsJson(
6703
- url`/v2/c/rooms/${config.roomId}/threads/${threadId}/comments/${commentId}`,
6704
- { method: "DELETE" }
6715
+ await httpClient2.delete(
6716
+ url`/v2/c/rooms/${config.roomId}/threads/${threadId}/comments/${commentId}`
6705
6717
  );
6706
6718
  }
6707
6719
  async function addReaction({
@@ -6709,15 +6721,9 @@ ${Array.from(traces).join("\n\n")}`
6709
6721
  commentId,
6710
6722
  emoji
6711
6723
  }) {
6712
- const reaction = await fetchCommentsJson(
6724
+ const reaction = await httpClient2.post(
6713
6725
  url`/v2/c/rooms/${config.roomId}/threads/${threadId}/comments/${commentId}/reactions`,
6714
- {
6715
- method: "POST",
6716
- headers: {
6717
- "Content-Type": "application/json"
6718
- },
6719
- body: JSON.stringify({ emoji })
6720
- }
6726
+ { emoji }
6721
6727
  );
6722
6728
  return convertToCommentUserReaction(reaction);
6723
6729
  }
@@ -6726,9 +6732,8 @@ ${Array.from(traces).join("\n\n")}`
6726
6732
  commentId,
6727
6733
  emoji
6728
6734
  }) {
6729
- await fetchCommentsJson(
6730
- url`/v2/c/rooms/${config.roomId}/threads/${threadId}/comments/${commentId}/reactions/${emoji}`,
6731
- { method: "DELETE" }
6735
+ await httpClient2.delete(
6736
+ url`/v2/c/rooms/${config.roomId}/threads/${threadId}/comments/${commentId}/reactions/${emoji}`
6732
6737
  );
6733
6738
  }
6734
6739
  function prepareAttachment(file) {
@@ -6755,23 +6760,18 @@ ${Array.from(traces).join("\n\n")}`
6755
6760
  if (abortSignal?.aborted) {
6756
6761
  throw abortError;
6757
6762
  }
6758
- if (err instanceof CommentsApiError && err.status === 413) {
6763
+ if (err instanceof HttpError && err.status === 413) {
6759
6764
  throw err;
6760
6765
  }
6761
6766
  return false;
6762
6767
  };
6763
6768
  if (attachment.size <= ATTACHMENT_PART_SIZE) {
6764
6769
  return autoRetry(
6765
- () => fetchCommentsJson(
6770
+ () => httpClient2.putBlob(
6766
6771
  url`/v2/c/rooms/${config.roomId}/attachments/${attachment.id}/upload/${encodeURIComponent(attachment.name)}`,
6767
- {
6768
- method: "PUT",
6769
- body: attachment.file,
6770
- signal: abortSignal
6771
- },
6772
- {
6773
- fileSize: attachment.size
6774
- }
6772
+ attachment.file,
6773
+ { fileSize: attachment.size },
6774
+ { signal: abortSignal }
6775
6775
  ),
6776
6776
  RETRY_ATTEMPTS,
6777
6777
  RETRY_DELAYS,
@@ -6781,15 +6781,11 @@ ${Array.from(traces).join("\n\n")}`
6781
6781
  let uploadId;
6782
6782
  const uploadedParts = [];
6783
6783
  const createMultiPartUpload = await autoRetry(
6784
- () => fetchCommentsJson(
6784
+ () => httpClient2.post(
6785
6785
  url`/v2/c/rooms/${config.roomId}/attachments/${attachment.id}/multipart/${encodeURIComponent(attachment.name)}`,
6786
- {
6787
- method: "POST",
6788
- signal: abortSignal
6789
- },
6790
- {
6791
- fileSize: attachment.size
6792
- }
6786
+ void 0,
6787
+ { signal: abortSignal },
6788
+ { fileSize: attachment.size }
6793
6789
  ),
6794
6790
  RETRY_ATTEMPTS,
6795
6791
  RETRY_DELAYS,
@@ -6807,13 +6803,11 @@ ${Array.from(traces).join("\n\n")}`
6807
6803
  for (const { part, partNumber } of parts2) {
6808
6804
  uploadedPartsPromises.push(
6809
6805
  autoRetry(
6810
- () => fetchCommentsJson(
6806
+ () => httpClient2.putBlob(
6811
6807
  url`/v2/c/rooms/${config.roomId}/attachments/${attachment.id}/multipart/${createMultiPartUpload.uploadId}/${String(partNumber)}`,
6812
- {
6813
- method: "PUT",
6814
- body: part,
6815
- signal: abortSignal
6816
- }
6808
+ part,
6809
+ void 0,
6810
+ { signal: abortSignal }
6817
6811
  ),
6818
6812
  RETRY_ATTEMPTS,
6819
6813
  RETRY_DELAYS,
@@ -6829,26 +6823,16 @@ ${Array.from(traces).join("\n\n")}`
6829
6823
  const sortedUploadedParts = uploadedParts.sort(
6830
6824
  (a, b) => a.partNumber - b.partNumber
6831
6825
  );
6832
- return fetchCommentsJson(
6826
+ return httpClient2.post(
6833
6827
  url`/v2/c/rooms/${config.roomId}/attachments/${attachment.id}/multipart/${uploadId}/complete`,
6834
- {
6835
- method: "POST",
6836
- headers: {
6837
- "Content-Type": "application/json"
6838
- },
6839
- body: JSON.stringify({ parts: sortedUploadedParts }),
6840
- signal: abortSignal
6841
- }
6828
+ { parts: sortedUploadedParts },
6829
+ { signal: abortSignal }
6842
6830
  );
6843
6831
  } catch (error3) {
6844
6832
  if (uploadId && error3?.name && (error3.name === "AbortError" || error3.name === "TimeoutError")) {
6845
6833
  try {
6846
- await fetchCommentsApi(
6847
- url`/v2/c/rooms/${config.roomId}/attachments/${attachment.id}/multipart/${uploadId}`,
6848
- void 0,
6849
- {
6850
- method: "DELETE"
6851
- }
6834
+ await httpClient2.rawDelete(
6835
+ url`/v2/c/rooms/${config.roomId}/attachments/${attachment.id}/multipart/${uploadId}`
6852
6836
  );
6853
6837
  } catch (error4) {
6854
6838
  }
@@ -6858,16 +6842,9 @@ ${Array.from(traces).join("\n\n")}`
6858
6842
  }
6859
6843
  }
6860
6844
  async function getAttachmentUrls(attachmentIds) {
6861
- const { urls } = await fetchCommentsJson(
6862
- url`/v2/c/rooms/${config.roomId}/attachments/presigned-urls`,
6863
- {
6864
- method: "POST",
6865
- headers: {
6866
- "Content-Type": "application/json"
6867
- },
6868
- body: JSON.stringify({ attachmentIds })
6869
- }
6870
- );
6845
+ const { urls } = await httpClient2.post(url`/v2/c/rooms/${config.roomId}/attachments/presigned-urls`, {
6846
+ attachmentIds
6847
+ });
6871
6848
  return urls;
6872
6849
  }
6873
6850
  const batchedGetAttachmentUrls = new Batch(
@@ -6885,38 +6862,12 @@ ${Array.from(traces).join("\n\n")}`
6885
6862
  return batchedGetAttachmentUrls.get(attachmentId);
6886
6863
  }
6887
6864
  async function fetchNotificationsJson(endpoint, options2) {
6888
- const authValue = await delegates.authenticate();
6889
- const response = await fetchClientApi(endpoint, authValue, options2);
6890
- if (!response.ok) {
6891
- if (response.status >= 400 && response.status < 600) {
6892
- let error3;
6893
- try {
6894
- const errorBody = await response.json();
6895
- error3 = new NotificationsApiError(
6896
- errorBody.message,
6897
- response.status,
6898
- errorBody
6899
- );
6900
- } catch {
6901
- error3 = new NotificationsApiError(
6902
- response.statusText,
6903
- response.status
6904
- );
6905
- }
6906
- throw error3;
6907
- }
6908
- }
6909
- let body;
6910
- try {
6911
- body = await response.json();
6912
- } catch {
6913
- body = {};
6914
- }
6915
- return body;
6865
+ return await httpClient2.get(endpoint, void 0, options2);
6916
6866
  }
6917
- function getNotificationSettings() {
6867
+ function getNotificationSettings(options2) {
6918
6868
  return fetchNotificationsJson(
6919
- url`/v2/c/rooms/${config.roomId}/notification-settings`
6869
+ url`/v2/c/rooms/${config.roomId}/notification-settings`,
6870
+ { signal: options2?.signal }
6920
6871
  );
6921
6872
  }
6922
6873
  function updateNotificationSettings(settings) {
@@ -6924,10 +6875,7 @@ ${Array.from(traces).join("\n\n")}`
6924
6875
  url`/v2/c/rooms/${config.roomId}/notification-settings`,
6925
6876
  {
6926
6877
  method: "POST",
6927
- body: JSON.stringify(settings),
6928
- headers: {
6929
- "Content-Type": "application/json"
6930
- }
6878
+ body: JSON.stringify(settings)
6931
6879
  }
6932
6880
  );
6933
6881
  }
@@ -6936,9 +6884,6 @@ ${Array.from(traces).join("\n\n")}`
6936
6884
  url`/v2/c/rooms/${config.roomId}/inbox-notifications/read`,
6937
6885
  {
6938
6886
  method: "POST",
6939
- headers: {
6940
- "Content-Type": "application/json"
6941
- },
6942
6887
  body: JSON.stringify({ inboxNotificationIds })
6943
6888
  }
6944
6889
  );
@@ -6985,6 +6930,8 @@ ${Array.from(traces).join("\n\n")}`
6985
6930
  deleteTextMention,
6986
6931
  // list versions of the document
6987
6932
  listTextVersions,
6933
+ // List versions of the document since the specified date
6934
+ listTextVersionsSince,
6988
6935
  // get a specific version
6989
6936
  getTextVersion,
6990
6937
  // create a version
@@ -7307,11 +7254,11 @@ function createClient(options) {
7307
7254
  }
7308
7255
  }
7309
7256
  const currentUserIdStore = createStore(null);
7310
- const fetcher = clientOptions.polyfills?.fetch || /* istanbul ignore next */
7311
- fetch;
7312
- const httpClientLike = createNotificationsApi({
7257
+ const fetchPolyfill = clientOptions.polyfills?.fetch || /* istanbul ignore next */
7258
+ globalThis.fetch?.bind(globalThis);
7259
+ const notificationsAPI = createNotificationsApi({
7313
7260
  baseUrl,
7314
- fetcher,
7261
+ fetchPolyfill,
7315
7262
  authManager,
7316
7263
  currentUserIdStore
7317
7264
  });
@@ -7330,6 +7277,9 @@ function createClient(options) {
7330
7277
  { delay: RESOLVE_USERS_BATCH_DELAY }
7331
7278
  );
7332
7279
  const usersStore = createBatchStore(batchedResolveUsers);
7280
+ function invalidateResolvedUsers(userIds) {
7281
+ usersStore.invalidate(userIds);
7282
+ }
7333
7283
  const resolveRoomsInfo = clientOptions.resolveRoomsInfo;
7334
7284
  const warnIfNoResolveRoomsInfo = createDevelopmentWarning(
7335
7285
  () => !resolveRoomsInfo,
@@ -7345,15 +7295,29 @@ function createClient(options) {
7345
7295
  { delay: RESOLVE_ROOMS_INFO_BATCH_DELAY }
7346
7296
  );
7347
7297
  const roomsInfoStore = createBatchStore(batchedResolveRoomsInfo);
7348
- return Object.defineProperty(
7298
+ function invalidateResolvedRoomsInfo(roomIds) {
7299
+ roomsInfoStore.invalidate(roomIds);
7300
+ }
7301
+ const mentionSuggestionsCache = /* @__PURE__ */ new Map();
7302
+ function invalidateResolvedMentionSuggestions() {
7303
+ mentionSuggestionsCache.clear();
7304
+ }
7305
+ const client = Object.defineProperty(
7349
7306
  {
7350
7307
  enterRoom,
7351
7308
  getRoom,
7352
7309
  logout,
7353
- ...httpClientLike,
7310
+ ...notificationsAPI,
7311
+ // Advanced resolvers APIs
7312
+ resolvers: {
7313
+ invalidateUsers: invalidateResolvedUsers,
7314
+ invalidateRoomsInfo: invalidateResolvedRoomsInfo,
7315
+ invalidateMentionSuggestions: invalidateResolvedMentionSuggestions
7316
+ },
7354
7317
  // Internal
7355
7318
  [kInternal]: {
7356
7319
  currentUserIdStore,
7320
+ mentionSuggestionsCache,
7357
7321
  resolveMentionSuggestions: clientOptions.resolveMentionSuggestions,
7358
7322
  usersStore,
7359
7323
  roomsInfoStore,
@@ -7361,8 +7325,10 @@ function createClient(options) {
7361
7325
  return Array.from(roomsById.keys());
7362
7326
  },
7363
7327
  // "All" threads (= "user" threads)
7364
- getUserThreads_experimental: httpClientLike.getUserThreads_experimental,
7365
- getUserThreadsSince_experimental: httpClientLike.getUserThreadsSince_experimental
7328
+ getUserThreads_experimental: notificationsAPI.getUserThreads_experimental,
7329
+ getUserThreadsSince_experimental: notificationsAPI.getUserThreadsSince_experimental,
7330
+ // Type-level helper only, it's effectively only an identity-function at runtime
7331
+ as: () => client
7366
7332
  }
7367
7333
  },
7368
7334
  kInternal,
@@ -7370,15 +7336,8 @@ function createClient(options) {
7370
7336
  enumerable: false
7371
7337
  }
7372
7338
  );
7339
+ return client;
7373
7340
  }
7374
- var NotificationsApiError = class extends Error {
7375
- constructor(message, status, details) {
7376
- super(message);
7377
- this.message = message;
7378
- this.status = status;
7379
- this.details = details;
7380
- }
7381
- };
7382
7341
  function checkBounds(option, value, min, max, recommendedMin) {
7383
7342
  if (typeof value !== "number" || value < min || max !== void 0 && value > max) {
7384
7343
  throw new Error(
@@ -8096,45 +8055,102 @@ function errorIf(condition, message) {
8096
8055
  }
8097
8056
 
8098
8057
  // src/lib/Poller.ts
8099
- function makePoller(callback, interval) {
8100
- let context = { state: "stopped" };
8101
- function poll() {
8102
- if (context.state === "running") {
8103
- schedule();
8104
- }
8105
- void callback();
8106
- }
8107
- function schedule() {
8108
- context = {
8109
- state: "running",
8110
- lastScheduledAt: performance.now(),
8111
- timeoutHandle: setTimeout(poll, interval)
8112
- };
8113
- }
8114
- function start() {
8115
- if (context.state === "running") {
8116
- return;
8058
+ var BACKOFF_DELAYS2 = [1e3, 2e3, 4e3, 8e3, 1e4];
8059
+ function makePoller(callback, intervalMs, options) {
8060
+ const startTime = performance.now();
8061
+ const doc = typeof document !== "undefined" ? document : void 0;
8062
+ const win = typeof window !== "undefined" ? window : void 0;
8063
+ const maxStaleTimeMs = options?.maxStaleTimeMs ?? Number.POSITIVE_INFINITY;
8064
+ const context = {
8065
+ inForeground: doc?.visibilityState !== "hidden",
8066
+ lastSuccessfulPollAt: startTime,
8067
+ count: 0,
8068
+ backoff: 0
8069
+ };
8070
+ function mayPoll() {
8071
+ return context.count > 0 && context.inForeground;
8072
+ }
8073
+ const fsm = new FSM({}).addState("@idle").addState("@enabled").addState("@polling");
8074
+ fsm.addTransitions("@idle", { START: "@enabled" });
8075
+ fsm.addTransitions("@enabled", { STOP: "@idle", POLL: "@polling" });
8076
+ fsm.addTimedTransition(
8077
+ "@enabled",
8078
+ () => {
8079
+ const lastPoll = context.lastSuccessfulPollAt;
8080
+ const nextPoll = lastPoll + intervalMs;
8081
+ return Math.max(0, nextPoll - performance.now()) + context.backoff;
8082
+ },
8083
+ "@polling"
8084
+ );
8085
+ fsm.onEnterAsync(
8086
+ "@polling",
8087
+ async (_ctx, signal) => {
8088
+ await callback(signal);
8089
+ if (!signal.aborted) {
8090
+ context.lastSuccessfulPollAt = performance.now();
8091
+ }
8092
+ },
8093
+ // When OK
8094
+ () => {
8095
+ return {
8096
+ target: mayPoll() ? "@enabled" : "@idle",
8097
+ effect: () => {
8098
+ context.backoff = 0;
8099
+ }
8100
+ };
8101
+ },
8102
+ // When error
8103
+ () => {
8104
+ return {
8105
+ target: mayPoll() ? "@enabled" : "@idle",
8106
+ effect: () => {
8107
+ context.backoff = BACKOFF_DELAYS2.find((delay) => delay > context.backoff) ?? BACKOFF_DELAYS2[BACKOFF_DELAYS2.length - 1];
8108
+ }
8109
+ };
8110
+ },
8111
+ 3e4
8112
+ // Abort the poll if the callback takes more than 30 seconds to complete
8113
+ );
8114
+ function startOrStop() {
8115
+ if (mayPoll()) {
8116
+ fsm.send({ type: "START" });
8117
+ } else {
8118
+ fsm.send({ type: "STOP" });
8117
8119
  }
8118
- schedule();
8119
8120
  }
8120
- function stop() {
8121
- if (context.state === "stopped") {
8122
- return;
8123
- }
8124
- if (context.timeoutHandle) {
8125
- clearTimeout(context.timeoutHandle);
8121
+ function inc() {
8122
+ context.count++;
8123
+ startOrStop();
8124
+ }
8125
+ function dec() {
8126
+ context.count--;
8127
+ if (context.count < 0) {
8128
+ context.count = 0;
8126
8129
  }
8127
- context = { state: "stopped" };
8130
+ startOrStop();
8128
8131
  }
8129
- function enable(condition) {
8130
- if (condition) {
8131
- start();
8132
- } else {
8133
- stop();
8132
+ function pollNowIfStale() {
8133
+ if (performance.now() - context.lastSuccessfulPollAt > maxStaleTimeMs) {
8134
+ fsm.send({ type: "POLL" });
8134
8135
  }
8135
8136
  }
8137
+ function setInForeground(inForeground) {
8138
+ context.inForeground = inForeground;
8139
+ startOrStop();
8140
+ pollNowIfStale();
8141
+ }
8142
+ function onVisibilityChange() {
8143
+ setInForeground(doc?.visibilityState !== "hidden");
8144
+ }
8145
+ doc?.addEventListener("visibilitychange", onVisibilityChange);
8146
+ win?.addEventListener("online", onVisibilityChange);
8147
+ fsm.start();
8136
8148
  return {
8137
- enable
8149
+ inc,
8150
+ dec,
8151
+ pollNowIfStale,
8152
+ // Internal API, used by unit tests only to simulate visibility events
8153
+ setInForeground
8138
8154
  };
8139
8155
  }
8140
8156
 
@@ -8177,19 +8193,92 @@ function shallow(a, b) {
8177
8193
  return shallowObj(a, b);
8178
8194
  }
8179
8195
 
8196
+ // src/lib/SortedList.ts
8197
+ function bisectRight(arr, x, lt) {
8198
+ let lo = 0;
8199
+ let hi = arr.length;
8200
+ while (lo < hi) {
8201
+ const mid = lo + (hi - lo >> 1);
8202
+ if (lt(x, arr[mid])) {
8203
+ hi = mid;
8204
+ } else {
8205
+ lo = mid + 1;
8206
+ }
8207
+ }
8208
+ return lo;
8209
+ }
8210
+ var SortedList = class _SortedList {
8211
+ constructor(alreadySortedList, lt) {
8212
+ this._lt = lt;
8213
+ this._data = alreadySortedList;
8214
+ }
8215
+ static from(arr, lt) {
8216
+ const sorted = new _SortedList([], lt);
8217
+ for (const item of arr) {
8218
+ sorted.add(item);
8219
+ }
8220
+ return sorted;
8221
+ }
8222
+ static fromAlreadySorted(alreadySorted, lt) {
8223
+ return new _SortedList(alreadySorted, lt);
8224
+ }
8225
+ /**
8226
+ * Clones the sorted list to a new instance.
8227
+ */
8228
+ clone() {
8229
+ return new _SortedList(this._data.slice(), this._lt);
8230
+ }
8231
+ /**
8232
+ * Adds a new item to the sorted list, such that it remains sorted.
8233
+ */
8234
+ add(value) {
8235
+ const idx = bisectRight(this._data, value, this._lt);
8236
+ this._data.splice(idx, 0, value);
8237
+ }
8238
+ /**
8239
+ * Removes the given value from the sorted list, if it exists. The given
8240
+ * value must be `===` to one of the list items. Only the first entry will be
8241
+ * removed if the element exists in the sorted list multiple times.
8242
+ */
8243
+ remove(value) {
8244
+ const idx = this._data.indexOf(value);
8245
+ if (idx >= 0) {
8246
+ this._data.splice(idx, 1);
8247
+ return true;
8248
+ }
8249
+ return false;
8250
+ }
8251
+ get length() {
8252
+ return this._data.length;
8253
+ }
8254
+ *filter(predicate) {
8255
+ for (const item of this._data) {
8256
+ if (predicate(item)) {
8257
+ yield item;
8258
+ }
8259
+ }
8260
+ }
8261
+ [Symbol.iterator]() {
8262
+ return this._data[Symbol.iterator]();
8263
+ }
8264
+ };
8265
+
8180
8266
  // src/index.ts
8181
8267
  detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
8268
+ var CommentsApiError = HttpError;
8269
+ var NotificationsApiError = HttpError;
8182
8270
  export {
8183
8271
  ClientMsgCode,
8184
8272
  CommentsApiError,
8185
8273
  CrdtType,
8274
+ HttpError,
8186
8275
  LiveList,
8187
8276
  LiveMap,
8188
8277
  LiveObject,
8189
8278
  NotificationsApiError,
8190
8279
  OpCode,
8191
8280
  ServerMsgCode,
8192
- StopRetrying2 as StopRetrying,
8281
+ SortedList,
8193
8282
  WebsocketCloseCodes,
8194
8283
  ackOp,
8195
8284
  asPos,