@legendapp/state 3.0.0-beta.12 → 3.0.0-beta.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.DS_Store +0 -0
- package/config/enableReactComponents.js +3 -1
- package/config/enableReactComponents.mjs +3 -1
- package/index.d.mts +6 -1
- package/index.d.ts +6 -1
- package/index.js +35 -9
- package/index.mjs +35 -9
- package/package.json +1 -1
- package/react-reactive/enableReactComponents.js +3 -1
- package/react-reactive/enableReactComponents.mjs +3 -1
- package/react-reactive/enableReactive.js +3 -1
- package/react-reactive/enableReactive.mjs +3 -1
- package/react.d.mts +26 -15
- package/react.d.ts +26 -15
- package/react.js +13 -9
- package/react.mjs +13 -9
- package/sync-plugins/crud.d.mts +8 -3
- package/sync-plugins/crud.d.ts +8 -3
- package/sync-plugins/crud.js +144 -80
- package/sync-plugins/crud.mjs +144 -80
- package/sync-plugins/firebase.d.mts +7 -3
- package/sync-plugins/firebase.d.ts +7 -3
- package/sync-plugins/firebase.js +4 -2
- package/sync-plugins/firebase.mjs +4 -2
- package/sync-plugins/keel.d.mts +5 -9
- package/sync-plugins/keel.d.ts +5 -9
- package/sync-plugins/keel.js +48 -30
- package/sync-plugins/keel.mjs +48 -30
- package/sync-plugins/supabase.d.mts +7 -3
- package/sync-plugins/supabase.d.ts +7 -3
- package/sync-plugins/supabase.js +55 -18
- package/sync-plugins/supabase.mjs +56 -19
- package/sync.d.mts +16 -8
- package/sync.d.ts +16 -8
- package/sync.js +95 -67
- package/sync.mjs +94 -67
package/sync-plugins/keel.mjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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 (
|
|
207
|
-
|
|
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
|
-
|
|
230
|
+
params.cancelRetry = true;
|
|
224
231
|
} else {
|
|
225
|
-
await handleApiError(props, error);
|
|
226
|
-
|
|
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?:
|
|
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?:
|
|
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 };
|
package/sync-plugins/supabase.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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 (
|
|
82
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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 (
|
|
80
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
40
|
-
onError: (error: Error,
|
|
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
|
-
|
|
52
|
-
|
|
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:
|
|
40
|
-
onError: (error: Error,
|
|
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
|
-
|
|
52
|
-
|
|
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 };
|