@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.
@@ -1,4 +1,5 @@
1
1
  import { observable, isFunction, when, batch, isEmpty } from '@legendapp/state';
2
+ import { createRevertChanges } from '@legendapp/state/sync';
2
3
  import { syncedCrud } from '@legendapp/state/sync-plugins/crud';
3
4
  import ksuid from 'ksuid';
4
5
 
@@ -46,12 +47,17 @@ async function ensureAuthToken(props, force) {
46
47
  }
47
48
  return isAuthed;
48
49
  }
49
- async function handleApiError(props, error, retry) {
50
+ async function handleApiError(props, error) {
51
+ var _a;
50
52
  if (error.type === "unauthorized" || error.type === "forbidden") {
51
53
  console.warn("Keel token expired, refreshing...");
52
54
  isAuthed$.set(false);
53
55
  await ensureAuthToken(props);
56
+ return true;
57
+ } else if (((_a = error.error) == null ? void 0 : _a.message) === "Failed to fetch") {
58
+ throw error.error;
54
59
  }
60
+ return false;
55
61
  }
56
62
  function convertObjectToCreate(item) {
57
63
  const cloned = {};
@@ -91,7 +97,7 @@ function setupRealtime(props) {
91
97
  }
92
98
  }
93
99
  var NumPerPage = 200;
94
- async function getAllPages(props, listFn, params) {
100
+ async function getAllPages(props, listFn, params, listParams, onError) {
95
101
  const allData = [];
96
102
  let pageInfo = void 0;
97
103
  const { first: firstParam } = params;
@@ -107,8 +113,17 @@ async function getAllPages(props, listFn, params) {
107
113
  if (ret) {
108
114
  const { data, error } = ret;
109
115
  if (error) {
110
- await handleApiError(props, error);
111
- throw new Error(error.message);
116
+ const handled = await handleApiError(props, error);
117
+ if (!handled) {
118
+ const err = new Error(error.message, { cause: { error } });
119
+ onError(err, {
120
+ getParams: listParams,
121
+ type: "get",
122
+ source: "list",
123
+ action: listFn.name || listFn.toString(),
124
+ retry: listParams
125
+ });
126
+ }
112
127
  } else if (data) {
113
128
  pageInfo = data.pageInfo;
114
129
  allData.push(...data.results);
@@ -132,7 +147,6 @@ function syncedKeel(props) {
132
147
  fieldDeleted,
133
148
  realtime,
134
149
  mode,
135
- onError,
136
150
  requireAuth = true,
137
151
  ...rest
138
152
  } = props;
@@ -152,7 +166,7 @@ function syncedKeel(props) {
152
166
  }
153
167
  } : void 0;
154
168
  const list = listParam ? async (listParams) => {
155
- const { lastSync } = listParams;
169
+ const { lastSync, onError } = listParams;
156
170
  const queryBySync = !!lastSync && changesSince === "last-sync";
157
171
  const where = Object.assign(
158
172
  queryBySync ? { updatedAt: { after: new Date(lastSync + 1) } } : {},
@@ -160,14 +174,14 @@ function syncedKeel(props) {
160
174
  );
161
175
  const params = { where, first };
162
176
  realtimeState.current = {};
163
- const promise = getAllPages(props, listParam, params);
177
+ const promise = getAllPages(props, listParam, params, listParams, onError);
164
178
  if (realtime) {
165
179
  setupSubscribe(listParams);
166
180
  }
167
181
  return promise;
168
182
  } : void 0;
169
183
  const get = getParam ? async (getParams) => {
170
- const { refresh } = getParams;
184
+ const { refresh, onError } = getParams;
171
185
  realtimeState.current = {};
172
186
  const promise = getParam({ refresh });
173
187
  if (realtime) {
@@ -175,7 +189,17 @@ function syncedKeel(props) {
175
189
  }
176
190
  const { data, error } = await promise;
177
191
  if (error) {
178
- throw new Error(error.message);
192
+ const handled = await handleApiError(props, error);
193
+ if (!handled) {
194
+ const err = new Error(error.message, { cause: { error } });
195
+ onError(err, {
196
+ getParams,
197
+ type: "get",
198
+ source: "get",
199
+ action: getParam.name || getParam.toString(),
200
+ retry: getParams
201
+ });
202
+ }
179
203
  } else {
180
204
  return data;
181
205
  }
@@ -192,7 +216,7 @@ function syncedKeel(props) {
192
216
  };
193
217
  const handleSetError = async (error, params, input, fn, from) => {
194
218
  var _a, _b;
195
- const { retryNum, update: update2 } = params;
219
+ const { update: update2, onError } = params;
196
220
  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"))) {
197
221
  if (__DEV__) {
198
222
  console.log("Creating duplicate data already saved, just ignore.");
@@ -202,28 +226,25 @@ function syncedKeel(props) {
202
226
  value: {},
203
227
  mode: "assign"
204
228
  });
205
- } else if (from === "delete") {
206
- if (error.message === "record not found") {
207
- if (__DEV__) {
208
- console.log("Deleting non-existing data, just ignore.");
209
- }
210
- params.cancelRetry = true;
211
- }
212
- } else if (error.type === "bad_request") {
213
- onError == null ? void 0 : onError(new Error(error.message), params, {
214
- error,
215
- params,
216
- input,
217
- type: from,
218
- action: fn.name || fn.toString()
219
- });
220
- if (retryNum > 4) {
221
- params.cancelRetry = true;
229
+ } else if (from === "delete" && error.message === "record not found") {
230
+ if (__DEV__) {
231
+ console.log("Deleting non-existing data, just ignore.");
222
232
  }
223
- throw new Error(error.message, { cause: { input } });
233
+ params.cancelRetry = true;
224
234
  } else {
225
- await handleApiError(props, error);
226
- throw new Error(error.message, { cause: { input } });
235
+ const handled = await handleApiError(props, error);
236
+ if (!handled) {
237
+ const err = new Error(error.message, { cause: { error } });
238
+ onError(err, {
239
+ setParams: params,
240
+ input,
241
+ type: "set",
242
+ source: from,
243
+ action: fn.name || fn.toString(),
244
+ retry: params,
245
+ revert: createRevertChanges(params.value$, params.changes)
246
+ });
247
+ }
227
248
  }
228
249
  };
229
250
  const create = createParam ? async (input, params) => {
@@ -1,9 +1,9 @@
1
1
  import { Observable } from '@legendapp/state';
2
2
  import { SyncedOptions, SyncedOptionsGlobal, SyncedGetParams } from '@legendapp/state/sync';
3
3
  import { SyncedCrudPropsBase, CrudAsOption, SyncedCrudReturnType, SyncedCrudPropsMany } from '@legendapp/state/sync-plugins/crud';
4
- import { PostgrestQueryBuilder, PostgrestFilterBuilder } from '@supabase/postgrest-js';
5
- import { SupabaseClient, PostgrestSingleResponse } from '@supabase/supabase-js';
6
4
  import { FunctionsResponse } from '@supabase/functions-js';
5
+ import { PostgrestFilterBuilder, PostgrestQueryBuilder } from '@supabase/postgrest-js';
6
+ import { SupabaseClient, PostgrestSingleResponse } from '@supabase/supabase-js';
7
7
 
8
8
  type DatabaseOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer TDB> ? TDB : never;
9
9
  type SchemaNameOf<Client extends SupabaseClient> = keyof DatabaseOf<Client>;
@@ -29,7 +29,7 @@ interface SyncedSupabaseProps<Client extends SupabaseClient<any, any>, Collectio
29
29
  supabase?: Client;
30
30
  collection: Collection;
31
31
  schema?: SchemaName;
32
- select?: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
32
+ select?: never;
33
33
  filter?: (select: PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>, params: SyncedGetParams<TRemote>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
34
34
  actions?: ('create' | 'read' | 'update' | 'delete')[];
35
35
  realtime?: boolean | {
@@ -42,8 +42,12 @@ interface SyncedSupabaseProps<Client extends SupabaseClient<any, any>, Collectio
42
42
  update?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['update']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
43
43
  delete?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['delete']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
44
44
  }
45
+ interface SyncedSupabasePropsWithSelect<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client> = 'public', TOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection, SchemaName> = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote> extends Omit<SyncedSupabaseProps<Client, Collection, SchemaName, TOption, TRemote, TLocal>, 'select'> {
46
+ select: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
47
+ }
45
48
  declare function getSyncedSupabaseConfiguration(): SyncedSupabaseConfiguration;
46
49
  declare function configureSyncedSupabase(config: SyncedSupabaseConfiguration): void;
50
+ declare function syncedSupabase<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName> & string, SchemaName extends SchemaNameOf<Client> = 'public', AsOption extends CrudAsOption = 'object', TRemote = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote>(props: SyncedSupabasePropsWithSelect<Client, Collection, SchemaName, AsOption, TRemote, TLocal>): SyncedCrudReturnType<TLocal, AsOption>;
47
51
  declare function syncedSupabase<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName> & string, SchemaName extends SchemaNameOf<Client> = 'public', AsOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection, SchemaName> = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote>(props: SyncedSupabaseProps<Client, Collection, SchemaName, AsOption, TRemote, TLocal>): SyncedCrudReturnType<TLocal, AsOption>;
48
52
 
49
53
  export { type SupabaseCollectionOf, type SupabaseRowOf, type SupabaseSchemaOf, type SupabaseTableOf, type SyncedSupabaseConfig, type SyncedSupabaseConfiguration, configureSyncedSupabase, getSyncedSupabaseConfiguration, syncedSupabase };
@@ -1,9 +1,9 @@
1
1
  import { Observable } from '@legendapp/state';
2
2
  import { SyncedOptions, SyncedOptionsGlobal, SyncedGetParams } from '@legendapp/state/sync';
3
3
  import { SyncedCrudPropsBase, CrudAsOption, SyncedCrudReturnType, SyncedCrudPropsMany } from '@legendapp/state/sync-plugins/crud';
4
- import { PostgrestQueryBuilder, PostgrestFilterBuilder } from '@supabase/postgrest-js';
5
- import { SupabaseClient, PostgrestSingleResponse } from '@supabase/supabase-js';
6
4
  import { FunctionsResponse } from '@supabase/functions-js';
5
+ import { PostgrestFilterBuilder, PostgrestQueryBuilder } from '@supabase/postgrest-js';
6
+ import { SupabaseClient, PostgrestSingleResponse } from '@supabase/supabase-js';
7
7
 
8
8
  type DatabaseOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer TDB> ? TDB : never;
9
9
  type SchemaNameOf<Client extends SupabaseClient> = keyof DatabaseOf<Client>;
@@ -29,7 +29,7 @@ interface SyncedSupabaseProps<Client extends SupabaseClient<any, any>, Collectio
29
29
  supabase?: Client;
30
30
  collection: Collection;
31
31
  schema?: SchemaName;
32
- select?: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
32
+ select?: never;
33
33
  filter?: (select: PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>, params: SyncedGetParams<TRemote>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
34
34
  actions?: ('create' | 'read' | 'update' | 'delete')[];
35
35
  realtime?: boolean | {
@@ -42,8 +42,12 @@ interface SyncedSupabaseProps<Client extends SupabaseClient<any, any>, Collectio
42
42
  update?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['update']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
43
43
  delete?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['delete']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
44
44
  }
45
+ interface SyncedSupabasePropsWithSelect<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client> = 'public', TOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection, SchemaName> = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote> extends Omit<SyncedSupabaseProps<Client, Collection, SchemaName, TOption, TRemote, TLocal>, 'select'> {
46
+ select: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
47
+ }
45
48
  declare function getSyncedSupabaseConfiguration(): SyncedSupabaseConfiguration;
46
49
  declare function configureSyncedSupabase(config: SyncedSupabaseConfiguration): void;
50
+ declare function syncedSupabase<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName> & string, SchemaName extends SchemaNameOf<Client> = 'public', AsOption extends CrudAsOption = 'object', TRemote = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote>(props: SyncedSupabasePropsWithSelect<Client, Collection, SchemaName, AsOption, TRemote, TLocal>): SyncedCrudReturnType<TLocal, AsOption>;
47
51
  declare function syncedSupabase<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName> & string, SchemaName extends SchemaNameOf<Client> = 'public', AsOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection, SchemaName> = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote>(props: SyncedSupabaseProps<Client, Collection, SchemaName, AsOption, TRemote, TLocal>): SyncedCrudReturnType<TLocal, AsOption>;
48
52
 
49
53
  export { type SupabaseCollectionOf, type SupabaseRowOf, type SupabaseSchemaOf, type SupabaseTableOf, type SyncedSupabaseConfig, type SyncedSupabaseConfiguration, configureSyncedSupabase, getSyncedSupabaseConfiguration, syncedSupabase };
@@ -18,15 +18,29 @@ function configureSyncedSupabase(config) {
18
18
  }
19
19
  Object.assign(supabaseConfig, sync.removeNullUndefined(rest));
20
20
  }
21
- function wrapSupabaseFn(fn) {
22
- return async (...args) => {
23
- const { data, error } = await fn(...args);
21
+ function wrapSupabaseFn(fn, source) {
22
+ return async (params, ...args) => {
23
+ const { onError } = params;
24
+ const { data, error } = await fn(params, ...args);
24
25
  if (error) {
25
- throw new Error(error.message);
26
+ onError(new Error(error.message), {
27
+ getParams: params,
28
+ source,
29
+ type: "get",
30
+ retry: params
31
+ });
26
32
  }
27
33
  return data;
28
34
  };
29
35
  }
36
+ function handleSupabaseError(error, onError, params) {
37
+ var _a;
38
+ if ((_a = error.message) == null ? void 0 : _a.includes("Failed to fetch")) {
39
+ throw error;
40
+ } else {
41
+ onError(new Error(error.message), params);
42
+ }
43
+ }
30
44
  function syncedSupabase(props) {
31
45
  props = { ...supabaseConfig, ...props };
32
46
  const {
@@ -65,8 +79,8 @@ function syncedSupabase(props) {
65
79
  console.warn("[legend-state] fieldDeleted is required when using last-sync mode");
66
80
  }
67
81
  }
68
- const list = !actions || actions.includes("read") ? listParam ? wrapSupabaseFn(listParam) : async (params) => {
69
- const { lastSync } = params;
82
+ const list = !actions || actions.includes("read") ? listParam ? wrapSupabaseFn(listParam, "list") : async (params) => {
83
+ const { lastSync, onError } = params;
70
84
  const clientSchema = schema ? client.schema(schema) : client;
71
85
  const from = clientSchema.from(collection);
72
86
  let select = selectFn ? selectFn(from) : from.select();
@@ -78,40 +92,71 @@ function syncedSupabase(props) {
78
92
  select = filter(select, params);
79
93
  }
80
94
  const { data, error } = await select;
81
- if (error) {
82
- throw new Error(error == null ? void 0 : error.message);
95
+ if (data) {
96
+ return data || [];
97
+ } else if (error) {
98
+ handleSupabaseError(error, onError, {
99
+ getParams: params,
100
+ source: "list",
101
+ type: "get",
102
+ retry: params
103
+ });
83
104
  }
84
- return data || [];
105
+ return null;
85
106
  } : void 0;
86
- const create = createParam ? wrapSupabaseFn(createParam) : !actions || actions.includes("create") ? async (input) => {
107
+ const create = createParam ? wrapSupabaseFn(createParam, "create") : !actions || actions.includes("create") ? async (input, params) => {
108
+ const { onError } = params;
87
109
  const res = await client.from(collection).insert(input).select();
88
110
  const { data, error } = res;
89
111
  if (data) {
90
112
  const created = data[0];
91
113
  return created;
92
- } else {
93
- throw new Error(error == null ? void 0 : error.message);
114
+ } else if (error) {
115
+ handleSupabaseError(error, onError, {
116
+ setParams: params,
117
+ source: "create",
118
+ type: "set",
119
+ retry: params,
120
+ input,
121
+ revert: sync.createRevertChanges(params.value$, params.changes)
122
+ });
94
123
  }
95
124
  } : void 0;
96
- const update = !actions || actions.includes("update") ? updateParam ? wrapSupabaseFn(updateParam) : async (input) => {
125
+ const update = !actions || actions.includes("update") ? updateParam ? wrapSupabaseFn(updateParam, "update") : async (input, params) => {
126
+ const { onError } = params;
97
127
  const res = await client.from(collection).update(input).eq("id", input.id).select();
98
128
  const { data, error } = res;
99
129
  if (data) {
100
130
  const created = data[0];
101
131
  return created;
102
- } else {
103
- throw new Error(error == null ? void 0 : error.message);
132
+ } else if (error) {
133
+ handleSupabaseError(error, onError, {
134
+ setParams: params,
135
+ source: "update",
136
+ type: "set",
137
+ retry: params,
138
+ input,
139
+ revert: sync.createRevertChanges(params.value$, params.changes)
140
+ });
104
141
  }
105
142
  } : void 0;
106
- const deleteFn = !fieldDeleted && (!actions || actions.includes("delete")) ? deleteParam ? wrapSupabaseFn(deleteParam) : async (input) => {
143
+ const deleteFn = !fieldDeleted && (!actions || actions.includes("delete")) ? deleteParam ? wrapSupabaseFn(deleteParam, "delete") : async (input, params) => {
144
+ const { onError } = params;
107
145
  const id = input.id;
108
146
  const res = await client.from(collection).delete().eq("id", id).select();
109
147
  const { data, error } = res;
110
148
  if (data) {
111
149
  const created = data[0];
112
150
  return created;
113
- } else {
114
- throw new Error(error == null ? void 0 : error.message);
151
+ } else if (error) {
152
+ handleSupabaseError(error, onError, {
153
+ setParams: params,
154
+ source: "delete",
155
+ type: "set",
156
+ retry: params,
157
+ input,
158
+ revert: sync.createRevertChanges(params.value$, params.changes)
159
+ });
115
160
  }
116
161
  } : void 0;
117
162
  const subscribe = realtime ? ({ node, value$, update: update2 }) => {
@@ -1,5 +1,5 @@
1
1
  import { observable, computeSelector, isFunction, isObject, symbolDelete } from '@legendapp/state';
2
- import { removeNullUndefined, transformStringifyDates, combineTransforms } from '@legendapp/state/sync';
2
+ import { removeNullUndefined, createRevertChanges, transformStringifyDates, combineTransforms } from '@legendapp/state/sync';
3
3
  import { syncedCrud } from '@legendapp/state/sync-plugins/crud';
4
4
 
5
5
  // src/sync-plugins/supabase.ts
@@ -16,15 +16,29 @@ function configureSyncedSupabase(config) {
16
16
  }
17
17
  Object.assign(supabaseConfig, removeNullUndefined(rest));
18
18
  }
19
- function wrapSupabaseFn(fn) {
20
- return async (...args) => {
21
- const { data, error } = await fn(...args);
19
+ function wrapSupabaseFn(fn, source) {
20
+ return async (params, ...args) => {
21
+ const { onError } = params;
22
+ const { data, error } = await fn(params, ...args);
22
23
  if (error) {
23
- throw new Error(error.message);
24
+ onError(new Error(error.message), {
25
+ getParams: params,
26
+ source,
27
+ type: "get",
28
+ retry: params
29
+ });
24
30
  }
25
31
  return data;
26
32
  };
27
33
  }
34
+ function handleSupabaseError(error, onError, params) {
35
+ var _a;
36
+ if ((_a = error.message) == null ? void 0 : _a.includes("Failed to fetch")) {
37
+ throw error;
38
+ } else {
39
+ onError(new Error(error.message), params);
40
+ }
41
+ }
28
42
  function syncedSupabase(props) {
29
43
  props = { ...supabaseConfig, ...props };
30
44
  const {
@@ -63,8 +77,8 @@ function syncedSupabase(props) {
63
77
  console.warn("[legend-state] fieldDeleted is required when using last-sync mode");
64
78
  }
65
79
  }
66
- const list = !actions || actions.includes("read") ? listParam ? wrapSupabaseFn(listParam) : async (params) => {
67
- const { lastSync } = params;
80
+ const list = !actions || actions.includes("read") ? listParam ? wrapSupabaseFn(listParam, "list") : async (params) => {
81
+ const { lastSync, onError } = params;
68
82
  const clientSchema = schema ? client.schema(schema) : client;
69
83
  const from = clientSchema.from(collection);
70
84
  let select = selectFn ? selectFn(from) : from.select();
@@ -76,40 +90,71 @@ function syncedSupabase(props) {
76
90
  select = filter(select, params);
77
91
  }
78
92
  const { data, error } = await select;
79
- if (error) {
80
- throw new Error(error == null ? void 0 : error.message);
93
+ if (data) {
94
+ return data || [];
95
+ } else if (error) {
96
+ handleSupabaseError(error, onError, {
97
+ getParams: params,
98
+ source: "list",
99
+ type: "get",
100
+ retry: params
101
+ });
81
102
  }
82
- return data || [];
103
+ return null;
83
104
  } : void 0;
84
- const create = createParam ? wrapSupabaseFn(createParam) : !actions || actions.includes("create") ? async (input) => {
105
+ const create = createParam ? wrapSupabaseFn(createParam, "create") : !actions || actions.includes("create") ? async (input, params) => {
106
+ const { onError } = params;
85
107
  const res = await client.from(collection).insert(input).select();
86
108
  const { data, error } = res;
87
109
  if (data) {
88
110
  const created = data[0];
89
111
  return created;
90
- } else {
91
- throw new Error(error == null ? void 0 : error.message);
112
+ } else if (error) {
113
+ handleSupabaseError(error, onError, {
114
+ setParams: params,
115
+ source: "create",
116
+ type: "set",
117
+ retry: params,
118
+ input,
119
+ revert: createRevertChanges(params.value$, params.changes)
120
+ });
92
121
  }
93
122
  } : void 0;
94
- const update = !actions || actions.includes("update") ? updateParam ? wrapSupabaseFn(updateParam) : async (input) => {
123
+ const update = !actions || actions.includes("update") ? updateParam ? wrapSupabaseFn(updateParam, "update") : async (input, params) => {
124
+ const { onError } = params;
95
125
  const res = await client.from(collection).update(input).eq("id", input.id).select();
96
126
  const { data, error } = res;
97
127
  if (data) {
98
128
  const created = data[0];
99
129
  return created;
100
- } else {
101
- throw new Error(error == null ? void 0 : error.message);
130
+ } else if (error) {
131
+ handleSupabaseError(error, onError, {
132
+ setParams: params,
133
+ source: "update",
134
+ type: "set",
135
+ retry: params,
136
+ input,
137
+ revert: createRevertChanges(params.value$, params.changes)
138
+ });
102
139
  }
103
140
  } : void 0;
104
- const deleteFn = !fieldDeleted && (!actions || actions.includes("delete")) ? deleteParam ? wrapSupabaseFn(deleteParam) : async (input) => {
141
+ const deleteFn = !fieldDeleted && (!actions || actions.includes("delete")) ? deleteParam ? wrapSupabaseFn(deleteParam, "delete") : async (input, params) => {
142
+ const { onError } = params;
105
143
  const id = input.id;
106
144
  const res = await client.from(collection).delete().eq("id", id).select();
107
145
  const { data, error } = res;
108
146
  if (data) {
109
147
  const created = data[0];
110
148
  return created;
111
- } else {
112
- throw new Error(error == null ? void 0 : error.message);
149
+ } else if (error) {
150
+ handleSupabaseError(error, onError, {
151
+ setParams: params,
152
+ source: "delete",
153
+ type: "set",
154
+ retry: params,
155
+ input,
156
+ revert: createRevertChanges(params.value$, params.changes)
157
+ });
113
158
  }
114
159
  } : void 0;
115
160
  const subscribe = realtime ? ({ node, value$, update: update2 }) => {
package/sync.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MMKVConfiguration } from 'react-native-mmkv';
2
2
  import { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
3
- import { ClassConstructor, NodeInfo, ObservableParam, GetMode, SetParams, UpdateFn, LinkedOptions, RetryOptions, Change, Observable, ObservableSyncState, TypeAtPath, RecordValue, ArrayValue, WaitForSet } from '@legendapp/state';
3
+ import { ClassConstructor, NodeInfo, ObservableParam, GetMode, SetParams, UpdateSetFn, UpdateFn, LinkedOptions, RetryOptions, Change, Observable, ObservableSyncState, TypeAtPath, RecordValue, ArrayValue, WaitForSet } from '@legendapp/state';
4
4
  import { SyncedOptionsGlobal as SyncedOptionsGlobal$1 } from '@legendapp/state/sync';
5
5
 
6
6
  interface PersistOptions<T = any> {
@@ -32,12 +32,12 @@ interface SyncedGetParams<T> extends SyncedGetSetBaseParams<T> {
32
32
  lastSync: number | undefined;
33
33
  updateLastSync: (lastSync: number) => void;
34
34
  mode: GetMode;
35
- onError: (error: Error) => void;
35
+ onError: (error: Error, params: SyncedErrorParams) => void;
36
36
  options: SyncedOptions;
37
37
  }
38
38
  interface SyncedSetParams<T> extends Pick<SetParams<T>, 'changes' | 'value'>, SyncedGetSetBaseParams<T> {
39
- update: UpdateFn<T>;
40
- onError: (error: Error, retryParams: OnErrorRetryParams) => void;
39
+ update: UpdateSetFn<T>;
40
+ onError: (error: Error, params: SyncedErrorParams) => void;
41
41
  }
42
42
  interface SyncedSubscribeParams<T = any> extends SyncedGetSetSubscribeBaseParams<T> {
43
43
  lastSync: number | undefined;
@@ -45,12 +45,14 @@ interface SyncedSubscribeParams<T = any> extends SyncedGetSetSubscribeBaseParams
45
45
  onError: (error: Error) => void;
46
46
  }
47
47
  interface SyncedErrorParams {
48
+ source: 'get' | 'set' | 'subscribe';
49
+ type: 'get' | 'set';
50
+ retry: OnErrorRetryParams;
48
51
  getParams?: SyncedGetParams<any>;
49
52
  setParams?: SyncedSetParams<any>;
50
53
  subscribeParams?: SyncedSubscribeParams<any>;
51
- source: 'get' | 'set' | 'subscribe';
52
- value$: ObservableParam<any>;
53
- retryParams?: OnErrorRetryParams;
54
+ input?: any;
55
+ revert?: () => void;
54
56
  }
55
57
  interface SyncedOptions<TRemote = any, TLocal = TRemote> extends Omit<LinkedOptions<TRemote>, 'get' | 'set'> {
56
58
  get?: (params: SyncedGetParams<TRemote>) => Promise<TRemote> | TRemote;
@@ -215,11 +217,17 @@ declare function synced<TRemote, TLocal = TRemote>(params: SyncedOptions<TRemote
215
217
  declare function configureSynced<T extends (...args: any[]) => any>(fn: T, origOptions: Partial<Parameters<T>[0]>): T;
216
218
  declare function configureSynced(origOptions: SyncedOptions): typeof synced;
217
219
 
220
+ declare function createRevertChanges(obs$: ObservableParam<any>, changes: Change[]): () => void;
221
+
218
222
  declare function waitForSet(waitForSet: WaitForSet<any>, changes: Change[], value: any, params?: Record<string, any>): Promise<void>;
219
223
 
224
+ declare function runWithRetry<T>(state: SyncedGetSetBaseParams<any>, retryOptions: RetryOptions | undefined, retryId: any, fn: (params: OnErrorRetryParams) => Promise<T>): Promise<T>;
225
+ declare function runWithRetry<T>(state: SyncedGetSetBaseParams<any>, retryOptions: RetryOptions | undefined, retryId: any, fn: (params: OnErrorRetryParams) => T): T;
226
+
220
227
  declare const internal: {
221
228
  observableSyncConfiguration: SyncedOptionsGlobal;
222
229
  waitForSet: typeof waitForSet;
230
+ runWithRetry: typeof runWithRetry;
223
231
  };
224
232
 
225
- export { type FieldTransforms, type FieldTransformsInner, type ObservablePersistAsyncStoragePluginOptions, type ObservablePersistIndexedDBPluginOptions, type ObservablePersistPlugin, type ObservablePersistPluginOptions, type ObservableSyncFunctions, type ObservableSyncSetParams, type OnErrorRetryParams, type PendingChanges, type PersistMetadata, type PersistOptions, type QueryByModified, type StringToDate, type SubscribeOptions, type SyncTransform, type SyncTransformMethod, type Synced, type SyncedErrorParams, type SyncedGetParams, type SyncedGetSetBaseParams, type SyncedGetSetSubscribeBaseParams, type SyncedOptions, type SyncedOptionsGlobal, type SyncedSetParams, type SyncedSubscribeParams, type TransformStringifyKeys, type TransformStringifyOptions, type TransformStringsToDates, combineTransforms, configureObservableSync, configureSynced, deepEqual, diffObjects, internal, mapSyncPlugins, onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };
233
+ export { type FieldTransforms, type FieldTransformsInner, type ObservablePersistAsyncStoragePluginOptions, type ObservablePersistIndexedDBPluginOptions, type ObservablePersistPlugin, type ObservablePersistPluginOptions, type ObservableSyncFunctions, type ObservableSyncSetParams, type OnErrorRetryParams, type PendingChanges, type PersistMetadata, type PersistOptions, type QueryByModified, type StringToDate, type SubscribeOptions, type SyncTransform, type SyncTransformMethod, type Synced, type SyncedErrorParams, type SyncedGetParams, type SyncedGetSetBaseParams, type SyncedGetSetSubscribeBaseParams, type SyncedOptions, type SyncedOptionsGlobal, type SyncedSetParams, type SyncedSubscribeParams, type TransformStringifyKeys, type TransformStringifyOptions, type TransformStringsToDates, combineTransforms, configureObservableSync, configureSynced, createRevertChanges, deepEqual, diffObjects, internal, mapSyncPlugins, onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };
package/sync.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MMKVConfiguration } from 'react-native-mmkv';
2
2
  import { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
3
- import { ClassConstructor, NodeInfo, ObservableParam, GetMode, SetParams, UpdateFn, LinkedOptions, RetryOptions, Change, Observable, ObservableSyncState, TypeAtPath, RecordValue, ArrayValue, WaitForSet } from '@legendapp/state';
3
+ import { ClassConstructor, NodeInfo, ObservableParam, GetMode, SetParams, UpdateSetFn, UpdateFn, LinkedOptions, RetryOptions, Change, Observable, ObservableSyncState, TypeAtPath, RecordValue, ArrayValue, WaitForSet } from '@legendapp/state';
4
4
  import { SyncedOptionsGlobal as SyncedOptionsGlobal$1 } from '@legendapp/state/sync';
5
5
 
6
6
  interface PersistOptions<T = any> {
@@ -32,12 +32,12 @@ interface SyncedGetParams<T> extends SyncedGetSetBaseParams<T> {
32
32
  lastSync: number | undefined;
33
33
  updateLastSync: (lastSync: number) => void;
34
34
  mode: GetMode;
35
- onError: (error: Error) => void;
35
+ onError: (error: Error, params: SyncedErrorParams) => void;
36
36
  options: SyncedOptions;
37
37
  }
38
38
  interface SyncedSetParams<T> extends Pick<SetParams<T>, 'changes' | 'value'>, SyncedGetSetBaseParams<T> {
39
- update: UpdateFn<T>;
40
- onError: (error: Error, retryParams: OnErrorRetryParams) => void;
39
+ update: UpdateSetFn<T>;
40
+ onError: (error: Error, params: SyncedErrorParams) => void;
41
41
  }
42
42
  interface SyncedSubscribeParams<T = any> extends SyncedGetSetSubscribeBaseParams<T> {
43
43
  lastSync: number | undefined;
@@ -45,12 +45,14 @@ interface SyncedSubscribeParams<T = any> extends SyncedGetSetSubscribeBaseParams
45
45
  onError: (error: Error) => void;
46
46
  }
47
47
  interface SyncedErrorParams {
48
+ source: 'get' | 'set' | 'subscribe';
49
+ type: 'get' | 'set';
50
+ retry: OnErrorRetryParams;
48
51
  getParams?: SyncedGetParams<any>;
49
52
  setParams?: SyncedSetParams<any>;
50
53
  subscribeParams?: SyncedSubscribeParams<any>;
51
- source: 'get' | 'set' | 'subscribe';
52
- value$: ObservableParam<any>;
53
- retryParams?: OnErrorRetryParams;
54
+ input?: any;
55
+ revert?: () => void;
54
56
  }
55
57
  interface SyncedOptions<TRemote = any, TLocal = TRemote> extends Omit<LinkedOptions<TRemote>, 'get' | 'set'> {
56
58
  get?: (params: SyncedGetParams<TRemote>) => Promise<TRemote> | TRemote;
@@ -215,11 +217,17 @@ declare function synced<TRemote, TLocal = TRemote>(params: SyncedOptions<TRemote
215
217
  declare function configureSynced<T extends (...args: any[]) => any>(fn: T, origOptions: Partial<Parameters<T>[0]>): T;
216
218
  declare function configureSynced(origOptions: SyncedOptions): typeof synced;
217
219
 
220
+ declare function createRevertChanges(obs$: ObservableParam<any>, changes: Change[]): () => void;
221
+
218
222
  declare function waitForSet(waitForSet: WaitForSet<any>, changes: Change[], value: any, params?: Record<string, any>): Promise<void>;
219
223
 
224
+ declare function runWithRetry<T>(state: SyncedGetSetBaseParams<any>, retryOptions: RetryOptions | undefined, retryId: any, fn: (params: OnErrorRetryParams) => Promise<T>): Promise<T>;
225
+ declare function runWithRetry<T>(state: SyncedGetSetBaseParams<any>, retryOptions: RetryOptions | undefined, retryId: any, fn: (params: OnErrorRetryParams) => T): T;
226
+
220
227
  declare const internal: {
221
228
  observableSyncConfiguration: SyncedOptionsGlobal;
222
229
  waitForSet: typeof waitForSet;
230
+ runWithRetry: typeof runWithRetry;
223
231
  };
224
232
 
225
- export { type FieldTransforms, type FieldTransformsInner, type ObservablePersistAsyncStoragePluginOptions, type ObservablePersistIndexedDBPluginOptions, type ObservablePersistPlugin, type ObservablePersistPluginOptions, type ObservableSyncFunctions, type ObservableSyncSetParams, type OnErrorRetryParams, type PendingChanges, type PersistMetadata, type PersistOptions, type QueryByModified, type StringToDate, type SubscribeOptions, type SyncTransform, type SyncTransformMethod, type Synced, type SyncedErrorParams, type SyncedGetParams, type SyncedGetSetBaseParams, type SyncedGetSetSubscribeBaseParams, type SyncedOptions, type SyncedOptionsGlobal, type SyncedSetParams, type SyncedSubscribeParams, type TransformStringifyKeys, type TransformStringifyOptions, type TransformStringsToDates, combineTransforms, configureObservableSync, configureSynced, deepEqual, diffObjects, internal, mapSyncPlugins, onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };
233
+ export { type FieldTransforms, type FieldTransformsInner, type ObservablePersistAsyncStoragePluginOptions, type ObservablePersistIndexedDBPluginOptions, type ObservablePersistPlugin, type ObservablePersistPluginOptions, type ObservableSyncFunctions, type ObservableSyncSetParams, type OnErrorRetryParams, type PendingChanges, type PersistMetadata, type PersistOptions, type QueryByModified, type StringToDate, type SubscribeOptions, type SyncTransform, type SyncTransformMethod, type Synced, type SyncedErrorParams, type SyncedGetParams, type SyncedGetSetBaseParams, type SyncedGetSetSubscribeBaseParams, type SyncedOptions, type SyncedOptionsGlobal, type SyncedSetParams, type SyncedSubscribeParams, type TransformStringifyKeys, type TransformStringifyOptions, type TransformStringsToDates, combineTransforms, configureObservableSync, configureSynced, createRevertChanges, deepEqual, diffObjects, internal, mapSyncPlugins, onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };