@legendapp/state 3.0.0-alpha.3 → 3.0.0-alpha.31

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 (74) hide show
  1. package/CHANGELOG.md +831 -1
  2. package/LICENSE +21 -1
  3. package/README.md +141 -1
  4. package/babel.js +0 -2
  5. package/babel.mjs +0 -2
  6. package/config/enable$GetSet.js +2 -1
  7. package/config/enable$GetSet.mjs +2 -1
  8. package/config/enableReactTracking.js +2 -1
  9. package/config/enableReactTracking.mjs +2 -1
  10. package/config/enableReactUse.js +2 -1
  11. package/config/enableReactUse.mjs +2 -1
  12. package/config/enable_PeekAssign.js +2 -1
  13. package/config/enable_PeekAssign.mjs +2 -1
  14. package/config.d.mts +13 -0
  15. package/config.d.ts +13 -0
  16. package/config.js +2066 -0
  17. package/config.mjs +2064 -0
  18. package/helpers/trackHistory.js +2 -2
  19. package/helpers/trackHistory.mjs +2 -2
  20. package/index.d.mts +25 -302
  21. package/index.d.ts +25 -302
  22. package/index.js +293 -322
  23. package/index.mjs +294 -321
  24. package/observableInterfaces-CZR3_8mM.d.mts +283 -0
  25. package/observableInterfaces-CZR3_8mM.d.ts +283 -0
  26. package/package.json +11 -1
  27. package/persist-plugins/async-storage.d.mts +6 -3
  28. package/persist-plugins/async-storage.d.ts +6 -3
  29. package/persist-plugins/async-storage.js +12 -4
  30. package/persist-plugins/async-storage.mjs +12 -5
  31. package/persist-plugins/indexeddb.d.mts +6 -4
  32. package/persist-plugins/indexeddb.d.ts +6 -4
  33. package/persist-plugins/indexeddb.js +16 -6
  34. package/persist-plugins/indexeddb.mjs +16 -7
  35. package/persist-plugins/mmkv.d.mts +5 -1
  36. package/persist-plugins/mmkv.d.ts +5 -1
  37. package/persist-plugins/mmkv.js +14 -5
  38. package/persist-plugins/mmkv.mjs +14 -6
  39. package/react.d.mts +18 -14
  40. package/react.d.ts +18 -14
  41. package/react.js +57 -32
  42. package/react.mjs +58 -33
  43. package/sync-plugins/crud.d.mts +21 -24
  44. package/sync-plugins/crud.d.ts +21 -24
  45. package/sync-plugins/crud.js +240 -139
  46. package/sync-plugins/crud.mjs +242 -141
  47. package/sync-plugins/fetch.js +12 -8
  48. package/sync-plugins/fetch.mjs +13 -9
  49. package/sync-plugins/firebase.d.mts +27 -0
  50. package/sync-plugins/firebase.d.ts +27 -0
  51. package/sync-plugins/firebase.js +373 -0
  52. package/sync-plugins/firebase.mjs +368 -0
  53. package/sync-plugins/keel.d.mts +27 -10
  54. package/sync-plugins/keel.d.ts +27 -10
  55. package/sync-plugins/keel.js +51 -32
  56. package/sync-plugins/keel.mjs +52 -33
  57. package/sync-plugins/supabase.d.mts +12 -7
  58. package/sync-plugins/supabase.d.ts +12 -7
  59. package/sync-plugins/supabase.js +24 -13
  60. package/sync-plugins/supabase.mjs +25 -14
  61. package/sync-plugins/tanstack-query.d.mts +2 -2
  62. package/sync-plugins/tanstack-query.d.ts +2 -2
  63. package/sync-plugins/tanstack-query.js +3 -2
  64. package/sync-plugins/tanstack-query.mjs +3 -2
  65. package/sync-plugins/tanstack-react-query.d.mts +1 -1
  66. package/sync-plugins/tanstack-react-query.d.ts +1 -1
  67. package/sync.d.mts +71 -197
  68. package/sync.d.ts +71 -197
  69. package/sync.js +465 -284
  70. package/sync.mjs +471 -290
  71. package/types/babel.d.ts +12 -1
  72. package/.DS_Store +0 -0
  73. /package/config/{enable_GetSet.d.mts → enable$GetSet.d.mts} +0 -0
  74. /package/config/{enable_GetSet.d.ts → enable$GetSet.d.ts} +0 -0
@@ -1,16 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var ksuid = require('ksuid');
4
3
  var state = require('@legendapp/state');
5
4
  var sync = require('@legendapp/state/sync');
6
5
  var crud = require('@legendapp/state/sync-plugins/crud');
6
+ var ksuid = require('ksuid');
7
7
 
8
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
9
 
10
10
  var ksuid__default = /*#__PURE__*/_interopDefault(ksuid);
11
11
 
12
12
  // src/sync-plugins/keel.ts
13
- var { clone } = state.internal;
14
13
  var KeelKeys = ["createdAt", "updatedAt"];
15
14
  function generateKeelId() {
16
15
  return ksuid__default.default.randomSync().string;
@@ -20,6 +19,9 @@ var modifiedClients = /* @__PURE__ */ new WeakSet();
20
19
  var isEnabled$ = state.observable(true);
21
20
  async function ensureAuthToken() {
22
21
  await state.when(isEnabled$.get());
22
+ if (keelConfig.refreshAuth) {
23
+ await keelConfig.refreshAuth();
24
+ }
23
25
  let isAuthed = await keelConfig.client.auth.isAuthenticated();
24
26
  if (!isAuthed) {
25
27
  isAuthed = await keelConfig.client.auth.refresh();
@@ -33,17 +35,20 @@ async function handleApiError(error, retry) {
33
35
  }
34
36
  }
35
37
  function convertObjectToCreate(item) {
36
- const cloned = clone(item);
37
- Object.keys(cloned).forEach((key) => {
38
+ const cloned = {};
39
+ Object.keys(item).forEach((key) => {
38
40
  if (key.endsWith("Id")) {
39
- if (cloned[key]) {
40
- cloned[key.slice(0, -2)] = { id: cloned[key] };
41
+ if (item[key]) {
42
+ cloned[key.slice(0, -2)] = { id: item[key] };
43
+ }
44
+ } else if (key !== "createdAt" && key !== "updatedAt") {
45
+ if (item[key] === void 0) {
46
+ cloned[key] = null;
47
+ } else {
48
+ cloned[key] = item[key];
41
49
  }
42
- delete cloned[key];
43
50
  }
44
51
  });
45
- delete cloned.createdAt;
46
- delete cloned.updatedAt;
47
52
  return cloned;
48
53
  }
49
54
  function getSyncedKeelConfiguration() {
@@ -65,9 +70,9 @@ function configureSyncedKeel(config) {
65
70
  const oldFn = queries[key];
66
71
  queries[key] = (i) => {
67
72
  const realtimeKey = [key, ...Object.values(i.where || {})].filter((value) => value && typeof value !== "object").join("/");
68
- const subscribe = ({ refresh }) => {
73
+ const subscribe = (params) => {
69
74
  if (realtimeKey) {
70
- return realtimePlugin.subscribe(realtimeKey, refresh);
75
+ return realtimePlugin.subscribe(realtimeKey, params);
71
76
  }
72
77
  };
73
78
  return oldFn(i).then((ret) => {
@@ -128,7 +133,9 @@ function syncedKeel(props) {
128
133
  first,
129
134
  where: whereParam,
130
135
  waitFor,
136
+ waitForSet,
131
137
  fieldDeleted,
138
+ mode,
132
139
  ...rest
133
140
  } = props;
134
141
  const { changesSince } = props;
@@ -137,8 +144,15 @@ function syncedKeel(props) {
137
144
  const subscribeFnKey$ = state.observable("");
138
145
  const fieldCreatedAt = "createdAt";
139
146
  const fieldUpdatedAt = "updatedAt";
147
+ const setupSubscribe = (doSubscribe, subscribeKey, lastSync) => {
148
+ subscribeFn = doSubscribe;
149
+ subscribeFnKey$.set(subscribeKey);
150
+ if (realtimePlugin && lastSync) {
151
+ realtimePlugin.setLatestChange(subscribeKey, new Date(lastSync));
152
+ }
153
+ };
140
154
  const list = listParam ? async (listParams) => {
141
- const { lastSync, refresh } = listParams;
155
+ const { lastSync } = listParams;
142
156
  const queryBySync = !!lastSync && changesSince === "last-sync";
143
157
  const where = Object.assign(
144
158
  queryBySync ? { updatedAt: { after: new Date(lastSync + 1) } } : {},
@@ -147,8 +161,7 @@ function syncedKeel(props) {
147
161
  const params = { where, first };
148
162
  const { results, subscribe: subscribe2, subscribeKey } = await getAllPages(listParam, params);
149
163
  if (subscribe2) {
150
- subscribeFn = () => subscribe2({ refresh });
151
- subscribeFnKey$.set(subscribeKey);
164
+ setupSubscribe(() => subscribe2(listParams), subscribeKey, lastSync);
152
165
  }
153
166
  return results;
154
167
  } : void 0;
@@ -156,8 +169,7 @@ function syncedKeel(props) {
156
169
  const { refresh } = getParams;
157
170
  const { data, error, subscribe: subscribe2, subscribeKey } = await getParam({ refresh });
158
171
  if (subscribe2) {
159
- subscribeFn = () => subscribe2({ refresh });
160
- subscribeFnKey$.set(subscribeKey);
172
+ setupSubscribe(() => subscribe2(getParams), subscribeKey);
161
173
  }
162
174
  if (error) {
163
175
  throw new Error(error.message);
@@ -176,32 +188,40 @@ function syncedKeel(props) {
176
188
  }
177
189
  }
178
190
  };
179
- const handleSetError = async (error, params, isCreate) => {
191
+ const handleSetError = async (error, params, input, fn, from) => {
180
192
  var _a, _b, _c;
181
- const { retryNum, cancelRetry, update: update2 } = params;
182
- 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 { retryNum, update: update2 } = params;
194
+ 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"))) {
183
195
  if (__DEV__) {
184
196
  console.log("Creating duplicate data already saved, just ignore.");
185
197
  }
198
+ params.cancelRetry = true;
186
199
  update2({
187
200
  value: {},
188
201
  mode: "assign"
189
202
  });
203
+ } else if (from === "delete") {
204
+ if (error.message === "record not found") {
205
+ if (__DEV__) {
206
+ console.log("Deleting non-existing data, just ignore.");
207
+ }
208
+ params.cancelRetry = true;
209
+ }
190
210
  } else if (error.type === "bad_request") {
191
- (_c = keelConfig.onError) == null ? void 0 : _c.call(keelConfig, error);
211
+ (_c = keelConfig.onError) == null ? void 0 : _c.call(keelConfig, { error, params, input, type: from, action: fn.name || fn.toString() });
192
212
  if (retryNum > 4) {
193
- cancelRetry();
213
+ params.cancelRetry = true;
194
214
  }
195
- throw new Error(error.message);
215
+ throw new Error(error.message, { cause: { input } });
196
216
  } else {
197
217
  await handleApiError(error);
198
- throw new Error(error.message);
218
+ throw new Error(error.message, { cause: { input } });
199
219
  }
200
220
  };
201
221
  const create = createParam ? async (input, params) => {
202
222
  const { data, error } = await createParam(convertObjectToCreate(input));
203
223
  if (error) {
204
- handleSetError(error, params, true);
224
+ await handleSetError(error, params, input, createParam, "create");
205
225
  }
206
226
  return data;
207
227
  } : void 0;
@@ -209,20 +229,18 @@ function syncedKeel(props) {
209
229
  const id = input.id;
210
230
  const values = convertObjectToCreate(input);
211
231
  delete values.id;
212
- delete values.createdAt;
213
- delete values.updatedAt;
214
232
  if (!state.isEmpty(values)) {
215
233
  const { data, error } = await updateParam({ where: { id }, values });
216
234
  if (error) {
217
- handleSetError(error, params, false);
235
+ await handleSetError(error, params, input, updateParam, "update");
218
236
  }
219
237
  return data;
220
238
  }
221
239
  } : void 0;
222
- const deleteFn = deleteParam ? async ({ id }, params) => {
223
- const { data, error } = await deleteParam({ id });
240
+ const deleteFn = deleteParam ? async (value, params) => {
241
+ const { data, error } = await deleteParam({ id: value.id });
224
242
  if (error) {
225
- handleSetError(error, params, false);
243
+ await handleSetError(error, params, value, deleteParam, "delete");
226
244
  }
227
245
  return data;
228
246
  } : void 0;
@@ -238,16 +256,17 @@ function syncedKeel(props) {
238
256
  return crud.syncedCrud({
239
257
  ...rest,
240
258
  as: asType,
259
+ mode: mode || "merge",
241
260
  list,
242
261
  create,
243
262
  update,
244
263
  delete: deleteFn,
245
264
  waitFor: () => isEnabled$.get() && (waitFor ? state.computeSelector(waitFor) : true),
265
+ waitForSet: (params) => isEnabled$.get() && (waitForSet ? state.isFunction(waitForSet) ? waitForSet(params) : waitForSet : true),
246
266
  onSaved,
247
- onSavedUpdate: "createdUpdatedAt",
248
267
  fieldCreatedAt,
249
268
  fieldUpdatedAt,
250
- fieldDeleted: fieldDeleted || "deleted",
269
+ fieldDeleted,
251
270
  changesSince,
252
271
  updatePartial: true,
253
272
  subscribe,
@@ -1,10 +1,9 @@
1
- import ksuid from 'ksuid';
2
- import { observable, computeSelector, isFunction, isEmpty, when, internal } from '@legendapp/state';
1
+ import { observable, computeSelector, isFunction, isEmpty, when } from '@legendapp/state';
3
2
  import { removeNullUndefined } from '@legendapp/state/sync';
4
3
  import { syncedCrud } from '@legendapp/state/sync-plugins/crud';
4
+ import ksuid from 'ksuid';
5
5
 
6
6
  // src/sync-plugins/keel.ts
7
- var { clone } = internal;
8
7
  var KeelKeys = ["createdAt", "updatedAt"];
9
8
  function generateKeelId() {
10
9
  return ksuid.randomSync().string;
@@ -14,6 +13,9 @@ var modifiedClients = /* @__PURE__ */ new WeakSet();
14
13
  var isEnabled$ = observable(true);
15
14
  async function ensureAuthToken() {
16
15
  await when(isEnabled$.get());
16
+ if (keelConfig.refreshAuth) {
17
+ await keelConfig.refreshAuth();
18
+ }
17
19
  let isAuthed = await keelConfig.client.auth.isAuthenticated();
18
20
  if (!isAuthed) {
19
21
  isAuthed = await keelConfig.client.auth.refresh();
@@ -27,17 +29,20 @@ async function handleApiError(error, retry) {
27
29
  }
28
30
  }
29
31
  function convertObjectToCreate(item) {
30
- const cloned = clone(item);
31
- Object.keys(cloned).forEach((key) => {
32
+ const cloned = {};
33
+ Object.keys(item).forEach((key) => {
32
34
  if (key.endsWith("Id")) {
33
- if (cloned[key]) {
34
- cloned[key.slice(0, -2)] = { id: cloned[key] };
35
+ if (item[key]) {
36
+ cloned[key.slice(0, -2)] = { id: item[key] };
37
+ }
38
+ } else if (key !== "createdAt" && key !== "updatedAt") {
39
+ if (item[key] === void 0) {
40
+ cloned[key] = null;
41
+ } else {
42
+ cloned[key] = item[key];
35
43
  }
36
- delete cloned[key];
37
44
  }
38
45
  });
39
- delete cloned.createdAt;
40
- delete cloned.updatedAt;
41
46
  return cloned;
42
47
  }
43
48
  function getSyncedKeelConfiguration() {
@@ -59,9 +64,9 @@ function configureSyncedKeel(config) {
59
64
  const oldFn = queries[key];
60
65
  queries[key] = (i) => {
61
66
  const realtimeKey = [key, ...Object.values(i.where || {})].filter((value) => value && typeof value !== "object").join("/");
62
- const subscribe = ({ refresh }) => {
67
+ const subscribe = (params) => {
63
68
  if (realtimeKey) {
64
- return realtimePlugin.subscribe(realtimeKey, refresh);
69
+ return realtimePlugin.subscribe(realtimeKey, params);
65
70
  }
66
71
  };
67
72
  return oldFn(i).then((ret) => {
@@ -122,7 +127,9 @@ function syncedKeel(props) {
122
127
  first,
123
128
  where: whereParam,
124
129
  waitFor,
130
+ waitForSet,
125
131
  fieldDeleted,
132
+ mode,
126
133
  ...rest
127
134
  } = props;
128
135
  const { changesSince } = props;
@@ -131,8 +138,15 @@ function syncedKeel(props) {
131
138
  const subscribeFnKey$ = observable("");
132
139
  const fieldCreatedAt = "createdAt";
133
140
  const fieldUpdatedAt = "updatedAt";
141
+ const setupSubscribe = (doSubscribe, subscribeKey, lastSync) => {
142
+ subscribeFn = doSubscribe;
143
+ subscribeFnKey$.set(subscribeKey);
144
+ if (realtimePlugin && lastSync) {
145
+ realtimePlugin.setLatestChange(subscribeKey, new Date(lastSync));
146
+ }
147
+ };
134
148
  const list = listParam ? async (listParams) => {
135
- const { lastSync, refresh } = listParams;
149
+ const { lastSync } = listParams;
136
150
  const queryBySync = !!lastSync && changesSince === "last-sync";
137
151
  const where = Object.assign(
138
152
  queryBySync ? { updatedAt: { after: new Date(lastSync + 1) } } : {},
@@ -141,8 +155,7 @@ function syncedKeel(props) {
141
155
  const params = { where, first };
142
156
  const { results, subscribe: subscribe2, subscribeKey } = await getAllPages(listParam, params);
143
157
  if (subscribe2) {
144
- subscribeFn = () => subscribe2({ refresh });
145
- subscribeFnKey$.set(subscribeKey);
158
+ setupSubscribe(() => subscribe2(listParams), subscribeKey, lastSync);
146
159
  }
147
160
  return results;
148
161
  } : void 0;
@@ -150,8 +163,7 @@ function syncedKeel(props) {
150
163
  const { refresh } = getParams;
151
164
  const { data, error, subscribe: subscribe2, subscribeKey } = await getParam({ refresh });
152
165
  if (subscribe2) {
153
- subscribeFn = () => subscribe2({ refresh });
154
- subscribeFnKey$.set(subscribeKey);
166
+ setupSubscribe(() => subscribe2(getParams), subscribeKey);
155
167
  }
156
168
  if (error) {
157
169
  throw new Error(error.message);
@@ -170,32 +182,40 @@ function syncedKeel(props) {
170
182
  }
171
183
  }
172
184
  };
173
- const handleSetError = async (error, params, isCreate) => {
185
+ const handleSetError = async (error, params, input, fn, from) => {
174
186
  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"))) {
187
+ const { retryNum, update: update2 } = params;
188
+ 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
189
  if (__DEV__) {
178
190
  console.log("Creating duplicate data already saved, just ignore.");
179
191
  }
192
+ params.cancelRetry = true;
180
193
  update2({
181
194
  value: {},
182
195
  mode: "assign"
183
196
  });
197
+ } else if (from === "delete") {
198
+ if (error.message === "record not found") {
199
+ if (__DEV__) {
200
+ console.log("Deleting non-existing data, just ignore.");
201
+ }
202
+ params.cancelRetry = true;
203
+ }
184
204
  } else if (error.type === "bad_request") {
185
- (_c = keelConfig.onError) == null ? void 0 : _c.call(keelConfig, error);
205
+ (_c = keelConfig.onError) == null ? void 0 : _c.call(keelConfig, { error, params, input, type: from, action: fn.name || fn.toString() });
186
206
  if (retryNum > 4) {
187
- cancelRetry();
207
+ params.cancelRetry = true;
188
208
  }
189
- throw new Error(error.message);
209
+ throw new Error(error.message, { cause: { input } });
190
210
  } else {
191
211
  await handleApiError(error);
192
- throw new Error(error.message);
212
+ throw new Error(error.message, { cause: { input } });
193
213
  }
194
214
  };
195
215
  const create = createParam ? async (input, params) => {
196
216
  const { data, error } = await createParam(convertObjectToCreate(input));
197
217
  if (error) {
198
- handleSetError(error, params, true);
218
+ await handleSetError(error, params, input, createParam, "create");
199
219
  }
200
220
  return data;
201
221
  } : void 0;
@@ -203,20 +223,18 @@ function syncedKeel(props) {
203
223
  const id = input.id;
204
224
  const values = convertObjectToCreate(input);
205
225
  delete values.id;
206
- delete values.createdAt;
207
- delete values.updatedAt;
208
226
  if (!isEmpty(values)) {
209
227
  const { data, error } = await updateParam({ where: { id }, values });
210
228
  if (error) {
211
- handleSetError(error, params, false);
229
+ await handleSetError(error, params, input, updateParam, "update");
212
230
  }
213
231
  return data;
214
232
  }
215
233
  } : void 0;
216
- const deleteFn = deleteParam ? async ({ id }, params) => {
217
- const { data, error } = await deleteParam({ id });
234
+ const deleteFn = deleteParam ? async (value, params) => {
235
+ const { data, error } = await deleteParam({ id: value.id });
218
236
  if (error) {
219
- handleSetError(error, params, false);
237
+ await handleSetError(error, params, value, deleteParam, "delete");
220
238
  }
221
239
  return data;
222
240
  } : void 0;
@@ -232,16 +250,17 @@ function syncedKeel(props) {
232
250
  return syncedCrud({
233
251
  ...rest,
234
252
  as: asType,
253
+ mode: mode || "merge",
235
254
  list,
236
255
  create,
237
256
  update,
238
257
  delete: deleteFn,
239
258
  waitFor: () => isEnabled$.get() && (waitFor ? computeSelector(waitFor) : true),
259
+ waitForSet: (params) => isEnabled$.get() && (waitForSet ? isFunction(waitForSet) ? waitForSet(params) : waitForSet : true),
240
260
  onSaved,
241
- onSavedUpdate: "createdUpdatedAt",
242
261
  fieldCreatedAt,
243
262
  fieldUpdatedAt,
244
- fieldDeleted: fieldDeleted || "deleted",
263
+ fieldDeleted,
245
264
  changesSince,
246
265
  updatePartial: true,
247
266
  subscribe,
@@ -4,10 +4,14 @@ import { SyncedCrudPropsBase, CrudAsOption, SyncedCrudReturnType, SyncedCrudProp
4
4
  import { PostgrestQueryBuilder, PostgrestFilterBuilder } from '@supabase/postgrest-js';
5
5
  import { SupabaseClient } from '@supabase/supabase-js';
6
6
 
7
+ type DatabaseOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer TDB> ? TDB : never;
8
+ type SchemaNameOf<Client extends SupabaseClient> = keyof DatabaseOf<Client>;
9
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
10
+ type IsUnionOfStrings<T> = [T] extends [string] ? ([T] extends [UnionToIntersection<T>] ? false : true) : false;
7
11
  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'];
12
+ type SupabaseTableOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = DatabaseOf<Client>[SchemaName]['Tables'];
13
+ type SupabaseCollectionOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = keyof SupabaseTableOf<Client, IsUnionOfStrings<SchemaName> extends true ? 'public' : SchemaName>;
14
+ type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>> = SupabaseTableOf<Client, SchemaName>[Collection]['Row'];
11
15
  type SyncedSupabaseConfig<TRemote extends {
12
16
  id: string | number;
13
17
  }, TLocal> = Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'create' | 'update' | 'delete'>;
@@ -20,11 +24,12 @@ interface SyncedSupabaseConfiguration extends Omit<SyncedSupabaseConfig<{
20
24
  enabled?: Observable<boolean>;
21
25
  as?: Exclude<CrudAsOption, 'value'>;
22
26
  }
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> {
27
+ interface SyncedSupabaseProps<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>, TOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection, SchemaName> = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote> extends SyncedSupabaseConfig<TRemote, TLocal>, SyncedCrudPropsMany<TRemote, TRemote, TOption> {
24
28
  supabase: Client;
25
29
  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, []>;
30
+ schema?: SchemaName;
31
+ select?: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
32
+ filter?: (select: PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>, params: SyncedGetParams<TRemote>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
28
33
  actions?: ('create' | 'read' | 'update' | 'delete')[];
29
34
  realtime?: boolean | {
30
35
  schema?: string;
@@ -34,6 +39,6 @@ interface SyncedSupabaseProps<Client extends SupabaseClient, Collection extends
34
39
  }
35
40
  declare function getSyncedSupabaseConfiguration(): SyncedSupabaseConfiguration;
36
41
  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>;
42
+ declare function syncedSupabase<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName> & string, SchemaName extends SchemaNameOf<Client>, 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
43
 
39
44
  export { type SupabaseCollectionOf, type SupabaseRowOf, type SupabaseSchemaOf, type SupabaseTableOf, type SyncedSupabaseConfig, type SyncedSupabaseConfiguration, configureSyncedSupabase, getSyncedSupabaseConfiguration, syncedSupabase };
@@ -4,10 +4,14 @@ import { SyncedCrudPropsBase, CrudAsOption, SyncedCrudReturnType, SyncedCrudProp
4
4
  import { PostgrestQueryBuilder, PostgrestFilterBuilder } from '@supabase/postgrest-js';
5
5
  import { SupabaseClient } from '@supabase/supabase-js';
6
6
 
7
+ type DatabaseOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer TDB> ? TDB : never;
8
+ type SchemaNameOf<Client extends SupabaseClient> = keyof DatabaseOf<Client>;
9
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
10
+ type IsUnionOfStrings<T> = [T] extends [string] ? ([T] extends [UnionToIntersection<T>] ? false : true) : false;
7
11
  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'];
12
+ type SupabaseTableOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = DatabaseOf<Client>[SchemaName]['Tables'];
13
+ type SupabaseCollectionOf<Client extends SupabaseClient, SchemaName extends SchemaNameOf<Client>> = keyof SupabaseTableOf<Client, IsUnionOfStrings<SchemaName> extends true ? 'public' : SchemaName>;
14
+ type SupabaseRowOf<Client extends SupabaseClient, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>> = SupabaseTableOf<Client, SchemaName>[Collection]['Row'];
11
15
  type SyncedSupabaseConfig<TRemote extends {
12
16
  id: string | number;
13
17
  }, TLocal> = Omit<SyncedCrudPropsBase<TRemote, TLocal>, 'create' | 'update' | 'delete'>;
@@ -20,11 +24,12 @@ interface SyncedSupabaseConfiguration extends Omit<SyncedSupabaseConfig<{
20
24
  enabled?: Observable<boolean>;
21
25
  as?: Exclude<CrudAsOption, 'value'>;
22
26
  }
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> {
27
+ interface SyncedSupabaseProps<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName>, SchemaName extends SchemaNameOf<Client>, TOption extends CrudAsOption = 'object', TRemote extends SupabaseRowOf<Client, Collection, SchemaName> = SupabaseRowOf<Client, Collection, SchemaName>, TLocal = TRemote> extends SyncedSupabaseConfig<TRemote, TLocal>, SyncedCrudPropsMany<TRemote, TRemote, TOption> {
24
28
  supabase: Client;
25
29
  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, []>;
30
+ schema?: SchemaName;
31
+ select?: (query: PostgrestQueryBuilder<SupabaseSchemaOf<Client>, SupabaseTableOf<Client, SchemaName>[Collection], Collection>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
32
+ filter?: (select: PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>, params: SyncedGetParams<TRemote>) => PostgrestFilterBuilder<SupabaseSchemaOf<Client>, TRemote, TRemote[], Collection, []>;
28
33
  actions?: ('create' | 'read' | 'update' | 'delete')[];
29
34
  realtime?: boolean | {
30
35
  schema?: string;
@@ -34,6 +39,6 @@ interface SyncedSupabaseProps<Client extends SupabaseClient, Collection extends
34
39
  }
35
40
  declare function getSyncedSupabaseConfiguration(): SyncedSupabaseConfiguration;
36
41
  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>;
42
+ declare function syncedSupabase<Client extends SupabaseClient<any, any>, Collection extends SupabaseCollectionOf<Client, SchemaName> & string, SchemaName extends SchemaNameOf<Client>, 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
43
 
39
44
  export { type SupabaseCollectionOf, type SupabaseRowOf, type SupabaseSchemaOf, type SupabaseTableOf, type SyncedSupabaseConfig, type SyncedSupabaseConfiguration, configureSyncedSupabase, getSyncedSupabaseConfiguration, syncedSupabase };
@@ -24,6 +24,7 @@ function syncedSupabase(props) {
24
24
  supabase: client,
25
25
  collection,
26
26
  select: selectFn,
27
+ schema,
27
28
  filter,
28
29
  actions,
29
30
  fieldCreatedAt: fieldCreatedAtParam,
@@ -36,6 +37,7 @@ function syncedSupabase(props) {
36
37
  waitFor,
37
38
  waitForSet,
38
39
  generateId,
40
+ mode,
39
41
  ...rest
40
42
  } = props;
41
43
  const fieldCreatedAt = fieldCreatedAtParam || (changesSince === "last-sync" ? "created_at" : void 0);
@@ -43,7 +45,8 @@ function syncedSupabase(props) {
43
45
  const fieldDeleted = fieldDeletedParam || (changesSince === "last-sync" ? "deleted" : void 0);
44
46
  const list = !actions || actions.includes("read") ? async (params) => {
45
47
  const { lastSync } = params;
46
- const from = client.from(collection);
48
+ const clientSchema = schema ? client.schema(schema) : client;
49
+ const from = clientSchema.from(collection);
47
50
  let select = selectFn ? selectFn(from) : from.select();
48
51
  if (changesSince === "last-sync" && lastSync) {
49
52
  const date = new Date(lastSync).toISOString();
@@ -58,8 +61,8 @@ function syncedSupabase(props) {
58
61
  }
59
62
  return data || [];
60
63
  } : void 0;
61
- const upsert = async (input) => {
62
- const res = await client.from(collection).upsert(input).select();
64
+ const create = !actions || actions.includes("create") ? async (input) => {
65
+ const res = await client.from(collection).insert(input).select();
63
66
  const { data, error } = res;
64
67
  if (data) {
65
68
  const created = data[0];
@@ -67,9 +70,17 @@ function syncedSupabase(props) {
67
70
  } else {
68
71
  throw new Error(error == null ? void 0 : error.message);
69
72
  }
70
- };
71
- const create = !actions || actions.includes("create") ? upsert : void 0;
72
- const update = !actions || actions.includes("update") ? upsert : void 0;
73
+ } : void 0;
74
+ const update = !actions || actions.includes("update") ? async (input) => {
75
+ const res = await client.from(collection).update(input).eq("id", input.id).select();
76
+ const { data, error } = res;
77
+ if (data) {
78
+ const created = data[0];
79
+ return created;
80
+ } else {
81
+ throw new Error(error == null ? void 0 : error.message);
82
+ }
83
+ } : void 0;
73
84
  const deleteFn = !fieldDeleted && (!actions || actions.includes("delete")) ? async (input) => {
74
85
  const id = input.id;
75
86
  const res = await client.from(collection).delete().eq("id", id).select();
@@ -82,13 +93,13 @@ function syncedSupabase(props) {
82
93
  }
83
94
  } : void 0;
84
95
  const subscribe = realtime ? ({ node, value$, update: update2 }) => {
85
- const { filter: filter2, schema } = state.isObject(realtime) ? realtime : {};
96
+ const { filter: filter2, schema: schema2 } = state.isObject(realtime) ? realtime : {};
86
97
  const channel = client.channel(`LS_${node.key || ""}${channelNum++}`).on(
87
98
  "postgres_changes",
88
99
  {
89
100
  event: "*",
90
101
  table: collection,
91
- schema: schema || "public",
102
+ schema: schema2 || "public",
92
103
  filter: filter2 || void 0
93
104
  },
94
105
  (payload) => {
@@ -101,15 +112,15 @@ function syncedSupabase(props) {
101
112
  const valueDate = +new Date(valueDateStr);
102
113
  if (valueDateStr && (!curDateStr || valueDate > +new Date(curDateStr))) {
103
114
  update2({
104
- value: { [value.id]: value },
115
+ value: [value],
105
116
  lastSync: valueDate,
106
117
  mode: "merge"
107
118
  });
108
119
  }
109
120
  } else if (eventType === "DELETE") {
110
- const { id } = old;
121
+ old[state.symbolDelete] = true;
111
122
  update2({
112
- value: { [id]: state.symbolDelete }
123
+ value: [old]
113
124
  });
114
125
  }
115
126
  }
@@ -123,6 +134,7 @@ function syncedSupabase(props) {
123
134
  }
124
135
  return crud.syncedCrud({
125
136
  ...rest,
137
+ mode: mode || "merge",
126
138
  list,
127
139
  create,
128
140
  update,
@@ -132,11 +144,10 @@ function syncedSupabase(props) {
132
144
  fieldUpdatedAt,
133
145
  fieldDeleted,
134
146
  updatePartial: false,
135
- onSavedUpdate: "createdUpdatedAt",
136
147
  transform,
137
148
  generateId,
138
149
  waitFor: () => isEnabled$.get() && (waitFor ? state.computeSelector(waitFor) : true),
139
- waitForSet
150
+ waitForSet: (params) => isEnabled$.get() && (waitForSet ? state.isFunction(waitForSet) ? waitForSet(params) : waitForSet : true)
140
151
  });
141
152
  }
142
153