@liveblocks/node 1.19.0-test1 → 2.0.0-alpha1

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
@@ -3,11 +3,27 @@ import { detectDupes } from "@liveblocks/core";
3
3
 
4
4
  // src/version.ts
5
5
  var PKG_NAME = "@liveblocks/node";
6
- var PKG_VERSION = "1.19.0-test1";
6
+ var PKG_VERSION = "2.0.0-alpha1";
7
7
  var PKG_FORMAT = "esm";
8
8
 
9
+ // src/client.ts
10
+ import {
11
+ convertToCommentData,
12
+ convertToCommentUserReaction,
13
+ convertToInboxNotificationData,
14
+ convertToThreadData,
15
+ objectToQuery
16
+ } from "@liveblocks/core";
17
+
9
18
  // src/utils.ts
10
19
  var DEFAULT_BASE_URL = "https://api.liveblocks.io";
20
+ function getBaseUrl(baseUrl) {
21
+ if (typeof baseUrl === "string" && baseUrl.startsWith("http")) {
22
+ return baseUrl;
23
+ } else {
24
+ return DEFAULT_BASE_URL;
25
+ }
26
+ }
11
27
  async function fetchPolyfill() {
12
28
  return typeof globalThis.fetch !== "undefined" ? globalThis.fetch : (await import("node-fetch")).default;
13
29
  }
@@ -59,55 +75,6 @@ function url(strings, ...values) {
59
75
  );
60
76
  }
61
77
 
62
- // src/authorize.ts
63
- async function authorize(options) {
64
- let url2 = null;
65
- try {
66
- const { room, secret, userId, userInfo, groupIds } = (
67
- // Ensure we'll validate inputs at runtime
68
- options
69
- );
70
- assertNonEmpty(secret, "secret");
71
- assertNonEmpty(room, "room");
72
- assertNonEmpty(userId, "userId");
73
- url2 = buildLiveblocksAuthorizeEndpoint(options, room);
74
- const fetch = await fetchPolyfill();
75
- const resp = await fetch(buildLiveblocksAuthorizeEndpoint(options, room), {
76
- method: "POST",
77
- headers: {
78
- Authorization: `Bearer ${secret}`,
79
- "Content-Type": "application/json"
80
- },
81
- body: JSON.stringify({
82
- userId,
83
- userInfo,
84
- groupIds
85
- })
86
- });
87
- return {
88
- status: normalizeStatusCode(resp.status),
89
- body: await resp.text()
90
- };
91
- } catch (er) {
92
- return {
93
- status: 503,
94
- body: (url2 ? `Call to "${url2}" failed.` : "Invalid authorize request.") + ' See "error" for more information.',
95
- error: er
96
- };
97
- }
98
- }
99
- function buildLiveblocksAuthorizeEndpoint(options, roomId) {
100
- const path = `/v2/rooms/${encodeURIComponent(roomId)}/authorize`;
101
- return urljoin(options.baseUrl || DEFAULT_BASE_URL, path);
102
- }
103
-
104
- // src/client.ts
105
- import {
106
- convertToCommentData,
107
- convertToCommentUserReaction,
108
- convertToThreadData
109
- } from "@liveblocks/core";
110
-
111
78
  // src/Session.ts
112
79
  var ALL_PERMISSIONS = Object.freeze([
113
80
  "room:write",
@@ -126,7 +93,7 @@ var READ_ACCESS = Object.freeze([
126
93
  "comments:read"
127
94
  ]);
128
95
  var FULL_ACCESS = Object.freeze(["room:write", "comments:write"]);
129
- var roomPatternRegex = /^[^*]{1,128}[*]?$/;
96
+ var roomPatternRegex = /^([*]|[^*]{1,128}[*]?)$/;
130
97
  var Session = class {
131
98
  /** @internal */
132
99
  constructor(postFn, userId, userInfo) {
@@ -161,6 +128,9 @@ var Session = class {
161
128
  }
162
129
  }
163
130
  allow(roomIdOrPattern, newPerms) {
131
+ if (typeof roomIdOrPattern !== "string") {
132
+ throw new Error("Room name or pattern must be a string");
133
+ }
164
134
  if (!roomPatternRegex.test(roomIdOrPattern)) {
165
135
  throw new Error("Invalid room name or pattern");
166
136
  }
@@ -206,10 +176,9 @@ var Session = class {
206
176
  async authorize() {
207
177
  this.seal();
208
178
  if (!this.hasPermissions()) {
209
- return {
210
- status: 403,
211
- body: "Forbidden"
212
- };
179
+ console.warn(
180
+ "Access tokens without any permission will not be supported soon, you should use wildcards when the client requests a token for resources outside a room. See https://liveblocks.io/docs/errors/liveblocks-client/access-tokens-not-enough-permissions"
181
+ );
213
182
  }
214
183
  try {
215
184
  const resp = await this._postFn(url`/v2/authorize-user`, {
@@ -243,7 +212,7 @@ var Liveblocks = class {
243
212
  const secret = options_.secret;
244
213
  assertSecretKey(secret, "secret");
245
214
  this._secret = secret;
246
- this._baseUrl = new URL(options.baseUrl ?? DEFAULT_BASE_URL);
215
+ this._baseUrl = new URL(getBaseUrl(options.baseUrl));
247
216
  }
248
217
  /** @internal */
249
218
  async post(path, json) {
@@ -268,12 +237,21 @@ var Liveblocks = class {
268
237
  "Content-Type": "application/json"
269
238
  };
270
239
  const fetch = await fetchPolyfill();
271
- const res = await fetch(url2, {
240
+ return await fetch(url2, {
272
241
  method: "PUT",
273
242
  headers,
274
243
  body: JSON.stringify(json)
275
244
  });
276
- return res;
245
+ }
246
+ /** @internal */
247
+ async putBinary(path, body, params) {
248
+ const url2 = urljoin(this._baseUrl, path, params);
249
+ const headers = {
250
+ Authorization: `Bearer ${this._secret}`,
251
+ "Content-Type": "application/octet-stream"
252
+ };
253
+ const fetch = await fetchPolyfill();
254
+ return await fetch(url2, { method: "PUT", headers, body });
277
255
  }
278
256
  /** @internal */
279
257
  async delete(path) {
@@ -288,7 +266,6 @@ var Liveblocks = class {
288
266
  /** @internal */
289
267
  async get(path, params) {
290
268
  const url2 = urljoin(this._baseUrl, path, params);
291
- console.log("url", url2);
292
269
  const headers = {
293
270
  Authorization: `Bearer ${this._secret}`
294
271
  };
@@ -388,10 +365,17 @@ var Liveblocks = class {
388
365
  * @param params.userId (optional) A filter on users accesses.
389
366
  * @param params.metadata (optional) A filter on metadata. Multiple metadata keys can be used to filter rooms.
390
367
  * @param params.groupIds (optional) A filter on groups accesses. Multiple groups can be used.
368
+ * @param params.query (optional) A query to filter rooms by. It is based on our query language. You can filter by metadata and room ID.
391
369
  * @returns A list of rooms.
392
370
  */
393
371
  async getRooms(params = {}) {
394
372
  const path = url`/v2/rooms`;
373
+ let query;
374
+ if (typeof params.query === "string") {
375
+ query = params.query;
376
+ } else if (typeof params.query === "object") {
377
+ query = objectToQuery(params.query);
378
+ }
395
379
  const queryParams = {
396
380
  limit: params.limit,
397
381
  startingAfter: params.startingAfter,
@@ -399,21 +383,26 @@ var Liveblocks = class {
399
383
  groupIds: params.groupIds ? params.groupIds.join(",") : void 0,
400
384
  // "Flatten" {metadata: {foo: "bar"}} to {"metadata.foo": "bar"}
401
385
  ...Object.fromEntries(
402
- Object.entries(params.metadata ?? {}).map(([key, val]) => {
403
- const value = Array.isArray(val) ? val.join(",") : val;
404
- return [`metadata.${key}`, value];
405
- })
406
- )
386
+ Object.entries(params.metadata ?? {}).map(([key, val]) => [
387
+ `metadata.${key}`,
388
+ val
389
+ ])
390
+ ),
391
+ query
407
392
  };
408
393
  const res = await this.get(path, queryParams);
394
+ if (!res.ok) {
395
+ const text = await res.text();
396
+ throw new LiveblocksError(res.status, text);
397
+ }
409
398
  const data = await res.json();
410
399
  const rooms = data.data.map((room) => {
411
400
  const lastConnectionAt = room.lastConnectionAt ? new Date(room.lastConnectionAt) : void 0;
412
- const createdAt = room.createdAt ? new Date(room.createdAt) : void 0;
401
+ const createdAt = new Date(room.createdAt);
413
402
  return {
414
403
  ...room,
415
- lastConnectionAt,
416
- createdAt
404
+ createdAt,
405
+ lastConnectionAt
417
406
  };
418
407
  });
419
408
  return {
@@ -445,7 +434,7 @@ var Liveblocks = class {
445
434
  }
446
435
  const data = await res.json();
447
436
  const lastConnectionAt = data.lastConnectionAt ? new Date(data.lastConnectionAt) : void 0;
448
- const createdAt = data.createdAt ? new Date(data.createdAt) : void 0;
437
+ const createdAt = new Date(data.createdAt);
449
438
  return {
450
439
  ...data,
451
440
  lastConnectionAt,
@@ -465,11 +454,11 @@ var Liveblocks = class {
465
454
  }
466
455
  const data = await res.json();
467
456
  const lastConnectionAt = data.lastConnectionAt ? new Date(data.lastConnectionAt) : void 0;
468
- const createdAt = data.createdAt ? new Date(data.createdAt) : void 0;
457
+ const createdAt = new Date(data.createdAt);
469
458
  return {
470
459
  ...data,
471
- lastConnectionAt,
472
- createdAt
460
+ createdAt,
461
+ lastConnectionAt
473
462
  };
474
463
  }
475
464
  /**
@@ -496,7 +485,7 @@ var Liveblocks = class {
496
485
  }
497
486
  const data = await res.json();
498
487
  const lastConnectionAt = data.lastConnectionAt ? new Date(data.lastConnectionAt) : void 0;
499
- const createdAt = data.createdAt ? new Date(data.createdAt) : void 0;
488
+ const createdAt = new Date(data.createdAt);
500
489
  return {
501
490
  ...data,
502
491
  lastConnectionAt,
@@ -605,12 +594,12 @@ var Liveblocks = class {
605
594
  /**
606
595
  * Send a Yjs binary update to the room’s Yjs document. You can use this endpoint to initialize Yjs data for the room or to update the room’s Yjs document.
607
596
  * @param roomId The id of the room to send the Yjs binary update to.
608
- * @param params The Yjs binary update to send. Read the [Yjs documentation](https://docs.yjs.dev/api/document-updates) to learn how to create a binary update.
597
+ * @param update The Yjs update to send. Typically the result of calling `Yjs.encodeStateAsUpdate(doc)`. Read the [Yjs documentation](https://docs.yjs.dev/api/document-updates) to learn how to create a binary update.
598
+ * @param params.guid (optional) If provided, the binary update will be applied to the Yjs subdocument with the given guid. If not provided, the binary update will be applied to the root Yjs document.
609
599
  */
610
- async sendYjsBinaryUpdate(roomId, params) {
611
- const { update } = params;
612
- const res = await this.put(url`/v2/rooms/${roomId}/ydoc`, {
613
- update
600
+ async sendYjsBinaryUpdate(roomId, update, params = {}) {
601
+ const res = await this.putBinary(url`/v2/rooms/${roomId}/ydoc`, update, {
602
+ guid: params.guid
614
603
  });
615
604
  if (!res.ok) {
616
605
  const text = await res.text();
@@ -621,10 +610,13 @@ var Liveblocks = class {
621
610
  * Returns the room’s Yjs document encoded as a single binary update. This can be used by Y.applyUpdate(responseBody) to get a copy of the document in your backend.
622
611
  * See [Yjs documentation](https://docs.yjs.dev/api/document-updates) for more information on working with updates.
623
612
  * @param roomId The id of the room to get the Yjs document from.
613
+ * @param params.guid (optional) If provided, returns the binary update of the Yjs subdocument with the given guid. If not provided, returns the binary update of the root Yjs document.
624
614
  * @returns The room’s Yjs document encoded as a single binary update.
625
615
  */
626
- async getYjsDocumentAsBinaryUpdate(roomId) {
627
- const res = await this.get(url`/v2/rooms/${roomId}/ydoc-binary`);
616
+ async getYjsDocumentAsBinaryUpdate(roomId, params = {}) {
617
+ const res = await this.get(url`/v2/rooms/${roomId}/ydoc-binary`, {
618
+ guid: params.guid
619
+ });
628
620
  if (!res.ok) {
629
621
  const text = await res.text();
630
622
  throw new LiveblocksError(res.status, text);
@@ -767,12 +759,19 @@ var Liveblocks = class {
767
759
  * Gets all the threads in a room.
768
760
  *
769
761
  * @param params.roomId The room ID to get the threads from.
762
+ * @param params.query The query to filter threads by. It is based on our query language and can filter by metadata.
770
763
  * @returns A list of threads.
771
764
  */
772
765
  async getThreads(params) {
773
766
  const { roomId } = params;
767
+ let query;
768
+ if (typeof params.query === "string") {
769
+ query = params.query;
770
+ } else if (typeof params.query === "object") {
771
+ query = objectToQuery(params.query);
772
+ }
774
773
  const res = await this.get(url`/v2/rooms/${roomId}/threads`, {
775
- "metadata.resolved": "false"
774
+ query
776
775
  });
777
776
  if (!res.ok) {
778
777
  const text = await res.text();
@@ -797,9 +796,7 @@ var Liveblocks = class {
797
796
  const text = await res.text();
798
797
  throw new LiveblocksError(res.status, text);
799
798
  }
800
- return convertToThreadData(
801
- await res.json()
802
- );
799
+ return convertToThreadData(await res.json());
803
800
  }
804
801
  /**
805
802
  * Gets a thread's participants.
@@ -929,9 +926,7 @@ var Liveblocks = class {
929
926
  const text = await res.text();
930
927
  throw new LiveblocksError(res.status, text);
931
928
  }
932
- return convertToThreadData(
933
- await res.json()
934
- );
929
+ return convertToThreadData(await res.json());
935
930
  }
936
931
  /**
937
932
  * Updates the metadata of the specified thread in a room.
@@ -1006,6 +1001,104 @@ var Liveblocks = class {
1006
1001
  throw new LiveblocksError(res.status, text);
1007
1002
  }
1008
1003
  }
1004
+ /**
1005
+ * Returns the inbox notifications for a user.
1006
+ * @param params.userId The user ID to get the inbox notifications from.
1007
+ * @param params.inboxNotificationId The ID of the inbox notification to get.
1008
+ */
1009
+ async getInboxNotification(params) {
1010
+ const { userId, inboxNotificationId } = params;
1011
+ const res = await this.get(
1012
+ url`/v2/users/${userId}/inbox-notifications/${inboxNotificationId}`
1013
+ );
1014
+ if (!res.ok) {
1015
+ const text = await res.text();
1016
+ throw new LiveblocksError(res.status, text);
1017
+ }
1018
+ return convertToInboxNotificationData(
1019
+ await res.json()
1020
+ );
1021
+ }
1022
+ /**
1023
+ * Gets the user's room notification settings.
1024
+ * @param params.userId The user ID to get the room notifications from.
1025
+ * @param params.roomId The room ID to get the room notification settings from.
1026
+ */
1027
+ async getRoomNotificationSettings(params) {
1028
+ const { userId, roomId } = params;
1029
+ const res = await this.get(
1030
+ url`/v2/rooms/${roomId}/users/${userId}/notification-settings`
1031
+ );
1032
+ if (!res.ok) {
1033
+ const text = await res.text();
1034
+ throw new LiveblocksError(res.status, text);
1035
+ }
1036
+ return await res.json();
1037
+ }
1038
+ /**
1039
+ * Updates the user's room notification settings.
1040
+ * @param params.userId The user ID to update the room notification settings for.
1041
+ * @param params.roomId The room ID to update the room notification settings for.
1042
+ * @param params.data The new room notification settings for the user.
1043
+ */
1044
+ async updateRoomNotificationSettings(params) {
1045
+ const { userId, roomId, data } = params;
1046
+ const res = await this.post(
1047
+ url`/v2/rooms/${roomId}/users/${userId}/notification-settings`,
1048
+ data
1049
+ );
1050
+ if (!res.ok) {
1051
+ const text = await res.text();
1052
+ throw new LiveblocksError(res.status, text);
1053
+ }
1054
+ return await res.json();
1055
+ }
1056
+ /**
1057
+ * Delete the user's room notification settings.
1058
+ * @param params.userId The user ID to delete the room notification settings from.
1059
+ * @param params.roomId The room ID to delete the room notification settings from.
1060
+ */
1061
+ async deleteRoomNotificationSettings(params) {
1062
+ const { userId, roomId } = params;
1063
+ const res = await this.delete(
1064
+ url`/v2/rooms/${roomId}/users/${userId}/notification-settings`
1065
+ );
1066
+ if (!res.ok) {
1067
+ const text = await res.text();
1068
+ throw new LiveblocksError(res.status, text);
1069
+ }
1070
+ }
1071
+ /**
1072
+ * Update a room ID.
1073
+ * @param params.roomId The current ID of the room.
1074
+ * @param params.newRoomId The new room ID.
1075
+ */
1076
+ async updateRoomId(params) {
1077
+ const { currentRoomId, newRoomId } = params;
1078
+ const res = await this.post(
1079
+ url`/v2/rooms/${currentRoomId}/update-room-id`,
1080
+ {
1081
+ newRoomId
1082
+ }
1083
+ );
1084
+ if (!res.ok) {
1085
+ const text = await res.text();
1086
+ throw new LiveblocksError(res.status, text);
1087
+ }
1088
+ const data = await res.json();
1089
+ return {
1090
+ ...data,
1091
+ createdAt: new Date(data.createdAt),
1092
+ lastConnectionAt: data.lastConnectionAt ? new Date(data.lastConnectionAt) : void 0
1093
+ };
1094
+ }
1095
+ async triggerInboxNotification(params) {
1096
+ const res = await this.post(url`/v2/inbox-notifications/trigger`, params);
1097
+ if (!res.ok) {
1098
+ const text = await res.text();
1099
+ throw new LiveblocksError(res.status, text);
1100
+ }
1101
+ }
1009
1102
  };
1010
1103
  var LiveblocksError = class extends Error {
1011
1104
  constructor(status, message = "") {
@@ -1121,7 +1214,8 @@ var _WebhookHandler = class _WebhookHandler {
1121
1214
  "commentReactionRemoved",
1122
1215
  "threadMetadataUpdated",
1123
1216
  "threadCreated",
1124
- "ydocUpdated"
1217
+ "ydocUpdated",
1218
+ "notification"
1125
1219
  ].includes(event.type))
1126
1220
  return;
1127
1221
  throw new Error(
@@ -1142,8 +1236,8 @@ import {
1142
1236
  detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
1143
1237
  export {
1144
1238
  Liveblocks,
1239
+ LiveblocksError,
1145
1240
  WebhookHandler,
1146
- authorize,
1147
1241
  getMentionedIdsFromCommentBody,
1148
1242
  stringifyCommentBody
1149
1243
  };