@liveblocks/core 3.20.0-perm3 → 3.20.0-perm5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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.20.0-perm3";
9
+ var PKG_VERSION = "3.20.0-perm5";
10
10
  var PKG_FORMAT = "esm";
11
11
 
12
12
  // src/dupe-detection.ts
@@ -5170,40 +5170,37 @@ function createReceivingToolInvocation(invocationId, name, partialArgsText = "")
5170
5170
  // src/protocol/Permissions.ts
5171
5171
  var Permission = {
5172
5172
  /**
5173
- * Default permission for a room
5173
+ * Default permission for a room.
5174
5174
  */
5175
- RoomWrite: "room:write",
5176
- RoomRead: "room:read",
5175
+ Read: "*:read",
5176
+ Write: "*:write",
5177
5177
  /**
5178
- * Presence (LiveRoom Websocket access)
5178
+ * Legacy aliases for default room permissions.
5179
5179
  */
5180
- RoomPresenceRead: "room:presence:read",
5181
- RoomPresenceNone: "room:presence:none",
5180
+ RoomWrite: "room:write",
5181
+ RoomRead: "room:read",
5182
5182
  /**
5183
5183
  * Storage
5184
5184
  */
5185
- RoomStorageRead: "room:storage:read",
5186
- RoomStorageWrite: "room:storage:write",
5187
- RoomStorageNone: "room:storage:none",
5185
+ StorageRead: "storage:read",
5186
+ StorageWrite: "storage:write",
5187
+ StorageNone: "storage:none",
5188
5188
  /**
5189
5189
  * Comments
5190
5190
  */
5191
- RoomCommentsWrite: "room:comments:write",
5192
- RoomCommentsRead: "room:comments:read",
5193
- RoomCommentsNone: "room:comments:none",
5191
+ CommentsWrite: "comments:write",
5192
+ CommentsRead: "comments:read",
5193
+ CommentsNone: "comments:none",
5194
5194
  /**
5195
5195
  * Feeds
5196
5196
  */
5197
- RoomFeedsRead: "room:feeds:read",
5198
- RoomFeedsWrite: "room:feeds:write",
5199
- RoomFeedsNone: "room:feeds:none",
5197
+ FeedsRead: "feeds:read",
5198
+ FeedsWrite: "feeds:write",
5199
+ FeedsNone: "feeds:none",
5200
5200
  /**
5201
5201
  * Legacy
5202
5202
  */
5203
- LegacyRoomPresenceWrite: "room:presence:write",
5204
- LegacyCommentsWrite: "comments:write",
5205
- LegacyCommentsRead: "comments:read",
5206
- LegacyFeedsWrite: "feeds:write"
5203
+ LegacyRoomPresenceWrite: "room:presence:write"
5207
5204
  };
5208
5205
  var ACCESS_LEVELS = [
5209
5206
  "none",
@@ -5215,46 +5212,39 @@ var ACCESS_RANKS = {
5215
5212
  read: 1,
5216
5213
  write: 2
5217
5214
  };
5218
- var NO_PERMISSION_CAPABILITIES = {
5219
- creation: "none",
5220
- presence: "none",
5215
+ var NO_PERMISSION_MATRIX = {
5216
+ room: "none",
5221
5217
  storage: "none",
5222
5218
  comments: "none",
5223
5219
  feeds: "none",
5224
5220
  personal: "write"
5225
5221
  };
5226
5222
  var RESOURCE_PERMISSIONS = {
5227
- creation: {
5228
- read: [Permission.RoomRead],
5229
- write: [Permission.RoomWrite]
5223
+ room: {
5224
+ read: [Permission.Read, Permission.RoomRead],
5225
+ write: [Permission.Write, Permission.RoomWrite]
5230
5226
  },
5231
5227
  personal: {
5232
5228
  write: []
5233
5229
  },
5234
- presence: {
5235
- write: [Permission.LegacyRoomPresenceWrite],
5236
- read: [Permission.RoomPresenceRead],
5237
- none: [Permission.RoomPresenceNone]
5238
- },
5239
5230
  storage: {
5240
- write: [Permission.RoomStorageWrite],
5241
- read: [Permission.RoomStorageRead],
5242
- none: [Permission.RoomStorageNone]
5231
+ write: [Permission.StorageWrite],
5232
+ read: [Permission.StorageRead],
5233
+ none: [Permission.StorageNone]
5243
5234
  },
5244
5235
  comments: {
5245
- write: [Permission.RoomCommentsWrite, Permission.LegacyCommentsWrite],
5246
- read: [Permission.RoomCommentsRead, Permission.LegacyCommentsRead],
5247
- none: [Permission.RoomCommentsNone]
5236
+ write: [Permission.CommentsWrite],
5237
+ read: [Permission.CommentsRead],
5238
+ none: [Permission.CommentsNone]
5248
5239
  },
5249
5240
  feeds: {
5250
- write: [Permission.RoomFeedsWrite, Permission.LegacyFeedsWrite],
5251
- read: [Permission.RoomFeedsRead],
5252
- none: [Permission.RoomFeedsNone]
5241
+ write: [Permission.FeedsWrite],
5242
+ read: [Permission.FeedsRead],
5243
+ none: [Permission.FeedsNone]
5253
5244
  }
5254
5245
  };
5255
- var DEFAULT_PERMISSION_RESOURCE = "creation";
5246
+ var DEFAULT_PERMISSION_RESOURCE = "room";
5256
5247
  var ROOM_PERMISSION_RESOURCES = [
5257
- "presence",
5258
5248
  "storage",
5259
5249
  "comments",
5260
5250
  "feeds"
@@ -5270,51 +5260,45 @@ function resolveResourceAccess(scopes, resource) {
5270
5260
  }
5271
5261
  return resourceAccess;
5272
5262
  }
5273
- function resolveFullPermissionCapabilities(resolved) {
5263
+ function resolveFullPermissionMatrix(resolved) {
5274
5264
  if (!resolved.hasDefaultPermission) {
5275
- return { ...NO_PERMISSION_CAPABILITIES, ...resolved.capabilities };
5265
+ return NO_PERMISSION_MATRIX;
5276
5266
  }
5277
- const capabilities = {
5278
- ...NO_PERMISSION_CAPABILITIES,
5267
+ const matrix = {
5268
+ ...NO_PERMISSION_MATRIX,
5279
5269
  [DEFAULT_PERMISSION_RESOURCE]: resolved.baseAccess
5280
5270
  };
5281
5271
  for (const resource of ROOM_PERMISSION_RESOURCES) {
5282
- capabilities[resource] = resolved.capabilities[resource] ?? resolved.baseAccess;
5272
+ matrix[resource] = resolved.matrix[resource] ?? resolved.baseAccess;
5283
5273
  }
5284
- return capabilities;
5274
+ return matrix;
5285
5275
  }
5286
- function permissionCapabilitiesFromScopes(scopes) {
5287
- return resolveFullPermissionCapabilities(
5288
- resolvePermissionCapabilities(scopes)
5289
- );
5276
+ function permissionMatrixFromScopes(scopes) {
5277
+ return resolveFullPermissionMatrix(resolvePermissionMatrix(scopes));
5290
5278
  }
5291
- function resolvePermissionCapabilities(scopes) {
5292
- const hasDefaultPermission = scopes.includes(Permission.RoomWrite) || scopes.includes(Permission.RoomRead);
5293
- const baseAccess = scopes.includes(Permission.RoomWrite) ? "write" : scopes.includes(Permission.RoomRead) ? "read" : "none";
5294
- const capabilities = {};
5279
+ function resolvePermissionMatrix(scopes) {
5280
+ const hasDefaultPermission = scopes.includes(Permission.Write) || scopes.includes(Permission.Read) || scopes.includes(Permission.RoomWrite) || scopes.includes(Permission.RoomRead);
5281
+ const baseAccess = scopes.includes(Permission.Write) || scopes.includes(Permission.RoomWrite) ? "write" : scopes.includes(Permission.Read) || scopes.includes(Permission.RoomRead) ? "read" : "none";
5282
+ const matrix = {};
5295
5283
  for (const resource of ROOM_PERMISSION_RESOURCES) {
5296
5284
  const access = resolveResourceAccess(scopes, resource);
5297
5285
  if (access !== void 0) {
5298
- capabilities[resource] = access;
5286
+ matrix[resource] = access;
5299
5287
  }
5300
5288
  }
5301
- return { hasDefaultPermission, baseAccess, capabilities };
5289
+ return { hasDefaultPermission, baseAccess, matrix };
5302
5290
  }
5303
- function hasPermissionCapability(scopes, resource, requiredAccess) {
5304
- const access = permissionCapabilitiesFromScopes(scopes)[resource];
5291
+ function hasPermissionAccess(source, resource, requiredAccess) {
5292
+ const matrix = isPermissionScopes(source) ? permissionMatrixFromScopes(source) : source;
5293
+ const access = matrix[resource] ?? "none";
5305
5294
  return ACCESS_RANKS[access] >= ACCESS_RANKS[requiredAccess];
5306
5295
  }
5307
- function hasPermissionCapabilityAccess(capabilities, resource, requiredAccess) {
5308
- const access = capabilities[resource] ?? "none";
5309
- return ACCESS_RANKS[access] >= ACCESS_RANKS[requiredAccess];
5296
+ function isPermissionScopes(source) {
5297
+ return Array.isArray(source);
5310
5298
  }
5311
5299
 
5312
5300
  // src/permissions.ts
5313
5301
  var VALID_PERMISSIONS = new Set(Object.values(Permission));
5314
- var ROOM_PERMISSION_OBJECT_KEYS = /* @__PURE__ */ new Set([
5315
- "default",
5316
- ...ROOM_PERMISSION_RESOURCES
5317
- ]);
5318
5302
  function permissionForAccessLevel(resource, access, field = resource) {
5319
5303
  const levels = RESOURCE_PERMISSIONS[resource];
5320
5304
  const permissions = levels[access];
@@ -5325,7 +5309,7 @@ function permissionForAccessLevel(resource, access, field = resource) {
5325
5309
  }
5326
5310
  return permissions[0];
5327
5311
  }
5328
- function resolveRoomPermissionCapabilities(permissions, roomId) {
5312
+ function resolveRoomPermissionMatrix(permissions, roomId) {
5329
5313
  const matchedPermissions = permissions.filter(
5330
5314
  (permission) => resourceMatchesRoomId(permission.resource, roomId)
5331
5315
  );
@@ -5334,69 +5318,47 @@ function resolveRoomPermissionCapabilities(permissions, roomId) {
5334
5318
  }
5335
5319
  let hasDefaultPermission = false;
5336
5320
  let baseAccess = "none";
5337
- const explicitCapabilities = {};
5321
+ const explicitMatrix = {};
5322
+ const explicitSpecificity = {};
5338
5323
  for (const permission of matchedPermissions) {
5339
- const resolved = resolvePermissionCapabilities(permission.scopes);
5324
+ const resolved = resolvePermissionMatrix(permission.scopes);
5325
+ const specificity = getResourceSpecificity(permission.resource);
5340
5326
  if (resolved.hasDefaultPermission) {
5341
5327
  hasDefaultPermission = true;
5342
5328
  baseAccess = strongestAccess(baseAccess, resolved.baseAccess);
5343
5329
  }
5344
5330
  for (const resource of ROOM_PERMISSION_RESOURCES) {
5345
- const access = resolved.capabilities[resource];
5331
+ const access = resolved.matrix[resource];
5346
5332
  if (access !== void 0) {
5347
- explicitCapabilities[resource] = strongestAccess(
5348
- explicitCapabilities[resource] ?? "none",
5349
- access
5350
- );
5333
+ const currentSpecificity = explicitSpecificity[resource] ?? -1;
5334
+ if (specificity > currentSpecificity) {
5335
+ explicitMatrix[resource] = access;
5336
+ explicitSpecificity[resource] = specificity;
5337
+ } else if (specificity === currentSpecificity) {
5338
+ explicitMatrix[resource] = strongestAccess(
5339
+ explicitMatrix[resource] ?? "none",
5340
+ access
5341
+ );
5342
+ }
5351
5343
  }
5352
5344
  }
5353
5345
  }
5354
- return resolveFullPermissionCapabilities({
5346
+ return resolveFullPermissionMatrix({
5355
5347
  hasDefaultPermission,
5356
5348
  baseAccess,
5357
- capabilities: explicitCapabilities
5349
+ matrix: explicitMatrix
5358
5350
  });
5359
5351
  }
5360
- function isRoomPermissionArray(input) {
5361
- return Array.isArray(input);
5362
- }
5363
5352
  function normalizeRoomPermissionInput(input) {
5364
- if (isRoomPermissionArray(input)) {
5365
- return input.map((permission) => {
5366
- if (!VALID_PERMISSIONS.has(permission)) {
5367
- throw new Error(`Not a valid permission: ${permission}`);
5368
- }
5369
- return permission;
5370
- });
5353
+ if (!Array.isArray(input)) {
5354
+ throw new Error("Permission list must be an array");
5371
5355
  }
5372
- return normalizeRoomPermissionObject(input);
5373
- }
5374
- function normalizeRoomPermissionObject(objectInput) {
5375
- for (const key of Object.keys(objectInput)) {
5376
- if (!ROOM_PERMISSION_OBJECT_KEYS.has(key)) {
5377
- throw new Error(`Unknown permission field: ${key}`);
5356
+ return input.map((permission) => {
5357
+ if (!VALID_PERMISSIONS.has(permission)) {
5358
+ throw new Error(`Not a valid permission: ${permission}`);
5378
5359
  }
5379
- }
5380
- const permissions = [];
5381
- if (objectInput.default !== void 0) {
5382
- permissions.push(
5383
- permissionForAccessLevel(
5384
- DEFAULT_PERMISSION_RESOURCE,
5385
- objectInput.default,
5386
- "default"
5387
- )
5388
- );
5389
- }
5390
- for (const resource of ROOM_PERMISSION_RESOURCES) {
5391
- const access = objectInput[resource];
5392
- if (access !== void 0) {
5393
- permissions.push(permissionForAccessLevel(resource, access));
5394
- }
5395
- }
5396
- if (permissions.length === 0) {
5397
- throw new Error("Permission object cannot be empty");
5398
- }
5399
- return permissions;
5360
+ return permission;
5361
+ });
5400
5362
  }
5401
5363
  function normalizeRoomAccessesInput(input) {
5402
5364
  if (input === void 0) {
@@ -5420,33 +5382,32 @@ function normalizeRoomAccessesUpdateInput(input) {
5420
5382
  ])
5421
5383
  );
5422
5384
  }
5423
- function mergePermissionCapabilities(sources) {
5385
+ function mergePermissionMatrices(sources) {
5424
5386
  return {
5425
- creation: strongestCapabilityAccess(sources, "creation"),
5426
- presence: strongestCapabilityAccess(sources, "presence"),
5427
- storage: strongestCapabilityAccess(sources, "storage"),
5428
- comments: strongestCapabilityAccess(sources, "comments"),
5429
- feeds: strongestCapabilityAccess(sources, "feeds"),
5387
+ room: strongestMatrixAccess(sources, "room"),
5388
+ storage: strongestMatrixAccess(sources, "storage"),
5389
+ comments: strongestMatrixAccess(sources, "comments"),
5390
+ feeds: strongestMatrixAccess(sources, "feeds"),
5430
5391
  personal: "write"
5431
5392
  };
5432
5393
  }
5433
- function permissionCapabilitiesToScopes(capabilities) {
5394
+ function permissionMatrixToScopes(matrix) {
5434
5395
  const scopes = [];
5435
- const baseAccess = capabilities.creation;
5396
+ const baseAccess = matrix.room;
5436
5397
  if (baseAccess !== "none") {
5437
5398
  scopes.push(
5438
5399
  permissionForAccessLevel(DEFAULT_PERMISSION_RESOURCE, baseAccess)
5439
5400
  );
5440
5401
  }
5441
- for (const capability of ROOM_PERMISSION_RESOURCES) {
5442
- const access = capabilities[capability];
5402
+ for (const resource of ROOM_PERMISSION_RESOURCES) {
5403
+ const access = matrix[resource];
5443
5404
  if (access !== baseAccess) {
5444
- scopes.push(permissionForAccessLevel(capability, access));
5405
+ scopes.push(permissionForAccessLevel(resource, access));
5445
5406
  }
5446
5407
  }
5447
5408
  return scopes;
5448
5409
  }
5449
- function strongestCapabilityAccess(sources, resource) {
5410
+ function strongestMatrixAccess(sources, resource) {
5450
5411
  return sources.reduce(
5451
5412
  (strongest, source) => strongestAccess(strongest, source[resource]),
5452
5413
  "none"
@@ -5461,6 +5422,9 @@ function resourceMatchesRoomId(resource, roomId) {
5461
5422
  }
5462
5423
  return resource === roomId;
5463
5424
  }
5425
+ function getResourceSpecificity(resource) {
5426
+ return resource.replace("*", "").length;
5427
+ }
5464
5428
 
5465
5429
  // src/protocol/AuthToken.ts
5466
5430
  function isValidAuthTokenPayload(data) {
@@ -5641,15 +5605,11 @@ function cachedTokenSatisfiesRequest(cachedToken, request) {
5641
5605
  if (request.roomId === void 0) {
5642
5606
  return false;
5643
5607
  }
5644
- const capabilities = resolveRoomPermissionCapabilities(
5608
+ const matrix = resolveRoomPermissionMatrix(
5645
5609
  cachedToken.permissions ?? [],
5646
5610
  request.roomId
5647
5611
  );
5648
- return capabilities !== void 0 && hasPermissionCapabilityAccess(
5649
- capabilities,
5650
- request.resource,
5651
- request.access
5652
- );
5612
+ return matrix !== void 0 && hasPermissionAccess(matrix, request.resource, request.access);
5653
5613
  }
5654
5614
  function prepareAuthentication(authOptions) {
5655
5615
  const { publicApiKey, authEndpoint } = authOptions;
@@ -9541,14 +9501,14 @@ var ClientMsgCode = Object.freeze({
9541
9501
  // src/refs/ManagedOthers.ts
9542
9502
  function makeUser(conn, presence) {
9543
9503
  const { connectionId, id, info } = conn;
9544
- const canWrite = hasPermissionCapability(conn.scopes, "storage", "write");
9504
+ const canWrite = hasPermissionAccess(conn.scopes, "storage", "write");
9545
9505
  return freeze(
9546
9506
  compactObject({
9547
9507
  connectionId,
9548
9508
  id,
9549
9509
  info,
9550
9510
  canWrite,
9551
- canComment: hasPermissionCapability(conn.scopes, "comments", "write"),
9511
+ canComment: hasPermissionAccess(conn.scopes, "comments", "write"),
9552
9512
  isReadOnly: !canWrite,
9553
9513
  // Deprecated, kept for backward-compatibility
9554
9514
  presence
@@ -10005,7 +9965,7 @@ function createRoom(options, config) {
10005
9965
  }
10006
9966
  function isStorageWritable() {
10007
9967
  const scopes = context.dynamicSessionInfoSig.get()?.scopes;
10008
- return scopes !== void 0 ? hasPermissionCapability(scopes, "storage", "write") : true;
9968
+ return scopes !== void 0 ? hasPermissionAccess(scopes, "storage", "write") : true;
10009
9969
  }
10010
9970
  const eventHub = {
10011
9971
  status: makeEventSource(),
@@ -10066,7 +10026,7 @@ function createRoom(options, config) {
10066
10026
  if (staticSession === null || dynamicSession === null) {
10067
10027
  return null;
10068
10028
  } else {
10069
- const canWrite = hasPermissionCapability(
10029
+ const canWrite = hasPermissionAccess(
10070
10030
  dynamicSession.scopes,
10071
10031
  "storage",
10072
10032
  "write"
@@ -10077,7 +10037,7 @@ function createRoom(options, config) {
10077
10037
  info: staticSession.userInfo,
10078
10038
  presence: myPresence,
10079
10039
  canWrite,
10080
- canComment: hasPermissionCapability(
10040
+ canComment: hasPermissionAccess(
10081
10041
  dynamicSession.scopes,
10082
10042
  "comments",
10083
10043
  "write"
@@ -11488,7 +11448,9 @@ function createRoom(options, config) {
11488
11448
  _dump: () => {
11489
11449
  const n = context.pool.nodes.size;
11490
11450
  return `Room "${roomId}" (${n} node${n === 1 ? "" : "s"}):
11491
- ${dumpPool(context.pool)}`;
11451
+ ${dumpPool(
11452
+ context.pool
11453
+ )}`;
11492
11454
  },
11493
11455
  destroy: () => {
11494
11456
  pendingFeedsRequests.forEach(
@@ -11683,7 +11645,7 @@ function makeAuthDelegateForRoom(roomId, authManager) {
11683
11645
  return async () => {
11684
11646
  return authManager.getAuthValue({
11685
11647
  roomId,
11686
- resource: "presence",
11648
+ resource: "room",
11687
11649
  access: "read"
11688
11650
  });
11689
11651
  };
@@ -12686,8 +12648,7 @@ export {
12686
12648
  generateUrl,
12687
12649
  getMentionsFromCommentBody,
12688
12650
  getSubscriptionKey,
12689
- hasPermissionCapability,
12690
- hasPermissionCapabilityAccess,
12651
+ hasPermissionAccess,
12691
12652
  html,
12692
12653
  htmlSafe,
12693
12654
  isCommentBodyLink,
@@ -12715,7 +12676,7 @@ export {
12715
12676
  makePosition,
12716
12677
  mapValues,
12717
12678
  memoizeOnSuccess,
12718
- mergePermissionCapabilities,
12679
+ mergePermissionMatrices,
12719
12680
  nanoid,
12720
12681
  nn,
12721
12682
  nodeStreamToCompactNodes,
@@ -12724,8 +12685,8 @@ export {
12724
12685
  normalizeRoomPermissionInput,
12725
12686
  objectToQuery,
12726
12687
  patchNotificationSettings,
12727
- permissionCapabilitiesFromScopes,
12728
- permissionCapabilitiesToScopes,
12688
+ permissionMatrixFromScopes,
12689
+ permissionMatrixToScopes,
12729
12690
  raise,
12730
12691
  resolveMentionsInCommentBody,
12731
12692
  sanitizeUrl,