@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.
Files changed (85) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/config/enableReactNativeComponents.js +15 -0
  3. package/config/enableReactNativeComponents.js.map +1 -1
  4. package/config/enableReactNativeComponents.mjs +16 -1
  5. package/config/enableReactNativeComponents.mjs.map +1 -1
  6. package/index.d.ts +3 -3
  7. package/index.js +84 -93
  8. package/index.js.map +1 -1
  9. package/index.mjs +84 -94
  10. package/index.mjs.map +1 -1
  11. package/package.json +21 -1
  12. package/persist-plugins/async-storage.d.ts +14 -0
  13. package/persist-plugins/async-storage.js +100 -0
  14. package/persist-plugins/async-storage.js.map +1 -0
  15. package/persist-plugins/async-storage.mjs +98 -0
  16. package/persist-plugins/async-storage.mjs.map +1 -0
  17. package/persist-plugins/fetch.d.ts +10 -0
  18. package/persist-plugins/fetch.js +22 -0
  19. package/persist-plugins/fetch.js.map +1 -0
  20. package/persist-plugins/fetch.mjs +20 -0
  21. package/persist-plugins/fetch.mjs.map +1 -0
  22. package/persist-plugins/firebase.d.ts +51 -0
  23. package/persist-plugins/firebase.js +694 -0
  24. package/persist-plugins/firebase.js.map +1 -0
  25. package/persist-plugins/firebase.mjs +692 -0
  26. package/persist-plugins/firebase.mjs.map +1 -0
  27. package/persist-plugins/indexeddb.d.ts +2 -3
  28. package/persist-plugins/indexeddb.js +1 -16
  29. package/persist-plugins/indexeddb.js.map +1 -1
  30. package/persist-plugins/indexeddb.mjs +1 -16
  31. package/persist-plugins/indexeddb.mjs.map +1 -1
  32. package/persist-plugins/local-storage.d.ts +1 -2
  33. package/persist-plugins/local-storage.js +1 -5
  34. package/persist-plugins/local-storage.js.map +1 -1
  35. package/persist-plugins/local-storage.mjs +1 -5
  36. package/persist-plugins/local-storage.mjs.map +1 -1
  37. package/persist-plugins/mmkv.d.ts +4 -4
  38. package/persist-plugins/mmkv.js +6 -4
  39. package/persist-plugins/mmkv.js.map +1 -1
  40. package/persist-plugins/mmkv.mjs +6 -4
  41. package/persist-plugins/mmkv.mjs.map +1 -1
  42. package/persist-plugins/query.d.ts +20 -0
  43. package/persist-plugins/query.js +89 -0
  44. package/persist-plugins/query.js.map +1 -0
  45. package/persist-plugins/query.mjs +87 -0
  46. package/persist-plugins/query.mjs.map +1 -0
  47. package/persist.js +157 -143
  48. package/persist.js.map +1 -1
  49. package/persist.mjs +158 -144
  50. package/persist.mjs.map +1 -1
  51. package/react-hooks/usePersistedObservable.d.ts +2 -2
  52. package/react-hooks/usePersistedObservable.js +1 -6
  53. package/react-hooks/usePersistedObservable.js.map +1 -1
  54. package/react-hooks/usePersistedObservable.mjs +1 -6
  55. package/react-hooks/usePersistedObservable.mjs.map +1 -1
  56. package/react.d.ts +1 -0
  57. package/react.js +84 -36
  58. package/react.js.map +1 -1
  59. package/react.mjs +84 -38
  60. package/react.mjs.map +1 -1
  61. package/src/ObservableObject.d.ts +3 -3
  62. package/src/globals.d.ts +1 -3
  63. package/src/is.d.ts +1 -0
  64. package/src/observable.d.ts +2 -2
  65. package/src/observableInterfaces.d.ts +77 -70
  66. package/src/observe.d.ts +1 -1
  67. package/src/persist/observablePersistRemoteFunctionsAdapter.d.ts +2 -0
  68. package/src/persist/persistObservable.d.ts +10 -13
  69. package/src/persist-plugins/async-storage.d.ts +14 -0
  70. package/src/persist-plugins/fetch.d.ts +10 -0
  71. package/src/persist-plugins/firebase.d.ts +51 -0
  72. package/src/persist-plugins/indexeddb.d.ts +2 -3
  73. package/src/persist-plugins/local-storage.d.ts +1 -2
  74. package/src/persist-plugins/mmkv.d.ts +4 -4
  75. package/src/persist-plugins/query.d.ts +20 -0
  76. package/src/react/For.d.ts +0 -1
  77. package/src/react/Reactive.d.ts +1 -1
  78. package/src/react/react-globals.d.ts +3 -0
  79. package/src/react/reactInterfaces.d.ts +8 -5
  80. package/src/react/useObservableState.d.ts +2 -0
  81. package/src/react/useWhen.d.ts +3 -0
  82. package/src/react-hooks/usePersistedObservable.d.ts +2 -2
  83. package/src/trackSelector.d.ts +2 -2
  84. package/src/tracking.d.ts +2 -3
  85. 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 observablePersistRemoteSimple({ get, set }) {
137
- return {
138
- async get({ dateModified, onChange, onLoad }) {
139
- const value = (await get({ dateModified }));
140
- onChange({ value, dateModified: Date.now() });
141
- onLoad();
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 adjustSaveData(value, path, pathTypes, { adjustData, fieldTransforms, }) {
164
- if (fieldTransforms || (adjustData === null || adjustData === void 0 ? void 0 : adjustData.save)) {
165
- const transform = () => {
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 (adjustData === null || adjustData === void 0 ? void 0 : adjustData.save) {
174
+ if (transform === null || transform === void 0 ? void 0 : transform.out) {
174
175
  const constructed = constructObjectWithPath(path, value, pathTypes);
175
- const saved = adjustData.save(constructed);
176
+ const saved = transform.out(constructed);
176
177
  const deconstruct = (toDeconstruct) => {
177
178
  value = deconstructObjectWithPath(path, toDeconstruct);
178
- return transform();
179
+ return transformFn();
179
180
  };
180
181
  return doInOrder(saved, deconstruct);
181
182
  }
182
- return transform();
183
+ return transformFn();
183
184
  }
184
185
  return { value, path };
185
186
  }
186
- function adjustLoadData(value, { adjustData, fieldTransforms, }, doUserAdjustData) {
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 (doUserAdjustData && (adjustData === null || adjustData === void 0 ? void 0 : adjustData.load)) {
192
- value = adjustData.load(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, obsState, persistOptions, newMetadata) {
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.updateMetadata(table, metadata, config);
213
+ await persistenceLocal.setMetadata(table, metadata, config);
213
214
  }
214
215
  if (modified) {
215
- obsState.dateModified.set(modified);
216
+ syncState.dateModified.set(modified);
216
217
  }
217
218
  }
218
219
  }
219
- function updateMetadata(obs, localState, obsState, persistOptions, newMetadata) {
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, obsState, persistOptions, newMetadata), 30);
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 adjustData.
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 adjustSaveData than others.
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 { obsState, changes, localState, persistOptions, inRemoteChange, isApplyingPending } = queuedChange;
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 && obsState.isEnabledLocal.peek();
252
- const saveRemote = !inRemoteChange && configRemote && !configRemote.readonly && obsState.isEnabledRemote.peek();
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 && !obsState.isLoadedLocal.peek()) {
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 promisesAdjustData = [];
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 promiseAdjustLocal = adjustSaveData(valueAtPath, path, pathTypes, configLocal);
284
- promisesAdjustData.push(doInOrder(promiseAdjustLocal, ({ path: pathAdjusted, value: valueAdjusted }) => {
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 (!pathAdjusted.includes(undefined)) {
287
- // Prepare the local change with the adjusted path/value
288
+ if (!pathTransformed.includes(undefined)) {
289
+ // Prepare the local change with the transformed path/value
288
290
  changesLocal.push({
289
- path: pathAdjusted,
291
+ path: pathTransformed,
290
292
  pathTypes,
291
293
  prevAtPath,
292
- valueAtPath: valueAdjusted,
294
+ valueAtPath: valueTransformed,
293
295
  pathStr,
294
296
  });
295
297
  }
296
298
  }));
297
299
  }
298
300
  if (saveRemote) {
299
- const promiseAdjustRemote = adjustSaveData(valueAtPath, path, pathTypes, configRemote);
300
- promisesAdjustData.push(doInOrder(promiseAdjustRemote, ({ path: pathAdjusted, value: valueAdjusted }) => {
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 (!pathAdjusted.includes(undefined)) {
304
+ if (!pathTransformed.includes(undefined)) {
303
305
  // Prepare pending changes
304
306
  if (!localState.pendingChanges) {
305
307
  localState.pendingChanges = {};
306
308
  }
307
- // The "p" saved in pending should be the previous state before changes,
308
- // so don't overwrite it if it already exists
309
- if (!localState.pendingChanges[pathStr]) {
310
- localState.pendingChanges[pathStr] = { p: prevAtPath !== null && prevAtPath !== void 0 ? prevAtPath : null, t: pathTypes };
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
- // Pending value is the unadjusted value because it gets loaded without adjustment
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: pathAdjusted,
340
+ path: pathTransformed,
318
341
  pathTypes,
319
342
  prevAtPath,
320
- valueAtPath: valueAdjusted,
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 adjustData promises, wait for them before saving
329
- promisesAdjustData = promisesAdjustData.filter(Boolean);
330
- if (promisesAdjustData.length > 0) {
331
- await Promise.all(promisesAdjustData);
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, obsState, localState, persistOptions } = queuedChange;
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
- if (changesRemote.length > 0) {
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, obsState, persistOptions, {
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(() => obsState.isLoadedRemote.get() || (configRemote.allowSaveIfError && obsState.remoteError.get()));
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
- const saves = await Promise.all(changesRemote.map(async (change) => {
371
- const { path, valueAtPath, prevAtPath, pathTypes, pathStr } = change;
372
- // Save to remote persistence
373
- return persistenceRemote
374
- .save({
375
- obs,
376
- state: obsState,
377
- options: persistOptions,
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 (saves.filter(Boolean).length > 0) {
390
- if (local) {
391
- const metadata = {};
392
- const pending = (_a = persistenceLocal.getMetadata(table, configLocal)) === null || _a === void 0 ? void 0 : _a.pending;
393
- let adjustedChanges = [];
394
- for (let i = 0; i < saves.length; i++) {
395
- const save = saves[i];
396
- if (save) {
397
- const { changes, dateModified, pathStr } = save;
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 localState.pendingChanges[pathStr];
418
+ delete pending[pathStr];
404
419
  metadata.pending = pending;
405
420
  }
406
- if (dateModified) {
407
- metadata.modified = dateModified;
408
- }
409
- // Remote can optionally have data that needs to be merged back into the observable,
410
- // for example Firebase may update dateModified with the server timestamp
411
- if (changes && !isEmpty(changes)) {
412
- adjustedChanges.push(adjustLoadData(changes, persistOptions.remote, false));
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
- if (adjustedChanges.length > 0) {
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, obsState, localState, persistOptions, { changes }) {
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
- obsState,
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, obsState, localState) {
461
- var _a, _b;
475
+ async function loadLocal(obs, persistOptions, syncState, localState) {
476
+ var _a;
462
477
  const { local } = persistOptions;
463
- const localPersistence = persistOptions.persistLocal || observablePersistConfiguration.persistLocal;
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.persistLocalOptions);
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
- obsState.dateModified.set(metadata.modified);
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
- // eslint-disable-next-line prefer-const
505
- let { adjustData, fieldTransforms } = config;
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
- obsState.peek().clearLocal = () => Promise.all([
534
+ syncState.peek().clearLocal = () => Promise.all([
528
535
  persistenceLocal.deleteTable(table, config),
529
536
  persistenceLocal.deleteMetadata(table, config),
530
537
  ]);
531
538
  }
532
- obsState.isLoadedLocal.set(true);
539
+ syncState.isLoadedLocal.set(true);
533
540
  }
534
- function persistObservable(obs, persistOptions) {
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.persistRemote || (observablePersistConfiguration === null || observablePersistConfiguration === void 0 ? void 0 : observablePersistConfiguration.persistRemote);
551
+ const remotePersistence = persistOptions.pluginRemote || (observablePersistConfiguration === null || observablePersistConfiguration === void 0 ? void 0 : observablePersistConfiguration.pluginRemote);
538
552
  const localState = {};
539
- const obsState = observable({
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, obsState, localState);
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 = observablePersistRemoteSimple(remotePersistence);
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).persist;
582
+ localState.persistenceRemote = mapPersistences.get(remotePersistence)
583
+ .persist;
569
584
  }
570
585
  let isSynced = false;
571
586
  const sync = async () => {
572
- var _a, _b;
587
+ var _a;
573
588
  if (!isSynced) {
574
589
  isSynced = true;
575
- localState.onSaveRemote = (_a = persistOptions.remote) === null || _a === void 0 ? void 0 : _a.onSaveRemote;
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: obsState,
592
+ state: syncState,
579
593
  obs,
580
594
  options: persistOptions,
581
595
  dateModified,
582
- onLoad: () => {
583
- obsState.isLoadedRemote.set(true);
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 = adjustLoadData(value, remote, true);
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, obsState, persistOptions, {
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(() => obsState.isLoadedRemote.get() || (remote.allowSaveIfError && obsState.remoteError.get()));
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, obsState, localState, persistOptions, {
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
- obsState.assign({ sync });
674
+ syncState.assign({ sync });
661
675
  }
662
676
  else {
663
- when(() => !local || obsState.isLoadedLocal.get(), sync);
677
+ when(() => !local || syncState.isLoadedLocal.get(), sync);
664
678
  }
665
679
  }
666
- when(!local || obsState.isLoadedLocal, function () {
667
- obs.onChange(onObsChange.bind(this, obs, obsState, localState, persistOptions));
680
+ when(!local || syncState.isLoadedLocal, function () {
681
+ obs.onChange(onObsChange.bind(this, obs, syncState, localState, persistOptions));
668
682
  });
669
- return obsState;
683
+ return [obs, syncState];
670
684
  }
671
685
 
672
686
  function isInRemoteChange() {