tinybase 9.5.0 → 9.6.0-beta.1
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/@types/omni/index.d.ts +4 -0
- package/@types/omni/with-schemas/index.d.ts +4 -0
- package/@types/persisters/index.d.ts +8 -1
- package/@types/persisters/persister-better-sqlite3/index.d.ts +178 -0
- package/@types/persisters/persister-better-sqlite3/with-schemas/index.d.ts +202 -0
- package/@types/persisters/persister-capacitor-sqlite/index.d.ts +181 -0
- package/@types/persisters/persister-capacitor-sqlite/with-schemas/index.d.ts +205 -0
- package/@types/persisters/persister-indexed-db/index.d.ts +17 -9
- package/@types/persisters/persister-indexed-db/with-schemas/index.d.ts +18 -10
- package/@types/persisters/persister-libsql/index.d.ts +27 -0
- package/@types/persisters/persister-libsql/with-schemas/index.d.ts +27 -0
- package/@types/persisters/persister-pg/index.d.ts +197 -0
- package/@types/persisters/persister-pg/with-schemas/index.d.ts +222 -0
- package/@types/persisters/persister-supabase/index.d.ts +201 -0
- package/@types/persisters/persister-supabase/with-schemas/index.d.ts +217 -0
- package/@types/persisters/with-schemas/index.d.ts +8 -1
- package/@types/ui-react-dom/index.d.ts +10 -10
- package/@types/ui-react-dom/with-schemas/index.d.ts +10 -10
- package/@types/ui-react-dom-charts/index.d.ts +7 -7
- package/@types/ui-react-dom-charts/with-schemas/index.d.ts +7 -7
- package/@types/ui-react-inspector/index.d.ts +1 -1
- package/@types/ui-react-inspector/with-schemas/index.d.ts +1 -1
- package/@types/ui-solid-dom/index.d.ts +10 -10
- package/@types/ui-solid-dom/with-schemas/index.d.ts +10 -10
- package/@types/ui-solid-inspector/index.d.ts +1 -1
- package/@types/ui-solid-inspector/with-schemas/index.d.ts +1 -1
- package/@types/ui-svelte-dom/index.d.ts +10 -10
- package/@types/ui-svelte-dom/with-schemas/index.d.ts +10 -10
- package/@types/ui-svelte-inspector/index.d.ts +1 -1
- package/@types/ui-svelte-inspector/with-schemas/index.d.ts +1 -1
- package/agents.md +55 -2
- package/min/omni/index.js +1 -1
- package/min/omni/index.js.gz +0 -0
- package/min/omni/with-schemas/index.js +1 -1
- package/min/omni/with-schemas/index.js.gz +0 -0
- package/min/persisters/index.js +1 -1
- package/min/persisters/index.js.gz +0 -0
- package/min/persisters/persister-better-sqlite3/index.js +1 -0
- package/min/persisters/persister-better-sqlite3/index.js.gz +0 -0
- package/min/persisters/persister-better-sqlite3/with-schemas/index.js +1 -0
- package/min/persisters/persister-better-sqlite3/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-capacitor-sqlite/index.js +1 -0
- package/min/persisters/persister-capacitor-sqlite/index.js.gz +0 -0
- package/min/persisters/persister-capacitor-sqlite/with-schemas/index.js +1 -0
- package/min/persisters/persister-capacitor-sqlite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-cr-sqlite-wasm/index.js +1 -1
- package/min/persisters/persister-cr-sqlite-wasm/index.js.gz +0 -0
- package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +1 -1
- package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-durable-object-sql-storage/index.js +1 -1
- package/min/persisters/persister-durable-object-sql-storage/index.js.gz +0 -0
- package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js +1 -1
- package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-electric-sql/index.js +1 -1
- package/min/persisters/persister-electric-sql/index.js.gz +0 -0
- package/min/persisters/persister-electric-sql/with-schemas/index.js +1 -1
- package/min/persisters/persister-electric-sql/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-expo-sqlite/index.js +1 -1
- package/min/persisters/persister-expo-sqlite/index.js.gz +0 -0
- package/min/persisters/persister-expo-sqlite/with-schemas/index.js +1 -1
- package/min/persisters/persister-expo-sqlite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-indexed-db/index.js +1 -1
- package/min/persisters/persister-indexed-db/index.js.gz +0 -0
- package/min/persisters/persister-indexed-db/with-schemas/index.js +1 -1
- package/min/persisters/persister-indexed-db/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-libsql/index.js +1 -1
- package/min/persisters/persister-libsql/index.js.gz +0 -0
- package/min/persisters/persister-libsql/with-schemas/index.js +1 -1
- package/min/persisters/persister-libsql/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-pg/index.js +1 -0
- package/min/persisters/persister-pg/index.js.gz +0 -0
- package/min/persisters/persister-pg/with-schemas/index.js +1 -0
- package/min/persisters/persister-pg/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-pglite/index.js +1 -1
- package/min/persisters/persister-pglite/index.js.gz +0 -0
- package/min/persisters/persister-pglite/with-schemas/index.js +1 -1
- package/min/persisters/persister-pglite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-postgres/index.js +1 -1
- package/min/persisters/persister-postgres/index.js.gz +0 -0
- package/min/persisters/persister-postgres/with-schemas/index.js +1 -1
- package/min/persisters/persister-postgres/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-powersync/index.js +1 -1
- package/min/persisters/persister-powersync/index.js.gz +0 -0
- package/min/persisters/persister-powersync/with-schemas/index.js +1 -1
- package/min/persisters/persister-powersync/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-react-native-sqlite/index.js +1 -1
- package/min/persisters/persister-react-native-sqlite/index.js.gz +0 -0
- package/min/persisters/persister-react-native-sqlite/with-schemas/index.js +1 -1
- package/min/persisters/persister-react-native-sqlite/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-bun/index.js +1 -1
- package/min/persisters/persister-sqlite-bun/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-bun/with-schemas/index.js +1 -1
- package/min/persisters/persister-sqlite-bun/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-wasm/index.js +1 -1
- package/min/persisters/persister-sqlite-wasm/index.js.gz +0 -0
- package/min/persisters/persister-sqlite-wasm/with-schemas/index.js +1 -1
- package/min/persisters/persister-sqlite-wasm/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-sqlite3/index.js +1 -1
- package/min/persisters/persister-sqlite3/index.js.gz +0 -0
- package/min/persisters/persister-sqlite3/with-schemas/index.js +1 -1
- package/min/persisters/persister-sqlite3/with-schemas/index.js.gz +0 -0
- package/min/persisters/persister-supabase/index.js +1 -0
- package/min/persisters/persister-supabase/index.js.gz +0 -0
- package/min/persisters/persister-supabase/with-schemas/index.js +1 -0
- package/min/persisters/persister-supabase/with-schemas/index.js.gz +0 -0
- package/min/persisters/with-schemas/index.js +1 -1
- package/min/persisters/with-schemas/index.js.gz +0 -0
- package/omni/index.js +269 -34
- package/omni/with-schemas/index.js +269 -34
- package/package.json +164 -4
- package/persisters/index.js +23 -7
- package/persisters/persister-better-sqlite3/index.js +1767 -0
- package/persisters/persister-better-sqlite3/with-schemas/index.js +1767 -0
- package/persisters/persister-capacitor-sqlite/index.js +1769 -0
- package/persisters/persister-capacitor-sqlite/with-schemas/index.js +1769 -0
- package/persisters/persister-cr-sqlite-wasm/index.js +20 -6
- package/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +20 -6
- package/persisters/persister-durable-object-sql-storage/index.js +20 -7
- package/persisters/persister-durable-object-sql-storage/with-schemas/index.js +20 -7
- package/persisters/persister-electric-sql/index.js +20 -6
- package/persisters/persister-electric-sql/with-schemas/index.js +20 -6
- package/persisters/persister-expo-sqlite/index.js +20 -6
- package/persisters/persister-expo-sqlite/with-schemas/index.js +20 -6
- package/persisters/persister-indexed-db/index.js +48 -20
- package/persisters/persister-indexed-db/with-schemas/index.js +48 -20
- package/persisters/persister-libsql/index.js +20 -6
- package/persisters/persister-libsql/with-schemas/index.js +20 -6
- package/persisters/persister-pg/index.js +1905 -0
- package/persisters/persister-pg/with-schemas/index.js +1905 -0
- package/persisters/persister-pglite/index.js +20 -6
- package/persisters/persister-pglite/with-schemas/index.js +20 -6
- package/persisters/persister-postgres/index.js +20 -6
- package/persisters/persister-postgres/with-schemas/index.js +20 -6
- package/persisters/persister-powersync/index.js +27 -10
- package/persisters/persister-powersync/with-schemas/index.js +27 -10
- package/persisters/persister-react-native-sqlite/index.js +20 -6
- package/persisters/persister-react-native-sqlite/with-schemas/index.js +20 -6
- package/persisters/persister-sqlite-bun/index.js +20 -6
- package/persisters/persister-sqlite-bun/with-schemas/index.js +20 -6
- package/persisters/persister-sqlite-wasm/index.js +20 -6
- package/persisters/persister-sqlite-wasm/with-schemas/index.js +20 -6
- package/persisters/persister-sqlite3/index.js +20 -6
- package/persisters/persister-sqlite3/with-schemas/index.js +20 -6
- package/persisters/persister-supabase/index.js +883 -0
- package/persisters/persister-supabase/with-schemas/index.js +883 -0
- package/persisters/with-schemas/index.js +23 -7
- package/readme.md +14 -14
- package/releases.md +163 -66
|
@@ -0,0 +1,883 @@
|
|
|
1
|
+
const getTypeOf = (thing) => typeof thing;
|
|
2
|
+
const TINYBASE = 'tinybase';
|
|
3
|
+
const EMPTY_STRING = '';
|
|
4
|
+
const STRING = getTypeOf(EMPTY_STRING);
|
|
5
|
+
const UNDEFINED = '\uFFFC';
|
|
6
|
+
const strSplit = (str, separator = EMPTY_STRING, limit) =>
|
|
7
|
+
str.split(separator, limit);
|
|
8
|
+
|
|
9
|
+
const promise = Promise;
|
|
10
|
+
const math = Math;
|
|
11
|
+
const getIfNotFunction = (predicate) => (value, then, otherwise) =>
|
|
12
|
+
predicate(value)
|
|
13
|
+
? /* istanbul ignore next */
|
|
14
|
+
otherwise?.()
|
|
15
|
+
: then(value);
|
|
16
|
+
const GLOBAL = globalThis;
|
|
17
|
+
const THOUSAND = 1e3;
|
|
18
|
+
const startInterval = (callback, sec, immediate) => {
|
|
19
|
+
return setInterval(callback, sec * THOUSAND);
|
|
20
|
+
};
|
|
21
|
+
const stopInterval = (interval) => clearInterval(interval);
|
|
22
|
+
const mathFloor = math.floor;
|
|
23
|
+
const mathRandom = math.random;
|
|
24
|
+
const isNullish = (thing) => thing == null;
|
|
25
|
+
const isUndefined = (thing) => thing === void 0;
|
|
26
|
+
const isNull = (thing) => thing === null;
|
|
27
|
+
const ifNotNullish = getIfNotFunction(isNullish);
|
|
28
|
+
const ifNotUndefined = getIfNotFunction(isUndefined);
|
|
29
|
+
const isString = (thing) => getTypeOf(thing) == STRING;
|
|
30
|
+
const isArray = (thing) => Array.isArray(thing);
|
|
31
|
+
const size = (thing) => thing.length;
|
|
32
|
+
const isEmpty = (thing) => size(thing) == 0;
|
|
33
|
+
const test = (regex, subject) => regex.test(subject);
|
|
34
|
+
const promiseNew = (resolver) => new promise(resolver);
|
|
35
|
+
|
|
36
|
+
const arrayForEach = (array, cb) => array.forEach(cb);
|
|
37
|
+
const arrayMap = (array, cb) => array.map(cb);
|
|
38
|
+
const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
|
|
39
|
+
const arrayFilter = (array, cb) => array.filter(cb);
|
|
40
|
+
const arrayClear = (array, to = size(array)) => array.splice(0, to);
|
|
41
|
+
const arrayPush = (array, ...values) => array.push(...values);
|
|
42
|
+
const arrayShift = (array) => array.shift();
|
|
43
|
+
|
|
44
|
+
const collSize = (coll) => coll?.size ?? 0;
|
|
45
|
+
const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
|
|
46
|
+
const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
|
|
47
|
+
const collForEach = (coll, cb) => coll?.forEach(cb);
|
|
48
|
+
const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
|
|
49
|
+
|
|
50
|
+
const object = Object;
|
|
51
|
+
const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
|
|
52
|
+
const isObject = (obj) =>
|
|
53
|
+
!isNullish(obj) &&
|
|
54
|
+
ifNotNullish(
|
|
55
|
+
getPrototypeOf(obj),
|
|
56
|
+
(objPrototype) =>
|
|
57
|
+
objPrototype == object.prototype ||
|
|
58
|
+
isNullish(getPrototypeOf(objPrototype)),
|
|
59
|
+
|
|
60
|
+
/* istanbul ignore next */
|
|
61
|
+
() => true,
|
|
62
|
+
);
|
|
63
|
+
const objIds = object.keys;
|
|
64
|
+
const objFreeze = object.freeze;
|
|
65
|
+
const objSet = (obj, id, value) => {
|
|
66
|
+
object.defineProperty(obj, id, {
|
|
67
|
+
configurable: true,
|
|
68
|
+
enumerable: true,
|
|
69
|
+
value,
|
|
70
|
+
writable: true,
|
|
71
|
+
});
|
|
72
|
+
return value;
|
|
73
|
+
};
|
|
74
|
+
const objNew = (entries = []) => {
|
|
75
|
+
const obj = object.create(null);
|
|
76
|
+
arrayForEach(entries, ([id, value]) => objSet(obj, id, value));
|
|
77
|
+
return obj;
|
|
78
|
+
};
|
|
79
|
+
const objForEach = (obj, cb) =>
|
|
80
|
+
arrayForEach(objIds(obj), (id) => cb(obj[id], id));
|
|
81
|
+
const objMap = (obj, cb) => {
|
|
82
|
+
const mapped = objNew();
|
|
83
|
+
objForEach(obj, (value, id) => objSet(mapped, id, cb(value, id)));
|
|
84
|
+
return mapped;
|
|
85
|
+
};
|
|
86
|
+
const objSize = (obj) => size(objIds(obj));
|
|
87
|
+
const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
|
|
88
|
+
|
|
89
|
+
const map = Map;
|
|
90
|
+
const mapNew = (entries) => new map(entries);
|
|
91
|
+
const mapGet = (map2, key) => map2?.get(key);
|
|
92
|
+
const mapSet = (map2, key, value) =>
|
|
93
|
+
isUndefined(value) ? (collDel(map2, key), map2) : map2?.set(key, value);
|
|
94
|
+
const mapEnsure = (map2, key, getDefaultValue, hadExistingValue) => {
|
|
95
|
+
let value = mapGet(map2, key);
|
|
96
|
+
if (collHas(map2, key)) {
|
|
97
|
+
hadExistingValue?.(value);
|
|
98
|
+
} else {
|
|
99
|
+
mapSet(map2, key, (value = getDefaultValue()));
|
|
100
|
+
}
|
|
101
|
+
return value;
|
|
102
|
+
};
|
|
103
|
+
const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
|
|
104
|
+
ifNotUndefined(
|
|
105
|
+
(ensureLeaf ? mapEnsure : mapGet)(
|
|
106
|
+
node,
|
|
107
|
+
path[p],
|
|
108
|
+
p > size(path) - 2 ? ensureLeaf : mapNew,
|
|
109
|
+
),
|
|
110
|
+
(nodeOrLeaf) => {
|
|
111
|
+
if (p > size(path) - 2) {
|
|
112
|
+
if (pruneLeaf?.(nodeOrLeaf)) {
|
|
113
|
+
mapSet(node, path[p]);
|
|
114
|
+
}
|
|
115
|
+
return nodeOrLeaf;
|
|
116
|
+
}
|
|
117
|
+
const leaf = visitTree(nodeOrLeaf, path, ensureLeaf, pruneLeaf, p + 1);
|
|
118
|
+
if (collIsEmpty(nodeOrLeaf)) {
|
|
119
|
+
mapSet(node, path[p]);
|
|
120
|
+
}
|
|
121
|
+
return leaf;
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const MASK6 = 63;
|
|
126
|
+
const ENCODE = strSplit(
|
|
127
|
+
'-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz',
|
|
128
|
+
);
|
|
129
|
+
mapNew(arrayMap(ENCODE, (char, index) => [char, index]));
|
|
130
|
+
const encode = (num) => ENCODE[num & MASK6];
|
|
131
|
+
const getRandomValues = GLOBAL.crypto
|
|
132
|
+
? (array) => GLOBAL.crypto.getRandomValues(array)
|
|
133
|
+
: /* istanbul ignore next */
|
|
134
|
+
(array) => arrayMap(array, () => mathFloor(mathRandom() * 256));
|
|
135
|
+
const getUniqueId = (length = 16) =>
|
|
136
|
+
arrayReduce(
|
|
137
|
+
getRandomValues(new Uint8Array(length)),
|
|
138
|
+
(uniqueId, number) => uniqueId + encode(number),
|
|
139
|
+
EMPTY_STRING,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const jsonString = JSON.stringify;
|
|
143
|
+
const jsonParse = JSON.parse;
|
|
144
|
+
const jsonStringWithUndefined = (obj) =>
|
|
145
|
+
jsonString(obj, (_key, value) => (isUndefined(value) ? UNDEFINED : value));
|
|
146
|
+
const jsonParseWithUndefined = (str) =>
|
|
147
|
+
// JSON.parse reviver removes properties with undefined values
|
|
148
|
+
replaceUndefinedString(jsonParse(str));
|
|
149
|
+
const replaceUndefinedString = (obj) =>
|
|
150
|
+
obj === UNDEFINED
|
|
151
|
+
? void 0
|
|
152
|
+
: isArray(obj)
|
|
153
|
+
? arrayMap(obj, replaceUndefinedString)
|
|
154
|
+
: isObject(obj)
|
|
155
|
+
? objMap(obj, replaceUndefinedString)
|
|
156
|
+
: obj;
|
|
157
|
+
|
|
158
|
+
const ERROR_STORE_TYPE = 0;
|
|
159
|
+
const ERROR_CONTENT = 1;
|
|
160
|
+
const errorNew = (code, details) =>
|
|
161
|
+
new Error(
|
|
162
|
+
TINYBASE +
|
|
163
|
+
':' +
|
|
164
|
+
code +
|
|
165
|
+
(isUndefined(details)
|
|
166
|
+
? EMPTY_STRING
|
|
167
|
+
: /* istanbul ignore next */
|
|
168
|
+
':' + details),
|
|
169
|
+
);
|
|
170
|
+
const errorThrow = (code, details) => {
|
|
171
|
+
throw errorNew(code, details);
|
|
172
|
+
};
|
|
173
|
+
const tryCatch = async (action, onError) => {
|
|
174
|
+
try {
|
|
175
|
+
return await action();
|
|
176
|
+
} catch (error) {
|
|
177
|
+
/* istanbul ignore next */
|
|
178
|
+
onError?.(error);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const tryCatchIgnore = (action, onIgnoredError) =>
|
|
182
|
+
tryCatch(action, (error) => void tryCatch(() => onIgnoredError?.(error)));
|
|
183
|
+
const tryCatchSync = (action, onError) => {
|
|
184
|
+
try {
|
|
185
|
+
return action();
|
|
186
|
+
} catch (error) {
|
|
187
|
+
onError?.(error);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
const tryFinally = (action, finallyAction) => {
|
|
191
|
+
try {
|
|
192
|
+
return action();
|
|
193
|
+
} finally {
|
|
194
|
+
finallyAction();
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const tryFinallyAsync = async (action, finallyAction) => {
|
|
198
|
+
try {
|
|
199
|
+
return await action();
|
|
200
|
+
} finally {
|
|
201
|
+
await finallyAction();
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const INTEGER = /^\d+$/;
|
|
206
|
+
const getPoolFunctions = () => {
|
|
207
|
+
const pool = [];
|
|
208
|
+
let nextId = 0;
|
|
209
|
+
return [
|
|
210
|
+
(reuse) => (reuse ? arrayShift(pool) : null) ?? EMPTY_STRING + nextId++,
|
|
211
|
+
(id) => {
|
|
212
|
+
if (test(INTEGER, id) && size(pool) < 1e3) {
|
|
213
|
+
arrayPush(pool, id);
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
];
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const setNew = (entryOrEntries) =>
|
|
220
|
+
new Set(
|
|
221
|
+
isArray(entryOrEntries) || isUndefined(entryOrEntries)
|
|
222
|
+
? entryOrEntries
|
|
223
|
+
: [entryOrEntries],
|
|
224
|
+
);
|
|
225
|
+
const setAdd = (set, value) => set?.add(value);
|
|
226
|
+
|
|
227
|
+
const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
|
|
228
|
+
const leaves = [];
|
|
229
|
+
const deep = (node, p) =>
|
|
230
|
+
p == size(path)
|
|
231
|
+
? arrayPush(leaves, node)
|
|
232
|
+
: isNull(path[p])
|
|
233
|
+
? collForEach(node, (node2) => deep(node2, p + 1))
|
|
234
|
+
: arrayForEach([path[p], null], (id) => deep(mapGet(node, id), p + 1));
|
|
235
|
+
deep(deepIdSet, 0);
|
|
236
|
+
return leaves;
|
|
237
|
+
};
|
|
238
|
+
const getListenerFunctions = (getThing) => {
|
|
239
|
+
let thing;
|
|
240
|
+
const [getId, releaseId] = getPoolFunctions();
|
|
241
|
+
const allListeners = mapNew();
|
|
242
|
+
const addListener = (
|
|
243
|
+
listener,
|
|
244
|
+
idSetNode,
|
|
245
|
+
path,
|
|
246
|
+
pathGetters = [],
|
|
247
|
+
extraArgsGetter = () => [],
|
|
248
|
+
) => {
|
|
249
|
+
thing ??= getThing();
|
|
250
|
+
const id = getId(1);
|
|
251
|
+
mapSet(allListeners, id, [
|
|
252
|
+
listener,
|
|
253
|
+
idSetNode,
|
|
254
|
+
path,
|
|
255
|
+
pathGetters,
|
|
256
|
+
extraArgsGetter,
|
|
257
|
+
]);
|
|
258
|
+
setAdd(visitTree(idSetNode, path ?? [EMPTY_STRING], setNew), id);
|
|
259
|
+
return id;
|
|
260
|
+
};
|
|
261
|
+
const callListenersImpl = (continueAfterError, idSetNode, ids, extraArgs) => {
|
|
262
|
+
let errorToThrow;
|
|
263
|
+
let failed = false;
|
|
264
|
+
arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
|
|
265
|
+
collForEach(set, (id) => {
|
|
266
|
+
const callListener2 = () =>
|
|
267
|
+
mapGet(allListeners, id)[0](thing, ...(ids ?? []), ...extraArgs);
|
|
268
|
+
if (continueAfterError) {
|
|
269
|
+
tryCatchSync(callListener2, (error) => {
|
|
270
|
+
if (!failed) {
|
|
271
|
+
errorToThrow = error;
|
|
272
|
+
}
|
|
273
|
+
failed = true;
|
|
274
|
+
});
|
|
275
|
+
} else {
|
|
276
|
+
callListener2();
|
|
277
|
+
}
|
|
278
|
+
}),
|
|
279
|
+
);
|
|
280
|
+
if (failed) {
|
|
281
|
+
throw errorToThrow;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const callListeners = (idSetNode, ids, ...extraArgs) =>
|
|
285
|
+
callListenersImpl(false, idSetNode, ids, extraArgs);
|
|
286
|
+
const callListenersThenThrow = (idSetNode, ids, ...extraArgs) =>
|
|
287
|
+
callListenersImpl(true, idSetNode, ids, extraArgs);
|
|
288
|
+
const delListener = (id) =>
|
|
289
|
+
ifNotUndefined(mapGet(allListeners, id), ([, idSetNode, idOrNulls]) => {
|
|
290
|
+
visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], void 0, (idSet) => {
|
|
291
|
+
collDel(idSet, id);
|
|
292
|
+
return collIsEmpty(idSet) ? 1 : 0;
|
|
293
|
+
});
|
|
294
|
+
mapSet(allListeners, id);
|
|
295
|
+
releaseId(id);
|
|
296
|
+
return idOrNulls;
|
|
297
|
+
});
|
|
298
|
+
const callListener = (id) =>
|
|
299
|
+
ifNotUndefined(
|
|
300
|
+
mapGet(allListeners, id),
|
|
301
|
+
([listener, , path = [], pathGetters, extraArgsGetter]) => {
|
|
302
|
+
const callWithIds = (...ids) => {
|
|
303
|
+
const index = size(ids);
|
|
304
|
+
if (index == size(path)) {
|
|
305
|
+
listener(thing, ...ids, ...extraArgsGetter(ids));
|
|
306
|
+
} else if (isNull(path[index])) {
|
|
307
|
+
arrayForEach(pathGetters[index]?.(...ids) ?? [], (id2) =>
|
|
308
|
+
callWithIds(...ids, id2),
|
|
309
|
+
);
|
|
310
|
+
} else {
|
|
311
|
+
callWithIds(...ids, path[index]);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
callWithIds();
|
|
315
|
+
},
|
|
316
|
+
);
|
|
317
|
+
return [
|
|
318
|
+
addListener,
|
|
319
|
+
callListeners,
|
|
320
|
+
delListener,
|
|
321
|
+
callListener,
|
|
322
|
+
callListenersThenThrow,
|
|
323
|
+
];
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const scheduleRunning = mapNew();
|
|
327
|
+
const scheduleActions = mapNew();
|
|
328
|
+
const scheduleReferences = mapNew();
|
|
329
|
+
const getStoreFunctions = (
|
|
330
|
+
persist = 1 /* StoreOnly */,
|
|
331
|
+
store,
|
|
332
|
+
isSynchronizer,
|
|
333
|
+
) =>
|
|
334
|
+
persist != 1 /* StoreOnly */ && store.isMergeable()
|
|
335
|
+
? [
|
|
336
|
+
1,
|
|
337
|
+
store.__[1],
|
|
338
|
+
() => store.__[2](!isSynchronizer),
|
|
339
|
+
([[changedTables], [changedValues]]) =>
|
|
340
|
+
!objIsEmpty(changedTables) || !objIsEmpty(changedValues),
|
|
341
|
+
store.setDefaultContent,
|
|
342
|
+
]
|
|
343
|
+
: persist != 2 /* MergeableStoreOnly */
|
|
344
|
+
? [
|
|
345
|
+
0,
|
|
346
|
+
store._[7],
|
|
347
|
+
store._[8],
|
|
348
|
+
([changedTables, changedValues]) =>
|
|
349
|
+
!objIsEmpty(changedTables) || !objIsEmpty(changedValues),
|
|
350
|
+
store.setContent,
|
|
351
|
+
]
|
|
352
|
+
: errorThrow(ERROR_STORE_TYPE);
|
|
353
|
+
const createCustomPersister = (
|
|
354
|
+
store,
|
|
355
|
+
getPersisted,
|
|
356
|
+
setPersisted,
|
|
357
|
+
addPersisterListener,
|
|
358
|
+
delPersisterListener,
|
|
359
|
+
onIgnoredError,
|
|
360
|
+
persist,
|
|
361
|
+
extra = {},
|
|
362
|
+
isSynchronizer = 0,
|
|
363
|
+
scheduleId = [],
|
|
364
|
+
) => {
|
|
365
|
+
let status = 0; /* Idle */
|
|
366
|
+
let loads = 0;
|
|
367
|
+
let saves = 0;
|
|
368
|
+
let autoLoadHandle;
|
|
369
|
+
let autoLoadPromise;
|
|
370
|
+
let autoLoadGeneration = 0;
|
|
371
|
+
let pendingAutoLoads = 0;
|
|
372
|
+
let pendingScheduledAutoLoads = 0;
|
|
373
|
+
let autoLoadAfterSaveGeneration = 0;
|
|
374
|
+
let autoSaveListenerId;
|
|
375
|
+
let autoSaveGeneration = 0;
|
|
376
|
+
let destroyed = 0;
|
|
377
|
+
let destroying;
|
|
378
|
+
let activeAction;
|
|
379
|
+
const scheduleOwner = {};
|
|
380
|
+
const extraDestroy = extra.destroy;
|
|
381
|
+
mapEnsure(scheduleRunning, scheduleId, () => 0);
|
|
382
|
+
mapEnsure(scheduleActions, scheduleId, () => []);
|
|
383
|
+
mapSet(
|
|
384
|
+
scheduleReferences,
|
|
385
|
+
scheduleId,
|
|
386
|
+
(mapGet(scheduleReferences, scheduleId) ?? 0) + 1,
|
|
387
|
+
);
|
|
388
|
+
const statusListeners = mapNew();
|
|
389
|
+
const [
|
|
390
|
+
isMergeableStore,
|
|
391
|
+
getContent,
|
|
392
|
+
getChanges,
|
|
393
|
+
hasChanges,
|
|
394
|
+
setDefaultContent,
|
|
395
|
+
] = getStoreFunctions(persist, store, isSynchronizer);
|
|
396
|
+
const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
|
|
397
|
+
() => persister,
|
|
398
|
+
);
|
|
399
|
+
const setStatus = (newStatus) => {
|
|
400
|
+
if (newStatus != status) {
|
|
401
|
+
status = newStatus;
|
|
402
|
+
callListeners(statusListeners, void 0, status);
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
const run = async () => {
|
|
406
|
+
/* istanbul ignore else */
|
|
407
|
+
if (!mapGet(scheduleRunning, scheduleId)) {
|
|
408
|
+
mapSet(scheduleRunning, scheduleId, 1);
|
|
409
|
+
const scheduledActions = mapGet(scheduleActions, scheduleId);
|
|
410
|
+
let actionIndex = 0;
|
|
411
|
+
await tryFinallyAsync(
|
|
412
|
+
async () => {
|
|
413
|
+
while (actionIndex < size(scheduledActions)) {
|
|
414
|
+
const scheduledAction = scheduledActions[actionIndex++];
|
|
415
|
+
scheduledAction[2] = void 0;
|
|
416
|
+
await scheduledAction[0]();
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
() => {
|
|
420
|
+
arrayClear(scheduledActions, actionIndex);
|
|
421
|
+
mapSet(scheduleRunning, scheduleId, 0);
|
|
422
|
+
pruneSchedule();
|
|
423
|
+
},
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
const pruneSchedule = () => {
|
|
428
|
+
if (
|
|
429
|
+
!mapGet(scheduleReferences, scheduleId) &&
|
|
430
|
+
!mapGet(scheduleRunning, scheduleId) &&
|
|
431
|
+
isEmpty(mapGet(scheduleActions, scheduleId) ?? [])
|
|
432
|
+
) {
|
|
433
|
+
mapSet(scheduleRunning, scheduleId);
|
|
434
|
+
mapSet(scheduleActions, scheduleId);
|
|
435
|
+
mapSet(scheduleReferences, scheduleId);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
const setContentOrChanges = (contentOrChanges) => {
|
|
439
|
+
(isMergeableStore && isArray(contentOrChanges?.[0])
|
|
440
|
+
? contentOrChanges?.[2] === 1
|
|
441
|
+
? store.__[4]
|
|
442
|
+
: store.__[3]
|
|
443
|
+
: contentOrChanges?.[2] === 1
|
|
444
|
+
? store._[10]
|
|
445
|
+
: store._[9])(contentOrChanges);
|
|
446
|
+
};
|
|
447
|
+
const saveAfterMutated = async () => {
|
|
448
|
+
if (isAutoSaving() && store.__?.[0]?.()) {
|
|
449
|
+
await save();
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
const trackAutoLoadPromise = (newAutoLoadPromise) =>
|
|
453
|
+
tryFinallyAsync(
|
|
454
|
+
() => (autoLoadPromise = newAutoLoadPromise),
|
|
455
|
+
() => {
|
|
456
|
+
if (autoLoadPromise == newAutoLoadPromise) {
|
|
457
|
+
autoLoadPromise = void 0;
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
);
|
|
461
|
+
const load = async (initialContent) => {
|
|
462
|
+
/* istanbul ignore else */
|
|
463
|
+
if (status != 2 /* Saving */) {
|
|
464
|
+
await tryFinallyAsync(
|
|
465
|
+
async () => {
|
|
466
|
+
setStatus(1 /* Loading */);
|
|
467
|
+
loads++;
|
|
468
|
+
await schedule(() =>
|
|
469
|
+
tryCatch(
|
|
470
|
+
async () => {
|
|
471
|
+
const content = await getPersisted();
|
|
472
|
+
if (isArray(content)) {
|
|
473
|
+
setContentOrChanges(content);
|
|
474
|
+
} else if (isUndefined(content) && initialContent) {
|
|
475
|
+
setDefaultContent(initialContent);
|
|
476
|
+
} else if (!isUndefined(content)) {
|
|
477
|
+
errorThrow(ERROR_CONTENT, content);
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
(error) => {
|
|
481
|
+
onIgnoredError?.(error);
|
|
482
|
+
if (initialContent) {
|
|
483
|
+
setDefaultContent(initialContent);
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
),
|
|
487
|
+
);
|
|
488
|
+
},
|
|
489
|
+
() => setStatus(0 /* Idle */),
|
|
490
|
+
);
|
|
491
|
+
await saveAfterMutated();
|
|
492
|
+
}
|
|
493
|
+
return persister;
|
|
494
|
+
};
|
|
495
|
+
const runAutoLoadAfterSave = async () => {
|
|
496
|
+
const generation = autoLoadAfterSaveGeneration;
|
|
497
|
+
autoLoadAfterSaveGeneration = 0;
|
|
498
|
+
if (generation && generation == autoLoadGeneration && !destroyed) {
|
|
499
|
+
if (status == 2 /* Saving */) {
|
|
500
|
+
autoLoadAfterSaveGeneration = generation;
|
|
501
|
+
} else {
|
|
502
|
+
await load();
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
const startAutoLoad = async (initialContent) => {
|
|
507
|
+
const generation = ++autoLoadGeneration;
|
|
508
|
+
let initialLoadPending = true;
|
|
509
|
+
await stopAutoLoad(true);
|
|
510
|
+
if (generation == autoLoadGeneration && !destroyed) {
|
|
511
|
+
const listenerPromise = tryCatch(async () => {
|
|
512
|
+
const handle = await addPersisterListener(async (content, changes) => {
|
|
513
|
+
if (generation == autoLoadGeneration && !destroyed) {
|
|
514
|
+
if (changes || content) {
|
|
515
|
+
const shouldSchedule =
|
|
516
|
+
initialLoadPending ||
|
|
517
|
+
status == 2 /* Saving */ ||
|
|
518
|
+
!!pendingScheduledAutoLoads;
|
|
519
|
+
pendingAutoLoads++;
|
|
520
|
+
if (shouldSchedule) {
|
|
521
|
+
pendingScheduledAutoLoads++;
|
|
522
|
+
}
|
|
523
|
+
await tryFinallyAsync(
|
|
524
|
+
async () => {
|
|
525
|
+
setStatus(1 /* Loading */);
|
|
526
|
+
loads++;
|
|
527
|
+
await (shouldSchedule
|
|
528
|
+
? schedule(() => setContentOrChanges(changes ?? content))
|
|
529
|
+
: tryFinally(
|
|
530
|
+
() => setContentOrChanges(changes ?? content),
|
|
531
|
+
() => setStatus(0 /* Idle */),
|
|
532
|
+
));
|
|
533
|
+
},
|
|
534
|
+
() => {
|
|
535
|
+
if (shouldSchedule) {
|
|
536
|
+
pendingScheduledAutoLoads--;
|
|
537
|
+
}
|
|
538
|
+
if (!--pendingAutoLoads) {
|
|
539
|
+
setStatus(0 /* Idle */);
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
);
|
|
543
|
+
if (!pendingAutoLoads) {
|
|
544
|
+
await saveAfterMutated();
|
|
545
|
+
}
|
|
546
|
+
} else if (status == 2 /* Saving */) {
|
|
547
|
+
autoLoadAfterSaveGeneration = generation;
|
|
548
|
+
} else {
|
|
549
|
+
await load();
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
if (generation == autoLoadGeneration && !destroyed) {
|
|
554
|
+
autoLoadHandle = handle;
|
|
555
|
+
} else if (!isUndefined(handle)) {
|
|
556
|
+
await delPersisterListener(handle);
|
|
557
|
+
}
|
|
558
|
+
}, onIgnoredError);
|
|
559
|
+
await trackAutoLoadPromise(listenerPromise);
|
|
560
|
+
if (generation == autoLoadGeneration && !destroyed) {
|
|
561
|
+
await tryFinallyAsync(
|
|
562
|
+
() => load(initialContent),
|
|
563
|
+
() => {
|
|
564
|
+
initialLoadPending = false;
|
|
565
|
+
},
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return persister;
|
|
570
|
+
};
|
|
571
|
+
const stopAutoLoad = async (keepGeneration = false) => {
|
|
572
|
+
autoLoadAfterSaveGeneration = 0;
|
|
573
|
+
if (!keepGeneration) {
|
|
574
|
+
autoLoadGeneration++;
|
|
575
|
+
}
|
|
576
|
+
const listenerPromise = autoLoadPromise;
|
|
577
|
+
const handle = autoLoadHandle;
|
|
578
|
+
autoLoadHandle = void 0;
|
|
579
|
+
await trackAutoLoadPromise(
|
|
580
|
+
tryFinallyAsync(
|
|
581
|
+
async () => {
|
|
582
|
+
await listenerPromise;
|
|
583
|
+
},
|
|
584
|
+
async () => {
|
|
585
|
+
if (!isUndefined(handle)) {
|
|
586
|
+
await tryCatch(() => delPersisterListener(handle), onIgnoredError);
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
),
|
|
590
|
+
);
|
|
591
|
+
return persister;
|
|
592
|
+
};
|
|
593
|
+
const isAutoLoading = () => !isUndefined(autoLoadHandle);
|
|
594
|
+
const save = async (changes) => {
|
|
595
|
+
/* istanbul ignore else */
|
|
596
|
+
if (status != 1 /* Loading */) {
|
|
597
|
+
await tryFinallyAsync(
|
|
598
|
+
() =>
|
|
599
|
+
tryFinallyAsync(
|
|
600
|
+
async () => {
|
|
601
|
+
setStatus(2 /* Saving */);
|
|
602
|
+
saves++;
|
|
603
|
+
await schedule(() =>
|
|
604
|
+
tryCatch(
|
|
605
|
+
() => setPersisted(getContent, changes),
|
|
606
|
+
onIgnoredError,
|
|
607
|
+
),
|
|
608
|
+
);
|
|
609
|
+
},
|
|
610
|
+
() => setStatus(0 /* Idle */),
|
|
611
|
+
),
|
|
612
|
+
runAutoLoadAfterSave,
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
return persister;
|
|
616
|
+
};
|
|
617
|
+
const startAutoSave = async () => {
|
|
618
|
+
const generation = ++autoSaveGeneration;
|
|
619
|
+
await stopAutoSave(true);
|
|
620
|
+
if (generation == autoSaveGeneration && !destroyed) {
|
|
621
|
+
await save();
|
|
622
|
+
if (generation == autoSaveGeneration && !destroyed) {
|
|
623
|
+
autoSaveListenerId = store.addDidFinishTransactionListener(() => {
|
|
624
|
+
if (generation == autoSaveGeneration && !destroyed) {
|
|
625
|
+
const changes = getChanges();
|
|
626
|
+
if (hasChanges(changes)) {
|
|
627
|
+
void tryCatch(() => save(changes));
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return persister;
|
|
634
|
+
};
|
|
635
|
+
const stopAutoSave = async (keepGeneration = false) => {
|
|
636
|
+
if (!keepGeneration) {
|
|
637
|
+
autoSaveGeneration++;
|
|
638
|
+
}
|
|
639
|
+
const listenerId = autoSaveListenerId;
|
|
640
|
+
autoSaveListenerId = void 0;
|
|
641
|
+
if (!isUndefined(listenerId)) {
|
|
642
|
+
store.delListener(listenerId);
|
|
643
|
+
}
|
|
644
|
+
return persister;
|
|
645
|
+
};
|
|
646
|
+
const isAutoSaving = () => !isUndefined(autoSaveListenerId);
|
|
647
|
+
const startAutoPersisting = async (
|
|
648
|
+
initialContent,
|
|
649
|
+
startSaveFirst = false,
|
|
650
|
+
) => {
|
|
651
|
+
const [call1, call2, stop1, stop2] = startSaveFirst
|
|
652
|
+
? [startAutoSave, startAutoLoad, stopAutoSave, stopAutoLoad]
|
|
653
|
+
: [startAutoLoad, startAutoSave, stopAutoLoad, stopAutoSave];
|
|
654
|
+
const start1 = call1(initialContent);
|
|
655
|
+
const generation1 = startSaveFirst
|
|
656
|
+
? autoSaveGeneration
|
|
657
|
+
: autoLoadGeneration;
|
|
658
|
+
await start1;
|
|
659
|
+
const start2 = call2(initialContent);
|
|
660
|
+
const generation2 = startSaveFirst
|
|
661
|
+
? autoLoadGeneration
|
|
662
|
+
: autoSaveGeneration;
|
|
663
|
+
try {
|
|
664
|
+
await start2;
|
|
665
|
+
} catch (error) {
|
|
666
|
+
if (
|
|
667
|
+
generation2 ==
|
|
668
|
+
(startSaveFirst ? autoLoadGeneration : autoSaveGeneration)
|
|
669
|
+
) {
|
|
670
|
+
await tryCatchIgnore(stop2);
|
|
671
|
+
}
|
|
672
|
+
if (
|
|
673
|
+
generation1 ==
|
|
674
|
+
(startSaveFirst ? autoSaveGeneration : autoLoadGeneration)
|
|
675
|
+
) {
|
|
676
|
+
await tryCatchIgnore(stop1);
|
|
677
|
+
}
|
|
678
|
+
throw error;
|
|
679
|
+
}
|
|
680
|
+
return persister;
|
|
681
|
+
};
|
|
682
|
+
const stopAutoPersisting = async (stopSaveFirst = false) => {
|
|
683
|
+
const [call1, call2] = stopSaveFirst
|
|
684
|
+
? [stopAutoSave, stopAutoLoad]
|
|
685
|
+
: [stopAutoLoad, stopAutoSave];
|
|
686
|
+
await tryFinallyAsync(
|
|
687
|
+
() => call1(),
|
|
688
|
+
async () => {
|
|
689
|
+
await call2();
|
|
690
|
+
},
|
|
691
|
+
);
|
|
692
|
+
return persister;
|
|
693
|
+
};
|
|
694
|
+
const getStatus = () => status;
|
|
695
|
+
const addStatusListener = (listener) =>
|
|
696
|
+
addListener(listener, statusListeners);
|
|
697
|
+
const delListener = (listenerId) => {
|
|
698
|
+
delListenerImpl(listenerId);
|
|
699
|
+
return store;
|
|
700
|
+
};
|
|
701
|
+
const schedule = async (...actions) => {
|
|
702
|
+
let failed = false;
|
|
703
|
+
let firstError;
|
|
704
|
+
const completion = promiseNew((resolve) =>
|
|
705
|
+
!isEmpty(actions)
|
|
706
|
+
? arrayPush(
|
|
707
|
+
mapGet(scheduleActions, scheduleId),
|
|
708
|
+
...arrayMap(actions, (action, index) => {
|
|
709
|
+
const last = index == size(actions) - 1;
|
|
710
|
+
return [
|
|
711
|
+
async () => {
|
|
712
|
+
let completeActiveAction;
|
|
713
|
+
activeAction = promiseNew(
|
|
714
|
+
(resolve2) => (completeActiveAction = resolve2),
|
|
715
|
+
);
|
|
716
|
+
await tryFinallyAsync(
|
|
717
|
+
async () => {
|
|
718
|
+
try {
|
|
719
|
+
await tryCatch(action, onIgnoredError);
|
|
720
|
+
} catch (error) {
|
|
721
|
+
if (!failed) {
|
|
722
|
+
failed = true;
|
|
723
|
+
firstError = error;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (last) {
|
|
727
|
+
resolve();
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
() => {
|
|
731
|
+
activeAction = void 0;
|
|
732
|
+
completeActiveAction();
|
|
733
|
+
},
|
|
734
|
+
);
|
|
735
|
+
},
|
|
736
|
+
last ? resolve : void 0,
|
|
737
|
+
scheduleOwner,
|
|
738
|
+
];
|
|
739
|
+
}),
|
|
740
|
+
)
|
|
741
|
+
: resolve(),
|
|
742
|
+
);
|
|
743
|
+
await run();
|
|
744
|
+
await completion;
|
|
745
|
+
if (failed) {
|
|
746
|
+
throw firstError;
|
|
747
|
+
}
|
|
748
|
+
return persister;
|
|
749
|
+
};
|
|
750
|
+
const getStore = () => store;
|
|
751
|
+
const destroy = async () => {
|
|
752
|
+
if (isUndefined(destroying)) {
|
|
753
|
+
destroyed = 1;
|
|
754
|
+
destroying = (async () => {
|
|
755
|
+
const scheduledActions = mapGet(scheduleActions, scheduleId);
|
|
756
|
+
const remainingActions = arrayFilter(
|
|
757
|
+
scheduledActions,
|
|
758
|
+
([, complete, owner]) => {
|
|
759
|
+
if (owner == scheduleOwner) {
|
|
760
|
+
complete?.();
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
return true;
|
|
764
|
+
},
|
|
765
|
+
);
|
|
766
|
+
const actionToAwait = activeAction;
|
|
767
|
+
arrayClear(scheduledActions);
|
|
768
|
+
arrayPush(scheduledActions, ...remainingActions);
|
|
769
|
+
await tryFinallyAsync(
|
|
770
|
+
() =>
|
|
771
|
+
tryFinallyAsync(
|
|
772
|
+
() => tryFinallyAsync(stopAutoPersisting, () => actionToAwait),
|
|
773
|
+
() => extraDestroy?.(),
|
|
774
|
+
),
|
|
775
|
+
() => {
|
|
776
|
+
const references =
|
|
777
|
+
(mapGet(scheduleReferences, scheduleId) ?? 1) - 1;
|
|
778
|
+
mapSet(scheduleReferences, scheduleId, references || void 0);
|
|
779
|
+
pruneSchedule();
|
|
780
|
+
},
|
|
781
|
+
);
|
|
782
|
+
})();
|
|
783
|
+
}
|
|
784
|
+
await destroying;
|
|
785
|
+
return persister;
|
|
786
|
+
};
|
|
787
|
+
const getStats = () => ({loads, saves});
|
|
788
|
+
const persister = {
|
|
789
|
+
load,
|
|
790
|
+
startAutoLoad,
|
|
791
|
+
stopAutoLoad,
|
|
792
|
+
isAutoLoading,
|
|
793
|
+
save,
|
|
794
|
+
startAutoSave,
|
|
795
|
+
stopAutoSave,
|
|
796
|
+
isAutoSaving,
|
|
797
|
+
startAutoPersisting,
|
|
798
|
+
stopAutoPersisting,
|
|
799
|
+
getStatus,
|
|
800
|
+
addStatusListener,
|
|
801
|
+
delListener,
|
|
802
|
+
schedule,
|
|
803
|
+
getStore,
|
|
804
|
+
getStats,
|
|
805
|
+
...extra,
|
|
806
|
+
destroy,
|
|
807
|
+
};
|
|
808
|
+
return objFreeze(persister);
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
const SINGLE_ROW_ID = '_';
|
|
812
|
+
const DEFAULT_ROW_ID_COLUMN_NAME = '_id';
|
|
813
|
+
|
|
814
|
+
const STORE_COLUMN_NAME = 'store';
|
|
815
|
+
const PUBLIC_SCHEMA = 'public';
|
|
816
|
+
const createSupabasePersister = (
|
|
817
|
+
store,
|
|
818
|
+
supabase,
|
|
819
|
+
configOrStoreTableName,
|
|
820
|
+
onIgnoredError,
|
|
821
|
+
) => {
|
|
822
|
+
const config = isString(configOrStoreTableName)
|
|
823
|
+
? {storeTableName: configOrStoreTableName}
|
|
824
|
+
: (configOrStoreTableName ?? {});
|
|
825
|
+
const storeTableName = config.storeTableName ?? TINYBASE;
|
|
826
|
+
const storeIdColumnName =
|
|
827
|
+
config.storeIdColumnName ?? DEFAULT_ROW_ID_COLUMN_NAME;
|
|
828
|
+
const storeColumnName = config.storeColumnName ?? STORE_COLUMN_NAME;
|
|
829
|
+
const {autoLoadIntervalSeconds} = config;
|
|
830
|
+
const getPersisted = async () => {
|
|
831
|
+
const {data, error} = await supabase
|
|
832
|
+
.from(storeTableName)
|
|
833
|
+
.select(storeColumnName)
|
|
834
|
+
.eq(storeIdColumnName, SINGLE_ROW_ID)
|
|
835
|
+
.maybeSingle();
|
|
836
|
+
if (error) {
|
|
837
|
+
throw error;
|
|
838
|
+
}
|
|
839
|
+
return jsonParseWithUndefined(data?.[storeColumnName] ?? 'null');
|
|
840
|
+
};
|
|
841
|
+
const setPersisted = async (getContent) => {
|
|
842
|
+
const {error} = await supabase.from(storeTableName).upsert(
|
|
843
|
+
{
|
|
844
|
+
[storeIdColumnName]: SINGLE_ROW_ID,
|
|
845
|
+
[storeColumnName]: jsonStringWithUndefined(getContent() ?? null),
|
|
846
|
+
},
|
|
847
|
+
{onConflict: storeIdColumnName},
|
|
848
|
+
);
|
|
849
|
+
if (error) {
|
|
850
|
+
throw error;
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
const addPersisterListener = (listener) => [
|
|
854
|
+
supabase
|
|
855
|
+
.channel(TINYBASE + '_' + storeTableName + '_' + getUniqueId())
|
|
856
|
+
.on(
|
|
857
|
+
'postgres_changes',
|
|
858
|
+
{event: '*', schema: PUBLIC_SCHEMA, table: storeTableName},
|
|
859
|
+
() => void listener(),
|
|
860
|
+
)
|
|
861
|
+
.subscribe((_status, error) => (error ? onIgnoredError?.(error) : 0)),
|
|
862
|
+
isUndefined(autoLoadIntervalSeconds)
|
|
863
|
+
? void 0
|
|
864
|
+
: startInterval(() => void listener(), autoLoadIntervalSeconds),
|
|
865
|
+
];
|
|
866
|
+
const delPersisterListener = async ([channel, interval]) => {
|
|
867
|
+
stopInterval(interval);
|
|
868
|
+
await supabase.removeChannel(channel);
|
|
869
|
+
};
|
|
870
|
+
return createCustomPersister(
|
|
871
|
+
store,
|
|
872
|
+
getPersisted,
|
|
873
|
+
setPersisted,
|
|
874
|
+
addPersisterListener,
|
|
875
|
+
delPersisterListener,
|
|
876
|
+
onIgnoredError,
|
|
877
|
+
3,
|
|
878
|
+
// StoreOrMergeableStore,
|
|
879
|
+
{getSupabase: () => supabase},
|
|
880
|
+
);
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
export {createSupabasePersister};
|