@legendapp/state 3.0.0-alpha.7 → 3.0.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.DS_Store +0 -0
- package/CHANGELOG.md +831 -1
- package/LICENSE +21 -1
- package/README.md +141 -1
- package/index.d.mts +1 -1
- package/index.d.ts +1 -1
- package/index.js +24 -22
- package/index.mjs +24 -22
- package/package.json +1 -1
- package/sync-plugins/crud.d.mts +0 -1
- package/sync-plugins/crud.d.ts +0 -1
- package/sync-plugins/crud.js +20 -31
- package/sync-plugins/crud.mjs +20 -31
- package/sync-plugins/keel.js +0 -1
- package/sync-plugins/keel.mjs +0 -1
- package/sync-plugins/supabase.js +0 -1
- package/sync-plugins/supabase.mjs +0 -1
- package/sync.js +36 -43
- package/sync.mjs +36 -43
- package/types/babel.d.ts +12 -1
- /package/config/{enable_GetSet.d.mts → enable$GetSet.d.mts} +0 -0
- /package/config/{enable_GetSet.d.ts → enable$GetSet.d.ts} +0 -0
package/LICENSE
CHANGED
|
@@ -1 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Moo.do LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1 +1,141 @@
|
|
|
1
|
-
|
|
1
|
+
# Legend-State
|
|
2
|
+
|
|
3
|
+
Legend-State is a super fast all-in-one state and sync library that lets you write less code to make faster apps. Legend-State has four primary goals:
|
|
4
|
+
|
|
5
|
+
### 1. 🦄 As easy as possible to use
|
|
6
|
+
|
|
7
|
+
There is no boilerplate and there are no contexts, actions, reducers, dispatchers, sagas, thunks, or epics. It doesn't modify your data at all, and you can just call `get()` to get the raw data and `set()` to change it.
|
|
8
|
+
|
|
9
|
+
In React components you can call `use()` on any observable to get the raw data and automatically re-render whenever it changes.
|
|
10
|
+
|
|
11
|
+
```jsx
|
|
12
|
+
import { observable, observe } from "@legendapp/state"
|
|
13
|
+
import { observer } from "@legendapp/state/react"
|
|
14
|
+
|
|
15
|
+
const settings$ = observable({ theme: 'dark' })
|
|
16
|
+
|
|
17
|
+
// get returns the raw data
|
|
18
|
+
settings$.theme.get() // 'dark'
|
|
19
|
+
// set sets
|
|
20
|
+
settings$.theme.set('light')
|
|
21
|
+
|
|
22
|
+
// Computed observables with just a function
|
|
23
|
+
const isDark$ = observable(() => settings$.theme.get() === 'dark')
|
|
24
|
+
|
|
25
|
+
// observing contexts re-run when tracked observables change
|
|
26
|
+
observe(() => {
|
|
27
|
+
console.log(settings$.theme.get())
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const Component = observer(function Component() {
|
|
31
|
+
const theme = state$.settings.theme.get()
|
|
32
|
+
|
|
33
|
+
return <div>Theme: {theme}</div>
|
|
34
|
+
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. ⚡️ The fastest React state library
|
|
38
|
+
|
|
39
|
+
Legend-State beats every other state library on just about every metric and is so optimized for arrays that it even beats vanilla JS on the "swap" and "replace all rows" benchmarks. At only `4kb` and with the massive reduction in boilerplate code, you'll have big savings in file size too.
|
|
40
|
+
|
|
41
|
+
<p>
|
|
42
|
+
<img src="https://www.legendapp.com/img/dev/state/times.png" />
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
See [Fast 🔥](https://www.legendapp.com/open-source/state/v3/intro/fast/) for more details of why Legend-State is so fast.
|
|
46
|
+
|
|
47
|
+
### 3. 🔥 Fine-grained reactivity for minimal renders
|
|
48
|
+
|
|
49
|
+
Legend-State lets you make your renders super fine-grained, so your apps will be much faster because React has to do less work. The best way to be fast is to render less, less often.
|
|
50
|
+
|
|
51
|
+
```jsx
|
|
52
|
+
function FineGrained() {
|
|
53
|
+
const count$ = useObservable(0)
|
|
54
|
+
|
|
55
|
+
useInterval(() => {
|
|
56
|
+
count$.set(v => v + 1)
|
|
57
|
+
}, 600)
|
|
58
|
+
|
|
59
|
+
// The text updates itself so the component doesn't re-render
|
|
60
|
+
return (
|
|
61
|
+
<div>
|
|
62
|
+
Count: <Memo>{count$}</Memo>
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 4. 💾 Powerful sync and persistence
|
|
69
|
+
|
|
70
|
+
Legend-State includes a powerful [sync and persistence system](../../usage/persist-sync). It easily enables local-first apps by optimistically applying all changes locally first, retrying changes even after restart until they eventually sync, and syncing minimal diffs. We use Legend-State as the sync systems in [Legend](https://legendapp.com) and [Bravely](https://bravely.io), so it is by necessity very full featured while being simple to set up.
|
|
71
|
+
|
|
72
|
+
Local persistence plugins for the browser and React Native are included, with sync plugins for [Keel](https://www.keel.so), [Supabase](https://www.supabase.com), [TanStack Query](https://tanstack.com/query), and `fetch`.
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
const state$ = observable(
|
|
76
|
+
users: syncedKeel({
|
|
77
|
+
list: queries.getUsers,
|
|
78
|
+
create: mutations.createUsers,
|
|
79
|
+
update: mutations.updateUsers,
|
|
80
|
+
delete: mutations.deleteUsers,
|
|
81
|
+
persist: { name: 'users', retrySync: true },
|
|
82
|
+
debounceSet: 500,
|
|
83
|
+
retry: {
|
|
84
|
+
infinite: true,
|
|
85
|
+
},
|
|
86
|
+
changesSince: 'last-sync',
|
|
87
|
+
}),
|
|
88
|
+
// direct link to my user within the users observable
|
|
89
|
+
me: () => state$.users['myuid']
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
observe(() => {
|
|
93
|
+
// get() activates through to state$.users and starts syncing.
|
|
94
|
+
// it updates itself and re-runs observers when name changes
|
|
95
|
+
const name = me$.name.get()
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
// Setting a value goes through to state$.users and saves update to server
|
|
99
|
+
me$.name.set('Annyong')
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Install
|
|
103
|
+
|
|
104
|
+
`bun add @legendapp/state` or `npm install @legendapp/state` or `yarn add @legendapp/state`
|
|
105
|
+
|
|
106
|
+
## Highlights
|
|
107
|
+
|
|
108
|
+
- ✨ Super easy to use 😌
|
|
109
|
+
- ✨ Super fast ⚡️
|
|
110
|
+
- ✨ Super small at 4kb 🐥
|
|
111
|
+
- ✨ Fine-grained reactivity 🔥
|
|
112
|
+
- ✨ No boilerplate
|
|
113
|
+
- ✨ Designed for maximum performance and scalability
|
|
114
|
+
- ✨ React components re-render only on changes
|
|
115
|
+
- ✨ Very strongly typed with TypeScript
|
|
116
|
+
- ✨ Persistence plugins for automatically saving/loading from storage
|
|
117
|
+
- ✨ State can be global or within components
|
|
118
|
+
|
|
119
|
+
[Read more](https://www.legendapp.com/open-source/state/v3/intro/why/) about why Legend-State might be right for you.
|
|
120
|
+
|
|
121
|
+
## Documentation
|
|
122
|
+
|
|
123
|
+
See [the documentation site](https://www.legendapp.com/open-source/state/).
|
|
124
|
+
|
|
125
|
+
## Community
|
|
126
|
+
|
|
127
|
+
Join us on [Discord](https://discord.gg/5CBaNtADNX) to get involved with the Legend community.
|
|
128
|
+
|
|
129
|
+
## 👩⚖️ License
|
|
130
|
+
|
|
131
|
+
[MIT](LICENSE)
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
Legend-State is created and maintained by [Jay Meistrich](https://github.com/jmeistrich) with [Legend](https://www.legendapp.com) and [Bravely](https://www.bravely.io).
|
|
136
|
+
|
|
137
|
+
<p>
|
|
138
|
+
<a href="https://www.legendapp.com"><img src="https://www.legendapp.com/img/LogoTextOnWhite.png" height="56" alt="Legend" /></a>
|
|
139
|
+
<span> </span>
|
|
140
|
+
<a href="https://www.bravely.io"><img src="https://www.legendapp.com/img/bravely-logo.png" height="56" alt="Bravely" /></a>
|
|
141
|
+
</p>
|
package/index.d.mts
CHANGED
|
@@ -96,7 +96,7 @@ type RecursiveValueOrFunction<T> = T extends Function ? T : T extends object ? (
|
|
|
96
96
|
|
|
97
97
|
declare const symbolOpaque: unique symbol;
|
|
98
98
|
declare function getPathType(value: any): TypeAtPath;
|
|
99
|
-
declare function safeStringify(value: any):
|
|
99
|
+
declare function safeStringify(value: any): any;
|
|
100
100
|
declare function safeParse(value: any): any;
|
|
101
101
|
declare function clone<T>(value: T): any;
|
|
102
102
|
declare function isObservable(value$: any): value$ is Observable;
|
package/index.d.ts
CHANGED
|
@@ -96,7 +96,7 @@ type RecursiveValueOrFunction<T> = T extends Function ? T : T extends object ? (
|
|
|
96
96
|
|
|
97
97
|
declare const symbolOpaque: unique symbol;
|
|
98
98
|
declare function getPathType(value: any): TypeAtPath;
|
|
99
|
-
declare function safeStringify(value: any):
|
|
99
|
+
declare function safeStringify(value: any): any;
|
|
100
100
|
declare function safeParse(value: any): any;
|
|
101
101
|
declare function clone<T>(value: T): any;
|
|
102
102
|
declare function isObservable(value$: any): value$ is Observable;
|
package/index.js
CHANGED
|
@@ -118,10 +118,10 @@ function reviver(key, value) {
|
|
|
118
118
|
return value;
|
|
119
119
|
}
|
|
120
120
|
function safeStringify(value) {
|
|
121
|
-
return JSON.stringify(value, replacer);
|
|
121
|
+
return value ? JSON.stringify(value, replacer) : value;
|
|
122
122
|
}
|
|
123
123
|
function safeParse(value) {
|
|
124
|
-
return JSON.parse(value, reviver);
|
|
124
|
+
return value ? JSON.parse(value, reviver) : value;
|
|
125
125
|
}
|
|
126
126
|
function clone(value) {
|
|
127
127
|
return safeParse(safeStringify(value));
|
|
@@ -2038,7 +2038,7 @@ function setToObservable(node, value) {
|
|
|
2038
2038
|
return value;
|
|
2039
2039
|
}
|
|
2040
2040
|
function recursivelyAutoActivate(obj, node) {
|
|
2041
|
-
if (isObject(obj) || isArray(obj)) {
|
|
2041
|
+
if ((isObject(obj) || isArray(obj)) && !obj[symbolOpaque]) {
|
|
2042
2042
|
const pathStack = [];
|
|
2043
2043
|
const getNodeAtPath2 = () => {
|
|
2044
2044
|
var _a;
|
|
@@ -2056,27 +2056,29 @@ function recursivelyAutoActivate(obj, node) {
|
|
|
2056
2056
|
}
|
|
2057
2057
|
function recursivelyAutoActivateInner(obj, pathStack, getNodeAtPath2) {
|
|
2058
2058
|
var _a;
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2059
|
+
if ((isObject(obj) || isArray(obj)) && !obj[symbolOpaque]) {
|
|
2060
|
+
for (const key in obj) {
|
|
2061
|
+
if (hasOwnProperty.call(obj, key)) {
|
|
2062
|
+
const value = obj[key];
|
|
2063
|
+
if (isObservable(value)) {
|
|
2064
|
+
const childNode = getNodeAtPath2();
|
|
2065
|
+
extractFunctionOrComputed(childNode, key, value);
|
|
2066
|
+
delete childNode.lazy;
|
|
2067
|
+
} else {
|
|
2068
|
+
const linkedOptions = isFunction(value) && ((_a = value.prototype) == null ? void 0 : _a[symbolLinked]);
|
|
2069
|
+
if (linkedOptions) {
|
|
2070
|
+
const activate = linkedOptions.activate;
|
|
2071
|
+
if (!activate || activate === "auto") {
|
|
2072
|
+
const childNode = getNodeAtPath2();
|
|
2073
|
+
peek(getChildNode(childNode, key, value));
|
|
2074
|
+
}
|
|
2073
2075
|
}
|
|
2074
2076
|
}
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2077
|
+
if (typeof value === "object") {
|
|
2078
|
+
pathStack.push({ key, value });
|
|
2079
|
+
recursivelyAutoActivateInner(value, pathStack, getNodeAtPath2);
|
|
2080
|
+
pathStack.pop();
|
|
2081
|
+
}
|
|
2080
2082
|
}
|
|
2081
2083
|
}
|
|
2082
2084
|
}
|
package/index.mjs
CHANGED
|
@@ -116,10 +116,10 @@ function reviver(key, value) {
|
|
|
116
116
|
return value;
|
|
117
117
|
}
|
|
118
118
|
function safeStringify(value) {
|
|
119
|
-
return JSON.stringify(value, replacer);
|
|
119
|
+
return value ? JSON.stringify(value, replacer) : value;
|
|
120
120
|
}
|
|
121
121
|
function safeParse(value) {
|
|
122
|
-
return JSON.parse(value, reviver);
|
|
122
|
+
return value ? JSON.parse(value, reviver) : value;
|
|
123
123
|
}
|
|
124
124
|
function clone(value) {
|
|
125
125
|
return safeParse(safeStringify(value));
|
|
@@ -2036,7 +2036,7 @@ function setToObservable(node, value) {
|
|
|
2036
2036
|
return value;
|
|
2037
2037
|
}
|
|
2038
2038
|
function recursivelyAutoActivate(obj, node) {
|
|
2039
|
-
if (isObject(obj) || isArray(obj)) {
|
|
2039
|
+
if ((isObject(obj) || isArray(obj)) && !obj[symbolOpaque]) {
|
|
2040
2040
|
const pathStack = [];
|
|
2041
2041
|
const getNodeAtPath2 = () => {
|
|
2042
2042
|
var _a;
|
|
@@ -2054,27 +2054,29 @@ function recursivelyAutoActivate(obj, node) {
|
|
|
2054
2054
|
}
|
|
2055
2055
|
function recursivelyAutoActivateInner(obj, pathStack, getNodeAtPath2) {
|
|
2056
2056
|
var _a;
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2057
|
+
if ((isObject(obj) || isArray(obj)) && !obj[symbolOpaque]) {
|
|
2058
|
+
for (const key in obj) {
|
|
2059
|
+
if (hasOwnProperty.call(obj, key)) {
|
|
2060
|
+
const value = obj[key];
|
|
2061
|
+
if (isObservable(value)) {
|
|
2062
|
+
const childNode = getNodeAtPath2();
|
|
2063
|
+
extractFunctionOrComputed(childNode, key, value);
|
|
2064
|
+
delete childNode.lazy;
|
|
2065
|
+
} else {
|
|
2066
|
+
const linkedOptions = isFunction(value) && ((_a = value.prototype) == null ? void 0 : _a[symbolLinked]);
|
|
2067
|
+
if (linkedOptions) {
|
|
2068
|
+
const activate = linkedOptions.activate;
|
|
2069
|
+
if (!activate || activate === "auto") {
|
|
2070
|
+
const childNode = getNodeAtPath2();
|
|
2071
|
+
peek(getChildNode(childNode, key, value));
|
|
2072
|
+
}
|
|
2071
2073
|
}
|
|
2072
2074
|
}
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2075
|
+
if (typeof value === "object") {
|
|
2076
|
+
pathStack.push({ key, value });
|
|
2077
|
+
recursivelyAutoActivateInner(value, pathStack, getNodeAtPath2);
|
|
2078
|
+
pathStack.pop();
|
|
2079
|
+
}
|
|
2078
2080
|
}
|
|
2079
2081
|
}
|
|
2080
2082
|
}
|
package/package.json
CHANGED
package/sync-plugins/crud.d.mts
CHANGED
|
@@ -30,7 +30,6 @@ interface SyncedCrudPropsBase<TRemote extends {
|
|
|
30
30
|
id: TRemote['id'];
|
|
31
31
|
}, params: SyncedSetParams<TRemote>): Promise<CrudResult<any>>;
|
|
32
32
|
onSaved?(params: SyncedCrudOnSavedParams<TRemote, TLocal>): Partial<TLocal> | void;
|
|
33
|
-
onSavedUpdate?: 'createdUpdatedAt';
|
|
34
33
|
fieldUpdatedAt?: string;
|
|
35
34
|
fieldCreatedAt?: string;
|
|
36
35
|
fieldDeleted?: string;
|
package/sync-plugins/crud.d.ts
CHANGED
|
@@ -30,7 +30,6 @@ interface SyncedCrudPropsBase<TRemote extends {
|
|
|
30
30
|
id: TRemote['id'];
|
|
31
31
|
}, params: SyncedSetParams<TRemote>): Promise<CrudResult<any>>;
|
|
32
32
|
onSaved?(params: SyncedCrudOnSavedParams<TRemote, TLocal>): Partial<TLocal> | void;
|
|
33
|
-
onSavedUpdate?: 'createdUpdatedAt';
|
|
34
33
|
fieldUpdatedAt?: string;
|
|
35
34
|
fieldCreatedAt?: string;
|
|
36
35
|
fieldDeleted?: string;
|
package/sync-plugins/crud.js
CHANGED
|
@@ -14,25 +14,6 @@ function ensureId(obj, generateId) {
|
|
|
14
14
|
}
|
|
15
15
|
return obj.id;
|
|
16
16
|
}
|
|
17
|
-
function onSavedCreatedUpdatedAt(mode, { saved, currentValue, isCreate, props }) {
|
|
18
|
-
const savedOut = {};
|
|
19
|
-
if (isCreate) {
|
|
20
|
-
Object.keys(saved).forEach((key) => {
|
|
21
|
-
if (state.isNullOrUndefined(currentValue[key])) {
|
|
22
|
-
savedOut[key] = saved[key];
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
} else if (mode === "createdUpdatedAt") {
|
|
26
|
-
Object.keys(saved).forEach((key) => {
|
|
27
|
-
const k = key;
|
|
28
|
-
const keyLower = key.toLowerCase();
|
|
29
|
-
if ((key === props.fieldCreatedAt || key === props.fieldUpdatedAt || keyLower.endsWith("createdat") || keyLower.endsWith("updatedat") || keyLower.endsWith("created_at") || keyLower.endsWith("updated_at")) && saved[k] instanceof Date) {
|
|
30
|
-
savedOut[k] = saved[k];
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
return savedOut;
|
|
35
|
-
}
|
|
36
17
|
function syncedCrud(props) {
|
|
37
18
|
const {
|
|
38
19
|
get: getFn,
|
|
@@ -46,7 +27,6 @@ function syncedCrud(props) {
|
|
|
46
27
|
fieldDeleted,
|
|
47
28
|
updatePartial,
|
|
48
29
|
onSaved,
|
|
49
|
-
onSavedUpdate,
|
|
50
30
|
mode: modeParam,
|
|
51
31
|
changesSince,
|
|
52
32
|
generateId,
|
|
@@ -198,7 +178,7 @@ function syncedCrud(props) {
|
|
|
198
178
|
}
|
|
199
179
|
});
|
|
200
180
|
const saveResult = async (itemKey, input, data, isCreate) => {
|
|
201
|
-
if (data
|
|
181
|
+
if (data) {
|
|
202
182
|
const saved = (transform == null ? void 0 : transform.load) ? transform.load(data, "set") : data;
|
|
203
183
|
const isChild = itemKey !== "undefined" && asType !== "value";
|
|
204
184
|
const currentPeeked = state.getNodeValue(node);
|
|
@@ -210,17 +190,26 @@ function syncedCrud(props) {
|
|
|
210
190
|
isCreate,
|
|
211
191
|
props
|
|
212
192
|
};
|
|
213
|
-
let savedOut =
|
|
214
|
-
if (onSavedUpdate) {
|
|
215
|
-
savedOut = onSavedCreatedUpdatedAt(onSavedUpdate, dataOnSaved);
|
|
216
|
-
}
|
|
217
|
-
if (onSaved) {
|
|
218
|
-
const ret = onSaved(dataOnSaved);
|
|
219
|
-
if (ret) {
|
|
220
|
-
savedOut = ret;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
193
|
+
let savedOut = saved;
|
|
223
194
|
if (savedOut) {
|
|
195
|
+
savedOut = clone(savedOut);
|
|
196
|
+
Object.keys(savedOut).forEach((key) => {
|
|
197
|
+
const i = input[key];
|
|
198
|
+
const c = currentValue[key];
|
|
199
|
+
if (
|
|
200
|
+
// value is already the new value, can ignore
|
|
201
|
+
savedOut[key] === c || // user has changed local value
|
|
202
|
+
key !== "id" && i !== c
|
|
203
|
+
) {
|
|
204
|
+
delete savedOut[key];
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
if (onSaved) {
|
|
208
|
+
const ret = onSaved(dataOnSaved);
|
|
209
|
+
if (ret) {
|
|
210
|
+
savedOut = ret;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
224
213
|
const createdAt = fieldCreatedAt ? savedOut[fieldCreatedAt] : void 0;
|
|
225
214
|
const updatedAt = fieldUpdatedAt ? savedOut[fieldUpdatedAt] : void 0;
|
|
226
215
|
const value2 = itemKey !== "undefined" && asType !== "value" ? { [itemKey]: savedOut } : savedOut;
|
package/sync-plugins/crud.mjs
CHANGED
|
@@ -12,25 +12,6 @@ function ensureId(obj, generateId) {
|
|
|
12
12
|
}
|
|
13
13
|
return obj.id;
|
|
14
14
|
}
|
|
15
|
-
function onSavedCreatedUpdatedAt(mode, { saved, currentValue, isCreate, props }) {
|
|
16
|
-
const savedOut = {};
|
|
17
|
-
if (isCreate) {
|
|
18
|
-
Object.keys(saved).forEach((key) => {
|
|
19
|
-
if (isNullOrUndefined(currentValue[key])) {
|
|
20
|
-
savedOut[key] = saved[key];
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
} else if (mode === "createdUpdatedAt") {
|
|
24
|
-
Object.keys(saved).forEach((key) => {
|
|
25
|
-
const k = key;
|
|
26
|
-
const keyLower = key.toLowerCase();
|
|
27
|
-
if ((key === props.fieldCreatedAt || key === props.fieldUpdatedAt || keyLower.endsWith("createdat") || keyLower.endsWith("updatedat") || keyLower.endsWith("created_at") || keyLower.endsWith("updated_at")) && saved[k] instanceof Date) {
|
|
28
|
-
savedOut[k] = saved[k];
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
return savedOut;
|
|
33
|
-
}
|
|
34
15
|
function syncedCrud(props) {
|
|
35
16
|
const {
|
|
36
17
|
get: getFn,
|
|
@@ -44,7 +25,6 @@ function syncedCrud(props) {
|
|
|
44
25
|
fieldDeleted,
|
|
45
26
|
updatePartial,
|
|
46
27
|
onSaved,
|
|
47
|
-
onSavedUpdate,
|
|
48
28
|
mode: modeParam,
|
|
49
29
|
changesSince,
|
|
50
30
|
generateId,
|
|
@@ -196,7 +176,7 @@ function syncedCrud(props) {
|
|
|
196
176
|
}
|
|
197
177
|
});
|
|
198
178
|
const saveResult = async (itemKey, input, data, isCreate) => {
|
|
199
|
-
if (data
|
|
179
|
+
if (data) {
|
|
200
180
|
const saved = (transform == null ? void 0 : transform.load) ? transform.load(data, "set") : data;
|
|
201
181
|
const isChild = itemKey !== "undefined" && asType !== "value";
|
|
202
182
|
const currentPeeked = getNodeValue(node);
|
|
@@ -208,17 +188,26 @@ function syncedCrud(props) {
|
|
|
208
188
|
isCreate,
|
|
209
189
|
props
|
|
210
190
|
};
|
|
211
|
-
let savedOut =
|
|
212
|
-
if (onSavedUpdate) {
|
|
213
|
-
savedOut = onSavedCreatedUpdatedAt(onSavedUpdate, dataOnSaved);
|
|
214
|
-
}
|
|
215
|
-
if (onSaved) {
|
|
216
|
-
const ret = onSaved(dataOnSaved);
|
|
217
|
-
if (ret) {
|
|
218
|
-
savedOut = ret;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
191
|
+
let savedOut = saved;
|
|
221
192
|
if (savedOut) {
|
|
193
|
+
savedOut = clone(savedOut);
|
|
194
|
+
Object.keys(savedOut).forEach((key) => {
|
|
195
|
+
const i = input[key];
|
|
196
|
+
const c = currentValue[key];
|
|
197
|
+
if (
|
|
198
|
+
// value is already the new value, can ignore
|
|
199
|
+
savedOut[key] === c || // user has changed local value
|
|
200
|
+
key !== "id" && i !== c
|
|
201
|
+
) {
|
|
202
|
+
delete savedOut[key];
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
if (onSaved) {
|
|
206
|
+
const ret = onSaved(dataOnSaved);
|
|
207
|
+
if (ret) {
|
|
208
|
+
savedOut = ret;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
222
211
|
const createdAt = fieldCreatedAt ? savedOut[fieldCreatedAt] : void 0;
|
|
223
212
|
const updatedAt = fieldUpdatedAt ? savedOut[fieldUpdatedAt] : void 0;
|
|
224
213
|
const value2 = itemKey !== "undefined" && asType !== "value" ? { [itemKey]: savedOut } : savedOut;
|
package/sync-plugins/keel.js
CHANGED
|
@@ -244,7 +244,6 @@ function syncedKeel(props) {
|
|
|
244
244
|
delete: deleteFn,
|
|
245
245
|
waitFor: () => isEnabled$.get() && (waitFor ? state.computeSelector(waitFor) : true),
|
|
246
246
|
onSaved,
|
|
247
|
-
onSavedUpdate: "createdUpdatedAt",
|
|
248
247
|
fieldCreatedAt,
|
|
249
248
|
fieldUpdatedAt,
|
|
250
249
|
fieldDeleted: fieldDeleted || "deleted",
|
package/sync-plugins/keel.mjs
CHANGED
|
@@ -238,7 +238,6 @@ function syncedKeel(props) {
|
|
|
238
238
|
delete: deleteFn,
|
|
239
239
|
waitFor: () => isEnabled$.get() && (waitFor ? computeSelector(waitFor) : true),
|
|
240
240
|
onSaved,
|
|
241
|
-
onSavedUpdate: "createdUpdatedAt",
|
|
242
241
|
fieldCreatedAt,
|
|
243
242
|
fieldUpdatedAt,
|
|
244
243
|
fieldDeleted: fieldDeleted || "deleted",
|
package/sync-plugins/supabase.js
CHANGED
|
@@ -132,7 +132,6 @@ function syncedSupabase(props) {
|
|
|
132
132
|
fieldUpdatedAt,
|
|
133
133
|
fieldDeleted,
|
|
134
134
|
updatePartial: false,
|
|
135
|
-
onSavedUpdate: "createdUpdatedAt",
|
|
136
135
|
transform,
|
|
137
136
|
generateId,
|
|
138
137
|
waitFor: () => isEnabled$.get() && (waitFor ? state.computeSelector(waitFor) : true),
|