coaction 0.0.1 → 0.1.0
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/coaction.cjs.d.mts +2 -0
- package/dist/coaction.cjs.d.ts +2 -0
- package/dist/coaction.cjs.js +661 -0
- package/dist/coaction.cjs.mjs +5 -0
- package/dist/coaction.esm.js +655 -0
- package/dist/coaction.umd.min.js +2 -0
- package/dist/coaction.umd.min.js.map +1 -0
- package/dist/declarations/src/binder.d.ts +27 -0
- package/dist/declarations/src/create.d.ts +5 -0
- package/dist/declarations/src/index.d.ts +4 -0
- package/dist/declarations/src/interface.d.ts +224 -0
- package/dist/declarations/src/wrapStore.d.ts +5 -0
- package/package.json +48 -8
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from "./declarations/src/index.js";
|
|
2
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29hY3Rpb24uY2pzLmQubXRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi9kZWNsYXJhdGlvbnMvc3JjL2luZGV4LmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEifQ==
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from "./declarations/src/index";
|
|
2
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29hY3Rpb24uY2pzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuL2RlY2xhcmF0aW9ucy9zcmMvaW5kZXguZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSJ9
|
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var mutative = require('mutative');
|
|
6
|
+
var dataTransport = require('data-transport');
|
|
7
|
+
|
|
8
|
+
const getGlobal = () => {
|
|
9
|
+
let _global;
|
|
10
|
+
if (typeof window !== 'undefined') {
|
|
11
|
+
_global = window;
|
|
12
|
+
} else if (typeof global !== 'undefined') {
|
|
13
|
+
_global = global;
|
|
14
|
+
} else if (typeof self !== 'undefined') {
|
|
15
|
+
_global = self;
|
|
16
|
+
} else {
|
|
17
|
+
_global = {};
|
|
18
|
+
}
|
|
19
|
+
return _global;
|
|
20
|
+
};
|
|
21
|
+
const _global = getGlobal();
|
|
22
|
+
|
|
23
|
+
const WorkerType = _global.SharedWorkerGlobalScope ? 'SharedWorkerInternal' : globalThis.WorkerGlobalScope ? 'WebWorkerInternal' : null;
|
|
24
|
+
const bindSymbol = Symbol('bind');
|
|
25
|
+
const defaultName = 'default';
|
|
26
|
+
|
|
27
|
+
const createAsyncClientStore = (createStore, asyncStoreClientOption) => {
|
|
28
|
+
const {
|
|
29
|
+
store: asyncClientStore
|
|
30
|
+
} = createStore({
|
|
31
|
+
share: 'client'
|
|
32
|
+
});
|
|
33
|
+
// the transport is in the worker or shared worker, and the client is in the main thread.
|
|
34
|
+
// This store can't be directly executed by any of the store's methods
|
|
35
|
+
// its methods are proxied to the worker or share worker for execution.
|
|
36
|
+
// and the executed patch is sent to the store to be applied to synchronize the state.
|
|
37
|
+
const transport = asyncStoreClientOption.worker ? dataTransport.createTransport(asyncStoreClientOption.worker instanceof SharedWorker ? 'SharedWorkerClient' : 'WebWorkerClient', {
|
|
38
|
+
worker: asyncStoreClientOption.worker,
|
|
39
|
+
prefix: asyncClientStore.name
|
|
40
|
+
}) : asyncStoreClientOption.clientTransport;
|
|
41
|
+
if (!transport) {
|
|
42
|
+
throw new Error('transport is required');
|
|
43
|
+
}
|
|
44
|
+
asyncClientStore.transport = transport;
|
|
45
|
+
let sequence;
|
|
46
|
+
const fullSync = async () => {
|
|
47
|
+
const latest = await transport.emit('fullSync');
|
|
48
|
+
asyncClientStore.apply(JSON.parse(latest.state));
|
|
49
|
+
sequence = latest.sequence;
|
|
50
|
+
};
|
|
51
|
+
if (typeof transport.onConnect !== 'function') {
|
|
52
|
+
throw new Error('transport.onConnect is required');
|
|
53
|
+
}
|
|
54
|
+
transport.onConnect?.(async () => {
|
|
55
|
+
await fullSync();
|
|
56
|
+
});
|
|
57
|
+
transport.listen('update', async options => {
|
|
58
|
+
if (typeof options.sequence === 'number' && options.sequence === sequence + 1) {
|
|
59
|
+
sequence = options.sequence;
|
|
60
|
+
asyncClientStore.apply(undefined, options.patches);
|
|
61
|
+
} else {
|
|
62
|
+
await fullSync();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const {
|
|
66
|
+
name,
|
|
67
|
+
..._store
|
|
68
|
+
} = asyncClientStore;
|
|
69
|
+
return Object.assign({
|
|
70
|
+
[name]: () => asyncClientStore.getState()
|
|
71
|
+
}[name], _store);
|
|
72
|
+
};
|
|
73
|
+
const emit = (store, internal, patches) => {
|
|
74
|
+
if (store.transport && patches?.length) {
|
|
75
|
+
internal.sequence += 1;
|
|
76
|
+
// it is not necessary to respond to the update event
|
|
77
|
+
store.transport.emit({
|
|
78
|
+
name: 'update',
|
|
79
|
+
respond: false
|
|
80
|
+
}, {
|
|
81
|
+
patches: patches,
|
|
82
|
+
sequence: internal.sequence
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const handleDraft = (store, internal) => {
|
|
87
|
+
internal.rootState = internal.backupState;
|
|
88
|
+
const [, patches, inversePatches] = internal.finalizeDraft();
|
|
89
|
+
const finalPatches = store.patch ? store.patch({
|
|
90
|
+
patches,
|
|
91
|
+
inversePatches
|
|
92
|
+
}) : {
|
|
93
|
+
patches,
|
|
94
|
+
inversePatches
|
|
95
|
+
};
|
|
96
|
+
if (finalPatches.patches.length) {
|
|
97
|
+
store.apply(internal.rootState, finalPatches.patches);
|
|
98
|
+
// 3rd party model will send update notifications on its own after `store.apply` in mutableInstance mode
|
|
99
|
+
emit(store, internal, finalPatches.patches);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const getInitialState = (store, createState) => {
|
|
104
|
+
const makeState = fn => {
|
|
105
|
+
// make sure createState is a function
|
|
106
|
+
if (process.env.NODE_ENV !== 'production' && typeof fn !== 'function') {
|
|
107
|
+
throw new Error('createState should be a function');
|
|
108
|
+
}
|
|
109
|
+
let state = fn(store.setState, store.getState, store);
|
|
110
|
+
if (typeof state === 'function') {
|
|
111
|
+
state = state();
|
|
112
|
+
}
|
|
113
|
+
if (state[bindSymbol]) {
|
|
114
|
+
const rawState = state[bindSymbol].bind(state);
|
|
115
|
+
state[bindSymbol].handleStore(store, rawState, state);
|
|
116
|
+
return rawState;
|
|
117
|
+
}
|
|
118
|
+
return state;
|
|
119
|
+
};
|
|
120
|
+
return store.isSliceStore ? Object.entries(createState).reduce((stateTree, [key, value]) => Object.assign(stateTree, {
|
|
121
|
+
[key]: makeState(value)
|
|
122
|
+
}), {}) : makeState(createState);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const isEqual = (x, y) => {
|
|
126
|
+
if (x === y) {
|
|
127
|
+
return x !== 0 || y !== 0 || 1 / x === 1 / y;
|
|
128
|
+
}
|
|
129
|
+
return x !== x && y !== y;
|
|
130
|
+
};
|
|
131
|
+
const areShallowEqualWithArray = (prev, next) => {
|
|
132
|
+
if (prev === null || next === null || prev.length !== next.length) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
const {
|
|
136
|
+
length
|
|
137
|
+
} = prev;
|
|
138
|
+
for (let i = 0; i < length; i += 1) {
|
|
139
|
+
if (!isEqual(prev[i], next[i])) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
};
|
|
145
|
+
const mergeObject = (target, source, isSlice) => {
|
|
146
|
+
if (isSlice) {
|
|
147
|
+
if (typeof source === 'object' && source !== null) {
|
|
148
|
+
for (const key in source) {
|
|
149
|
+
if (typeof source[key] === 'object' && source[key] !== null) {
|
|
150
|
+
Object.assign(target[key], source[key]);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
Object.assign(target, source);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
const uuid = () => {
|
|
159
|
+
let timestamp = new Date().getTime();
|
|
160
|
+
const uuidTemplate = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
|
161
|
+
const uuid = uuidTemplate.replace(/[xy]/g, char => {
|
|
162
|
+
let randomNum = (timestamp + Math.random() * 16) % 16 | 0;
|
|
163
|
+
timestamp = Math.floor(timestamp / 16);
|
|
164
|
+
return (char === 'x' ? randomNum : randomNum & 0x3 | 0x8).toString(16);
|
|
165
|
+
});
|
|
166
|
+
return uuid;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
class Computed {
|
|
170
|
+
constructor(deps, fn) {
|
|
171
|
+
this.deps = deps;
|
|
172
|
+
this.fn = fn;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const defaultMemoize = func => {
|
|
176
|
+
const lastArgs = new WeakMap();
|
|
177
|
+
const lastResult = new WeakMap();
|
|
178
|
+
return function () {
|
|
179
|
+
if (!areShallowEqualWithArray(lastArgs.get(this) ?? [], arguments)) {
|
|
180
|
+
lastResult.set(this, func.apply(this, arguments));
|
|
181
|
+
}
|
|
182
|
+
lastArgs.set(this, arguments);
|
|
183
|
+
return lastResult.get(this);
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
const createSelectorCreatorWithArray = (memoize = defaultMemoize) => {
|
|
187
|
+
return (dependenciesFunc, resultFunc) => {
|
|
188
|
+
const memoizedResultFunc = memoize(function () {
|
|
189
|
+
return resultFunc.apply(this, arguments);
|
|
190
|
+
});
|
|
191
|
+
return function () {
|
|
192
|
+
return memoizedResultFunc.apply(this, dependenciesFunc.apply(null, [this]));
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
const createSelectorWithArray = createSelectorCreatorWithArray();
|
|
197
|
+
|
|
198
|
+
const getRawState = (store, internal, initialState, options) => {
|
|
199
|
+
const rawState = {};
|
|
200
|
+
const handle = (_rawState, _initialState, sliceKey) => {
|
|
201
|
+
internal.mutableInstance = store.toRaw?.(_initialState);
|
|
202
|
+
const descriptors = Object.getOwnPropertyDescriptors(_initialState);
|
|
203
|
+
Object.entries(descriptors).forEach(([key, descriptor]) => {
|
|
204
|
+
if (Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
|
|
205
|
+
if (typeof descriptor.value !== 'function') {
|
|
206
|
+
const isComputed = descriptor.value instanceof Computed;
|
|
207
|
+
if (internal.mutableInstance) {
|
|
208
|
+
Object.defineProperty(_rawState, key, {
|
|
209
|
+
get: () => internal.mutableInstance[key],
|
|
210
|
+
set: value => {
|
|
211
|
+
internal.mutableInstance[key] = value;
|
|
212
|
+
},
|
|
213
|
+
enumerable: true
|
|
214
|
+
});
|
|
215
|
+
} else if (!isComputed) {
|
|
216
|
+
_rawState[key] = descriptor.value;
|
|
217
|
+
}
|
|
218
|
+
if (isComputed) {
|
|
219
|
+
if (internal.mutableInstance) {
|
|
220
|
+
throw new Error('Computed is not supported with mutable instance');
|
|
221
|
+
}
|
|
222
|
+
// manually handle computed property
|
|
223
|
+
const {
|
|
224
|
+
deps,
|
|
225
|
+
fn
|
|
226
|
+
} = descriptor.value;
|
|
227
|
+
const depsCallbackSelector = createSelectorWithArray(() => [internal.rootState], () => {
|
|
228
|
+
return deps(internal.module);
|
|
229
|
+
});
|
|
230
|
+
const selector = createSelectorWithArray(that => depsCallbackSelector.call(that), fn);
|
|
231
|
+
descriptor.get = function () {
|
|
232
|
+
return selector.call(this);
|
|
233
|
+
};
|
|
234
|
+
} else {
|
|
235
|
+
if (sliceKey) {
|
|
236
|
+
descriptor.get = () => internal.rootState[sliceKey][key];
|
|
237
|
+
descriptor.set = value => {
|
|
238
|
+
internal.rootState[sliceKey][key] = value;
|
|
239
|
+
};
|
|
240
|
+
} else {
|
|
241
|
+
descriptor.get = () => internal.rootState[key];
|
|
242
|
+
descriptor.set = value => {
|
|
243
|
+
internal.rootState[key] = value;
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// handle state property
|
|
248
|
+
delete descriptor.value;
|
|
249
|
+
delete descriptor.writable;
|
|
250
|
+
} else if (store.share === 'client') {
|
|
251
|
+
descriptor.value = (...args) => {
|
|
252
|
+
let actionId;
|
|
253
|
+
let done;
|
|
254
|
+
if (store.trace) {
|
|
255
|
+
actionId = uuid();
|
|
256
|
+
store.trace({
|
|
257
|
+
method: key,
|
|
258
|
+
parameters: args,
|
|
259
|
+
id: actionId,
|
|
260
|
+
sliceKey
|
|
261
|
+
});
|
|
262
|
+
done = result => {
|
|
263
|
+
store.trace({
|
|
264
|
+
method: key,
|
|
265
|
+
id: actionId,
|
|
266
|
+
result,
|
|
267
|
+
sliceKey
|
|
268
|
+
});
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const keys = sliceKey ? [sliceKey, key] : [key];
|
|
272
|
+
// emit the action to worker or main thread execute
|
|
273
|
+
return store.transport.emit('execute', keys, args).then(result => {
|
|
274
|
+
if (result?.$$Error) {
|
|
275
|
+
done?.(result);
|
|
276
|
+
throw new Error(result.$$Error);
|
|
277
|
+
}
|
|
278
|
+
done?.(result);
|
|
279
|
+
return result;
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
} else {
|
|
283
|
+
const fn = descriptor.value;
|
|
284
|
+
descriptor.value = (...args) => {
|
|
285
|
+
let actionId;
|
|
286
|
+
let done;
|
|
287
|
+
if (store.trace) {
|
|
288
|
+
actionId = uuid();
|
|
289
|
+
store.trace({
|
|
290
|
+
method: key,
|
|
291
|
+
parameters: args,
|
|
292
|
+
id: actionId,
|
|
293
|
+
sliceKey
|
|
294
|
+
});
|
|
295
|
+
done = result => {
|
|
296
|
+
store.trace({
|
|
297
|
+
method: key,
|
|
298
|
+
id: actionId,
|
|
299
|
+
result,
|
|
300
|
+
sliceKey
|
|
301
|
+
});
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
const enablePatches = store.transport ?? options.enablePatches;
|
|
305
|
+
if (internal.mutableInstance && !internal.isBatching && enablePatches) {
|
|
306
|
+
let result;
|
|
307
|
+
const handleResult = isDrafted => {
|
|
308
|
+
handleDraft(store, internal);
|
|
309
|
+
if (isDrafted) {
|
|
310
|
+
internal.backupState = internal.rootState;
|
|
311
|
+
const [draft, finalize] = mutative.create(internal.rootState, {
|
|
312
|
+
enablePatches: true
|
|
313
|
+
});
|
|
314
|
+
internal.finalizeDraft = finalize;
|
|
315
|
+
internal.rootState = draft;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
const isDrafted = mutative.isDraft(internal.rootState);
|
|
319
|
+
if (isDrafted) {
|
|
320
|
+
handleResult();
|
|
321
|
+
}
|
|
322
|
+
internal.backupState = internal.rootState;
|
|
323
|
+
const [draft, finalize] = mutative.create(internal.rootState, {
|
|
324
|
+
enablePatches: true
|
|
325
|
+
});
|
|
326
|
+
internal.finalizeDraft = finalize;
|
|
327
|
+
internal.rootState = draft;
|
|
328
|
+
try {
|
|
329
|
+
result = fn.apply(sliceKey ? store.getState()[sliceKey] : store.getState(), args);
|
|
330
|
+
} finally {
|
|
331
|
+
if (result instanceof Promise) {
|
|
332
|
+
// if (process.env.NODE_ENV === 'development') {
|
|
333
|
+
// console.warn(
|
|
334
|
+
// 'It will be combined with the next state in the async function.'
|
|
335
|
+
// );
|
|
336
|
+
// }
|
|
337
|
+
return result.finally(() => {
|
|
338
|
+
const result = handleResult(isDrafted);
|
|
339
|
+
done?.(result);
|
|
340
|
+
return result;
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
handleResult(isDrafted);
|
|
344
|
+
}
|
|
345
|
+
done?.(result);
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
if (internal.mutableInstance && store.act) {
|
|
349
|
+
const result = store.act(() => {
|
|
350
|
+
return fn.apply(sliceKey ? store.getState()[sliceKey] : store.getState(), args);
|
|
351
|
+
});
|
|
352
|
+
done?.(result);
|
|
353
|
+
return result;
|
|
354
|
+
}
|
|
355
|
+
const result = fn.apply(sliceKey ? store.getState()[sliceKey] : store.getState(), args);
|
|
356
|
+
done?.(result);
|
|
357
|
+
return result;
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
// it should be a immutable state
|
|
363
|
+
const slice = Object.defineProperties({}, descriptors);
|
|
364
|
+
return slice;
|
|
365
|
+
};
|
|
366
|
+
if (store.isSliceStore) {
|
|
367
|
+
internal.module = {};
|
|
368
|
+
Object.entries(initialState).forEach(([key, value]) => {
|
|
369
|
+
rawState[key] = {};
|
|
370
|
+
internal.module[key] = handle(rawState[key], value, key);
|
|
371
|
+
});
|
|
372
|
+
} else {
|
|
373
|
+
internal.module = handle(rawState, initialState);
|
|
374
|
+
}
|
|
375
|
+
return rawState;
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
const handleState = (store, internal, options) => {
|
|
379
|
+
const setState = (next, updater = next => {
|
|
380
|
+
const merge = (_next = next) => {
|
|
381
|
+
mergeObject(internal.rootState, _next, store.isSliceStore);
|
|
382
|
+
};
|
|
383
|
+
const fn = typeof next === 'function' ? () => {
|
|
384
|
+
const returnValue = next(internal.module);
|
|
385
|
+
if (returnValue instanceof Promise) {
|
|
386
|
+
throw new Error('setState with async function is not supported');
|
|
387
|
+
}
|
|
388
|
+
if (typeof returnValue === 'object' && returnValue !== null) {
|
|
389
|
+
merge(returnValue);
|
|
390
|
+
}
|
|
391
|
+
} : merge;
|
|
392
|
+
const enablePatches = store.transport ?? options.enablePatches;
|
|
393
|
+
if (!enablePatches) {
|
|
394
|
+
if (internal.mutableInstance) {
|
|
395
|
+
if (store.act) {
|
|
396
|
+
store.act(() => {
|
|
397
|
+
fn.apply(null);
|
|
398
|
+
});
|
|
399
|
+
return [];
|
|
400
|
+
}
|
|
401
|
+
fn.apply(null);
|
|
402
|
+
return [];
|
|
403
|
+
}
|
|
404
|
+
// best performance by default for immutable state
|
|
405
|
+
// TODO: supporting nested set functions?
|
|
406
|
+
try {
|
|
407
|
+
internal.backupState = internal.rootState;
|
|
408
|
+
internal.rootState = mutative.create(internal.rootState, draft => {
|
|
409
|
+
internal.rootState = draft;
|
|
410
|
+
return fn.apply(null);
|
|
411
|
+
});
|
|
412
|
+
} catch (error) {
|
|
413
|
+
internal.rootState = internal.backupState;
|
|
414
|
+
throw error;
|
|
415
|
+
}
|
|
416
|
+
internal.listeners.forEach(listener => listener());
|
|
417
|
+
return [];
|
|
418
|
+
}
|
|
419
|
+
internal.backupState = internal.rootState;
|
|
420
|
+
let patches;
|
|
421
|
+
let inversePatches;
|
|
422
|
+
try {
|
|
423
|
+
const result = mutative.create(internal.rootState, draft => {
|
|
424
|
+
internal.rootState = draft;
|
|
425
|
+
return fn.apply(null);
|
|
426
|
+
}, {
|
|
427
|
+
enablePatches: true
|
|
428
|
+
});
|
|
429
|
+
patches = result[1];
|
|
430
|
+
inversePatches = result[2];
|
|
431
|
+
} finally {
|
|
432
|
+
internal.rootState = internal.backupState;
|
|
433
|
+
}
|
|
434
|
+
const finalPatches = store.patch ? store.patch({
|
|
435
|
+
patches,
|
|
436
|
+
inversePatches
|
|
437
|
+
}) : {
|
|
438
|
+
patches,
|
|
439
|
+
inversePatches
|
|
440
|
+
};
|
|
441
|
+
if (finalPatches.patches.length) {
|
|
442
|
+
store.apply(internal.rootState, finalPatches.patches);
|
|
443
|
+
if (!internal.mutableInstance) {
|
|
444
|
+
internal.listeners.forEach(listener => listener());
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return [internal.rootState, patches, inversePatches];
|
|
448
|
+
}) => {
|
|
449
|
+
if (store.share === 'client') {
|
|
450
|
+
throw new Error(`setState() cannot be called in the client store. To update the state, please trigger a store method with setState() instead.`);
|
|
451
|
+
}
|
|
452
|
+
if (internal.isBatching) {
|
|
453
|
+
throw new Error('setState cannot be called within the updater');
|
|
454
|
+
}
|
|
455
|
+
internal.isBatching = true;
|
|
456
|
+
let result;
|
|
457
|
+
try {
|
|
458
|
+
const isDrafted = internal.mutableInstance && mutative.isDraft(internal.rootState);
|
|
459
|
+
if (isDrafted) {
|
|
460
|
+
handleDraft(store, internal);
|
|
461
|
+
}
|
|
462
|
+
result = updater(next);
|
|
463
|
+
if (isDrafted) {
|
|
464
|
+
internal.backupState = internal.rootState;
|
|
465
|
+
const [draft, finalize] = mutative.create(internal.rootState, {
|
|
466
|
+
enablePatches: true
|
|
467
|
+
});
|
|
468
|
+
internal.finalizeDraft = finalize;
|
|
469
|
+
internal.rootState = draft;
|
|
470
|
+
}
|
|
471
|
+
} finally {
|
|
472
|
+
internal.isBatching = false;
|
|
473
|
+
}
|
|
474
|
+
emit(store, internal, result?.[1]);
|
|
475
|
+
return result;
|
|
476
|
+
};
|
|
477
|
+
const getState = (deps, selector) => deps && selector ? new Computed(deps, selector) : internal.module;
|
|
478
|
+
return {
|
|
479
|
+
setState,
|
|
480
|
+
getState
|
|
481
|
+
};
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
const applyMiddlewares = (store, middlewares) => {
|
|
485
|
+
return middlewares.reduce((store, middleware, index) => {
|
|
486
|
+
if (process.env.NODE_ENV === 'development') {
|
|
487
|
+
if (typeof middleware !== 'function') {
|
|
488
|
+
throw new Error(`middlewares[${index}] should be a function`);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return middleware(store);
|
|
492
|
+
}, store);
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* wrapStore is a function to wrap the store and return function to get the state with store.
|
|
497
|
+
*/
|
|
498
|
+
const wrapStore = (store, getState = () => store.getState()) => {
|
|
499
|
+
const {
|
|
500
|
+
name,
|
|
501
|
+
..._store
|
|
502
|
+
} = store;
|
|
503
|
+
return Object.assign({
|
|
504
|
+
[name]: (...args) => getState(...args)
|
|
505
|
+
}[name], _store);
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
const handleMainTransport = (store, internal, storeTransport, workerType, checkEnablePatches) => {
|
|
509
|
+
// store transport for server port
|
|
510
|
+
// the store transport is responsible for transmitting the sync state to the client transport.
|
|
511
|
+
const transport = storeTransport ?? (workerType === 'SharedWorkerInternal' || workerType === 'WebWorkerInternal' ? dataTransport.createTransport(workerType, {
|
|
512
|
+
prefix: store.name
|
|
513
|
+
}) : undefined);
|
|
514
|
+
if (!transport) return;
|
|
515
|
+
if (typeof transport.onConnect !== 'function') {
|
|
516
|
+
throw new Error('transport.onConnect is required');
|
|
517
|
+
}
|
|
518
|
+
if (checkEnablePatches) {
|
|
519
|
+
throw new Error(`enablePatches: true is required for the transport`);
|
|
520
|
+
}
|
|
521
|
+
transport.listen('execute', async (keys, args) => {
|
|
522
|
+
let base = store.getState();
|
|
523
|
+
let obj = base;
|
|
524
|
+
for (const key of keys) {
|
|
525
|
+
base = base[key];
|
|
526
|
+
if (typeof base === 'function') {
|
|
527
|
+
base = base.bind(obj);
|
|
528
|
+
}
|
|
529
|
+
obj = base;
|
|
530
|
+
}
|
|
531
|
+
if (process.env.NODE_ENV === 'development' && typeof base !== 'function') {
|
|
532
|
+
throw new Error('The function is not found');
|
|
533
|
+
}
|
|
534
|
+
try {
|
|
535
|
+
return base(...args);
|
|
536
|
+
} catch (error) {
|
|
537
|
+
console.error(error);
|
|
538
|
+
return {
|
|
539
|
+
$$Error: error.message
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
transport.listen('fullSync', async () => {
|
|
544
|
+
return {
|
|
545
|
+
state: JSON.stringify(internal.rootState),
|
|
546
|
+
sequence: internal.sequence
|
|
547
|
+
};
|
|
548
|
+
});
|
|
549
|
+
store.transport = transport;
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
const namespaceMap = new Map();
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Create a simple store or a shared store. The shared store can be used in a worker or another thread.
|
|
556
|
+
*/
|
|
557
|
+
const create = (createState, options = {}) => {
|
|
558
|
+
const checkEnablePatches = Object.hasOwnProperty.call(options, 'enablePatches') && !options.enablePatches;
|
|
559
|
+
const workerType = options.workerType ?? WorkerType;
|
|
560
|
+
if (process.env.NODE_ENV === 'development' && options.transport && options.clientTransport) {
|
|
561
|
+
throw new Error(`transport and clientTransport cannot be used together, please use one of them.`);
|
|
562
|
+
}
|
|
563
|
+
const storeTransport = options.transport;
|
|
564
|
+
const share = workerType === 'WebWorkerInternal' || workerType === 'SharedWorkerInternal' || storeTransport ? 'main' : undefined;
|
|
565
|
+
const createStore = ({
|
|
566
|
+
share
|
|
567
|
+
}) => {
|
|
568
|
+
const store = {};
|
|
569
|
+
const internal = {
|
|
570
|
+
sequence: 0,
|
|
571
|
+
isBatching: false,
|
|
572
|
+
listeners: new Set()
|
|
573
|
+
};
|
|
574
|
+
const name = options.name ?? defaultName;
|
|
575
|
+
// check if the store name is unique in main share mode
|
|
576
|
+
if (process.env.NODE_ENV === 'development' && share === 'main') {
|
|
577
|
+
if (namespaceMap.get(name)) {
|
|
578
|
+
throw new Error(`Store name '${name}' is not unique.`);
|
|
579
|
+
}
|
|
580
|
+
namespaceMap.set(name, true);
|
|
581
|
+
}
|
|
582
|
+
const {
|
|
583
|
+
setState,
|
|
584
|
+
getState
|
|
585
|
+
} = handleState(store, internal, options);
|
|
586
|
+
const subscribe = listener => {
|
|
587
|
+
internal.listeners.add(listener);
|
|
588
|
+
return () => internal.listeners.delete(listener);
|
|
589
|
+
};
|
|
590
|
+
const destroy = () => {
|
|
591
|
+
internal.listeners.clear();
|
|
592
|
+
store.transport?.dispose();
|
|
593
|
+
};
|
|
594
|
+
const apply = (state = internal.rootState, patches) => {
|
|
595
|
+
internal.rootState = patches ? mutative.apply(state, patches) : state;
|
|
596
|
+
internal.listeners.forEach(listener => listener());
|
|
597
|
+
};
|
|
598
|
+
const getPureState = () => internal.rootState;
|
|
599
|
+
const isSliceStore = typeof createState === 'object';
|
|
600
|
+
Object.assign(store, {
|
|
601
|
+
name,
|
|
602
|
+
share: share ?? false,
|
|
603
|
+
setState,
|
|
604
|
+
getState,
|
|
605
|
+
subscribe,
|
|
606
|
+
destroy,
|
|
607
|
+
apply,
|
|
608
|
+
isSliceStore,
|
|
609
|
+
getPureState
|
|
610
|
+
});
|
|
611
|
+
applyMiddlewares(store, options.middlewares ?? []);
|
|
612
|
+
const initialState = getInitialState(store, createState);
|
|
613
|
+
store.getInitialState = () => initialState;
|
|
614
|
+
internal.rootState = getRawState(store, internal, initialState, options);
|
|
615
|
+
return {
|
|
616
|
+
store,
|
|
617
|
+
internal
|
|
618
|
+
};
|
|
619
|
+
};
|
|
620
|
+
if (options.clientTransport || options.worker || options.workerType === 'WebWorkerClient' || options.workerType === 'SharedWorkerClient') {
|
|
621
|
+
if (checkEnablePatches) {
|
|
622
|
+
throw new Error(`enablePatches: true is required for the async store`);
|
|
623
|
+
}
|
|
624
|
+
const store = createAsyncClientStore(createStore, options);
|
|
625
|
+
return wrapStore(store);
|
|
626
|
+
}
|
|
627
|
+
const {
|
|
628
|
+
store,
|
|
629
|
+
internal
|
|
630
|
+
} = createStore({
|
|
631
|
+
share
|
|
632
|
+
});
|
|
633
|
+
handleMainTransport(store, internal, storeTransport, workerType, checkEnablePatches);
|
|
634
|
+
return wrapStore(store);
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* createBinder is a function to create a binder for the 3rd party store.
|
|
639
|
+
*/
|
|
640
|
+
function createBinder({
|
|
641
|
+
handleState,
|
|
642
|
+
handleStore
|
|
643
|
+
}) {
|
|
644
|
+
return state => {
|
|
645
|
+
const {
|
|
646
|
+
copyState,
|
|
647
|
+
key,
|
|
648
|
+
bind
|
|
649
|
+
} = handleState(state);
|
|
650
|
+
const value = key ? copyState[key] : copyState;
|
|
651
|
+
value[bindSymbol] = {
|
|
652
|
+
handleStore,
|
|
653
|
+
bind
|
|
654
|
+
};
|
|
655
|
+
return copyState;
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
exports.create = create;
|
|
660
|
+
exports.createBinder = createBinder;
|
|
661
|
+
exports.wrapStore = wrapStore;
|