@liveblocks/redux 3.17.0-rc1 → 3.18.0-rc1
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.cjs +34 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +35 -63
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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
2
|
var _core = require('@liveblocks/core');
|
|
8
3
|
|
|
9
4
|
// src/errors.ts
|
|
@@ -34,7 +29,7 @@ function mappingToFunctionIsNotAllowed(key) {
|
|
|
34
29
|
|
|
35
30
|
// src/version.ts
|
|
36
31
|
var PKG_NAME = "@liveblocks/redux";
|
|
37
|
-
var PKG_VERSION = "3.
|
|
32
|
+
var PKG_VERSION = "3.18.0-rc1";
|
|
38
33
|
var PKG_FORMAT = "cjs";
|
|
39
34
|
|
|
40
35
|
// src/index.ts
|
|
@@ -48,6 +43,13 @@ var ACTION_TYPES = {
|
|
|
48
43
|
UPDATE_CONNECTION: "@@LIVEBLOCKS/UPDATE_CONNECTION",
|
|
49
44
|
UPDATE_OTHERS: "@@LIVEBLOCKS/UPDATE_OTHERS"
|
|
50
45
|
};
|
|
46
|
+
function ensureNoFunctions(state) {
|
|
47
|
+
for (const key in state) {
|
|
48
|
+
if (typeof state[key] === "function") {
|
|
49
|
+
throw mappingToFunctionIsNotAllowed(key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
51
53
|
var internalEnhancer = (options) => {
|
|
52
54
|
if (process.env.NODE_ENV !== "production" && options.client == null) {
|
|
53
55
|
throw missingClient();
|
|
@@ -65,6 +67,7 @@ var internalEnhancer = (options) => {
|
|
|
65
67
|
validateNoDuplicateKeys(storageMapping, presenceMapping);
|
|
66
68
|
}
|
|
67
69
|
const presenceKeys = Object.keys(presenceMapping);
|
|
70
|
+
const storageKeys = Object.keys(storageMapping);
|
|
68
71
|
return (createStore) => {
|
|
69
72
|
return (reducer, initialState, enhancer) => {
|
|
70
73
|
let maybeRoom = null;
|
|
@@ -121,20 +124,22 @@ var internalEnhancer = (options) => {
|
|
|
121
124
|
if (maybeRoom) {
|
|
122
125
|
isPatching = true;
|
|
123
126
|
try {
|
|
124
|
-
updatePresence(
|
|
125
|
-
maybeRoom,
|
|
126
|
-
state,
|
|
127
|
-
newState,
|
|
128
|
-
presenceMapping
|
|
129
|
-
);
|
|
130
127
|
maybeRoom.batch(() => {
|
|
128
|
+
updatePresence(
|
|
129
|
+
maybeRoom,
|
|
130
|
+
state,
|
|
131
|
+
newState,
|
|
132
|
+
presenceMapping
|
|
133
|
+
);
|
|
131
134
|
if (storageRoot) {
|
|
132
|
-
|
|
133
|
-
storageRoot,
|
|
134
|
-
state,
|
|
135
|
+
const partialState = pick(
|
|
135
136
|
newState,
|
|
136
|
-
|
|
137
|
+
storageKeys
|
|
137
138
|
);
|
|
139
|
+
if (process.env.NODE_ENV !== "production") {
|
|
140
|
+
ensureNoFunctions(partialState);
|
|
141
|
+
}
|
|
142
|
+
storageRoot.reconcilePartially(partialState);
|
|
138
143
|
}
|
|
139
144
|
});
|
|
140
145
|
} finally {
|
|
@@ -201,38 +206,29 @@ var internalEnhancer = (options) => {
|
|
|
201
206
|
type: ACTION_TYPES.START_LOADING_STORAGE
|
|
202
207
|
});
|
|
203
208
|
void room.getStorage().then(({ root }) => {
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
updates[key] = store.getState()[key];
|
|
210
|
-
_core.legacy_patchLiveObjectKey.call(void 0,
|
|
211
|
-
root,
|
|
212
|
-
key,
|
|
213
|
-
void 0,
|
|
214
|
-
store.getState()[key]
|
|
215
|
-
);
|
|
216
|
-
} else {
|
|
217
|
-
updates[key] = _core.lsonToJson.call(void 0, liveblocksStatePart);
|
|
218
|
-
}
|
|
209
|
+
const reduxState = store.getState();
|
|
210
|
+
const missing = {};
|
|
211
|
+
for (const key of storageKeys) {
|
|
212
|
+
if (root.get(key) == null) {
|
|
213
|
+
missing[key] = reduxState[key];
|
|
219
214
|
}
|
|
215
|
+
}
|
|
216
|
+
room.history[_core.kInternal].withoutHistory(() => {
|
|
217
|
+
maybeRoom.batch(() => {
|
|
218
|
+
root.reconcilePartially(missing);
|
|
219
|
+
});
|
|
220
220
|
});
|
|
221
221
|
store.dispatch({
|
|
222
222
|
type: ACTION_TYPES.INIT_STORAGE,
|
|
223
|
-
state:
|
|
223
|
+
state: pick(root.toJSON(), storageKeys)
|
|
224
224
|
});
|
|
225
225
|
storageRoot = root;
|
|
226
226
|
unsubscribeCallbacks.push(
|
|
227
|
-
maybeRoom.events.storageBatch.subscribe((
|
|
227
|
+
maybeRoom.events.storageBatch.subscribe(() => {
|
|
228
228
|
if (!isPatching) {
|
|
229
229
|
store.dispatch({
|
|
230
230
|
type: ACTION_TYPES.PATCH_REDUX_STATE,
|
|
231
|
-
state:
|
|
232
|
-
store.getState(),
|
|
233
|
-
updates2,
|
|
234
|
-
storageMapping
|
|
235
|
-
)
|
|
231
|
+
state: pick(root.toJSON(), storageKeys)
|
|
236
232
|
});
|
|
237
233
|
}
|
|
238
234
|
})
|
|
@@ -293,18 +289,6 @@ function leaveRoom() {
|
|
|
293
289
|
return { type: ACTION_TYPES.LEAVE };
|
|
294
290
|
}
|
|
295
291
|
var liveblocksEnhancer = internalEnhancer;
|
|
296
|
-
function patchLiveblocksStorage(root, oldState, newState, mapping) {
|
|
297
|
-
for (const key in mapping) {
|
|
298
|
-
if (process.env.NODE_ENV !== "production" && typeof newState[key] === "function") {
|
|
299
|
-
throw mappingToFunctionIsNotAllowed("value");
|
|
300
|
-
}
|
|
301
|
-
if (oldState[key] !== newState[key]) {
|
|
302
|
-
const oldVal = oldState[key];
|
|
303
|
-
const newVal = newState[key];
|
|
304
|
-
_core.legacy_patchLiveObjectKey.call(void 0, root, key, oldVal, newVal);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
292
|
function updatePresence(room, oldState, newState, presenceMapping) {
|
|
309
293
|
for (const key in presenceMapping) {
|
|
310
294
|
if (typeof newState[key] === "function") {
|
|
@@ -332,18 +316,6 @@ function pick(source, keys) {
|
|
|
332
316
|
}
|
|
333
317
|
return result;
|
|
334
318
|
}
|
|
335
|
-
function patchState(state, updates, mapping) {
|
|
336
|
-
const partialState = {};
|
|
337
|
-
for (const key in mapping) {
|
|
338
|
-
partialState[key] = state[key];
|
|
339
|
-
}
|
|
340
|
-
const patched = _core.legacy_patchImmutableObject.call(void 0, partialState, updates);
|
|
341
|
-
const result = {};
|
|
342
|
-
for (const key in mapping) {
|
|
343
|
-
result[key] = patched[key];
|
|
344
|
-
}
|
|
345
|
-
return result;
|
|
346
|
-
}
|
|
347
319
|
function validateMapping(mapping, mappingType) {
|
|
348
320
|
if (process.env.NODE_ENV !== "production") {
|
|
349
321
|
if (!isObject(mapping)) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/liveblocks/liveblocks/packages/liveblocks-redux/dist/index.cjs","../src/index.ts","../src/errors.ts","../src/version.ts"],"names":["enterRoom","options","updates","leaveRoom"],"mappings":"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","file":"/home/runner/work/liveblocks/liveblocks/packages/liveblocks-redux/dist/index.cjs","sourcesContent":[null,"import type {\n BaseUserMeta,\n JsonObject,\n LiveObject,\n LsonObject,\n Room,\n Status,\n User,\n} from \"@liveblocks/client\";\nimport type { EnterOptions, OpaqueClient, OpaqueRoom } from \"@liveblocks/core\";\nimport {\n detectDupes,\n legacy_patchImmutableObject,\n legacy_patchLiveObjectKey,\n lsonToJson,\n} from \"@liveblocks/core\";\nimport type { StoreEnhancer } from \"redux\";\n\nimport {\n mappingShouldBeAnObject,\n mappingShouldNotHaveTheSameKeys,\n mappingToFunctionIsNotAllowed,\n mappingValueShouldBeABoolean,\n missingClient,\n} from \"./errors\";\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type Mapping<T> = {\n [K in keyof T]?: boolean;\n};\n\nconst ACTION_TYPES = {\n ENTER: \"@@LIVEBLOCKS/ENTER\",\n LEAVE: \"@@LIVEBLOCKS/LEAVE\",\n START_LOADING_STORAGE: \"@@LIVEBLOCKS/START_LOADING_STORAGE\",\n INIT_STORAGE: \"@@LIVEBLOCKS/INIT_STORAGE\",\n PATCH_REDUX_STATE: \"@@LIVEBLOCKS/PATCH_REDUX_STATE\",\n UPDATE_CONNECTION: \"@@LIVEBLOCKS/UPDATE_CONNECTION\",\n UPDATE_OTHERS: \"@@LIVEBLOCKS/UPDATE_OTHERS\",\n};\n\ntype LiveblocksContext<P extends JsonObject, U extends BaseUserMeta> = {\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 Redux state.\n */\nexport type WithLiveblocks<\n TState,\n P extends JsonObject,\n U extends BaseUserMeta,\n> = TState & { readonly liveblocks: LiveblocksContext<P, U> };\n\nconst internalEnhancer = <TState>(options: {\n client: OpaqueClient;\n storageMapping?: Mapping<TState>;\n presenceMapping?: Mapping<TState>;\n}) => {\n if (process.env.NODE_ENV !== \"production\" && options.client == null) {\n throw missingClient();\n }\n const client = options.client;\n const storageMapping = validateMapping(\n options.storageMapping || {},\n \"storageMapping\"\n );\n const presenceMapping = validateMapping(\n options.presenceMapping || {},\n \"presenceMapping\"\n );\n if (process.env.NODE_ENV !== \"production\") {\n validateNoDuplicateKeys(storageMapping, presenceMapping);\n }\n const presenceKeys = Object.keys(presenceMapping);\n\n return (createStore: any) => {\n return (reducer: any, initialState: any, enhancer: any) => {\n let maybeRoom: OpaqueRoom | null = null;\n let isPatching = false;\n let storageRoot: LiveObject<LsonObject> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n let lastRoomId: string | null = null;\n let lastLeaveFn: (() => void) | null = null;\n\n const newReducer = (state: any, action: any) => {\n switch (action.type) {\n case ACTION_TYPES.PATCH_REDUX_STATE:\n return {\n ...state,\n ...action.state,\n };\n case ACTION_TYPES.INIT_STORAGE:\n return {\n ...state,\n ...action.state,\n liveblocks: {\n ...state.liveblocks,\n isStorageLoading: false,\n },\n };\n case ACTION_TYPES.START_LOADING_STORAGE:\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n isStorageLoading: true,\n },\n };\n case ACTION_TYPES.UPDATE_CONNECTION: {\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n connection: action.connection,\n status: action.status,\n },\n };\n }\n case ACTION_TYPES.UPDATE_OTHERS: {\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n others: action.others,\n },\n };\n }\n default: {\n const newState = reducer(state, action);\n\n if (maybeRoom) {\n isPatching = true;\n try {\n updatePresence(\n maybeRoom,\n state,\n newState,\n presenceMapping as any\n );\n\n maybeRoom.batch(() => {\n if (storageRoot) {\n patchLiveblocksStorage(\n storageRoot,\n state,\n newState,\n storageMapping as any\n );\n }\n });\n } finally {\n isPatching = false;\n }\n }\n\n if (newState.liveblocks == null) {\n return {\n ...newState,\n liveblocks: {\n others: [],\n isStorageLoading: false,\n connection: \"closed\",\n status: \"initial\",\n },\n };\n }\n return newState;\n }\n }\n };\n\n const store = createStore(newReducer, initialState, enhancer);\n\n function enterRoom(\n newRoomId: string,\n options?: Pick<EnterOptions, \"engine\">\n ): 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 = pick(store.getState(), presenceKeys) as any;\n\n const { room, leave } = client.enterRoom(newRoomId, {\n engine: options?.engine,\n initialPresence,\n });\n maybeRoom = room as OpaqueRoom;\n\n unsubscribeCallbacks.push(\n room.events.status.subscribe((status) => {\n store.dispatch({\n type: ACTION_TYPES.UPDATE_CONNECTION,\n status,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.others.subscribe(({ others }) => {\n store.dispatch({\n type: ACTION_TYPES.UPDATE_OTHERS,\n others,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.myPresence.subscribe(() => {\n if (!isPatching) {\n store.dispatch({\n type: ACTION_TYPES.PATCH_REDUX_STATE,\n state: pick(room.getPresence(), presenceKeys),\n });\n }\n })\n );\n\n store.dispatch({\n type: ACTION_TYPES.START_LOADING_STORAGE,\n });\n\n void room.getStorage().then(({ root }) => {\n const updates: any = {};\n\n maybeRoom!.batch(() => {\n for (const key in storageMapping) {\n const liveblocksStatePart = root.get(key);\n if (liveblocksStatePart == null) {\n updates[key] = store.getState()[key];\n legacy_patchLiveObjectKey(\n root,\n key,\n undefined,\n store.getState()[key]\n );\n } else {\n updates[key] = lsonToJson(liveblocksStatePart);\n }\n }\n });\n\n store.dispatch({\n type: ACTION_TYPES.INIT_STORAGE,\n state: updates,\n });\n\n storageRoot = root;\n unsubscribeCallbacks.push(\n maybeRoom!.events.storageBatch.subscribe((updates) => {\n if (!isPatching) {\n store.dispatch({\n type: ACTION_TYPES.PATCH_REDUX_STATE,\n state: patchState(\n store.getState(),\n updates,\n storageMapping as any\n ),\n });\n }\n })\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 }\n\n function leaveRoom() {\n lastLeaveFn?.();\n }\n\n function newDispatch(action: any) {\n if (action.type === ACTION_TYPES.ENTER) {\n enterRoom(action.roomId, action.options);\n } else if (action.type === ACTION_TYPES.LEAVE) {\n leaveRoom();\n } else {\n store.dispatch(action);\n }\n }\n\n return {\n ...store,\n dispatch: newDispatch,\n };\n };\n };\n};\n\n/**\n * Actions used to interact with Liveblocks\n */\nexport const actions = {\n /**\n * Enters a room and starts sync it with Redux state\n * @param roomId The id of the room\n * @param options Optional. Options to pass to the underlying client.enterRoom call (e.g. `engine`).\n */\n enterRoom,\n /**\n * Leaves the currently entered room and stops sync it with Redux state.\n */\n leaveRoom,\n};\n\nfunction enterRoom(\n roomId: string,\n options?: Pick<EnterOptions, \"engine\">\n): {\n type: string;\n roomId: string;\n options?: Pick<EnterOptions, \"engine\">;\n} {\n return {\n type: ACTION_TYPES.ENTER,\n roomId,\n options,\n };\n}\n\nfunction leaveRoom(): {\n type: string;\n} {\n return { type: ACTION_TYPES.LEAVE };\n}\n\n/**\n * Redux store enhancer that will make the `liveblocks` key available on your\n * Redux store.\n */\nexport const liveblocksEnhancer = internalEnhancer as <TState>(options: {\n client: OpaqueClient;\n storageMapping?: Mapping<TState>;\n presenceMapping?: Mapping<TState>;\n}) => StoreEnhancer;\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(\"value\");\n }\n\n if (oldState[key] !== newState[key]) {\n const oldVal = oldState[key];\n const newVal = newState[key];\n legacy_patchLiveObjectKey(root, key, oldVal as any, newVal);\n }\n }\n}\n\nfunction updatePresence<P extends JsonObject>(\n room: Room<P, any, any, any, any>,\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(\"value\");\n }\n\n if (oldState[key] !== newState[key]) {\n room.updatePresence({ [key]: newState[key] } as P);\n }\n }\n}\n\nfunction isObject(value: any): value is object {\n return Object.prototype.toString.call(value) === \"[object Object]\";\n}\n\nfunction validateNoDuplicateKeys<TState>(\n storageMapping: Mapping<TState>,\n presenceMapping: Mapping<TState>\n) {\n for (const key in storageMapping) {\n if (presenceMapping[key] !== undefined) {\n throw mappingShouldNotHaveTheSameKeys(key);\n }\n }\n}\n\nfunction pick(\n source: Record<string, unknown>,\n keys: Iterable<string>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const key of keys) {\n result[key] = source[key];\n }\n return result;\n}\n\nfunction patchState<TState extends JsonObject>(\n state: TState,\n updates: any[], // StorageUpdate\n mapping: Mapping<TState>\n) {\n const partialState: Partial<TState> = {};\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<TState> = {};\n\n for (const key in mapping) {\n result[key] = patched[key];\n }\n\n return result;\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<TState>(\n mapping: Mapping<TState>,\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Mapping<TState> {\n if (process.env.NODE_ENV !== \"production\") {\n if (!isObject(mapping)) {\n throw mappingShouldBeAnObject(mappingType);\n }\n }\n\n const result: Mapping<TState> = {};\n for (const key in mapping) {\n if (\n process.env.NODE_ENV !== \"production\" &&\n typeof mapping[key] !== \"boolean\"\n ) {\n throw mappingValueShouldBeABoolean(mappingType, key);\n }\n\n if (mapping[key] === true) {\n result[key] = true;\n }\n }\n return result;\n}\n","export const ERROR_PREFIX = \"Invalid @liveblocks/redux middleware config.\";\n\nexport function missingClient(): Error {\n return new Error(`${ERROR_PREFIX} client is missing`);\n}\n\nexport function mappingShouldBeAnObject(\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Error {\n return new Error(\n `${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`\n );\n}\n\nexport function mappingValueShouldBeABoolean(\n mappingType: \"storageMapping\" | \"presenceMapping\",\n key: string\n): Error {\n return new Error(\n `${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`\n );\n}\n\nexport function mappingShouldNotHaveTheSameKeys(key: string): Error {\n return new Error(\n `${ERROR_PREFIX} \"${key}\" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.`\n );\n}\n\nexport function 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","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/redux\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/liveblocks/liveblocks/packages/liveblocks-redux/dist/index.cjs","../src/index.ts","../src/errors.ts","../src/version.ts"],"names":["enterRoom","options","leaveRoom"],"mappings":"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","file":"/home/runner/work/liveblocks/liveblocks/packages/liveblocks-redux/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 { EnterOptions, OpaqueClient, OpaqueRoom } from \"@liveblocks/core\";\nimport { detectDupes, kInternal } from \"@liveblocks/core\";\nimport type { StoreEnhancer } from \"redux\";\n\nimport {\n mappingShouldBeAnObject,\n mappingShouldNotHaveTheSameKeys,\n mappingToFunctionIsNotAllowed,\n mappingValueShouldBeABoolean,\n missingClient,\n} from \"./errors\";\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type Mapping<T> = {\n [K in keyof T]?: boolean;\n};\n\nconst ACTION_TYPES = {\n ENTER: \"@@LIVEBLOCKS/ENTER\",\n LEAVE: \"@@LIVEBLOCKS/LEAVE\",\n START_LOADING_STORAGE: \"@@LIVEBLOCKS/START_LOADING_STORAGE\",\n INIT_STORAGE: \"@@LIVEBLOCKS/INIT_STORAGE\",\n PATCH_REDUX_STATE: \"@@LIVEBLOCKS/PATCH_REDUX_STATE\",\n UPDATE_CONNECTION: \"@@LIVEBLOCKS/UPDATE_CONNECTION\",\n UPDATE_OTHERS: \"@@LIVEBLOCKS/UPDATE_OTHERS\",\n};\n\ntype LiveblocksContext<P extends JsonObject, U extends BaseUserMeta> = {\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 Redux state.\n */\nexport type WithLiveblocks<\n TState,\n P extends JsonObject,\n U extends BaseUserMeta,\n> = TState & { readonly liveblocks: LiveblocksContext<P, U> };\n\n/** Ensures values of the provided object are not functions */\nfunction ensureNoFunctions(state: Record<string, unknown>): void {\n for (const key in state) {\n if (typeof state[key] === \"function\") {\n throw mappingToFunctionIsNotAllowed(key);\n }\n }\n}\n\nconst internalEnhancer = <TState>(options: {\n client: OpaqueClient;\n storageMapping?: Mapping<TState>;\n presenceMapping?: Mapping<TState>;\n}) => {\n if (process.env.NODE_ENV !== \"production\" && options.client == null) {\n throw missingClient();\n }\n const client = options.client;\n const storageMapping = validateMapping(\n options.storageMapping || {},\n \"storageMapping\"\n );\n const presenceMapping = validateMapping(\n options.presenceMapping || {},\n \"presenceMapping\"\n );\n if (process.env.NODE_ENV !== \"production\") {\n validateNoDuplicateKeys(storageMapping, presenceMapping);\n }\n const presenceKeys = Object.keys(presenceMapping);\n const storageKeys = Object.keys(storageMapping);\n\n return (createStore: any) => {\n return (reducer: any, initialState: any, enhancer: any) => {\n let maybeRoom: OpaqueRoom | null = null;\n let isPatching = false;\n let storageRoot: LiveObject<LsonObject> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n let lastRoomId: string | null = null;\n let lastLeaveFn: (() => void) | null = null;\n\n const newReducer = (state: any, action: any) => {\n switch (action.type) {\n case ACTION_TYPES.PATCH_REDUX_STATE:\n return {\n ...state,\n ...action.state,\n };\n case ACTION_TYPES.INIT_STORAGE:\n return {\n ...state,\n ...action.state,\n liveblocks: {\n ...state.liveblocks,\n isStorageLoading: false,\n },\n };\n case ACTION_TYPES.START_LOADING_STORAGE:\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n isStorageLoading: true,\n },\n };\n case ACTION_TYPES.UPDATE_CONNECTION: {\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n connection: action.connection,\n status: action.status,\n },\n };\n }\n case ACTION_TYPES.UPDATE_OTHERS: {\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n others: action.others,\n },\n };\n }\n default: {\n const newState = reducer(state, action);\n\n if (maybeRoom) {\n isPatching = true;\n try {\n maybeRoom.batch(() => {\n updatePresence(\n maybeRoom!,\n state,\n newState,\n presenceMapping as any\n );\n\n if (storageRoot) {\n const partialState = pick(\n newState,\n storageKeys\n ) as JsonObject;\n if (process.env.NODE_ENV !== \"production\") {\n ensureNoFunctions(partialState);\n }\n storageRoot.reconcilePartially(partialState);\n }\n });\n } finally {\n isPatching = false;\n }\n }\n\n if (newState.liveblocks == null) {\n return {\n ...newState,\n liveblocks: {\n others: [],\n isStorageLoading: false,\n connection: \"closed\",\n status: \"initial\",\n },\n };\n }\n return newState;\n }\n }\n };\n\n const store = createStore(newReducer, initialState, enhancer);\n\n function enterRoom(\n newRoomId: string,\n options?: Pick<EnterOptions, \"engine\">\n ): 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 = pick(store.getState(), presenceKeys) as any;\n\n const { room, leave } = client.enterRoom(newRoomId, {\n engine: options?.engine,\n initialPresence,\n });\n maybeRoom = room as OpaqueRoom;\n\n unsubscribeCallbacks.push(\n room.events.status.subscribe((status) => {\n store.dispatch({\n type: ACTION_TYPES.UPDATE_CONNECTION,\n status,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.others.subscribe(({ others }) => {\n store.dispatch({\n type: ACTION_TYPES.UPDATE_OTHERS,\n others,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.myPresence.subscribe(() => {\n if (!isPatching) {\n store.dispatch({\n type: ACTION_TYPES.PATCH_REDUX_STATE,\n state: pick(room.getPresence(), presenceKeys),\n });\n }\n })\n );\n\n store.dispatch({\n type: ACTION_TYPES.START_LOADING_STORAGE,\n });\n\n void room.getStorage().then(({ root }) => {\n // Seed any missing storage keys from the current Redux state.\n // Only writes keys that don't exist yet in storage — existing\n // storage values are left untouched and will be read back below.\n const reduxState = store.getState();\n const missing: JsonObject = {};\n for (const key of storageKeys) {\n if (root.get(key) == null) {\n missing[key] = reduxState[key] as Json;\n }\n }\n\n room.history[kInternal].withoutHistory(() => {\n maybeRoom!.batch(() => {\n root.reconcilePartially(missing);\n });\n });\n\n store.dispatch({\n type: ACTION_TYPES.INIT_STORAGE,\n state: pick(root.toJSON(), storageKeys),\n });\n\n storageRoot = root;\n unsubscribeCallbacks.push(\n maybeRoom!.events.storageBatch.subscribe(() => {\n if (!isPatching) {\n store.dispatch({\n type: ACTION_TYPES.PATCH_REDUX_STATE,\n state: pick(root.toJSON(), storageKeys),\n });\n }\n })\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 }\n\n function leaveRoom() {\n lastLeaveFn?.();\n }\n\n function newDispatch(action: any) {\n if (action.type === ACTION_TYPES.ENTER) {\n enterRoom(action.roomId, action.options);\n } else if (action.type === ACTION_TYPES.LEAVE) {\n leaveRoom();\n } else {\n store.dispatch(action);\n }\n }\n\n return {\n ...store,\n dispatch: newDispatch,\n };\n };\n };\n};\n\n/**\n * Actions used to interact with Liveblocks\n */\nexport const actions = {\n /**\n * Enters a room and starts sync it with Redux state\n * @param roomId The id of the room\n * @param options Optional. Options to pass to the underlying client.enterRoom call (e.g. `engine`).\n */\n enterRoom,\n /**\n * Leaves the currently entered room and stops sync it with Redux state.\n */\n leaveRoom,\n};\n\nfunction enterRoom(\n roomId: string,\n options?: Pick<EnterOptions, \"engine\">\n): {\n type: string;\n roomId: string;\n options?: Pick<EnterOptions, \"engine\">;\n} {\n return {\n type: ACTION_TYPES.ENTER,\n roomId,\n options,\n };\n}\n\nfunction leaveRoom(): {\n type: string;\n} {\n return { type: ACTION_TYPES.LEAVE };\n}\n\n/**\n * Redux store enhancer that will make the `liveblocks` key available on your\n * Redux store.\n */\nexport const liveblocksEnhancer = internalEnhancer as <TState>(options: {\n client: OpaqueClient;\n storageMapping?: Mapping<TState>;\n presenceMapping?: Mapping<TState>;\n}) => StoreEnhancer;\n\nfunction updatePresence<P extends JsonObject>(\n room: Room<P, any, any, any, any>,\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(\"value\");\n }\n\n if (oldState[key] !== newState[key]) {\n room.updatePresence({ [key]: newState[key] } as P);\n }\n }\n}\n\nfunction isObject(value: any): value is object {\n return Object.prototype.toString.call(value) === \"[object Object]\";\n}\n\nfunction validateNoDuplicateKeys<TState>(\n storageMapping: Mapping<TState>,\n presenceMapping: Mapping<TState>\n) {\n for (const key in storageMapping) {\n if (presenceMapping[key] !== undefined) {\n throw mappingShouldNotHaveTheSameKeys(key);\n }\n }\n}\n\nfunction pick(\n source: Record<string, unknown>,\n keys: Iterable<string>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const key of keys) {\n result[key] = source[key];\n }\n return result;\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<TState>(\n mapping: Mapping<TState>,\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Mapping<TState> {\n if (process.env.NODE_ENV !== \"production\") {\n if (!isObject(mapping)) {\n throw mappingShouldBeAnObject(mappingType);\n }\n }\n\n const result: Mapping<TState> = {};\n for (const key in mapping) {\n if (\n process.env.NODE_ENV !== \"production\" &&\n typeof mapping[key] !== \"boolean\"\n ) {\n throw mappingValueShouldBeABoolean(mappingType, key);\n }\n\n if (mapping[key] === true) {\n result[key] = true;\n }\n }\n return result;\n}\n","export const ERROR_PREFIX = \"Invalid @liveblocks/redux middleware config.\";\n\nexport function missingClient(): Error {\n return new Error(`${ERROR_PREFIX} client is missing`);\n}\n\nexport function mappingShouldBeAnObject(\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Error {\n return new Error(\n `${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`\n );\n}\n\nexport function mappingValueShouldBeABoolean(\n mappingType: \"storageMapping\" | \"presenceMapping\",\n key: string\n): Error {\n return new Error(\n `${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`\n );\n}\n\nexport function mappingShouldNotHaveTheSameKeys(key: string): Error {\n return new Error(\n `${ERROR_PREFIX} \"${key}\" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.`\n );\n}\n\nexport function 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","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/redux\";\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,10 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import {
|
|
3
|
-
detectDupes,
|
|
4
|
-
legacy_patchImmutableObject,
|
|
5
|
-
legacy_patchLiveObjectKey,
|
|
6
|
-
lsonToJson
|
|
7
|
-
} from "@liveblocks/core";
|
|
2
|
+
import { detectDupes, kInternal } from "@liveblocks/core";
|
|
8
3
|
|
|
9
4
|
// src/errors.ts
|
|
10
5
|
var ERROR_PREFIX = "Invalid @liveblocks/redux middleware config.";
|
|
@@ -34,7 +29,7 @@ function mappingToFunctionIsNotAllowed(key) {
|
|
|
34
29
|
|
|
35
30
|
// src/version.ts
|
|
36
31
|
var PKG_NAME = "@liveblocks/redux";
|
|
37
|
-
var PKG_VERSION = "3.
|
|
32
|
+
var PKG_VERSION = "3.18.0-rc1";
|
|
38
33
|
var PKG_FORMAT = "esm";
|
|
39
34
|
|
|
40
35
|
// src/index.ts
|
|
@@ -48,6 +43,13 @@ var ACTION_TYPES = {
|
|
|
48
43
|
UPDATE_CONNECTION: "@@LIVEBLOCKS/UPDATE_CONNECTION",
|
|
49
44
|
UPDATE_OTHERS: "@@LIVEBLOCKS/UPDATE_OTHERS"
|
|
50
45
|
};
|
|
46
|
+
function ensureNoFunctions(state) {
|
|
47
|
+
for (const key in state) {
|
|
48
|
+
if (typeof state[key] === "function") {
|
|
49
|
+
throw mappingToFunctionIsNotAllowed(key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
51
53
|
var internalEnhancer = (options) => {
|
|
52
54
|
if (process.env.NODE_ENV !== "production" && options.client == null) {
|
|
53
55
|
throw missingClient();
|
|
@@ -65,6 +67,7 @@ var internalEnhancer = (options) => {
|
|
|
65
67
|
validateNoDuplicateKeys(storageMapping, presenceMapping);
|
|
66
68
|
}
|
|
67
69
|
const presenceKeys = Object.keys(presenceMapping);
|
|
70
|
+
const storageKeys = Object.keys(storageMapping);
|
|
68
71
|
return (createStore) => {
|
|
69
72
|
return (reducer, initialState, enhancer) => {
|
|
70
73
|
let maybeRoom = null;
|
|
@@ -121,20 +124,22 @@ var internalEnhancer = (options) => {
|
|
|
121
124
|
if (maybeRoom) {
|
|
122
125
|
isPatching = true;
|
|
123
126
|
try {
|
|
124
|
-
updatePresence(
|
|
125
|
-
maybeRoom,
|
|
126
|
-
state,
|
|
127
|
-
newState,
|
|
128
|
-
presenceMapping
|
|
129
|
-
);
|
|
130
127
|
maybeRoom.batch(() => {
|
|
128
|
+
updatePresence(
|
|
129
|
+
maybeRoom,
|
|
130
|
+
state,
|
|
131
|
+
newState,
|
|
132
|
+
presenceMapping
|
|
133
|
+
);
|
|
131
134
|
if (storageRoot) {
|
|
132
|
-
|
|
133
|
-
storageRoot,
|
|
134
|
-
state,
|
|
135
|
+
const partialState = pick(
|
|
135
136
|
newState,
|
|
136
|
-
|
|
137
|
+
storageKeys
|
|
137
138
|
);
|
|
139
|
+
if (process.env.NODE_ENV !== "production") {
|
|
140
|
+
ensureNoFunctions(partialState);
|
|
141
|
+
}
|
|
142
|
+
storageRoot.reconcilePartially(partialState);
|
|
138
143
|
}
|
|
139
144
|
});
|
|
140
145
|
} finally {
|
|
@@ -201,38 +206,29 @@ var internalEnhancer = (options) => {
|
|
|
201
206
|
type: ACTION_TYPES.START_LOADING_STORAGE
|
|
202
207
|
});
|
|
203
208
|
void room.getStorage().then(({ root }) => {
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
updates[key] = store.getState()[key];
|
|
210
|
-
legacy_patchLiveObjectKey(
|
|
211
|
-
root,
|
|
212
|
-
key,
|
|
213
|
-
void 0,
|
|
214
|
-
store.getState()[key]
|
|
215
|
-
);
|
|
216
|
-
} else {
|
|
217
|
-
updates[key] = lsonToJson(liveblocksStatePart);
|
|
218
|
-
}
|
|
209
|
+
const reduxState = store.getState();
|
|
210
|
+
const missing = {};
|
|
211
|
+
for (const key of storageKeys) {
|
|
212
|
+
if (root.get(key) == null) {
|
|
213
|
+
missing[key] = reduxState[key];
|
|
219
214
|
}
|
|
215
|
+
}
|
|
216
|
+
room.history[kInternal].withoutHistory(() => {
|
|
217
|
+
maybeRoom.batch(() => {
|
|
218
|
+
root.reconcilePartially(missing);
|
|
219
|
+
});
|
|
220
220
|
});
|
|
221
221
|
store.dispatch({
|
|
222
222
|
type: ACTION_TYPES.INIT_STORAGE,
|
|
223
|
-
state:
|
|
223
|
+
state: pick(root.toJSON(), storageKeys)
|
|
224
224
|
});
|
|
225
225
|
storageRoot = root;
|
|
226
226
|
unsubscribeCallbacks.push(
|
|
227
|
-
maybeRoom.events.storageBatch.subscribe((
|
|
227
|
+
maybeRoom.events.storageBatch.subscribe(() => {
|
|
228
228
|
if (!isPatching) {
|
|
229
229
|
store.dispatch({
|
|
230
230
|
type: ACTION_TYPES.PATCH_REDUX_STATE,
|
|
231
|
-
state:
|
|
232
|
-
store.getState(),
|
|
233
|
-
updates2,
|
|
234
|
-
storageMapping
|
|
235
|
-
)
|
|
231
|
+
state: pick(root.toJSON(), storageKeys)
|
|
236
232
|
});
|
|
237
233
|
}
|
|
238
234
|
})
|
|
@@ -293,18 +289,6 @@ function leaveRoom() {
|
|
|
293
289
|
return { type: ACTION_TYPES.LEAVE };
|
|
294
290
|
}
|
|
295
291
|
var liveblocksEnhancer = internalEnhancer;
|
|
296
|
-
function patchLiveblocksStorage(root, oldState, newState, mapping) {
|
|
297
|
-
for (const key in mapping) {
|
|
298
|
-
if (process.env.NODE_ENV !== "production" && typeof newState[key] === "function") {
|
|
299
|
-
throw mappingToFunctionIsNotAllowed("value");
|
|
300
|
-
}
|
|
301
|
-
if (oldState[key] !== newState[key]) {
|
|
302
|
-
const oldVal = oldState[key];
|
|
303
|
-
const newVal = newState[key];
|
|
304
|
-
legacy_patchLiveObjectKey(root, key, oldVal, newVal);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
292
|
function updatePresence(room, oldState, newState, presenceMapping) {
|
|
309
293
|
for (const key in presenceMapping) {
|
|
310
294
|
if (typeof newState[key] === "function") {
|
|
@@ -332,18 +316,6 @@ function pick(source, keys) {
|
|
|
332
316
|
}
|
|
333
317
|
return result;
|
|
334
318
|
}
|
|
335
|
-
function patchState(state, updates, mapping) {
|
|
336
|
-
const partialState = {};
|
|
337
|
-
for (const key in mapping) {
|
|
338
|
-
partialState[key] = state[key];
|
|
339
|
-
}
|
|
340
|
-
const patched = legacy_patchImmutableObject(partialState, updates);
|
|
341
|
-
const result = {};
|
|
342
|
-
for (const key in mapping) {
|
|
343
|
-
result[key] = patched[key];
|
|
344
|
-
}
|
|
345
|
-
return result;
|
|
346
|
-
}
|
|
347
319
|
function validateMapping(mapping, mappingType) {
|
|
348
320
|
if (process.env.NODE_ENV !== "production") {
|
|
349
321
|
if (!isObject(mapping)) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/version.ts"],"sourcesContent":["import type {\n BaseUserMeta,\n JsonObject,\n LiveObject,\n LsonObject,\n Room,\n Status,\n User,\n} from \"@liveblocks/client\";\nimport type { EnterOptions, OpaqueClient, OpaqueRoom } from \"@liveblocks/core\";\nimport {\n detectDupes,\n legacy_patchImmutableObject,\n legacy_patchLiveObjectKey,\n lsonToJson,\n} from \"@liveblocks/core\";\nimport type { StoreEnhancer } from \"redux\";\n\nimport {\n mappingShouldBeAnObject,\n mappingShouldNotHaveTheSameKeys,\n mappingToFunctionIsNotAllowed,\n mappingValueShouldBeABoolean,\n missingClient,\n} from \"./errors\";\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type Mapping<T> = {\n [K in keyof T]?: boolean;\n};\n\nconst ACTION_TYPES = {\n ENTER: \"@@LIVEBLOCKS/ENTER\",\n LEAVE: \"@@LIVEBLOCKS/LEAVE\",\n START_LOADING_STORAGE: \"@@LIVEBLOCKS/START_LOADING_STORAGE\",\n INIT_STORAGE: \"@@LIVEBLOCKS/INIT_STORAGE\",\n PATCH_REDUX_STATE: \"@@LIVEBLOCKS/PATCH_REDUX_STATE\",\n UPDATE_CONNECTION: \"@@LIVEBLOCKS/UPDATE_CONNECTION\",\n UPDATE_OTHERS: \"@@LIVEBLOCKS/UPDATE_OTHERS\",\n};\n\ntype LiveblocksContext<P extends JsonObject, U extends BaseUserMeta> = {\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 Redux state.\n */\nexport type WithLiveblocks<\n TState,\n P extends JsonObject,\n U extends BaseUserMeta,\n> = TState & { readonly liveblocks: LiveblocksContext<P, U> };\n\nconst internalEnhancer = <TState>(options: {\n client: OpaqueClient;\n storageMapping?: Mapping<TState>;\n presenceMapping?: Mapping<TState>;\n}) => {\n if (process.env.NODE_ENV !== \"production\" && options.client == null) {\n throw missingClient();\n }\n const client = options.client;\n const storageMapping = validateMapping(\n options.storageMapping || {},\n \"storageMapping\"\n );\n const presenceMapping = validateMapping(\n options.presenceMapping || {},\n \"presenceMapping\"\n );\n if (process.env.NODE_ENV !== \"production\") {\n validateNoDuplicateKeys(storageMapping, presenceMapping);\n }\n const presenceKeys = Object.keys(presenceMapping);\n\n return (createStore: any) => {\n return (reducer: any, initialState: any, enhancer: any) => {\n let maybeRoom: OpaqueRoom | null = null;\n let isPatching = false;\n let storageRoot: LiveObject<LsonObject> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n let lastRoomId: string | null = null;\n let lastLeaveFn: (() => void) | null = null;\n\n const newReducer = (state: any, action: any) => {\n switch (action.type) {\n case ACTION_TYPES.PATCH_REDUX_STATE:\n return {\n ...state,\n ...action.state,\n };\n case ACTION_TYPES.INIT_STORAGE:\n return {\n ...state,\n ...action.state,\n liveblocks: {\n ...state.liveblocks,\n isStorageLoading: false,\n },\n };\n case ACTION_TYPES.START_LOADING_STORAGE:\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n isStorageLoading: true,\n },\n };\n case ACTION_TYPES.UPDATE_CONNECTION: {\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n connection: action.connection,\n status: action.status,\n },\n };\n }\n case ACTION_TYPES.UPDATE_OTHERS: {\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n others: action.others,\n },\n };\n }\n default: {\n const newState = reducer(state, action);\n\n if (maybeRoom) {\n isPatching = true;\n try {\n updatePresence(\n maybeRoom,\n state,\n newState,\n presenceMapping as any\n );\n\n maybeRoom.batch(() => {\n if (storageRoot) {\n patchLiveblocksStorage(\n storageRoot,\n state,\n newState,\n storageMapping as any\n );\n }\n });\n } finally {\n isPatching = false;\n }\n }\n\n if (newState.liveblocks == null) {\n return {\n ...newState,\n liveblocks: {\n others: [],\n isStorageLoading: false,\n connection: \"closed\",\n status: \"initial\",\n },\n };\n }\n return newState;\n }\n }\n };\n\n const store = createStore(newReducer, initialState, enhancer);\n\n function enterRoom(\n newRoomId: string,\n options?: Pick<EnterOptions, \"engine\">\n ): 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 = pick(store.getState(), presenceKeys) as any;\n\n const { room, leave } = client.enterRoom(newRoomId, {\n engine: options?.engine,\n initialPresence,\n });\n maybeRoom = room as OpaqueRoom;\n\n unsubscribeCallbacks.push(\n room.events.status.subscribe((status) => {\n store.dispatch({\n type: ACTION_TYPES.UPDATE_CONNECTION,\n status,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.others.subscribe(({ others }) => {\n store.dispatch({\n type: ACTION_TYPES.UPDATE_OTHERS,\n others,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.myPresence.subscribe(() => {\n if (!isPatching) {\n store.dispatch({\n type: ACTION_TYPES.PATCH_REDUX_STATE,\n state: pick(room.getPresence(), presenceKeys),\n });\n }\n })\n );\n\n store.dispatch({\n type: ACTION_TYPES.START_LOADING_STORAGE,\n });\n\n void room.getStorage().then(({ root }) => {\n const updates: any = {};\n\n maybeRoom!.batch(() => {\n for (const key in storageMapping) {\n const liveblocksStatePart = root.get(key);\n if (liveblocksStatePart == null) {\n updates[key] = store.getState()[key];\n legacy_patchLiveObjectKey(\n root,\n key,\n undefined,\n store.getState()[key]\n );\n } else {\n updates[key] = lsonToJson(liveblocksStatePart);\n }\n }\n });\n\n store.dispatch({\n type: ACTION_TYPES.INIT_STORAGE,\n state: updates,\n });\n\n storageRoot = root;\n unsubscribeCallbacks.push(\n maybeRoom!.events.storageBatch.subscribe((updates) => {\n if (!isPatching) {\n store.dispatch({\n type: ACTION_TYPES.PATCH_REDUX_STATE,\n state: patchState(\n store.getState(),\n updates,\n storageMapping as any\n ),\n });\n }\n })\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 }\n\n function leaveRoom() {\n lastLeaveFn?.();\n }\n\n function newDispatch(action: any) {\n if (action.type === ACTION_TYPES.ENTER) {\n enterRoom(action.roomId, action.options);\n } else if (action.type === ACTION_TYPES.LEAVE) {\n leaveRoom();\n } else {\n store.dispatch(action);\n }\n }\n\n return {\n ...store,\n dispatch: newDispatch,\n };\n };\n };\n};\n\n/**\n * Actions used to interact with Liveblocks\n */\nexport const actions = {\n /**\n * Enters a room and starts sync it with Redux state\n * @param roomId The id of the room\n * @param options Optional. Options to pass to the underlying client.enterRoom call (e.g. `engine`).\n */\n enterRoom,\n /**\n * Leaves the currently entered room and stops sync it with Redux state.\n */\n leaveRoom,\n};\n\nfunction enterRoom(\n roomId: string,\n options?: Pick<EnterOptions, \"engine\">\n): {\n type: string;\n roomId: string;\n options?: Pick<EnterOptions, \"engine\">;\n} {\n return {\n type: ACTION_TYPES.ENTER,\n roomId,\n options,\n };\n}\n\nfunction leaveRoom(): {\n type: string;\n} {\n return { type: ACTION_TYPES.LEAVE };\n}\n\n/**\n * Redux store enhancer that will make the `liveblocks` key available on your\n * Redux store.\n */\nexport const liveblocksEnhancer = internalEnhancer as <TState>(options: {\n client: OpaqueClient;\n storageMapping?: Mapping<TState>;\n presenceMapping?: Mapping<TState>;\n}) => StoreEnhancer;\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(\"value\");\n }\n\n if (oldState[key] !== newState[key]) {\n const oldVal = oldState[key];\n const newVal = newState[key];\n legacy_patchLiveObjectKey(root, key, oldVal as any, newVal);\n }\n }\n}\n\nfunction updatePresence<P extends JsonObject>(\n room: Room<P, any, any, any, any>,\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(\"value\");\n }\n\n if (oldState[key] !== newState[key]) {\n room.updatePresence({ [key]: newState[key] } as P);\n }\n }\n}\n\nfunction isObject(value: any): value is object {\n return Object.prototype.toString.call(value) === \"[object Object]\";\n}\n\nfunction validateNoDuplicateKeys<TState>(\n storageMapping: Mapping<TState>,\n presenceMapping: Mapping<TState>\n) {\n for (const key in storageMapping) {\n if (presenceMapping[key] !== undefined) {\n throw mappingShouldNotHaveTheSameKeys(key);\n }\n }\n}\n\nfunction pick(\n source: Record<string, unknown>,\n keys: Iterable<string>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const key of keys) {\n result[key] = source[key];\n }\n return result;\n}\n\nfunction patchState<TState extends JsonObject>(\n state: TState,\n updates: any[], // StorageUpdate\n mapping: Mapping<TState>\n) {\n const partialState: Partial<TState> = {};\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<TState> = {};\n\n for (const key in mapping) {\n result[key] = patched[key];\n }\n\n return result;\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<TState>(\n mapping: Mapping<TState>,\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Mapping<TState> {\n if (process.env.NODE_ENV !== \"production\") {\n if (!isObject(mapping)) {\n throw mappingShouldBeAnObject(mappingType);\n }\n }\n\n const result: Mapping<TState> = {};\n for (const key in mapping) {\n if (\n process.env.NODE_ENV !== \"production\" &&\n typeof mapping[key] !== \"boolean\"\n ) {\n throw mappingValueShouldBeABoolean(mappingType, key);\n }\n\n if (mapping[key] === true) {\n result[key] = true;\n }\n }\n return result;\n}\n","export const ERROR_PREFIX = \"Invalid @liveblocks/redux middleware config.\";\n\nexport function missingClient(): Error {\n return new Error(`${ERROR_PREFIX} client is missing`);\n}\n\nexport function mappingShouldBeAnObject(\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Error {\n return new Error(\n `${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`\n );\n}\n\nexport function mappingValueShouldBeABoolean(\n mappingType: \"storageMapping\" | \"presenceMapping\",\n key: string\n): Error {\n return new Error(\n `${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`\n );\n}\n\nexport function mappingShouldNotHaveTheSameKeys(key: string): Error {\n return new Error(\n `${ERROR_PREFIX} \"${key}\" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.`\n );\n}\n\nexport function 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","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/redux\";\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":["enterRoom","options","updates","leaveRoom"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.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 { EnterOptions, OpaqueClient, OpaqueRoom } from \"@liveblocks/core\";\nimport { detectDupes, kInternal } from \"@liveblocks/core\";\nimport type { StoreEnhancer } from \"redux\";\n\nimport {\n mappingShouldBeAnObject,\n mappingShouldNotHaveTheSameKeys,\n mappingToFunctionIsNotAllowed,\n mappingValueShouldBeABoolean,\n missingClient,\n} from \"./errors\";\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type Mapping<T> = {\n [K in keyof T]?: boolean;\n};\n\nconst ACTION_TYPES = {\n ENTER: \"@@LIVEBLOCKS/ENTER\",\n LEAVE: \"@@LIVEBLOCKS/LEAVE\",\n START_LOADING_STORAGE: \"@@LIVEBLOCKS/START_LOADING_STORAGE\",\n INIT_STORAGE: \"@@LIVEBLOCKS/INIT_STORAGE\",\n PATCH_REDUX_STATE: \"@@LIVEBLOCKS/PATCH_REDUX_STATE\",\n UPDATE_CONNECTION: \"@@LIVEBLOCKS/UPDATE_CONNECTION\",\n UPDATE_OTHERS: \"@@LIVEBLOCKS/UPDATE_OTHERS\",\n};\n\ntype LiveblocksContext<P extends JsonObject, U extends BaseUserMeta> = {\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 Redux state.\n */\nexport type WithLiveblocks<\n TState,\n P extends JsonObject,\n U extends BaseUserMeta,\n> = TState & { readonly liveblocks: LiveblocksContext<P, U> };\n\n/** Ensures values of the provided object are not functions */\nfunction ensureNoFunctions(state: Record<string, unknown>): void {\n for (const key in state) {\n if (typeof state[key] === \"function\") {\n throw mappingToFunctionIsNotAllowed(key);\n }\n }\n}\n\nconst internalEnhancer = <TState>(options: {\n client: OpaqueClient;\n storageMapping?: Mapping<TState>;\n presenceMapping?: Mapping<TState>;\n}) => {\n if (process.env.NODE_ENV !== \"production\" && options.client == null) {\n throw missingClient();\n }\n const client = options.client;\n const storageMapping = validateMapping(\n options.storageMapping || {},\n \"storageMapping\"\n );\n const presenceMapping = validateMapping(\n options.presenceMapping || {},\n \"presenceMapping\"\n );\n if (process.env.NODE_ENV !== \"production\") {\n validateNoDuplicateKeys(storageMapping, presenceMapping);\n }\n const presenceKeys = Object.keys(presenceMapping);\n const storageKeys = Object.keys(storageMapping);\n\n return (createStore: any) => {\n return (reducer: any, initialState: any, enhancer: any) => {\n let maybeRoom: OpaqueRoom | null = null;\n let isPatching = false;\n let storageRoot: LiveObject<LsonObject> | null = null;\n let unsubscribeCallbacks: Array<() => void> = [];\n let lastRoomId: string | null = null;\n let lastLeaveFn: (() => void) | null = null;\n\n const newReducer = (state: any, action: any) => {\n switch (action.type) {\n case ACTION_TYPES.PATCH_REDUX_STATE:\n return {\n ...state,\n ...action.state,\n };\n case ACTION_TYPES.INIT_STORAGE:\n return {\n ...state,\n ...action.state,\n liveblocks: {\n ...state.liveblocks,\n isStorageLoading: false,\n },\n };\n case ACTION_TYPES.START_LOADING_STORAGE:\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n isStorageLoading: true,\n },\n };\n case ACTION_TYPES.UPDATE_CONNECTION: {\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n connection: action.connection,\n status: action.status,\n },\n };\n }\n case ACTION_TYPES.UPDATE_OTHERS: {\n return {\n ...state,\n liveblocks: {\n ...state.liveblocks,\n others: action.others,\n },\n };\n }\n default: {\n const newState = reducer(state, action);\n\n if (maybeRoom) {\n isPatching = true;\n try {\n maybeRoom.batch(() => {\n updatePresence(\n maybeRoom!,\n state,\n newState,\n presenceMapping as any\n );\n\n if (storageRoot) {\n const partialState = pick(\n newState,\n storageKeys\n ) as JsonObject;\n if (process.env.NODE_ENV !== \"production\") {\n ensureNoFunctions(partialState);\n }\n storageRoot.reconcilePartially(partialState);\n }\n });\n } finally {\n isPatching = false;\n }\n }\n\n if (newState.liveblocks == null) {\n return {\n ...newState,\n liveblocks: {\n others: [],\n isStorageLoading: false,\n connection: \"closed\",\n status: \"initial\",\n },\n };\n }\n return newState;\n }\n }\n };\n\n const store = createStore(newReducer, initialState, enhancer);\n\n function enterRoom(\n newRoomId: string,\n options?: Pick<EnterOptions, \"engine\">\n ): 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 = pick(store.getState(), presenceKeys) as any;\n\n const { room, leave } = client.enterRoom(newRoomId, {\n engine: options?.engine,\n initialPresence,\n });\n maybeRoom = room as OpaqueRoom;\n\n unsubscribeCallbacks.push(\n room.events.status.subscribe((status) => {\n store.dispatch({\n type: ACTION_TYPES.UPDATE_CONNECTION,\n status,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.others.subscribe(({ others }) => {\n store.dispatch({\n type: ACTION_TYPES.UPDATE_OTHERS,\n others,\n });\n })\n );\n\n unsubscribeCallbacks.push(\n room.events.myPresence.subscribe(() => {\n if (!isPatching) {\n store.dispatch({\n type: ACTION_TYPES.PATCH_REDUX_STATE,\n state: pick(room.getPresence(), presenceKeys),\n });\n }\n })\n );\n\n store.dispatch({\n type: ACTION_TYPES.START_LOADING_STORAGE,\n });\n\n void room.getStorage().then(({ root }) => {\n // Seed any missing storage keys from the current Redux state.\n // Only writes keys that don't exist yet in storage — existing\n // storage values are left untouched and will be read back below.\n const reduxState = store.getState();\n const missing: JsonObject = {};\n for (const key of storageKeys) {\n if (root.get(key) == null) {\n missing[key] = reduxState[key] as Json;\n }\n }\n\n room.history[kInternal].withoutHistory(() => {\n maybeRoom!.batch(() => {\n root.reconcilePartially(missing);\n });\n });\n\n store.dispatch({\n type: ACTION_TYPES.INIT_STORAGE,\n state: pick(root.toJSON(), storageKeys),\n });\n\n storageRoot = root;\n unsubscribeCallbacks.push(\n maybeRoom!.events.storageBatch.subscribe(() => {\n if (!isPatching) {\n store.dispatch({\n type: ACTION_TYPES.PATCH_REDUX_STATE,\n state: pick(root.toJSON(), storageKeys),\n });\n }\n })\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 }\n\n function leaveRoom() {\n lastLeaveFn?.();\n }\n\n function newDispatch(action: any) {\n if (action.type === ACTION_TYPES.ENTER) {\n enterRoom(action.roomId, action.options);\n } else if (action.type === ACTION_TYPES.LEAVE) {\n leaveRoom();\n } else {\n store.dispatch(action);\n }\n }\n\n return {\n ...store,\n dispatch: newDispatch,\n };\n };\n };\n};\n\n/**\n * Actions used to interact with Liveblocks\n */\nexport const actions = {\n /**\n * Enters a room and starts sync it with Redux state\n * @param roomId The id of the room\n * @param options Optional. Options to pass to the underlying client.enterRoom call (e.g. `engine`).\n */\n enterRoom,\n /**\n * Leaves the currently entered room and stops sync it with Redux state.\n */\n leaveRoom,\n};\n\nfunction enterRoom(\n roomId: string,\n options?: Pick<EnterOptions, \"engine\">\n): {\n type: string;\n roomId: string;\n options?: Pick<EnterOptions, \"engine\">;\n} {\n return {\n type: ACTION_TYPES.ENTER,\n roomId,\n options,\n };\n}\n\nfunction leaveRoom(): {\n type: string;\n} {\n return { type: ACTION_TYPES.LEAVE };\n}\n\n/**\n * Redux store enhancer that will make the `liveblocks` key available on your\n * Redux store.\n */\nexport const liveblocksEnhancer = internalEnhancer as <TState>(options: {\n client: OpaqueClient;\n storageMapping?: Mapping<TState>;\n presenceMapping?: Mapping<TState>;\n}) => StoreEnhancer;\n\nfunction updatePresence<P extends JsonObject>(\n room: Room<P, any, any, any, any>,\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(\"value\");\n }\n\n if (oldState[key] !== newState[key]) {\n room.updatePresence({ [key]: newState[key] } as P);\n }\n }\n}\n\nfunction isObject(value: any): value is object {\n return Object.prototype.toString.call(value) === \"[object Object]\";\n}\n\nfunction validateNoDuplicateKeys<TState>(\n storageMapping: Mapping<TState>,\n presenceMapping: Mapping<TState>\n) {\n for (const key in storageMapping) {\n if (presenceMapping[key] !== undefined) {\n throw mappingShouldNotHaveTheSameKeys(key);\n }\n }\n}\n\nfunction pick(\n source: Record<string, unknown>,\n keys: Iterable<string>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const key of keys) {\n result[key] = source[key];\n }\n return result;\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<TState>(\n mapping: Mapping<TState>,\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Mapping<TState> {\n if (process.env.NODE_ENV !== \"production\") {\n if (!isObject(mapping)) {\n throw mappingShouldBeAnObject(mappingType);\n }\n }\n\n const result: Mapping<TState> = {};\n for (const key in mapping) {\n if (\n process.env.NODE_ENV !== \"production\" &&\n typeof mapping[key] !== \"boolean\"\n ) {\n throw mappingValueShouldBeABoolean(mappingType, key);\n }\n\n if (mapping[key] === true) {\n result[key] = true;\n }\n }\n return result;\n}\n","export const ERROR_PREFIX = \"Invalid @liveblocks/redux middleware config.\";\n\nexport function missingClient(): Error {\n return new Error(`${ERROR_PREFIX} client is missing`);\n}\n\nexport function mappingShouldBeAnObject(\n mappingType: \"storageMapping\" | \"presenceMapping\"\n): Error {\n return new Error(\n `${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`\n );\n}\n\nexport function mappingValueShouldBeABoolean(\n mappingType: \"storageMapping\" | \"presenceMapping\",\n key: string\n): Error {\n return new Error(\n `${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`\n );\n}\n\nexport function mappingShouldNotHaveTheSameKeys(key: string): Error {\n return new Error(\n `${ERROR_PREFIX} \"${key}\" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.`\n );\n}\n\nexport function 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","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/redux\";\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":["enterRoom","options","leaveRoom"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liveblocks/redux",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.18.0-rc1",
|
|
4
4
|
"description": "A store enhancer to integrate Liveblocks into Redux 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
|
"author": "Liveblocks Inc.",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"test:watch": "vitest"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@liveblocks/client": "3.
|
|
39
|
-
"@liveblocks/core": "3.
|
|
38
|
+
"@liveblocks/client": "3.18.0-rc1",
|
|
39
|
+
"@liveblocks/core": "3.18.0-rc1"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"redux": "^4 || ^5"
|