@legendapp/state 3.0.0-beta.2 → 3.0.0-beta.21

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 (74) hide show
  1. package/.DS_Store +0 -0
  2. package/config/enableReactComponents.js +3 -1
  3. package/config/enableReactComponents.mjs +3 -1
  4. package/config/enableReactTracking.d.mts +2 -1
  5. package/config/enableReactTracking.d.ts +2 -1
  6. package/config/enableReactTracking.js +32 -13
  7. package/config/enableReactTracking.mjs +32 -13
  8. package/index.d.mts +13 -4
  9. package/index.d.ts +13 -4
  10. package/index.js +70 -22
  11. package/index.mjs +70 -22
  12. package/package.json +22 -1
  13. package/persist-plugins/async-storage.js +17 -9
  14. package/persist-plugins/async-storage.mjs +17 -9
  15. package/react-native.d.mts +4 -0
  16. package/react-native.d.ts +4 -0
  17. package/react-native.js +53 -0
  18. package/react-native.mjs +40 -0
  19. package/react-reactive/Components.d.mts +19 -0
  20. package/react-reactive/Components.d.ts +19 -0
  21. package/react-reactive/Components.js +53 -0
  22. package/react-reactive/Components.mjs +40 -0
  23. package/react-reactive/enableReactComponents.d.mts +3 -2
  24. package/react-reactive/enableReactComponents.d.ts +3 -2
  25. package/react-reactive/enableReactComponents.js +10 -3
  26. package/react-reactive/enableReactComponents.mjs +10 -3
  27. package/react-reactive/enableReactNativeComponents.d.mts +3 -20
  28. package/react-reactive/enableReactNativeComponents.d.ts +3 -20
  29. package/react-reactive/enableReactNativeComponents.js +8 -3
  30. package/react-reactive/enableReactNativeComponents.mjs +8 -3
  31. package/react-reactive/enableReactive.js +10 -3
  32. package/react-reactive/enableReactive.mjs +10 -3
  33. package/react-reactive/enableReactive.native.js +8 -3
  34. package/react-reactive/enableReactive.native.mjs +8 -3
  35. package/react-reactive/enableReactive.web.js +8 -3
  36. package/react-reactive/enableReactive.web.mjs +8 -3
  37. package/react-web.d.mts +6 -0
  38. package/react-web.d.ts +6 -0
  39. package/react-web.js +39 -0
  40. package/react-web.mjs +37 -0
  41. package/react.d.mts +38 -20
  42. package/react.d.ts +38 -20
  43. package/react.js +36 -23
  44. package/react.mjs +37 -25
  45. package/sync-plugins/crud.d.mts +24 -9
  46. package/sync-plugins/crud.d.ts +24 -9
  47. package/sync-plugins/crud.js +199 -108
  48. package/sync-plugins/crud.mjs +200 -109
  49. package/sync-plugins/firebase.d.mts +7 -3
  50. package/sync-plugins/firebase.d.ts +7 -3
  51. package/sync-plugins/firebase.js +4 -2
  52. package/sync-plugins/firebase.mjs +4 -2
  53. package/sync-plugins/keel.d.mts +9 -13
  54. package/sync-plugins/keel.d.ts +9 -13
  55. package/sync-plugins/keel.js +52 -41
  56. package/sync-plugins/keel.mjs +53 -37
  57. package/sync-plugins/supabase.d.mts +7 -3
  58. package/sync-plugins/supabase.d.ts +7 -3
  59. package/sync-plugins/supabase.js +87 -31
  60. package/sync-plugins/supabase.mjs +88 -32
  61. package/sync-plugins/tanstack-query.d.mts +5 -5
  62. package/sync-plugins/tanstack-query.d.ts +5 -5
  63. package/sync-plugins/tanstack-query.js +10 -1
  64. package/sync-plugins/tanstack-query.mjs +10 -1
  65. package/sync-plugins/tanstack-react-query.d.mts +4 -2
  66. package/sync-plugins/tanstack-react-query.d.ts +4 -2
  67. package/sync.d.mts +16 -8
  68. package/sync.d.ts +16 -8
  69. package/sync.js +267 -174
  70. package/sync.mjs +266 -174
  71. package/trace.js +5 -6
  72. package/trace.mjs +5 -6
  73. package/types/reactive-native.d.ts +19 -0
  74. package/types/reactive-web.d.ts +7 -0
@@ -1,9 +1,9 @@
1
- import { isPromise, applyChanges, isNullOrUndefined, setAtPath, symbolDelete, isArray, internal, getNodeValue } from '@legendapp/state';
1
+ import { isPromise, isNullOrUndefined, applyChanges, setAtPath, symbolDelete, isArray, internal, getNodeValue } from '@legendapp/state';
2
2
  import { synced, deepEqual, internal as internal$1, diffObjects } from '@legendapp/state/sync';
3
3
 
4
4
  // src/sync-plugins/crud.ts
5
5
  var { clone } = internal;
6
- var { waitForSet } = internal$1;
6
+ var { waitForSet, runWithRetry } = internal$1;
7
7
  function transformOut(data, transform) {
8
8
  return transform ? transform(clone(data)) : data;
9
9
  }
@@ -23,6 +23,35 @@ function computeLastSync(data, fieldUpdatedAt, fieldCreatedAt) {
23
23
  }
24
24
  return newLastSync;
25
25
  }
26
+ function retrySet(params, retry, action, itemKey, itemValue, change, queuedRetries, actionFn, saveResult) {
27
+ if (action === "delete") {
28
+ if (queuedRetries.create.has(itemKey)) {
29
+ queuedRetries.create.delete(itemKey);
30
+ }
31
+ if (queuedRetries.update.has(itemKey)) {
32
+ queuedRetries.update.delete(itemKey);
33
+ }
34
+ } else {
35
+ if (queuedRetries.delete.has(itemKey)) {
36
+ queuedRetries.delete.delete(itemKey);
37
+ }
38
+ }
39
+ const queuedRetry = queuedRetries[action].get(itemKey);
40
+ if (queuedRetry) {
41
+ itemValue = Object.assign(queuedRetry, itemValue);
42
+ }
43
+ queuedRetries[action].set(itemKey, itemValue);
44
+ const paramsWithChanges = { ...params, changes: [change] };
45
+ return runWithRetry(
46
+ paramsWithChanges,
47
+ retry,
48
+ "create_" + itemKey,
49
+ () => actionFn(itemValue, paramsWithChanges).then((result) => {
50
+ queuedRetries[action].delete(itemKey);
51
+ return saveResult(itemKey, itemValue, result, true, change);
52
+ })
53
+ );
54
+ }
26
55
  function syncedCrud(props) {
27
56
  const {
28
57
  get: getFn,
@@ -43,10 +72,16 @@ function syncedCrud(props) {
43
72
  changesSince,
44
73
  generateId,
45
74
  waitForSet: waitForSetParam,
75
+ retry,
46
76
  ...rest
47
77
  } = props;
48
78
  const fieldId = fieldIdProp || "id";
49
79
  const pendingCreates = /* @__PURE__ */ new Set();
80
+ const queuedRetries = {
81
+ create: /* @__PURE__ */ new Map(),
82
+ update: /* @__PURE__ */ new Map(),
83
+ delete: /* @__PURE__ */ new Map()
84
+ };
50
85
  let asType = props.as;
51
86
  if (!asType) {
52
87
  asType = getFn ? "value" : "object";
@@ -75,69 +110,75 @@ function syncedCrud(props) {
75
110
  return out;
76
111
  };
77
112
  const transformRows = (data) => {
78
- return Promise.all(
113
+ return data.length ? Promise.all(
79
114
  data.map(
80
115
  (value) => (
81
116
  // Skip transforming any children with symbolDelete or fieldDeleted because they'll get deleted by resultsToOutType
82
117
  value[symbolDelete] || fieldDeleted && value[fieldDeleted] || fieldDeletedList && value[fieldDeletedList] ? value : transform.load(value, "get")
83
118
  )
84
119
  )
85
- );
120
+ ) : [];
86
121
  };
87
122
  const get = getFn || listFn ? (getParams) => {
88
- const { updateLastSync, lastSync, value } = getParams;
89
- if (listFn) {
90
- const isLastSyncMode = changesSince === "last-sync";
91
- if (isLastSyncMode && lastSync) {
92
- getParams.mode = modeParam || (asType === "array" ? "append" : asType === "value" ? "set" : "assign");
93
- }
94
- const listPromise = listFn(getParams);
95
- const toOut = (transformed) => {
96
- var _a;
97
- if (asType === "value") {
98
- return transformed.length > 0 ? transformed[0] : (_a = (isLastSyncMode && lastSync || fieldDeleted) && value) != null ? _a : null;
99
- } else {
100
- return resultsToOutType(transformed);
123
+ return runWithRetry(getParams, retry, getFn || listFn, () => {
124
+ const { updateLastSync, lastSync, value } = getParams;
125
+ if (listFn) {
126
+ const isLastSyncMode = changesSince === "last-sync";
127
+ if (isLastSyncMode && lastSync) {
128
+ getParams.mode = modeParam || (asType === "array" ? "append" : asType === "value" ? "set" : "assign");
101
129
  }
102
- };
103
- const processResults = (data) => {
104
- data || (data = []);
105
- if (fieldUpdatedAt) {
106
- const newLastSync = computeLastSync(data, fieldUpdatedAt, fieldCreatedAt);
107
- if (newLastSync && newLastSync !== lastSync) {
108
- updateLastSync(newLastSync);
130
+ const listPromise = listFn(getParams);
131
+ const toOut = (transformed) => {
132
+ if (asType === "value") {
133
+ if (transformed.length > 0) {
134
+ return transformed[0];
135
+ } else {
136
+ return value ? void 0 : null;
137
+ }
138
+ } else {
139
+ return resultsToOutType(transformed);
109
140
  }
110
- }
111
- let transformed = data;
112
- if (transform == null ? void 0 : transform.load) {
113
- transformed = transformRows(data);
114
- }
115
- return isPromise(transformed) ? transformed.then(toOut) : toOut(transformed);
116
- };
117
- return isPromise(listPromise) ? listPromise.then(processResults) : processResults(listPromise);
118
- } else if (getFn) {
119
- const dataPromise = getFn(getParams);
120
- const processData = (data) => {
121
- let transformed = data;
122
- if (data) {
123
- const newLastSync = data[fieldUpdatedAt] || data[fieldCreatedAt];
124
- if (newLastSync && newLastSync !== lastSync) {
125
- updateLastSync(newLastSync);
141
+ };
142
+ const processResults = (data) => {
143
+ data || (data = []);
144
+ if (fieldUpdatedAt) {
145
+ const newLastSync = computeLastSync(data, fieldUpdatedAt, fieldCreatedAt);
146
+ if (newLastSync && newLastSync !== lastSync) {
147
+ updateLastSync(newLastSync);
148
+ }
126
149
  }
150
+ let transformed = data;
127
151
  if (transform == null ? void 0 : transform.load) {
128
- transformed = transform.load(data, "get");
152
+ transformed = transformRows(data);
129
153
  }
130
- }
131
- return transformed;
132
- };
133
- return isPromise(dataPromise) ? dataPromise.then(processData) : processData(dataPromise);
134
- }
154
+ return isPromise(transformed) ? transformed.then(toOut) : toOut(transformed);
155
+ };
156
+ return isPromise(listPromise) ? listPromise.then(processResults) : processResults(listPromise);
157
+ } else if (getFn) {
158
+ const dataPromise = getFn(getParams);
159
+ const processData = (data) => {
160
+ let transformed = data;
161
+ if (data) {
162
+ const newLastSync = data[fieldUpdatedAt] || data[fieldCreatedAt];
163
+ if (newLastSync && newLastSync !== lastSync) {
164
+ updateLastSync(newLastSync);
165
+ }
166
+ if (transform == null ? void 0 : transform.load) {
167
+ transformed = transform.load(data, "get");
168
+ }
169
+ }
170
+ return transformed;
171
+ };
172
+ return isPromise(dataPromise) ? dataPromise.then(processData) : processData(dataPromise);
173
+ }
174
+ });
135
175
  } : void 0;
136
176
  const set = createFn || updateFn || deleteFn ? async (params) => {
137
177
  const { value, changes, update, retryAsCreate, node } = params;
138
178
  const creates = /* @__PURE__ */ new Map();
139
179
  const updates = /* @__PURE__ */ new Map();
140
180
  const deletes = /* @__PURE__ */ new Set();
181
+ const changesById = /* @__PURE__ */ new Map();
141
182
  const getUpdateValue = (itemValue, prev) => {
142
183
  return updatePartial ? Object.assign(
143
184
  diffObjects(
@@ -146,7 +187,7 @@ function syncedCrud(props) {
146
187
  /*deep*/
147
188
  true
148
189
  ),
149
- itemValue[fieldId] ? { [fieldId]: itemValue[fieldId] } : {}
190
+ !isNullOrUndefined(itemValue[fieldId]) ? { [fieldId]: itemValue[fieldId] } : {}
150
191
  ) : itemValue;
151
192
  };
152
193
  changes.forEach((change) => {
@@ -155,10 +196,11 @@ function syncedCrud(props) {
155
196
  if (value) {
156
197
  let id = value == null ? void 0 : value[fieldId];
157
198
  let isCreate = fieldCreatedAt ? !value[fieldCreatedAt] : !prevAtPath;
158
- if (!id && generateId) {
199
+ if (isNullOrUndefined(id) && generateId) {
159
200
  id = ensureId(value, fieldId, generateId);
160
201
  }
161
- if (id) {
202
+ if (!isNullOrUndefined(id)) {
203
+ changesById.set(id, change);
162
204
  if (pendingCreates.has(id)) {
163
205
  isCreate = false;
164
206
  }
@@ -188,6 +230,7 @@ function syncedCrud(props) {
188
230
  }
189
231
  } else if (path.length === 0) {
190
232
  deletes.add(prevAtPath);
233
+ changesById.set(prevAtPath[fieldId], change);
191
234
  }
192
235
  } else {
193
236
  let itemsChanged = [];
@@ -195,7 +238,7 @@ function syncedCrud(props) {
195
238
  const changed = asMap ? Array.from(valueAtPath.entries()) : Object.entries(valueAtPath);
196
239
  for (let i = 0; i < changed.length; i++) {
197
240
  const [key, value2] = changed[i];
198
- const prev = asMap ? prevAtPath.get(key) : prevAtPath[key];
241
+ const prev = prevAtPath ? asMap ? prevAtPath.get(key) : prevAtPath[key] : void 0;
199
242
  if (isNullOrUndefined(value2) && !isNullOrUndefined(prev)) {
200
243
  deletes.add(prev);
201
244
  return false;
@@ -212,6 +255,7 @@ function syncedCrud(props) {
212
255
  if (!itemValue) {
213
256
  if (path.length === 1 && prevAtPath) {
214
257
  deletes.add(prevAtPath);
258
+ changesById.set(prevAtPath[fieldId], change);
215
259
  }
216
260
  } else {
217
261
  const previous = setAtPath(
@@ -233,17 +277,18 @@ function syncedCrud(props) {
233
277
  console.error("[legend-state]: added item without an id");
234
278
  }
235
279
  if (createFn) {
236
- pendingCreates.add(item[fieldId]);
237
- creates.set(item[fieldId], item);
280
+ const id = item[fieldId];
281
+ changesById.set(id, change);
282
+ pendingCreates.add(id);
283
+ creates.set(id, item);
238
284
  } else {
239
285
  console.warn("[legend-state] missing create function");
240
286
  }
241
287
  } else {
242
288
  if (updateFn) {
243
- updates.set(
244
- item[fieldId],
245
- updates.has(item[fieldId]) ? Object.assign(updates.get(item[fieldId]), item) : item
246
- );
289
+ const id = item[fieldId];
290
+ changesById.set(id, change);
291
+ updates.set(id, updates.has(id) ? Object.assign(updates.get(id), item) : item);
247
292
  } else {
248
293
  console.warn("[legend-state] missing update function");
249
294
  }
@@ -251,93 +296,139 @@ function syncedCrud(props) {
251
296
  });
252
297
  }
253
298
  });
254
- const saveResult = async (itemKey, input, data, isCreate) => {
299
+ const saveResult = async (itemKey, input, data, isCreate, change) => {
255
300
  var _a;
256
301
  if (data) {
257
- const saved = (transform == null ? void 0 : transform.load) ? await transform.load(data, "set") : data;
302
+ let saved = (transform == null ? void 0 : transform.load) ? await transform.load(data, "set") : data;
258
303
  const isChild = itemKey !== "undefined" && asType !== "value";
259
304
  const currentPeeked = getNodeValue(node);
260
- const currentValue = isChild ? (_a = asType === "array" && isArray(currentPeeked) ? currentPeeked.find((v) => v[fieldId] === itemKey) : void 0) != null ? _a : currentPeeked[itemKey] : currentPeeked;
261
- const dataOnSaved = {
262
- saved,
263
- input,
264
- currentValue,
265
- isCreate,
266
- props
267
- };
268
- let savedOut = saved;
269
- if (savedOut && !isNullOrUndefined(currentValue)) {
270
- savedOut = clone(savedOut);
271
- Object.keys(savedOut).forEach((key) => {
305
+ const currentValue = isChild ? (_a = asType === "array" && isArray(currentPeeked) ? currentPeeked.find((v) => v[fieldId] === itemKey) : void 0) != null ? _a : asType === "Map" ? currentPeeked.get(itemKey) : currentPeeked[itemKey] : currentPeeked;
306
+ if (saved && !isNullOrUndefined(currentValue)) {
307
+ if (onSaved) {
308
+ const ret = onSaved({
309
+ saved,
310
+ input,
311
+ currentValue,
312
+ isCreate,
313
+ props
314
+ });
315
+ if (ret) {
316
+ saved = ret;
317
+ }
318
+ }
319
+ saved = clone(saved);
320
+ Object.keys(saved).forEach((key) => {
272
321
  const i = input[key];
273
322
  const c = currentValue[key];
274
323
  if (
275
324
  // value is already the new value, can ignore
276
- savedOut[key] === c || // user has changed local value
277
- key !== "id" && i !== c
325
+ saved[key] === c || // user has changed local value
326
+ key !== fieldId && i !== void 0 && i !== c
278
327
  ) {
279
- delete savedOut[key];
328
+ delete saved[key];
280
329
  }
281
330
  });
282
- if (onSaved) {
283
- const ret = onSaved(dataOnSaved);
284
- if (ret) {
285
- savedOut = ret;
331
+ let value2;
332
+ if (asType === "array") {
333
+ const index = currentPeeked.findIndex(
334
+ (cur) => cur[fieldId] === itemKey
335
+ );
336
+ if (index < 0) {
337
+ console.warn("[legend-state] Item saved that does not exist in array", saved);
338
+ } else {
339
+ value2 = { [index < 0 ? 0 : index]: saved };
286
340
  }
341
+ } else {
342
+ value2 = itemKey !== "undefined" && asType !== "value" ? { [itemKey]: saved } : saved;
343
+ }
344
+ if (value2 !== void 0) {
345
+ update({
346
+ value: value2,
347
+ mode: "merge",
348
+ changes: [change]
349
+ });
287
350
  }
288
- const createdAt = fieldCreatedAt ? savedOut[fieldCreatedAt] : void 0;
289
- const updatedAt = fieldUpdatedAt ? savedOut[fieldUpdatedAt] : void 0;
290
- const value2 = itemKey !== "undefined" && asType !== "value" ? { [itemKey]: savedOut } : savedOut;
291
- update({
292
- value: value2,
293
- lastSync: updatedAt || createdAt ? +new Date(updatedAt || createdAt) : void 0,
294
- mode: "merge"
295
- });
296
351
  }
297
352
  }
298
353
  };
299
354
  return Promise.all([
355
+ // Handle creates
300
356
  ...Array.from(creates).map(async ([itemKey, itemValue]) => {
301
357
  if (waitForSetParam) {
302
358
  await waitForSet(waitForSetParam, changes, itemValue, { type: "create" });
303
359
  }
304
360
  const createObj = await transformOut(itemValue, transform == null ? void 0 : transform.save);
305
- return createFn(createObj, params).then((result) => {
306
- return saveResult(itemKey, createObj, result, true);
307
- }).finally(() => {
361
+ return retrySet(
362
+ params,
363
+ retry,
364
+ "create",
365
+ itemKey,
366
+ createObj,
367
+ changesById.get(itemKey),
368
+ queuedRetries,
369
+ createFn,
370
+ saveResult
371
+ ).then(() => {
308
372
  pendingCreates.delete(itemKey);
309
373
  });
310
374
  }),
375
+ // Handle updates
311
376
  ...Array.from(updates).map(async ([itemKey, itemValue]) => {
312
377
  if (waitForSetParam) {
313
378
  await waitForSet(waitForSetParam, changes, itemValue, { type: "update" });
314
379
  }
315
- const toSave = itemValue;
316
- const changed = await transformOut(toSave, transform == null ? void 0 : transform.save);
380
+ const changed = await transformOut(itemValue, transform == null ? void 0 : transform.save);
317
381
  if (Object.keys(changed).length > 0) {
318
- return updateFn(changed, params).then(
319
- (result) => result && saveResult(itemKey, changed, result, false)
382
+ return retrySet(
383
+ params,
384
+ retry,
385
+ "update",
386
+ itemKey,
387
+ changed,
388
+ changesById.get(itemKey),
389
+ queuedRetries,
390
+ updateFn,
391
+ saveResult
320
392
  );
321
393
  }
322
394
  }),
323
- ...Array.from(deletes).map(async (valuePrevious) => {
324
- if (valuePrevious !== symbolDelete) {
325
- if (waitForSetParam) {
326
- await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
327
- }
328
- if (deleteFn) {
329
- deleteFn(valuePrevious, params);
330
- } else if (fieldDeleted && updateFn) {
331
- const valueId = valuePrevious[fieldId];
332
- if (valueId) {
333
- updateFn({ ...{ [fieldId]: valueId }, [fieldDeleted]: true }, params);
334
- } else {
335
- console.error("[legend-state]: deleting item without an id");
336
- }
337
- } else {
338
- console.warn("[legend-state] missing delete function");
339
- }
395
+ // Handle deletes
396
+ ...Array.from(deletes).filter((val) => val !== symbolDelete).map(async (valuePrevious) => {
397
+ if (waitForSetParam) {
398
+ await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
399
+ }
400
+ const itemKey = valuePrevious[fieldId];
401
+ if (!itemKey) {
402
+ console.error("[legend-state]: deleting item without an id");
403
+ return;
404
+ }
405
+ if (deleteFn) {
406
+ return retrySet(
407
+ params,
408
+ retry,
409
+ "delete",
410
+ itemKey,
411
+ valuePrevious,
412
+ changesById.get(itemKey),
413
+ queuedRetries,
414
+ deleteFn,
415
+ saveResult
416
+ );
417
+ }
418
+ if (fieldDeleted && updateFn) {
419
+ return retrySet(
420
+ params,
421
+ retry,
422
+ "delete",
423
+ itemKey,
424
+ { [fieldId]: itemKey, [fieldDeleted]: true },
425
+ changesById.get(itemKey),
426
+ queuedRetries,
427
+ updateFn,
428
+ saveResult
429
+ );
340
430
  }
431
+ console.warn("[legend-state] missing delete function");
341
432
  })
342
433
  ]);
343
434
  } : void 0;
@@ -1,4 +1,4 @@
1
- import { FieldTransforms } from '@legendapp/state/sync';
1
+ import { FieldTransforms, SyncedErrorParams } from '@legendapp/state/sync';
2
2
  export { FieldTransforms } from '@legendapp/state/sync';
3
3
  import { CrudAsOption, SyncedCrudPropsMany, SyncedCrudPropsBase, SyncedCrudReturnType } from '@legendapp/state/sync-plugins/crud';
4
4
  import { DatabaseReference, Query } from 'firebase/database';
@@ -6,11 +6,12 @@ import { DatabaseReference, Query } from 'firebase/database';
6
6
  declare function transformObjectFields(dataIn: Record<string, any>, map: Record<string, any>): any;
7
7
  declare function invertFieldMap(obj: Record<string, any>): any;
8
8
 
9
- interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, SyncedCrudPropsBase<TRemote, TLocal> {
9
+ interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'onError'> {
10
10
  refPath: (uid: string | undefined) => string;
11
11
  query?: (ref: DatabaseReference) => DatabaseReference | Query;
12
12
  fieldId?: string;
13
13
  fieldTransforms?: FieldTransforms<TRemote>;
14
+ onError?: (error: Error, params: FirebaseErrorParams) => void;
14
15
  realtime?: boolean;
15
16
  requireAuth?: boolean;
16
17
  readonly?: boolean;
@@ -22,6 +23,9 @@ interface SyncedFirebaseConfiguration {
22
23
  enabled?: boolean;
23
24
  }
24
25
  declare function configureSyncedFirebase(config: SyncedFirebaseConfiguration): void;
26
+ interface FirebaseErrorParams extends Omit<SyncedErrorParams, 'source'> {
27
+ source: 'list' | 'get' | 'create' | 'update' | 'delete';
28
+ }
25
29
  declare function syncedFirebase<TRemote extends object, TLocal = TRemote, TAs extends CrudAsOption = 'object'>(props: SyncedFirebaseProps<TRemote, TLocal, TAs>): SyncedCrudReturnType<TLocal, TAs>;
26
30
 
27
- export { type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
31
+ export { type FirebaseErrorParams, type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
@@ -1,4 +1,4 @@
1
- import { FieldTransforms } from '@legendapp/state/sync';
1
+ import { FieldTransforms, SyncedErrorParams } from '@legendapp/state/sync';
2
2
  export { FieldTransforms } from '@legendapp/state/sync';
3
3
  import { CrudAsOption, SyncedCrudPropsMany, SyncedCrudPropsBase, SyncedCrudReturnType } from '@legendapp/state/sync-plugins/crud';
4
4
  import { DatabaseReference, Query } from 'firebase/database';
@@ -6,11 +6,12 @@ import { DatabaseReference, Query } from 'firebase/database';
6
6
  declare function transformObjectFields(dataIn: Record<string, any>, map: Record<string, any>): any;
7
7
  declare function invertFieldMap(obj: Record<string, any>): any;
8
8
 
9
- interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, SyncedCrudPropsBase<TRemote, TLocal> {
9
+ interface SyncedFirebaseProps<TRemote extends object, TLocal, TAs extends CrudAsOption = 'value'> extends Omit<SyncedCrudPropsMany<TRemote, TLocal, TAs>, 'list' | 'retry'>, Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'onError'> {
10
10
  refPath: (uid: string | undefined) => string;
11
11
  query?: (ref: DatabaseReference) => DatabaseReference | Query;
12
12
  fieldId?: string;
13
13
  fieldTransforms?: FieldTransforms<TRemote>;
14
+ onError?: (error: Error, params: FirebaseErrorParams) => void;
14
15
  realtime?: boolean;
15
16
  requireAuth?: boolean;
16
17
  readonly?: boolean;
@@ -22,6 +23,9 @@ interface SyncedFirebaseConfiguration {
22
23
  enabled?: boolean;
23
24
  }
24
25
  declare function configureSyncedFirebase(config: SyncedFirebaseConfiguration): void;
26
+ interface FirebaseErrorParams extends Omit<SyncedErrorParams, 'source'> {
27
+ source: 'list' | 'get' | 'create' | 'update' | 'delete';
28
+ }
25
29
  declare function syncedFirebase<TRemote extends object, TLocal = TRemote, TAs extends CrudAsOption = 'object'>(props: SyncedFirebaseProps<TRemote, TLocal, TAs>): SyncedCrudReturnType<TLocal, TAs>;
26
30
 
27
- export { type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
31
+ export { type FirebaseErrorParams, type SyncedFirebaseProps, configureSyncedFirebase, invertFieldMap, syncedFirebase, transformObjectFields };
@@ -185,7 +185,8 @@ function syncedFirebase(props) {
185
185
  }
186
186
  return ref;
187
187
  };
188
- const list = async ({ lastSync, onError }) => {
188
+ const list = async (getParams) => {
189
+ const { lastSync, onError } = getParams;
189
190
  const ref = computeRef(lastSync);
190
191
  return new Promise((resolve) => {
191
192
  fns.once(
@@ -204,7 +205,7 @@ function syncedFirebase(props) {
204
205
  didList = true;
205
206
  resolve(values);
206
207
  },
207
- onError
208
+ (error) => onError(error, { source: "list", type: "get", retry: getParams })
208
209
  );
209
210
  });
210
211
  };
@@ -354,6 +355,7 @@ function syncedFirebase(props) {
354
355
  }
355
356
  return crud.syncedCrud({
356
357
  ...rest,
358
+ // Workaround for type errors
357
359
  list,
358
360
  subscribe,
359
361
  create,
@@ -183,7 +183,8 @@ function syncedFirebase(props) {
183
183
  }
184
184
  return ref;
185
185
  };
186
- const list = async ({ lastSync, onError }) => {
186
+ const list = async (getParams) => {
187
+ const { lastSync, onError } = getParams;
187
188
  const ref = computeRef(lastSync);
188
189
  return new Promise((resolve) => {
189
190
  fns.once(
@@ -202,7 +203,7 @@ function syncedFirebase(props) {
202
203
  didList = true;
203
204
  resolve(values);
204
205
  },
205
- onError
206
+ (error) => onError(error, { source: "list", type: "get", retry: getParams })
206
207
  );
207
208
  });
208
209
  };
@@ -352,6 +353,7 @@ function syncedFirebase(props) {
352
353
  }
353
354
  return syncedCrud({
354
355
  ...rest,
356
+ // Workaround for type errors
355
357
  list,
356
358
  subscribe,
357
359
  create,
@@ -1,5 +1,5 @@
1
- import { SyncedGetSetSubscribeBaseParams, OnErrorRetryParams, SyncedSetParams } from '@legendapp/state/sync';
2
- import { SyncedCrudPropsBase, SyncedCrudReturnType, CrudAsOption, SyncedCrudPropsSingle, CrudResult, SyncedCrudPropsMany } from '@legendapp/state/sync-plugins/crud';
1
+ import { SyncedGetSetSubscribeBaseParams } from '@legendapp/state/sync';
2
+ import { CrudErrorParams, SyncedCrudPropsBase, SyncedCrudReturnType, CrudAsOption, SyncedCrudPropsSingle, CrudResult, SyncedCrudPropsMany } from '@legendapp/state/sync-plugins/crud';
3
3
 
4
4
  interface KeelObjectBase {
5
5
  id: string;
@@ -13,6 +13,7 @@ type APIError = {
13
13
  type: string;
14
14
  message: string;
15
15
  requestId?: string;
16
+ error?: unknown;
16
17
  };
17
18
  type APIResult<T> = Result<T, APIError>;
18
19
  type Data<T> = {
@@ -24,7 +25,6 @@ type Err<U> = {
24
25
  error: U;
25
26
  };
26
27
  type Result<T, U> = NonNullable<Data<T> | Err<U>>;
27
- declare function generateKeelId(): string;
28
28
  interface KeelGetParams {
29
29
  }
30
30
  interface KeelListParams<Where = {}> {
@@ -62,7 +62,7 @@ interface SyncedKeelPropsManyWhere<TRemote extends {
62
62
  }, TLocal, AOption extends CrudAsOption, Where extends Record<string, any>> extends SyncedKeelPropsManyBase<TRemote, TLocal, AOption> {
63
63
  list?: (params: KeelListParams<NoInfer<Where>>) => Promise<CrudResult<APIResult<{
64
64
  results: TRemote[];
65
- pageInfo: any;
65
+ pageInfo?: any;
66
66
  }>>>;
67
67
  where?: Where | (() => Where);
68
68
  }
@@ -71,7 +71,7 @@ interface SyncedKeelPropsManyNoWhere<TRemote extends {
71
71
  }, TLocal, AOption extends CrudAsOption> extends SyncedKeelPropsManyBase<TRemote, TLocal, AOption> {
72
72
  list?: (params: KeelListParams<{}>) => Promise<CrudResult<APIResult<{
73
73
  results: TRemote[];
74
- pageInfo: any;
74
+ pageInfo?: any;
75
75
  }>>>;
76
76
  where?: never | {};
77
77
  }
@@ -88,12 +88,8 @@ interface SyncedKeelPropsSingle<TRemote extends {
88
88
  list?: never;
89
89
  as?: never;
90
90
  }
91
- interface ErrorDetails {
92
- type: 'create' | 'update' | 'delete';
93
- params: SyncedSetParams<any>;
94
- input: any;
91
+ interface KeelErrorParams extends CrudErrorParams {
95
92
  action: string;
96
- error: APIResult<any>['error'];
97
93
  }
98
94
  interface SyncedKeelPropsBase<TRemote extends {
99
95
  id: string;
@@ -102,7 +98,7 @@ interface SyncedKeelPropsBase<TRemote extends {
102
98
  create?: (i: NoInfer<Partial<TRemote>>) => Promise<APIResult<NoInfer<TRemote>>>;
103
99
  update?: (params: {
104
100
  where: any;
105
- values?: Partial<TRemote>;
101
+ values?: Partial<NoInfer<TRemote>>;
106
102
  }) => Promise<APIResult<TRemote>>;
107
103
  delete?: (params: {
108
104
  id: string;
@@ -113,7 +109,7 @@ interface SyncedKeelPropsBase<TRemote extends {
113
109
  };
114
110
  refreshAuth?: () => void | Promise<void>;
115
111
  requireAuth?: boolean;
116
- onError?: (error: Error, retryParams: OnErrorRetryParams, details: ErrorDetails) => void;
112
+ onError?: (error: Error, params: KeelErrorParams) => void;
117
113
  }
118
114
  declare function syncedKeel<TRemote extends {
119
115
  id: string;
@@ -122,4 +118,4 @@ declare function syncedKeel<TRemote extends {
122
118
  id: string;
123
119
  }, TLocal = TRemote, TOption extends CrudAsOption = 'object', Where extends Record<string, any> = {}>(props: SyncedKeelPropsBase<TRemote, TLocal> & SyncedKeelPropsMany<TRemote, TLocal, TOption, Where>): SyncedCrudReturnType<TLocal, Exclude<TOption, 'value'>>;
124
120
 
125
- export { type KeelClient, type KeelGetParams, type KeelKey, KeelKeys, type KeelListParams, type KeelObjectBase, type KeelRealtimePlugin, type OmitKeelBuiltins, type SyncedKeelPropsBase, generateKeelId, syncedKeel };
121
+ export { type KeelClient, type KeelErrorParams, type KeelGetParams, type KeelKey, KeelKeys, type KeelListParams, type KeelObjectBase, type KeelRealtimePlugin, type OmitKeelBuiltins, type SyncedKeelPropsBase, syncedKeel };