@legendapp/state 3.0.0-beta.12 → 3.0.0-beta.14

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.
@@ -3,7 +3,7 @@ import { synced, deepEqual, internal as internal$1, diffObjects } from '@legenda
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,39 @@ function computeLastSync(data, fieldUpdatedAt, fieldCreatedAt) {
23
23
  }
24
24
  return newLastSync;
25
25
  }
26
+ var queuedRetries = {
27
+ create: /* @__PURE__ */ new Map(),
28
+ update: /* @__PURE__ */ new Map(),
29
+ delete: /* @__PURE__ */ new Map()
30
+ };
31
+ function retrySet(params, retry, action, itemKey, itemValue, actionFn, saveResult) {
32
+ if (action === "delete") {
33
+ if (queuedRetries.create.has(itemKey)) {
34
+ queuedRetries.create.delete(itemKey);
35
+ }
36
+ if (queuedRetries.update.has(itemKey)) {
37
+ queuedRetries.update.delete(itemKey);
38
+ }
39
+ } else {
40
+ if (queuedRetries.delete.has(itemKey)) {
41
+ queuedRetries.delete.delete(itemKey);
42
+ }
43
+ }
44
+ const queuedRetry = queuedRetries[action].get(itemKey);
45
+ if (queuedRetry) {
46
+ itemValue = Object.assign(queuedRetry, itemValue);
47
+ }
48
+ queuedRetries[action].set(itemKey, itemValue);
49
+ return runWithRetry(
50
+ params,
51
+ retry,
52
+ "create_" + itemKey,
53
+ () => actionFn(itemValue, params).then((result) => {
54
+ queuedRetries[action].delete(itemKey);
55
+ return saveResult(itemKey, itemValue, result, true);
56
+ })
57
+ );
58
+ }
26
59
  function syncedCrud(props) {
27
60
  const {
28
61
  get: getFn,
@@ -43,6 +76,7 @@ function syncedCrud(props) {
43
76
  changesSince,
44
77
  generateId,
45
78
  waitForSet: waitForSetParam,
79
+ retry,
46
80
  ...rest
47
81
  } = props;
48
82
  const fieldId = fieldIdProp || "id";
@@ -75,63 +109,68 @@ function syncedCrud(props) {
75
109
  return out;
76
110
  };
77
111
  const transformRows = (data) => {
78
- return Promise.all(
112
+ return data.length ? Promise.all(
79
113
  data.map(
80
114
  (value) => (
81
115
  // Skip transforming any children with symbolDelete or fieldDeleted because they'll get deleted by resultsToOutType
82
116
  value[symbolDelete] || fieldDeleted && value[fieldDeleted] || fieldDeletedList && value[fieldDeletedList] ? value : transform.load(value, "get")
83
117
  )
84
118
  )
85
- );
119
+ ) : [];
86
120
  };
87
121
  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);
122
+ return runWithRetry(getParams, retry, getFn || listFn, () => {
123
+ const { updateLastSync, lastSync, value } = getParams;
124
+ if (listFn) {
125
+ const isLastSyncMode = changesSince === "last-sync";
126
+ if (isLastSyncMode && lastSync) {
127
+ getParams.mode = modeParam || (asType === "array" ? "append" : asType === "value" ? "set" : "assign");
101
128
  }
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);
129
+ const listPromise = listFn(getParams);
130
+ const toOut = (transformed) => {
131
+ if (asType === "value") {
132
+ if (transformed.length > 0) {
133
+ return transformed[0];
134
+ } else {
135
+ return value ? void 0 : null;
136
+ }
137
+ } else {
138
+ return resultsToOutType(transformed);
109
139
  }
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);
140
+ };
141
+ const processResults = (data) => {
142
+ data || (data = []);
143
+ if (fieldUpdatedAt) {
144
+ const newLastSync = computeLastSync(data, fieldUpdatedAt, fieldCreatedAt);
145
+ if (newLastSync && newLastSync !== lastSync) {
146
+ updateLastSync(newLastSync);
147
+ }
126
148
  }
149
+ let transformed = data;
127
150
  if (transform == null ? void 0 : transform.load) {
128
- transformed = transform.load(data, "get");
151
+ transformed = transformRows(data);
129
152
  }
130
- }
131
- return transformed;
132
- };
133
- return isPromise(dataPromise) ? dataPromise.then(processData) : processData(dataPromise);
134
- }
153
+ return isPromise(transformed) ? transformed.then(toOut) : toOut(transformed);
154
+ };
155
+ return isPromise(listPromise) ? listPromise.then(processResults) : processResults(listPromise);
156
+ } else if (getFn) {
157
+ const dataPromise = getFn(getParams);
158
+ const processData = (data) => {
159
+ let transformed = data;
160
+ if (data) {
161
+ const newLastSync = data[fieldUpdatedAt] || data[fieldCreatedAt];
162
+ if (newLastSync && newLastSync !== lastSync) {
163
+ updateLastSync(newLastSync);
164
+ }
165
+ if (transform == null ? void 0 : transform.load) {
166
+ transformed = transform.load(data, "get");
167
+ }
168
+ }
169
+ return transformed;
170
+ };
171
+ return isPromise(dataPromise) ? dataPromise.then(processData) : processData(dataPromise);
172
+ }
173
+ });
135
174
  } : void 0;
136
175
  const set = createFn || updateFn || deleteFn ? async (params) => {
137
176
  const { value, changes, update, retryAsCreate, node } = params;
@@ -283,59 +322,84 @@ function syncedCrud(props) {
283
322
  delete saved[key];
284
323
  }
285
324
  });
286
- const createdAt = fieldCreatedAt ? saved[fieldCreatedAt] : void 0;
287
- const updatedAt = fieldUpdatedAt ? saved[fieldUpdatedAt] : void 0;
288
- const value2 = itemKey !== "undefined" && asType !== "value" ? { [itemKey]: saved } : saved;
289
- update({
290
- value: value2,
291
- lastSync: updatedAt || createdAt ? +new Date(updatedAt || createdAt) : void 0,
292
- mode: "merge"
293
- });
325
+ let value2;
326
+ if (asType === "array") {
327
+ const index = currentPeeked.findIndex(
328
+ (cur) => cur[fieldId] === itemKey
329
+ );
330
+ if (index < 0) {
331
+ console.warn("[legend-state] Item saved that does not exist in array", saved);
332
+ } else {
333
+ value2 = { [index < 0 ? 0 : index]: saved };
334
+ }
335
+ } else {
336
+ value2 = itemKey !== "undefined" && asType !== "value" ? { [itemKey]: saved } : saved;
337
+ }
338
+ if (value2 !== void 0) {
339
+ update({
340
+ value: value2,
341
+ mode: "merge"
342
+ });
343
+ }
294
344
  }
295
345
  }
296
346
  };
297
347
  return Promise.all([
348
+ // Handle creates
298
349
  ...Array.from(creates).map(async ([itemKey, itemValue]) => {
299
350
  if (waitForSetParam) {
300
351
  await waitForSet(waitForSetParam, changes, itemValue, { type: "create" });
301
352
  }
302
353
  const createObj = await transformOut(itemValue, transform == null ? void 0 : transform.save);
303
- return createFn(createObj, params).then((result) => {
304
- return saveResult(itemKey, createObj, result, true);
305
- }).finally(() => {
306
- pendingCreates.delete(itemKey);
307
- });
354
+ return retrySet(params, retry, "create", itemKey, createObj, createFn, saveResult).then(
355
+ () => {
356
+ pendingCreates.delete(itemKey);
357
+ }
358
+ );
308
359
  }),
360
+ // Handle updates
309
361
  ...Array.from(updates).map(async ([itemKey, itemValue]) => {
310
362
  if (waitForSetParam) {
311
363
  await waitForSet(waitForSetParam, changes, itemValue, { type: "update" });
312
364
  }
313
- const toSave = itemValue;
314
- const changed = await transformOut(toSave, transform == null ? void 0 : transform.save);
365
+ const changed = await transformOut(itemValue, transform == null ? void 0 : transform.save);
315
366
  if (Object.keys(changed).length > 0) {
316
- return updateFn(changed, params).then(
317
- (result) => result && saveResult(itemKey, changed, result, false)
318
- );
367
+ return retrySet(params, retry, "update", itemKey, changed, updateFn, saveResult);
319
368
  }
320
369
  }),
321
- ...Array.from(deletes).map(async (valuePrevious) => {
322
- if (valuePrevious !== symbolDelete) {
323
- if (waitForSetParam) {
324
- await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
325
- }
326
- if (deleteFn) {
327
- deleteFn(valuePrevious, params);
328
- } else if (fieldDeleted && updateFn) {
329
- const valueId = valuePrevious[fieldId];
330
- if (valueId) {
331
- updateFn({ ...{ [fieldId]: valueId }, [fieldDeleted]: true }, params);
332
- } else {
333
- console.error("[legend-state]: deleting item without an id");
334
- }
335
- } else {
336
- console.warn("[legend-state] missing delete function");
337
- }
370
+ // Handle deletes
371
+ ...Array.from(deletes).filter((val) => val !== symbolDelete).map(async (valuePrevious) => {
372
+ if (waitForSetParam) {
373
+ await waitForSet(waitForSetParam, changes, valuePrevious, { type: "delete" });
374
+ }
375
+ const valueId = valuePrevious[fieldId];
376
+ if (!valueId) {
377
+ console.error("[legend-state]: deleting item without an id");
378
+ return;
379
+ }
380
+ if (deleteFn) {
381
+ return retrySet(
382
+ params,
383
+ retry,
384
+ "delete",
385
+ valueId,
386
+ valuePrevious,
387
+ deleteFn,
388
+ saveResult
389
+ );
390
+ }
391
+ if (fieldDeleted && updateFn) {
392
+ return retrySet(
393
+ params,
394
+ retry,
395
+ "delete",
396
+ valueId,
397
+ { [fieldId]: valueId, [fieldDeleted]: true },
398
+ updateFn,
399
+ saveResult
400
+ );
338
401
  }
402
+ console.warn("[legend-state] missing delete function");
339
403
  })
340
404
  ]);
341
405
  } : 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;
@@ -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;
@@ -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, generateKeelId, syncedKeel };
@@ -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;
@@ -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;
@@ -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, generateKeelId, syncedKeel };
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var state = require('@legendapp/state');
4
+ var sync = require('@legendapp/state/sync');
4
5
  var crud = require('@legendapp/state/sync-plugins/crud');
5
6
  var ksuid = require('ksuid');
6
7
 
@@ -52,12 +53,14 @@ async function ensureAuthToken(props, force) {
52
53
  }
53
54
  return isAuthed;
54
55
  }
55
- async function handleApiError(props, error, retry) {
56
+ async function handleApiError(props, error) {
56
57
  if (error.type === "unauthorized" || error.type === "forbidden") {
57
58
  console.warn("Keel token expired, refreshing...");
58
59
  isAuthed$.set(false);
59
60
  await ensureAuthToken(props);
61
+ return true;
60
62
  }
63
+ return false;
61
64
  }
62
65
  function convertObjectToCreate(item) {
63
66
  const cloned = {};
@@ -97,7 +100,7 @@ function setupRealtime(props) {
97
100
  }
98
101
  }
99
102
  var NumPerPage = 200;
100
- async function getAllPages(props, listFn, params) {
103
+ async function getAllPages(props, listFn, params, listParams, onError) {
101
104
  const allData = [];
102
105
  let pageInfo = void 0;
103
106
  const { first: firstParam } = params;
@@ -113,8 +116,17 @@ async function getAllPages(props, listFn, params) {
113
116
  if (ret) {
114
117
  const { data, error } = ret;
115
118
  if (error) {
116
- await handleApiError(props, error);
117
- throw new Error(error.message);
119
+ const handled = await handleApiError(props, error);
120
+ if (!handled) {
121
+ const err = new Error(error.message, { cause: { error } });
122
+ onError(err, {
123
+ getParams: listParams,
124
+ type: "get",
125
+ source: "list",
126
+ action: listFn.name || listFn.toString(),
127
+ retry: listParams
128
+ });
129
+ }
118
130
  } else if (data) {
119
131
  pageInfo = data.pageInfo;
120
132
  allData.push(...data.results);
@@ -138,7 +150,6 @@ function syncedKeel(props) {
138
150
  fieldDeleted,
139
151
  realtime,
140
152
  mode,
141
- onError,
142
153
  requireAuth = true,
143
154
  ...rest
144
155
  } = props;
@@ -158,7 +169,7 @@ function syncedKeel(props) {
158
169
  }
159
170
  } : void 0;
160
171
  const list = listParam ? async (listParams) => {
161
- const { lastSync } = listParams;
172
+ const { lastSync, onError } = listParams;
162
173
  const queryBySync = !!lastSync && changesSince === "last-sync";
163
174
  const where = Object.assign(
164
175
  queryBySync ? { updatedAt: { after: new Date(lastSync + 1) } } : {},
@@ -166,14 +177,14 @@ function syncedKeel(props) {
166
177
  );
167
178
  const params = { where, first };
168
179
  realtimeState.current = {};
169
- const promise = getAllPages(props, listParam, params);
180
+ const promise = getAllPages(props, listParam, params, listParams, onError);
170
181
  if (realtime) {
171
182
  setupSubscribe(listParams);
172
183
  }
173
184
  return promise;
174
185
  } : void 0;
175
186
  const get = getParam ? async (getParams) => {
176
- const { refresh } = getParams;
187
+ const { refresh, onError } = getParams;
177
188
  realtimeState.current = {};
178
189
  const promise = getParam({ refresh });
179
190
  if (realtime) {
@@ -181,7 +192,17 @@ function syncedKeel(props) {
181
192
  }
182
193
  const { data, error } = await promise;
183
194
  if (error) {
184
- throw new Error(error.message);
195
+ const handled = await handleApiError(props, error);
196
+ if (!handled) {
197
+ const err = new Error(error.message, { cause: { error } });
198
+ onError(err, {
199
+ getParams,
200
+ type: "get",
201
+ source: "get",
202
+ action: getParam.name || getParam.toString(),
203
+ retry: getParams
204
+ });
205
+ }
185
206
  } else {
186
207
  return data;
187
208
  }
@@ -198,7 +219,7 @@ function syncedKeel(props) {
198
219
  };
199
220
  const handleSetError = async (error, params, input, fn, from) => {
200
221
  var _a, _b;
201
- const { retryNum, update: update2 } = params;
222
+ const { update: update2, onError } = params;
202
223
  if (from === "create" && ((_a = error.message) == null ? void 0 : _a.includes("for the unique")) && ((_b = error.message) == null ? void 0 : _b.includes("must be unique"))) {
203
224
  if (__DEV__) {
204
225
  console.log("Creating duplicate data already saved, just ignore.");
@@ -208,28 +229,25 @@ function syncedKeel(props) {
208
229
  value: {},
209
230
  mode: "assign"
210
231
  });
211
- } else if (from === "delete") {
212
- if (error.message === "record not found") {
213
- if (__DEV__) {
214
- console.log("Deleting non-existing data, just ignore.");
215
- }
216
- params.cancelRetry = true;
217
- }
218
- } else if (error.type === "bad_request") {
219
- onError == null ? void 0 : onError(new Error(error.message), params, {
220
- error,
221
- params,
222
- input,
223
- type: from,
224
- action: fn.name || fn.toString()
225
- });
226
- if (retryNum > 4) {
227
- params.cancelRetry = true;
232
+ } else if (from === "delete" && error.message === "record not found") {
233
+ if (__DEV__) {
234
+ console.log("Deleting non-existing data, just ignore.");
228
235
  }
229
- throw new Error(error.message, { cause: { input } });
236
+ params.cancelRetry = true;
230
237
  } else {
231
- await handleApiError(props, error);
232
- throw new Error(error.message, { cause: { input } });
238
+ const handled = await handleApiError(props, error);
239
+ if (!handled) {
240
+ const err = new Error(error.message, { cause: { error } });
241
+ onError(err, {
242
+ setParams: params,
243
+ input,
244
+ type: "set",
245
+ source: from,
246
+ action: fn.name || fn.toString(),
247
+ retry: params,
248
+ revert: sync.createRevertChanges(params.value$, params.changes)
249
+ });
250
+ }
233
251
  }
234
252
  };
235
253
  const create = createParam ? async (input, params) => {