@liveblocks/zustand 2.18.3 → 2.18.4-uns1

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.
@@ -1,19 +1,19 @@
1
- // src/index.ts
2
- import {
3
- detectDupes,
4
- errorIf,
5
- legacy_patchImmutableObject,
6
- lsonToJson,
7
- patchLiveObjectKey
8
- } from "@liveblocks/core";
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
2
+
3
+
4
+
5
+
6
+
7
+
8
+ var _core = require('@liveblocks/core');
9
9
 
10
10
  // src/version.ts
11
11
  var PKG_NAME = "@liveblocks/zustand";
12
- var PKG_VERSION = "2.18.3";
13
- var PKG_FORMAT = "esm";
12
+ var PKG_VERSION = "2.18.4-uns1";
13
+ var PKG_FORMAT = "cjs";
14
14
 
15
15
  // src/index.ts
16
- detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
16
+ _core.detectDupes.call(void 0, PKG_NAME, PKG_VERSION, PKG_FORMAT);
17
17
  var ERROR_PREFIX = "Invalid @liveblocks/zustand middleware config.";
18
18
  function mappingToFunctionIsNotAllowed(key) {
19
19
  return new Error(
@@ -77,14 +77,14 @@ var middlewareImpl = (config, options) => {
77
77
  const liveblocksStatePart = root.get(key);
78
78
  if (liveblocksStatePart === void 0) {
79
79
  updates[key] = get()[key];
80
- patchLiveObjectKey(
80
+ _core.patchLiveObjectKey.call(void 0,
81
81
  root,
82
82
  key,
83
83
  void 0,
84
84
  get()[key]
85
85
  );
86
86
  } else {
87
- updates[key] = lsonToJson(
87
+ updates[key] = _core.lsonToJson.call(void 0,
88
88
  liveblocksStatePart
89
89
  );
90
90
  }
@@ -127,7 +127,7 @@ var middlewareImpl = (config, options) => {
127
127
  };
128
128
  }
129
129
  function leaveRoom() {
130
- lastLeaveFn?.();
130
+ _optionalChain([lastLeaveFn, 'optionalCall', _2 => _2()]);
131
131
  }
132
132
  const store = config(
133
133
  (...args) => {
@@ -178,7 +178,7 @@ function patchState(state, updates, mapping) {
178
178
  for (const key in mapping) {
179
179
  partialState[key] = state[key];
180
180
  }
181
- const patched = legacy_patchImmutableObject(
181
+ const patched = _core.legacy_patchImmutableObject.call(void 0,
182
182
  partialState,
183
183
  updates
184
184
  );
@@ -204,7 +204,7 @@ function updatePresence(room, oldState, newState, presenceMapping) {
204
204
  throw mappingToFunctionIsNotAllowed(key);
205
205
  }
206
206
  if (oldState[key] !== newState[key]) {
207
- const val = newState?.[key];
207
+ const val = _optionalChain([newState, 'optionalAccess', _3 => _3[key]]);
208
208
  const patch = {};
209
209
  patch[key] = val;
210
210
  room.updatePresence(patch);
@@ -219,7 +219,7 @@ function patchLiveblocksStorage(root, oldState, newState, mapping) {
219
219
  if (oldState[key] !== newState[key]) {
220
220
  const oldVal = oldState[key];
221
221
  const newVal = newState[key];
222
- patchLiveObjectKey(root, key, oldVal, newVal);
222
+ _core.patchLiveObjectKey.call(void 0, root, key, oldVal, newVal);
223
223
  }
224
224
  }
225
225
  }
@@ -236,13 +236,13 @@ function validateNoDuplicateKeys(storageMapping, presenceMapping) {
236
236
  }
237
237
  }
238
238
  function validateMapping(mapping, mappingType) {
239
- errorIf(
239
+ _core.errorIf.call(void 0,
240
240
  !isObject(mapping),
241
241
  `${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`
242
242
  );
243
243
  const result = {};
244
244
  for (const key in mapping) {
245
- errorIf(
245
+ _core.errorIf.call(void 0,
246
246
  typeof mapping[key] !== "boolean",
247
247
  `${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`
248
248
  );
@@ -254,13 +254,13 @@ function validateMapping(mapping, mappingType) {
254
254
  }
255
255
  function validateOptions(options) {
256
256
  const client = options.client;
257
- errorIf(!client, `${ERROR_PREFIX} client is missing`);
257
+ _core.errorIf.call(void 0, !client, `${ERROR_PREFIX} client is missing`);
258
258
  const storageMapping = validateMapping(
259
- options.storageMapping ?? {},
259
+ _nullishCoalesce(options.storageMapping, () => ( {})),
260
260
  "storageMapping"
261
261
  );
262
262
  const presenceMapping = validateMapping(
263
- options.presenceMapping ?? {},
263
+ _nullishCoalesce(options.presenceMapping, () => ( {})),
264
264
  "presenceMapping"
265
265
  );
266
266
  if (process.env.NODE_ENV !== "production") {
@@ -268,7 +268,7 @@ function validateOptions(options) {
268
268
  }
269
269
  return { client, storageMapping, presenceMapping };
270
270
  }
271
- export {
272
- liveblocks
273
- };
274
- //# sourceMappingURL=index.mjs.map
271
+
272
+
273
+ exports.liveblocks = liveblocks;
274
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/liveblocks/liveblocks/packages/liveblocks-zustand/dist/index.cjs","../src/index.ts","../src/version.ts"],"names":[],"mappings":"AAAA;ACqBA;AACE;AACA;AACA;AACA;AACA;AAAA,wCACK;ADnBP;AACA;AENO,IAAM,SAAA,EAAW,qBAAA;AACjB,IAAM,YAAA,EAAiD,aAAA;AACvD,IAAM,WAAA,EAAgD,KAAA;AFQ7D;AACA;ACkBA,+BAAA,QAAY,EAAU,WAAA,EAAa,UAAU,CAAA;AAE7C,IAAM,aAAA,EAAe,gDAAA;AAErB,SAAS,6BAAA,CAA8B,GAAA,EAAoB;AACzD,EAAA,OAAO,IAAI,KAAA;AAAA,IACT,CAAA,EAAA;AACF,EAAA;AACF;AAoGM;AAOJ,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AAEA,IAAA;AACE,MAAA;AACE,QAAA;AAAA,MAAA;AAGF,MAAA;AACA,MAAA;AAEE,QAAA;AAAY,MAAA;AAGd,MAAA;AAAwB,QAAA;AAClB,QAAA;AACJ,MAAA;AAGF,MAAA;AAAoD,QAAA;AAClD,MAAA;AAEF,MAAA;AAEA,MAAA;AAEA,MAAA;AAAqB,QAAA;AAEjB,UAAA;AAAuC,QAAA;AACxC,MAAA;AAGH,MAAA;AAAqB,QAAA;AAEjB,UAAA;AAA6B,YAAA;AAC3B,UAAA;AACD,QAAA;AACF,MAAA;AAGH,MAAA;AAAqB,QAAA;AAEjB,UAAA;AACE,YAAA;AAAA,cAAA;AACE,gBAAA;AACmB,gBAAA;AACjB,cAAA;AACF,YAAA;AACF,UAAA;AACF,QAAA;AACD,MAAA;AAGH,MAAA;AACE,QAAA;AAEA,QAAA;AACE,UAAA;AACE,YAAA;AACA,YAAA;AACE,cAAA;AACA,cAAA;AAAA,gBAAA;AACE,gBAAA;AACA,gBAAA;AACA,gBAAA;AACS,cAAA;AACX,YAAA;AAEA,cAAA;AAAe,gBAAA;AACb,cAAA;AACF,YAAA;AACF,UAAA;AACF,QAAA;AAGF,QAAA;AAEA,QAAA;AACA,QAAA;AAAqB,UAAA;AACd,YAAA;AACH,YAAA;AAEE,cAAA;AACE,gBAAA;AAA8C,cAAA;AAChD,YAAA;AACF,YAAA;AACe,UAAA;AACjB,QAAA;AAIF,QAAA;AAA6B,UAAA;AACT,QAAA;AACnB,MAAA;AAGH,MAAA;AACE,QAAA;AACE,UAAA;AAAY,QAAA;AAEd,QAAA;AAEA,QAAA;AACA,QAAA;AACA,QAAA;AAEA,QAAA;AACA,QAAA;AACA,QAAA;AAEA,QAAA;AAA6B,UAAA;AAClB,UAAA;AACD,UAAA;AACU,UAAA;AACZ,QAAA;AACP,MAAA;AAEL,IAAA;AAEA,IAAA;AACE,sBAAA;AACF,IAAA;AAEA,IAAA;AAAc,MAAA;AAEV,QAAA;AAEA,QAAA;AACA,QAAA;AAEA,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AAAA,YAAA;AACE,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AAGF,UAAA;AACE,YAAA;AACE,cAAA;AAAA,gBAAA;AACE,gBAAA;AACA,gBAAA;AACA,gBAAA;AACA,cAAA;AACF,YAAA;AACF,UAAA;AAGF,UAAA;AAAa,QAAA;AACf,MAAA;AACF,MAAA;AACA,MAAA;AAEF,IAAA;AAEA,IAAA;AAAO,MAAA;AACF,MAAA;AACS,QAAA;AACV,QAAA;AACA,QAAA;AACM,QAAA;AACG,QAAA;AACG,QAAA;AACM,MAAA;AAEtB,IAAA;AACF,EAAA;AACF;AAEa;AAGb;AAKE,EAAA;AAEA,EAAA;AACE,IAAA;AACF,EAAA;AAEA,EAAA;AACE,IAAA;AACA,IAAA;AACF,EAAA;AAEA,EAAA;AAEA,EAAA;AAEE,IAAA;AACF,EAAA;AAEA,EAAA;AACF;AAEA;AAKE,EAAA;AACA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACF;AAEA;AAeE,EAAA;AACF;AAEA;AAYE,EAAA;AACE,IAAA;AACE,MAAA;AACF,IAAA;AAEA,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACF,EAAA;AACF;AAEA;AAME,EAAA;AACE,IAAA;AAIE,MAAA;AACF,IAAA;AAEA,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACF,EAAA;AACF;AAEA;AACE,EAAA;AACF;AAEA;AAIE,EAAA;AACE,IAAA;AACE,MAAA;AAAU,QAAA;AACe,MAAA;AAE3B,IAAA;AACF,EAAA;AACF;AAKA;AAIE,EAAA;AACG,IAAA;AACD,IAAA;AACF,EAAA;AAEA,EAAA;AACA,EAAA;AACE,IAAA;AAAA,MAAA;AAC0B,MAAA;AAE1B,IAAA;AAEA,IAAA;AACE,MAAA;AACF,IAAA;AACF,EAAA;AACA,EAAA;AACF;AAEA;AAKE,EAAA;AACA,EAAA;AAEA,EAAA;AACE,qBAAA;AACA,IAAA;AACF,EAAA;AAEA,EAAA;AACE,qBAAA;AACA,IAAA;AACF,EAAA;AAEA,EAAA;AACE,IAAA;AACF,EAAA;AAEA,EAAA;AACF;ADpOK;AACA;AACA","file":"/home/runner/work/liveblocks/liveblocks/packages/liveblocks-zustand/dist/index.cjs","sourcesContent":[null,"import type {\n BaseUserMeta,\n Json,\n JsonObject,\n LiveObject,\n LsonObject,\n Room,\n Status,\n User,\n} from \"@liveblocks/client\";\nimport type {\n BaseMetadata,\n DE,\n DM,\n DP,\n DS,\n DU,\n OpaqueClient,\n OpaqueRoom,\n StorageUpdate,\n} from \"@liveblocks/core\";\nimport {\n detectDupes,\n errorIf,\n legacy_patchImmutableObject,\n lsonToJson,\n patchLiveObjectKey,\n} from \"@liveblocks/core\";\nimport type { StateCreator, StoreMutatorIdentifier } from \"zustand\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\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 P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\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 the currently entered room and stops sync it with zustand state, if\n * any. If enterRoom was not called before, this is a no-op.\n */\n readonly leaveRoom: () => void;\n /**\n * The room currently synced to your zustand state.\n */\n readonly room: Room<P, S, U, E, M> | null;\n /**\n * Other users in the room. Empty no room is currently synced\n */\n readonly others: readonly User<P, U>[];\n /**\n * Whether or not the room storage is currently loading\n */\n readonly isStorageLoading: boolean;\n /**\n * Connection status of the room.\n */\n readonly status: Status;\n};\n\n/**\n * Adds the `liveblocks` property to your custom Zustand state.\n */\nexport type WithLiveblocks<\n TState,\n P extends JsonObject = DP,\n S extends LsonObject = DS,\n U extends BaseUserMeta = DU,\n E extends Json = DE,\n M extends BaseMetadata = DM,\n> = TState & {\n readonly liveblocks: LiveblocksContext<P, S, U, E, M>;\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: OpaqueClient;\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 BaseMetadata\n >;\n },\n>(\n config: StateCreator<TState, [], []>,\n options: Options<TState>\n) => StateCreator<TState, [], []>;\n\ntype ExtractPresence<TRoom extends OpaqueRoom> =\n TRoom extends Room<infer P, any, any, any, any> ? P : never;\n\ntype ExtractStorage<TRoom extends OpaqueRoom> =\n TRoom extends Room<any, infer S, any, 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 P = ExtractPresence<TRoom>;\n type S = 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<S> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n let lastRoomId: string | null = null;\n let lastLeaveFn: (() => void) | null = null;\n\n function enterRoom(newRoomId: string): void {\n if (lastRoomId === newRoomId) {\n return;\n }\n\n lastRoomId = newRoomId;\n if (lastLeaveFn !== null) {\n // First leave the old room before entering a potential new one\n lastLeaveFn();\n }\n\n const initialPresence = selectFields(\n get(),\n presenceMapping\n ) as unknown as P;\n\n const { room, leave } = client.enterRoom(newRoomId, {\n initialPresence,\n }) as unknown as { room: TRoom; leave: () => void };\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.status.subscribe((status) => {\n updateLiveblocksContext(set, {\n status,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.myPresence.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(\n root,\n key,\n undefined,\n get()[key] as Json | undefined\n );\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<S>;\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 lastLeaveFn = () => {\n for (const unsubscribe of unsubscribeCallbacks) {\n unsubscribe();\n }\n unsubscribeCallbacks = [];\n\n storageRoot = null;\n maybeRoom = null;\n isPatching = false;\n\n lastRoomId = null;\n lastLeaveFn = null;\n leave();\n\n updateLiveblocksContext(set, {\n others: [],\n status: \"initial\",\n isStorageLoading: false,\n room: null,\n });\n };\n }\n\n function leaveRoom() {\n lastLeaveFn?.();\n }\n\n const store = config(\n (...args) => {\n const { liveblocks: _, ...oldState } = get();\n // @ts-expect-error a bit too dynamic to type\n set(...args);\n const { liveblocks: __, ...newState } = get();\n\n if (maybeRoom) {\n const room = maybeRoom;\n isPatching = true;\n updatePresence(\n room,\n oldState as JsonObject,\n newState as JsonObject,\n presenceMapping\n );\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\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(\n partialState as JsonObject,\n updates\n );\n\n const result: Partial<T> = {};\n\n for (const key in mapping) {\n // @ts-expect-error key is a key of T\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 P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(\n set: (\n callbackOrPartial: (\n current: WithLiveblocks<TState, P, S, U, E, M>\n ) => WithLiveblocks<TState, P, S, U, E> | Partial<any>\n ) => void,\n partial: Partial<LiveblocksContext<P, S, U, E, M>>\n) {\n set((state) => ({ liveblocks: { ...state.liveblocks, ...partial } }));\n}\n\nfunction updatePresence<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(\n room: Room<P, S, U, E, M>,\n oldState: P,\n newState: P,\n presenceMapping: Mapping<P>\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<P>;\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] as Json | undefined;\n const newVal = newState[key] as Json | undefined;\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: OpaqueClient;\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","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/zustand\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"]}
package/dist/index.js CHANGED
@@ -1,19 +1,19 @@
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
2
-
3
-
4
-
5
-
6
-
7
-
8
- var _core = require('@liveblocks/core');
1
+ // src/index.ts
2
+ import {
3
+ detectDupes,
4
+ errorIf,
5
+ legacy_patchImmutableObject,
6
+ lsonToJson,
7
+ patchLiveObjectKey
8
+ } from "@liveblocks/core";
9
9
 
10
10
  // src/version.ts
11
11
  var PKG_NAME = "@liveblocks/zustand";
12
- var PKG_VERSION = "2.18.3";
13
- var PKG_FORMAT = "cjs";
12
+ var PKG_VERSION = "2.18.4-uns1";
13
+ var PKG_FORMAT = "esm";
14
14
 
15
15
  // src/index.ts
16
- _core.detectDupes.call(void 0, PKG_NAME, PKG_VERSION, PKG_FORMAT);
16
+ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
17
17
  var ERROR_PREFIX = "Invalid @liveblocks/zustand middleware config.";
18
18
  function mappingToFunctionIsNotAllowed(key) {
19
19
  return new Error(
@@ -77,14 +77,14 @@ var middlewareImpl = (config, options) => {
77
77
  const liveblocksStatePart = root.get(key);
78
78
  if (liveblocksStatePart === void 0) {
79
79
  updates[key] = get()[key];
80
- _core.patchLiveObjectKey.call(void 0,
80
+ patchLiveObjectKey(
81
81
  root,
82
82
  key,
83
83
  void 0,
84
84
  get()[key]
85
85
  );
86
86
  } else {
87
- updates[key] = _core.lsonToJson.call(void 0,
87
+ updates[key] = lsonToJson(
88
88
  liveblocksStatePart
89
89
  );
90
90
  }
@@ -127,7 +127,7 @@ var middlewareImpl = (config, options) => {
127
127
  };
128
128
  }
129
129
  function leaveRoom() {
130
- _optionalChain([lastLeaveFn, 'optionalCall', _2 => _2()]);
130
+ lastLeaveFn?.();
131
131
  }
132
132
  const store = config(
133
133
  (...args) => {
@@ -178,7 +178,7 @@ function patchState(state, updates, mapping) {
178
178
  for (const key in mapping) {
179
179
  partialState[key] = state[key];
180
180
  }
181
- const patched = _core.legacy_patchImmutableObject.call(void 0,
181
+ const patched = legacy_patchImmutableObject(
182
182
  partialState,
183
183
  updates
184
184
  );
@@ -204,7 +204,7 @@ function updatePresence(room, oldState, newState, presenceMapping) {
204
204
  throw mappingToFunctionIsNotAllowed(key);
205
205
  }
206
206
  if (oldState[key] !== newState[key]) {
207
- const val = _optionalChain([newState, 'optionalAccess', _3 => _3[key]]);
207
+ const val = newState?.[key];
208
208
  const patch = {};
209
209
  patch[key] = val;
210
210
  room.updatePresence(patch);
@@ -219,7 +219,7 @@ function patchLiveblocksStorage(root, oldState, newState, mapping) {
219
219
  if (oldState[key] !== newState[key]) {
220
220
  const oldVal = oldState[key];
221
221
  const newVal = newState[key];
222
- _core.patchLiveObjectKey.call(void 0, root, key, oldVal, newVal);
222
+ patchLiveObjectKey(root, key, oldVal, newVal);
223
223
  }
224
224
  }
225
225
  }
@@ -236,13 +236,13 @@ function validateNoDuplicateKeys(storageMapping, presenceMapping) {
236
236
  }
237
237
  }
238
238
  function validateMapping(mapping, mappingType) {
239
- _core.errorIf.call(void 0,
239
+ errorIf(
240
240
  !isObject(mapping),
241
241
  `${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`
242
242
  );
243
243
  const result = {};
244
244
  for (const key in mapping) {
245
- _core.errorIf.call(void 0,
245
+ errorIf(
246
246
  typeof mapping[key] !== "boolean",
247
247
  `${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`
248
248
  );
@@ -254,13 +254,13 @@ function validateMapping(mapping, mappingType) {
254
254
  }
255
255
  function validateOptions(options) {
256
256
  const client = options.client;
257
- _core.errorIf.call(void 0, !client, `${ERROR_PREFIX} client is missing`);
257
+ errorIf(!client, `${ERROR_PREFIX} client is missing`);
258
258
  const storageMapping = validateMapping(
259
- _nullishCoalesce(options.storageMapping, () => ( {})),
259
+ options.storageMapping ?? {},
260
260
  "storageMapping"
261
261
  );
262
262
  const presenceMapping = validateMapping(
263
- _nullishCoalesce(options.presenceMapping, () => ( {})),
263
+ options.presenceMapping ?? {},
264
264
  "presenceMapping"
265
265
  );
266
266
  if (process.env.NODE_ENV !== "production") {
@@ -268,7 +268,7 @@ function validateOptions(options) {
268
268
  }
269
269
  return { client, storageMapping, presenceMapping };
270
270
  }
271
-
272
-
273
- exports.liveblocks = liveblocks;
271
+ export {
272
+ liveblocks
273
+ };
274
274
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/liveblocks/liveblocks/packages/liveblocks-zustand/dist/index.js","../src/index.ts","../src/version.ts"],"names":[],"mappings":"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","file":"/home/runner/work/liveblocks/liveblocks/packages/liveblocks-zustand/dist/index.js","sourcesContent":[null,"import type {\n BaseUserMeta,\n Json,\n JsonObject,\n LiveObject,\n LsonObject,\n Room,\n Status,\n User,\n} from \"@liveblocks/client\";\nimport type {\n BaseMetadata,\n DE,\n DM,\n DP,\n DS,\n DU,\n OpaqueClient,\n OpaqueRoom,\n StorageUpdate,\n} from \"@liveblocks/core\";\nimport {\n detectDupes,\n errorIf,\n legacy_patchImmutableObject,\n lsonToJson,\n patchLiveObjectKey,\n} from \"@liveblocks/core\";\nimport type { StateCreator, StoreMutatorIdentifier } from \"zustand\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\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 P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\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 the currently entered room and stops sync it with zustand state, if\n * any. If enterRoom was not called before, this is a no-op.\n */\n readonly leaveRoom: () => void;\n /**\n * The room currently synced to your zustand state.\n */\n readonly room: Room<P, S, U, E, M> | null;\n /**\n * Other users in the room. Empty no room is currently synced\n */\n readonly others: readonly User<P, U>[];\n /**\n * Whether or not the room storage is currently loading\n */\n readonly isStorageLoading: boolean;\n /**\n * Connection status of the room.\n */\n readonly status: Status;\n};\n\n/**\n * Adds the `liveblocks` property to your custom Zustand state.\n */\nexport type WithLiveblocks<\n TState,\n P extends JsonObject = DP,\n S extends LsonObject = DS,\n U extends BaseUserMeta = DU,\n E extends Json = DE,\n M extends BaseMetadata = DM,\n> = TState & {\n readonly liveblocks: LiveblocksContext<P, S, U, E, M>;\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: OpaqueClient;\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 BaseMetadata\n >;\n },\n>(\n config: StateCreator<TState, [], []>,\n options: Options<TState>\n) => StateCreator<TState, [], []>;\n\ntype ExtractPresence<TRoom extends OpaqueRoom> =\n TRoom extends Room<infer P, any, any, any, any> ? P : never;\n\ntype ExtractStorage<TRoom extends OpaqueRoom> =\n TRoom extends Room<any, infer S, any, 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 P = ExtractPresence<TRoom>;\n type S = 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<S> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n let lastRoomId: string | null = null;\n let lastLeaveFn: (() => void) | null = null;\n\n function enterRoom(newRoomId: string): void {\n if (lastRoomId === newRoomId) {\n return;\n }\n\n lastRoomId = newRoomId;\n if (lastLeaveFn !== null) {\n // First leave the old room before entering a potential new one\n lastLeaveFn();\n }\n\n const initialPresence = selectFields(\n get(),\n presenceMapping\n ) as unknown as P;\n\n const { room, leave } = client.enterRoom(newRoomId, {\n initialPresence,\n }) as unknown as { room: TRoom; leave: () => void };\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.status.subscribe((status) => {\n updateLiveblocksContext(set, {\n status,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.myPresence.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(\n root,\n key,\n undefined,\n get()[key] as Json | undefined\n );\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<S>;\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 lastLeaveFn = () => {\n for (const unsubscribe of unsubscribeCallbacks) {\n unsubscribe();\n }\n unsubscribeCallbacks = [];\n\n storageRoot = null;\n maybeRoom = null;\n isPatching = false;\n\n lastRoomId = null;\n lastLeaveFn = null;\n leave();\n\n updateLiveblocksContext(set, {\n others: [],\n status: \"initial\",\n isStorageLoading: false,\n room: null,\n });\n };\n }\n\n function leaveRoom() {\n lastLeaveFn?.();\n }\n\n const store = config(\n (...args) => {\n const { liveblocks: _, ...oldState } = get();\n // @ts-expect-error a bit too dynamic to type\n set(...args);\n const { liveblocks: __, ...newState } = get();\n\n if (maybeRoom) {\n const room = maybeRoom;\n isPatching = true;\n updatePresence(\n room,\n oldState as JsonObject,\n newState as JsonObject,\n presenceMapping\n );\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\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(\n partialState as JsonObject,\n updates\n );\n\n const result: Partial<T> = {};\n\n for (const key in mapping) {\n // @ts-expect-error key is a key of T\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 P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(\n set: (\n callbackOrPartial: (\n current: WithLiveblocks<TState, P, S, U, E, M>\n ) => WithLiveblocks<TState, P, S, U, E> | Partial<any>\n ) => void,\n partial: Partial<LiveblocksContext<P, S, U, E, M>>\n) {\n set((state) => ({ liveblocks: { ...state.liveblocks, ...partial } }));\n}\n\nfunction updatePresence<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(\n room: Room<P, S, U, E, M>,\n oldState: P,\n newState: P,\n presenceMapping: Mapping<P>\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<P>;\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] as Json | undefined;\n const newVal = newState[key] as Json | undefined;\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: OpaqueClient;\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","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/zustand\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/version.ts"],"sourcesContent":["import type {\n BaseUserMeta,\n Json,\n JsonObject,\n LiveObject,\n LsonObject,\n Room,\n Status,\n User,\n} from \"@liveblocks/client\";\nimport type {\n BaseMetadata,\n DE,\n DM,\n DP,\n DS,\n DU,\n OpaqueClient,\n OpaqueRoom,\n StorageUpdate,\n} from \"@liveblocks/core\";\nimport {\n detectDupes,\n errorIf,\n legacy_patchImmutableObject,\n lsonToJson,\n patchLiveObjectKey,\n} from \"@liveblocks/core\";\nimport type { StateCreator, StoreMutatorIdentifier } from \"zustand\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\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 P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\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 the currently entered room and stops sync it with zustand state, if\n * any. If enterRoom was not called before, this is a no-op.\n */\n readonly leaveRoom: () => void;\n /**\n * The room currently synced to your zustand state.\n */\n readonly room: Room<P, S, U, E, M> | null;\n /**\n * Other users in the room. Empty no room is currently synced\n */\n readonly others: readonly User<P, U>[];\n /**\n * Whether or not the room storage is currently loading\n */\n readonly isStorageLoading: boolean;\n /**\n * Connection status of the room.\n */\n readonly status: Status;\n};\n\n/**\n * Adds the `liveblocks` property to your custom Zustand state.\n */\nexport type WithLiveblocks<\n TState,\n P extends JsonObject = DP,\n S extends LsonObject = DS,\n U extends BaseUserMeta = DU,\n E extends Json = DE,\n M extends BaseMetadata = DM,\n> = TState & {\n readonly liveblocks: LiveblocksContext<P, S, U, E, M>;\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: OpaqueClient;\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 BaseMetadata\n >;\n },\n>(\n config: StateCreator<TState, [], []>,\n options: Options<TState>\n) => StateCreator<TState, [], []>;\n\ntype ExtractPresence<TRoom extends OpaqueRoom> =\n TRoom extends Room<infer P, any, any, any, any> ? P : never;\n\ntype ExtractStorage<TRoom extends OpaqueRoom> =\n TRoom extends Room<any, infer S, any, 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 P = ExtractPresence<TRoom>;\n type S = 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<S> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n let lastRoomId: string | null = null;\n let lastLeaveFn: (() => void) | null = null;\n\n function enterRoom(newRoomId: string): void {\n if (lastRoomId === newRoomId) {\n return;\n }\n\n lastRoomId = newRoomId;\n if (lastLeaveFn !== null) {\n // First leave the old room before entering a potential new one\n lastLeaveFn();\n }\n\n const initialPresence = selectFields(\n get(),\n presenceMapping\n ) as unknown as P;\n\n const { room, leave } = client.enterRoom(newRoomId, {\n initialPresence,\n }) as unknown as { room: TRoom; leave: () => void };\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.status.subscribe((status) => {\n updateLiveblocksContext(set, {\n status,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.myPresence.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(\n root,\n key,\n undefined,\n get()[key] as Json | undefined\n );\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<S>;\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 lastLeaveFn = () => {\n for (const unsubscribe of unsubscribeCallbacks) {\n unsubscribe();\n }\n unsubscribeCallbacks = [];\n\n storageRoot = null;\n maybeRoom = null;\n isPatching = false;\n\n lastRoomId = null;\n lastLeaveFn = null;\n leave();\n\n updateLiveblocksContext(set, {\n others: [],\n status: \"initial\",\n isStorageLoading: false,\n room: null,\n });\n };\n }\n\n function leaveRoom() {\n lastLeaveFn?.();\n }\n\n const store = config(\n (...args) => {\n const { liveblocks: _, ...oldState } = get();\n // @ts-expect-error a bit too dynamic to type\n set(...args);\n const { liveblocks: __, ...newState } = get();\n\n if (maybeRoom) {\n const room = maybeRoom;\n isPatching = true;\n updatePresence(\n room,\n oldState as JsonObject,\n newState as JsonObject,\n presenceMapping\n );\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\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(\n partialState as JsonObject,\n updates\n );\n\n const result: Partial<T> = {};\n\n for (const key in mapping) {\n // @ts-expect-error key is a key of T\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 P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(\n set: (\n callbackOrPartial: (\n current: WithLiveblocks<TState, P, S, U, E, M>\n ) => WithLiveblocks<TState, P, S, U, E> | Partial<any>\n ) => void,\n partial: Partial<LiveblocksContext<P, S, U, E, M>>\n) {\n set((state) => ({ liveblocks: { ...state.liveblocks, ...partial } }));\n}\n\nfunction updatePresence<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(\n room: Room<P, S, U, E, M>,\n oldState: P,\n newState: P,\n presenceMapping: Mapping<P>\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<P>;\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] as Json | undefined;\n const newVal = newState[key] as Json | undefined;\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: OpaqueClient;\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","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/zustand\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"mappings":"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","names":["updates"]}
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@liveblocks/zustand",
3
- "version": "2.18.3",
3
+ "version": "2.18.4-uns1",
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
- "type": "commonjs",
7
- "main": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "types": "./dist/index.d.cts",
9
9
  "exports": {
10
10
  ".": {
11
11
  "import": {
12
- "types": "./dist/index.d.mts",
13
- "default": "./dist/index.mjs"
14
- },
15
- "require": {
16
12
  "types": "./dist/index.d.ts",
17
- "module": "./dist/index.mjs",
18
13
  "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "module": "./dist/index.js",
18
+ "default": "./dist/index.cjs"
19
19
  }
20
20
  }
21
21
  },
@@ -34,8 +34,8 @@
34
34
  "test:watch": "jest --silent --verbose --color=always --watch"
35
35
  },
36
36
  "dependencies": {
37
- "@liveblocks/client": "2.18.3",
38
- "@liveblocks/core": "2.18.3"
37
+ "@liveblocks/client": "2.18.4-uns1",
38
+ "@liveblocks/core": "2.18.4-uns1"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "zustand": "^5.0.1"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/version.ts"],"sourcesContent":["import type {\n BaseUserMeta,\n Json,\n JsonObject,\n LiveObject,\n LsonObject,\n Room,\n Status,\n User,\n} from \"@liveblocks/client\";\nimport type {\n BaseMetadata,\n DE,\n DM,\n DP,\n DS,\n DU,\n OpaqueClient,\n OpaqueRoom,\n StorageUpdate,\n} from \"@liveblocks/core\";\nimport {\n detectDupes,\n errorIf,\n legacy_patchImmutableObject,\n lsonToJson,\n patchLiveObjectKey,\n} from \"@liveblocks/core\";\nimport type { StateCreator, StoreMutatorIdentifier } from \"zustand\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\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 P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\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 the currently entered room and stops sync it with zustand state, if\n * any. If enterRoom was not called before, this is a no-op.\n */\n readonly leaveRoom: () => void;\n /**\n * The room currently synced to your zustand state.\n */\n readonly room: Room<P, S, U, E, M> | null;\n /**\n * Other users in the room. Empty no room is currently synced\n */\n readonly others: readonly User<P, U>[];\n /**\n * Whether or not the room storage is currently loading\n */\n readonly isStorageLoading: boolean;\n /**\n * Connection status of the room.\n */\n readonly status: Status;\n};\n\n/**\n * Adds the `liveblocks` property to your custom Zustand state.\n */\nexport type WithLiveblocks<\n TState,\n P extends JsonObject = DP,\n S extends LsonObject = DS,\n U extends BaseUserMeta = DU,\n E extends Json = DE,\n M extends BaseMetadata = DM,\n> = TState & {\n readonly liveblocks: LiveblocksContext<P, S, U, E, M>;\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: OpaqueClient;\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 BaseMetadata\n >;\n },\n>(\n config: StateCreator<TState, [], []>,\n options: Options<TState>\n) => StateCreator<TState, [], []>;\n\ntype ExtractPresence<TRoom extends OpaqueRoom> =\n TRoom extends Room<infer P, any, any, any, any> ? P : never;\n\ntype ExtractStorage<TRoom extends OpaqueRoom> =\n TRoom extends Room<any, infer S, any, 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 P = ExtractPresence<TRoom>;\n type S = 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<S> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n let lastRoomId: string | null = null;\n let lastLeaveFn: (() => void) | null = null;\n\n function enterRoom(newRoomId: string): void {\n if (lastRoomId === newRoomId) {\n return;\n }\n\n lastRoomId = newRoomId;\n if (lastLeaveFn !== null) {\n // First leave the old room before entering a potential new one\n lastLeaveFn();\n }\n\n const initialPresence = selectFields(\n get(),\n presenceMapping\n ) as unknown as P;\n\n const { room, leave } = client.enterRoom(newRoomId, {\n initialPresence,\n }) as unknown as { room: TRoom; leave: () => void };\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.status.subscribe((status) => {\n updateLiveblocksContext(set, {\n status,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.myPresence.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(\n root,\n key,\n undefined,\n get()[key] as Json | undefined\n );\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<S>;\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 lastLeaveFn = () => {\n for (const unsubscribe of unsubscribeCallbacks) {\n unsubscribe();\n }\n unsubscribeCallbacks = [];\n\n storageRoot = null;\n maybeRoom = null;\n isPatching = false;\n\n lastRoomId = null;\n lastLeaveFn = null;\n leave();\n\n updateLiveblocksContext(set, {\n others: [],\n status: \"initial\",\n isStorageLoading: false,\n room: null,\n });\n };\n }\n\n function leaveRoom() {\n lastLeaveFn?.();\n }\n\n const store = config(\n (...args) => {\n const { liveblocks: _, ...oldState } = get();\n // @ts-expect-error a bit too dynamic to type\n set(...args);\n const { liveblocks: __, ...newState } = get();\n\n if (maybeRoom) {\n const room = maybeRoom;\n isPatching = true;\n updatePresence(\n room,\n oldState as JsonObject,\n newState as JsonObject,\n presenceMapping\n );\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\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(\n partialState as JsonObject,\n updates\n );\n\n const result: Partial<T> = {};\n\n for (const key in mapping) {\n // @ts-expect-error key is a key of T\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 P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(\n set: (\n callbackOrPartial: (\n current: WithLiveblocks<TState, P, S, U, E, M>\n ) => WithLiveblocks<TState, P, S, U, E> | Partial<any>\n ) => void,\n partial: Partial<LiveblocksContext<P, S, U, E, M>>\n) {\n set((state) => ({ liveblocks: { ...state.liveblocks, ...partial } }));\n}\n\nfunction updatePresence<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(\n room: Room<P, S, U, E, M>,\n oldState: P,\n newState: P,\n presenceMapping: Mapping<P>\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<P>;\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] as Json | undefined;\n const newVal = newState[key] as Json | undefined;\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: OpaqueClient;\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","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/zustand\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"mappings":"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","names":["updates"]}
File without changes