@liveblocks/core 1.2.0-internal3 → 1.2.0-internal4

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.d.ts CHANGED
@@ -703,16 +703,9 @@ declare type User<TPresence extends JsonObject, TUserMeta extends BaseUserMeta>
703
703
  */
704
704
  readonly presence: TPresence;
705
705
  /**
706
- * @deprecated Use `!user.canWrite` instead.
707
- * False if the user can mutate the Room’s Storage and/or YDoc, true if they
708
- * can only read but not mutate it.
706
+ * False if the user can modify the room storage, true otherwise.
709
707
  */
710
708
  readonly isReadOnly: boolean;
711
- /**
712
- * True if the user can mutate the Room’s Storage and/or YDoc, false if they
713
- * can only read but not mutate it.
714
- */
715
- readonly canWrite: boolean;
716
709
  };
717
710
 
718
711
  /**
@@ -1555,33 +1548,6 @@ declare enum ServerMsgCode {
1555
1548
  REJECT_STORAGE_OP = 299,
1556
1549
  UPDATE_YDOC = 300
1557
1550
  }
1558
- /**
1559
- * Traits are bitflags that are used at the protocol level to communicate what
1560
- * traits a given User has. Traits may or may not map to official permissions.
1561
- * Users cannot see each other's true permissions, but they can see each
1562
- * other's traits.
1563
- *
1564
- * Traits are not a security feature, but should only be used to optimize the
1565
- * app experience (e.g. to visually indicate that another connected user has no
1566
- * write access to the document).
1567
- */
1568
- declare enum Traits {
1569
- None = 0,
1570
- /**
1571
- * Whether the user has write access to Storage™ + YDoc.
1572
- * Maps to the public `User.canWrite` property.
1573
- */
1574
- CanWriteDocument = 1,
1575
- /**
1576
- * Whether the user has access to Comments™.
1577
- * Maps to the public `User.canComment` property.
1578
- */
1579
- CanWriteComments = 2,
1580
- /**
1581
- * Convenience accessor only, where all the bitflags are enabled.
1582
- */
1583
- All = 3
1584
- }
1585
1551
  /**
1586
1552
  * Messages that can be sent from the server to the client.
1587
1553
  */
@@ -1656,10 +1622,9 @@ declare type UserJoinServerMsg<TUserMeta extends BaseUserMeta> = {
1656
1622
  */
1657
1623
  readonly info: TUserMeta["info"];
1658
1624
  /**
1659
- * Informs the client what Traits this (other) User has.
1660
- * @since v1.2 (WS API v7)
1625
+ * Permissions that the user has in the Room.
1661
1626
  */
1662
- readonly traits: Traits;
1627
+ readonly scopes: string[];
1663
1628
  };
1664
1629
  /**
1665
1630
  * Sent by the WebSocket server and broadcasted to all clients to announce that
@@ -1706,13 +1671,13 @@ declare type RoomStateServerMsg<TUserMeta extends BaseUserMeta> = {
1706
1671
  */
1707
1672
  readonly actor: number;
1708
1673
  /**
1709
- * Informs the client what Traits the current User (self) has.
1674
+ * Informs the client what permissions the current User (self) has.
1710
1675
  * @since v1.2 (WS API v7)
1711
1676
  */
1712
- readonly traits: Traits;
1677
+ readonly scopes: string[];
1713
1678
  readonly users: {
1714
- readonly [otherActor: number]: TUserMeta & {
1715
- traits: Traits;
1679
+ readonly [actor: number]: TUserMeta & {
1680
+ scopes: string[];
1716
1681
  };
1717
1682
  };
1718
1683
  };
@@ -1935,4 +1900,4 @@ declare type EnsureJson<T> = [
1935
1900
  [K in keyof T]: EnsureJson<T[K]>;
1936
1901
  };
1937
1902
 
1938
- export { AckOp, BaseAuthResult, BaseUserMeta, BroadcastEventClientMsg, BroadcastOptions, BroadcastedEventServerMsg, Client, ClientMsg, ClientMsgCode, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateOp, CreateRegisterOp, CreateRootObjectOp, Delegates, DeleteCrdtOp, DeleteObjectKeyOp, DevToolsTreeNode as DevTools, protocol as DevToolsMsg, EnsureJson, FetchStorageClientMsg, FetchYDocClientMsg, History, IWebSocket, IWebSocketCloseEvent, IWebSocketEvent, IWebSocketInstance, IWebSocketMessageEvent, IdTuple, Immutable, InitialDocumentStateServerMsg, Json, JsonArray, JsonObject, JsonScalar, LegacyConnectionStatus, LiveList, LiveListUpdate, LiveMap, LiveMapUpdate, LiveNode, LiveObject, LiveObjectUpdate, LiveStructure, LostConnectionEvent, Lson, LsonObject, NodeMap, Op, OpCode, Others, ParentToChildNodeMap, PlainLson, PlainLsonFields, PlainLsonList, PlainLsonMap, PlainLsonObject, RejectedStorageOpServerMsg, Resolve, Room, RoomInitializers, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, Status, StorageStatus, StorageUpdate, ToImmutable, ToJson, Traits, UpdateObjectOp, UpdatePresenceClientMsg, UpdatePresenceServerMsg, UpdateStorageClientMsg, UpdateStorageServerMsg, UpdateYDocClientMsg, User, UserJoinServerMsg, UserLeftServerMsg, WebsocketCloseCodes, asArrayWithLegacyMethods, asPos, assert, assertNever, b64decode, createClient, deprecate, deprecateIf, errorIf, freeze, isChildCrdt, isJsonArray, isJsonObject, isJsonScalar, isPlainObject, isRootCrdt, legacy_patchImmutableObject, lsonToJson, makePosition, nn, patchLiveObjectKey, shallow, throwUsageError, toPlainLson, tryParseJson, withTimeout };
1903
+ export { AckOp, BaseAuthResult, BaseUserMeta, BroadcastEventClientMsg, BroadcastOptions, BroadcastedEventServerMsg, Client, ClientMsg, ClientMsgCode, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateOp, CreateRegisterOp, CreateRootObjectOp, Delegates, DeleteCrdtOp, DeleteObjectKeyOp, DevToolsTreeNode as DevTools, protocol as DevToolsMsg, EnsureJson, FetchStorageClientMsg, FetchYDocClientMsg, History, IWebSocket, IWebSocketCloseEvent, IWebSocketEvent, IWebSocketInstance, IWebSocketMessageEvent, IdTuple, Immutable, InitialDocumentStateServerMsg, Json, JsonArray, JsonObject, JsonScalar, LegacyConnectionStatus, LiveList, LiveListUpdate, LiveMap, LiveMapUpdate, LiveNode, LiveObject, LiveObjectUpdate, LiveStructure, LostConnectionEvent, Lson, LsonObject, NodeMap, Op, OpCode, Others, ParentToChildNodeMap, PlainLson, PlainLsonFields, PlainLsonList, PlainLsonMap, PlainLsonObject, RejectedStorageOpServerMsg, Resolve, Room, RoomInitializers, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, Status, StorageStatus, StorageUpdate, ToImmutable, ToJson, UpdateObjectOp, UpdatePresenceClientMsg, UpdatePresenceServerMsg, UpdateStorageClientMsg, UpdateStorageServerMsg, UpdateYDocClientMsg, User, UserJoinServerMsg, UserLeftServerMsg, WebsocketCloseCodes, asArrayWithLegacyMethods, asPos, assert, assertNever, b64decode, createClient, deprecate, deprecateIf, errorIf, freeze, isChildCrdt, isJsonArray, isJsonObject, isJsonScalar, isPlainObject, isRootCrdt, legacy_patchImmutableObject, lsonToJson, makePosition, nn, patchLiveObjectKey, shallow, throwUsageError, toPlainLson, tryParseJson, withTimeout };
package/dist/index.js CHANGED
@@ -145,7 +145,7 @@ var onMessageFromPanel = eventSource.observable;
145
145
  // src/devtools/index.ts
146
146
  var VERSION = true ? (
147
147
  /* istanbul ignore next */
148
- "1.2.0-internal3"
148
+ "1.2.0-internal4"
149
149
  ) : "dev";
150
150
  var _devtoolsSetupHasRun = false;
151
151
  function setupDevTools(getAllRooms) {
@@ -4025,19 +4025,7 @@ var ImmutableRef = class {
4025
4025
 
4026
4026
  // src/refs/OthersRef.ts
4027
4027
  function makeUser(conn, presence) {
4028
- const { connectionId, id, info, traits } = conn;
4029
- const canWrite = (traits & 1 /* CanWriteDocument */) === 1 /* CanWriteDocument */;
4030
- return freeze(
4031
- compactObject({
4032
- connectionId,
4033
- id,
4034
- info,
4035
- canWrite,
4036
- isReadOnly: !canWrite,
4037
- // Deprecated, kept for backward-compatibility
4038
- presence
4039
- })
4040
- );
4028
+ return freeze(compactObject(__spreadProps(__spreadValues({}, conn), { presence })));
4041
4029
  }
4042
4030
  var OthersRef = class extends ImmutableRef {
4043
4031
  //
@@ -4096,12 +4084,12 @@ var OthersRef = class extends ImmutableRef {
4096
4084
  * Records a known connection. This records the connection ID and the
4097
4085
  * associated metadata.
4098
4086
  */
4099
- setConnection(connectionId, traits, metaUserId, metaUserInfo) {
4087
+ setConnection(connectionId, metaUserId, metaUserInfo, metaIsReadonly) {
4100
4088
  this._connections[connectionId] = freeze({
4089
+ connectionId,
4101
4090
  id: metaUserId,
4102
4091
  info: metaUserInfo,
4103
- connectionId,
4104
- traits
4092
+ isReadOnly: metaIsReadonly
4105
4093
  });
4106
4094
  if (this._presences[connectionId] !== void 0) {
4107
4095
  this._invalidateUser(connectionId);
@@ -4248,9 +4236,8 @@ function createRoom(options, config) {
4248
4236
  messages: [],
4249
4237
  storageOperations: []
4250
4238
  },
4251
- staticSessionInfo: new ValueRef(null),
4252
- dynamicSessionInfo: new ValueRef(null),
4253
- myPresence: new PatchableRef(initialPresence),
4239
+ sessionInfo: new ValueRef(null),
4240
+ me: new PatchableRef(initialPresence),
4254
4241
  others: new OthersRef(),
4255
4242
  initialStorage,
4256
4243
  idFactory: null,
@@ -4274,9 +4261,12 @@ function createRoom(options, config) {
4274
4261
  var _a2;
4275
4262
  const token = (_a2 = managedSocket.token) == null ? void 0 : _a2.parsed;
4276
4263
  if (token !== void 0 && token !== lastToken) {
4277
- context.staticSessionInfo.set({
4264
+ context.sessionInfo.set({
4278
4265
  userInfo: token.info,
4279
- userId: token.id
4266
+ userId: token.id,
4267
+ // NOTE: In the future, these fields will get assigned in the connection phase
4268
+ actor: token.actor,
4269
+ isReadOnly: isStorageReadOnly(token.scopes)
4280
4270
  });
4281
4271
  lastToken = token;
4282
4272
  }
@@ -4314,15 +4304,20 @@ function createRoom(options, config) {
4314
4304
  }
4315
4305
  }
4316
4306
  function onDidConnect() {
4307
+ const sessionInfo = context.sessionInfo.current;
4308
+ if (sessionInfo === null) {
4309
+ throw new Error("Unexpected missing session info");
4310
+ }
4317
4311
  context.buffer.me = {
4318
4312
  type: "full",
4319
4313
  data: (
4320
4314
  // Because context.me.current is a readonly object, we'll have to
4321
4315
  // make a copy here. Otherwise, type errors happen later when
4322
4316
  // "patching" my presence.
4323
- __spreadValues({}, context.myPresence.current)
4317
+ __spreadValues({}, context.me.current)
4324
4318
  )
4325
4319
  };
4320
+ context.idFactory = makeIdFactory(sessionInfo.actor);
4326
4321
  if (_getStorage$ !== null) {
4327
4322
  refreshStorage({ flush: false });
4328
4323
  }
@@ -4387,17 +4382,8 @@ function createRoom(options, config) {
4387
4382
  }
4388
4383
  },
4389
4384
  assertStorageIsWritable: () => {
4390
- var _a2, _b2;
4391
- const traits = (_b2 = (_a2 = context.dynamicSessionInfo.current) == null ? void 0 : _a2.traits) != null ? _b2 : (
4392
- // XXX Double-check if this is the sane thing to do! Previously this is
4393
- // how the context.sessionInfo?.isReadOnly check worked too. If the
4394
- // isReadOnly property wasn't known yet, the client assumed write
4395
- // access. Not sure if this will break anything if we flip it to
4396
- // Traits.None.
4397
- 3 /* All */
4398
- );
4399
- const canWrite = (traits & 1 /* CanWriteDocument */) === 1 /* CanWriteDocument */;
4400
- if (!canWrite) {
4385
+ var _a2;
4386
+ if ((_a2 = context.sessionInfo.current) == null ? void 0 : _a2.isReadOnly) {
4401
4387
  throw new Error(
4402
4388
  "Cannot write to storage with a read only user, please ensure the user has write permissions"
4403
4389
  );
@@ -4444,24 +4430,16 @@ function createRoom(options, config) {
4444
4430
  managedSocket.send(message);
4445
4431
  }
4446
4432
  const self = new DerivedRef(
4447
- context.staticSessionInfo,
4448
- context.dynamicSessionInfo,
4449
- context.myPresence,
4450
- (staticSession, dynamicSession, myPresence) => {
4451
- if (staticSession === null || dynamicSession === null) {
4452
- return null;
4453
- } else {
4454
- const canWrite = (dynamicSession.traits & 1 /* CanWriteDocument */) === 1 /* CanWriteDocument */;
4455
- return {
4456
- connectionId: dynamicSession.actor,
4457
- id: staticSession.userId,
4458
- info: staticSession.userInfo,
4459
- presence: myPresence,
4460
- canWrite,
4461
- isReadOnly: !canWrite
4462
- // Deprecated, kept for backward-compatibility
4463
- };
4464
- }
4433
+ context.sessionInfo,
4434
+ context.me,
4435
+ (info, me) => {
4436
+ return info !== null ? {
4437
+ connectionId: info.actor,
4438
+ id: info.userId,
4439
+ info: info.userInfo,
4440
+ presence: me,
4441
+ isReadOnly: info.isReadOnly
4442
+ } : null;
4465
4443
  }
4466
4444
  );
4467
4445
  const selfAsTreeNode = new DerivedRef(
@@ -4522,7 +4500,7 @@ function createRoom(options, config) {
4522
4500
  }
4523
4501
  }
4524
4502
  if (presence) {
4525
- eventHub.me.notify(context.myPresence.current);
4503
+ eventHub.me.notify(context.me.current);
4526
4504
  }
4527
4505
  if (storageUpdates.size > 0) {
4528
4506
  const updates = Array.from(storageUpdates.values());
@@ -4531,7 +4509,7 @@ function createRoom(options, config) {
4531
4509
  });
4532
4510
  }
4533
4511
  function getConnectionId() {
4534
- const info = context.dynamicSessionInfo.current;
4512
+ const info = context.sessionInfo.current;
4535
4513
  if (info) {
4536
4514
  return info.actor;
4537
4515
  }
@@ -4560,9 +4538,9 @@ function createRoom(options, config) {
4560
4538
  data: {}
4561
4539
  };
4562
4540
  for (const key in op.data) {
4563
- reverse.data[key] = context.myPresence.current[key];
4541
+ reverse.data[key] = context.me.current[key];
4564
4542
  }
4565
- context.myPresence.patch(op.data);
4543
+ context.me.patch(op.data);
4566
4544
  if (context.buffer.me === null) {
4567
4545
  context.buffer.me = { type: "partial", data: op.data };
4568
4546
  } else {
@@ -4670,9 +4648,9 @@ function createRoom(options, config) {
4670
4648
  continue;
4671
4649
  }
4672
4650
  context.buffer.me.data[key] = overrideValue;
4673
- oldValues[key] = context.myPresence.current[key];
4651
+ oldValues[key] = context.me.current[key];
4674
4652
  }
4675
- context.myPresence.patch(patch);
4653
+ context.me.patch(patch);
4676
4654
  if (context.activeBatch) {
4677
4655
  if (options2 == null ? void 0 : options2.addToHistory) {
4678
4656
  context.activeBatch.reverseOps.unshift({
@@ -4694,6 +4672,9 @@ function createRoom(options, config) {
4694
4672
  });
4695
4673
  }
4696
4674
  }
4675
+ function isStorageReadOnly(scopes) {
4676
+ return scopes.includes("room:read" /* Read */) && scopes.includes("room:presence:write" /* PresenceWrite */) && !scopes.includes("room:write" /* Write */);
4677
+ }
4697
4678
  function onUpdatePresenceMessage(message) {
4698
4679
  if (message.targetActor !== void 0) {
4699
4680
  const oldUser = context.others.getUser(message.actor);
@@ -4725,11 +4706,6 @@ function createRoom(options, config) {
4725
4706
  return null;
4726
4707
  }
4727
4708
  function onRoomStateMessage(message) {
4728
- context.dynamicSessionInfo.set({
4729
- actor: message.actor,
4730
- traits: message.traits
4731
- });
4732
- context.idFactory = makeIdFactory(message.actor);
4733
4709
  for (const connectionId in context.others._connections) {
4734
4710
  const user = message.users[connectionId];
4735
4711
  if (user === void 0) {
@@ -4741,9 +4717,9 @@ function createRoom(options, config) {
4741
4717
  const connectionId = Number(key);
4742
4718
  context.others.setConnection(
4743
4719
  connectionId,
4744
- user.traits,
4745
4720
  user.id,
4746
- user.info
4721
+ user.info,
4722
+ isStorageReadOnly(user.scopes)
4747
4723
  );
4748
4724
  }
4749
4725
  return { type: "reset" };
@@ -4762,13 +4738,13 @@ function createRoom(options, config) {
4762
4738
  function onUserJoinedMessage(message) {
4763
4739
  context.others.setConnection(
4764
4740
  message.actor,
4765
- message.traits,
4766
4741
  message.id,
4767
- message.info
4742
+ message.info,
4743
+ isStorageReadOnly(message.scopes)
4768
4744
  );
4769
4745
  context.buffer.messages.push({
4770
4746
  type: 100 /* UPDATE_PRESENCE */,
4771
- data: context.myPresence.current,
4747
+ data: context.me.current,
4772
4748
  targetActor: message.actor
4773
4749
  });
4774
4750
  flushNowOrSoon();
@@ -5221,10 +5197,10 @@ ${Array.from(traces).join("\n\n")}`
5221
5197
  // Core
5222
5198
  getStatus: () => managedSocket.getStatus(),
5223
5199
  getConnectionState: () => managedSocket.getLegacyStatus(),
5224
- isSelfAware: () => context.staticSessionInfo.current !== null,
5200
+ isSelfAware: () => context.sessionInfo.current !== null,
5225
5201
  getSelf: () => self.current,
5226
5202
  // Presence
5227
- getPresence: () => context.myPresence.current,
5203
+ getPresence: () => context.me.current,
5228
5204
  getOthers: () => context.others.current
5229
5205
  };
5230
5206
  }
@@ -5329,7 +5305,7 @@ function makeCreateSocketDelegateForRoom(liveblocksServer, WebSocketPolyfill) {
5329
5305
  // @ts-ignore (__PACKAGE_VERSION__ will be injected by the build script)
5330
5306
  true ? (
5331
5307
  /* istanbul ignore next */
5332
- "1.2.0-internal3"
5308
+ "1.2.0-internal4"
5333
5309
  ) : "dev"}`
5334
5310
  );
5335
5311
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/core",
3
- "version": "1.2.0-internal3",
3
+ "version": "1.2.0-internal4",
4
4
  "description": "Shared code and foundational internals for Liveblocks",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",