@legendapp/state 2.2.0-next.78 → 2.2.0-next.79

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 (82) hide show
  1. package/index.d.ts +0 -2
  2. package/index.js +10 -0
  3. package/index.js.map +1 -1
  4. package/index.mjs +10 -0
  5. package/index.mjs.map +1 -1
  6. package/package.json +1 -1
  7. package/persist-plugins/async-storage.d.ts +2 -1
  8. package/persist-plugins/fetch.d.ts +1 -1
  9. package/persist-plugins/fetch.js.map +1 -1
  10. package/persist-plugins/fetch.mjs.map +1 -1
  11. package/persist-plugins/firebase.d.ts +1 -1
  12. package/persist-plugins/firebase.js.map +1 -1
  13. package/persist-plugins/firebase.mjs.map +1 -1
  14. package/persist-plugins/indexeddb.d.ts +2 -1
  15. package/persist-plugins/indexeddb.js.map +1 -1
  16. package/persist-plugins/indexeddb.mjs.map +1 -1
  17. package/persist-plugins/local-storage.d.ts +2 -1
  18. package/persist-plugins/local-storage.js.map +1 -1
  19. package/persist-plugins/local-storage.mjs.map +1 -1
  20. package/persist-plugins/mmkv.d.ts +2 -1
  21. package/persist-plugins/mmkv.js.map +1 -1
  22. package/persist-plugins/mmkv.mjs.map +1 -1
  23. package/persist-plugins/query.d.ts +1 -1
  24. package/persist-plugins/query.js.map +1 -1
  25. package/persist-plugins/query.mjs.map +1 -1
  26. package/persist.d.ts +1 -1
  27. package/persist.js +4 -6
  28. package/persist.js.map +1 -1
  29. package/persist.mjs +4 -6
  30. package/persist.mjs.map +1 -1
  31. package/react-hooks/usePersistedObservable.d.ts +2 -1
  32. package/react-hooks/usePersistedObservable.js.map +1 -1
  33. package/react-hooks/usePersistedObservable.mjs.map +1 -1
  34. package/src/ObservableObject.ts +12 -0
  35. package/src/globals.ts +1 -1
  36. package/src/observable.ts +1 -1
  37. package/src/observableInterfaces.ts +2 -20
  38. package/src/persist/configureObservablePersistence.ts +1 -1
  39. package/src/persist/fieldTransformer.ts +1 -1
  40. package/src/persist/observablePersistRemoteFunctionsAdapter.ts +2 -2
  41. package/src/persist/persistObservable.ts +12 -10
  42. package/src/persist-plugins/async-storage.ts +2 -2
  43. package/src/persist-plugins/fetch.ts +2 -1
  44. package/src/persist-plugins/firebase.ts +8 -6
  45. package/src/persist-plugins/indexeddb.ts +2 -3
  46. package/src/persist-plugins/local-storage.ts +2 -1
  47. package/src/persist-plugins/mmkv.ts +2 -1
  48. package/src/persist-plugins/query.ts +2 -6
  49. package/src/react-hooks/usePersistedObservable.ts +2 -1
  50. package/src/retry.ts +2 -1
  51. package/src/sync/activateSyncedNode.ts +3 -5
  52. package/src/sync/configureObservableSync.ts +1 -1
  53. package/src/{persistTypes.ts → sync/persistTypes.ts} +4 -4
  54. package/src/sync/syncObservable.ts +20 -20
  55. package/src/sync/syncObservableAdapter.ts +2 -1
  56. package/src/{syncTypes.ts → sync/syncTypes.ts} +19 -5
  57. package/src/sync/synced.ts +1 -1
  58. package/src/sync-plugins/crud.ts +28 -11
  59. package/src/sync-plugins/fetch.ts +2 -2
  60. package/src/sync-plugins/keel.ts +52 -47
  61. package/src/sync-plugins/supabase.ts +47 -31
  62. package/sync-plugins/crud.d.ts +2 -1
  63. package/sync-plugins/crud.js +19 -4
  64. package/sync-plugins/crud.js.map +1 -1
  65. package/sync-plugins/crud.mjs +19 -4
  66. package/sync-plugins/crud.mjs.map +1 -1
  67. package/sync-plugins/fetch.d.ts +2 -1
  68. package/sync-plugins/keel.d.ts +5 -5
  69. package/sync-plugins/keel.js +29 -30
  70. package/sync-plugins/keel.js.map +1 -1
  71. package/sync-plugins/keel.mjs +29 -30
  72. package/sync-plugins/keel.mjs.map +1 -1
  73. package/sync-plugins/supabase.d.ts +14 -11
  74. package/sync-plugins/supabase.js +7 -3
  75. package/sync-plugins/supabase.js.map +1 -1
  76. package/sync-plugins/supabase.mjs +7 -3
  77. package/sync-plugins/supabase.mjs.map +1 -1
  78. package/sync.d.ts +4 -2
  79. package/sync.js +4 -6
  80. package/sync.js.map +1 -1
  81. package/sync.mjs +5 -7
  82. package/sync.mjs.map +1 -1
@@ -1,14 +1,12 @@
1
+ import type { NodeValue, Observable, UpdateFn } from '@legendapp/state';
1
2
  import type {
2
- NodeValue,
3
- Observable,
4
- ObservablePersistState,
5
3
  ObservableSyncFunctions,
6
4
  ObservableSyncGetParams,
7
5
  ObservableSyncSetParams,
8
6
  SyncedGetParams,
9
7
  SyncedSetParams,
10
- UpdateFn,
11
- } from '@legendapp/state';
8
+ } from './syncTypes';
9
+ import type { ObservablePersistState } from './persistTypes';
12
10
  import { internal, isFunction, isPromise, mergeIntoObservable, whenReady } from '@legendapp/state';
13
11
  import { syncObservable } from './syncObservable';
14
12
  const { getProxy, globalState, runWithRetry, symbolLinked, setNodeValue, getNodeValue } = internal;
@@ -1,4 +1,4 @@
1
- import type { SyncedOptionsGlobal } from '@legendapp/state';
1
+ import type { SyncedOptionsGlobal } from '@legendapp/state/sync';
2
2
 
3
3
  export const observableSyncConfiguration: SyncedOptionsGlobal = {};
4
4
 
@@ -6,18 +6,18 @@ import type { AsyncStorageStatic } from '@react-native-async-storage/async-stora
6
6
  // @ts-ignore
7
7
  import type { DatabaseReference, Query } from 'firebase/database';
8
8
 
9
- import type { GetMode, PersistMetadata } from './syncTypes';
10
9
  import type {
11
10
  ArrayValue,
12
11
  Change,
13
12
  ClassConstructor,
13
+ GetMode,
14
14
  LinkedOptions,
15
15
  RecordValue,
16
- RetryOptions,
17
16
  Selector,
18
17
  TypeAtPath,
19
- } from './observableInterfaces';
20
- import type { Observable, ObservableParam, ObservableState } from './observableTypes';
18
+ } from '../observableInterfaces';
19
+ import type { Observable, ObservableParam, ObservableState } from '../observableTypes';
20
+ import type { PersistMetadata, RetryOptions } from './syncTypes';
21
21
 
22
22
  export interface PersistTransform<TOrig = any, TSaved = TOrig> {
23
23
  load?: (value: TSaved) => TOrig | Promise<TOrig>;
@@ -5,17 +5,7 @@ import type {
5
5
  NodeValue,
6
6
  Observable,
7
7
  ObservableObject,
8
- ObservableOnChangeParams,
9
8
  ObservableParam,
10
- ObservablePersistPlugin,
11
- ObservableSyncClass,
12
- ObservableSyncState,
13
- PersistMetadata,
14
- PersistOptions,
15
- SyncTransform,
16
- SyncTransformMethod,
17
- Synced,
18
- SyncedOptions,
19
9
  TypeAtPath,
20
10
  UpdateFnParams,
21
11
  } from '@legendapp/state';
@@ -37,10 +27,22 @@ import {
37
27
  when,
38
28
  } from '@legendapp/state';
39
29
  import { observableSyncConfiguration } from './configureObservableSync';
30
+ import type { ObservableOnChangeParams } from './persistTypes';
40
31
  import { removeNullUndefined } from './syncHelpers';
41
32
  import { syncObservableAdapter } from './syncObservableAdapter';
33
+ import type {
34
+ ObservablePersistPlugin,
35
+ ObservableSyncClass,
36
+ ObservableSyncState,
37
+ PersistMetadata,
38
+ PersistOptions,
39
+ SyncTransform,
40
+ SyncTransformMethod,
41
+ Synced,
42
+ SyncedOptions,
43
+ } from './syncTypes';
42
44
 
43
- const { createPreviousHandler, getValueAtPath, globalState, symbolLinked, getNode, getNodeValue } = internal;
45
+ const { createPreviousHandler, clone, getValueAtPath, globalState, symbolLinked, getNode, getNodeValue } = internal;
44
46
 
45
47
  export const mapSyncPlugins: WeakMap<
46
48
  ClassConstructor<ObservablePersistPlugin | ObservableSyncClass>,
@@ -832,15 +834,13 @@ export function syncObservable<T>(
832
834
  const node = getNode(obs$);
833
835
 
834
836
  // Merge remote sync options with global options
835
- if (syncOptions) {
836
- syncOptions = Object.assign(
837
- {
838
- syncMode: 'auto',
839
- } as SyncedOptions,
840
- observableSyncConfiguration,
841
- removeNullUndefined(syncOptions),
842
- );
843
- }
837
+ syncOptions = mergeIntoObservable(
838
+ {
839
+ syncMode: 'auto',
840
+ } as SyncedOptions,
841
+ clone(observableSyncConfiguration),
842
+ removeNullUndefined(syncOptions || {}),
843
+ );
844
844
  const localState: LocalState = {};
845
845
  let sync: () => Promise<void>;
846
846
 
@@ -1,4 +1,5 @@
1
- import { ObservableSyncGetParams, SyncedOptions, isPromise, type ObservableSyncClass } from '@legendapp/state';
1
+ import { isPromise } from '@legendapp/state';
2
+ import { ObservableSyncGetParams, SyncedOptions, type ObservableSyncClass } from '@legendapp/state/sync';
2
3
 
3
4
  export function syncObservableAdapter<T = {}>({ get, set }: SyncedOptions<T>): ObservableSyncClass {
4
5
  const ret: ObservableSyncClass = {};
@@ -7,14 +7,14 @@ import type { AsyncStorageStatic } from '@react-native-async-storage/async-stora
7
7
  import {
8
8
  Change,
9
9
  ClassConstructor,
10
+ GetMode,
10
11
  LinkedOptions,
11
12
  NodeValue,
12
- RetryOptions,
13
13
  SetParams,
14
14
  UpdateFn,
15
15
  UpdateFnParams,
16
- } from './observableInterfaces';
17
- import { Observable, ObservableParam, ObservableState } from './observableTypes';
16
+ } from '../observableInterfaces';
17
+ import { Observable, ObservableParam, ObservableState } from '../observableTypes';
18
18
 
19
19
  export interface PersistOptions<T = any> {
20
20
  name: string;
@@ -54,8 +54,6 @@ export interface SyncedSubscribeParams {
54
54
  refresh: () => void;
55
55
  }
56
56
 
57
- export type GetMode = 'set' | 'assign' | 'merge' | 'append' | 'prepend';
58
-
59
57
  export interface SyncedOptions<T = any> extends Omit<LinkedOptions<T>, 'get' | 'set'> {
60
58
  get?: (params: SyncedGetParams) => Promise<T> | T;
61
59
  set?: (params: SyncedSetParams<T>) => void | Promise<any>;
@@ -172,3 +170,19 @@ export interface ObservableSyncFunctions<T = any> {
172
170
  params: ObservableSyncSetParams<T>,
173
171
  ): void | Promise<void | { changes?: object | undefined; dateModified?: number; lastSync?: number }>;
174
172
  }
173
+
174
+ export interface RetryOptions {
175
+ infinite?: boolean;
176
+ times?: number;
177
+ delay?: number;
178
+ backoff?: 'constant' | 'exponential';
179
+ maxDelay?: number;
180
+ }
181
+
182
+ export interface SubscribeOptions {
183
+ node: NodeValue;
184
+ update: UpdateFn;
185
+ refresh: () => void;
186
+ }
187
+
188
+ export type Synced<T> = T;
@@ -1,4 +1,4 @@
1
- import type { Synced, SyncedOptions } from '@legendapp/state';
1
+ import type { Synced, SyncedOptions } from './syncTypes';
2
2
  import { internal } from '@legendapp/state';
3
3
  import { enableActivateSyncedNode } from './activateSyncedNode';
4
4
 
@@ -1,17 +1,13 @@
1
+ import { internal, isArray, isNullOrUndefined, isNumber, isObject, isString } from '@legendapp/state';
1
2
  import {
3
+ synced,
4
+ diffObjects,
2
5
  SyncTransform,
3
6
  SyncTransformMethod,
4
7
  SyncedGetParams,
5
8
  SyncedOptions,
6
9
  SyncedSetParams,
7
- internal,
8
- isArray,
9
- isNullOrUndefined,
10
- isNumber,
11
- isObject,
12
- isString,
13
- } from '@legendapp/state';
14
- import { synced, diffObjects } from '@legendapp/state/sync';
10
+ } from '@legendapp/state/sync';
15
11
 
16
12
  const { clone } = internal;
17
13
 
@@ -43,6 +39,7 @@ export interface SyncedCrudPropsBase<TRemote extends { id: string | number }, TL
43
39
  fieldCreatedAt?: string;
44
40
  updatePartial?: boolean;
45
41
  changesSince?: 'all' | 'last-sync';
42
+ generateId?: () => string | number;
46
43
  }
47
44
 
48
45
  type InitialValue<T, TAsOption extends CrudAsOption> = TAsOption extends 'Map'
@@ -134,6 +131,13 @@ export function combineTransforms<T, T2>(
134
131
  };
135
132
  }
136
133
 
134
+ function ensureId(obj: { id: string | number }, generateId: () => string | number) {
135
+ if (!obj.id) {
136
+ obj.id = generateId();
137
+ }
138
+ return obj.id;
139
+ }
140
+
137
141
  export function syncedCrud<TRemote extends { id: string | number }, TLocal = TRemote>(
138
142
  props: SyncedCrudPropsBase<TRemote, TLocal> & SyncedCrudPropsSingle<TRemote, TLocal>,
139
143
  ): SyncedCrudReturnType<TLocal, 'first'>;
@@ -165,6 +169,7 @@ export function syncedCrud<
165
169
  onSaved,
166
170
  mode: modeParam,
167
171
  changesSince,
172
+ generateId,
168
173
  ...rest
169
174
  } = props;
170
175
 
@@ -242,9 +247,12 @@ export function syncedCrud<
242
247
  changes.forEach(({ path, prevAtPath, valueAtPath }) => {
243
248
  if (asType === 'first') {
244
249
  if (value) {
245
- const id = value?.id;
250
+ let id = value?.id;
251
+ const isCreate = fieldCreatedAt ? !value[fieldCreatedAt!] : !prevAtPath;
252
+ if (!id && generateId) {
253
+ id = ensureId(value, generateId);
254
+ }
246
255
  if (id) {
247
- const isCreate = fieldCreatedAt ? !value[fieldCreatedAt!] : !prevAtPath;
248
256
  if (isCreate || retryAsCreate) {
249
257
  creates.set(id, value);
250
258
  } else if (path.length === 0) {
@@ -308,6 +316,12 @@ export function syncedCrud<
308
316
  ? !item[fieldUpdatedAt]
309
317
  : isCreateGuess;
310
318
  if (isCreate) {
319
+ if (generateId) {
320
+ ensureId(item, generateId);
321
+ }
322
+ if (!item.id) {
323
+ console.error('[legend-state]: added item without an id');
324
+ }
311
325
  if (createFn) {
312
326
  creates.set(item.id, item);
313
327
  } else {
@@ -362,7 +376,10 @@ export function syncedCrud<
362
376
  }),
363
377
  ...Array.from(updates).map(([itemKey, itemValue]) => {
364
378
  const toSave = updatePartial
365
- ? diffObjects(asType === 'first' ? valuePrevious : valuePrevious[itemKey], itemValue)
379
+ ? Object.assign(
380
+ diffObjects(asType === 'first' ? valuePrevious : valuePrevious[itemKey], itemValue),
381
+ { id: (itemValue as any).id },
382
+ )
366
383
  : itemValue;
367
384
  const changed = transformOut(toSave as TLocal, transform?.save) as TRemote;
368
385
 
@@ -1,5 +1,5 @@
1
- import { Selector, SyncTransform, Synced, SyncedOptions, SyncedSetParams, computeSelector } from '@legendapp/state';
2
- import { synced } from '@legendapp/state/sync';
1
+ import { Selector, computeSelector } from '@legendapp/state';
2
+ import { synced, SyncTransform, Synced, SyncedOptions, SyncedSetParams } from '@legendapp/state/sync';
3
3
 
4
4
  export interface SyncedFetchProps<TRemote, TLocal> extends Omit<SyncedOptions, 'get' | 'set' | 'transform'> {
5
5
  get: Selector<string>;
@@ -1,12 +1,11 @@
1
+ import { computeSelector, observable, when, internal } from '@legendapp/state';
1
2
  import {
2
- SyncedSetParams,
3
- computeSelector,
4
- internal,
5
- observable,
6
- when,
3
+ SyncedOptions,
4
+ removeNullUndefined,
7
5
  type SyncedGetParams,
6
+ type SyncedSetParams,
8
7
  type SyncedSubscribeParams,
9
- } from '@legendapp/state';
8
+ } from '@legendapp/state/sync';
10
9
  import {
11
10
  CrudAsOption,
12
11
  CrudResult,
@@ -54,7 +53,6 @@ interface ListGetParams {
54
53
  refresh?: () => void;
55
54
  after?: string;
56
55
  first?: number;
57
- maxResults?: number;
58
56
  }
59
57
 
60
58
  export interface KeelRealtimePlugin {
@@ -62,7 +60,20 @@ export interface KeelRealtimePlugin {
62
60
  setLatestChange: (realtimeKey: string, time: Date) => void;
63
61
  }
64
62
 
65
- interface SyncedKeelConfiguration {
63
+ export interface SyncedKeelConfiguration
64
+ extends Omit<
65
+ SyncedCrudPropsBase<any>,
66
+ | keyof SyncedOptions
67
+ | 'create'
68
+ | 'update'
69
+ | 'delete'
70
+ | 'onSaved'
71
+ | 'transform'
72
+ | 'updatePartial'
73
+ | 'subscribe'
74
+ | 'fieldCreatedAt'
75
+ | 'fieldUpdatedAt'
76
+ > {
66
77
  client: {
67
78
  auth: { refresh: () => Promise<boolean>; isAuthenticated: () => Promise<boolean> };
68
79
  api: { queries: Record<string, (i: any) => Promise<any>> };
@@ -84,14 +95,14 @@ interface PageInfo {
84
95
  interface SyncedKeelPropsMany<TRemote, TLocal, AOption extends CrudAsOption>
85
96
  extends Omit<SyncedCrudPropsMany<TRemote, TLocal, AOption>, 'list'> {
86
97
  list?: (params: ListGetParams) => Promise<CrudResult<APIResult<{ results: TRemote[]; pageInfo: any }>>>;
87
- maxResults?: number;
98
+ first?: number;
88
99
  get?: never;
89
100
  }
90
101
 
91
102
  interface SyncedKeelPropsSingle<TRemote, TLocal> extends Omit<SyncedCrudPropsSingle<TRemote, TLocal>, 'get'> {
92
103
  get?: (params: GetGetParams) => Promise<APIResult<TRemote>>;
93
104
 
94
- maxResults?: never;
105
+ first?: never;
95
106
  list?: never;
96
107
  as?: never;
97
108
  }
@@ -103,18 +114,15 @@ interface SyncedKeelPropsBase<TRemote extends { id: string }, TLocal = TRemote>
103
114
  delete?: (params: { id: string }) => Promise<APIResult<string>>;
104
115
  }
105
116
 
106
- let _client: SyncedKeelConfiguration['client'];
107
- let _asOption: CrudAsOption;
108
- let _realtimePlugin: KeelRealtimePlugin;
109
- let _onError: (error: APIResult<any>['error']) => void;
117
+ const keelConfig: SyncedKeelConfiguration = {} as SyncedKeelConfiguration;
110
118
  const modifiedClients = new WeakSet<Record<string, any>>();
111
119
  const isEnabled$ = observable(true);
112
120
 
113
121
  async function ensureAuthToken() {
114
122
  await when(isEnabled$.get());
115
- let isAuthed = await _client.auth.isAuthenticated();
123
+ let isAuthed = await keelConfig.client.auth.isAuthenticated();
116
124
  if (!isAuthed) {
117
- isAuthed = await _client.auth.refresh();
125
+ isAuthed = await keelConfig.client.auth.refresh();
118
126
  }
119
127
 
120
128
  return isAuthed;
@@ -144,25 +152,17 @@ function convertObjectToCreate<TRemote, TLocal>(item: TRemote) {
144
152
  return cloned as unknown as TLocal;
145
153
  }
146
154
 
147
- export function configureSyncedKeel({
148
- realtimePlugin,
149
- as: asOption,
150
- client,
151
- enabled,
152
- onError,
153
- }: SyncedKeelConfiguration) {
154
- if (asOption) {
155
- _asOption = asOption;
156
- }
157
- if (client) {
158
- _client = client;
159
- }
155
+ export function configureSyncedKeel(config: SyncedKeelConfiguration) {
156
+ const { enabled, realtimePlugin, ...rest } = config;
157
+ Object.assign(keelConfig, removeNullUndefined(rest));
158
+
160
159
  if (enabled !== undefined) {
161
160
  isEnabled$.set(enabled);
162
161
  }
162
+ const { client } = keelConfig;
163
163
 
164
164
  if (realtimePlugin) {
165
- _realtimePlugin = realtimePlugin;
165
+ keelConfig.realtimePlugin = realtimePlugin;
166
166
  if (client && !modifiedClients.has(client)) {
167
167
  modifiedClients.add(client);
168
168
  const queries = client.api.queries;
@@ -194,10 +194,6 @@ export function configureSyncedKeel({
194
194
  });
195
195
  }
196
196
  }
197
-
198
- if (onError) {
199
- _onError = onError;
200
- }
201
197
  }
202
198
 
203
199
  const NumPerPage = 200;
@@ -214,10 +210,10 @@ async function getAllPages<TRemote>(
214
210
  let pageInfo: PageInfo | undefined = undefined;
215
211
  let subscribe_;
216
212
 
217
- const { maxResults } = params;
213
+ const { first: firstParam } = params;
218
214
 
219
215
  do {
220
- const first = maxResults ? Math.min(maxResults - allData.length, NumPerPage) : NumPerPage;
216
+ const first = firstParam ? Math.min(firstParam - allData.length, NumPerPage) : NumPerPage;
221
217
  if (first < 1) {
222
218
  break;
223
219
  }
@@ -265,19 +261,24 @@ export function syncedKeel<TRemote extends { id: string }, TLocal = TRemote, TOp
265
261
  create: createParam,
266
262
  update: updateParam,
267
263
  delete: deleteParam,
268
- maxResults,
269
- initial,
264
+ first,
270
265
  waitFor,
271
266
  waitForSet,
267
+ generateId: generateIdParam,
272
268
  ...rest
273
269
  } = props;
274
270
 
271
+ const { changesSince } = props;
272
+
275
273
  let asType = props.as as TOption;
276
274
 
277
275
  if (!asType) {
278
- asType = (getParam ? 'first' : _asOption || undefined) as TOption;
276
+ asType = (getParam ? 'first' : keelConfig.as || undefined) as TOption;
279
277
  }
280
278
 
279
+ const generateId = generateIdParam || keelConfig.generateId;
280
+
281
+ const realtimePlugin = keelConfig.realtimePlugin;
281
282
  let realtimeKeyList: string | undefined = undefined;
282
283
  let realtimeKeyGet: string | undefined = undefined;
283
284
 
@@ -287,10 +288,13 @@ export function syncedKeel<TRemote extends { id: string }, TLocal = TRemote, TOp
287
288
  const list = listParam
288
289
  ? async (listParams: SyncedGetParams) => {
289
290
  const { lastSync, refresh } = listParams;
290
- const queryBySync = !!lastSync;
291
+ const queryBySync = !!lastSync && changesSince === 'last-sync';
292
+ // If this is one of the customized functions for use with realtime then we need to pass
293
+ // the refresh function to it
291
294
  const isRawRequest = (listParam || getParam).toString().includes('rawRequest');
295
+ // If querying with lastSync pass it to the "where" parameters
292
296
  const where = queryBySync ? { updatedAt: { after: new Date(+new Date(lastSync) + 1) } } : {};
293
- const params: ListGetParams = isRawRequest ? { where, maxResults } : { where, refresh, maxResults };
297
+ const params: ListGetParams = isRawRequest ? { where, first } : { where, refresh, first };
294
298
 
295
299
  // TODO: Error?
296
300
  const { results, subscribe } = await getAllPages(listParam, params);
@@ -342,12 +346,12 @@ export function syncedKeel<TRemote extends { id: string }, TLocal = TRemote, TOp
342
346
 
343
347
  const updatedAt = data[fieldUpdatedAt as keyof TLocal] as Date;
344
348
 
345
- if (updatedAt && _realtimePlugin) {
349
+ if (updatedAt && realtimePlugin) {
346
350
  if (realtimeKeyGet) {
347
- _realtimePlugin.setLatestChange(realtimeKeyGet, updatedAt);
351
+ realtimePlugin.setLatestChange(realtimeKeyGet, updatedAt);
348
352
  }
349
353
  if (realtimeKeyList) {
350
- _realtimePlugin.setLatestChange(realtimeKeyList, updatedAt);
354
+ realtimePlugin.setLatestChange(realtimeKeyList, updatedAt);
351
355
  }
352
356
  }
353
357
 
@@ -372,7 +376,7 @@ export function syncedKeel<TRemote extends { id: string }, TLocal = TRemote, TOp
372
376
  mode: 'assign',
373
377
  });
374
378
  } else if (error.type === 'bad_request') {
375
- _onError?.(error);
379
+ keelConfig.onError?.(error);
376
380
 
377
381
  if (retryNum > 4) {
378
382
  cancelRetry();
@@ -434,13 +438,14 @@ export function syncedKeel<TRemote extends { id: string }, TLocal = TRemote, TOp
434
438
  create,
435
439
  update,
436
440
  delete: deleteFn,
437
- retry: { infinite: true },
438
441
  waitFor: () => isEnabled$.get() && (waitFor ? computeSelector(waitFor) : true),
439
442
  waitForSet: () => isEnabled$.get() && (waitForSet ? computeSelector(waitForSet) : true),
440
443
  onSaved,
441
444
  fieldCreatedAt,
442
445
  fieldUpdatedAt,
443
- initial: initial as any, // This errors because of the get/list union type
446
+ changesSince,
447
+ updatePartial: true,
448
+ generateId,
444
449
  // @ts-expect-error This errors because of the get/list union type
445
450
  get: get as any,
446
451
  }) as SyncedCrudReturnType<TLocal, TOption>;
@@ -1,15 +1,18 @@
1
1
  import {
2
2
  Observable,
3
- SyncedOptions,
4
- SyncedOptionsGlobal,
5
3
  computeSelector,
6
4
  getNodeValue,
7
5
  mergeIntoObservable,
8
6
  observable,
9
7
  symbolDelete,
8
+ } from '@legendapp/state';
9
+ import {
10
+ SyncedOptions,
11
+ SyncedOptionsGlobal,
12
+ removeNullUndefined,
10
13
  type SyncedGetParams,
11
14
  type SyncedSubscribeParams,
12
- } from '@legendapp/state';
15
+ } from '@legendapp/state/sync';
13
16
  import {
14
17
  CrudAsOption,
15
18
  SyncedCrudPropsBase,
@@ -17,25 +20,22 @@ import {
17
20
  SyncedCrudReturnType,
18
21
  syncedCrud,
19
22
  } from '@legendapp/state/sync-plugins/crud';
20
- import type { PostgrestFilterBuilder } from '@supabase/postgrest-js';
23
+ import type { PostgrestFilterBuilder, PostgrestQueryBuilder } from '@supabase/postgrest-js';
21
24
  import type { SupabaseClient } from '@supabase/supabase-js';
22
25
 
23
26
  // Unused types but maybe useful in the future so keeping them for now
24
- // type DatabaseOf<TClient extends SupabaseClient> = TClient extends SupabaseClient<infer TDB> ? TDB : never;
25
- // type SchemaNameOf<TClient extends SupabaseClient> = TClient extends SupabaseClient<infer _, infer TSchemaName>
26
- // ? TSchemaName
27
+ // type DatabaseOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer TDB> ? TDB : never;
28
+ // type SchemaNameOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer _, infer SchemaName>
29
+ // ? SchemaName
27
30
  // : never;
28
31
 
29
32
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
30
- type SchemaOf<TClient extends SupabaseClient> = TClient extends SupabaseClient<infer _, infer __, infer TSchema>
31
- ? TSchema
33
+ type SchemaOf<Client extends SupabaseClient> = Client extends SupabaseClient<infer _, infer __, infer Schema>
34
+ ? Schema
32
35
  : never;
33
- type TableOf<TClient extends SupabaseClient> = SchemaOf<TClient>['Tables'];
34
- type CollectionOf<TClient extends SupabaseClient> = keyof TableOf<TClient>;
35
- type RowOf<
36
- TClient extends SupabaseClient,
37
- TCollection extends CollectionOf<TClient>,
38
- > = TableOf<TClient>[TCollection]['Row'];
36
+ type TableOf<Client extends SupabaseClient> = SchemaOf<Client>['Tables'];
37
+ type CollectionOf<Client extends SupabaseClient> = keyof TableOf<Client>;
38
+ type RowOf<Client extends SupabaseClient, Collection extends CollectionOf<Client>> = TableOf<Client>[Collection]['Row'];
39
39
 
40
40
  export type SyncedSupabaseConfig<T extends { id: string }> = Omit<
41
41
  SyncedCrudPropsBase<T>,
@@ -50,27 +50,36 @@ export interface SyncedSupabaseGlobalConfig
50
50
  }
51
51
 
52
52
  interface SyncedSupabaseProps<
53
- TClient extends SupabaseClient,
54
- TCollection extends CollectionOf<TClient>,
53
+ Client extends SupabaseClient,
54
+ Collection extends CollectionOf<Client>,
55
55
  TOption extends CrudAsOption = 'object',
56
- > extends SyncedSupabaseConfig<RowOf<TClient, TCollection>>,
57
- SyncedCrudPropsMany<RowOf<TClient, TCollection>, RowOf<TClient, TCollection>, TOption> {
58
- supabase: TClient;
59
- collection: TCollection;
56
+ > extends SyncedSupabaseConfig<RowOf<Client, Collection>>,
57
+ SyncedCrudPropsMany<RowOf<Client, Collection>, RowOf<Client, Collection>, TOption> {
58
+ supabase: Client;
59
+ collection: Collection;
60
+ select?: (
61
+ query: PostgrestQueryBuilder<SchemaOf<Client>, TableOf<Client>[Collection], Collection>,
62
+ ) => PostgrestFilterBuilder<
63
+ SchemaOf<Client>,
64
+ RowOf<Client, Collection>,
65
+ RowOf<Client, Collection>[],
66
+ Collection,
67
+ []
68
+ >;
60
69
  filter?: (
61
70
  select: PostgrestFilterBuilder<
62
- SchemaOf<TClient>,
63
- RowOf<TClient, TCollection>,
64
- RowOf<TClient, TCollection>[],
65
- TCollection,
71
+ SchemaOf<Client>,
72
+ RowOf<Client, Collection>,
73
+ RowOf<Client, Collection>[],
74
+ Collection,
66
75
  []
67
76
  >,
68
77
  params: SyncedGetParams,
69
78
  ) => PostgrestFilterBuilder<
70
- SchemaOf<TClient>,
71
- RowOf<TClient, TCollection>,
72
- RowOf<TClient, TCollection>[],
73
- TCollection,
79
+ SchemaOf<Client>,
80
+ RowOf<Client, Collection>,
81
+ RowOf<Client, Collection>[],
82
+ Collection,
74
83
  []
75
84
  >;
76
85
  actions?: ('create' | 'read' | 'update' | 'delete')[];
@@ -86,7 +95,7 @@ export function configureSyncedSupabase(config: SyncedSupabaseGlobalConfig) {
86
95
  if (enabled !== undefined) {
87
96
  isEnabled$.set(enabled);
88
97
  }
89
- Object.assign(supabaseConfig, rest);
98
+ Object.assign(supabaseConfig, removeNullUndefined(rest));
90
99
  }
91
100
 
92
101
  export function syncedSupabase<
@@ -98,6 +107,7 @@ export function syncedSupabase<
98
107
  const {
99
108
  supabase: client,
100
109
  collection,
110
+ select: selectFn,
101
111
  filter,
102
112
  actions,
103
113
  fieldCreatedAt,
@@ -106,13 +116,18 @@ export function syncedSupabase<
106
116
  changesSince,
107
117
  waitFor,
108
118
  waitForSet,
119
+ generateId: generateIdParam,
109
120
  ...rest
110
121
  } = props;
122
+
123
+ const generateId = generateIdParam || supabaseConfig.generateId;
124
+
111
125
  const list =
112
126
  !actions || actions.includes('read')
113
127
  ? async (params: SyncedGetParams) => {
114
128
  const { lastSync } = params;
115
- let select = client.from(collection).select();
129
+ const from = client.from(collection);
130
+ let select = selectFn ? selectFn(from) : from.select();
116
131
  if (changesSince === 'last-sync') {
117
132
  select = select.neq('deleted', true);
118
133
  if (lastSync) {
@@ -239,6 +254,7 @@ export function syncedSupabase<
239
254
  fieldCreatedAt,
240
255
  fieldUpdatedAt,
241
256
  updatePartial: true,
257
+ generateId,
242
258
  waitFor: () => isEnabled$.get() && (waitFor ? computeSelector(waitFor) : true),
243
259
  waitForSet: () => isEnabled$.get() && (waitForSet ? computeSelector(waitForSet) : true),
244
260
  });
@@ -1,4 +1,4 @@
1
- import { SyncTransform, SyncedGetParams, SyncedOptions, SyncedSetParams } from '@legendapp/state';
1
+ import { SyncTransform, SyncedGetParams, SyncedOptions, SyncedSetParams } from '@legendapp/state/sync';
2
2
  export type CrudAsOption = 'Map' | 'object' | 'first';
3
3
  export type CrudResult<T> = T;
4
4
  export interface SyncedCrudPropsSingle<TRemote, TLocal> {
@@ -23,6 +23,7 @@ export interface SyncedCrudPropsBase<TRemote extends {
23
23
  fieldCreatedAt?: string;
24
24
  updatePartial?: boolean;
25
25
  changesSince?: 'all' | 'last-sync';
26
+ generateId?: () => string | number;
26
27
  }
27
28
  type InitialValue<T, TAsOption extends CrudAsOption> = TAsOption extends 'Map' ? Map<string, T> : TAsOption extends 'object' ? Record<string, T> : TAsOption extends 'first' ? T : T[];
28
29
  export type SyncedCrudReturnType<TLocal, TAsOption extends CrudAsOption> = TAsOption extends 'Map' ? Map<string, TLocal> : TAsOption extends 'object' ? Record<string, TLocal> : TAsOption extends 'first' ? TLocal : TLocal[];