@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.
- package/.DS_Store +0 -0
- package/index.d.mts +5 -1
- package/index.d.ts +5 -1
- package/index.js +6 -4
- package/index.mjs +6 -4
- package/package.json +1 -1
- package/react.d.mts +3 -3
- package/react.d.ts +3 -3
- 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 +6 -9
- package/sync-plugins/keel.d.ts +6 -9
- package/sync-plugins/keel.js +51 -30
- package/sync-plugins/keel.mjs +51 -30
- package/sync-plugins/supabase.d.mts +7 -3
- package/sync-plugins/supabase.d.ts +7 -3
- package/sync-plugins/supabase.js +63 -18
- package/sync-plugins/supabase.mjs +64 -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,17 @@ 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) {
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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 (
|
|
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;
|
|
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
|
-
|
|
233
|
+
params.cancelRetry = true;
|
|
224
234
|
} else {
|
|
225
|
-
await handleApiError(props, error);
|
|
226
|
-
|
|
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?:
|
|
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,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 {
|
|
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
|
};
|
|
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 (
|
|
82
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
};
|
|
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 (
|
|
80
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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 };
|