@legendapp/state 3.0.0-alpha.4 → 3.0.0-alpha.41

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.
Files changed (94) hide show
  1. package/.DS_Store +0 -0
  2. package/CHANGELOG.md +831 -1
  3. package/LICENSE +21 -1
  4. package/README.md +141 -1
  5. package/babel.js +0 -2
  6. package/babel.mjs +0 -2
  7. package/config/configureLegendState.d.mts +13 -0
  8. package/config/configureLegendState.d.ts +13 -0
  9. package/config/configureLegendState.js +45 -0
  10. package/config/configureLegendState.mjs +43 -0
  11. package/config/enable$GetSet.js +2 -1
  12. package/config/enable$GetSet.mjs +2 -1
  13. package/config/enableReactTracking.js +2 -1
  14. package/config/enableReactTracking.mjs +2 -1
  15. package/config/enableReactUse.js +2 -1
  16. package/config/enableReactUse.mjs +2 -1
  17. package/config/enable_PeekAssign.js +2 -1
  18. package/config/enable_PeekAssign.mjs +2 -1
  19. package/helpers/trackHistory.js +2 -2
  20. package/helpers/trackHistory.mjs +2 -2
  21. package/index.d.mts +106 -81
  22. package/index.d.ts +106 -81
  23. package/index.js +347 -335
  24. package/index.mjs +344 -333
  25. package/package.json +36 -1
  26. package/persist-plugins/async-storage.d.mts +6 -3
  27. package/persist-plugins/async-storage.d.ts +6 -3
  28. package/persist-plugins/async-storage.js +8 -4
  29. package/persist-plugins/async-storage.mjs +8 -5
  30. package/persist-plugins/indexeddb.d.mts +6 -4
  31. package/persist-plugins/indexeddb.d.ts +6 -4
  32. package/persist-plugins/indexeddb.js +35 -15
  33. package/persist-plugins/indexeddb.mjs +35 -16
  34. package/persist-plugins/mmkv.d.mts +5 -1
  35. package/persist-plugins/mmkv.d.ts +5 -1
  36. package/persist-plugins/mmkv.js +10 -5
  37. package/persist-plugins/mmkv.mjs +10 -6
  38. package/react-reactive/enableReactComponents.d.mts +9 -0
  39. package/react-reactive/enableReactComponents.d.ts +9 -0
  40. package/react-reactive/enableReactComponents.js +19 -0
  41. package/react-reactive/enableReactComponents.mjs +17 -0
  42. package/react-reactive/enableReactNativeComponents.d.mts +22 -0
  43. package/react-reactive/enableReactNativeComponents.d.ts +22 -0
  44. package/react-reactive/enableReactNativeComponents.js +53 -0
  45. package/react-reactive/enableReactNativeComponents.mjs +51 -0
  46. package/react-reactive/enableReactive.d.mts +5 -0
  47. package/react-reactive/enableReactive.d.ts +5 -0
  48. package/react-reactive/enableReactive.js +24 -0
  49. package/react-reactive/enableReactive.mjs +22 -0
  50. package/react-reactive/enableReactive.native.d.mts +5 -0
  51. package/react-reactive/enableReactive.native.d.ts +5 -0
  52. package/react-reactive/enableReactive.native.js +58 -0
  53. package/react-reactive/enableReactive.native.mjs +56 -0
  54. package/react-reactive/enableReactive.web.d.mts +5 -0
  55. package/react-reactive/enableReactive.web.d.ts +5 -0
  56. package/react-reactive/enableReactive.web.js +58 -0
  57. package/react-reactive/enableReactive.web.mjs +56 -0
  58. package/react.d.mts +39 -34
  59. package/react.d.ts +39 -34
  60. package/react.js +54 -27
  61. package/react.mjs +55 -28
  62. package/sync-plugins/crud.d.mts +21 -24
  63. package/sync-plugins/crud.d.ts +21 -24
  64. package/sync-plugins/crud.js +241 -140
  65. package/sync-plugins/crud.mjs +243 -142
  66. package/sync-plugins/fetch.js +12 -8
  67. package/sync-plugins/fetch.mjs +13 -9
  68. package/sync-plugins/firebase.d.mts +27 -0
  69. package/sync-plugins/firebase.d.ts +27 -0
  70. package/sync-plugins/firebase.js +373 -0
  71. package/sync-plugins/firebase.mjs +368 -0
  72. package/sync-plugins/keel.d.mts +43 -26
  73. package/sync-plugins/keel.d.ts +43 -26
  74. package/sync-plugins/keel.js +145 -100
  75. package/sync-plugins/keel.mjs +147 -100
  76. package/sync-plugins/supabase.d.mts +19 -9
  77. package/sync-plugins/supabase.d.ts +19 -9
  78. package/sync-plugins/supabase.js +52 -22
  79. package/sync-plugins/supabase.mjs +53 -23
  80. package/sync-plugins/tanstack-query.d.mts +2 -2
  81. package/sync-plugins/tanstack-query.d.ts +2 -2
  82. package/sync-plugins/tanstack-query.js +22 -5
  83. package/sync-plugins/tanstack-query.mjs +22 -5
  84. package/sync-plugins/tanstack-react-query.d.mts +1 -1
  85. package/sync-plugins/tanstack-react-query.d.ts +1 -1
  86. package/sync-plugins/tanstack-react-query.js +8 -1
  87. package/sync-plugins/tanstack-react-query.mjs +8 -1
  88. package/sync.d.mts +74 -200
  89. package/sync.d.ts +74 -200
  90. package/sync.js +510 -307
  91. package/sync.mjs +516 -313
  92. package/types/babel.d.ts +12 -1
  93. /package/config/{enable_GetSet.d.mts → enable$GetSet.d.mts} +0 -0
  94. /package/config/{enable_GetSet.d.ts → enable$GetSet.d.ts} +0 -0
@@ -1,88 +1,99 @@
1
- import ksuid from 'ksuid';
2
- import { observable, computeSelector, isFunction, isEmpty, when, internal } from '@legendapp/state';
3
- import { removeNullUndefined } from '@legendapp/state/sync';
1
+ import { observable, isFunction, when, batch, isEmpty } from '@legendapp/state';
4
2
  import { syncedCrud } from '@legendapp/state/sync-plugins/crud';
3
+ import ksuid from 'ksuid';
5
4
 
6
5
  // src/sync-plugins/keel.ts
7
- var { clone } = internal;
8
6
  var KeelKeys = ["createdAt", "updatedAt"];
9
7
  function generateKeelId() {
10
8
  return ksuid.randomSync().string;
11
9
  }
12
- var keelConfig = {};
13
10
  var modifiedClients = /* @__PURE__ */ new WeakSet();
14
- var isEnabled$ = observable(true);
15
- async function ensureAuthToken() {
16
- await when(isEnabled$.get());
17
- let isAuthed = await keelConfig.client.auth.isAuthenticated();
11
+ var isAuthed$ = observable(false);
12
+ var isAuthing$ = observable(false);
13
+ async function ensureAuthToken(props, force) {
14
+ if (!force && isAuthed$.get()) {
15
+ return true;
16
+ }
17
+ const { client, refreshAuth } = props;
18
+ let isAuthed = await client.auth.isAuthenticated().then(({ data }) => data);
18
19
  if (!isAuthed) {
19
- isAuthed = await keelConfig.client.auth.refresh();
20
+ if (!force && isAuthing$.get()) {
21
+ return when(
22
+ () => !isAuthing$.get(),
23
+ () => isAuthed$.get()
24
+ );
25
+ }
26
+ isAuthing$.set(true);
27
+ if (refreshAuth) {
28
+ await refreshAuth();
29
+ }
30
+ isAuthed = await client.auth.isAuthenticated().then(({ data }) => data);
31
+ if (!isAuthed) {
32
+ isAuthed = await client.auth.refresh().then(({ data }) => data);
33
+ }
34
+ }
35
+ if (isAuthed) {
36
+ batch(() => {
37
+ isAuthed$.set(true);
38
+ isAuthing$.set(false);
39
+ });
40
+ } else {
41
+ setTimeout(() => ensureAuthToken(
42
+ props,
43
+ /*force*/
44
+ true
45
+ ), 1e3);
20
46
  }
21
47
  return isAuthed;
22
48
  }
23
- async function handleApiError(error, retry) {
49
+ async function handleApiError(props, error, retry) {
24
50
  if (error.type === "unauthorized" || error.type === "forbidden") {
25
51
  console.warn("Keel token expired, refreshing...");
26
- await ensureAuthToken();
52
+ isAuthed$.set(false);
53
+ await ensureAuthToken(props);
27
54
  }
28
55
  }
29
56
  function convertObjectToCreate(item) {
30
- const cloned = clone(item);
31
- Object.keys(cloned).forEach((key) => {
57
+ const cloned = {};
58
+ Object.keys(item).forEach((key) => {
32
59
  if (key.endsWith("Id")) {
33
- if (cloned[key]) {
34
- cloned[key.slice(0, -2)] = { id: cloned[key] };
60
+ if (item[key]) {
61
+ cloned[key.slice(0, -2)] = { id: item[key] };
62
+ }
63
+ } else if (key !== "createdAt" && key !== "updatedAt") {
64
+ if (item[key] === void 0) {
65
+ cloned[key] = null;
66
+ } else {
67
+ cloned[key] = item[key];
35
68
  }
36
- delete cloned[key];
37
69
  }
38
70
  });
39
- delete cloned.createdAt;
40
- delete cloned.updatedAt;
41
71
  return cloned;
42
72
  }
43
- function getSyncedKeelConfiguration() {
44
- return keelConfig;
45
- }
46
- function configureSyncedKeel(config) {
47
- const { enabled, realtimePlugin, client, ...rest } = config;
48
- Object.assign(keelConfig, removeNullUndefined(rest));
49
- if (enabled !== void 0) {
50
- isEnabled$.set(enabled);
51
- }
52
- if (realtimePlugin) {
53
- keelConfig.realtimePlugin = realtimePlugin;
54
- if (client && !modifiedClients.has(client)) {
55
- modifiedClients.add(client);
56
- const queries = client.api.queries;
57
- Object.keys(queries).forEach((key) => {
58
- if (key.startsWith("list")) {
59
- const oldFn = queries[key];
60
- queries[key] = (i) => {
61
- const realtimeKey = [key, ...Object.values(i.where || {})].filter((value) => value && typeof value !== "object").join("/");
62
- const subscribe = ({ refresh }) => {
63
- if (realtimeKey) {
64
- return realtimePlugin.subscribe(realtimeKey, refresh);
65
- }
66
- };
67
- return oldFn(i).then((ret) => {
68
- if (subscribe) {
69
- ret.subscribe = subscribe;
70
- ret.subscribeKey = realtimeKey;
71
- }
72
- return ret;
73
- });
73
+ var realtimeState = { current: {} };
74
+ function setupRealtime(props) {
75
+ const { client } = props;
76
+ if (client && !modifiedClients.has(client)) {
77
+ modifiedClients.add(client);
78
+ const queries = client.api.queries;
79
+ Object.keys(queries).forEach((key) => {
80
+ if (key.startsWith("list")) {
81
+ const origFn = queries[key];
82
+ queries[key] = (i) => {
83
+ realtimeState.current = {
84
+ lastAction: key,
85
+ lastParams: i
74
86
  };
75
- }
76
- });
77
- }
87
+ return origFn(i);
88
+ };
89
+ }
90
+ });
78
91
  }
79
92
  }
80
93
  var NumPerPage = 200;
81
- async function getAllPages(listFn, params) {
94
+ async function getAllPages(props, listFn, params) {
82
95
  const allData = [];
83
96
  let pageInfo = void 0;
84
- let subscribe_;
85
- let subscribeKey_;
86
97
  const { first: firstParam } = params;
87
98
  do {
88
99
  const first = firstParam ? Math.min(firstParam - allData.length, NumPerPage) : NumPerPage;
@@ -94,13 +105,9 @@ async function getAllPages(listFn, params) {
94
105
  pageInfo = void 0;
95
106
  const ret = await listFn(paramsWithCursor);
96
107
  if (ret) {
97
- const { data, error, subscribe, subscribeKey } = ret;
98
- if (subscribe) {
99
- subscribe_ = subscribe;
100
- subscribeKey_ = subscribeKey;
101
- }
108
+ const { data, error } = ret;
102
109
  if (error) {
103
- await handleApiError(error);
110
+ await handleApiError(props, error);
104
111
  throw new Error(error.message);
105
112
  } else if (data) {
106
113
  pageInfo = data.pageInfo;
@@ -108,21 +115,25 @@ async function getAllPages(listFn, params) {
108
115
  }
109
116
  }
110
117
  } while (pageInfo == null ? void 0 : pageInfo.hasNextPage);
111
- return { results: allData, subscribe: subscribe_, subscribeKey: subscribeKey_ };
118
+ return allData;
112
119
  }
113
120
  function syncedKeel(props) {
114
- const { realtimePlugin } = keelConfig;
115
- props = { ...keelConfig, ...props };
116
121
  const {
117
122
  get: getParam,
118
123
  list: listParam,
119
124
  create: createParam,
120
125
  update: updateParam,
121
126
  delete: deleteParam,
127
+ subscribe: subscribeParam,
122
128
  first,
123
129
  where: whereParam,
124
130
  waitFor,
131
+ waitForSet,
125
132
  fieldDeleted,
133
+ realtime,
134
+ mode,
135
+ onError,
136
+ requireAuth = true,
126
137
  ...rest
127
138
  } = props;
128
139
  const { changesSince } = props;
@@ -131,28 +142,38 @@ function syncedKeel(props) {
131
142
  const subscribeFnKey$ = observable("");
132
143
  const fieldCreatedAt = "createdAt";
133
144
  const fieldUpdatedAt = "updatedAt";
145
+ const setupSubscribe = realtime ? async (getParams) => {
146
+ const { lastAction, lastParams } = realtimeState.current;
147
+ const { path, plugin } = realtime;
148
+ if (lastAction && path && plugin) {
149
+ const key = await path(lastAction, lastParams);
150
+ subscribeFn = () => realtime.plugin.subscribe(key, getParams);
151
+ subscribeFnKey$.set(key);
152
+ }
153
+ } : void 0;
134
154
  const list = listParam ? async (listParams) => {
135
- const { lastSync, refresh } = listParams;
155
+ const { lastSync } = listParams;
136
156
  const queryBySync = !!lastSync && changesSince === "last-sync";
137
157
  const where = Object.assign(
138
158
  queryBySync ? { updatedAt: { after: new Date(lastSync + 1) } } : {},
139
159
  isFunction(whereParam) ? whereParam() : whereParam
140
160
  );
141
161
  const params = { where, first };
142
- const { results, subscribe: subscribe2, subscribeKey } = await getAllPages(listParam, params);
143
- if (subscribe2) {
144
- subscribeFn = () => subscribe2({ refresh });
145
- subscribeFnKey$.set(subscribeKey);
162
+ realtimeState.current = {};
163
+ const promise = getAllPages(props, listParam, params);
164
+ if (realtime) {
165
+ setupSubscribe(listParams);
146
166
  }
147
- return results;
167
+ return promise;
148
168
  } : void 0;
149
169
  const get = getParam ? async (getParams) => {
150
170
  const { refresh } = getParams;
151
- const { data, error, subscribe: subscribe2, subscribeKey } = await getParam({ refresh });
152
- if (subscribe2) {
153
- subscribeFn = () => subscribe2({ refresh });
154
- subscribeFnKey$.set(subscribeKey);
171
+ realtimeState.current = {};
172
+ const promise = getParam({ refresh });
173
+ if (realtime) {
174
+ setupSubscribe(getParams);
155
175
  }
176
+ const { data, error } = await promise;
156
177
  if (error) {
157
178
  throw new Error(error.message);
158
179
  } else {
@@ -161,41 +182,54 @@ function syncedKeel(props) {
161
182
  } : void 0;
162
183
  const onSaved = ({ saved }) => {
163
184
  if (saved) {
164
- const updatedAt = saved[fieldUpdatedAt];
165
- if (updatedAt && realtimePlugin) {
185
+ if (realtime == null ? void 0 : realtime.plugin) {
166
186
  const subscribeFnKey = subscribeFnKey$.get();
167
187
  if (subscribeFnKey) {
168
- realtimePlugin.setLatestChange(subscribeFnKey, updatedAt);
188
+ realtime == null ? void 0 : realtime.plugin.setSaved(subscribeFnKey);
169
189
  }
170
190
  }
171
191
  }
172
192
  };
173
- const handleSetError = async (error, params, isCreate) => {
174
- var _a, _b, _c;
175
- const { retryNum, cancelRetry, update: update2 } = params;
176
- if (isCreate && ((_a = error.message) == null ? void 0 : _a.includes("for the unique")) && ((_b = error.message) == null ? void 0 : _b.includes("must be unique"))) {
193
+ const handleSetError = async (error, params, input, fn, from) => {
194
+ var _a, _b;
195
+ const { retryNum, update: update2 } = params;
196
+ 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"))) {
177
197
  if (__DEV__) {
178
198
  console.log("Creating duplicate data already saved, just ignore.");
179
199
  }
200
+ params.cancelRetry = true;
180
201
  update2({
181
202
  value: {},
182
203
  mode: "assign"
183
204
  });
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
+ }
184
212
  } else if (error.type === "bad_request") {
185
- (_c = keelConfig.onError) == null ? void 0 : _c.call(keelConfig, error);
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
+ });
186
220
  if (retryNum > 4) {
187
- cancelRetry();
221
+ params.cancelRetry = true;
188
222
  }
189
- throw new Error(error.message);
223
+ throw new Error(error.message, { cause: { input } });
190
224
  } else {
191
- await handleApiError(error);
192
- throw new Error(error.message);
225
+ await handleApiError(props, error);
226
+ throw new Error(error.message, { cause: { input } });
193
227
  }
194
228
  };
195
229
  const create = createParam ? async (input, params) => {
196
230
  const { data, error } = await createParam(convertObjectToCreate(input));
197
231
  if (error) {
198
- handleSetError(error, params, true);
232
+ await handleSetError(error, params, input, createParam, "create");
199
233
  }
200
234
  return data;
201
235
  } : void 0;
@@ -203,45 +237,58 @@ function syncedKeel(props) {
203
237
  const id = input.id;
204
238
  const values = convertObjectToCreate(input);
205
239
  delete values.id;
206
- delete values.createdAt;
207
- delete values.updatedAt;
208
240
  if (!isEmpty(values)) {
209
241
  const { data, error } = await updateParam({ where: { id }, values });
210
242
  if (error) {
211
- handleSetError(error, params, false);
243
+ await handleSetError(error, params, input, updateParam, "update");
212
244
  }
213
245
  return data;
214
246
  }
215
247
  } : void 0;
216
- const deleteFn = deleteParam ? async ({ id }, params) => {
217
- const { data, error } = await deleteParam({ id });
248
+ const deleteFn = deleteParam ? async (value, params) => {
249
+ const { data, error } = await deleteParam({ id: value.id });
218
250
  if (error) {
219
- handleSetError(error, params, false);
251
+ await handleSetError(error, params, value, deleteParam, "delete");
220
252
  }
221
253
  return data;
222
254
  } : void 0;
223
- const subscribe = (params) => {
255
+ if (realtime) {
256
+ setupRealtime(props);
257
+ }
258
+ const subscribe = realtime ? (params) => {
224
259
  let unsubscribe = void 0;
225
260
  when(subscribeFnKey$, () => {
226
261
  unsubscribe = subscribeFn(params);
227
262
  });
263
+ const unsubscribeParam = subscribeParam == null ? void 0 : subscribeParam(params);
228
264
  return () => {
229
265
  unsubscribe == null ? void 0 : unsubscribe();
266
+ unsubscribeParam == null ? void 0 : unsubscribeParam();
230
267
  };
231
- };
268
+ } : subscribeParam;
232
269
  return syncedCrud({
233
270
  ...rest,
234
271
  as: asType,
272
+ mode: mode || "merge",
235
273
  list,
236
274
  create,
237
275
  update,
238
276
  delete: deleteFn,
239
- waitFor: () => isEnabled$.get() && (waitFor ? computeSelector(waitFor) : true),
277
+ waitFor: () => {
278
+ ensureAuthToken(props);
279
+ return [requireAuth ? isAuthed$ : true, waitFor || true];
280
+ },
281
+ waitForSet: (params) => {
282
+ ensureAuthToken(props);
283
+ return [
284
+ requireAuth ? isAuthed$ : true,
285
+ () => waitForSet ? isFunction(waitForSet) ? waitForSet(params) : waitForSet : true
286
+ ];
287
+ },
240
288
  onSaved,
241
- onSavedUpdate: "createdUpdatedAt",
242
289
  fieldCreatedAt,
243
290
  fieldUpdatedAt,
244
- fieldDeleted: fieldDeleted || "deleted",
291
+ fieldDeleted,
245
292
  changesSince,
246
293
  updatePartial: true,
247
294
  subscribe,
@@ -251,4 +298,4 @@ function syncedKeel(props) {
251
298
  });
252
299
  }
253
300
 
254
- export { KeelKeys, configureSyncedKeel, generateKeelId, getSyncedKeelConfiguration, syncedKeel };
301
+ export { KeelKeys, generateKeelId, syncedKeel };
@@ -2,12 +2,17 @@ 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
4
  import { PostgrestQueryBuilder, PostgrestFilterBuilder } from '@supabase/postgrest-js';
5
- import { SupabaseClient } from '@supabase/supabase-js';
5
+ import { SupabaseClient, PostgrestSingleResponse } from '@supabase/supabase-js';
6
+ import { FunctionsResponse } from '@supabase/functions-js';
6
7
 
8
+ type DatabaseOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer TDB> ? TDB : never;
9
+ type SchemaNameOf<Client extends SupabaseClient> = keyof DatabaseOf<Client>;
10
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
11
+ type IsUnionOfStrings<T> = [T] extends [string] ? ([T] extends [UnionToIntersection<T>] ? false : true) : false;
7
12
  type SupabaseSchemaOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer _, infer __, infer Schema> ? Schema : never;
8
- type SupabaseTableOf<Client extends SupabaseClient> = SupabaseSchemaOf<Client>['Tables'];
9
- type SupabaseCollectionOf<Client extends SupabaseClient> = keyof SupabaseTableOf<Client>;
10
- type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client>> = SupabaseTableOf<Client>[Collection]['Row'];
13
+ type SupabaseTableOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = DatabaseOf<Client>[SchemaName]['Tables'];
14
+ type SupabaseCollectionOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = keyof SupabaseTableOf<Client, IsUnionOfStrings<SchemaName> extends true ? 'public' : SchemaName>;
15
+ type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>> = SupabaseTableOf<Client, SchemaName>[Collection]['Row'];
11
16
  type SyncedSupabaseConfig<TRemote extends {
12
17
  id: string | number;
13
18
  }, TLocal> = Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'create' | 'update' | 'delete'>;
@@ -20,20 +25,25 @@ interface SyncedSupabaseConfiguration extends Omit<SyncedSupabaseConfig<{
20
25
  enabled?: Observable<boolean>;
21
26
  as?: Exclude<CrudAsOption, 'value'>;
22
27
  }
23
- interface SyncedSupabaseProps<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client>, TOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection> = SupabaseRowOf<Client, Collection>, TLocal = TRemote> extends SyncedSupabaseConfig<TRemote, TLocal>, SyncedCrudPropsMany<TRemote, TRemote, TOption> {
24
- supabase: Client;
28
+ interface SyncedSupabaseProps<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 SyncedSupabaseConfig<TRemote, TLocal>, Omit<SyncedCrudPropsMany<TRemote, TRemote, TOption>, 'list'> {
29
+ supabase?: Client;
25
30
  collection: Collection;
26
- select?: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
27
- filter?: (select: PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>, params: SyncedGetParams) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
31
+ schema?: SchemaName;
32
+ select?: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
33
+ filter?: (select: PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>, params: SyncedGetParams<TRemote>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
28
34
  actions?: ('create' | 'read' | 'update' | 'delete')[];
29
35
  realtime?: boolean | {
30
36
  schema?: string;
31
37
  filter?: string;
32
38
  };
33
39
  stringifyDates?: boolean;
40
+ list?: (...params: Parameters<Required<SyncedCrudPropsMany<TRemote, TLocal, TOption>>['list']>) => PromiseLike<PostgrestSingleResponse<TRemote[]>> | Promise<FunctionsResponse<NoInfer<TRemote>[]>>;
41
+ create?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['create']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
42
+ update?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['update']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
43
+ delete?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['delete']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
34
44
  }
35
45
  declare function getSyncedSupabaseConfiguration(): SyncedSupabaseConfiguration;
36
46
  declare function configureSyncedSupabase(config: SyncedSupabaseConfiguration): void;
37
- declare function syncedSupabase<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client> & string, AsOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection> = SupabaseRowOf<Client, Collection>, TLocal = TRemote>(props: SyncedSupabaseProps<Client, Collection, AsOption, TRemote, TLocal>): SyncedCrudReturnType<TLocal, AsOption>;
47
+ 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>;
38
48
 
39
49
  export { type SupabaseCollectionOf, type SupabaseRowOf, type SupabaseSchemaOf, type SupabaseTableOf, type SyncedSupabaseConfig, type SyncedSupabaseConfiguration, configureSyncedSupabase, getSyncedSupabaseConfiguration, syncedSupabase };
@@ -2,12 +2,17 @@ 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
4
  import { PostgrestQueryBuilder, PostgrestFilterBuilder } from '@supabase/postgrest-js';
5
- import { SupabaseClient } from '@supabase/supabase-js';
5
+ import { SupabaseClient, PostgrestSingleResponse } from '@supabase/supabase-js';
6
+ import { FunctionsResponse } from '@supabase/functions-js';
6
7
 
8
+ type DatabaseOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer TDB> ? TDB : never;
9
+ type SchemaNameOf<Client extends SupabaseClient> = keyof DatabaseOf<Client>;
10
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
11
+ type IsUnionOfStrings<T> = [T] extends [string] ? ([T] extends [UnionToIntersection<T>] ? false : true) : false;
7
12
  type SupabaseSchemaOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer _, infer __, infer Schema> ? Schema : never;
8
- type SupabaseTableOf<Client extends SupabaseClient> = SupabaseSchemaOf<Client>['Tables'];
9
- type SupabaseCollectionOf<Client extends SupabaseClient> = keyof SupabaseTableOf<Client>;
10
- type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client>> = SupabaseTableOf<Client>[Collection]['Row'];
13
+ type SupabaseTableOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = DatabaseOf<Client>[SchemaName]['Tables'];
14
+ type SupabaseCollectionOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = keyof SupabaseTableOf<Client, IsUnionOfStrings<SchemaName> extends true ? 'public' : SchemaName>;
15
+ type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>> = SupabaseTableOf<Client, SchemaName>[Collection]['Row'];
11
16
  type SyncedSupabaseConfig<TRemote extends {
12
17
  id: string | number;
13
18
  }, TLocal> = Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'create' | 'update' | 'delete'>;
@@ -20,20 +25,25 @@ interface SyncedSupabaseConfiguration extends Omit<SyncedSupabaseConfig<{
20
25
  enabled?: Observable<boolean>;
21
26
  as?: Exclude<CrudAsOption, 'value'>;
22
27
  }
23
- interface SyncedSupabaseProps<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client>, TOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection> = SupabaseRowOf<Client, Collection>, TLocal = TRemote> extends SyncedSupabaseConfig<TRemote, TLocal>, SyncedCrudPropsMany<TRemote, TRemote, TOption> {
24
- supabase: Client;
28
+ interface SyncedSupabaseProps<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 SyncedSupabaseConfig<TRemote, TLocal>, Omit<SyncedCrudPropsMany<TRemote, TRemote, TOption>, 'list'> {
29
+ supabase?: Client;
25
30
  collection: Collection;
26
- select?: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
27
- filter?: (select: PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>, params: SyncedGetParams) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
31
+ schema?: SchemaName;
32
+ select?: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
33
+ filter?: (select: PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>, params: SyncedGetParams<TRemote>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
28
34
  actions?: ('create' | 'read' | 'update' | 'delete')[];
29
35
  realtime?: boolean | {
30
36
  schema?: string;
31
37
  filter?: string;
32
38
  };
33
39
  stringifyDates?: boolean;
40
+ list?: (...params: Parameters<Required<SyncedCrudPropsMany<TRemote, TLocal, TOption>>['list']>) => PromiseLike<PostgrestSingleResponse<TRemote[]>> | Promise<FunctionsResponse<NoInfer<TRemote>[]>>;
41
+ create?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['create']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
42
+ update?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['update']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
43
+ delete?: (...params: Parameters<Required<SyncedCrudPropsBase<TRemote>>['delete']>) => PromiseLike<PostgrestSingleResponse<TRemote>> | Promise<FunctionsResponse<NoInfer<TRemote>>>;
34
44
  }
35
45
  declare function getSyncedSupabaseConfiguration(): SyncedSupabaseConfiguration;
36
46
  declare function configureSyncedSupabase(config: SyncedSupabaseConfiguration): void;
37
- declare function syncedSupabase<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client> & string, AsOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection> = SupabaseRowOf<Client, Collection>, TLocal = TRemote>(props: SyncedSupabaseProps<Client, Collection, AsOption, TRemote, TLocal>): SyncedCrudReturnType<TLocal, AsOption>;
47
+ 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>;
38
48
 
39
49
  export { type SupabaseCollectionOf, type SupabaseRowOf, type SupabaseSchemaOf, type SupabaseTableOf, type SyncedSupabaseConfig, type SyncedSupabaseConfiguration, configureSyncedSupabase, getSyncedSupabaseConfiguration, syncedSupabase };