@liveblocks/core 3.21.0-private1 → 3.21.0-private2

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.cjs 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 = "3.21.0-private1";
9
+ var PKG_VERSION = "3.21.0-private2";
10
10
  var PKG_FORMAT = "cjs";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -1718,7 +1718,7 @@ function createApiClient({
1718
1718
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}`,
1719
1719
  await authManager.getAuthValue({
1720
1720
  roomId: options.roomId,
1721
- resource: "comments",
1721
+ resource: commentsResourceForVisibility(options.visibility),
1722
1722
  access: "write"
1723
1723
  })
1724
1724
  );
@@ -1756,7 +1756,7 @@ function createApiClient({
1756
1756
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/metadata`,
1757
1757
  await authManager.getAuthValue({
1758
1758
  roomId: options.roomId,
1759
- resource: "comments",
1759
+ resource: commentsResourceForVisibility(options.visibility),
1760
1760
  access: "write"
1761
1761
  }),
1762
1762
  options.metadata
@@ -1767,7 +1767,7 @@ function createApiClient({
1767
1767
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}/metadata`,
1768
1768
  await authManager.getAuthValue({
1769
1769
  roomId: options.roomId,
1770
- resource: "comments",
1770
+ resource: commentsResourceForVisibility(options.visibility),
1771
1771
  access: "write"
1772
1772
  }),
1773
1773
  options.metadata
@@ -1779,7 +1779,7 @@ function createApiClient({
1779
1779
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments`,
1780
1780
  await authManager.getAuthValue({
1781
1781
  roomId: options.roomId,
1782
- resource: "comments",
1782
+ resource: commentsResourceForVisibility(options.visibility),
1783
1783
  access: "write"
1784
1784
  }),
1785
1785
  {
@@ -1796,7 +1796,7 @@ function createApiClient({
1796
1796
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}`,
1797
1797
  await authManager.getAuthValue({
1798
1798
  roomId: options.roomId,
1799
- resource: "comments",
1799
+ resource: commentsResourceForVisibility(options.visibility),
1800
1800
  access: "write"
1801
1801
  }),
1802
1802
  {
@@ -1812,7 +1812,7 @@ function createApiClient({
1812
1812
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}`,
1813
1813
  await authManager.getAuthValue({
1814
1814
  roomId: options.roomId,
1815
- resource: "comments",
1815
+ resource: commentsResourceForVisibility(options.visibility),
1816
1816
  access: "write"
1817
1817
  })
1818
1818
  );
@@ -1822,7 +1822,7 @@ function createApiClient({
1822
1822
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}/reactions`,
1823
1823
  await authManager.getAuthValue({
1824
1824
  roomId: options.roomId,
1825
- resource: "comments",
1825
+ resource: commentsResourceForVisibility(options.visibility),
1826
1826
  access: "write"
1827
1827
  }),
1828
1828
  { emoji: options.emoji }
@@ -1834,7 +1834,7 @@ function createApiClient({
1834
1834
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/comments/${options.commentId}/reactions/${options.emoji}`,
1835
1835
  await authManager.getAuthValue({
1836
1836
  roomId: options.roomId,
1837
- resource: "comments",
1837
+ resource: commentsResourceForVisibility(options.visibility),
1838
1838
  access: "write"
1839
1839
  })
1840
1840
  );
@@ -1844,7 +1844,7 @@ function createApiClient({
1844
1844
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/mark-as-resolved`,
1845
1845
  await authManager.getAuthValue({
1846
1846
  roomId: options.roomId,
1847
- resource: "comments",
1847
+ resource: commentsResourceForVisibility(options.visibility),
1848
1848
  access: "write"
1849
1849
  })
1850
1850
  );
@@ -1854,7 +1854,7 @@ function createApiClient({
1854
1854
  url`/v2/c/rooms/${options.roomId}/threads/${options.threadId}/mark-as-unresolved`,
1855
1855
  await authManager.getAuthValue({
1856
1856
  roomId: options.roomId,
1857
- resource: "comments",
1857
+ resource: commentsResourceForVisibility(options.visibility),
1858
1858
  access: "write"
1859
1859
  })
1860
1860
  );
@@ -5207,9 +5207,6 @@ var Permission = {
5207
5207
  CommentsPrivateWrite: "comments:private:write",
5208
5208
  CommentsPrivateRead: "comments:private:read",
5209
5209
  CommentsPrivateNone: "comments:private:none",
5210
- CommentsPersonalWrite: "comments:personal:write",
5211
- CommentsPersonalRead: "comments:personal:read",
5212
- CommentsPersonalNone: "comments:personal:none",
5213
5210
  /**
5214
5211
  * Feeds
5215
5212
  */
@@ -5227,75 +5224,11 @@ var ACCESS_LEVEL_RANKS = {
5227
5224
  read: 1,
5228
5225
  write: 2
5229
5226
  };
5230
- var BASE_PERMISSIONS_BY_ACCESS = {
5231
- read: [Permission.Read, Permission.RoomRead],
5232
- write: [Permission.Write, Permission.RoomWrite]
5233
- };
5234
- var NO_PERMISSION_MATRIX = {
5235
- room: "none",
5236
- storage: "none",
5237
- comments: "none",
5238
- "comments:public": "none",
5239
- "comments:private": "none",
5240
- "comments:personal": "none",
5241
- feeds: "none",
5242
- personal: "none"
5243
- };
5244
- var BASE_PERMISSION_RESOURCE = "room";
5245
- var basePermissionScopes = /* @__PURE__ */ new Set([
5246
- Permission.Read,
5247
- Permission.Write,
5248
- Permission.RoomRead,
5249
- Permission.RoomWrite
5250
- ]);
5251
- var ROOM_PERMISSION_RESOURCES = Object.freeze([
5252
- "storage",
5253
- "comments",
5254
- "comments:public",
5255
- "comments:private",
5256
- "comments:personal",
5257
- "feeds"
5258
- ]);
5259
- var CHILD_ROOM_PERMISSION_RESOURCES = (() => {
5260
- const result = /* @__PURE__ */ new Map();
5261
- for (const resource of ROOM_PERMISSION_RESOURCES) {
5262
- const childResourcePrefix = `${resource}:`;
5263
- result.set(
5264
- resource,
5265
- Object.freeze(
5266
- ROOM_PERMISSION_RESOURCES.filter((candidate) => {
5267
- if (!candidate.startsWith(childResourcePrefix)) {
5268
- return false;
5269
- }
5270
- return !candidate.slice(childResourcePrefix.length).includes(":");
5271
- })
5272
- )
5273
- );
5274
- }
5275
- return result;
5276
- })();
5277
- var LEAF_ROOM_PERMISSION_RESOURCES_BY_PARENT = (() => {
5278
- const result = /* @__PURE__ */ new Map();
5279
- for (const resource of ROOM_PERMISSION_RESOURCES) {
5280
- result.set(resource, Object.freeze(getLeafResources(resource)));
5281
- }
5282
- return result;
5283
- })();
5284
- var PARENT_ROOM_PERMISSION_RESOURCES = (() => {
5285
- const result = /* @__PURE__ */ new Map();
5286
- for (const parentResource of ROOM_PERMISSION_RESOURCES) {
5287
- for (const childResource of childResourcesOf(parentResource)) {
5288
- result.set(childResource, parentResource);
5289
- }
5290
- }
5291
- return result;
5292
- })();
5293
- var LEAF_ROOM_PERMISSION_RESOURCES = Object.freeze(
5294
- ROOM_PERMISSION_RESOURCES.filter(
5295
- (resource) => childResourcesOf(resource).length === 0
5296
- )
5297
- );
5298
- var PERMISSIONS_BY_ROOM_RESOURCE = {
5227
+ var PERMISSIONS_BY_RESOURCE = {
5228
+ room: {
5229
+ read: [Permission.Read, Permission.RoomRead],
5230
+ write: [Permission.Write, Permission.RoomWrite]
5231
+ },
5299
5232
  storage: {
5300
5233
  write: [Permission.StorageWrite],
5301
5234
  read: [Permission.StorageRead],
@@ -5316,31 +5249,134 @@ var PERMISSIONS_BY_ROOM_RESOURCE = {
5316
5249
  read: [Permission.CommentsPrivateRead],
5317
5250
  none: [Permission.CommentsPrivateNone]
5318
5251
  },
5319
- "comments:personal": {
5320
- write: [Permission.CommentsPersonalWrite],
5321
- read: [Permission.CommentsPersonalRead],
5322
- none: [Permission.CommentsPersonalNone]
5323
- },
5324
5252
  feeds: {
5325
5253
  write: [Permission.FeedsWrite],
5326
5254
  read: [Permission.FeedsRead],
5327
5255
  none: [Permission.FeedsNone]
5328
5256
  }
5329
5257
  };
5258
+ var NO_PERMISSION_MATRIX = {
5259
+ room: "none",
5260
+ storage: "none",
5261
+ comments: "none",
5262
+ "comments:public": "none",
5263
+ "comments:private": "none",
5264
+ feeds: "none",
5265
+ personal: "none"
5266
+ };
5267
+ var BASE_PERMISSION_RESOURCE = "room";
5268
+ var ROOM_PERMISSION_RESOURCES = [
5269
+ "storage",
5270
+ "comments",
5271
+ "comments:public",
5272
+ "comments:private",
5273
+ "feeds"
5274
+ ];
5275
+ var COMMENT_VISIBILITY_RESOURCES = [
5276
+ "comments:public",
5277
+ "comments:private"
5278
+ ];
5279
+ var basePermissionScopes = /* @__PURE__ */ new Set([
5280
+ Permission.Read,
5281
+ Permission.Write,
5282
+ Permission.RoomRead,
5283
+ Permission.RoomWrite
5284
+ ]);
5330
5285
  var VALID_PERMISSIONS = new Set(Object.values(Permission));
5286
+ function isPermission(permission) {
5287
+ return VALID_PERMISSIONS.has(permission);
5288
+ }
5289
+ function resolveResourceAccess(scopes, resource) {
5290
+ const permissions = PERMISSIONS_BY_RESOURCE[resource];
5291
+ let resourceAccess;
5292
+ for (const access of ACCESS_LEVELS) {
5293
+ const scopedPermissions = permissions[access];
5294
+ if (scopedPermissions !== void 0 && scopedPermissions.some((permission) => scopes.includes(permission))) {
5295
+ resourceAccess = access;
5296
+ }
5297
+ }
5298
+ return resourceAccess;
5299
+ }
5300
+ function explicitPermissionMatrixFromScopes(scopes) {
5301
+ const matrix = {};
5302
+ const baseAccess = resolveResourceAccess(scopes, BASE_PERMISSION_RESOURCE);
5303
+ if (baseAccess !== void 0) {
5304
+ matrix.room = baseAccess;
5305
+ }
5306
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5307
+ const access = resolveResourceAccess(scopes, resource);
5308
+ if (access !== void 0) {
5309
+ matrix[resource] = access;
5310
+ }
5311
+ }
5312
+ return matrix;
5313
+ }
5314
+ function permissionMatrixFromExplicitPermissions(explicitMatrix) {
5315
+ const baseAccess = explicitMatrix.room;
5316
+ if (baseAccess === void 0) {
5317
+ return { ...NO_PERMISSION_MATRIX };
5318
+ }
5319
+ const commentsAccess = _nullishCoalesce(explicitMatrix.comments, () => ( baseAccess));
5320
+ return {
5321
+ room: baseAccess,
5322
+ storage: _nullishCoalesce(explicitMatrix.storage, () => ( baseAccess)),
5323
+ comments: commentsAccess,
5324
+ "comments:public": _nullishCoalesce(explicitMatrix["comments:public"], () => ( commentsAccess)),
5325
+ "comments:private": _nullishCoalesce(explicitMatrix["comments:private"], () => ( commentsAccess)),
5326
+ feeds: _nullishCoalesce(explicitMatrix.feeds, () => ( baseAccess)),
5327
+ personal: "write"
5328
+ };
5329
+ }
5330
+ function permissionMatrixFromScopes(scopes) {
5331
+ return permissionMatrixFromExplicitPermissions(
5332
+ explicitPermissionMatrixFromScopes(scopes)
5333
+ );
5334
+ }
5335
+ function hasPermissionAccess(matrix, resource, requiredAccess) {
5336
+ const access = _nullishCoalesce(matrix[resource], () => ( "none"));
5337
+ return ACCESS_LEVEL_RANKS[access] >= ACCESS_LEVEL_RANKS[requiredAccess];
5338
+ }
5339
+ function resolveRoomPermissionMatrix(permissions, roomId) {
5340
+ const matchedPermissions = permissions.filter(
5341
+ (entry) => roomPatternMatches(entry.pattern, roomId)
5342
+ );
5343
+ if (matchedPermissions.length === 0) {
5344
+ return void 0;
5345
+ }
5346
+ const matrix = {};
5347
+ const specificityByResource = {};
5348
+ for (const entry of matchedPermissions) {
5349
+ const explicitMatrix = explicitPermissionMatrixFromScopes(entry.scopes);
5350
+ const specificity = roomPatternSpecificity(entry.pattern);
5351
+ if (explicitMatrix.room !== void 0) {
5352
+ matrix.room = strongestAccess(_nullishCoalesce(matrix.room, () => ( "none")), explicitMatrix.room);
5353
+ }
5354
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5355
+ const access = explicitAccessForResource(explicitMatrix, resource);
5356
+ if (access === void 0) {
5357
+ continue;
5358
+ }
5359
+ const currentSpecificity = _nullishCoalesce(specificityByResource[resource], () => ( -1));
5360
+ if (specificity > currentSpecificity) {
5361
+ matrix[resource] = access;
5362
+ specificityByResource[resource] = specificity;
5363
+ } else if (specificity === currentSpecificity) {
5364
+ matrix[resource] = strongestAccess(_nullishCoalesce(matrix[resource], () => ( "none")), access);
5365
+ }
5366
+ }
5367
+ }
5368
+ return permissionMatrixFromExplicitPermissions(matrix);
5369
+ }
5331
5370
  function normalizeRoomPermissions(permissions) {
5332
5371
  if (!Array.isArray(permissions)) {
5333
5372
  throw new Error("Permission list must be an array");
5334
5373
  }
5335
5374
  const result = [];
5336
5375
  for (const permission of permissions) {
5337
- const knownPermission = Object.values(Permission).find(
5338
- (value) => value === permission
5339
- );
5340
- if (knownPermission === void 0) {
5376
+ if (!isPermission(permission)) {
5341
5377
  throw new Error(`Not a valid permission: ${permission}`);
5342
5378
  }
5343
- result.push(knownPermission);
5379
+ result.push(permission);
5344
5380
  }
5345
5381
  return result;
5346
5382
  }
@@ -5366,90 +5402,28 @@ function normalizeUpdateRoomAccesses(accesses) {
5366
5402
  ])
5367
5403
  );
5368
5404
  }
5369
- function validatePermissionsSet(scopes) {
5370
- const unknownScopes = scopes.filter((scope) => !VALID_PERMISSIONS.has(scope));
5371
- if (unknownScopes.length > 0) {
5372
- return `Unknown permission scope(s): ${unknownScopes.join(", ")}`;
5373
- }
5374
- const baseScopes = scopes.filter((scope) => basePermissionScopes.has(scope));
5375
- if (baseScopes.length !== 1) {
5376
- return `Permissions must include exactly one of ${Permission.Read}, ${Permission.Write} (or the legacy aliases ${Permission.RoomRead}, ${Permission.RoomWrite}), got ${baseScopes.length === 0 ? "none" : baseScopes.join(", ")}`;
5377
- }
5378
- const seenFeatures = /* @__PURE__ */ new Set();
5379
- for (const scope of scopes) {
5380
- if (basePermissionScopes.has(scope) || scope === Permission.LegacyRoomPresenceWrite) {
5381
- continue;
5382
- }
5383
- const feature = scope.split(":").slice(0, -1).join(":");
5384
- if (seenFeatures.has(feature)) {
5385
- return `Permissions can include at most one scope per feature, got multiple "${feature}" scopes`;
5386
- }
5387
- seenFeatures.add(feature);
5388
- }
5389
- return true;
5390
- }
5391
- function permissionMatrixFromScopes(scopes) {
5392
- return permissionMatrixFromResolvedScopes(resolvePermissionScopes(scopes));
5393
- }
5394
5405
  function permissionMatrixToScopes(matrix) {
5395
5406
  const scopes = [];
5396
5407
  const baseAccess = matrix.room;
5397
5408
  if (baseAccess !== "none") {
5398
5409
  scopes.push(permissionForAccessLevel(BASE_PERMISSION_RESOURCE, baseAccess));
5399
5410
  }
5400
- for (const resource of ROOM_PERMISSION_RESOURCES) {
5401
- if (parentResourceOf(resource) === void 0) {
5402
- pushResourcePermissions(scopes, matrix, resource, baseAccess);
5403
- }
5411
+ if (matrix.storage !== baseAccess) {
5412
+ scopes.push(permissionForAccessLevel("storage", matrix.storage));
5404
5413
  }
5405
- return scopes;
5406
- }
5407
- function hasPermissionAccess(matrix, resource, requiredAccess) {
5408
- const access = _nullishCoalesce(matrix[resource], () => ( "none"));
5409
- return ACCESS_LEVEL_RANKS[access] >= ACCESS_LEVEL_RANKS[requiredAccess];
5410
- }
5411
- function resolveRoomPermissionMatrix(permissions, roomId) {
5412
- const matchedPermissions = permissions.filter((entry) => {
5413
- if (entry.pattern.includes("*")) {
5414
- return roomId.startsWith(entry.pattern.replace("*", ""));
5415
- }
5416
- return entry.pattern === roomId;
5417
- });
5418
- if (matchedPermissions.length === 0) {
5419
- return void 0;
5414
+ const commentsAccess = matrix.comments;
5415
+ if (commentsAccess !== baseAccess) {
5416
+ scopes.push(permissionForAccessLevel("comments", commentsAccess));
5420
5417
  }
5421
- let hasDefaultPermission = false;
5422
- let baseAccess = "none";
5423
- const leafAccesses = {};
5424
- const leafSpecificity = {};
5425
- for (const entry of matchedPermissions) {
5426
- const resolved = resolvePermissionScopes(entry.scopes);
5427
- const specificity = entry.pattern.replace("*", "").length;
5428
- if (resolved.baseAccess !== void 0) {
5429
- hasDefaultPermission = true;
5430
- baseAccess = strongestAccess(baseAccess, resolved.baseAccess);
5431
- }
5432
- for (const resource of LEAF_ROOM_PERMISSION_RESOURCES) {
5433
- if (resolved.leafAccesses[resource] === void 0) {
5434
- continue;
5435
- }
5436
- const access = resolveLeafAccessFromSource(resolved, resource);
5437
- const currentSpecificity = _nullishCoalesce(leafSpecificity[resource], () => ( -1));
5438
- if (specificity > currentSpecificity) {
5439
- leafAccesses[resource] = access;
5440
- leafSpecificity[resource] = specificity;
5441
- } else if (specificity === currentSpecificity) {
5442
- leafAccesses[resource] = strongestAccess(
5443
- _nullishCoalesce(leafAccesses[resource], () => ( "none")),
5444
- access
5445
- );
5446
- }
5418
+ for (const resource of COMMENT_VISIBILITY_RESOURCES) {
5419
+ if (matrix[resource] !== commentsAccess) {
5420
+ scopes.push(permissionForAccessLevel(resource, matrix[resource]));
5447
5421
  }
5448
5422
  }
5449
- return permissionMatrixFromResolvedScopes({
5450
- baseAccess: hasDefaultPermission ? baseAccess : void 0,
5451
- leafAccesses
5452
- });
5423
+ if (matrix.feeds !== baseAccess) {
5424
+ scopes.push(permissionForAccessLevel("feeds", matrix.feeds));
5425
+ }
5426
+ return scopes;
5453
5427
  }
5454
5428
  function mergeRoomPermissionScopes({
5455
5429
  defaultAccesses,
@@ -5457,139 +5431,48 @@ function mergeRoomPermissionScopes({
5457
5431
  userAccesses
5458
5432
  }) {
5459
5433
  const sources = [
5460
- resolvePermissionScopes(defaultAccesses),
5461
- mergeResolvedScopesByHighestAccess(
5462
- groupsAccesses.map(resolvePermissionScopes)
5434
+ explicitPermissionMatrixFromScopes(defaultAccesses),
5435
+ mergeExplicitPermissionMatricesByHighestAccess(
5436
+ groupsAccesses.map(explicitPermissionMatrixFromScopes)
5463
5437
  ),
5464
- resolvePermissionScopes(userAccesses)
5438
+ explicitPermissionMatrixFromScopes(userAccesses)
5465
5439
  ];
5466
- const merged = {
5467
- leafAccesses: {}
5468
- };
5440
+ const merged = {};
5469
5441
  for (const source of sources) {
5470
- if (source.baseAccess !== void 0) {
5471
- merged.baseAccess = source.baseAccess;
5442
+ if (source.room !== void 0) {
5443
+ merged.room = source.room;
5472
5444
  }
5473
- for (const resource of LEAF_ROOM_PERMISSION_RESOURCES) {
5474
- const sourceAccess = source.leafAccesses[resource];
5475
- if (sourceAccess === void 0) {
5476
- continue;
5445
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5446
+ const access = explicitAccessForResource(source, resource);
5447
+ if (access !== void 0) {
5448
+ merged[resource] = access;
5477
5449
  }
5478
- merged.leafAccesses[resource] = sourceAccess;
5479
5450
  }
5480
5451
  }
5481
- return permissionMatrixToScopes(permissionMatrixFromResolvedScopes(merged));
5482
- }
5483
- function resolvePermissionScopes(scopes) {
5484
- const baseAccess = resolveAccess(scopes, BASE_PERMISSIONS_BY_ACCESS);
5485
- const leafAccesses = {};
5486
- for (const resource of ROOM_PERMISSION_RESOURCES) {
5487
- const access = resolveResourceAccess(scopes, resource);
5488
- if (access !== void 0) {
5489
- for (const leafResource of leafResourcesOf(resource)) {
5490
- leafAccesses[leafResource] = access;
5491
- }
5492
- }
5493
- }
5494
- return { baseAccess, leafAccesses };
5495
- }
5496
- function resolveResourceAccess(scopes, resource) {
5497
- return resolveAccess(scopes, PERMISSIONS_BY_ROOM_RESOURCE[resource]);
5498
- }
5499
- function resolveAccess(scopes, permissions) {
5500
- let resourceAccess;
5501
- for (const access of ACCESS_LEVELS) {
5502
- const scopedPermissions = permissions[access];
5503
- if (scopedPermissions !== void 0 && scopedPermissions.some((permission) => scopes.includes(permission))) {
5504
- resourceAccess = access;
5505
- }
5506
- }
5507
- return resourceAccess;
5508
- }
5509
- function permissionMatrixFromResolvedScopes(resolved) {
5510
- if (resolved.baseAccess === void 0) {
5511
- return { ...NO_PERMISSION_MATRIX };
5512
- }
5513
- const matrix = {
5514
- ...NO_PERMISSION_MATRIX,
5515
- [BASE_PERMISSION_RESOURCE]: resolved.baseAccess,
5516
- personal: "write"
5517
- };
5518
- for (const resource of LEAF_ROOM_PERMISSION_RESOURCES) {
5519
- matrix[resource] = resolveLeafAccessFromSource(resolved, resource);
5520
- }
5521
- for (const resource of ROOM_PERMISSION_RESOURCES) {
5522
- if (childResourcesOf(resource).length > 0) {
5523
- let strongest = "none";
5524
- for (const leafResource of leafResourcesOf(resource)) {
5525
- strongest = strongestAccess(strongest, matrix[leafResource]);
5526
- }
5527
- matrix[resource] = strongest;
5528
- }
5529
- }
5530
- return matrix;
5531
- }
5532
- function resolveLeafAccessFromSource(source, resource) {
5533
- const access = source.leafAccesses[resource];
5534
- if (access !== void 0) {
5535
- return access;
5536
- }
5537
- return _nullishCoalesce(source.baseAccess, () => ( "none"));
5538
- }
5539
- function pushResourcePermissions(scopes, matrix, resource, baseAccess) {
5540
- const childResources = childResourcesOf(resource);
5541
- if (childResources.length === 0) {
5542
- const access = matrix[resource];
5543
- if (access !== baseAccess) {
5544
- scopes.push(permissionForAccessLevel(resource, access));
5545
- }
5546
- return;
5547
- }
5548
- const leafResources = leafResourcesOf(resource);
5549
- let sharedAccess;
5550
- let allLeavesShareAccess = true;
5551
- for (const leafResource of leafResources) {
5552
- const access = matrix[leafResource];
5553
- sharedAccess ??= access;
5554
- if (access !== sharedAccess) {
5555
- allLeavesShareAccess = false;
5556
- break;
5557
- }
5558
- }
5559
- if (sharedAccess !== void 0 && sharedAccess !== baseAccess && allLeavesShareAccess) {
5560
- scopes.push(permissionForAccessLevel(resource, sharedAccess));
5561
- return;
5562
- }
5563
- for (const childResource of childResources) {
5564
- pushResourcePermissions(scopes, matrix, childResource, baseAccess);
5565
- }
5452
+ return permissionMatrixToScopes(
5453
+ permissionMatrixFromExplicitPermissions(merged)
5454
+ );
5566
5455
  }
5567
- function mergeResolvedScopesByHighestAccess(sources) {
5568
- const merged = {
5569
- leafAccesses: {}
5570
- };
5456
+ function mergeExplicitPermissionMatricesByHighestAccess(sources) {
5457
+ const merged = {};
5571
5458
  for (const source of sources) {
5572
- if (source.baseAccess !== void 0) {
5573
- merged.baseAccess = strongestAccess(
5574
- _nullishCoalesce(merged.baseAccess, () => ( "none")),
5575
- source.baseAccess
5576
- );
5459
+ if (source.room !== void 0) {
5460
+ merged.room = strongestAccess(_nullishCoalesce(merged.room, () => ( "none")), source.room);
5577
5461
  }
5578
- for (const resource of LEAF_ROOM_PERMISSION_RESOURCES) {
5579
- const sourceAccess = source.leafAccesses[resource];
5580
- if (sourceAccess === void 0) {
5581
- continue;
5462
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5463
+ const access = explicitAccessForResource(source, resource);
5464
+ if (access !== void 0) {
5465
+ merged[resource] = strongestAccess(_nullishCoalesce(merged[resource], () => ( "none")), access);
5582
5466
  }
5583
- merged.leafAccesses[resource] = strongestAccess(
5584
- _nullishCoalesce(merged.leafAccesses[resource], () => ( "none")),
5585
- sourceAccess
5586
- );
5587
5467
  }
5588
5468
  }
5589
5469
  return merged;
5590
5470
  }
5471
+ function explicitAccessForResource(source, resource) {
5472
+ return _nullishCoalesce(source[resource], () => ( (isCommentVisibilityResource(resource) ? source.comments : void 0)));
5473
+ }
5591
5474
  function permissionForAccessLevel(resource, access, field = resource) {
5592
- const permissions = resource === "room" ? BASE_PERMISSIONS_BY_ACCESS[access] : resource === "personal" ? void 0 : PERMISSIONS_BY_ROOM_RESOURCE[resource][access];
5475
+ const permissions = PERMISSIONS_BY_RESOURCE[resource][access];
5593
5476
  const permission = _optionalChain([permissions, 'optionalAccess', _109 => _109[0]]);
5594
5477
  if (permission !== void 0) {
5595
5478
  return permission;
@@ -5601,21 +5484,43 @@ function permissionForAccessLevel(resource, access, field = resource) {
5601
5484
  function strongestAccess(left, right) {
5602
5485
  return ACCESS_LEVEL_RANKS[right] > ACCESS_LEVEL_RANKS[left] ? right : left;
5603
5486
  }
5604
- function leafResourcesOf(resource) {
5605
- return _nullishCoalesce(LEAF_ROOM_PERMISSION_RESOURCES_BY_PARENT.get(resource), () => ( []));
5606
- }
5607
- function childResourcesOf(resource) {
5608
- return _nullishCoalesce(CHILD_ROOM_PERMISSION_RESOURCES.get(resource), () => ( []));
5487
+ function roomPatternMatches(pattern, roomId) {
5488
+ if (pattern.includes("*")) {
5489
+ return roomId.startsWith(pattern.replace("*", ""));
5490
+ }
5491
+ return pattern === roomId;
5609
5492
  }
5610
- function parentResourceOf(resource) {
5611
- return PARENT_ROOM_PERMISSION_RESOURCES.get(resource);
5493
+ function roomPatternSpecificity(pattern) {
5494
+ return pattern.replace("*", "").length;
5612
5495
  }
5613
- function getLeafResources(resource) {
5614
- const childResources = childResourcesOf(resource);
5615
- if (childResources.length === 0) {
5616
- return [resource];
5496
+ function validatePermissionsSet(scopes) {
5497
+ const unknownScopes = scopes.filter((scope) => !VALID_PERMISSIONS.has(scope));
5498
+ if (unknownScopes.length > 0) {
5499
+ return `Unknown permission scope(s): ${unknownScopes.join(", ")}`;
5500
+ }
5501
+ const baseScopes = scopes.filter((scope) => basePermissionScopes.has(scope));
5502
+ if (baseScopes.length !== 1) {
5503
+ return `Permissions must include exactly one of ${Permission.Read}, ${Permission.Write} (or the legacy aliases ${Permission.RoomRead}, ${Permission.RoomWrite}), got ${baseScopes.length === 0 ? "none" : baseScopes.join(", ")}`;
5504
+ }
5505
+ const seenFeatures = /* @__PURE__ */ new Set();
5506
+ for (const scope of scopes) {
5507
+ if (basePermissionScopes.has(scope) || scope === Permission.LegacyRoomPresenceWrite) {
5508
+ continue;
5509
+ }
5510
+ const feature = permissionFeature(scope);
5511
+ if (seenFeatures.has(feature)) {
5512
+ return `Permissions can include at most one scope per feature, got multiple "${feature}" scopes`;
5513
+ }
5514
+ seenFeatures.add(feature);
5617
5515
  }
5618
- return childResources.flatMap(getLeafResources);
5516
+ return true;
5517
+ }
5518
+ function permissionFeature(scope) {
5519
+ const accessSeparatorIndex = scope.lastIndexOf(":");
5520
+ return accessSeparatorIndex === -1 ? scope : scope.slice(0, accessSeparatorIndex);
5521
+ }
5522
+ function isCommentVisibilityResource(resource) {
5523
+ return resource.startsWith("comments:");
5619
5524
  }
5620
5525
 
5621
5526
  // src/protocol/AuthToken.ts
@@ -5804,7 +5709,13 @@ function cachedTokenSatisfiesRequest(cachedToken, request) {
5804
5709
  _nullishCoalesce(cachedToken.permissions, () => ( [])),
5805
5710
  request.roomId
5806
5711
  );
5807
- return matrix !== void 0 && hasPermissionAccess(matrix, request.resource, request.access);
5712
+ if (matrix === void 0) {
5713
+ return false;
5714
+ }
5715
+ if (request.resource === "comments" && request.access === "read") {
5716
+ return hasPermissionAccess(matrix, "comments", "read") || hasPermissionAccess(matrix, "comments:public", "read") || hasPermissionAccess(matrix, "comments:private", "read");
5717
+ }
5718
+ return hasPermissionAccess(matrix, request.resource, request.access);
5808
5719
  }
5809
5720
  function prepareAuthentication(authOptions) {
5810
5721
  const { publicApiKey, authEndpoint } = authOptions;
@@ -8662,7 +8573,7 @@ var LiveObject = (_class2 = class _LiveObject extends AbstractCrdt {
8662
8573
  const preciseSize = new TextEncoder().encode(jsonString).length;
8663
8574
  if (preciseSize > MAX_LIVE_OBJECT_SIZE) {
8664
8575
  throw new Error(
8665
- `LiveObject size exceeded limit: ${preciseSize} bytes > ${MAX_LIVE_OBJECT_SIZE} bytes. See https://liveblocks.io/docs/platform/limits#Liveblocks-Storage-limits`
8576
+ `LiveObject size exceeded limit: ${preciseSize} bytes > ${MAX_LIVE_OBJECT_SIZE} bytes. See https://liveblocks.io/docs/pricing/limits#Other-limits`
8666
8577
  );
8667
8578
  }
8668
8579
  }
@@ -11605,6 +11516,7 @@ function createRoom(options, config) {
11605
11516
  yjsProviderDidChange: context.yjsProviderDidChange.observable,
11606
11517
  // send metadata when using a text editor
11607
11518
  reportTextEditor,
11519
+ getPermissionMatrix: () => _optionalChain([context, 'access', _277 => _277.dynamicSessionInfoSig, 'access', _278 => _278.get, 'call', _279 => _279(), 'optionalAccess', _280 => _280.permissionMatrix]),
11608
11520
  // create a text mention when using a text editor
11609
11521
  createTextMention,
11610
11522
  // delete a text mention when using a text editor
@@ -11659,7 +11571,7 @@ ${dumpPool(
11659
11571
  source.dispose();
11660
11572
  }
11661
11573
  eventHub.roomWillDestroy.notify();
11662
- _optionalChain([context, 'access', _277 => _277.yjsProvider, 'optionalAccess', _278 => _278.off, 'call', _279 => _279("status", yjsStatusDidChange)]);
11574
+ _optionalChain([context, 'access', _281 => _281.yjsProvider, 'optionalAccess', _282 => _282.off, 'call', _283 => _283("status", yjsStatusDidChange)]);
11663
11575
  syncSourceForStorage.destroy();
11664
11576
  syncSourceForYjs.destroy();
11665
11577
  uninstallBgTabSpy();
@@ -11821,7 +11733,7 @@ function makeClassicSubscribeFn(roomId, events, errorEvents) {
11821
11733
  }
11822
11734
  if (isLiveNode(first)) {
11823
11735
  const node = first;
11824
- if (_optionalChain([options, 'optionalAccess', _280 => _280.isDeep])) {
11736
+ if (_optionalChain([options, 'optionalAccess', _284 => _284.isDeep])) {
11825
11737
  const storageCallback = second;
11826
11738
  return subscribeToLiveStructureDeeply(node, storageCallback);
11827
11739
  } else {
@@ -11911,8 +11823,8 @@ function createClient(options) {
11911
11823
  const authManager = createAuthManager(options, (token) => {
11912
11824
  currentUserId.set(() => token.uid);
11913
11825
  });
11914
- const fetchPolyfill = _optionalChain([clientOptions, 'access', _281 => _281.polyfills, 'optionalAccess', _282 => _282.fetch]) || /* istanbul ignore next */
11915
- _optionalChain([globalThis, 'access', _283 => _283.fetch, 'optionalAccess', _284 => _284.bind, 'call', _285 => _285(globalThis)]);
11826
+ const fetchPolyfill = _optionalChain([clientOptions, 'access', _285 => _285.polyfills, 'optionalAccess', _286 => _286.fetch]) || /* istanbul ignore next */
11827
+ _optionalChain([globalThis, 'access', _287 => _287.fetch, 'optionalAccess', _288 => _288.bind, 'call', _289 => _289(globalThis)]);
11916
11828
  const httpClient = createApiClient({
11917
11829
  baseUrl,
11918
11830
  fetchPolyfill,
@@ -11929,7 +11841,7 @@ function createClient(options) {
11929
11841
  delegates: {
11930
11842
  createSocket: makeCreateSocketDelegateForAi(
11931
11843
  baseUrl,
11932
- _optionalChain([clientOptions, 'access', _286 => _286.polyfills, 'optionalAccess', _287 => _287.WebSocket])
11844
+ _optionalChain([clientOptions, 'access', _290 => _290.polyfills, 'optionalAccess', _291 => _291.WebSocket])
11933
11845
  ),
11934
11846
  authenticate: async () => {
11935
11847
  const resp = await authManager.getAuthValue({
@@ -12000,7 +11912,7 @@ function createClient(options) {
12000
11912
  createSocket: makeCreateSocketDelegateForRoom(
12001
11913
  roomId,
12002
11914
  baseUrl,
12003
- _optionalChain([clientOptions, 'access', _288 => _288.polyfills, 'optionalAccess', _289 => _289.WebSocket])
11915
+ _optionalChain([clientOptions, 'access', _292 => _292.polyfills, 'optionalAccess', _293 => _293.WebSocket])
12004
11916
  ),
12005
11917
  authenticate: makeAuthDelegateForRoom(roomId, authManager)
12006
11918
  })),
@@ -12022,7 +11934,7 @@ function createClient(options) {
12022
11934
  const shouldConnect = _nullishCoalesce(options2.autoConnect, () => ( true));
12023
11935
  if (shouldConnect) {
12024
11936
  if (typeof atob === "undefined") {
12025
- if (_optionalChain([clientOptions, 'access', _290 => _290.polyfills, 'optionalAccess', _291 => _291.atob]) === void 0) {
11937
+ if (_optionalChain([clientOptions, 'access', _294 => _294.polyfills, 'optionalAccess', _295 => _295.atob]) === void 0) {
12026
11938
  throw new Error(
12027
11939
  "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"
12028
11940
  );
@@ -12034,7 +11946,7 @@ function createClient(options) {
12034
11946
  return leaseRoom(newRoomDetails);
12035
11947
  }
12036
11948
  function getRoom(roomId) {
12037
- const room = _optionalChain([roomsById, 'access', _292 => _292.get, 'call', _293 => _293(roomId), 'optionalAccess', _294 => _294.room]);
11949
+ const room = _optionalChain([roomsById, 'access', _296 => _296.get, 'call', _297 => _297(roomId), 'optionalAccess', _298 => _298.room]);
12038
11950
  return room ? room : null;
12039
11951
  }
12040
11952
  function logout() {
@@ -12050,7 +11962,7 @@ function createClient(options) {
12050
11962
  const batchedResolveUsers = new Batch(
12051
11963
  async (batchedUserIds) => {
12052
11964
  const userIds = batchedUserIds.flat();
12053
- const users = await _optionalChain([resolveUsers, 'optionalCall', _295 => _295({ userIds })]);
11965
+ const users = await _optionalChain([resolveUsers, 'optionalCall', _299 => _299({ userIds })]);
12054
11966
  warnOnceIf(
12055
11967
  !resolveUsers,
12056
11968
  "Set the resolveUsers option in createClient to specify user info."
@@ -12067,7 +11979,7 @@ function createClient(options) {
12067
11979
  const batchedResolveRoomsInfo = new Batch(
12068
11980
  async (batchedRoomIds) => {
12069
11981
  const roomIds = batchedRoomIds.flat();
12070
- const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _296 => _296({ roomIds })]);
11982
+ const roomsInfo = await _optionalChain([resolveRoomsInfo, 'optionalCall', _300 => _300({ roomIds })]);
12071
11983
  warnOnceIf(
12072
11984
  !resolveRoomsInfo,
12073
11985
  "Set the resolveRoomsInfo option in createClient to specify room info."
@@ -12084,7 +11996,7 @@ function createClient(options) {
12084
11996
  const batchedResolveGroupsInfo = new Batch(
12085
11997
  async (batchedGroupIds) => {
12086
11998
  const groupIds = batchedGroupIds.flat();
12087
- const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _297 => _297({ groupIds })]);
11999
+ const groupsInfo = await _optionalChain([resolveGroupsInfo, 'optionalCall', _301 => _301({ groupIds })]);
12088
12000
  warnOnceIf(
12089
12001
  !resolveGroupsInfo,
12090
12002
  "Set the resolveGroupsInfo option in createClient to specify group info."
@@ -12143,7 +12055,7 @@ function createClient(options) {
12143
12055
  }
12144
12056
  };
12145
12057
  const win = typeof window !== "undefined" ? window : void 0;
12146
- _optionalChain([win, 'optionalAccess', _298 => _298.addEventListener, 'call', _299 => _299("beforeunload", maybePreventClose)]);
12058
+ _optionalChain([win, 'optionalAccess', _302 => _302.addEventListener, 'call', _303 => _303("beforeunload", maybePreventClose)]);
12147
12059
  }
12148
12060
  async function getNotificationSettings(options2) {
12149
12061
  const plainSettings = await httpClient.getNotificationSettings(options2);
@@ -12271,7 +12183,7 @@ var commentBodyElementsTypes = {
12271
12183
  mention: "inline"
12272
12184
  };
12273
12185
  function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
12274
- if (!body || !_optionalChain([body, 'optionalAccess', _300 => _300.content])) {
12186
+ if (!body || !_optionalChain([body, 'optionalAccess', _304 => _304.content])) {
12275
12187
  return;
12276
12188
  }
12277
12189
  const element = typeof elementOrVisitor === "string" ? elementOrVisitor : void 0;
@@ -12281,13 +12193,13 @@ function traverseCommentBody(body, elementOrVisitor, possiblyVisitor) {
12281
12193
  for (const block of body.content) {
12282
12194
  if (type === "all" || type === "block") {
12283
12195
  if (guard(block)) {
12284
- _optionalChain([visitor, 'optionalCall', _301 => _301(block)]);
12196
+ _optionalChain([visitor, 'optionalCall', _305 => _305(block)]);
12285
12197
  }
12286
12198
  }
12287
12199
  if (type === "all" || type === "inline") {
12288
12200
  for (const inline of block.children) {
12289
12201
  if (guard(inline)) {
12290
- _optionalChain([visitor, 'optionalCall', _302 => _302(inline)]);
12202
+ _optionalChain([visitor, 'optionalCall', _306 => _306(inline)]);
12291
12203
  }
12292
12204
  }
12293
12205
  }
@@ -12457,7 +12369,7 @@ var stringifyCommentBodyPlainElements = {
12457
12369
  text: ({ element }) => element.text,
12458
12370
  link: ({ element }) => _nullishCoalesce(element.text, () => ( element.url)),
12459
12371
  mention: ({ element, user, group }) => {
12460
- return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _303 => _303.name]), () => ( _optionalChain([group, 'optionalAccess', _304 => _304.name]))), () => ( element.id))}`;
12372
+ return `@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _307 => _307.name]), () => ( _optionalChain([group, 'optionalAccess', _308 => _308.name]))), () => ( element.id))}`;
12461
12373
  }
12462
12374
  };
12463
12375
  var stringifyCommentBodyHtmlElements = {
@@ -12487,7 +12399,7 @@ var stringifyCommentBodyHtmlElements = {
12487
12399
  return html`<a href="${href}" target="_blank" rel="noopener noreferrer">${element.text ? html`${element.text}` : element.url}</a>`;
12488
12400
  },
12489
12401
  mention: ({ element, user, group }) => {
12490
- return html`<span data-mention>@${_optionalChain([user, 'optionalAccess', _305 => _305.name]) ? html`${_optionalChain([user, 'optionalAccess', _306 => _306.name])}` : _optionalChain([group, 'optionalAccess', _307 => _307.name]) ? html`${_optionalChain([group, 'optionalAccess', _308 => _308.name])}` : element.id}</span>`;
12402
+ return html`<span data-mention>@${_optionalChain([user, 'optionalAccess', _309 => _309.name]) ? html`${_optionalChain([user, 'optionalAccess', _310 => _310.name])}` : _optionalChain([group, 'optionalAccess', _311 => _311.name]) ? html`${_optionalChain([group, 'optionalAccess', _312 => _312.name])}` : element.id}</span>`;
12491
12403
  }
12492
12404
  };
12493
12405
  var stringifyCommentBodyMarkdownElements = {
@@ -12517,20 +12429,20 @@ var stringifyCommentBodyMarkdownElements = {
12517
12429
  return markdown`[${_nullishCoalesce(element.text, () => ( element.url))}](${href})`;
12518
12430
  },
12519
12431
  mention: ({ element, user, group }) => {
12520
- return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _309 => _309.name]), () => ( _optionalChain([group, 'optionalAccess', _310 => _310.name]))), () => ( element.id))}`;
12432
+ return markdown`@${_nullishCoalesce(_nullishCoalesce(_optionalChain([user, 'optionalAccess', _313 => _313.name]), () => ( _optionalChain([group, 'optionalAccess', _314 => _314.name]))), () => ( element.id))}`;
12521
12433
  }
12522
12434
  };
12523
12435
  async function stringifyCommentBody(body, options) {
12524
- const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _311 => _311.format]), () => ( "plain"));
12525
- const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _312 => _312.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
12436
+ const format = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _315 => _315.format]), () => ( "plain"));
12437
+ const separator = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _316 => _316.separator]), () => ( (format === "markdown" ? "\n\n" : "\n")));
12526
12438
  const elements = {
12527
12439
  ...format === "html" ? stringifyCommentBodyHtmlElements : format === "markdown" ? stringifyCommentBodyMarkdownElements : stringifyCommentBodyPlainElements,
12528
- ..._optionalChain([options, 'optionalAccess', _313 => _313.elements])
12440
+ ..._optionalChain([options, 'optionalAccess', _317 => _317.elements])
12529
12441
  };
12530
12442
  const { users: resolvedUsers, groups: resolvedGroupsInfo } = await resolveMentionsInCommentBody(
12531
12443
  body,
12532
- _optionalChain([options, 'optionalAccess', _314 => _314.resolveUsers]),
12533
- _optionalChain([options, 'optionalAccess', _315 => _315.resolveGroupsInfo])
12444
+ _optionalChain([options, 'optionalAccess', _318 => _318.resolveUsers]),
12445
+ _optionalChain([options, 'optionalAccess', _319 => _319.resolveGroupsInfo])
12534
12446
  );
12535
12447
  const blocks = body.content.flatMap((block, blockIndex) => {
12536
12448
  switch (block.type) {
@@ -12665,9 +12577,9 @@ function makePoller(callback, intervalMs, options) {
12665
12577
  const startTime = performance.now();
12666
12578
  const doc = typeof document !== "undefined" ? document : void 0;
12667
12579
  const win = typeof window !== "undefined" ? window : void 0;
12668
- const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _316 => _316.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
12580
+ const maxStaleTimeMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _320 => _320.maxStaleTimeMs]), () => ( Number.POSITIVE_INFINITY));
12669
12581
  const context = {
12670
- inForeground: _optionalChain([doc, 'optionalAccess', _317 => _317.visibilityState]) !== "hidden",
12582
+ inForeground: _optionalChain([doc, 'optionalAccess', _321 => _321.visibilityState]) !== "hidden",
12671
12583
  lastSuccessfulPollAt: startTime,
12672
12584
  count: 0,
12673
12585
  backoff: 0
@@ -12748,11 +12660,11 @@ function makePoller(callback, intervalMs, options) {
12748
12660
  pollNowIfStale();
12749
12661
  }
12750
12662
  function onVisibilityChange() {
12751
- setInForeground(_optionalChain([doc, 'optionalAccess', _318 => _318.visibilityState]) !== "hidden");
12663
+ setInForeground(_optionalChain([doc, 'optionalAccess', _322 => _322.visibilityState]) !== "hidden");
12752
12664
  }
12753
- _optionalChain([doc, 'optionalAccess', _319 => _319.addEventListener, 'call', _320 => _320("visibilitychange", onVisibilityChange)]);
12754
- _optionalChain([win, 'optionalAccess', _321 => _321.addEventListener, 'call', _322 => _322("online", onVisibilityChange)]);
12755
- _optionalChain([win, 'optionalAccess', _323 => _323.addEventListener, 'call', _324 => _324("focus", pollNowIfStale)]);
12665
+ _optionalChain([doc, 'optionalAccess', _323 => _323.addEventListener, 'call', _324 => _324("visibilitychange", onVisibilityChange)]);
12666
+ _optionalChain([win, 'optionalAccess', _325 => _325.addEventListener, 'call', _326 => _326("online", onVisibilityChange)]);
12667
+ _optionalChain([win, 'optionalAccess', _327 => _327.addEventListener, 'call', _328 => _328("focus", pollNowIfStale)]);
12756
12668
  fsm.start();
12757
12669
  return {
12758
12670
  inc,