@liveblocks/zustand 0.16.15 → 0.17.0-test1

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.
Files changed (4) hide show
  1. package/index.d.ts +74 -46
  2. package/index.js +303 -162
  3. package/index.mjs +225 -122
  4. package/package.json +10 -8
package/index.d.ts CHANGED
@@ -1,57 +1,85 @@
1
- import { Presence, Room, User, Client } from '@liveblocks/client';
2
- import { StateCreator, SetState, GetState, StoreApi } from 'zustand';
1
+ import { JsonObject, LsonObject, Room, User, Client } from "@liveblocks/client";
2
+ import { StateCreator, SetState, GetState, StoreApi } from "zustand";
3
3
 
4
- declare type LiveblocksState<TState, TPresence extends Presence = Presence> = TState & {
4
+ declare type ZustandState = Record<string, unknown>;
5
+ declare type LiveblocksState<
6
+ TState extends ZustandState,
7
+ TPresence extends JsonObject,
8
+ TStorage extends LsonObject
9
+ > = TState & {
10
+ /**
11
+ * Liveblocks extra state attached by the middleware
12
+ */
13
+ readonly liveblocks: {
5
14
  /**
6
- * Liveblocks extra state attached by the middleware
15
+ * Enters a room and starts sync it with zustand state
16
+ * @param roomId The id of the room
17
+ * @param initialState The initial state of the room storage. If a key does not exist if your room storage root, initialState[key] will be used.
7
18
  */
8
- readonly liveblocks: {
9
- /**
10
- * Enters a room and starts sync it with zustand state
11
- * @param roomId The id of the room
12
- * @param initialState The initial state of the room storage. If a key does not exist if your room storage root, initialState[key] will be used.
13
- */
14
- readonly enterRoom: (roomId: string, initialState: Partial<TState>) => void;
15
- /**
16
- * Leaves a room and stops sync it with zustand state.
17
- * @param roomId The id of the room
18
- */
19
- readonly leaveRoom: (roomId: string) => void;
20
- /**
21
- * The room currently synced to your zustand state.
22
- */
23
- readonly room: Room | null;
24
- /**
25
- * Other users in the room. Empty no room is currently synced
26
- */
27
- readonly others: Array<User<TPresence>>;
28
- /**
29
- * Whether or not the room storage is currently loading
30
- */
31
- readonly isStorageLoading: boolean;
32
- /**
33
- * Connection state of the room
34
- */
35
- readonly connection: "closed" | "authenticating" | "unavailable" | "failed" | "open" | "connecting";
36
- };
37
- };
38
- declare type Mapping<T> = Partial<{
39
- [Property in keyof T]: boolean;
40
- }>;
41
- declare type Options<T> = {
19
+ readonly enterRoom: (roomId: string, initialState: Partial<TState>) => void;
42
20
  /**
43
- * Liveblocks client created by @liveblocks/client createClient
21
+ * Leaves a room and stops sync it with zustand state.
22
+ * @param roomId The id of the room
44
23
  */
45
- client: Client;
24
+ readonly leaveRoom: (roomId: string) => void;
46
25
  /**
47
- * Mapping used to synchronize a part of your zustand state with one Liveblocks Room storage.
26
+ * The room currently synced to your zustand state.
48
27
  */
49
- storageMapping?: Mapping<T>;
28
+ readonly room: Room<TPresence, TStorage> | null;
50
29
  /**
51
- * Mapping used to synchronize a part of your zustand state with one Liveblocks Room presence.
30
+ * Other users in the room. Empty no room is currently synced
52
31
  */
53
- presenceMapping?: Mapping<T>;
32
+ readonly others: Array<User<TPresence>>;
33
+ /**
34
+ * Whether or not the room storage is currently loading
35
+ */
36
+ readonly isStorageLoading: boolean;
37
+ /**
38
+ * Connection state of the room
39
+ */
40
+ readonly connection:
41
+ | "closed"
42
+ | "authenticating"
43
+ | "unavailable"
44
+ | "failed"
45
+ | "open"
46
+ | "connecting";
47
+ };
48
+ };
49
+ declare type Mapping<T> = {
50
+ [K in keyof T]?: boolean;
51
+ };
52
+ declare type Options<T> = {
53
+ /**
54
+ * Liveblocks client created by @liveblocks/client createClient
55
+ */
56
+ client: Client;
57
+ /**
58
+ * Mapping used to synchronize a part of your zustand state with one Liveblocks Room storage.
59
+ */
60
+ storageMapping?: Mapping<T>;
61
+ /**
62
+ * Mapping used to synchronize a part of your zustand state with one Liveblocks Room presence.
63
+ */
64
+ presenceMapping?: Mapping<T>;
54
65
  };
55
- declare function middleware<T extends Record<string, unknown>, TPresence extends Record<string, unknown> = Presence>(config: StateCreator<T, SetState<T>, GetState<LiveblocksState<T>>, StoreApi<T>>, options: Options<T>): StateCreator<LiveblocksState<T, TPresence>, SetState<LiveblocksState<T, TPresence>>, GetState<LiveblocksState<T, TPresence>>, StoreApi<LiveblocksState<T, TPresence>>>;
66
+ declare function middleware<
67
+ T extends ZustandState,
68
+ TPresence extends JsonObject,
69
+ TStorage extends LsonObject
70
+ >(
71
+ config: StateCreator<
72
+ T,
73
+ SetState<T>,
74
+ GetState<LiveblocksState<T, TPresence, TStorage>>,
75
+ StoreApi<T>
76
+ >,
77
+ options: Options<T>
78
+ ): StateCreator<
79
+ LiveblocksState<T, TPresence, TStorage>,
80
+ SetState<LiveblocksState<T, TPresence, TStorage>>,
81
+ GetState<LiveblocksState<T, TPresence, TStorage>>,
82
+ StoreApi<LiveblocksState<T, TPresence, TStorage>>
83
+ >;
56
84
 
57
- export { LiveblocksState, Mapping, middleware };
85
+ export { LiveblocksState, Mapping, ZustandState, middleware };
package/index.js CHANGED
@@ -1,185 +1,326 @@
1
1
  "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: !0
5
- });
6
-
2
+ Object.defineProperty(exports, "__esModule", { value: !0 });
7
3
  var internal = require("@liveblocks/client/internal");
8
-
9
4
  function _extends() {
10
- return _extends = Object.assign || function(target) {
11
- for (var i = 1; i < arguments.length; i++) {
12
- var source = arguments[i];
13
- for (var key in source) Object.prototype.hasOwnProperty.call(source, key) && (target[key] = source[key]);
14
- }
15
- return target;
16
- }, _extends.apply(this, arguments);
5
+ return (
6
+ (_extends =
7
+ Object.assign ||
8
+ function (target) {
9
+ for (var i = 1; i < arguments.length; i++) {
10
+ var source = arguments[i];
11
+ for (var key in source)
12
+ Object.prototype.hasOwnProperty.call(source, key) &&
13
+ (target[key] = source[key]);
14
+ }
15
+ return target;
16
+ }),
17
+ _extends.apply(this, arguments)
18
+ );
17
19
  }
18
-
19
20
  function _arrayLikeToArray(arr, len) {
20
- (null == len || len > arr.length) && (len = arr.length);
21
- for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
22
- return arr2;
21
+ (null == len || len > arr.length) && (len = arr.length);
22
+ for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
23
+ return arr2;
23
24
  }
24
-
25
25
  function _createForOfIteratorHelperLoose(o, allowArrayLike) {
26
- var it = "undefined" != typeof Symbol && o[Symbol.iterator] || o["@@iterator"];
27
- if (it) return (it = it.call(o)).next.bind(it);
28
- if (Array.isArray(o) || (it = function(o, minLen) {
29
- if (o) {
30
- if ("string" == typeof o) return _arrayLikeToArray(o, minLen);
31
- var n = Object.prototype.toString.call(o).slice(8, -1);
32
- return "Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n ? Array.from(o) : "Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n) ? _arrayLikeToArray(o, minLen) : void 0;
26
+ var it =
27
+ ("undefined" != typeof Symbol && o[Symbol.iterator]) || o["@@iterator"];
28
+ if (it) return (it = it.call(o)).next.bind(it);
29
+ if (
30
+ Array.isArray(o) ||
31
+ (it = (function (o, minLen) {
32
+ if (o) {
33
+ if ("string" == typeof o) return _arrayLikeToArray(o, minLen);
34
+ var n = Object.prototype.toString.call(o).slice(8, -1);
35
+ return (
36
+ "Object" === n && o.constructor && (n = o.constructor.name),
37
+ "Map" === n || "Set" === n
38
+ ? Array.from(o)
39
+ : "Arguments" === n ||
40
+ /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)
41
+ ? _arrayLikeToArray(o, minLen)
42
+ : void 0
43
+ );
44
+ }
45
+ })(o)) ||
46
+ (allowArrayLike && o && "number" == typeof o.length)
47
+ ) {
48
+ it && (o = it);
49
+ var i = 0;
50
+ return function () {
51
+ return i >= o.length ? { done: !0 } : { done: !1, value: o[i++] };
52
+ };
33
53
  }
34
- }(o)) || allowArrayLike && o && "number" == typeof o.length) {
35
- it && (o = it);
36
- var i = 0;
37
- return function() {
38
- return i >= o.length ? {
39
- done: !0
40
- } : {
41
- done: !1,
42
- value: o[i++]
43
- };
44
- };
45
- }
46
- throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
54
+ throw new TypeError(
55
+ "Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
56
+ );
47
57
  }
48
-
49
58
  var ERROR_PREFIX = "Invalid @liveblocks/zustand middleware config.";
50
-
51
59
  function mappingValueShouldBeABoolean(mappingType, key) {
52
- return new Error(ERROR_PREFIX + " " + mappingType + "." + key + " value should be a boolean");
60
+ return new Error(
61
+ ERROR_PREFIX + " " + mappingType + "." + key + " value should be a boolean"
62
+ );
53
63
  }
54
-
55
64
  function mappingShouldNotHaveTheSameKeys(key) {
56
- return new Error(ERROR_PREFIX + ' "' + key + "\" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.");
65
+ return new Error(
66
+ ERROR_PREFIX +
67
+ ' "' +
68
+ key +
69
+ "\" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping."
70
+ );
57
71
  }
58
-
59
72
  function mappingToFunctionIsNotAllowed(key) {
60
- return new Error(ERROR_PREFIX + " mapping." + key + " is invalid. Mapping to a function is not allowed.");
73
+ return new Error(
74
+ ERROR_PREFIX +
75
+ " mapping." +
76
+ key +
77
+ " is invalid. Mapping to a function is not allowed."
78
+ );
79
+ }
80
+ function isJson(value) {
81
+ return (
82
+ null === value ||
83
+ "string" == typeof value ||
84
+ "number" == typeof value ||
85
+ "boolean" == typeof value ||
86
+ (Array.isArray(value) && value.every(isJson)) ||
87
+ ("object" == typeof value && Object.values(value).every(isJson))
88
+ );
61
89
  }
62
-
63
90
  function updateZustandLiveblocksState(set, partial) {
64
- set((function(state) {
65
- return {
66
- liveblocks: _extends({}, state.liveblocks, partial)
67
- };
68
- }));
91
+ set(function (state) {
92
+ return { liveblocks: _extends({}, state.liveblocks, partial) };
93
+ });
69
94
  }
70
-
71
95
  function validateMapping(mapping, mappingType) {
72
- if ("production" !== process.env.NODE_ENV) {
73
- if (null == mapping) throw function(mappingType) {
74
- return new Error(ERROR_PREFIX + " " + mappingType + " is missing.");
75
- }(mappingType);
76
- if (value = mapping, "[object Object]" !== Object.prototype.toString.call(value)) throw function(mappingType) {
77
- return new Error(ERROR_PREFIX + " " + mappingType + " should be an object where the values are boolean.");
78
- }(mappingType);
79
- }
80
- var value, result = {};
81
- for (var key in mapping) {
82
- if ("production" !== process.env.NODE_ENV && "boolean" != typeof mapping[key]) throw mappingValueShouldBeABoolean(mappingType, key);
83
- !0 === mapping[key] && (result[key] = !0);
84
- }
85
- return result;
96
+ if ("production" !== process.env.NODE_ENV) {
97
+ if (null == mapping)
98
+ throw (function (mappingType) {
99
+ return new Error(ERROR_PREFIX + " " + mappingType + " is missing.");
100
+ })(mappingType);
101
+ if (
102
+ ((value = mapping),
103
+ "[object Object]" !== Object.prototype.toString.call(value))
104
+ )
105
+ throw (function (mappingType) {
106
+ return new Error(
107
+ ERROR_PREFIX +
108
+ " " +
109
+ mappingType +
110
+ " should be an object where the values are boolean."
111
+ );
112
+ })(mappingType);
113
+ }
114
+ var value,
115
+ result = {};
116
+ for (var key in mapping) {
117
+ if (
118
+ "production" !== process.env.NODE_ENV &&
119
+ "boolean" != typeof mapping[key]
120
+ )
121
+ throw mappingValueShouldBeABoolean(mappingType, key);
122
+ !0 === mapping[key] && (result[key] = !0);
123
+ }
124
+ return result;
86
125
  }
126
+ exports.middleware = function (config, options) {
127
+ if ("production" !== process.env.NODE_ENV && null == options.client)
128
+ throw new Error(ERROR_PREFIX + " client is missing");
129
+ var client = options.client,
130
+ storageMapping = validateMapping(
131
+ options.storageMapping || {},
132
+ "storageMapping"
133
+ ),
134
+ presenceMapping = validateMapping(
135
+ options.presenceMapping || {},
136
+ "presenceMapping"
137
+ );
138
+ return (
139
+ "production" !== process.env.NODE_ENV &&
140
+ (function (storageMapping, presenceMapping) {
141
+ for (var key in storageMapping)
142
+ if (void 0 !== presenceMapping[key])
143
+ throw mappingShouldNotHaveTheSameKeys(key);
144
+ })(storageMapping, presenceMapping),
145
+ function (set, get, api) {
146
+ var typedSet = set,
147
+ room = null,
148
+ isPatching = !1,
149
+ storageRoot = null,
150
+ unsubscribeCallbacks = [],
151
+ store = config(
152
+ function (args) {
153
+ var oldState = get();
154
+ set(args);
155
+ var newState = get();
156
+ room &&
157
+ ((isPatching = !0),
158
+ (function (room, oldState, newState, presenceMapping) {
159
+ for (var key in presenceMapping) {
160
+ if ("function" == typeof newState[key])
161
+ throw mappingToFunctionIsNotAllowed("value");
162
+ if (oldState[key] !== newState[key]) {
163
+ var _room$updatePresence2,
164
+ val = newState[key];
165
+ room.updatePresence(
166
+ (((_room$updatePresence2 = {})[key] = val),
167
+ _room$updatePresence2)
168
+ );
169
+ }
170
+ }
171
+ })(room, oldState, newState, presenceMapping),
172
+ room.batch(function () {
173
+ storageRoot &&
174
+ (function (root, oldState, newState, mapping) {
175
+ for (var key in mapping) {
176
+ if (
177
+ "production" !== process.env.NODE_ENV &&
178
+ "function" == typeof newState[key]
179
+ )
180
+ throw mappingToFunctionIsNotAllowed("value");
181
+ if (oldState[key] !== newState[key]) {
182
+ var oldVal = oldState[key],
183
+ newVal = newState[key];
184
+ (void 0 !== oldVal && !isJson(oldVal)) ||
185
+ (void 0 !== newVal && !isJson(newVal)) ||
186
+ internal.patchLiveObjectKey(
187
+ root,
188
+ key,
189
+ oldVal,
190
+ newVal
191
+ );
192
+ }
193
+ }
194
+ })(storageRoot, oldState, newState, storageMapping);
195
+ }),
196
+ (isPatching = !1));
197
+ },
198
+ get,
199
+ api
200
+ );
201
+ return _extends({}, store, {
202
+ liveblocks: {
203
+ enterRoom: function (roomId, initialState) {
204
+ if (!storageRoot) {
205
+ (room = client.enter(roomId)),
206
+ updateZustandLiveblocksState(set, {
207
+ isStorageLoading: !0,
208
+ room: room,
209
+ });
210
+ var state = get();
211
+ !(function (room, state, mapping) {
212
+ for (var key in mapping) {
213
+ var _room$updatePresence;
214
+ null == room ||
215
+ room.updatePresence(
216
+ (((_room$updatePresence = {})[key] = state[key]),
217
+ _room$updatePresence)
218
+ );
219
+ }
220
+ })(room, state, presenceMapping),
221
+ unsubscribeCallbacks.push(
222
+ room.subscribe("others", function (others) {
223
+ updateZustandLiveblocksState(set, {
224
+ others: others.toArray(),
225
+ });
226
+ })
227
+ ),
228
+ unsubscribeCallbacks.push(
229
+ room.subscribe("connection", function () {
230
+ updateZustandLiveblocksState(set, {
231
+ connection: room.getConnectionState(),
232
+ });
233
+ })
234
+ ),
235
+ unsubscribeCallbacks.push(
236
+ room.subscribe("my-presence", function () {
237
+ !1 === isPatching &&
238
+ set(
239
+ (function (presence, mapping) {
240
+ var partialState = {};
241
+ for (var key in mapping)
242
+ partialState[key] = presence[key];
243
+ return partialState;
244
+ })(room.getPresence(), presenceMapping)
245
+ );
246
+ })
247
+ ),
248
+ room.getStorage().then(function (_ref) {
249
+ var root = _ref.root,
250
+ updates = {};
251
+ room.batch(function () {
252
+ for (var key in storageMapping) {
253
+ var liveblocksStatePart = root.get(key);
254
+ null == liveblocksStatePart
255
+ ? ((updates[key] = initialState[key]),
256
+ internal.patchLiveObjectKey(
257
+ root,
258
+ key,
259
+ void 0,
260
+ initialState[key]
261
+ ))
262
+ : (updates[key] =
263
+ internal.lsonToJson(liveblocksStatePart));
264
+ }
265
+ }),
266
+ typedSet(updates),
267
+ (storageRoot = root),
268
+ unsubscribeCallbacks.push(
269
+ room.subscribe(
270
+ root,
271
+ function (updates) {
272
+ !1 === isPatching &&
273
+ set(
274
+ (function (state, updates, mapping) {
275
+ var partialState = {};
276
+ for (var key in mapping)
277
+ partialState[key] = state[key];
278
+ var patched = internal.patchImmutableObject(
279
+ partialState,
280
+ updates
281
+ ),
282
+ result = {};
283
+ for (var _key in mapping)
284
+ result[_key] = patched[_key];
285
+ return result;
286
+ })(get(), updates, storageMapping)
287
+ );
288
+ },
289
+ { isDeep: !0 }
290
+ )
291
+ ),
292
+ updateZustandLiveblocksState(set, { isStorageLoading: !1 });
293
+ });
294
+ }
295
+ },
296
+ leaveRoom: function (roomId) {
297
+ for (
298
+ var _step,
299
+ _iterator =
300
+ _createForOfIteratorHelperLoose(unsubscribeCallbacks);
301
+ !(_step = _iterator()).done;
87
302
 
88
- exports.middleware = function(config, options) {
89
- if ("production" !== process.env.NODE_ENV && null == options.client) throw new Error(ERROR_PREFIX + " client is missing");
90
- var client = options.client, storageMapping = validateMapping(options.storageMapping || {}, "storageMapping"), presenceMapping = validateMapping(options.presenceMapping || {}, "presenceMapping");
91
- return "production" !== process.env.NODE_ENV && function(storageMapping, presenceMapping) {
92
- for (var key in storageMapping) if (void 0 !== presenceMapping[key]) throw mappingShouldNotHaveTheSameKeys(key);
93
- }(storageMapping, presenceMapping), function(set, get, api) {
94
- var typedSet = set, room = null, isPatching = !1, storageRoot = null, unsubscribeCallbacks = [], store = config((function(args) {
95
- var oldState = get();
96
- set(args);
97
- var newState = get();
98
- room && (isPatching = !0, function(room, oldState, newState, presenceMapping) {
99
- for (var key in presenceMapping) {
100
- if ("function" == typeof newState[key]) throw mappingToFunctionIsNotAllowed("value");
101
- var _room$updatePresence2;
102
- if (oldState[key] !== newState[key]) room.updatePresence(((_room$updatePresence2 = {})[key] = newState[key],
103
- _room$updatePresence2));
104
- }
105
- }(room, oldState, newState, presenceMapping), room.batch((function() {
106
- storageRoot && function(root, oldState, newState, mapping) {
107
- for (var key in mapping) {
108
- if ("production" !== process.env.NODE_ENV && "function" == typeof newState[key]) throw mappingToFunctionIsNotAllowed("value");
109
- oldState[key] !== newState[key] && internal.patchLiveObjectKey(root, key, oldState[key], newState[key]);
110
- }
111
- }(storageRoot, oldState, newState, storageMapping);
112
- })), isPatching = !1);
113
- }), get, api);
114
- return _extends({}, store, {
115
- liveblocks: {
116
- enterRoom: function(roomId, initialState) {
117
- if (!storageRoot) {
118
- room = client.enter(roomId), updateZustandLiveblocksState(set, {
119
- isStorageLoading: !0,
120
- room: room
303
+ ) {
304
+ (0, _step.value)();
305
+ }
306
+ (storageRoot = null),
307
+ (room = null),
308
+ (isPatching = !1),
309
+ (unsubscribeCallbacks = []),
310
+ client.leave(roomId),
311
+ updateZustandLiveblocksState(set, {
312
+ others: [],
313
+ connection: "closed",
314
+ isStorageLoading: !1,
315
+ room: null,
316
+ });
317
+ },
318
+ room: null,
319
+ others: [],
320
+ connection: "closed",
321
+ isStorageLoading: !1,
322
+ },
121
323
  });
122
- var state = get();
123
- !function(room, state, mapping) {
124
- for (var key in mapping) {
125
- var _room$updatePresence;
126
- null == room || room.updatePresence(((_room$updatePresence = {})[key] = state[key],
127
- _room$updatePresence));
128
- }
129
- }(room, state, presenceMapping), unsubscribeCallbacks.push(room.subscribe("others", (function(others) {
130
- updateZustandLiveblocksState(set, {
131
- others: others.toArray()
132
- });
133
- }))), unsubscribeCallbacks.push(room.subscribe("connection", (function() {
134
- updateZustandLiveblocksState(set, {
135
- connection: room.getConnectionState()
136
- });
137
- }))), unsubscribeCallbacks.push(room.subscribe("my-presence", (function() {
138
- !1 === isPatching && set(function(presence, mapping) {
139
- var partialState = {};
140
- for (var key in mapping) partialState[key] = presence[key];
141
- return partialState;
142
- }(room.getPresence(), presenceMapping));
143
- }))), room.getStorage().then((function(_ref) {
144
- var root = _ref.root, updates = {};
145
- room.batch((function() {
146
- for (var key in storageMapping) {
147
- var liveblocksStatePart = root.get(key);
148
- null == liveblocksStatePart ? (updates[key] = initialState[key], internal.patchLiveObjectKey(root, key, void 0, initialState[key])) : updates[key] = internal.lsonToJson(liveblocksStatePart);
149
- }
150
- })), typedSet(updates), storageRoot = root, unsubscribeCallbacks.push(room.subscribe(root, (function(updates) {
151
- !1 === isPatching && set(function(state, updates, mapping) {
152
- var partialState = {};
153
- for (var key in mapping) partialState[key] = state[key];
154
- var patched = internal.patchImmutableObject(partialState, updates), result = {};
155
- for (var _key in mapping) result[_key] = patched[_key];
156
- return result;
157
- }(get(), updates, storageMapping));
158
- }), {
159
- isDeep: !0
160
- })), updateZustandLiveblocksState(set, {
161
- isStorageLoading: !1
162
- });
163
- }));
164
- }
165
- },
166
- leaveRoom: function(roomId) {
167
- for (var _step, _iterator = _createForOfIteratorHelperLoose(unsubscribeCallbacks); !(_step = _iterator()).done; ) {
168
- (0, _step.value)();
169
- }
170
- storageRoot = null, room = null, isPatching = !1, unsubscribeCallbacks = [], client.leave(roomId),
171
- updateZustandLiveblocksState(set, {
172
- others: [],
173
- connection: "closed",
174
- isStorageLoading: !1,
175
- room: null
176
- });
177
- },
178
- room: null,
179
- others: [],
180
- connection: "closed",
181
- isStorageLoading: !1
182
- }
183
- });
184
- };
324
+ }
325
+ );
185
326
  };
package/index.mjs CHANGED
@@ -1,137 +1,240 @@
1
- import { patchLiveObjectKey, lsonToJson, patchImmutableObject } from "@liveblocks/client/internal";
2
-
1
+ import {
2
+ patchLiveObjectKey,
3
+ lsonToJson,
4
+ patchImmutableObject,
5
+ } from "@liveblocks/client/internal";
3
6
  const ERROR_PREFIX = "Invalid @liveblocks/zustand middleware config.";
4
-
5
7
  function mappingValueShouldBeABoolean(mappingType, key) {
6
- return new Error(`${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`);
8
+ return new Error(
9
+ `${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`
10
+ );
7
11
  }
8
-
9
12
  function mappingShouldNotHaveTheSameKeys(key) {
10
- return new Error(`${ERROR_PREFIX} "${key}" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.`);
13
+ return new Error(
14
+ `${ERROR_PREFIX} "${key}" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.`
15
+ );
11
16
  }
12
-
13
17
  function mappingToFunctionIsNotAllowed(key) {
14
- return new Error(`${ERROR_PREFIX} mapping.${key} is invalid. Mapping to a function is not allowed.`);
18
+ return new Error(
19
+ `${ERROR_PREFIX} mapping.${key} is invalid. Mapping to a function is not allowed.`
20
+ );
21
+ }
22
+ function isJson(value) {
23
+ return (
24
+ null === value ||
25
+ "string" == typeof value ||
26
+ "number" == typeof value ||
27
+ "boolean" == typeof value ||
28
+ (Array.isArray(value) && value.every(isJson)) ||
29
+ ("object" == typeof value && Object.values(value).every(isJson))
30
+ );
15
31
  }
16
-
17
32
  function middleware(config, options) {
18
- if ("production" !== process.env.NODE_ENV && null == options.client) throw new Error(`${ERROR_PREFIX} client is missing`);
19
- const client = options.client, storageMapping = validateMapping(options.storageMapping || {}, "storageMapping"), presenceMapping = validateMapping(options.presenceMapping || {}, "presenceMapping");
20
- return "production" !== process.env.NODE_ENV && function(storageMapping, presenceMapping) {
21
- for (const key in storageMapping) if (void 0 !== presenceMapping[key]) throw mappingShouldNotHaveTheSameKeys(key);
22
- }(storageMapping, presenceMapping), (set, get, api) => {
23
- const typedSet = set;
24
- let room = null, isPatching = !1, storageRoot = null, unsubscribeCallbacks = [];
25
- const store = config((args => {
26
- const oldState = get();
27
- set(args);
28
- const newState = get();
29
- room && (isPatching = !0, function(room, oldState, newState, presenceMapping) {
30
- for (const key in presenceMapping) {
31
- if ("function" == typeof newState[key]) throw mappingToFunctionIsNotAllowed("value");
32
- oldState[key] !== newState[key] && room.updatePresence({
33
- [key]: newState[key]
34
- });
35
- }
36
- }(room, oldState, newState, presenceMapping), room.batch((() => {
37
- storageRoot && function(root, oldState, newState, mapping) {
38
- for (const key in mapping) {
39
- if ("production" !== process.env.NODE_ENV && "function" == typeof newState[key]) throw mappingToFunctionIsNotAllowed("value");
40
- oldState[key] !== newState[key] && patchLiveObjectKey(root, key, oldState[key], newState[key]);
41
- }
42
- }(storageRoot, oldState, newState, storageMapping);
43
- })), isPatching = !1);
44
- }), get, api);
45
- return Object.assign(Object.assign({}, store), {
46
- liveblocks: {
47
- enterRoom: function(roomId, initialState) {
48
- if (storageRoot) return;
49
- room = client.enter(roomId), updateZustandLiveblocksState(set, {
50
- isStorageLoading: !0,
51
- room: room
52
- });
53
- const state = get();
54
- !function(room, state, mapping) {
55
- for (const key in mapping) null == room || room.updatePresence({
56
- [key]: state[key]
57
- });
58
- }(room, state, presenceMapping), unsubscribeCallbacks.push(room.subscribe("others", (others => {
59
- updateZustandLiveblocksState(set, {
60
- others: others.toArray()
33
+ if ("production" !== process.env.NODE_ENV && null == options.client)
34
+ throw new Error(`${ERROR_PREFIX} client is missing`);
35
+ const client = options.client,
36
+ storageMapping = validateMapping(
37
+ options.storageMapping || {},
38
+ "storageMapping"
39
+ ),
40
+ presenceMapping = validateMapping(
41
+ options.presenceMapping || {},
42
+ "presenceMapping"
43
+ );
44
+ return (
45
+ "production" !== process.env.NODE_ENV &&
46
+ (function (storageMapping, presenceMapping) {
47
+ for (const key in storageMapping)
48
+ if (void 0 !== presenceMapping[key])
49
+ throw mappingShouldNotHaveTheSameKeys(key);
50
+ })(storageMapping, presenceMapping),
51
+ (set, get, api) => {
52
+ const typedSet = set;
53
+ let room = null,
54
+ isPatching = !1,
55
+ storageRoot = null,
56
+ unsubscribeCallbacks = [];
57
+ const store = config(
58
+ (args) => {
59
+ const oldState = get();
60
+ set(args);
61
+ const newState = get();
62
+ room &&
63
+ ((isPatching = !0),
64
+ (function (room, oldState, newState, presenceMapping) {
65
+ for (const key in presenceMapping) {
66
+ if ("function" == typeof newState[key])
67
+ throw mappingToFunctionIsNotAllowed("value");
68
+ if (oldState[key] !== newState[key]) {
69
+ const val = newState[key];
70
+ room.updatePresence({ [key]: val });
71
+ }
72
+ }
73
+ })(room, oldState, newState, presenceMapping),
74
+ room.batch(() => {
75
+ storageRoot &&
76
+ (function (root, oldState, newState, mapping) {
77
+ for (const key in mapping) {
78
+ if (
79
+ "production" !== process.env.NODE_ENV &&
80
+ "function" == typeof newState[key]
81
+ )
82
+ throw mappingToFunctionIsNotAllowed("value");
83
+ if (oldState[key] !== newState[key]) {
84
+ const oldVal = oldState[key],
85
+ newVal = newState[key];
86
+ (void 0 !== oldVal && !isJson(oldVal)) ||
87
+ (void 0 !== newVal && !isJson(newVal)) ||
88
+ patchLiveObjectKey(root, key, oldVal, newVal);
89
+ }
90
+ }
91
+ })(storageRoot, oldState, newState, storageMapping);
92
+ }),
93
+ (isPatching = !1));
94
+ },
95
+ get,
96
+ api
97
+ );
98
+ return Object.assign(Object.assign({}, store), {
99
+ liveblocks: {
100
+ enterRoom: function (roomId, initialState) {
101
+ if (storageRoot) return;
102
+ (room = client.enter(roomId)),
103
+ updateZustandLiveblocksState(set, {
104
+ isStorageLoading: !0,
105
+ room: room,
106
+ });
107
+ const state = get();
108
+ !(function (room, state, mapping) {
109
+ for (const key in mapping)
110
+ null == room || room.updatePresence({ [key]: state[key] });
111
+ })(room, state, presenceMapping),
112
+ unsubscribeCallbacks.push(
113
+ room.subscribe("others", (others) => {
114
+ updateZustandLiveblocksState(set, {
115
+ others: others.toArray(),
116
+ });
117
+ })
118
+ ),
119
+ unsubscribeCallbacks.push(
120
+ room.subscribe("connection", () => {
121
+ updateZustandLiveblocksState(set, {
122
+ connection: room.getConnectionState(),
123
+ });
124
+ })
125
+ ),
126
+ unsubscribeCallbacks.push(
127
+ room.subscribe("my-presence", () => {
128
+ !1 === isPatching &&
129
+ set(
130
+ (function (presence, mapping) {
131
+ const partialState = {};
132
+ for (const key in mapping)
133
+ partialState[key] = presence[key];
134
+ return partialState;
135
+ })(room.getPresence(), presenceMapping)
136
+ );
137
+ })
138
+ ),
139
+ room.getStorage().then(({ root: root }) => {
140
+ const updates = {};
141
+ room.batch(() => {
142
+ for (const key in storageMapping) {
143
+ const liveblocksStatePart = root.get(key);
144
+ null == liveblocksStatePart
145
+ ? ((updates[key] = initialState[key]),
146
+ patchLiveObjectKey(
147
+ root,
148
+ key,
149
+ void 0,
150
+ initialState[key]
151
+ ))
152
+ : (updates[key] = lsonToJson(liveblocksStatePart));
153
+ }
154
+ }),
155
+ typedSet(updates),
156
+ (storageRoot = root),
157
+ unsubscribeCallbacks.push(
158
+ room.subscribe(
159
+ root,
160
+ (updates) => {
161
+ !1 === isPatching &&
162
+ set(
163
+ (function (state, updates, mapping) {
164
+ const partialState = {};
165
+ for (const key in mapping)
166
+ partialState[key] = state[key];
167
+ const patched = patchImmutableObject(
168
+ partialState,
169
+ updates
170
+ ),
171
+ result = {};
172
+ for (const key in mapping)
173
+ result[key] = patched[key];
174
+ return result;
175
+ })(get(), updates, storageMapping)
176
+ );
177
+ },
178
+ { isDeep: !0 }
179
+ )
180
+ ),
181
+ updateZustandLiveblocksState(set, { isStorageLoading: !1 });
182
+ });
183
+ },
184
+ leaveRoom: function (roomId) {
185
+ for (const unsubscribe of unsubscribeCallbacks) unsubscribe();
186
+ (storageRoot = null),
187
+ (room = null),
188
+ (isPatching = !1),
189
+ (unsubscribeCallbacks = []),
190
+ client.leave(roomId),
191
+ updateZustandLiveblocksState(set, {
192
+ others: [],
193
+ connection: "closed",
194
+ isStorageLoading: !1,
195
+ room: null,
196
+ });
197
+ },
198
+ room: null,
199
+ others: [],
200
+ connection: "closed",
201
+ isStorageLoading: !1,
202
+ },
61
203
  });
62
- }))), unsubscribeCallbacks.push(room.subscribe("connection", (() => {
63
- updateZustandLiveblocksState(set, {
64
- connection: room.getConnectionState()
65
- });
66
- }))), unsubscribeCallbacks.push(room.subscribe("my-presence", (() => {
67
- !1 === isPatching && set(function(presence, mapping) {
68
- const partialState = {};
69
- for (const key in mapping) partialState[key] = presence[key];
70
- return partialState;
71
- }(room.getPresence(), presenceMapping));
72
- }))), room.getStorage().then((({root: root}) => {
73
- const updates = {};
74
- room.batch((() => {
75
- for (const key in storageMapping) {
76
- const liveblocksStatePart = root.get(key);
77
- null == liveblocksStatePart ? (updates[key] = initialState[key], patchLiveObjectKey(root, key, void 0, initialState[key])) : updates[key] = lsonToJson(liveblocksStatePart);
78
- }
79
- })), typedSet(updates), storageRoot = root, unsubscribeCallbacks.push(room.subscribe(root, (updates => {
80
- !1 === isPatching && set(function(state, updates, mapping) {
81
- const partialState = {};
82
- for (const key in mapping) partialState[key] = state[key];
83
- const patched = patchImmutableObject(partialState, updates), result = {};
84
- for (const key in mapping) result[key] = patched[key];
85
- return result;
86
- }(get(), updates, storageMapping));
87
- }), {
88
- isDeep: !0
89
- })), updateZustandLiveblocksState(set, {
90
- isStorageLoading: !1
91
- });
92
- }));
93
- },
94
- leaveRoom: function(roomId) {
95
- for (const unsubscribe of unsubscribeCallbacks) unsubscribe();
96
- storageRoot = null, room = null, isPatching = !1, unsubscribeCallbacks = [], client.leave(roomId),
97
- updateZustandLiveblocksState(set, {
98
- others: [],
99
- connection: "closed",
100
- isStorageLoading: !1,
101
- room: null
102
- });
103
- },
104
- room: null,
105
- others: [],
106
- connection: "closed",
107
- isStorageLoading: !1
108
- }
109
- });
110
- };
204
+ }
205
+ );
111
206
  }
112
-
113
207
  function updateZustandLiveblocksState(set, partial) {
114
- set((state => ({
115
- liveblocks: Object.assign(Object.assign({}, state.liveblocks), partial)
116
- })));
208
+ set((state) => ({
209
+ liveblocks: Object.assign(Object.assign({}, state.liveblocks), partial),
210
+ }));
117
211
  }
118
-
119
212
  function validateMapping(mapping, mappingType) {
120
- if ("production" !== process.env.NODE_ENV) {
121
- if (null == mapping) throw function(mappingType) {
122
- return new Error(`${ERROR_PREFIX} ${mappingType} is missing.`);
123
- }(mappingType);
124
- if (value = mapping, "[object Object]" !== Object.prototype.toString.call(value)) throw function(mappingType) {
125
- return new Error(`${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`);
126
- }(mappingType);
127
- }
128
- var value;
129
- const result = {};
130
- for (const key in mapping) {
131
- if ("production" !== process.env.NODE_ENV && "boolean" != typeof mapping[key]) throw mappingValueShouldBeABoolean(mappingType, key);
132
- !0 === mapping[key] && (result[key] = !0);
133
- }
134
- return result;
213
+ if ("production" !== process.env.NODE_ENV) {
214
+ if (null == mapping)
215
+ throw (function (mappingType) {
216
+ return new Error(`${ERROR_PREFIX} ${mappingType} is missing.`);
217
+ })(mappingType);
218
+ if (
219
+ ((value = mapping),
220
+ "[object Object]" !== Object.prototype.toString.call(value))
221
+ )
222
+ throw (function (mappingType) {
223
+ return new Error(
224
+ `${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`
225
+ );
226
+ })(mappingType);
227
+ }
228
+ var value;
229
+ const result = {};
230
+ for (const key in mapping) {
231
+ if (
232
+ "production" !== process.env.NODE_ENV &&
233
+ "boolean" != typeof mapping[key]
234
+ )
235
+ throw mappingValueShouldBeABoolean(mappingType, key);
236
+ !0 === mapping[key] && (result[key] = !0);
237
+ }
238
+ return result;
135
239
  }
136
-
137
240
  export { middleware };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/zustand",
3
- "version": "0.16.15",
3
+ "version": "0.17.0-test1",
4
4
  "description": "A middleware to integrate Liveblocks into Zustand stores.",
5
5
  "main": "./index.js",
6
6
  "module": "./index.mjs",
@@ -20,8 +20,8 @@
20
20
  "build": "rollup -c && cp ./package.json ./README.md ./lib",
21
21
  "format": "eslint --fix src/ test/ && prettier --write src/ test/",
22
22
  "lint": "eslint src/ test/",
23
- "test": "jest --watch",
24
- "test-ci": "jest",
23
+ "test": "jest --watch --silent --verbose",
24
+ "test-ci": "jest --silent --verbose",
25
25
  "dtslint": "dtslint --localTs node_modules/typescript/lib --expectOnly types"
26
26
  },
27
27
  "license": "Apache-2.0",
@@ -31,7 +31,7 @@
31
31
  "directory": "packages/liveblocks-zustand"
32
32
  },
33
33
  "peerDependencies": {
34
- "@liveblocks/client": "0.16.15",
34
+ "@liveblocks/client": "0.17.0-test1",
35
35
  "zustand": "^3"
36
36
  },
37
37
  "devDependencies": {
@@ -46,9 +46,9 @@
46
46
  "@testing-library/jest-dom": "^5.16.1",
47
47
  "@testing-library/react": "^12.1.2",
48
48
  "@testing-library/react-hooks": "^7.0.2",
49
- "@types/jest": "^27.4.0",
50
- "@typescript-eslint/eslint-plugin": "^5.18.0",
51
- "@typescript-eslint/parser": "^5.18.0",
49
+ "@types/jest": "^27.5.1",
50
+ "@typescript-eslint/eslint-plugin": "^5.26.0",
51
+ "@typescript-eslint/parser": "^5.26.0",
52
52
  "eslint": "^8.12.0",
53
53
  "eslint-plugin-import": "^2.26.0",
54
54
  "eslint-plugin-simple-import-sort": "^7.0.0",
@@ -56,8 +56,10 @@
56
56
  "msw": "^0.36.4",
57
57
  "rollup": "^2.64.0",
58
58
  "rollup-plugin-command": "^1.1.3",
59
- "rollup-plugin-dts": "^4.2.1",
59
+ "rollup-plugin-dts": "^4.2.2",
60
+ "rollup-plugin-prettier": "^2.2.2",
60
61
  "rollup-plugin-terser": "^7.0.2",
62
+ "typescript": "^4.7.2",
61
63
  "whatwg-fetch": "^3.6.2",
62
64
  "zustand": "^3.6.9"
63
65
  },