@legendapp/state 3.0.0-beta.13 → 3.0.0-beta.15

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;
@@ -13,6 +13,7 @@ type APIError = {
13
13
  type: string;
14
14
  message: string;
15
15
  requestId?: string;
16
+ error?: Error;
16
17
  };
17
18
  type APIResult<T> = Result<T, APIError>;
18
19
  type Data<T> = {
@@ -88,12 +89,8 @@ interface SyncedKeelPropsSingle<TRemote extends {
88
89
  list?: never;
89
90
  as?: never;
90
91
  }
91
- interface ErrorDetails {
92
- type: 'create' | 'update' | 'delete';
93
- params: SyncedSetParams<any>;
94
- input: any;
92
+ interface KeelErrorParams extends CrudErrorParams {
95
93
  action: string;
96
- error: APIResult<any>['error'];
97
94
  }
98
95
  interface SyncedKeelPropsBase<TRemote extends {
99
96
  id: string;
@@ -113,7 +110,7 @@ interface SyncedKeelPropsBase<TRemote extends {
113
110
  };
114
111
  refreshAuth?: () => void | Promise<void>;
115
112
  requireAuth?: boolean;
116
- onError?: (error: Error, retryParams: OnErrorRetryParams, details: ErrorDetails) => void;
113
+ onError?: (error: Error, params: KeelErrorParams) => void;
117
114
  }
118
115
  declare function syncedKeel<TRemote extends {
119
116
  id: string;
@@ -122,4 +119,4 @@ declare function syncedKeel<TRemote extends {
122
119
  id: string;
123
120
  }, 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
121
 
125
- export { type KeelClient, type KeelGetParams, type KeelKey, KeelKeys, type KeelListParams, type KeelObjectBase, type KeelRealtimePlugin, type OmitKeelBuiltins, type SyncedKeelPropsBase, generateKeelId, syncedKeel };
122
+ 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;
@@ -13,6 +13,7 @@ type APIError = {
13
13
  type: string;
14
14
  message: string;
15
15
  requestId?: string;
16
+ error?: Error;
16
17
  };
17
18
  type APIResult<T> = Result<T, APIError>;
18
19
  type Data<T> = {
@@ -88,12 +89,8 @@ interface SyncedKeelPropsSingle<TRemote extends {
88
89
  list?: never;
89
90
  as?: never;
90
91
  }
91
- interface ErrorDetails {
92
- type: 'create' | 'update' | 'delete';
93
- params: SyncedSetParams<any>;
94
- input: any;
92
+ interface KeelErrorParams extends CrudErrorParams {
95
93
  action: string;
96
- error: APIResult<any>['error'];
97
94
  }
98
95
  interface SyncedKeelPropsBase<TRemote extends {
99
96
  id: string;
@@ -113,7 +110,7 @@ interface SyncedKeelPropsBase<TRemote extends {
113
110
  };
114
111
  refreshAuth?: () => void | Promise<void>;
115
112
  requireAuth?: boolean;
116
- onError?: (error: Error, retryParams: OnErrorRetryParams, details: ErrorDetails) => void;
113
+ onError?: (error: Error, params: KeelErrorParams) => void;
117
114
  }
118
115
  declare function syncedKeel<TRemote extends {
119
116
  id: string;
@@ -122,4 +119,4 @@ declare function syncedKeel<TRemote extends {
122
119
  id: string;
123
120
  }, 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
121
 
125
- export { type KeelClient, type KeelGetParams, type KeelKey, KeelKeys, type KeelListParams, type KeelObjectBase, type KeelRealtimePlugin, type OmitKeelBuiltins, type SyncedKeelPropsBase, generateKeelId, syncedKeel };
122
+ 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,17 @@ 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) {
57
+ var _a;
56
58
  if (error.type === "unauthorized" || error.type === "forbidden") {
57
59
  console.warn("Keel token expired, refreshing...");
58
60
  isAuthed$.set(false);
59
61
  await ensureAuthToken(props);
62
+ return true;
63
+ } else if (((_a = error.error) == null ? void 0 : _a.message) === "Failed to fetch") {
64
+ throw error.error;
60
65
  }
66
+ return false;
61
67
  }
62
68
  function convertObjectToCreate(item) {
63
69
  const cloned = {};
@@ -97,7 +103,7 @@ function setupRealtime(props) {
97
103
  }
98
104
  }
99
105
  var NumPerPage = 200;
100
- async function getAllPages(props, listFn, params) {
106
+ async function getAllPages(props, listFn, params, listParams, onError) {
101
107
  const allData = [];
102
108
  let pageInfo = void 0;
103
109
  const { first: firstParam } = params;
@@ -113,8 +119,17 @@ async function getAllPages(props, listFn, params) {
113
119
  if (ret) {
114
120
  const { data, error } = ret;
115
121
  if (error) {
116
- await handleApiError(props, error);
117
- throw new Error(error.message);
122
+ const handled = await handleApiError(props, error);
123
+ if (!handled) {
124
+ const err = new Error(error.message, { cause: { error } });
125
+ onError(err, {
126
+ getParams: listParams,
127
+ type: "get",
128
+ source: "list",
129
+ action: listFn.name || listFn.toString(),
130
+ retry: listParams
131
+ });
132
+ }
118
133
  } else if (data) {
119
134
  pageInfo = data.pageInfo;
120
135
  allData.push(...data.results);
@@ -138,7 +153,6 @@ function syncedKeel(props) {
138
153
  fieldDeleted,
139
154
  realtime,
140
155
  mode,
141
- onError,
142
156
  requireAuth = true,
143
157
  ...rest
144
158
  } = props;
@@ -158,7 +172,7 @@ function syncedKeel(props) {
158
172
  }
159
173
  } : void 0;
160
174
  const list = listParam ? async (listParams) => {
161
- const { lastSync } = listParams;
175
+ const { lastSync, onError } = listParams;
162
176
  const queryBySync = !!lastSync && changesSince === "last-sync";
163
177
  const where = Object.assign(
164
178
  queryBySync ? { updatedAt: { after: new Date(lastSync + 1) } } : {},
@@ -166,14 +180,14 @@ function syncedKeel(props) {
166
180
  );
167
181
  const params = { where, first };
168
182
  realtimeState.current = {};
169
- const promise = getAllPages(props, listParam, params);
183
+ const promise = getAllPages(props, listParam, params, listParams, onError);
170
184
  if (realtime) {
171
185
  setupSubscribe(listParams);
172
186
  }
173
187
  return promise;
174
188
  } : void 0;
175
189
  const get = getParam ? async (getParams) => {
176
- const { refresh } = getParams;
190
+ const { refresh, onError } = getParams;
177
191
  realtimeState.current = {};
178
192
  const promise = getParam({ refresh });
179
193
  if (realtime) {
@@ -181,7 +195,17 @@ function syncedKeel(props) {
181
195
  }
182
196
  const { data, error } = await promise;
183
197
  if (error) {
184
- throw new Error(error.message);
198
+ const handled = await handleApiError(props, error);
199
+ if (!handled) {
200
+ const err = new Error(error.message, { cause: { error } });
201
+ onError(err, {
202
+ getParams,
203
+ type: "get",
204
+ source: "get",
205
+ action: getParam.name || getParam.toString(),
206
+ retry: getParams
207
+ });
208
+ }
185
209
  } else {
186
210
  return data;
187
211
  }
@@ -198,7 +222,7 @@ function syncedKeel(props) {
198
222
  };
199
223
  const handleSetError = async (error, params, input, fn, from) => {
200
224
  var _a, _b;
201
- const { retryNum, update: update2 } = params;
225
+ const { update: update2, onError } = params;
202
226
  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
227
  if (__DEV__) {
204
228
  console.log("Creating duplicate data already saved, just ignore.");
@@ -208,28 +232,25 @@ function syncedKeel(props) {
208
232
  value: {},
209
233
  mode: "assign"
210
234
  });
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;
235
+ } else if (from === "delete" && error.message === "record not found") {
236
+ if (__DEV__) {
237
+ console.log("Deleting non-existing data, just ignore.");
228
238
  }
229
- throw new Error(error.message, { cause: { input } });
239
+ params.cancelRetry = true;
230
240
  } else {
231
- await handleApiError(props, error);
232
- throw new Error(error.message, { cause: { input } });
241
+ const handled = await handleApiError(props, error);
242
+ if (!handled) {
243
+ const err = new Error(error.message, { cause: { error } });
244
+ onError(err, {
245
+ setParams: params,
246
+ input,
247
+ type: "set",
248
+ source: from,
249
+ action: fn.name || fn.toString(),
250
+ retry: params,
251
+ revert: sync.createRevertChanges(params.value$, params.changes)
252
+ });
253
+ }
233
254
  }
234
255
  };
235
256
  const create = createParam ? async (input, params) => {