@liveblocks/zustand 1.2.0-internal4 → 1.2.0-internal6
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.mts +84 -0
- package/dist/index.js +11 -42
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +244 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +16 -3
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { JsonObject, LsonObject, BaseUserMeta, Json, Room, User, Status, Client } from '@liveblocks/client';
|
|
2
|
+
import { LegacyConnectionStatus } from '@liveblocks/core';
|
|
3
|
+
import { StoreMutatorIdentifier, StateCreator } from 'zustand';
|
|
4
|
+
|
|
5
|
+
declare type LiveblocksContext<TPresence extends JsonObject, TStorage extends LsonObject, TUserMeta extends BaseUserMeta, TRoomEvent extends Json> = {
|
|
6
|
+
/**
|
|
7
|
+
* Enters a room and starts sync it with zustand state
|
|
8
|
+
* @param roomId The id of the room
|
|
9
|
+
*/
|
|
10
|
+
readonly enterRoom: (roomId: string) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Leaves a room and stops sync it with zustand state.
|
|
13
|
+
* @param roomId The id of the room
|
|
14
|
+
*/
|
|
15
|
+
readonly leaveRoom: (roomId: string) => void;
|
|
16
|
+
/**
|
|
17
|
+
* The room currently synced to your zustand state.
|
|
18
|
+
*/
|
|
19
|
+
readonly room: Room<TPresence, TStorage, TUserMeta, TRoomEvent> | null;
|
|
20
|
+
/**
|
|
21
|
+
* Other users in the room. Empty no room is currently synced
|
|
22
|
+
*/
|
|
23
|
+
readonly others: readonly User<TPresence, TUserMeta>[];
|
|
24
|
+
/**
|
|
25
|
+
* Whether or not the room storage is currently loading
|
|
26
|
+
*/
|
|
27
|
+
readonly isStorageLoading: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Legacy connection status of the room.
|
|
30
|
+
*
|
|
31
|
+
* @deprecated This API will be removed in a future version of Liveblocks.
|
|
32
|
+
* Prefer using the newer `.status` property.
|
|
33
|
+
*
|
|
34
|
+
* We recommend making the following changes if you use these APIs:
|
|
35
|
+
*
|
|
36
|
+
* OLD STATUSES NEW STATUSES
|
|
37
|
+
* closed --> initial
|
|
38
|
+
* authenticating --> connecting
|
|
39
|
+
* connecting --> connecting
|
|
40
|
+
* open --> connected
|
|
41
|
+
* unavailable --> reconnecting
|
|
42
|
+
* failed --> disconnected
|
|
43
|
+
*/
|
|
44
|
+
readonly connection: LegacyConnectionStatus;
|
|
45
|
+
/**
|
|
46
|
+
* Connection status of the room.
|
|
47
|
+
*/
|
|
48
|
+
readonly status: Status;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* @deprecated Renamed to WithLiveblocks<...>
|
|
52
|
+
*/
|
|
53
|
+
declare type LiveblocksState<TState, TPresence extends JsonObject = JsonObject, TStorage extends LsonObject = LsonObject, TUserMeta extends BaseUserMeta = BaseUserMeta, TRoomEvent extends Json = Json> = WithLiveblocks<TState, TPresence, TStorage, TUserMeta, TRoomEvent>;
|
|
54
|
+
/**
|
|
55
|
+
* Adds the `liveblocks` property to your custom Zustand state.
|
|
56
|
+
*/
|
|
57
|
+
declare type WithLiveblocks<TState, TPresence extends JsonObject = JsonObject, TStorage extends LsonObject = LsonObject, TUserMeta extends BaseUserMeta = BaseUserMeta, TRoomEvent extends Json = Json> = TState & {
|
|
58
|
+
readonly liveblocks: LiveblocksContext<TPresence, TStorage, TUserMeta, TRoomEvent>;
|
|
59
|
+
};
|
|
60
|
+
declare type Mapping<T> = {
|
|
61
|
+
[K in keyof T]?: boolean;
|
|
62
|
+
};
|
|
63
|
+
declare type Options<T> = {
|
|
64
|
+
/**
|
|
65
|
+
* Liveblocks client created by @liveblocks/client createClient
|
|
66
|
+
*/
|
|
67
|
+
client: Client;
|
|
68
|
+
/**
|
|
69
|
+
* Mapping used to synchronize a part of your zustand state with one Liveblocks Room storage.
|
|
70
|
+
*/
|
|
71
|
+
storageMapping?: Mapping<T>;
|
|
72
|
+
/**
|
|
73
|
+
* Mapping used to synchronize a part of your zustand state with one Liveblocks Room presence.
|
|
74
|
+
*/
|
|
75
|
+
presenceMapping?: Mapping<T>;
|
|
76
|
+
};
|
|
77
|
+
declare type OuterLiveblocksMiddleware = <TState, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(config: StateCreator<TState, Mps, Mcs, Omit<TState, "liveblocks">>, options: Options<Omit<TState, "liveblocks">>) => StateCreator<TState, Mps, Mcs, TState>;
|
|
78
|
+
declare const liveblocks: OuterLiveblocksMiddleware;
|
|
79
|
+
/**
|
|
80
|
+
* @deprecated Renamed to `liveblocks`.
|
|
81
|
+
*/
|
|
82
|
+
declare const middleware: OuterLiveblocksMiddleware;
|
|
83
|
+
|
|
84
|
+
export { LiveblocksContext, LiveblocksState, Mapping, WithLiveblocks, liveblocks, middleware };
|
package/dist/index.js
CHANGED
|
@@ -1,36 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
-
var __defProps = Object.defineProperties;
|
|
3
|
-
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
-
var __spreadValues = (a, b) => {
|
|
9
|
-
for (var prop in b || (b = {}))
|
|
10
|
-
if (__hasOwnProp.call(b, prop))
|
|
11
|
-
__defNormalProp(a, prop, b[prop]);
|
|
12
|
-
if (__getOwnPropSymbols)
|
|
13
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
-
if (__propIsEnum.call(b, prop))
|
|
15
|
-
__defNormalProp(a, prop, b[prop]);
|
|
16
|
-
}
|
|
17
|
-
return a;
|
|
18
|
-
};
|
|
19
|
-
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
-
var __objRest = (source, exclude) => {
|
|
21
|
-
var target = {};
|
|
22
|
-
for (var prop in source)
|
|
23
|
-
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
-
target[prop] = source[prop];
|
|
25
|
-
if (source != null && __getOwnPropSymbols)
|
|
26
|
-
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
-
target[prop] = source[prop];
|
|
29
|
-
}
|
|
30
|
-
return target;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// src/index.ts
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/index.ts
|
|
34
2
|
|
|
35
3
|
|
|
36
4
|
|
|
@@ -139,9 +107,9 @@ var middlewareImpl = (config, options) => {
|
|
|
139
107
|
}
|
|
140
108
|
const store = config(
|
|
141
109
|
(args) => {
|
|
142
|
-
const
|
|
110
|
+
const { liveblocks: _, ...oldState } = get();
|
|
143
111
|
set(args);
|
|
144
|
-
const
|
|
112
|
+
const { liveblocks: __, ...newState } = get();
|
|
145
113
|
if (maybeRoom) {
|
|
146
114
|
const room = maybeRoom;
|
|
147
115
|
isPatching = true;
|
|
@@ -162,7 +130,8 @@ var middlewareImpl = (config, options) => {
|
|
|
162
130
|
get,
|
|
163
131
|
api
|
|
164
132
|
);
|
|
165
|
-
return
|
|
133
|
+
return {
|
|
134
|
+
...store,
|
|
166
135
|
liveblocks: {
|
|
167
136
|
enterRoom,
|
|
168
137
|
leaveRoom,
|
|
@@ -171,7 +140,7 @@ var middlewareImpl = (config, options) => {
|
|
|
171
140
|
connection: "closed",
|
|
172
141
|
isStorageLoading: false
|
|
173
142
|
}
|
|
174
|
-
}
|
|
143
|
+
};
|
|
175
144
|
};
|
|
176
145
|
};
|
|
177
146
|
var liveblocks = middlewareImpl;
|
|
@@ -196,7 +165,7 @@ function selectFields(presence, mapping) {
|
|
|
196
165
|
return partialState;
|
|
197
166
|
}
|
|
198
167
|
function updateLiveblocksContext(set, partial) {
|
|
199
|
-
set((state) => ({ liveblocks:
|
|
168
|
+
set((state) => ({ liveblocks: { ...state.liveblocks, ...partial } }));
|
|
200
169
|
}
|
|
201
170
|
function updatePresence(room, oldState, newState, presenceMapping) {
|
|
202
171
|
for (const key in presenceMapping) {
|
|
@@ -204,7 +173,7 @@ function updatePresence(room, oldState, newState, presenceMapping) {
|
|
|
204
173
|
throw mappingToFunctionIsNotAllowed(key);
|
|
205
174
|
}
|
|
206
175
|
if (oldState[key] !== newState[key]) {
|
|
207
|
-
const val = newState
|
|
176
|
+
const val = _optionalChain([newState, 'optionalAccess', _2 => _2[key]]);
|
|
208
177
|
const patch = {};
|
|
209
178
|
patch[key] = val;
|
|
210
179
|
room.updatePresence(patch);
|
|
@@ -253,15 +222,14 @@ function validateMapping(mapping, mappingType) {
|
|
|
253
222
|
return result;
|
|
254
223
|
}
|
|
255
224
|
function validateOptions(options) {
|
|
256
|
-
var _a, _b;
|
|
257
225
|
const client = options.client;
|
|
258
226
|
_core.errorIf.call(void 0, !client, `${ERROR_PREFIX} client is missing`);
|
|
259
227
|
const storageMapping = validateMapping(
|
|
260
|
-
(
|
|
228
|
+
_nullishCoalesce(options.storageMapping, () => ( {})),
|
|
261
229
|
"storageMapping"
|
|
262
230
|
);
|
|
263
231
|
const presenceMapping = validateMapping(
|
|
264
|
-
(
|
|
232
|
+
_nullishCoalesce(options.presenceMapping, () => ( {})),
|
|
265
233
|
"presenceMapping"
|
|
266
234
|
);
|
|
267
235
|
if (process.env.NODE_ENV !== "production") {
|
|
@@ -273,3 +241,4 @@ function validateOptions(options) {
|
|
|
273
241
|
|
|
274
242
|
|
|
275
243
|
exports.liveblocks = liveblocks; exports.middleware = middleware;
|
|
244
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["updates"],"mappings":"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","sourcesContent":["import type {\n BaseUserMeta,\n Client,\n Json,\n JsonObject,\n LiveObject,\n LsonObject,\n Room,\n Status,\n User,\n} from \"@liveblocks/client\";\nimport type { LegacyConnectionStatus, StorageUpdate } from \"@liveblocks/core\";\nimport {\n errorIf,\n legacy_patchImmutableObject,\n lsonToJson,\n patchLiveObjectKey,\n} from \"@liveblocks/core\";\nimport type { StateCreator, StoreMutatorIdentifier } from \"zustand\";\n\nconst ERROR_PREFIX = \"Invalid @liveblocks/zustand middleware config.\";\n\nfunction mappingToFunctionIsNotAllowed(key: string): Error {\n return new Error(\n `${ERROR_PREFIX} mapping.${key} is invalid. Mapping to a function is not allowed.`\n );\n}\n\nexport type LiveblocksContext<\n TPresence extends JsonObject,\n TStorage extends LsonObject,\n TUserMeta extends BaseUserMeta,\n TRoomEvent extends Json,\n> = {\n /**\n * Enters a room and starts sync it with zustand state\n * @param roomId The id of the room\n */\n readonly enterRoom: (roomId: string) => void;\n /**\n * Leaves a room and stops sync it with zustand state.\n * @param roomId The id of the room\n */\n readonly leaveRoom: (roomId: string) => void;\n /**\n * The room currently synced to your zustand state.\n */\n readonly room: Room<TPresence, TStorage, TUserMeta, TRoomEvent> | null;\n /**\n * Other users in the room. Empty no room is currently synced\n */\n readonly others: readonly User<TPresence, TUserMeta>[];\n /**\n * Whether or not the room storage is currently loading\n */\n readonly isStorageLoading: boolean;\n /**\n * Legacy connection status of the room.\n *\n * @deprecated This API will be removed in a future version of Liveblocks.\n * Prefer using the newer `.status` property.\n *\n * We recommend making the following changes if you use these APIs:\n *\n * OLD STATUSES NEW STATUSES\n * closed --> initial\n * authenticating --> connecting\n * connecting --> connecting\n * open --> connected\n * unavailable --> reconnecting\n * failed --> disconnected\n */\n readonly connection: LegacyConnectionStatus;\n /**\n * Connection status of the room.\n */\n readonly status: Status;\n};\n\n/**\n * @deprecated Renamed to WithLiveblocks<...>\n */\nexport type LiveblocksState<\n TState,\n TPresence extends JsonObject = JsonObject,\n TStorage extends LsonObject = LsonObject,\n TUserMeta extends BaseUserMeta = BaseUserMeta,\n TRoomEvent extends Json = Json,\n> = WithLiveblocks<TState, TPresence, TStorage, TUserMeta, TRoomEvent>;\n\n/**\n * Adds the `liveblocks` property to your custom Zustand state.\n */\nexport type WithLiveblocks<\n TState,\n TPresence extends JsonObject = JsonObject,\n TStorage extends LsonObject = LsonObject,\n TUserMeta extends BaseUserMeta = BaseUserMeta,\n TRoomEvent extends Json = Json,\n> = TState & {\n readonly liveblocks: LiveblocksContext<\n TPresence,\n TStorage,\n TUserMeta,\n TRoomEvent\n >;\n};\n\nexport type Mapping<T> = {\n [K in keyof T]?: boolean;\n};\n\ntype Options<T> = {\n /**\n * Liveblocks client created by @liveblocks/client createClient\n */\n client: Client;\n /**\n * Mapping used to synchronize a part of your zustand state with one Liveblocks Room storage.\n */\n storageMapping?: Mapping<T>;\n /**\n * Mapping used to synchronize a part of your zustand state with one Liveblocks Room presence.\n */\n presenceMapping?: Mapping<T>;\n};\n\ntype OuterLiveblocksMiddleware = <\n TState,\n Mps extends [StoreMutatorIdentifier, unknown][] = [],\n Mcs extends [StoreMutatorIdentifier, unknown][] = [],\n>(\n config: StateCreator<TState, Mps, Mcs, Omit<TState, \"liveblocks\">>,\n options: Options<Omit<TState, \"liveblocks\">>\n) => StateCreator<TState, Mps, Mcs, TState>;\n\ntype InnerLiveblocksMiddleware = <\n TState extends {\n readonly liveblocks: LiveblocksContext<\n JsonObject,\n LsonObject,\n BaseUserMeta,\n Json\n >;\n },\n>(\n config: StateCreator<TState, [], []>,\n options: Options<TState>\n) => StateCreator<TState, [], []>;\n\ntype ExtractPresence<\n TRoom extends Room<JsonObject, LsonObject, BaseUserMeta, Json>,\n> = TRoom extends Room<infer P, any, any, any> ? P : never;\n\ntype ExtractStorage<\n TRoom extends Room<JsonObject, LsonObject, BaseUserMeta, Json>,\n> = TRoom extends Room<any, infer S, any, any> ? S : never;\n\nconst middlewareImpl: InnerLiveblocksMiddleware = (config, options) => {\n type TState = ReturnType<typeof config>;\n type TLiveblocksContext = TState[\"liveblocks\"];\n type TRoom = NonNullable<TLiveblocksContext[\"room\"]>;\n type TPresence = ExtractPresence<TRoom>;\n type TStorage = ExtractStorage<TRoom>;\n\n const { client, presenceMapping, storageMapping } = validateOptions(options);\n return (set, get, api) => {\n let maybeRoom: TRoom | null = null;\n let isPatching: boolean = false;\n let storageRoot: LiveObject<TStorage> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n\n function enterRoom(roomId: string) {\n if (storageRoot) {\n return;\n }\n\n const initialPresence = selectFields(\n get(),\n presenceMapping\n ) as unknown as TPresence;\n\n const room = client.enter(roomId, {\n initialPresence,\n }) as unknown as TRoom;\n maybeRoom = room;\n\n updateLiveblocksContext(set, { isStorageLoading: true, room });\n\n unsubscribeCallbacks.push(\n room.events.others.subscribe(({ others }) => {\n updateLiveblocksContext(set, { others });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.connection.subscribe(() => {\n updateLiveblocksContext(set, {\n connection: room.getConnectionState(),\n status: room.getStatus(),\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.me.subscribe(() => {\n if (isPatching === false) {\n set(\n selectFields(\n room.getPresence(),\n presenceMapping\n ) as Partial<TState>\n );\n }\n })\n );\n\n void room.getStorage().then(({ root }) => {\n const updates = {} as Partial<TState>;\n\n room.batch(() => {\n for (const key in storageMapping) {\n const liveblocksStatePart = root.get(key);\n if (liveblocksStatePart === undefined) {\n updates[key] = get()[key];\n patchLiveObjectKey(root, key, undefined, get()[key]);\n } else {\n updates[key] = lsonToJson(\n liveblocksStatePart\n ) as unknown as TState[Extract<keyof TState, string>];\n }\n }\n });\n\n set(updates);\n\n storageRoot = root as LiveObject<TStorage>;\n unsubscribeCallbacks.push(\n room.subscribe(\n root,\n (updates) => {\n if (isPatching === false) {\n set(patchState(get(), updates, storageMapping));\n }\n },\n { isDeep: true }\n )\n );\n\n // set isLoading storage to false once storage is loaded\n updateLiveblocksContext(set, {\n isStorageLoading: false,\n });\n });\n }\n\n function leaveRoom(roomId: string) {\n for (const unsubscribe of unsubscribeCallbacks) {\n unsubscribe();\n }\n storageRoot = null;\n maybeRoom = null;\n isPatching = false;\n unsubscribeCallbacks = [];\n client.leave(roomId);\n updateLiveblocksContext(set, {\n others: [],\n connection: \"closed\",\n isStorageLoading: false,\n room: null,\n });\n }\n\n const store = config(\n (args) => {\n const { liveblocks: _, ...oldState } = get();\n set(args);\n const { liveblocks: __, ...newState } = get();\n\n if (maybeRoom) {\n const room = maybeRoom;\n isPatching = true;\n updatePresence(room, oldState, newState, presenceMapping);\n\n room.batch(() => {\n if (storageRoot) {\n patchLiveblocksStorage(\n storageRoot,\n oldState,\n newState,\n storageMapping\n );\n }\n });\n\n isPatching = false;\n }\n },\n get,\n api\n );\n\n return {\n ...store,\n liveblocks: {\n enterRoom,\n leaveRoom,\n room: null,\n others: [],\n connection: \"closed\",\n isStorageLoading: false,\n },\n };\n };\n};\n\nexport const liveblocks =\n middlewareImpl as unknown as OuterLiveblocksMiddleware;\n\n/**\n * @deprecated Renamed to `liveblocks`.\n */\nexport const middleware = liveblocks;\n\nfunction patchState<T>(\n state: T,\n updates: StorageUpdate[],\n mapping: Mapping<T>\n) {\n const partialState: Partial<T> = {};\n\n for (const key in mapping) {\n partialState[key] = state[key];\n }\n\n const patched = legacy_patchImmutableObject(partialState, updates);\n\n const result: Partial<T> = {};\n\n for (const key in mapping) {\n result[key] = patched[key];\n }\n\n return result;\n}\n\nfunction selectFields<TState>(\n presence: TState,\n mapping: Mapping<TState>\n): /* TODO: Actually, Pick<TState, keyof Mapping<TState>> ? */\nPartial<TState> {\n const partialState = {} as Partial<TState>;\n for (const key in mapping) {\n partialState[key] = presence[key];\n }\n return partialState;\n}\n\nfunction updateLiveblocksContext<\n TState,\n TPresence extends JsonObject,\n TStorage extends LsonObject,\n TUserMeta extends BaseUserMeta,\n TRoomEvent extends Json,\n>(\n set: (\n callbackOrPartial: (\n current: WithLiveblocks<\n TState,\n TPresence,\n TStorage,\n TUserMeta,\n TRoomEvent\n >\n ) =>\n | WithLiveblocks<TState, TPresence, TStorage, TUserMeta, TRoomEvent>\n | Partial<any>\n ) => void,\n partial: Partial<\n LiveblocksContext<TPresence, TStorage, TUserMeta, TRoomEvent>\n >\n) {\n set((state) => ({ liveblocks: { ...state.liveblocks, ...partial } }));\n}\n\nfunction updatePresence<\n TPresence extends JsonObject,\n TStorage extends LsonObject,\n TUserMeta extends BaseUserMeta,\n TRoomEvent extends Json,\n>(\n room: Room<TPresence, TStorage, TUserMeta, TRoomEvent>,\n oldState: TPresence,\n newState: TPresence,\n presenceMapping: Mapping<TPresence>\n) {\n for (const key in presenceMapping) {\n if (typeof newState[key] === \"function\") {\n throw mappingToFunctionIsNotAllowed(key);\n }\n\n if (oldState[key] !== newState[key]) {\n const val = newState?.[key];\n const patch = {} as Partial<TPresence>;\n patch[key] = val;\n room.updatePresence(patch);\n }\n }\n}\n\nfunction patchLiveblocksStorage<O extends LsonObject, TState>(\n root: LiveObject<O>,\n oldState: TState,\n newState: TState,\n mapping: Mapping<TState>\n) {\n for (const key in mapping) {\n if (\n process.env.NODE_ENV !== \"production\" &&\n typeof newState[key] === \"function\"\n ) {\n throw mappingToFunctionIsNotAllowed(key);\n }\n\n if (oldState[key] !== newState[key]) {\n const oldVal = oldState[key];\n const newVal = newState[key];\n patchLiveObjectKey(root, key, oldVal, newVal);\n }\n }\n}\n\nfunction isObject(value: unknown): value is object {\n return Object.prototype.toString.call(value) === \"[object Object]\";\n}\n\nfunction validateNoDuplicateKeys<T>(\n storageMapping: Mapping<T>,\n presenceMapping: Mapping<T>\n) {\n for (const key in storageMapping) {\n if (presenceMapping[key] !== undefined) {\n throw new Error(\n `${ERROR_PREFIX} \"${key}\" is mapped on both presenceMapping and storageMapping. A key shouldn't exist on both mapping.`\n );\n }\n }\n}\n\n/**\n * Remove false keys from mapping and generate to a new object to avoid potential mutation from outside the middleware\n */\nfunction validateMapping<T>(\n mapping: Mapping<T>,\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Mapping<T> {\n errorIf(\n !isObject(mapping),\n `${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`\n );\n\n const result: Mapping<T> = {};\n for (const key in mapping) {\n errorIf(\n typeof mapping[key] !== \"boolean\",\n `${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`\n );\n\n if (mapping[key] === true) {\n result[key] = true;\n }\n }\n return result;\n}\n\nfunction validateOptions<TState>(options: Options<TState>): {\n client: Client;\n presenceMapping: Mapping<TState>;\n storageMapping: Mapping<TState>;\n} {\n const client = options.client;\n errorIf(!client, `${ERROR_PREFIX} client is missing`);\n\n const storageMapping = validateMapping(\n options.storageMapping ?? {},\n \"storageMapping\"\n );\n\n const presenceMapping = validateMapping(\n options.presenceMapping ?? {},\n \"presenceMapping\"\n );\n\n if (process.env.NODE_ENV !== \"production\") {\n validateNoDuplicateKeys(storageMapping, presenceMapping);\n }\n\n return { client, storageMapping, presenceMapping };\n}\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
errorIf,
|
|
4
|
+
legacy_patchImmutableObject,
|
|
5
|
+
lsonToJson,
|
|
6
|
+
patchLiveObjectKey
|
|
7
|
+
} from "@liveblocks/core";
|
|
8
|
+
var ERROR_PREFIX = "Invalid @liveblocks/zustand middleware config.";
|
|
9
|
+
function mappingToFunctionIsNotAllowed(key) {
|
|
10
|
+
return new Error(
|
|
11
|
+
`${ERROR_PREFIX} mapping.${key} is invalid. Mapping to a function is not allowed.`
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
var middlewareImpl = (config, options) => {
|
|
15
|
+
const { client, presenceMapping, storageMapping } = validateOptions(options);
|
|
16
|
+
return (set, get, api) => {
|
|
17
|
+
let maybeRoom = null;
|
|
18
|
+
let isPatching = false;
|
|
19
|
+
let storageRoot = null;
|
|
20
|
+
let unsubscribeCallbacks = [];
|
|
21
|
+
function enterRoom(roomId) {
|
|
22
|
+
if (storageRoot) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const initialPresence = selectFields(
|
|
26
|
+
get(),
|
|
27
|
+
presenceMapping
|
|
28
|
+
);
|
|
29
|
+
const room = client.enter(roomId, {
|
|
30
|
+
initialPresence
|
|
31
|
+
});
|
|
32
|
+
maybeRoom = room;
|
|
33
|
+
updateLiveblocksContext(set, { isStorageLoading: true, room });
|
|
34
|
+
unsubscribeCallbacks.push(
|
|
35
|
+
room.events.others.subscribe(({ others }) => {
|
|
36
|
+
updateLiveblocksContext(set, { others });
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
unsubscribeCallbacks.push(
|
|
40
|
+
room.events.connection.subscribe(() => {
|
|
41
|
+
updateLiveblocksContext(set, {
|
|
42
|
+
connection: room.getConnectionState(),
|
|
43
|
+
status: room.getStatus()
|
|
44
|
+
});
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
unsubscribeCallbacks.push(
|
|
48
|
+
room.events.me.subscribe(() => {
|
|
49
|
+
if (isPatching === false) {
|
|
50
|
+
set(
|
|
51
|
+
selectFields(
|
|
52
|
+
room.getPresence(),
|
|
53
|
+
presenceMapping
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
void room.getStorage().then(({ root }) => {
|
|
60
|
+
const updates = {};
|
|
61
|
+
room.batch(() => {
|
|
62
|
+
for (const key in storageMapping) {
|
|
63
|
+
const liveblocksStatePart = root.get(key);
|
|
64
|
+
if (liveblocksStatePart === void 0) {
|
|
65
|
+
updates[key] = get()[key];
|
|
66
|
+
patchLiveObjectKey(root, key, void 0, get()[key]);
|
|
67
|
+
} else {
|
|
68
|
+
updates[key] = lsonToJson(
|
|
69
|
+
liveblocksStatePart
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
set(updates);
|
|
75
|
+
storageRoot = root;
|
|
76
|
+
unsubscribeCallbacks.push(
|
|
77
|
+
room.subscribe(
|
|
78
|
+
root,
|
|
79
|
+
(updates2) => {
|
|
80
|
+
if (isPatching === false) {
|
|
81
|
+
set(patchState(get(), updates2, storageMapping));
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{ isDeep: true }
|
|
85
|
+
)
|
|
86
|
+
);
|
|
87
|
+
updateLiveblocksContext(set, {
|
|
88
|
+
isStorageLoading: false
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function leaveRoom(roomId) {
|
|
93
|
+
for (const unsubscribe of unsubscribeCallbacks) {
|
|
94
|
+
unsubscribe();
|
|
95
|
+
}
|
|
96
|
+
storageRoot = null;
|
|
97
|
+
maybeRoom = null;
|
|
98
|
+
isPatching = false;
|
|
99
|
+
unsubscribeCallbacks = [];
|
|
100
|
+
client.leave(roomId);
|
|
101
|
+
updateLiveblocksContext(set, {
|
|
102
|
+
others: [],
|
|
103
|
+
connection: "closed",
|
|
104
|
+
isStorageLoading: false,
|
|
105
|
+
room: null
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
const store = config(
|
|
109
|
+
(args) => {
|
|
110
|
+
const { liveblocks: _, ...oldState } = get();
|
|
111
|
+
set(args);
|
|
112
|
+
const { liveblocks: __, ...newState } = get();
|
|
113
|
+
if (maybeRoom) {
|
|
114
|
+
const room = maybeRoom;
|
|
115
|
+
isPatching = true;
|
|
116
|
+
updatePresence(room, oldState, newState, presenceMapping);
|
|
117
|
+
room.batch(() => {
|
|
118
|
+
if (storageRoot) {
|
|
119
|
+
patchLiveblocksStorage(
|
|
120
|
+
storageRoot,
|
|
121
|
+
oldState,
|
|
122
|
+
newState,
|
|
123
|
+
storageMapping
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
isPatching = false;
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
get,
|
|
131
|
+
api
|
|
132
|
+
);
|
|
133
|
+
return {
|
|
134
|
+
...store,
|
|
135
|
+
liveblocks: {
|
|
136
|
+
enterRoom,
|
|
137
|
+
leaveRoom,
|
|
138
|
+
room: null,
|
|
139
|
+
others: [],
|
|
140
|
+
connection: "closed",
|
|
141
|
+
isStorageLoading: false
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
var liveblocks = middlewareImpl;
|
|
147
|
+
var middleware = liveblocks;
|
|
148
|
+
function patchState(state, updates, mapping) {
|
|
149
|
+
const partialState = {};
|
|
150
|
+
for (const key in mapping) {
|
|
151
|
+
partialState[key] = state[key];
|
|
152
|
+
}
|
|
153
|
+
const patched = legacy_patchImmutableObject(partialState, updates);
|
|
154
|
+
const result = {};
|
|
155
|
+
for (const key in mapping) {
|
|
156
|
+
result[key] = patched[key];
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
function selectFields(presence, mapping) {
|
|
161
|
+
const partialState = {};
|
|
162
|
+
for (const key in mapping) {
|
|
163
|
+
partialState[key] = presence[key];
|
|
164
|
+
}
|
|
165
|
+
return partialState;
|
|
166
|
+
}
|
|
167
|
+
function updateLiveblocksContext(set, partial) {
|
|
168
|
+
set((state) => ({ liveblocks: { ...state.liveblocks, ...partial } }));
|
|
169
|
+
}
|
|
170
|
+
function updatePresence(room, oldState, newState, presenceMapping) {
|
|
171
|
+
for (const key in presenceMapping) {
|
|
172
|
+
if (typeof newState[key] === "function") {
|
|
173
|
+
throw mappingToFunctionIsNotAllowed(key);
|
|
174
|
+
}
|
|
175
|
+
if (oldState[key] !== newState[key]) {
|
|
176
|
+
const val = newState?.[key];
|
|
177
|
+
const patch = {};
|
|
178
|
+
patch[key] = val;
|
|
179
|
+
room.updatePresence(patch);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function patchLiveblocksStorage(root, oldState, newState, mapping) {
|
|
184
|
+
for (const key in mapping) {
|
|
185
|
+
if (process.env.NODE_ENV !== "production" && typeof newState[key] === "function") {
|
|
186
|
+
throw mappingToFunctionIsNotAllowed(key);
|
|
187
|
+
}
|
|
188
|
+
if (oldState[key] !== newState[key]) {
|
|
189
|
+
const oldVal = oldState[key];
|
|
190
|
+
const newVal = newState[key];
|
|
191
|
+
patchLiveObjectKey(root, key, oldVal, newVal);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function isObject(value) {
|
|
196
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
197
|
+
}
|
|
198
|
+
function validateNoDuplicateKeys(storageMapping, presenceMapping) {
|
|
199
|
+
for (const key in storageMapping) {
|
|
200
|
+
if (presenceMapping[key] !== void 0) {
|
|
201
|
+
throw new Error(
|
|
202
|
+
`${ERROR_PREFIX} "${key}" is mapped on both presenceMapping and storageMapping. A key shouldn't exist on both mapping.`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function validateMapping(mapping, mappingType) {
|
|
208
|
+
errorIf(
|
|
209
|
+
!isObject(mapping),
|
|
210
|
+
`${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`
|
|
211
|
+
);
|
|
212
|
+
const result = {};
|
|
213
|
+
for (const key in mapping) {
|
|
214
|
+
errorIf(
|
|
215
|
+
typeof mapping[key] !== "boolean",
|
|
216
|
+
`${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`
|
|
217
|
+
);
|
|
218
|
+
if (mapping[key] === true) {
|
|
219
|
+
result[key] = true;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
function validateOptions(options) {
|
|
225
|
+
const client = options.client;
|
|
226
|
+
errorIf(!client, `${ERROR_PREFIX} client is missing`);
|
|
227
|
+
const storageMapping = validateMapping(
|
|
228
|
+
options.storageMapping ?? {},
|
|
229
|
+
"storageMapping"
|
|
230
|
+
);
|
|
231
|
+
const presenceMapping = validateMapping(
|
|
232
|
+
options.presenceMapping ?? {},
|
|
233
|
+
"presenceMapping"
|
|
234
|
+
);
|
|
235
|
+
if (process.env.NODE_ENV !== "production") {
|
|
236
|
+
validateNoDuplicateKeys(storageMapping, presenceMapping);
|
|
237
|
+
}
|
|
238
|
+
return { client, storageMapping, presenceMapping };
|
|
239
|
+
}
|
|
240
|
+
export {
|
|
241
|
+
liveblocks,
|
|
242
|
+
middleware
|
|
243
|
+
};
|
|
244
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n BaseUserMeta,\n Client,\n Json,\n JsonObject,\n LiveObject,\n LsonObject,\n Room,\n Status,\n User,\n} from \"@liveblocks/client\";\nimport type { LegacyConnectionStatus, StorageUpdate } from \"@liveblocks/core\";\nimport {\n errorIf,\n legacy_patchImmutableObject,\n lsonToJson,\n patchLiveObjectKey,\n} from \"@liveblocks/core\";\nimport type { StateCreator, StoreMutatorIdentifier } from \"zustand\";\n\nconst ERROR_PREFIX = \"Invalid @liveblocks/zustand middleware config.\";\n\nfunction mappingToFunctionIsNotAllowed(key: string): Error {\n return new Error(\n `${ERROR_PREFIX} mapping.${key} is invalid. Mapping to a function is not allowed.`\n );\n}\n\nexport type LiveblocksContext<\n TPresence extends JsonObject,\n TStorage extends LsonObject,\n TUserMeta extends BaseUserMeta,\n TRoomEvent extends Json,\n> = {\n /**\n * Enters a room and starts sync it with zustand state\n * @param roomId The id of the room\n */\n readonly enterRoom: (roomId: string) => void;\n /**\n * Leaves a room and stops sync it with zustand state.\n * @param roomId The id of the room\n */\n readonly leaveRoom: (roomId: string) => void;\n /**\n * The room currently synced to your zustand state.\n */\n readonly room: Room<TPresence, TStorage, TUserMeta, TRoomEvent> | null;\n /**\n * Other users in the room. Empty no room is currently synced\n */\n readonly others: readonly User<TPresence, TUserMeta>[];\n /**\n * Whether or not the room storage is currently loading\n */\n readonly isStorageLoading: boolean;\n /**\n * Legacy connection status of the room.\n *\n * @deprecated This API will be removed in a future version of Liveblocks.\n * Prefer using the newer `.status` property.\n *\n * We recommend making the following changes if you use these APIs:\n *\n * OLD STATUSES NEW STATUSES\n * closed --> initial\n * authenticating --> connecting\n * connecting --> connecting\n * open --> connected\n * unavailable --> reconnecting\n * failed --> disconnected\n */\n readonly connection: LegacyConnectionStatus;\n /**\n * Connection status of the room.\n */\n readonly status: Status;\n};\n\n/**\n * @deprecated Renamed to WithLiveblocks<...>\n */\nexport type LiveblocksState<\n TState,\n TPresence extends JsonObject = JsonObject,\n TStorage extends LsonObject = LsonObject,\n TUserMeta extends BaseUserMeta = BaseUserMeta,\n TRoomEvent extends Json = Json,\n> = WithLiveblocks<TState, TPresence, TStorage, TUserMeta, TRoomEvent>;\n\n/**\n * Adds the `liveblocks` property to your custom Zustand state.\n */\nexport type WithLiveblocks<\n TState,\n TPresence extends JsonObject = JsonObject,\n TStorage extends LsonObject = LsonObject,\n TUserMeta extends BaseUserMeta = BaseUserMeta,\n TRoomEvent extends Json = Json,\n> = TState & {\n readonly liveblocks: LiveblocksContext<\n TPresence,\n TStorage,\n TUserMeta,\n TRoomEvent\n >;\n};\n\nexport type Mapping<T> = {\n [K in keyof T]?: boolean;\n};\n\ntype Options<T> = {\n /**\n * Liveblocks client created by @liveblocks/client createClient\n */\n client: Client;\n /**\n * Mapping used to synchronize a part of your zustand state with one Liveblocks Room storage.\n */\n storageMapping?: Mapping<T>;\n /**\n * Mapping used to synchronize a part of your zustand state with one Liveblocks Room presence.\n */\n presenceMapping?: Mapping<T>;\n};\n\ntype OuterLiveblocksMiddleware = <\n TState,\n Mps extends [StoreMutatorIdentifier, unknown][] = [],\n Mcs extends [StoreMutatorIdentifier, unknown][] = [],\n>(\n config: StateCreator<TState, Mps, Mcs, Omit<TState, \"liveblocks\">>,\n options: Options<Omit<TState, \"liveblocks\">>\n) => StateCreator<TState, Mps, Mcs, TState>;\n\ntype InnerLiveblocksMiddleware = <\n TState extends {\n readonly liveblocks: LiveblocksContext<\n JsonObject,\n LsonObject,\n BaseUserMeta,\n Json\n >;\n },\n>(\n config: StateCreator<TState, [], []>,\n options: Options<TState>\n) => StateCreator<TState, [], []>;\n\ntype ExtractPresence<\n TRoom extends Room<JsonObject, LsonObject, BaseUserMeta, Json>,\n> = TRoom extends Room<infer P, any, any, any> ? P : never;\n\ntype ExtractStorage<\n TRoom extends Room<JsonObject, LsonObject, BaseUserMeta, Json>,\n> = TRoom extends Room<any, infer S, any, any> ? S : never;\n\nconst middlewareImpl: InnerLiveblocksMiddleware = (config, options) => {\n type TState = ReturnType<typeof config>;\n type TLiveblocksContext = TState[\"liveblocks\"];\n type TRoom = NonNullable<TLiveblocksContext[\"room\"]>;\n type TPresence = ExtractPresence<TRoom>;\n type TStorage = ExtractStorage<TRoom>;\n\n const { client, presenceMapping, storageMapping } = validateOptions(options);\n return (set, get, api) => {\n let maybeRoom: TRoom | null = null;\n let isPatching: boolean = false;\n let storageRoot: LiveObject<TStorage> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n\n function enterRoom(roomId: string) {\n if (storageRoot) {\n return;\n }\n\n const initialPresence = selectFields(\n get(),\n presenceMapping\n ) as unknown as TPresence;\n\n const room = client.enter(roomId, {\n initialPresence,\n }) as unknown as TRoom;\n maybeRoom = room;\n\n updateLiveblocksContext(set, { isStorageLoading: true, room });\n\n unsubscribeCallbacks.push(\n room.events.others.subscribe(({ others }) => {\n updateLiveblocksContext(set, { others });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.connection.subscribe(() => {\n updateLiveblocksContext(set, {\n connection: room.getConnectionState(),\n status: room.getStatus(),\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.me.subscribe(() => {\n if (isPatching === false) {\n set(\n selectFields(\n room.getPresence(),\n presenceMapping\n ) as Partial<TState>\n );\n }\n })\n );\n\n void room.getStorage().then(({ root }) => {\n const updates = {} as Partial<TState>;\n\n room.batch(() => {\n for (const key in storageMapping) {\n const liveblocksStatePart = root.get(key);\n if (liveblocksStatePart === undefined) {\n updates[key] = get()[key];\n patchLiveObjectKey(root, key, undefined, get()[key]);\n } else {\n updates[key] = lsonToJson(\n liveblocksStatePart\n ) as unknown as TState[Extract<keyof TState, string>];\n }\n }\n });\n\n set(updates);\n\n storageRoot = root as LiveObject<TStorage>;\n unsubscribeCallbacks.push(\n room.subscribe(\n root,\n (updates) => {\n if (isPatching === false) {\n set(patchState(get(), updates, storageMapping));\n }\n },\n { isDeep: true }\n )\n );\n\n // set isLoading storage to false once storage is loaded\n updateLiveblocksContext(set, {\n isStorageLoading: false,\n });\n });\n }\n\n function leaveRoom(roomId: string) {\n for (const unsubscribe of unsubscribeCallbacks) {\n unsubscribe();\n }\n storageRoot = null;\n maybeRoom = null;\n isPatching = false;\n unsubscribeCallbacks = [];\n client.leave(roomId);\n updateLiveblocksContext(set, {\n others: [],\n connection: \"closed\",\n isStorageLoading: false,\n room: null,\n });\n }\n\n const store = config(\n (args) => {\n const { liveblocks: _, ...oldState } = get();\n set(args);\n const { liveblocks: __, ...newState } = get();\n\n if (maybeRoom) {\n const room = maybeRoom;\n isPatching = true;\n updatePresence(room, oldState, newState, presenceMapping);\n\n room.batch(() => {\n if (storageRoot) {\n patchLiveblocksStorage(\n storageRoot,\n oldState,\n newState,\n storageMapping\n );\n }\n });\n\n isPatching = false;\n }\n },\n get,\n api\n );\n\n return {\n ...store,\n liveblocks: {\n enterRoom,\n leaveRoom,\n room: null,\n others: [],\n connection: \"closed\",\n isStorageLoading: false,\n },\n };\n };\n};\n\nexport const liveblocks =\n middlewareImpl as unknown as OuterLiveblocksMiddleware;\n\n/**\n * @deprecated Renamed to `liveblocks`.\n */\nexport const middleware = liveblocks;\n\nfunction patchState<T>(\n state: T,\n updates: StorageUpdate[],\n mapping: Mapping<T>\n) {\n const partialState: Partial<T> = {};\n\n for (const key in mapping) {\n partialState[key] = state[key];\n }\n\n const patched = legacy_patchImmutableObject(partialState, updates);\n\n const result: Partial<T> = {};\n\n for (const key in mapping) {\n result[key] = patched[key];\n }\n\n return result;\n}\n\nfunction selectFields<TState>(\n presence: TState,\n mapping: Mapping<TState>\n): /* TODO: Actually, Pick<TState, keyof Mapping<TState>> ? */\nPartial<TState> {\n const partialState = {} as Partial<TState>;\n for (const key in mapping) {\n partialState[key] = presence[key];\n }\n return partialState;\n}\n\nfunction updateLiveblocksContext<\n TState,\n TPresence extends JsonObject,\n TStorage extends LsonObject,\n TUserMeta extends BaseUserMeta,\n TRoomEvent extends Json,\n>(\n set: (\n callbackOrPartial: (\n current: WithLiveblocks<\n TState,\n TPresence,\n TStorage,\n TUserMeta,\n TRoomEvent\n >\n ) =>\n | WithLiveblocks<TState, TPresence, TStorage, TUserMeta, TRoomEvent>\n | Partial<any>\n ) => void,\n partial: Partial<\n LiveblocksContext<TPresence, TStorage, TUserMeta, TRoomEvent>\n >\n) {\n set((state) => ({ liveblocks: { ...state.liveblocks, ...partial } }));\n}\n\nfunction updatePresence<\n TPresence extends JsonObject,\n TStorage extends LsonObject,\n TUserMeta extends BaseUserMeta,\n TRoomEvent extends Json,\n>(\n room: Room<TPresence, TStorage, TUserMeta, TRoomEvent>,\n oldState: TPresence,\n newState: TPresence,\n presenceMapping: Mapping<TPresence>\n) {\n for (const key in presenceMapping) {\n if (typeof newState[key] === \"function\") {\n throw mappingToFunctionIsNotAllowed(key);\n }\n\n if (oldState[key] !== newState[key]) {\n const val = newState?.[key];\n const patch = {} as Partial<TPresence>;\n patch[key] = val;\n room.updatePresence(patch);\n }\n }\n}\n\nfunction patchLiveblocksStorage<O extends LsonObject, TState>(\n root: LiveObject<O>,\n oldState: TState,\n newState: TState,\n mapping: Mapping<TState>\n) {\n for (const key in mapping) {\n if (\n process.env.NODE_ENV !== \"production\" &&\n typeof newState[key] === \"function\"\n ) {\n throw mappingToFunctionIsNotAllowed(key);\n }\n\n if (oldState[key] !== newState[key]) {\n const oldVal = oldState[key];\n const newVal = newState[key];\n patchLiveObjectKey(root, key, oldVal, newVal);\n }\n }\n}\n\nfunction isObject(value: unknown): value is object {\n return Object.prototype.toString.call(value) === \"[object Object]\";\n}\n\nfunction validateNoDuplicateKeys<T>(\n storageMapping: Mapping<T>,\n presenceMapping: Mapping<T>\n) {\n for (const key in storageMapping) {\n if (presenceMapping[key] !== undefined) {\n throw new Error(\n `${ERROR_PREFIX} \"${key}\" is mapped on both presenceMapping and storageMapping. A key shouldn't exist on both mapping.`\n );\n }\n }\n}\n\n/**\n * Remove false keys from mapping and generate to a new object to avoid potential mutation from outside the middleware\n */\nfunction validateMapping<T>(\n mapping: Mapping<T>,\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Mapping<T> {\n errorIf(\n !isObject(mapping),\n `${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`\n );\n\n const result: Mapping<T> = {};\n for (const key in mapping) {\n errorIf(\n typeof mapping[key] !== \"boolean\",\n `${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`\n );\n\n if (mapping[key] === true) {\n result[key] = true;\n }\n }\n return result;\n}\n\nfunction validateOptions<TState>(options: Options<TState>): {\n client: Client;\n presenceMapping: Mapping<TState>;\n storageMapping: Mapping<TState>;\n} {\n const client = options.client;\n errorIf(!client, `${ERROR_PREFIX} client is missing`);\n\n const storageMapping = validateMapping(\n options.storageMapping ?? {},\n \"storageMapping\"\n );\n\n const presenceMapping = validateMapping(\n options.presenceMapping ?? {},\n \"presenceMapping\"\n );\n\n if (process.env.NODE_ENV !== \"production\") {\n validateNoDuplicateKeys(storageMapping, presenceMapping);\n }\n\n return { client, storageMapping, presenceMapping };\n}\n"],"mappings":"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","names":["updates"]}
|
package/package.json
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/zustand",
|
|
3
|
-
"version": "1.2.0-
|
|
3
|
+
"version": "1.2.0-internal6",
|
|
4
4
|
"description": "A middleware to integrate Liveblocks into Zustand stores. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"default": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"module": "./dist/index.mjs",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
8
21
|
"files": [
|
|
9
22
|
"dist/**",
|
|
10
23
|
"README.md"
|
|
@@ -20,8 +33,8 @@
|
|
|
20
33
|
"test:watch": "jest --silent --verbose --color=always --watch"
|
|
21
34
|
},
|
|
22
35
|
"dependencies": {
|
|
23
|
-
"@liveblocks/client": "1.2.0-
|
|
24
|
-
"@liveblocks/core": "1.2.0-
|
|
36
|
+
"@liveblocks/client": "1.2.0-internal6",
|
|
37
|
+
"@liveblocks/core": "1.2.0-internal6"
|
|
25
38
|
},
|
|
26
39
|
"peerDependencies": {
|
|
27
40
|
"zustand": "^4.1.3"
|