@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,94 +1,105 @@
1
1
  'use strict';
2
2
 
3
- var ksuid = require('ksuid');
4
3
  var state = require('@legendapp/state');
5
- var sync = require('@legendapp/state/sync');
6
4
  var crud = require('@legendapp/state/sync-plugins/crud');
5
+ var ksuid = require('ksuid');
7
6
 
8
7
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
8
 
10
9
  var ksuid__default = /*#__PURE__*/_interopDefault(ksuid);
11
10
 
12
11
  // src/sync-plugins/keel.ts
13
- var { clone } = state.internal;
14
12
  var KeelKeys = ["createdAt", "updatedAt"];
15
13
  function generateKeelId() {
16
14
  return ksuid__default.default.randomSync().string;
17
15
  }
18
- var keelConfig = {};
19
16
  var modifiedClients = /* @__PURE__ */ new WeakSet();
20
- var isEnabled$ = state.observable(true);
21
- async function ensureAuthToken() {
22
- await state.when(isEnabled$.get());
23
- let isAuthed = await keelConfig.client.auth.isAuthenticated();
17
+ var isAuthed$ = state.observable(false);
18
+ var isAuthing$ = state.observable(false);
19
+ async function ensureAuthToken(props, force) {
20
+ if (!force && isAuthed$.get()) {
21
+ return true;
22
+ }
23
+ const { client, refreshAuth } = props;
24
+ let isAuthed = await client.auth.isAuthenticated().then(({ data }) => data);
24
25
  if (!isAuthed) {
25
- isAuthed = await keelConfig.client.auth.refresh();
26
+ if (!force && isAuthing$.get()) {
27
+ return state.when(
28
+ () => !isAuthing$.get(),
29
+ () => isAuthed$.get()
30
+ );
31
+ }
32
+ isAuthing$.set(true);
33
+ if (refreshAuth) {
34
+ await refreshAuth();
35
+ }
36
+ isAuthed = await client.auth.isAuthenticated().then(({ data }) => data);
37
+ if (!isAuthed) {
38
+ isAuthed = await client.auth.refresh().then(({ data }) => data);
39
+ }
40
+ }
41
+ if (isAuthed) {
42
+ state.batch(() => {
43
+ isAuthed$.set(true);
44
+ isAuthing$.set(false);
45
+ });
46
+ } else {
47
+ setTimeout(() => ensureAuthToken(
48
+ props,
49
+ /*force*/
50
+ true
51
+ ), 1e3);
26
52
  }
27
53
  return isAuthed;
28
54
  }
29
- async function handleApiError(error, retry) {
55
+ async function handleApiError(props, error, retry) {
30
56
  if (error.type === "unauthorized" || error.type === "forbidden") {
31
57
  console.warn("Keel token expired, refreshing...");
32
- await ensureAuthToken();
58
+ isAuthed$.set(false);
59
+ await ensureAuthToken(props);
33
60
  }
34
61
  }
35
62
  function convertObjectToCreate(item) {
36
- const cloned = clone(item);
37
- Object.keys(cloned).forEach((key) => {
63
+ const cloned = {};
64
+ Object.keys(item).forEach((key) => {
38
65
  if (key.endsWith("Id")) {
39
- if (cloned[key]) {
40
- cloned[key.slice(0, -2)] = { id: cloned[key] };
66
+ if (item[key]) {
67
+ cloned[key.slice(0, -2)] = { id: item[key] };
68
+ }
69
+ } else if (key !== "createdAt" && key !== "updatedAt") {
70
+ if (item[key] === void 0) {
71
+ cloned[key] = null;
72
+ } else {
73
+ cloned[key] = item[key];
41
74
  }
42
- delete cloned[key];
43
75
  }
44
76
  });
45
- delete cloned.createdAt;
46
- delete cloned.updatedAt;
47
77
  return cloned;
48
78
  }
49
- function getSyncedKeelConfiguration() {
50
- return keelConfig;
51
- }
52
- function configureSyncedKeel(config) {
53
- const { enabled, realtimePlugin, client, ...rest } = config;
54
- Object.assign(keelConfig, sync.removeNullUndefined(rest));
55
- if (enabled !== void 0) {
56
- isEnabled$.set(enabled);
57
- }
58
- if (realtimePlugin) {
59
- keelConfig.realtimePlugin = realtimePlugin;
60
- if (client && !modifiedClients.has(client)) {
61
- modifiedClients.add(client);
62
- const queries = client.api.queries;
63
- Object.keys(queries).forEach((key) => {
64
- if (key.startsWith("list")) {
65
- const oldFn = queries[key];
66
- queries[key] = (i) => {
67
- const realtimeKey = [key, ...Object.values(i.where || {})].filter((value) => value && typeof value !== "object").join("/");
68
- const subscribe = ({ refresh }) => {
69
- if (realtimeKey) {
70
- return realtimePlugin.subscribe(realtimeKey, refresh);
71
- }
72
- };
73
- return oldFn(i).then((ret) => {
74
- if (subscribe) {
75
- ret.subscribe = subscribe;
76
- ret.subscribeKey = realtimeKey;
77
- }
78
- return ret;
79
- });
79
+ var realtimeState = { current: {} };
80
+ function setupRealtime(props) {
81
+ const { client } = props;
82
+ if (client && !modifiedClients.has(client)) {
83
+ modifiedClients.add(client);
84
+ const queries = client.api.queries;
85
+ Object.keys(queries).forEach((key) => {
86
+ if (key.startsWith("list")) {
87
+ const origFn = queries[key];
88
+ queries[key] = (i) => {
89
+ realtimeState.current = {
90
+ lastAction: key,
91
+ lastParams: i
80
92
  };
81
- }
82
- });
83
- }
93
+ return origFn(i);
94
+ };
95
+ }
96
+ });
84
97
  }
85
98
  }
86
99
  var NumPerPage = 200;
87
- async function getAllPages(listFn, params) {
100
+ async function getAllPages(props, listFn, params) {
88
101
  const allData = [];
89
102
  let pageInfo = void 0;
90
- let subscribe_;
91
- let subscribeKey_;
92
103
  const { first: firstParam } = params;
93
104
  do {
94
105
  const first = firstParam ? Math.min(firstParam - allData.length, NumPerPage) : NumPerPage;
@@ -100,13 +111,9 @@ async function getAllPages(listFn, params) {
100
111
  pageInfo = void 0;
101
112
  const ret = await listFn(paramsWithCursor);
102
113
  if (ret) {
103
- const { data, error, subscribe, subscribeKey } = ret;
104
- if (subscribe) {
105
- subscribe_ = subscribe;
106
- subscribeKey_ = subscribeKey;
107
- }
114
+ const { data, error } = ret;
108
115
  if (error) {
109
- await handleApiError(error);
116
+ await handleApiError(props, error);
110
117
  throw new Error(error.message);
111
118
  } else if (data) {
112
119
  pageInfo = data.pageInfo;
@@ -114,21 +121,25 @@ async function getAllPages(listFn, params) {
114
121
  }
115
122
  }
116
123
  } while (pageInfo == null ? void 0 : pageInfo.hasNextPage);
117
- return { results: allData, subscribe: subscribe_, subscribeKey: subscribeKey_ };
124
+ return allData;
118
125
  }
119
126
  function syncedKeel(props) {
120
- const { realtimePlugin } = keelConfig;
121
- props = { ...keelConfig, ...props };
122
127
  const {
123
128
  get: getParam,
124
129
  list: listParam,
125
130
  create: createParam,
126
131
  update: updateParam,
127
132
  delete: deleteParam,
133
+ subscribe: subscribeParam,
128
134
  first,
129
135
  where: whereParam,
130
136
  waitFor,
137
+ waitForSet,
131
138
  fieldDeleted,
139
+ realtime,
140
+ mode,
141
+ onError,
142
+ requireAuth = true,
132
143
  ...rest
133
144
  } = props;
134
145
  const { changesSince } = props;
@@ -137,28 +148,38 @@ function syncedKeel(props) {
137
148
  const subscribeFnKey$ = state.observable("");
138
149
  const fieldCreatedAt = "createdAt";
139
150
  const fieldUpdatedAt = "updatedAt";
151
+ const setupSubscribe = realtime ? async (getParams) => {
152
+ const { lastAction, lastParams } = realtimeState.current;
153
+ const { path, plugin } = realtime;
154
+ if (lastAction && path && plugin) {
155
+ const key = await path(lastAction, lastParams);
156
+ subscribeFn = () => realtime.plugin.subscribe(key, getParams);
157
+ subscribeFnKey$.set(key);
158
+ }
159
+ } : void 0;
140
160
  const list = listParam ? async (listParams) => {
141
- const { lastSync, refresh } = listParams;
161
+ const { lastSync } = listParams;
142
162
  const queryBySync = !!lastSync && changesSince === "last-sync";
143
163
  const where = Object.assign(
144
164
  queryBySync ? { updatedAt: { after: new Date(lastSync + 1) } } : {},
145
165
  state.isFunction(whereParam) ? whereParam() : whereParam
146
166
  );
147
167
  const params = { where, first };
148
- const { results, subscribe: subscribe2, subscribeKey } = await getAllPages(listParam, params);
149
- if (subscribe2) {
150
- subscribeFn = () => subscribe2({ refresh });
151
- subscribeFnKey$.set(subscribeKey);
168
+ realtimeState.current = {};
169
+ const promise = getAllPages(props, listParam, params);
170
+ if (realtime) {
171
+ setupSubscribe(listParams);
152
172
  }
153
- return results;
173
+ return promise;
154
174
  } : void 0;
155
175
  const get = getParam ? async (getParams) => {
156
176
  const { refresh } = getParams;
157
- const { data, error, subscribe: subscribe2, subscribeKey } = await getParam({ refresh });
158
- if (subscribe2) {
159
- subscribeFn = () => subscribe2({ refresh });
160
- subscribeFnKey$.set(subscribeKey);
177
+ realtimeState.current = {};
178
+ const promise = getParam({ refresh });
179
+ if (realtime) {
180
+ setupSubscribe(getParams);
161
181
  }
182
+ const { data, error } = await promise;
162
183
  if (error) {
163
184
  throw new Error(error.message);
164
185
  } else {
@@ -167,41 +188,54 @@ function syncedKeel(props) {
167
188
  } : void 0;
168
189
  const onSaved = ({ saved }) => {
169
190
  if (saved) {
170
- const updatedAt = saved[fieldUpdatedAt];
171
- if (updatedAt && realtimePlugin) {
191
+ if (realtime == null ? void 0 : realtime.plugin) {
172
192
  const subscribeFnKey = subscribeFnKey$.get();
173
193
  if (subscribeFnKey) {
174
- realtimePlugin.setLatestChange(subscribeFnKey, updatedAt);
194
+ realtime == null ? void 0 : realtime.plugin.setSaved(subscribeFnKey);
175
195
  }
176
196
  }
177
197
  }
178
198
  };
179
- const handleSetError = async (error, params, isCreate) => {
180
- 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"))) {
199
+ const handleSetError = async (error, params, input, fn, from) => {
200
+ var _a, _b;
201
+ const { retryNum, update: update2 } = params;
202
+ 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
203
  if (__DEV__) {
184
204
  console.log("Creating duplicate data already saved, just ignore.");
185
205
  }
206
+ params.cancelRetry = true;
186
207
  update2({
187
208
  value: {},
188
209
  mode: "assign"
189
210
  });
211
+ } else if (from === "delete") {
212
+ if (error.message === "record not found") {
213
+ if (__DEV__) {
214
+ console.log("Deleting non-existing data, just ignore.");
215
+ }
216
+ params.cancelRetry = true;
217
+ }
190
218
  } else if (error.type === "bad_request") {
191
- (_c = keelConfig.onError) == null ? void 0 : _c.call(keelConfig, error);
219
+ onError == null ? void 0 : onError(new Error(error.message), params, {
220
+ error,
221
+ params,
222
+ input,
223
+ type: from,
224
+ action: fn.name || fn.toString()
225
+ });
192
226
  if (retryNum > 4) {
193
- cancelRetry();
227
+ params.cancelRetry = true;
194
228
  }
195
- throw new Error(error.message);
229
+ throw new Error(error.message, { cause: { input } });
196
230
  } else {
197
- await handleApiError(error);
198
- throw new Error(error.message);
231
+ await handleApiError(props, error);
232
+ throw new Error(error.message, { cause: { input } });
199
233
  }
200
234
  };
201
235
  const create = createParam ? async (input, params) => {
202
236
  const { data, error } = await createParam(convertObjectToCreate(input));
203
237
  if (error) {
204
- handleSetError(error, params, true);
238
+ await handleSetError(error, params, input, createParam, "create");
205
239
  }
206
240
  return data;
207
241
  } : void 0;
@@ -209,45 +243,58 @@ function syncedKeel(props) {
209
243
  const id = input.id;
210
244
  const values = convertObjectToCreate(input);
211
245
  delete values.id;
212
- delete values.createdAt;
213
- delete values.updatedAt;
214
246
  if (!state.isEmpty(values)) {
215
247
  const { data, error } = await updateParam({ where: { id }, values });
216
248
  if (error) {
217
- handleSetError(error, params, false);
249
+ await handleSetError(error, params, input, updateParam, "update");
218
250
  }
219
251
  return data;
220
252
  }
221
253
  } : void 0;
222
- const deleteFn = deleteParam ? async ({ id }, params) => {
223
- const { data, error } = await deleteParam({ id });
254
+ const deleteFn = deleteParam ? async (value, params) => {
255
+ const { data, error } = await deleteParam({ id: value.id });
224
256
  if (error) {
225
- handleSetError(error, params, false);
257
+ await handleSetError(error, params, value, deleteParam, "delete");
226
258
  }
227
259
  return data;
228
260
  } : void 0;
229
- const subscribe = (params) => {
261
+ if (realtime) {
262
+ setupRealtime(props);
263
+ }
264
+ const subscribe = realtime ? (params) => {
230
265
  let unsubscribe = void 0;
231
266
  state.when(subscribeFnKey$, () => {
232
267
  unsubscribe = subscribeFn(params);
233
268
  });
269
+ const unsubscribeParam = subscribeParam == null ? void 0 : subscribeParam(params);
234
270
  return () => {
235
271
  unsubscribe == null ? void 0 : unsubscribe();
272
+ unsubscribeParam == null ? void 0 : unsubscribeParam();
236
273
  };
237
- };
274
+ } : subscribeParam;
238
275
  return crud.syncedCrud({
239
276
  ...rest,
240
277
  as: asType,
278
+ mode: mode || "merge",
241
279
  list,
242
280
  create,
243
281
  update,
244
282
  delete: deleteFn,
245
- waitFor: () => isEnabled$.get() && (waitFor ? state.computeSelector(waitFor) : true),
283
+ waitFor: () => {
284
+ ensureAuthToken(props);
285
+ return [requireAuth ? isAuthed$ : true, waitFor || true];
286
+ },
287
+ waitForSet: (params) => {
288
+ ensureAuthToken(props);
289
+ return [
290
+ requireAuth ? isAuthed$ : true,
291
+ () => waitForSet ? state.isFunction(waitForSet) ? waitForSet(params) : waitForSet : true
292
+ ];
293
+ },
246
294
  onSaved,
247
- onSavedUpdate: "createdUpdatedAt",
248
295
  fieldCreatedAt,
249
296
  fieldUpdatedAt,
250
- fieldDeleted: fieldDeleted || "deleted",
297
+ fieldDeleted,
251
298
  changesSince,
252
299
  updatePartial: true,
253
300
  subscribe,
@@ -258,7 +305,5 @@ function syncedKeel(props) {
258
305
  }
259
306
 
260
307
  exports.KeelKeys = KeelKeys;
261
- exports.configureSyncedKeel = configureSyncedKeel;
262
308
  exports.generateKeelId = generateKeelId;
263
- exports.getSyncedKeelConfiguration = getSyncedKeelConfiguration;
264
309
  exports.syncedKeel = syncedKeel;