@legendapp/state 2.0.0-next.9 → 2.0.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/CHANGELOG.md +4 -0
- package/config/enableReactNativeComponents.js +15 -0
- package/config/enableReactNativeComponents.js.map +1 -1
- package/config/enableReactNativeComponents.mjs +16 -1
- package/config/enableReactNativeComponents.mjs.map +1 -1
- package/index.d.ts +3 -3
- package/index.js +84 -93
- package/index.js.map +1 -1
- package/index.mjs +84 -94
- package/index.mjs.map +1 -1
- package/package.json +21 -1
- package/persist-plugins/async-storage.d.ts +14 -0
- package/persist-plugins/async-storage.js +100 -0
- package/persist-plugins/async-storage.js.map +1 -0
- package/persist-plugins/async-storage.mjs +98 -0
- package/persist-plugins/async-storage.mjs.map +1 -0
- package/persist-plugins/fetch.d.ts +10 -0
- package/persist-plugins/fetch.js +22 -0
- package/persist-plugins/fetch.js.map +1 -0
- package/persist-plugins/fetch.mjs +20 -0
- package/persist-plugins/fetch.mjs.map +1 -0
- package/persist-plugins/firebase.d.ts +51 -0
- package/persist-plugins/firebase.js +694 -0
- package/persist-plugins/firebase.js.map +1 -0
- package/persist-plugins/firebase.mjs +692 -0
- package/persist-plugins/firebase.mjs.map +1 -0
- package/persist-plugins/indexeddb.d.ts +2 -3
- package/persist-plugins/indexeddb.js +1 -16
- package/persist-plugins/indexeddb.js.map +1 -1
- package/persist-plugins/indexeddb.mjs +1 -16
- package/persist-plugins/indexeddb.mjs.map +1 -1
- package/persist-plugins/local-storage.d.ts +1 -2
- package/persist-plugins/local-storage.js +1 -5
- package/persist-plugins/local-storage.js.map +1 -1
- package/persist-plugins/local-storage.mjs +1 -5
- package/persist-plugins/local-storage.mjs.map +1 -1
- package/persist-plugins/mmkv.d.ts +4 -4
- package/persist-plugins/mmkv.js +6 -4
- package/persist-plugins/mmkv.js.map +1 -1
- package/persist-plugins/mmkv.mjs +6 -4
- package/persist-plugins/mmkv.mjs.map +1 -1
- package/persist-plugins/query.d.ts +20 -0
- package/persist-plugins/query.js +89 -0
- package/persist-plugins/query.js.map +1 -0
- package/persist-plugins/query.mjs +87 -0
- package/persist-plugins/query.mjs.map +1 -0
- package/persist.js +157 -143
- package/persist.js.map +1 -1
- package/persist.mjs +158 -144
- package/persist.mjs.map +1 -1
- package/react-hooks/usePersistedObservable.d.ts +2 -2
- package/react-hooks/usePersistedObservable.js +1 -6
- package/react-hooks/usePersistedObservable.js.map +1 -1
- package/react-hooks/usePersistedObservable.mjs +1 -6
- package/react-hooks/usePersistedObservable.mjs.map +1 -1
- package/react.d.ts +1 -0
- package/react.js +84 -36
- package/react.js.map +1 -1
- package/react.mjs +84 -38
- package/react.mjs.map +1 -1
- package/src/ObservableObject.d.ts +3 -3
- package/src/globals.d.ts +1 -3
- package/src/is.d.ts +1 -0
- package/src/observable.d.ts +2 -2
- package/src/observableInterfaces.d.ts +77 -70
- package/src/observe.d.ts +1 -1
- package/src/persist/observablePersistRemoteFunctionsAdapter.d.ts +2 -0
- package/src/persist/persistObservable.d.ts +10 -13
- package/src/persist-plugins/async-storage.d.ts +14 -0
- package/src/persist-plugins/fetch.d.ts +10 -0
- package/src/persist-plugins/firebase.d.ts +51 -0
- package/src/persist-plugins/indexeddb.d.ts +2 -3
- package/src/persist-plugins/local-storage.d.ts +1 -2
- package/src/persist-plugins/mmkv.d.ts +4 -4
- package/src/persist-plugins/query.d.ts +20 -0
- package/src/react/For.d.ts +0 -1
- package/src/react/Reactive.d.ts +1 -1
- package/src/react/react-globals.d.ts +3 -0
- package/src/react/reactInterfaces.d.ts +8 -5
- package/src/react/useObservableState.d.ts +2 -0
- package/src/react/useWhen.d.ts +3 -0
- package/src/react-hooks/usePersistedObservable.d.ts +2 -2
- package/src/trackSelector.d.ts +2 -2
- package/src/tracking.d.ts +2 -3
- package/src/persist/observablePersistRemoteSimple.d.ts +0 -2
package/persist.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { symbolDelete, isString, isArray, isObject, constructObjectWithPath, deconstructObjectWithPath, observable, when, internal as internal$1, batch, isPromise, mergeIntoObservable, isEmpty, setInObservableAtPath, setAtPath } from '@legendapp/state';
|
|
1
|
+
import { symbolDelete, isString, isArray, isObject, constructObjectWithPath, deconstructObjectWithPath, observable, when, internal as internal$1, batch, isObservable, isFunction, isPromise, mergeIntoObservable, isEmpty, setInObservableAtPath, setAtPath } from '@legendapp/state';
|
|
2
2
|
|
|
3
3
|
const observablePersistConfiguration = {};
|
|
4
4
|
function configureObservablePersistence(options) {
|
|
@@ -133,17 +133,18 @@ if (process.env.NODE_ENV === 'development') {
|
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
function
|
|
137
|
-
|
|
138
|
-
async get(
|
|
139
|
-
const value = (await get(
|
|
140
|
-
onChange({ value, dateModified: Date.now() });
|
|
141
|
-
|
|
142
|
-
},
|
|
143
|
-
async save({ valueAtPath, prevAtPath, path, pathTypes, value }) {
|
|
144
|
-
return set ? set({ valueAtPath, path, pathTypes, prevAtPath, value }) : {};
|
|
136
|
+
function observablePersistRemoteFunctionsAdapter({ get, set, }) {
|
|
137
|
+
const ret = {
|
|
138
|
+
async get(params) {
|
|
139
|
+
const value = (await get(params));
|
|
140
|
+
params.onChange({ value, dateModified: Date.now() });
|
|
141
|
+
params.onGet();
|
|
145
142
|
},
|
|
146
143
|
};
|
|
144
|
+
if (set) {
|
|
145
|
+
ret.set = set;
|
|
146
|
+
}
|
|
147
|
+
return ret;
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
const mapPersistences = new WeakMap();
|
|
@@ -160,9 +161,9 @@ function parseLocalConfig(config) {
|
|
|
160
161
|
function doInOrder(arg1, arg2) {
|
|
161
162
|
return isPromise(arg1) ? arg1.then(arg2) : arg2(arg1);
|
|
162
163
|
}
|
|
163
|
-
function
|
|
164
|
-
if (fieldTransforms || (
|
|
165
|
-
const
|
|
164
|
+
function transformOutData(value, path, pathTypes, { transform, fieldTransforms }) {
|
|
165
|
+
if (fieldTransforms || (transform === null || transform === void 0 ? void 0 : transform.out)) {
|
|
166
|
+
const transformFn = () => {
|
|
166
167
|
if (fieldTransforms) {
|
|
167
168
|
const { obj, path: pathTransformed } = transformObjectWithPath(value, path, pathTypes, fieldTransforms);
|
|
168
169
|
value = obj;
|
|
@@ -170,30 +171,30 @@ function adjustSaveData(value, path, pathTypes, { adjustData, fieldTransforms, }
|
|
|
170
171
|
}
|
|
171
172
|
return { value, path };
|
|
172
173
|
};
|
|
173
|
-
if (
|
|
174
|
+
if (transform === null || transform === void 0 ? void 0 : transform.out) {
|
|
174
175
|
const constructed = constructObjectWithPath(path, value, pathTypes);
|
|
175
|
-
const saved =
|
|
176
|
+
const saved = transform.out(constructed);
|
|
176
177
|
const deconstruct = (toDeconstruct) => {
|
|
177
178
|
value = deconstructObjectWithPath(path, toDeconstruct);
|
|
178
|
-
return
|
|
179
|
+
return transformFn();
|
|
179
180
|
};
|
|
180
181
|
return doInOrder(saved, deconstruct);
|
|
181
182
|
}
|
|
182
|
-
return
|
|
183
|
+
return transformFn();
|
|
183
184
|
}
|
|
184
185
|
return { value, path };
|
|
185
186
|
}
|
|
186
|
-
function
|
|
187
|
+
function transformLoadData(value, { transform, fieldTransforms }, doUserTransform) {
|
|
187
188
|
if (fieldTransforms) {
|
|
188
189
|
const inverted = invertFieldMap(fieldTransforms);
|
|
189
190
|
value = transformObject(value, inverted);
|
|
190
191
|
}
|
|
191
|
-
if (
|
|
192
|
-
value =
|
|
192
|
+
if (doUserTransform && (transform === null || transform === void 0 ? void 0 : transform.in)) {
|
|
193
|
+
value = transform.in(value);
|
|
193
194
|
}
|
|
194
195
|
return value;
|
|
195
196
|
}
|
|
196
|
-
async function updateMetadataImmediate(obs, localState,
|
|
197
|
+
async function updateMetadataImmediate(obs, localState, syncState, persistOptions, newMetadata) {
|
|
197
198
|
const saves = Array.from(promisesLocalSaves);
|
|
198
199
|
if (saves.length > 0) {
|
|
199
200
|
await Promise.all(saves);
|
|
@@ -209,18 +210,18 @@ async function updateMetadataImmediate(obs, localState, obsState, persistOptions
|
|
|
209
210
|
const metadata = Object.assign({}, oldMetadata, newMetadata);
|
|
210
211
|
metadatas.set(obs, metadata);
|
|
211
212
|
if (persistenceLocal) {
|
|
212
|
-
await persistenceLocal.
|
|
213
|
+
await persistenceLocal.setMetadata(table, metadata, config);
|
|
213
214
|
}
|
|
214
215
|
if (modified) {
|
|
215
|
-
|
|
216
|
+
syncState.dateModified.set(modified);
|
|
216
217
|
}
|
|
217
218
|
}
|
|
218
219
|
}
|
|
219
|
-
function updateMetadata(obs, localState,
|
|
220
|
+
function updateMetadata(obs, localState, syncState, persistOptions, newMetadata) {
|
|
220
221
|
if (localState.timeoutSaveMetadata) {
|
|
221
222
|
clearTimeout(localState.timeoutSaveMetadata);
|
|
222
223
|
}
|
|
223
|
-
localState.timeoutSaveMetadata = setTimeout(() => updateMetadataImmediate(obs, localState,
|
|
224
|
+
localState.timeoutSaveMetadata = setTimeout(() => updateMetadataImmediate(obs, localState, syncState, persistOptions, newMetadata), 30);
|
|
224
225
|
}
|
|
225
226
|
let _queuedChanges = [];
|
|
226
227
|
async function processQueuedChanges() {
|
|
@@ -228,9 +229,9 @@ async function processQueuedChanges() {
|
|
|
228
229
|
const queuedChanges = _queuedChanges;
|
|
229
230
|
_queuedChanges = [];
|
|
230
231
|
// Note: Summary of the order of operations these functions:
|
|
231
|
-
// 1. Prepare all changes for saving. This may involve waiting for promises if the user has asynchronous
|
|
232
|
+
// 1. Prepare all changes for saving. This may involve waiting for promises if the user has asynchronous transform.
|
|
232
233
|
// We need to prepare all of the changes in the queue before saving so that the saves happen in the correct order,
|
|
233
|
-
// since some may take longer to
|
|
234
|
+
// since some may take longer to transformSaveData than others.
|
|
234
235
|
const changes = await Promise.all(queuedChanges.map(prepChange));
|
|
235
236
|
// 2. Save pending to the metadata table first. If this is the only operation that succeeds, it would try to save
|
|
236
237
|
// the current value again on next load, which isn't too bad.
|
|
@@ -244,21 +245,22 @@ async function processQueuedChanges() {
|
|
|
244
245
|
changes.forEach(doChange);
|
|
245
246
|
}
|
|
246
247
|
async function prepChange(queuedChange) {
|
|
247
|
-
const {
|
|
248
|
+
const { syncState, changes, localState, persistOptions, inRemoteChange, isApplyingPending } = queuedChange;
|
|
248
249
|
const local = persistOptions.local;
|
|
250
|
+
const { persistenceRemote } = localState;
|
|
249
251
|
const { config: configLocal } = parseLocalConfig(local);
|
|
250
252
|
const configRemote = persistOptions.remote;
|
|
251
|
-
const saveLocal = local && !configLocal.readonly && !isApplyingPending &&
|
|
252
|
-
const saveRemote = !inRemoteChange &&
|
|
253
|
+
const saveLocal = local && !configLocal.readonly && !isApplyingPending && syncState.isEnabledLocal.peek();
|
|
254
|
+
const saveRemote = !inRemoteChange && persistenceRemote && !(configRemote === null || configRemote === void 0 ? void 0 : configRemote.readonly) && syncState.isEnabledRemote.peek();
|
|
253
255
|
if (saveLocal || saveRemote) {
|
|
254
|
-
if (saveLocal && !
|
|
256
|
+
if (saveLocal && !syncState.isLoadedLocal.peek()) {
|
|
255
257
|
console.error('[legend-state] WARNING: An observable was changed before being loaded from persistence', local);
|
|
256
258
|
return;
|
|
257
259
|
}
|
|
258
260
|
const changesLocal = [];
|
|
259
261
|
const changesRemote = [];
|
|
260
262
|
const changesPaths = new Set();
|
|
261
|
-
let
|
|
263
|
+
let promisesTransform = [];
|
|
262
264
|
// Reverse order
|
|
263
265
|
for (let i = changes.length - 1; i >= 0; i--) {
|
|
264
266
|
const { path } = changes[i];
|
|
@@ -280,44 +282,65 @@ async function prepChange(queuedChange) {
|
|
|
280
282
|
changesPaths.add(pathStr);
|
|
281
283
|
const { prevAtPath, valueAtPath, pathTypes } = changes[i];
|
|
282
284
|
if (saveLocal) {
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
+
const promiseTransformLocal = transformOutData(valueAtPath, path, pathTypes, configLocal);
|
|
286
|
+
promisesTransform.push(doInOrder(promiseTransformLocal, ({ path: pathTransformed, value: valueTransformed }) => {
|
|
285
287
|
// If path includes undefined there was a null in fieldTransforms so don't need to save it
|
|
286
|
-
if (!
|
|
287
|
-
// Prepare the local change with the
|
|
288
|
+
if (!pathTransformed.includes(undefined)) {
|
|
289
|
+
// Prepare the local change with the transformed path/value
|
|
288
290
|
changesLocal.push({
|
|
289
|
-
path:
|
|
291
|
+
path: pathTransformed,
|
|
290
292
|
pathTypes,
|
|
291
293
|
prevAtPath,
|
|
292
|
-
valueAtPath:
|
|
294
|
+
valueAtPath: valueTransformed,
|
|
293
295
|
pathStr,
|
|
294
296
|
});
|
|
295
297
|
}
|
|
296
298
|
}));
|
|
297
299
|
}
|
|
298
300
|
if (saveRemote) {
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
+
const promiseTransformRemote = transformOutData(valueAtPath, path, pathTypes, configRemote || {});
|
|
302
|
+
promisesTransform.push(doInOrder(promiseTransformRemote, ({ path: pathTransformed, value: valueTransformed }) => {
|
|
301
303
|
// If path includes undefined there was a null in fieldTransforms so don't need to save it
|
|
302
|
-
if (!
|
|
304
|
+
if (!pathTransformed.includes(undefined)) {
|
|
303
305
|
// Prepare pending changes
|
|
304
306
|
if (!localState.pendingChanges) {
|
|
305
307
|
localState.pendingChanges = {};
|
|
306
308
|
}
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
|
|
309
|
+
// First look for existing pending changes at a higher level than this change
|
|
310
|
+
// If they exist then merge this change into it
|
|
311
|
+
const split = pathStr.split('/');
|
|
312
|
+
let found = false;
|
|
313
|
+
for (let i = 0; !found && i < split.length - 1; i++) {
|
|
314
|
+
const pathParent = split.slice(0, i + 1).join('/');
|
|
315
|
+
if (localState.pendingChanges[pathParent]) {
|
|
316
|
+
found = true;
|
|
317
|
+
const pathChild = split.slice(i + 1);
|
|
318
|
+
setAtPath(localState.pendingChanges[pathParent].v, pathChild, [], valueAtPath);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (!found) {
|
|
322
|
+
// If an existing pending change is deeper than this change, just delete it
|
|
323
|
+
// in favor of this wider change
|
|
324
|
+
for (const key in localState.pendingChanges) {
|
|
325
|
+
if (key !== pathStr && key.startsWith(pathStr)) {
|
|
326
|
+
delete localState.pendingChanges[key];
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// The "p" saved in pending should be the previous state before changes,
|
|
330
|
+
// so don't overwrite it if it already exists
|
|
331
|
+
if (!localState.pendingChanges[pathStr]) {
|
|
332
|
+
localState.pendingChanges[pathStr] = { p: prevAtPath !== null && prevAtPath !== void 0 ? prevAtPath : null, t: pathTypes };
|
|
333
|
+
}
|
|
334
|
+
// Pending value is the untransformed value because it gets loaded without transformment
|
|
335
|
+
// and forwarded through to onObsChange where it gets transformed before save
|
|
336
|
+
localState.pendingChanges[pathStr].v = valueAtPath;
|
|
311
337
|
}
|
|
312
|
-
//
|
|
313
|
-
// and forwarded through to onObsChange where it gets adjusted before save
|
|
314
|
-
localState.pendingChanges[pathStr].v = valueAtPath;
|
|
315
|
-
// Prepare the remote change with the adjusted path/value
|
|
338
|
+
// Prepare the remote change with the transformed path/value
|
|
316
339
|
changesRemote.push({
|
|
317
|
-
path:
|
|
340
|
+
path: pathTransformed,
|
|
318
341
|
pathTypes,
|
|
319
342
|
prevAtPath,
|
|
320
|
-
valueAtPath:
|
|
343
|
+
valueAtPath: valueTransformed,
|
|
321
344
|
pathStr,
|
|
322
345
|
});
|
|
323
346
|
}
|
|
@@ -325,27 +348,28 @@ async function prepChange(queuedChange) {
|
|
|
325
348
|
}
|
|
326
349
|
}
|
|
327
350
|
}
|
|
328
|
-
// If there's any
|
|
329
|
-
|
|
330
|
-
if (
|
|
331
|
-
await Promise.all(
|
|
351
|
+
// If there's any transform promises, wait for them before saving
|
|
352
|
+
promisesTransform = promisesTransform.filter(Boolean);
|
|
353
|
+
if (promisesTransform.length > 0) {
|
|
354
|
+
await Promise.all(promisesTransform);
|
|
332
355
|
}
|
|
333
356
|
return { queuedChange, changesLocal, changesRemote };
|
|
334
357
|
}
|
|
335
358
|
}
|
|
336
359
|
async function doChange(changeInfo) {
|
|
337
|
-
var _a, _b;
|
|
360
|
+
var _a, _b, _c;
|
|
338
361
|
if (!changeInfo)
|
|
339
362
|
return;
|
|
340
363
|
const { queuedChange, changesLocal, changesRemote } = changeInfo;
|
|
341
|
-
const { obs,
|
|
364
|
+
const { obs, syncState, localState, persistOptions } = queuedChange;
|
|
342
365
|
const { persistenceLocal, persistenceRemote } = localState;
|
|
343
366
|
const local = persistOptions.local;
|
|
344
367
|
const { table, config: configLocal } = parseLocalConfig(local);
|
|
345
368
|
const configRemote = persistOptions.remote;
|
|
346
|
-
|
|
369
|
+
const shouldSaveMetadata = local && (configRemote === null || configRemote === void 0 ? void 0 : configRemote.offlineBehavior) === 'retry';
|
|
370
|
+
if (changesRemote.length > 0 && shouldSaveMetadata) {
|
|
347
371
|
// First save pending changes before saving local or remote
|
|
348
|
-
await updateMetadataImmediate(obs, localState,
|
|
372
|
+
await updateMetadataImmediate(obs, localState, syncState, persistOptions, {
|
|
349
373
|
pending: localState.pendingChanges,
|
|
350
374
|
});
|
|
351
375
|
}
|
|
@@ -365,76 +389,67 @@ async function doChange(changeInfo) {
|
|
|
365
389
|
}
|
|
366
390
|
if (changesRemote.length > 0) {
|
|
367
391
|
// Wait for remote to be ready before saving
|
|
368
|
-
await when(() =>
|
|
392
|
+
await when(() => syncState.isLoadedRemote.get() || ((configRemote === null || configRemote === void 0 ? void 0 : configRemote.allowSetIfError) && syncState.remoteError.get()));
|
|
369
393
|
const value = obs.peek();
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
path: path,
|
|
379
|
-
pathTypes,
|
|
380
|
-
valueAtPath,
|
|
381
|
-
prevAtPath,
|
|
382
|
-
value,
|
|
383
|
-
})
|
|
384
|
-
.then(({ changes, dateModified }) => ({ changes, dateModified, pathStr }));
|
|
385
|
-
}));
|
|
394
|
+
(_a = configRemote === null || configRemote === void 0 ? void 0 : configRemote.onBeforeSet) === null || _a === void 0 ? void 0 : _a.call(configRemote);
|
|
395
|
+
const saved = await persistenceRemote.set({
|
|
396
|
+
obs,
|
|
397
|
+
syncState: syncState,
|
|
398
|
+
options: persistOptions,
|
|
399
|
+
changes: changesRemote,
|
|
400
|
+
value,
|
|
401
|
+
}).catch((err) => { var _a; return (_a = configRemote === null || configRemote === void 0 ? void 0 : configRemote.onSetError) === null || _a === void 0 ? void 0 : _a.call(configRemote, err); });
|
|
386
402
|
// If this remote save changed anything then update persistence and metadata
|
|
387
403
|
// Because save happens after a timeout and they're batched together, some calls to save will
|
|
388
404
|
// return saved data and others won't, so those can be ignored.
|
|
389
|
-
if (
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
|
|
405
|
+
if (saved) {
|
|
406
|
+
const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
|
|
407
|
+
const { changes, dateModified } = saved;
|
|
408
|
+
if (pathStrs.length > 0) {
|
|
409
|
+
if (local) {
|
|
410
|
+
const metadata = {};
|
|
411
|
+
const pending = (_b = persistenceLocal.getMetadata(table, configLocal)) === null || _b === void 0 ? void 0 : _b.pending;
|
|
412
|
+
let transformedChanges = [];
|
|
413
|
+
for (let i = 0; i < pathStrs.length; i++) {
|
|
414
|
+
const pathStr = pathStrs[i];
|
|
398
415
|
// Clear pending for this path
|
|
399
416
|
if (pending === null || pending === void 0 ? void 0 : pending[pathStr]) {
|
|
400
|
-
// Remove pending from the saved object
|
|
401
|
-
delete pending[pathStr];
|
|
402
417
|
// Remove pending from local state
|
|
403
|
-
delete
|
|
418
|
+
delete pending[pathStr];
|
|
404
419
|
metadata.pending = pending;
|
|
405
420
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
421
|
+
}
|
|
422
|
+
if (dateModified) {
|
|
423
|
+
metadata.modified = dateModified;
|
|
424
|
+
}
|
|
425
|
+
// Remote can optionally have data that needs to be merged back into the observable,
|
|
426
|
+
// for example Firebase may update dateModified with the server timestamp
|
|
427
|
+
if (changes && !isEmpty(changes)) {
|
|
428
|
+
transformedChanges.push(transformLoadData(changes, persistOptions.remote, false));
|
|
429
|
+
}
|
|
430
|
+
if (transformedChanges.length > 0) {
|
|
431
|
+
if (transformedChanges.some((change) => isPromise(change))) {
|
|
432
|
+
transformedChanges = await Promise.all(transformedChanges);
|
|
413
433
|
}
|
|
434
|
+
onChangeRemote(() => mergeIntoObservable(obs, ...transformedChanges));
|
|
414
435
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (adjustedChanges.some((change) => isPromise(change))) {
|
|
418
|
-
adjustedChanges = await Promise.all(adjustedChanges);
|
|
436
|
+
if (shouldSaveMetadata && !isEmpty(metadata)) {
|
|
437
|
+
updateMetadata(obs, localState, syncState, persistOptions, metadata);
|
|
419
438
|
}
|
|
420
|
-
onChangeRemote(() => mergeIntoObservable(obs, ...adjustedChanges));
|
|
421
|
-
}
|
|
422
|
-
if (local && !isEmpty(metadata)) {
|
|
423
|
-
updateMetadata(obs, localState, obsState, persistOptions, metadata);
|
|
424
439
|
}
|
|
440
|
+
(_c = configRemote === null || configRemote === void 0 ? void 0 : configRemote.onSet) === null || _c === void 0 ? void 0 : _c.call(configRemote);
|
|
425
441
|
}
|
|
426
|
-
(_b = localState.onSaveRemote) === null || _b === void 0 ? void 0 : _b.call(localState);
|
|
427
442
|
}
|
|
428
443
|
}
|
|
429
444
|
}
|
|
430
|
-
function onObsChange(obs,
|
|
445
|
+
function onObsChange(obs, syncState, localState, persistOptions, { changes }) {
|
|
431
446
|
if (!internal$1.globalState.isLoadingLocal) {
|
|
432
447
|
const inRemoteChange = internal$1.globalState.isLoadingRemote;
|
|
433
448
|
const isApplyingPending = localState.isApplyingPending;
|
|
434
449
|
// Queue changes in a microtask so that multiple changes within a frame get run together
|
|
435
450
|
_queuedChanges.push({
|
|
436
451
|
obs: obs,
|
|
437
|
-
|
|
452
|
+
syncState,
|
|
438
453
|
localState,
|
|
439
454
|
persistOptions,
|
|
440
455
|
changes,
|
|
@@ -457,10 +472,10 @@ function onChangeRemote(cb) {
|
|
|
457
472
|
});
|
|
458
473
|
});
|
|
459
474
|
}
|
|
460
|
-
async function loadLocal(obs, persistOptions,
|
|
461
|
-
var _a
|
|
475
|
+
async function loadLocal(obs, persistOptions, syncState, localState) {
|
|
476
|
+
var _a;
|
|
462
477
|
const { local } = persistOptions;
|
|
463
|
-
const localPersistence = persistOptions.
|
|
478
|
+
const localPersistence = persistOptions.pluginLocal || observablePersistConfiguration.pluginLocal;
|
|
464
479
|
if (local) {
|
|
465
480
|
const { table, config } = parseLocalConfig(local);
|
|
466
481
|
if (!localPersistence) {
|
|
@@ -472,7 +487,7 @@ async function loadLocal(obs, persistOptions, obsState, localState) {
|
|
|
472
487
|
const mapValue = { persist: persistenceLocal, initialized: observable(false) };
|
|
473
488
|
mapPersistences.set(localPersistence, mapValue);
|
|
474
489
|
if (persistenceLocal.initialize) {
|
|
475
|
-
const initializePromise = (_a = persistenceLocal.initialize) === null || _a === void 0 ? void 0 : _a.call(persistenceLocal, observablePersistConfiguration.
|
|
490
|
+
const initializePromise = (_a = persistenceLocal.initialize) === null || _a === void 0 ? void 0 : _a.call(persistenceLocal, observablePersistConfiguration.localOptions || {});
|
|
476
491
|
if (isPromise(initializePromise)) {
|
|
477
492
|
await initializePromise;
|
|
478
493
|
}
|
|
@@ -497,20 +512,12 @@ async function loadLocal(obs, persistOptions, obsState, localState) {
|
|
|
497
512
|
if (metadata) {
|
|
498
513
|
metadatas.set(obs, metadata);
|
|
499
514
|
localState.pendingChanges = metadata.pending;
|
|
500
|
-
|
|
515
|
+
syncState.dateModified.set(metadata.modified);
|
|
501
516
|
}
|
|
502
517
|
// Merge the data from local persistence into the default state
|
|
503
518
|
if (value !== null && value !== undefined) {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
if (fieldTransforms) {
|
|
507
|
-
const valueLoaded = (_b = persistenceLocal.getTableTransformed) === null || _b === void 0 ? void 0 : _b.call(persistenceLocal, table, config);
|
|
508
|
-
if (valueLoaded) {
|
|
509
|
-
value = valueLoaded;
|
|
510
|
-
fieldTransforms = undefined;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
value = adjustLoadData(value, { adjustData, fieldTransforms }, true);
|
|
519
|
+
const { transform, fieldTransforms } = config;
|
|
520
|
+
value = transformLoadData(value, { transform, fieldTransforms }, true);
|
|
514
521
|
if (isPromise(value)) {
|
|
515
522
|
value = await value;
|
|
516
523
|
}
|
|
@@ -524,19 +531,26 @@ async function loadLocal(obs, persistOptions, obsState, localState) {
|
|
|
524
531
|
internal$1.globalState.isLoadingLocal = false;
|
|
525
532
|
});
|
|
526
533
|
}
|
|
527
|
-
|
|
534
|
+
syncState.peek().clearLocal = () => Promise.all([
|
|
528
535
|
persistenceLocal.deleteTable(table, config),
|
|
529
536
|
persistenceLocal.deleteMetadata(table, config),
|
|
530
537
|
]);
|
|
531
538
|
}
|
|
532
|
-
|
|
539
|
+
syncState.isLoadedLocal.set(true);
|
|
533
540
|
}
|
|
534
|
-
function persistObservable(
|
|
541
|
+
function persistObservable(initialOrObservable, persistOptions) {
|
|
542
|
+
const obs = (isObservable(initialOrObservable)
|
|
543
|
+
? initialOrObservable
|
|
544
|
+
: observable(isFunction(initialOrObservable) ? initialOrObservable() : initialOrObservable));
|
|
545
|
+
// Merge remote persist options with clobal options
|
|
546
|
+
if (persistOptions.remote) {
|
|
547
|
+
persistOptions.remote = Object.assign({}, observablePersistConfiguration.remoteOptions, persistOptions.remote);
|
|
548
|
+
}
|
|
535
549
|
let { remote } = persistOptions;
|
|
536
550
|
const { local } = persistOptions;
|
|
537
|
-
const remotePersistence = persistOptions.
|
|
551
|
+
const remotePersistence = persistOptions.pluginRemote || (observablePersistConfiguration === null || observablePersistConfiguration === void 0 ? void 0 : observablePersistConfiguration.pluginRemote);
|
|
538
552
|
const localState = {};
|
|
539
|
-
const
|
|
553
|
+
const syncState = observable({
|
|
540
554
|
isLoadedLocal: false,
|
|
541
555
|
isLoadedRemote: false,
|
|
542
556
|
isEnabledLocal: true,
|
|
@@ -546,7 +560,7 @@ function persistObservable(obs, persistOptions) {
|
|
|
546
560
|
getPendingChanges: () => localState.pendingChanges,
|
|
547
561
|
});
|
|
548
562
|
if (local) {
|
|
549
|
-
loadLocal(obs, persistOptions,
|
|
563
|
+
loadLocal(obs, persistOptions, syncState, localState);
|
|
550
564
|
}
|
|
551
565
|
if (remote || remotePersistence) {
|
|
552
566
|
if (!remotePersistence) {
|
|
@@ -556,7 +570,7 @@ function persistObservable(obs, persistOptions) {
|
|
|
556
570
|
remote = {};
|
|
557
571
|
}
|
|
558
572
|
if (isObject(remotePersistence)) {
|
|
559
|
-
localState.persistenceRemote =
|
|
573
|
+
localState.persistenceRemote = observablePersistRemoteFunctionsAdapter(remotePersistence);
|
|
560
574
|
}
|
|
561
575
|
else {
|
|
562
576
|
// Ensure there's only one instance of the persistence plugin
|
|
@@ -565,28 +579,28 @@ function persistObservable(obs, persistOptions) {
|
|
|
565
579
|
persist: new remotePersistence(),
|
|
566
580
|
});
|
|
567
581
|
}
|
|
568
|
-
localState.persistenceRemote = mapPersistences.get(remotePersistence)
|
|
582
|
+
localState.persistenceRemote = mapPersistences.get(remotePersistence)
|
|
583
|
+
.persist;
|
|
569
584
|
}
|
|
570
585
|
let isSynced = false;
|
|
571
586
|
const sync = async () => {
|
|
572
|
-
var _a
|
|
587
|
+
var _a;
|
|
573
588
|
if (!isSynced) {
|
|
574
589
|
isSynced = true;
|
|
575
|
-
|
|
576
|
-
const dateModified = (_b = metadatas.get(obs)) === null || _b === void 0 ? void 0 : _b.modified;
|
|
590
|
+
const dateModified = (_a = metadatas.get(obs)) === null || _a === void 0 ? void 0 : _a.modified;
|
|
577
591
|
localState.persistenceRemote.get({
|
|
578
|
-
state:
|
|
592
|
+
state: syncState,
|
|
579
593
|
obs,
|
|
580
594
|
options: persistOptions,
|
|
581
595
|
dateModified,
|
|
582
|
-
|
|
583
|
-
|
|
596
|
+
onGet: () => {
|
|
597
|
+
syncState.isLoadedRemote.set(true);
|
|
584
598
|
},
|
|
585
599
|
onChange: async ({ value, path = [], pathTypes = [], mode = 'set', dateModified }) => {
|
|
586
600
|
// Note: value is the constructed value, path is used for setInObservableAtPath
|
|
587
601
|
// to start the set into the observable from the path
|
|
588
602
|
if (value !== undefined) {
|
|
589
|
-
value =
|
|
603
|
+
value = transformLoadData(value, remote, true);
|
|
590
604
|
if (isPromise(value)) {
|
|
591
605
|
value = await value;
|
|
592
606
|
}
|
|
@@ -625,14 +639,14 @@ function persistObservable(obs, persistOptions) {
|
|
|
625
639
|
}
|
|
626
640
|
}
|
|
627
641
|
if (dateModified && local) {
|
|
628
|
-
updateMetadata(obs, localState,
|
|
642
|
+
updateMetadata(obs, localState, syncState, persistOptions, {
|
|
629
643
|
modified: dateModified,
|
|
630
644
|
});
|
|
631
645
|
}
|
|
632
646
|
},
|
|
633
647
|
});
|
|
634
648
|
// Wait for remote to be ready before saving pending
|
|
635
|
-
await when(() =>
|
|
649
|
+
await when(() => syncState.isLoadedRemote.get() || (remote.allowSetIfError && syncState.remoteError.get()));
|
|
636
650
|
const pending = localState.pendingChanges;
|
|
637
651
|
if (pending && !isEmpty(pending)) {
|
|
638
652
|
localState.isApplyingPending = true;
|
|
@@ -646,7 +660,7 @@ function persistObservable(obs, persistOptions) {
|
|
|
646
660
|
changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
|
|
647
661
|
}
|
|
648
662
|
// Send the changes into onObsChange so that they get persisted remotely
|
|
649
|
-
onObsChange(obs,
|
|
663
|
+
onObsChange(obs, syncState, localState, persistOptions, {
|
|
650
664
|
value: obs.peek(),
|
|
651
665
|
// TODO getPrevious if any remote persistence layers need it
|
|
652
666
|
getPrevious: () => undefined,
|
|
@@ -657,16 +671,16 @@ function persistObservable(obs, persistOptions) {
|
|
|
657
671
|
}
|
|
658
672
|
};
|
|
659
673
|
if (remote.manual) {
|
|
660
|
-
|
|
674
|
+
syncState.assign({ sync });
|
|
661
675
|
}
|
|
662
676
|
else {
|
|
663
|
-
when(() => !local ||
|
|
677
|
+
when(() => !local || syncState.isLoadedLocal.get(), sync);
|
|
664
678
|
}
|
|
665
679
|
}
|
|
666
|
-
when(!local ||
|
|
667
|
-
obs.onChange(onObsChange.bind(this, obs,
|
|
680
|
+
when(!local || syncState.isLoadedLocal, function () {
|
|
681
|
+
obs.onChange(onObsChange.bind(this, obs, syncState, localState, persistOptions));
|
|
668
682
|
});
|
|
669
|
-
return
|
|
683
|
+
return [obs, syncState];
|
|
670
684
|
}
|
|
671
685
|
|
|
672
686
|
function isInRemoteChange() {
|