@liveblocks/redux 0.15.0-alpha.3
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/README.md +0 -0
- package/lib/esm/index.js +277 -0
- package/lib/esm/index.mjs +277 -0
- package/lib/index.d.ts +38 -0
- package/lib/index.js +377 -0
- package/package.json +63 -0
package/README.md
ADDED
|
File without changes
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { patchLiveObjectKey, liveNodeToJson, patchImmutableObject } from '@liveblocks/client';
|
|
2
|
+
|
|
3
|
+
const ERROR_PREFIX = "Invalid @liveblocks/redux middleware config.";
|
|
4
|
+
function missingClient() {
|
|
5
|
+
return new Error(`${ERROR_PREFIX} client is missing`);
|
|
6
|
+
}
|
|
7
|
+
function missingMapping(mappingType) {
|
|
8
|
+
return new Error(`${ERROR_PREFIX} ${mappingType} is missing.`);
|
|
9
|
+
}
|
|
10
|
+
function mappingShouldBeAnObject(mappingType) {
|
|
11
|
+
return new Error(`${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`);
|
|
12
|
+
}
|
|
13
|
+
function mappingValueShouldBeABoolean(mappingType, key) {
|
|
14
|
+
return new Error(`${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`);
|
|
15
|
+
}
|
|
16
|
+
function mappingShouldNotHaveTheSameKeys(key) {
|
|
17
|
+
return new Error(`${ERROR_PREFIX} "${key}" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.`);
|
|
18
|
+
}
|
|
19
|
+
function mappingToFunctionIsNotAllowed(key) {
|
|
20
|
+
return new Error(`${ERROR_PREFIX} mapping.${key} is invalid. Mapping to a function is not allowed.`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
var __defProp = Object.defineProperty;
|
|
24
|
+
var __defProps = Object.defineProperties;
|
|
25
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
26
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
27
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
28
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
29
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
30
|
+
var __spreadValues = (a, b) => {
|
|
31
|
+
for (var prop in b || (b = {}))
|
|
32
|
+
if (__hasOwnProp.call(b, prop))
|
|
33
|
+
__defNormalProp(a, prop, b[prop]);
|
|
34
|
+
if (__getOwnPropSymbols)
|
|
35
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
36
|
+
if (__propIsEnum.call(b, prop))
|
|
37
|
+
__defNormalProp(a, prop, b[prop]);
|
|
38
|
+
}
|
|
39
|
+
return a;
|
|
40
|
+
};
|
|
41
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
42
|
+
const ACTION_TYPES = {
|
|
43
|
+
ENTER: "@@LIVEBLOCKS/ENTER",
|
|
44
|
+
LEAVE: "@@LIVEBLOCKS/LEAVE",
|
|
45
|
+
START_LOADING_STORAGE: "@@LIVEBLOCKS/START_LOADING_STORAGE",
|
|
46
|
+
INIT_STORAGE: "@@LIVEBLOCKS/INIT_STORAGE",
|
|
47
|
+
PATCH_STORAGE: "@@LIVEBLOCKS/PATCH_STORAGE",
|
|
48
|
+
UPDATE_CONNECTION: "@@LIVEBLOCKS/UPDATE_CONNECTION",
|
|
49
|
+
UPDATE_OTHERS: "@@LIVEBLOCKS/UPDATE_OTHERS"
|
|
50
|
+
};
|
|
51
|
+
const internalPlugin = (options) => {
|
|
52
|
+
if (process.env.NODE_ENV !== "production" && options.client == null) {
|
|
53
|
+
throw missingClient();
|
|
54
|
+
}
|
|
55
|
+
const client = options.client;
|
|
56
|
+
const mapping = validateMapping(options.storageMapping, "storageMapping");
|
|
57
|
+
const presenceMapping = validateMapping(options.presenceMapping || {}, "presenceMapping");
|
|
58
|
+
if (process.env.NODE_ENV !== "production") {
|
|
59
|
+
validateNoDuplicateKeys(mapping, presenceMapping);
|
|
60
|
+
}
|
|
61
|
+
return (createStore) => (reducer, initialState, enhancer2) => {
|
|
62
|
+
let room = null;
|
|
63
|
+
let isPatching = false;
|
|
64
|
+
let storageRoot = null;
|
|
65
|
+
let unsubscribeCallbacks = [];
|
|
66
|
+
const newReducer = (state, action) => {
|
|
67
|
+
switch (action.type) {
|
|
68
|
+
case ACTION_TYPES.PATCH_STORAGE:
|
|
69
|
+
return __spreadValues(__spreadValues({}, state), action.state);
|
|
70
|
+
case ACTION_TYPES.INIT_STORAGE:
|
|
71
|
+
return __spreadProps(__spreadValues(__spreadValues({}, state), action.state), {
|
|
72
|
+
liveblocks: __spreadProps(__spreadValues({}, state.liveblocks), {
|
|
73
|
+
isStorageLoading: false
|
|
74
|
+
})
|
|
75
|
+
});
|
|
76
|
+
case ACTION_TYPES.START_LOADING_STORAGE:
|
|
77
|
+
return __spreadProps(__spreadValues({}, state), {
|
|
78
|
+
liveblocks: __spreadProps(__spreadValues({}, state.liveblocks), {
|
|
79
|
+
isStorageLoading: true
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
case ACTION_TYPES.UPDATE_CONNECTION: {
|
|
83
|
+
return __spreadProps(__spreadValues({}, state), {
|
|
84
|
+
liveblocks: __spreadProps(__spreadValues({}, state.liveblocks), {
|
|
85
|
+
connection: action.connection
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
case ACTION_TYPES.UPDATE_OTHERS: {
|
|
90
|
+
return __spreadProps(__spreadValues({}, state), {
|
|
91
|
+
liveblocks: __spreadProps(__spreadValues({}, state.liveblocks), {
|
|
92
|
+
others: action.others
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
default: {
|
|
97
|
+
const newState = reducer(state, action);
|
|
98
|
+
if (room) {
|
|
99
|
+
isPatching = true;
|
|
100
|
+
updatePresence(room, state, newState, presenceMapping);
|
|
101
|
+
room.batch(() => {
|
|
102
|
+
if (storageRoot) {
|
|
103
|
+
patchLiveblocksStorage(storageRoot, state, newState, mapping);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
isPatching = false;
|
|
107
|
+
}
|
|
108
|
+
if (newState.liveblocks == null) {
|
|
109
|
+
return __spreadProps(__spreadValues({}, newState), {
|
|
110
|
+
liveblocks: {
|
|
111
|
+
others: [],
|
|
112
|
+
isStorageLoading: false,
|
|
113
|
+
connection: "closed"
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return newState;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const store = createStore(newReducer, initialState, enhancer2);
|
|
122
|
+
function enterRoom2(roomId, storageInitialState = {}, reduxState) {
|
|
123
|
+
if (storageRoot) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
room = client.enter(roomId);
|
|
127
|
+
broadcastInitialPresence(room, reduxState, presenceMapping);
|
|
128
|
+
unsubscribeCallbacks.push(room.subscribe("connection", () => {
|
|
129
|
+
store.dispatch({
|
|
130
|
+
type: ACTION_TYPES.UPDATE_CONNECTION,
|
|
131
|
+
connection: room.getConnectionState()
|
|
132
|
+
});
|
|
133
|
+
}));
|
|
134
|
+
unsubscribeCallbacks.push(room.subscribe("others", (others) => {
|
|
135
|
+
store.dispatch({
|
|
136
|
+
type: ACTION_TYPES.UPDATE_OTHERS,
|
|
137
|
+
others: others.toArray()
|
|
138
|
+
});
|
|
139
|
+
}));
|
|
140
|
+
store.dispatch({
|
|
141
|
+
type: ACTION_TYPES.START_LOADING_STORAGE
|
|
142
|
+
});
|
|
143
|
+
room.getStorage().then(({ root }) => {
|
|
144
|
+
const updates = {};
|
|
145
|
+
room.batch(() => {
|
|
146
|
+
for (const key in mapping) {
|
|
147
|
+
const liveblocksStatePart = root.get(key);
|
|
148
|
+
if (liveblocksStatePart == null) {
|
|
149
|
+
updates[key] = storageInitialState[key];
|
|
150
|
+
patchLiveObjectKey(root, key, void 0, storageInitialState[key]);
|
|
151
|
+
} else {
|
|
152
|
+
updates[key] = liveNodeToJson(liveblocksStatePart);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
store.dispatch({
|
|
157
|
+
type: ACTION_TYPES.INIT_STORAGE,
|
|
158
|
+
state: updates
|
|
159
|
+
});
|
|
160
|
+
storageRoot = root;
|
|
161
|
+
unsubscribeCallbacks.push(room.subscribe(root, (updates2) => {
|
|
162
|
+
if (isPatching === false) {
|
|
163
|
+
store.dispatch({
|
|
164
|
+
type: ACTION_TYPES.PATCH_STORAGE,
|
|
165
|
+
state: patchState(store.getState(), updates2, mapping)
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}, { isDeep: true }));
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function leaveRoom2(roomId) {
|
|
172
|
+
for (const unsubscribe of unsubscribeCallbacks) {
|
|
173
|
+
unsubscribe();
|
|
174
|
+
}
|
|
175
|
+
storageRoot = null;
|
|
176
|
+
room = null;
|
|
177
|
+
isPatching = false;
|
|
178
|
+
unsubscribeCallbacks = [];
|
|
179
|
+
client.leave(roomId);
|
|
180
|
+
}
|
|
181
|
+
function newDispatch(action, state) {
|
|
182
|
+
if (action.type === ACTION_TYPES.ENTER) {
|
|
183
|
+
enterRoom2(action.roomId, action.initialState, store.getState());
|
|
184
|
+
} else if (action.type === ACTION_TYPES.LEAVE) {
|
|
185
|
+
leaveRoom2(action.roomId);
|
|
186
|
+
} else {
|
|
187
|
+
store.dispatch(action, state);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return __spreadProps(__spreadValues({}, store), {
|
|
191
|
+
dispatch: newDispatch
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
function enterRoom(roomId, initialState) {
|
|
196
|
+
return {
|
|
197
|
+
type: ACTION_TYPES.ENTER,
|
|
198
|
+
roomId,
|
|
199
|
+
initialState
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function leaveRoom(roomId) {
|
|
203
|
+
return {
|
|
204
|
+
type: ACTION_TYPES.LEAVE,
|
|
205
|
+
roomId
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const enhancer = internalPlugin;
|
|
209
|
+
function patchLiveblocksStorage(root, oldState, newState, mapping) {
|
|
210
|
+
for (const key in mapping) {
|
|
211
|
+
if (process.env.NODE_ENV !== "production" && typeof newState[key] === "function") {
|
|
212
|
+
throw mappingToFunctionIsNotAllowed("value");
|
|
213
|
+
}
|
|
214
|
+
if (oldState[key] !== newState[key]) {
|
|
215
|
+
patchLiveObjectKey(root, key, oldState[key], newState[key]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function broadcastInitialPresence(room, state, mapping) {
|
|
220
|
+
for (const key in mapping) {
|
|
221
|
+
room == null ? void 0 : room.updatePresence({ [key]: state[key] });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function updatePresence(room, oldState, newState, presenceMapping) {
|
|
225
|
+
for (const key in presenceMapping) {
|
|
226
|
+
if (typeof newState[key] === "function") {
|
|
227
|
+
throw mappingToFunctionIsNotAllowed("value");
|
|
228
|
+
}
|
|
229
|
+
if (oldState[key] !== newState[key]) {
|
|
230
|
+
room.updatePresence({ [key]: newState[key] });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function isObject(value) {
|
|
235
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
236
|
+
}
|
|
237
|
+
function validateNoDuplicateKeys(storageMapping, presenceMapping) {
|
|
238
|
+
for (const key in storageMapping) {
|
|
239
|
+
if (presenceMapping[key] !== void 0) {
|
|
240
|
+
throw mappingShouldNotHaveTheSameKeys(key);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function patchState(state, updates, mapping) {
|
|
245
|
+
const partialState = {};
|
|
246
|
+
for (const key in mapping) {
|
|
247
|
+
partialState[key] = state[key];
|
|
248
|
+
}
|
|
249
|
+
const patched = patchImmutableObject(partialState, updates);
|
|
250
|
+
const result = {};
|
|
251
|
+
for (const key in mapping) {
|
|
252
|
+
result[key] = patched[key];
|
|
253
|
+
}
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
function validateMapping(mapping, mappingType) {
|
|
257
|
+
if (process.env.NODE_ENV !== "production") {
|
|
258
|
+
if (mapping == null) {
|
|
259
|
+
throw missingMapping(mappingType);
|
|
260
|
+
}
|
|
261
|
+
if (!isObject(mapping)) {
|
|
262
|
+
throw mappingShouldBeAnObject(mappingType);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const result = {};
|
|
266
|
+
for (const key in mapping) {
|
|
267
|
+
if (process.env.NODE_ENV !== "production" && typeof mapping[key] !== "boolean") {
|
|
268
|
+
throw mappingValueShouldBeABoolean(mappingType, key);
|
|
269
|
+
}
|
|
270
|
+
if (mapping[key] === true) {
|
|
271
|
+
result[key] = true;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export { enhancer, enterRoom, leaveRoom };
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { patchLiveObjectKey, liveNodeToJson, patchImmutableObject } from '@liveblocks/client';
|
|
2
|
+
|
|
3
|
+
const ERROR_PREFIX = "Invalid @liveblocks/redux middleware config.";
|
|
4
|
+
function missingClient() {
|
|
5
|
+
return new Error(`${ERROR_PREFIX} client is missing`);
|
|
6
|
+
}
|
|
7
|
+
function missingMapping(mappingType) {
|
|
8
|
+
return new Error(`${ERROR_PREFIX} ${mappingType} is missing.`);
|
|
9
|
+
}
|
|
10
|
+
function mappingShouldBeAnObject(mappingType) {
|
|
11
|
+
return new Error(`${ERROR_PREFIX} ${mappingType} should be an object where the values are boolean.`);
|
|
12
|
+
}
|
|
13
|
+
function mappingValueShouldBeABoolean(mappingType, key) {
|
|
14
|
+
return new Error(`${ERROR_PREFIX} ${mappingType}.${key} value should be a boolean`);
|
|
15
|
+
}
|
|
16
|
+
function mappingShouldNotHaveTheSameKeys(key) {
|
|
17
|
+
return new Error(`${ERROR_PREFIX} "${key}" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.`);
|
|
18
|
+
}
|
|
19
|
+
function mappingToFunctionIsNotAllowed(key) {
|
|
20
|
+
return new Error(`${ERROR_PREFIX} mapping.${key} is invalid. Mapping to a function is not allowed.`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
var __defProp = Object.defineProperty;
|
|
24
|
+
var __defProps = Object.defineProperties;
|
|
25
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
26
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
27
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
28
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
29
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
30
|
+
var __spreadValues = (a, b) => {
|
|
31
|
+
for (var prop in b || (b = {}))
|
|
32
|
+
if (__hasOwnProp.call(b, prop))
|
|
33
|
+
__defNormalProp(a, prop, b[prop]);
|
|
34
|
+
if (__getOwnPropSymbols)
|
|
35
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
36
|
+
if (__propIsEnum.call(b, prop))
|
|
37
|
+
__defNormalProp(a, prop, b[prop]);
|
|
38
|
+
}
|
|
39
|
+
return a;
|
|
40
|
+
};
|
|
41
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
42
|
+
const ACTION_TYPES = {
|
|
43
|
+
ENTER: "@@LIVEBLOCKS/ENTER",
|
|
44
|
+
LEAVE: "@@LIVEBLOCKS/LEAVE",
|
|
45
|
+
START_LOADING_STORAGE: "@@LIVEBLOCKS/START_LOADING_STORAGE",
|
|
46
|
+
INIT_STORAGE: "@@LIVEBLOCKS/INIT_STORAGE",
|
|
47
|
+
PATCH_STORAGE: "@@LIVEBLOCKS/PATCH_STORAGE",
|
|
48
|
+
UPDATE_CONNECTION: "@@LIVEBLOCKS/UPDATE_CONNECTION",
|
|
49
|
+
UPDATE_OTHERS: "@@LIVEBLOCKS/UPDATE_OTHERS"
|
|
50
|
+
};
|
|
51
|
+
const internalPlugin = (options) => {
|
|
52
|
+
if (process.env.NODE_ENV !== "production" && options.client == null) {
|
|
53
|
+
throw missingClient();
|
|
54
|
+
}
|
|
55
|
+
const client = options.client;
|
|
56
|
+
const mapping = validateMapping(options.storageMapping, "storageMapping");
|
|
57
|
+
const presenceMapping = validateMapping(options.presenceMapping || {}, "presenceMapping");
|
|
58
|
+
if (process.env.NODE_ENV !== "production") {
|
|
59
|
+
validateNoDuplicateKeys(mapping, presenceMapping);
|
|
60
|
+
}
|
|
61
|
+
return (createStore) => (reducer, initialState, enhancer2) => {
|
|
62
|
+
let room = null;
|
|
63
|
+
let isPatching = false;
|
|
64
|
+
let storageRoot = null;
|
|
65
|
+
let unsubscribeCallbacks = [];
|
|
66
|
+
const newReducer = (state, action) => {
|
|
67
|
+
switch (action.type) {
|
|
68
|
+
case ACTION_TYPES.PATCH_STORAGE:
|
|
69
|
+
return __spreadValues(__spreadValues({}, state), action.state);
|
|
70
|
+
case ACTION_TYPES.INIT_STORAGE:
|
|
71
|
+
return __spreadProps(__spreadValues(__spreadValues({}, state), action.state), {
|
|
72
|
+
liveblocks: __spreadProps(__spreadValues({}, state.liveblocks), {
|
|
73
|
+
isStorageLoading: false
|
|
74
|
+
})
|
|
75
|
+
});
|
|
76
|
+
case ACTION_TYPES.START_LOADING_STORAGE:
|
|
77
|
+
return __spreadProps(__spreadValues({}, state), {
|
|
78
|
+
liveblocks: __spreadProps(__spreadValues({}, state.liveblocks), {
|
|
79
|
+
isStorageLoading: true
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
case ACTION_TYPES.UPDATE_CONNECTION: {
|
|
83
|
+
return __spreadProps(__spreadValues({}, state), {
|
|
84
|
+
liveblocks: __spreadProps(__spreadValues({}, state.liveblocks), {
|
|
85
|
+
connection: action.connection
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
case ACTION_TYPES.UPDATE_OTHERS: {
|
|
90
|
+
return __spreadProps(__spreadValues({}, state), {
|
|
91
|
+
liveblocks: __spreadProps(__spreadValues({}, state.liveblocks), {
|
|
92
|
+
others: action.others
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
default: {
|
|
97
|
+
const newState = reducer(state, action);
|
|
98
|
+
if (room) {
|
|
99
|
+
isPatching = true;
|
|
100
|
+
updatePresence(room, state, newState, presenceMapping);
|
|
101
|
+
room.batch(() => {
|
|
102
|
+
if (storageRoot) {
|
|
103
|
+
patchLiveblocksStorage(storageRoot, state, newState, mapping);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
isPatching = false;
|
|
107
|
+
}
|
|
108
|
+
if (newState.liveblocks == null) {
|
|
109
|
+
return __spreadProps(__spreadValues({}, newState), {
|
|
110
|
+
liveblocks: {
|
|
111
|
+
others: [],
|
|
112
|
+
isStorageLoading: false,
|
|
113
|
+
connection: "closed"
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return newState;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const store = createStore(newReducer, initialState, enhancer2);
|
|
122
|
+
function enterRoom2(roomId, storageInitialState = {}, reduxState) {
|
|
123
|
+
if (storageRoot) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
room = client.enter(roomId);
|
|
127
|
+
broadcastInitialPresence(room, reduxState, presenceMapping);
|
|
128
|
+
unsubscribeCallbacks.push(room.subscribe("connection", () => {
|
|
129
|
+
store.dispatch({
|
|
130
|
+
type: ACTION_TYPES.UPDATE_CONNECTION,
|
|
131
|
+
connection: room.getConnectionState()
|
|
132
|
+
});
|
|
133
|
+
}));
|
|
134
|
+
unsubscribeCallbacks.push(room.subscribe("others", (others) => {
|
|
135
|
+
store.dispatch({
|
|
136
|
+
type: ACTION_TYPES.UPDATE_OTHERS,
|
|
137
|
+
others: others.toArray()
|
|
138
|
+
});
|
|
139
|
+
}));
|
|
140
|
+
store.dispatch({
|
|
141
|
+
type: ACTION_TYPES.START_LOADING_STORAGE
|
|
142
|
+
});
|
|
143
|
+
room.getStorage().then(({ root }) => {
|
|
144
|
+
const updates = {};
|
|
145
|
+
room.batch(() => {
|
|
146
|
+
for (const key in mapping) {
|
|
147
|
+
const liveblocksStatePart = root.get(key);
|
|
148
|
+
if (liveblocksStatePart == null) {
|
|
149
|
+
updates[key] = storageInitialState[key];
|
|
150
|
+
patchLiveObjectKey(root, key, void 0, storageInitialState[key]);
|
|
151
|
+
} else {
|
|
152
|
+
updates[key] = liveNodeToJson(liveblocksStatePart);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
store.dispatch({
|
|
157
|
+
type: ACTION_TYPES.INIT_STORAGE,
|
|
158
|
+
state: updates
|
|
159
|
+
});
|
|
160
|
+
storageRoot = root;
|
|
161
|
+
unsubscribeCallbacks.push(room.subscribe(root, (updates2) => {
|
|
162
|
+
if (isPatching === false) {
|
|
163
|
+
store.dispatch({
|
|
164
|
+
type: ACTION_TYPES.PATCH_STORAGE,
|
|
165
|
+
state: patchState(store.getState(), updates2, mapping)
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}, { isDeep: true }));
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function leaveRoom2(roomId) {
|
|
172
|
+
for (const unsubscribe of unsubscribeCallbacks) {
|
|
173
|
+
unsubscribe();
|
|
174
|
+
}
|
|
175
|
+
storageRoot = null;
|
|
176
|
+
room = null;
|
|
177
|
+
isPatching = false;
|
|
178
|
+
unsubscribeCallbacks = [];
|
|
179
|
+
client.leave(roomId);
|
|
180
|
+
}
|
|
181
|
+
function newDispatch(action, state) {
|
|
182
|
+
if (action.type === ACTION_TYPES.ENTER) {
|
|
183
|
+
enterRoom2(action.roomId, action.initialState, store.getState());
|
|
184
|
+
} else if (action.type === ACTION_TYPES.LEAVE) {
|
|
185
|
+
leaveRoom2(action.roomId);
|
|
186
|
+
} else {
|
|
187
|
+
store.dispatch(action, state);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return __spreadProps(__spreadValues({}, store), {
|
|
191
|
+
dispatch: newDispatch
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
function enterRoom(roomId, initialState) {
|
|
196
|
+
return {
|
|
197
|
+
type: ACTION_TYPES.ENTER,
|
|
198
|
+
roomId,
|
|
199
|
+
initialState
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function leaveRoom(roomId) {
|
|
203
|
+
return {
|
|
204
|
+
type: ACTION_TYPES.LEAVE,
|
|
205
|
+
roomId
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const enhancer = internalPlugin;
|
|
209
|
+
function patchLiveblocksStorage(root, oldState, newState, mapping) {
|
|
210
|
+
for (const key in mapping) {
|
|
211
|
+
if (process.env.NODE_ENV !== "production" && typeof newState[key] === "function") {
|
|
212
|
+
throw mappingToFunctionIsNotAllowed("value");
|
|
213
|
+
}
|
|
214
|
+
if (oldState[key] !== newState[key]) {
|
|
215
|
+
patchLiveObjectKey(root, key, oldState[key], newState[key]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function broadcastInitialPresence(room, state, mapping) {
|
|
220
|
+
for (const key in mapping) {
|
|
221
|
+
room == null ? void 0 : room.updatePresence({ [key]: state[key] });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function updatePresence(room, oldState, newState, presenceMapping) {
|
|
225
|
+
for (const key in presenceMapping) {
|
|
226
|
+
if (typeof newState[key] === "function") {
|
|
227
|
+
throw mappingToFunctionIsNotAllowed("value");
|
|
228
|
+
}
|
|
229
|
+
if (oldState[key] !== newState[key]) {
|
|
230
|
+
room.updatePresence({ [key]: newState[key] });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function isObject(value) {
|
|
235
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
236
|
+
}
|
|
237
|
+
function validateNoDuplicateKeys(storageMapping, presenceMapping) {
|
|
238
|
+
for (const key in storageMapping) {
|
|
239
|
+
if (presenceMapping[key] !== void 0) {
|
|
240
|
+
throw mappingShouldNotHaveTheSameKeys(key);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function patchState(state, updates, mapping) {
|
|
245
|
+
const partialState = {};
|
|
246
|
+
for (const key in mapping) {
|
|
247
|
+
partialState[key] = state[key];
|
|
248
|
+
}
|
|
249
|
+
const patched = patchImmutableObject(partialState, updates);
|
|
250
|
+
const result = {};
|
|
251
|
+
for (const key in mapping) {
|
|
252
|
+
result[key] = patched[key];
|
|
253
|
+
}
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
function validateMapping(mapping, mappingType) {
|
|
257
|
+
if (process.env.NODE_ENV !== "production") {
|
|
258
|
+
if (mapping == null) {
|
|
259
|
+
throw missingMapping(mappingType);
|
|
260
|
+
}
|
|
261
|
+
if (!isObject(mapping)) {
|
|
262
|
+
throw mappingShouldBeAnObject(mappingType);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const result = {};
|
|
266
|
+
for (const key in mapping) {
|
|
267
|
+
if (process.env.NODE_ENV !== "production" && typeof mapping[key] !== "boolean") {
|
|
268
|
+
throw mappingValueShouldBeABoolean(mappingType, key);
|
|
269
|
+
}
|
|
270
|
+
if (mapping[key] === true) {
|
|
271
|
+
result[key] = true;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export { enhancer, enterRoom, leaveRoom };
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Client, User } from "@liveblocks/client";
|
|
2
|
+
import { StoreEnhancer } from "redux";
|
|
3
|
+
export declare type Mapping<T> = Partial<{
|
|
4
|
+
[Property in keyof T]: boolean;
|
|
5
|
+
}>;
|
|
6
|
+
export declare type LiveblocksState<TState, TPresence = any> = TState & {
|
|
7
|
+
/**
|
|
8
|
+
* Liveblocks extra state attached by the middleware
|
|
9
|
+
*/
|
|
10
|
+
readonly liveblocks: {
|
|
11
|
+
/**
|
|
12
|
+
* Other users in the room. Empty no room is currently synced
|
|
13
|
+
*/
|
|
14
|
+
readonly others: Array<User<TPresence>>;
|
|
15
|
+
/**
|
|
16
|
+
* Whether or not the room storage is currently loading
|
|
17
|
+
*/
|
|
18
|
+
readonly isStorageLoading: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Connection state of the room
|
|
21
|
+
*/
|
|
22
|
+
readonly connection: "closed" | "authenticating" | "unavailable" | "failed" | "open" | "connecting";
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export declare function enterRoom(roomId: string, initialState?: any): {
|
|
26
|
+
type: string;
|
|
27
|
+
roomId: string;
|
|
28
|
+
initialState: any;
|
|
29
|
+
};
|
|
30
|
+
export declare function leaveRoom(roomId: string): {
|
|
31
|
+
type: string;
|
|
32
|
+
roomId: string;
|
|
33
|
+
};
|
|
34
|
+
export declare const enhancer: <T>(options: {
|
|
35
|
+
client: Client;
|
|
36
|
+
storageMapping: Partial<{ [Property in keyof T]: boolean; }>;
|
|
37
|
+
presenceMapping?: Partial<{ [Property in keyof T]: boolean; }> | undefined;
|
|
38
|
+
}) => StoreEnhancer;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var client = require('@liveblocks/client');
|
|
6
|
+
|
|
7
|
+
function _extends() {
|
|
8
|
+
_extends = Object.assign || function (target) {
|
|
9
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
10
|
+
var source = arguments[i];
|
|
11
|
+
|
|
12
|
+
for (var key in source) {
|
|
13
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
14
|
+
target[key] = source[key];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return target;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return _extends.apply(this, arguments);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function _unsupportedIterableToArray(o, minLen) {
|
|
26
|
+
if (!o) return;
|
|
27
|
+
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
|
28
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
29
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
30
|
+
if (n === "Map" || n === "Set") return Array.from(o);
|
|
31
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function _arrayLikeToArray(arr, len) {
|
|
35
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
36
|
+
|
|
37
|
+
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
|
38
|
+
|
|
39
|
+
return arr2;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
|
|
43
|
+
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
|
|
44
|
+
if (it) return (it = it.call(o)).next.bind(it);
|
|
45
|
+
|
|
46
|
+
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
|
|
47
|
+
if (it) o = it;
|
|
48
|
+
var i = 0;
|
|
49
|
+
return function () {
|
|
50
|
+
if (i >= o.length) return {
|
|
51
|
+
done: true
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
done: false,
|
|
55
|
+
value: o[i++]
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
var ERROR_PREFIX = "Invalid @liveblocks/redux middleware config.";
|
|
64
|
+
function missingClient() {
|
|
65
|
+
return new Error(ERROR_PREFIX + " client is missing");
|
|
66
|
+
}
|
|
67
|
+
function missingMapping(mappingType) {
|
|
68
|
+
return new Error(ERROR_PREFIX + " " + mappingType + " is missing.");
|
|
69
|
+
}
|
|
70
|
+
function mappingShouldBeAnObject(mappingType) {
|
|
71
|
+
return new Error(ERROR_PREFIX + " " + mappingType + " should be an object where the values are boolean.");
|
|
72
|
+
}
|
|
73
|
+
function mappingValueShouldBeABoolean(mappingType, key) {
|
|
74
|
+
return new Error(ERROR_PREFIX + " " + mappingType + "." + key + " value should be a boolean");
|
|
75
|
+
}
|
|
76
|
+
function mappingShouldNotHaveTheSameKeys(key) {
|
|
77
|
+
return new Error(ERROR_PREFIX + " \"" + key + "\" is mapped on presenceMapping and storageMapping. A key shouldn't exist on both mapping.");
|
|
78
|
+
}
|
|
79
|
+
function mappingToFunctionIsNotAllowed(key) {
|
|
80
|
+
return new Error(ERROR_PREFIX + " mapping." + key + " is invalid. Mapping to a function is not allowed.");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
var ACTION_TYPES = {
|
|
84
|
+
ENTER: "@@LIVEBLOCKS/ENTER",
|
|
85
|
+
LEAVE: "@@LIVEBLOCKS/LEAVE",
|
|
86
|
+
START_LOADING_STORAGE: "@@LIVEBLOCKS/START_LOADING_STORAGE",
|
|
87
|
+
INIT_STORAGE: "@@LIVEBLOCKS/INIT_STORAGE",
|
|
88
|
+
PATCH_STORAGE: "@@LIVEBLOCKS/PATCH_STORAGE",
|
|
89
|
+
UPDATE_CONNECTION: "@@LIVEBLOCKS/UPDATE_CONNECTION",
|
|
90
|
+
UPDATE_OTHERS: "@@LIVEBLOCKS/UPDATE_OTHERS"
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
var internalPlugin = function internalPlugin(options) {
|
|
94
|
+
if (process.env.NODE_ENV !== "production" && options.client == null) {
|
|
95
|
+
throw missingClient();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
var client$1 = options.client;
|
|
99
|
+
var mapping = validateMapping(options.storageMapping, "storageMapping");
|
|
100
|
+
var presenceMapping = validateMapping(options.presenceMapping || {}, "presenceMapping");
|
|
101
|
+
|
|
102
|
+
if (process.env.NODE_ENV !== "production") {
|
|
103
|
+
validateNoDuplicateKeys(mapping, presenceMapping);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return function (createStore) {
|
|
107
|
+
return function (reducer, initialState, enhancer) {
|
|
108
|
+
var room = null;
|
|
109
|
+
var isPatching = false;
|
|
110
|
+
var storageRoot = null;
|
|
111
|
+
var unsubscribeCallbacks = [];
|
|
112
|
+
|
|
113
|
+
var newReducer = function newReducer(state, action) {
|
|
114
|
+
switch (action.type) {
|
|
115
|
+
case ACTION_TYPES.PATCH_STORAGE:
|
|
116
|
+
return _extends({}, state, action.state);
|
|
117
|
+
|
|
118
|
+
case ACTION_TYPES.INIT_STORAGE:
|
|
119
|
+
return _extends({}, state, action.state, {
|
|
120
|
+
liveblocks: _extends({}, state.liveblocks, {
|
|
121
|
+
isStorageLoading: false
|
|
122
|
+
})
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
case ACTION_TYPES.START_LOADING_STORAGE:
|
|
126
|
+
return _extends({}, state, {
|
|
127
|
+
liveblocks: _extends({}, state.liveblocks, {
|
|
128
|
+
isStorageLoading: true
|
|
129
|
+
})
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
case ACTION_TYPES.UPDATE_CONNECTION:
|
|
133
|
+
{
|
|
134
|
+
return _extends({}, state, {
|
|
135
|
+
liveblocks: _extends({}, state.liveblocks, {
|
|
136
|
+
connection: action.connection
|
|
137
|
+
})
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
case ACTION_TYPES.UPDATE_OTHERS:
|
|
142
|
+
{
|
|
143
|
+
return _extends({}, state, {
|
|
144
|
+
liveblocks: _extends({}, state.liveblocks, {
|
|
145
|
+
others: action.others
|
|
146
|
+
})
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
default:
|
|
151
|
+
{
|
|
152
|
+
var newState = reducer(state, action);
|
|
153
|
+
|
|
154
|
+
if (room) {
|
|
155
|
+
isPatching = true;
|
|
156
|
+
updatePresence(room, state, newState, presenceMapping);
|
|
157
|
+
room.batch(function () {
|
|
158
|
+
if (storageRoot) {
|
|
159
|
+
patchLiveblocksStorage(storageRoot, state, newState, mapping);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
isPatching = false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (newState.liveblocks == null) {
|
|
166
|
+
return _extends({}, newState, {
|
|
167
|
+
liveblocks: {
|
|
168
|
+
others: [],
|
|
169
|
+
isStorageLoading: false,
|
|
170
|
+
connection: "closed"
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return newState;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
var store = createStore(newReducer, initialState, enhancer);
|
|
181
|
+
|
|
182
|
+
function enterRoom(roomId, storageInitialState, reduxState) {
|
|
183
|
+
if (storageInitialState === void 0) {
|
|
184
|
+
storageInitialState = {};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (storageRoot) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
room = client$1.enter(roomId);
|
|
192
|
+
broadcastInitialPresence(room, reduxState, presenceMapping);
|
|
193
|
+
unsubscribeCallbacks.push(room.subscribe("connection", function () {
|
|
194
|
+
store.dispatch({
|
|
195
|
+
type: ACTION_TYPES.UPDATE_CONNECTION,
|
|
196
|
+
connection: room.getConnectionState()
|
|
197
|
+
});
|
|
198
|
+
}));
|
|
199
|
+
unsubscribeCallbacks.push(room.subscribe("others", function (others) {
|
|
200
|
+
store.dispatch({
|
|
201
|
+
type: ACTION_TYPES.UPDATE_OTHERS,
|
|
202
|
+
others: others.toArray()
|
|
203
|
+
});
|
|
204
|
+
}));
|
|
205
|
+
store.dispatch({
|
|
206
|
+
type: ACTION_TYPES.START_LOADING_STORAGE
|
|
207
|
+
});
|
|
208
|
+
room.getStorage().then(function (_ref) {
|
|
209
|
+
var root = _ref.root;
|
|
210
|
+
var updates = {};
|
|
211
|
+
room.batch(function () {
|
|
212
|
+
for (var key in mapping) {
|
|
213
|
+
var liveblocksStatePart = root.get(key);
|
|
214
|
+
|
|
215
|
+
if (liveblocksStatePart == null) {
|
|
216
|
+
updates[key] = storageInitialState[key];
|
|
217
|
+
client.patchLiveObjectKey(root, key, undefined, storageInitialState[key]);
|
|
218
|
+
} else {
|
|
219
|
+
updates[key] = client.liveNodeToJson(liveblocksStatePart);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
store.dispatch({
|
|
224
|
+
type: ACTION_TYPES.INIT_STORAGE,
|
|
225
|
+
state: updates
|
|
226
|
+
});
|
|
227
|
+
storageRoot = root;
|
|
228
|
+
unsubscribeCallbacks.push(room.subscribe(root, function (updates) {
|
|
229
|
+
if (isPatching === false) {
|
|
230
|
+
store.dispatch({
|
|
231
|
+
type: ACTION_TYPES.PATCH_STORAGE,
|
|
232
|
+
state: patchState(store.getState(), updates, mapping)
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}, {
|
|
236
|
+
isDeep: true
|
|
237
|
+
}));
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function leaveRoom(roomId) {
|
|
242
|
+
for (var _iterator = _createForOfIteratorHelperLoose(unsubscribeCallbacks), _step; !(_step = _iterator()).done;) {
|
|
243
|
+
var unsubscribe = _step.value;
|
|
244
|
+
unsubscribe();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
storageRoot = null;
|
|
248
|
+
room = null;
|
|
249
|
+
isPatching = false;
|
|
250
|
+
unsubscribeCallbacks = [];
|
|
251
|
+
client$1.leave(roomId);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function newDispatch(action, state) {
|
|
255
|
+
if (action.type === ACTION_TYPES.ENTER) {
|
|
256
|
+
enterRoom(action.roomId, action.initialState, store.getState());
|
|
257
|
+
} else if (action.type === ACTION_TYPES.LEAVE) {
|
|
258
|
+
leaveRoom(action.roomId);
|
|
259
|
+
} else {
|
|
260
|
+
store.dispatch(action, state);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return _extends({}, store, {
|
|
265
|
+
dispatch: newDispatch
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
function enterRoom(roomId, initialState) {
|
|
272
|
+
return {
|
|
273
|
+
type: ACTION_TYPES.ENTER,
|
|
274
|
+
roomId: roomId,
|
|
275
|
+
initialState: initialState
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function leaveRoom(roomId) {
|
|
279
|
+
return {
|
|
280
|
+
type: ACTION_TYPES.LEAVE,
|
|
281
|
+
roomId: roomId
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
var enhancer = internalPlugin;
|
|
285
|
+
|
|
286
|
+
function patchLiveblocksStorage(root, oldState, newState, mapping) {
|
|
287
|
+
for (var key in mapping) {
|
|
288
|
+
if (process.env.NODE_ENV !== "production" && typeof newState[key] === "function") {
|
|
289
|
+
throw mappingToFunctionIsNotAllowed("value");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (oldState[key] !== newState[key]) {
|
|
293
|
+
client.patchLiveObjectKey(root, key, oldState[key], newState[key]);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function broadcastInitialPresence(room, state, mapping) {
|
|
299
|
+
for (var key in mapping) {
|
|
300
|
+
var _room$updatePresence;
|
|
301
|
+
|
|
302
|
+
room == null ? void 0 : room.updatePresence((_room$updatePresence = {}, _room$updatePresence[key] = state[key], _room$updatePresence));
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function updatePresence(room, oldState, newState, presenceMapping) {
|
|
307
|
+
for (var key in presenceMapping) {
|
|
308
|
+
if (typeof newState[key] === "function") {
|
|
309
|
+
throw mappingToFunctionIsNotAllowed("value");
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (oldState[key] !== newState[key]) {
|
|
313
|
+
var _room$updatePresence2;
|
|
314
|
+
|
|
315
|
+
room.updatePresence((_room$updatePresence2 = {}, _room$updatePresence2[key] = newState[key], _room$updatePresence2));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function isObject(value) {
|
|
321
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function validateNoDuplicateKeys(storageMapping, presenceMapping) {
|
|
325
|
+
for (var key in storageMapping) {
|
|
326
|
+
if (presenceMapping[key] !== undefined) {
|
|
327
|
+
throw mappingShouldNotHaveTheSameKeys(key);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function patchState(state, updates, mapping) {
|
|
333
|
+
var partialState = {};
|
|
334
|
+
|
|
335
|
+
for (var key in mapping) {
|
|
336
|
+
partialState[key] = state[key];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
var patched = client.patchImmutableObject(partialState, updates);
|
|
340
|
+
var result = {};
|
|
341
|
+
|
|
342
|
+
for (var _key in mapping) {
|
|
343
|
+
result[_key] = patched[_key];
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function validateMapping(mapping, mappingType) {
|
|
350
|
+
if (process.env.NODE_ENV !== "production") {
|
|
351
|
+
if (mapping == null) {
|
|
352
|
+
throw missingMapping(mappingType);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (!isObject(mapping)) {
|
|
356
|
+
throw mappingShouldBeAnObject(mappingType);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
var result = {};
|
|
361
|
+
|
|
362
|
+
for (var key in mapping) {
|
|
363
|
+
if (process.env.NODE_ENV !== "production" && typeof mapping[key] !== "boolean") {
|
|
364
|
+
throw mappingValueShouldBeABoolean(mappingType, key);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (mapping[key] === true) {
|
|
368
|
+
result[key] = true;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
exports.enhancer = enhancer;
|
|
376
|
+
exports.enterRoom = enterRoom;
|
|
377
|
+
exports.leaveRoom = leaveRoom;
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@liveblocks/redux",
|
|
3
|
+
"version": "0.15.0-alpha.3",
|
|
4
|
+
"sideEffects": false,
|
|
5
|
+
"description": "",
|
|
6
|
+
"main": "./lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"lib/"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./lib/index.d.ts",
|
|
14
|
+
"module": "./lib/esm/index.js",
|
|
15
|
+
"import": "./lib/esm/index.mjs",
|
|
16
|
+
"default": "./lib/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"redux",
|
|
21
|
+
"react",
|
|
22
|
+
"liveblocks",
|
|
23
|
+
"multiplayer",
|
|
24
|
+
"live-cursors",
|
|
25
|
+
"collaborative"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "rollup -c",
|
|
29
|
+
"test": "jest --watch",
|
|
30
|
+
"dtslint": "dtslint --localTs node_modules/typescript/lib --expectOnly types"
|
|
31
|
+
},
|
|
32
|
+
"license": "Apache-2.0",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/liveblocks/liveblocks.git",
|
|
36
|
+
"directory": "packages/liveblocks-redux"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@liveblocks/client": "0.15.0-alpha.3",
|
|
40
|
+
"redux": "^4"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@babel/core": "^7.16.7",
|
|
44
|
+
"@babel/plugin-transform-typescript": "^7.16.8",
|
|
45
|
+
"@babel/preset-env": "^7.16.8",
|
|
46
|
+
"@definitelytyped/dtslint": "^0.0.103",
|
|
47
|
+
"@reduxjs/toolkit": "^1.7.2",
|
|
48
|
+
"@rollup/plugin-babel": "^5.3.0",
|
|
49
|
+
"@rollup/plugin-node-resolve": "^13.1.3",
|
|
50
|
+
"@rollup/plugin-typescript": "^8.3.0",
|
|
51
|
+
"@testing-library/jest-dom": "^5.16.1",
|
|
52
|
+
"@testing-library/react": "^12.1.2",
|
|
53
|
+
"@testing-library/react-hooks": "^7.0.2",
|
|
54
|
+
"@types/jest": "^27.4.1",
|
|
55
|
+
"esbuild": "0.14.11",
|
|
56
|
+
"jest": "^27.4.7",
|
|
57
|
+
"msw": "^0.36.4",
|
|
58
|
+
"redux": "^4.1.2",
|
|
59
|
+
"rollup": "^2.64.0",
|
|
60
|
+
"rollup-plugin-esbuild": "^4.8.2",
|
|
61
|
+
"whatwg-fetch": "^3.6.2"
|
|
62
|
+
}
|
|
63
|
+
}
|