@legendapp/state 3.0.0-beta.13 → 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.
@@ -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,14 @@ 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) {
50
51
  if (error.type === "unauthorized" || error.type === "forbidden") {
51
52
  console.warn("Keel token expired, refreshing...");
52
53
  isAuthed$.set(false);
53
54
  await ensureAuthToken(props);
55
+ return true;
54
56
  }
57
+ return false;
55
58
  }
56
59
  function convertObjectToCreate(item) {
57
60
  const cloned = {};
@@ -91,7 +94,7 @@ function setupRealtime(props) {
91
94
  }
92
95
  }
93
96
  var NumPerPage = 200;
94
- async function getAllPages(props, listFn, params) {
97
+ async function getAllPages(props, listFn, params, listParams, onError) {
95
98
  const allData = [];
96
99
  let pageInfo = void 0;
97
100
  const { first: firstParam } = params;
@@ -107,8 +110,17 @@ async function getAllPages(props, listFn, params) {
107
110
  if (ret) {
108
111
  const { data, error } = ret;
109
112
  if (error) {
110
- await handleApiError(props, error);
111
- throw new Error(error.message);
113
+ const handled = await handleApiError(props, error);
114
+ if (!handled) {
115
+ const err = new Error(error.message, { cause: { error } });
116
+ onError(err, {
117
+ getParams: listParams,
118
+ type: "get",
119
+ source: "list",
120
+ action: listFn.name || listFn.toString(),
121
+ retry: listParams
122
+ });
123
+ }
112
124
  } else if (data) {
113
125
  pageInfo = data.pageInfo;
114
126
  allData.push(...data.results);
@@ -132,7 +144,6 @@ function syncedKeel(props) {
132
144
  fieldDeleted,
133
145
  realtime,
134
146
  mode,
135
- onError,
136
147
  requireAuth = true,
137
148
  ...rest
138
149
  } = props;
@@ -152,7 +163,7 @@ function syncedKeel(props) {
152
163
  }
153
164
  } : void 0;
154
165
  const list = listParam ? async (listParams) => {
155
- const { lastSync } = listParams;
166
+ const { lastSync, onError } = listParams;
156
167
  const queryBySync = !!lastSync && changesSince === "last-sync";
157
168
  const where = Object.assign(
158
169
  queryBySync ? { updatedAt: { after: new Date(lastSync + 1) } } : {},
@@ -160,14 +171,14 @@ function syncedKeel(props) {
160
171
  );
161
172
  const params = { where, first };
162
173
  realtimeState.current = {};
163
- const promise = getAllPages(props, listParam, params);
174
+ const promise = getAllPages(props, listParam, params, listParams, onError);
164
175
  if (realtime) {
165
176
  setupSubscribe(listParams);
166
177
  }
167
178
  return promise;
168
179
  } : void 0;
169
180
  const get = getParam ? async (getParams) => {
170
- const { refresh } = getParams;
181
+ const { refresh, onError } = getParams;
171
182
  realtimeState.current = {};
172
183
  const promise = getParam({ refresh });
173
184
  if (realtime) {
@@ -175,7 +186,17 @@ function syncedKeel(props) {
175
186
  }
176
187
  const { data, error } = await promise;
177
188
  if (error) {
178
- throw new Error(error.message);
189
+ const handled = await handleApiError(props, error);
190
+ if (!handled) {
191
+ const err = new Error(error.message, { cause: { error } });
192
+ onError(err, {
193
+ getParams,
194
+ type: "get",
195
+ source: "get",
196
+ action: getParam.name || getParam.toString(),
197
+ retry: getParams
198
+ });
199
+ }
179
200
  } else {
180
201
  return data;
181
202
  }
@@ -192,7 +213,7 @@ function syncedKeel(props) {
192
213
  };
193
214
  const handleSetError = async (error, params, input, fn, from) => {
194
215
  var _a, _b;
195
- const { retryNum, update: update2 } = params;
216
+ const { update: update2, onError } = params;
196
217
  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
218
  if (__DEV__) {
198
219
  console.log("Creating duplicate data already saved, just ignore.");
@@ -202,28 +223,25 @@ function syncedKeel(props) {
202
223
  value: {},
203
224
  mode: "assign"
204
225
  });
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;
226
+ } else if (from === "delete" && error.message === "record not found") {
227
+ if (__DEV__) {
228
+ console.log("Deleting non-existing data, just ignore.");
222
229
  }
223
- throw new Error(error.message, { cause: { input } });
230
+ params.cancelRetry = true;
224
231
  } else {
225
- await handleApiError(props, error);
226
- throw new Error(error.message, { cause: { input } });
232
+ const handled = await handleApiError(props, error);
233
+ if (!handled) {
234
+ const err = new Error(error.message, { cause: { error } });
235
+ onError(err, {
236
+ setParams: params,
237
+ input,
238
+ type: "set",
239
+ source: from,
240
+ action: fn.name || fn.toString(),
241
+ retry: params,
242
+ revert: createRevertChanges(params.value$, params.changes)
243
+ });
244
+ }
227
245
  }
228
246
  };
229
247
  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,11 +18,17 @@ 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
  };
@@ -65,8 +71,8 @@ function syncedSupabase(props) {
65
71
  console.warn("[legend-state] fieldDeleted is required when using last-sync mode");
66
72
  }
67
73
  }
68
- const list = !actions || actions.includes("read") ? listParam ? wrapSupabaseFn(listParam) : async (params) => {
69
- const { lastSync } = params;
74
+ const list = !actions || actions.includes("read") ? listParam ? wrapSupabaseFn(listParam, "list") : async (params) => {
75
+ const { lastSync, onError } = params;
70
76
  const clientSchema = schema ? client.schema(schema) : client;
71
77
  const from = clientSchema.from(collection);
72
78
  let select = selectFn ? selectFn(from) : from.select();
@@ -78,40 +84,71 @@ function syncedSupabase(props) {
78
84
  select = filter(select, params);
79
85
  }
80
86
  const { data, error } = await select;
81
- if (error) {
82
- throw new Error(error == null ? void 0 : error.message);
87
+ if (data) {
88
+ return data || [];
89
+ } else if (error) {
90
+ onError(new Error(error.message), {
91
+ getParams: params,
92
+ source: "list",
93
+ type: "get",
94
+ retry: params
95
+ });
83
96
  }
84
- return data || [];
97
+ return null;
85
98
  } : void 0;
86
- const create = createParam ? wrapSupabaseFn(createParam) : !actions || actions.includes("create") ? async (input) => {
99
+ const create = createParam ? wrapSupabaseFn(createParam, "create") : !actions || actions.includes("create") ? async (input, params) => {
100
+ const { onError } = params;
87
101
  const res = await client.from(collection).insert(input).select();
88
102
  const { data, error } = res;
89
103
  if (data) {
90
104
  const created = data[0];
91
105
  return created;
92
- } else {
93
- throw new Error(error == null ? void 0 : error.message);
106
+ } else if (error) {
107
+ onError(new Error(error.message), {
108
+ setParams: params,
109
+ source: "create",
110
+ type: "set",
111
+ retry: params,
112
+ input,
113
+ revert: sync.createRevertChanges(params.value$, params.changes)
114
+ });
94
115
  }
95
116
  } : void 0;
96
- const update = !actions || actions.includes("update") ? updateParam ? wrapSupabaseFn(updateParam) : async (input) => {
117
+ const update = !actions || actions.includes("update") ? updateParam ? wrapSupabaseFn(updateParam, "update") : async (input, params) => {
118
+ const { onError } = params;
97
119
  const res = await client.from(collection).update(input).eq("id", input.id).select();
98
120
  const { data, error } = res;
99
121
  if (data) {
100
122
  const created = data[0];
101
123
  return created;
102
- } else {
103
- throw new Error(error == null ? void 0 : error.message);
124
+ } else if (error) {
125
+ onError(new Error(error.message), {
126
+ setParams: params,
127
+ source: "update",
128
+ type: "set",
129
+ retry: params,
130
+ input,
131
+ revert: sync.createRevertChanges(params.value$, params.changes)
132
+ });
104
133
  }
105
134
  } : void 0;
106
- const deleteFn = !fieldDeleted && (!actions || actions.includes("delete")) ? deleteParam ? wrapSupabaseFn(deleteParam) : async (input) => {
135
+ const deleteFn = !fieldDeleted && (!actions || actions.includes("delete")) ? deleteParam ? wrapSupabaseFn(deleteParam, "delete") : async (input, params) => {
136
+ const { onError } = params;
107
137
  const id = input.id;
108
138
  const res = await client.from(collection).delete().eq("id", id).select();
109
139
  const { data, error } = res;
110
140
  if (data) {
111
141
  const created = data[0];
112
142
  return created;
113
- } else {
114
- throw new Error(error == null ? void 0 : error.message);
143
+ } else if (error) {
144
+ onError(new Error(error.message), {
145
+ setParams: params,
146
+ source: "delete",
147
+ type: "set",
148
+ retry: params,
149
+ input,
150
+ revert: sync.createRevertChanges(params.value$, params.changes)
151
+ });
115
152
  }
116
153
  } : void 0;
117
154
  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,11 +16,17 @@ 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
  };
@@ -63,8 +69,8 @@ function syncedSupabase(props) {
63
69
  console.warn("[legend-state] fieldDeleted is required when using last-sync mode");
64
70
  }
65
71
  }
66
- const list = !actions || actions.includes("read") ? listParam ? wrapSupabaseFn(listParam) : async (params) => {
67
- const { lastSync } = params;
72
+ const list = !actions || actions.includes("read") ? listParam ? wrapSupabaseFn(listParam, "list") : async (params) => {
73
+ const { lastSync, onError } = params;
68
74
  const clientSchema = schema ? client.schema(schema) : client;
69
75
  const from = clientSchema.from(collection);
70
76
  let select = selectFn ? selectFn(from) : from.select();
@@ -76,40 +82,71 @@ function syncedSupabase(props) {
76
82
  select = filter(select, params);
77
83
  }
78
84
  const { data, error } = await select;
79
- if (error) {
80
- throw new Error(error == null ? void 0 : error.message);
85
+ if (data) {
86
+ return data || [];
87
+ } else if (error) {
88
+ onError(new Error(error.message), {
89
+ getParams: params,
90
+ source: "list",
91
+ type: "get",
92
+ retry: params
93
+ });
81
94
  }
82
- return data || [];
95
+ return null;
83
96
  } : void 0;
84
- const create = createParam ? wrapSupabaseFn(createParam) : !actions || actions.includes("create") ? async (input) => {
97
+ const create = createParam ? wrapSupabaseFn(createParam, "create") : !actions || actions.includes("create") ? async (input, params) => {
98
+ const { onError } = params;
85
99
  const res = await client.from(collection).insert(input).select();
86
100
  const { data, error } = res;
87
101
  if (data) {
88
102
  const created = data[0];
89
103
  return created;
90
- } else {
91
- throw new Error(error == null ? void 0 : error.message);
104
+ } else if (error) {
105
+ onError(new Error(error.message), {
106
+ setParams: params,
107
+ source: "create",
108
+ type: "set",
109
+ retry: params,
110
+ input,
111
+ revert: createRevertChanges(params.value$, params.changes)
112
+ });
92
113
  }
93
114
  } : void 0;
94
- const update = !actions || actions.includes("update") ? updateParam ? wrapSupabaseFn(updateParam) : async (input) => {
115
+ const update = !actions || actions.includes("update") ? updateParam ? wrapSupabaseFn(updateParam, "update") : async (input, params) => {
116
+ const { onError } = params;
95
117
  const res = await client.from(collection).update(input).eq("id", input.id).select();
96
118
  const { data, error } = res;
97
119
  if (data) {
98
120
  const created = data[0];
99
121
  return created;
100
- } else {
101
- throw new Error(error == null ? void 0 : error.message);
122
+ } else if (error) {
123
+ onError(new Error(error.message), {
124
+ setParams: params,
125
+ source: "update",
126
+ type: "set",
127
+ retry: params,
128
+ input,
129
+ revert: createRevertChanges(params.value$, params.changes)
130
+ });
102
131
  }
103
132
  } : void 0;
104
- const deleteFn = !fieldDeleted && (!actions || actions.includes("delete")) ? deleteParam ? wrapSupabaseFn(deleteParam) : async (input) => {
133
+ const deleteFn = !fieldDeleted && (!actions || actions.includes("delete")) ? deleteParam ? wrapSupabaseFn(deleteParam, "delete") : async (input, params) => {
134
+ const { onError } = params;
105
135
  const id = input.id;
106
136
  const res = await client.from(collection).delete().eq("id", id).select();
107
137
  const { data, error } = res;
108
138
  if (data) {
109
139
  const created = data[0];
110
140
  return created;
111
- } else {
112
- throw new Error(error == null ? void 0 : error.message);
141
+ } else if (error) {
142
+ onError(new Error(error.message), {
143
+ setParams: params,
144
+ source: "delete",
145
+ type: "set",
146
+ retry: params,
147
+ input,
148
+ revert: createRevertChanges(params.value$, params.changes)
149
+ });
113
150
  }
114
151
  } : void 0;
115
152
  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 };