tinybase 7.3.2 → 7.3.4

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 (249) hide show
  1. package/checkpoints/index.js +12 -11
  2. package/checkpoints/with-schemas/index.js +12 -11
  3. package/common/index.js +3 -2
  4. package/common/with-schemas/index.js +3 -2
  5. package/index.js +92 -64
  6. package/indexes/index.js +13 -12
  7. package/indexes/with-schemas/index.js +13 -12
  8. package/mergeable-store/index.js +92 -64
  9. package/mergeable-store/with-schemas/index.js +92 -64
  10. package/metrics/index.js +13 -12
  11. package/metrics/with-schemas/index.js +13 -12
  12. package/min/checkpoints/index.js +1 -1
  13. package/min/checkpoints/index.js.gz +0 -0
  14. package/min/checkpoints/with-schemas/index.js +1 -1
  15. package/min/checkpoints/with-schemas/index.js.gz +0 -0
  16. package/min/common/index.js +1 -1
  17. package/min/common/index.js.gz +0 -0
  18. package/min/common/with-schemas/index.js +1 -1
  19. package/min/common/with-schemas/index.js.gz +0 -0
  20. package/min/index.js +1 -1
  21. package/min/index.js.gz +0 -0
  22. package/min/indexes/index.js +1 -1
  23. package/min/indexes/index.js.gz +0 -0
  24. package/min/indexes/with-schemas/index.js +1 -1
  25. package/min/indexes/with-schemas/index.js.gz +0 -0
  26. package/min/mergeable-store/index.js +1 -1
  27. package/min/mergeable-store/index.js.gz +0 -0
  28. package/min/mergeable-store/with-schemas/index.js +1 -1
  29. package/min/mergeable-store/with-schemas/index.js.gz +0 -0
  30. package/min/metrics/index.js +1 -1
  31. package/min/metrics/index.js.gz +0 -0
  32. package/min/metrics/with-schemas/index.js +1 -1
  33. package/min/metrics/with-schemas/index.js.gz +0 -0
  34. package/min/omni/index.js +1 -1
  35. package/min/omni/index.js.gz +0 -0
  36. package/min/omni/with-schemas/index.js +1 -1
  37. package/min/omni/with-schemas/index.js.gz +0 -0
  38. package/min/persisters/index.js +1 -1
  39. package/min/persisters/index.js.gz +0 -0
  40. package/min/persisters/persister-automerge/index.js +1 -1
  41. package/min/persisters/persister-automerge/index.js.gz +0 -0
  42. package/min/persisters/persister-automerge/with-schemas/index.js +1 -1
  43. package/min/persisters/persister-automerge/with-schemas/index.js.gz +0 -0
  44. package/min/persisters/persister-browser/index.js +1 -1
  45. package/min/persisters/persister-browser/index.js.gz +0 -0
  46. package/min/persisters/persister-browser/with-schemas/index.js +1 -1
  47. package/min/persisters/persister-browser/with-schemas/index.js.gz +0 -0
  48. package/min/persisters/persister-cr-sqlite-wasm/index.js +1 -1
  49. package/min/persisters/persister-cr-sqlite-wasm/index.js.gz +0 -0
  50. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +1 -1
  51. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js.gz +0 -0
  52. package/min/persisters/persister-durable-object-sql-storage/index.js +1 -1
  53. package/min/persisters/persister-durable-object-sql-storage/index.js.gz +0 -0
  54. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js +1 -1
  55. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js.gz +0 -0
  56. package/min/persisters/persister-durable-object-storage/index.js +1 -1
  57. package/min/persisters/persister-durable-object-storage/index.js.gz +0 -0
  58. package/min/persisters/persister-durable-object-storage/with-schemas/index.js +1 -1
  59. package/min/persisters/persister-durable-object-storage/with-schemas/index.js.gz +0 -0
  60. package/min/persisters/persister-electric-sql/index.js +1 -1
  61. package/min/persisters/persister-electric-sql/index.js.gz +0 -0
  62. package/min/persisters/persister-electric-sql/with-schemas/index.js +1 -1
  63. package/min/persisters/persister-electric-sql/with-schemas/index.js.gz +0 -0
  64. package/min/persisters/persister-expo-sqlite/index.js +1 -1
  65. package/min/persisters/persister-expo-sqlite/index.js.gz +0 -0
  66. package/min/persisters/persister-expo-sqlite/with-schemas/index.js +1 -1
  67. package/min/persisters/persister-expo-sqlite/with-schemas/index.js.gz +0 -0
  68. package/min/persisters/persister-file/index.js +1 -1
  69. package/min/persisters/persister-file/index.js.gz +0 -0
  70. package/min/persisters/persister-file/with-schemas/index.js +1 -1
  71. package/min/persisters/persister-file/with-schemas/index.js.gz +0 -0
  72. package/min/persisters/persister-indexed-db/index.js +1 -1
  73. package/min/persisters/persister-indexed-db/index.js.gz +0 -0
  74. package/min/persisters/persister-indexed-db/with-schemas/index.js +1 -1
  75. package/min/persisters/persister-indexed-db/with-schemas/index.js.gz +0 -0
  76. package/min/persisters/persister-libsql/index.js +1 -1
  77. package/min/persisters/persister-libsql/index.js.gz +0 -0
  78. package/min/persisters/persister-libsql/with-schemas/index.js +1 -1
  79. package/min/persisters/persister-libsql/with-schemas/index.js.gz +0 -0
  80. package/min/persisters/persister-partykit-client/index.js +1 -1
  81. package/min/persisters/persister-partykit-client/index.js.gz +0 -0
  82. package/min/persisters/persister-partykit-client/with-schemas/index.js +1 -1
  83. package/min/persisters/persister-partykit-client/with-schemas/index.js.gz +0 -0
  84. package/min/persisters/persister-partykit-server/index.js +1 -1
  85. package/min/persisters/persister-partykit-server/index.js.gz +0 -0
  86. package/min/persisters/persister-partykit-server/with-schemas/index.js +1 -1
  87. package/min/persisters/persister-partykit-server/with-schemas/index.js.gz +0 -0
  88. package/min/persisters/persister-pglite/index.js +1 -1
  89. package/min/persisters/persister-pglite/index.js.gz +0 -0
  90. package/min/persisters/persister-pglite/with-schemas/index.js +1 -1
  91. package/min/persisters/persister-pglite/with-schemas/index.js.gz +0 -0
  92. package/min/persisters/persister-postgres/index.js +1 -1
  93. package/min/persisters/persister-postgres/index.js.gz +0 -0
  94. package/min/persisters/persister-postgres/with-schemas/index.js +1 -1
  95. package/min/persisters/persister-postgres/with-schemas/index.js.gz +0 -0
  96. package/min/persisters/persister-powersync/index.js +1 -1
  97. package/min/persisters/persister-powersync/index.js.gz +0 -0
  98. package/min/persisters/persister-powersync/with-schemas/index.js +1 -1
  99. package/min/persisters/persister-powersync/with-schemas/index.js.gz +0 -0
  100. package/min/persisters/persister-react-native-mmkv/index.js +1 -1
  101. package/min/persisters/persister-react-native-mmkv/index.js.gz +0 -0
  102. package/min/persisters/persister-react-native-mmkv/with-schemas/index.js +1 -1
  103. package/min/persisters/persister-react-native-mmkv/with-schemas/index.js.gz +0 -0
  104. package/min/persisters/persister-react-native-sqlite/index.js +1 -1
  105. package/min/persisters/persister-react-native-sqlite/index.js.gz +0 -0
  106. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js +1 -1
  107. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js.gz +0 -0
  108. package/min/persisters/persister-remote/index.js +1 -1
  109. package/min/persisters/persister-remote/index.js.gz +0 -0
  110. package/min/persisters/persister-remote/with-schemas/index.js +1 -1
  111. package/min/persisters/persister-remote/with-schemas/index.js.gz +0 -0
  112. package/min/persisters/persister-sqlite-bun/index.js +1 -1
  113. package/min/persisters/persister-sqlite-bun/index.js.gz +0 -0
  114. package/min/persisters/persister-sqlite-bun/with-schemas/index.js +1 -1
  115. package/min/persisters/persister-sqlite-bun/with-schemas/index.js.gz +0 -0
  116. package/min/persisters/persister-sqlite-wasm/index.js +1 -1
  117. package/min/persisters/persister-sqlite-wasm/index.js.gz +0 -0
  118. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js +1 -1
  119. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js.gz +0 -0
  120. package/min/persisters/persister-sqlite3/index.js +1 -1
  121. package/min/persisters/persister-sqlite3/index.js.gz +0 -0
  122. package/min/persisters/persister-sqlite3/with-schemas/index.js +1 -1
  123. package/min/persisters/persister-sqlite3/with-schemas/index.js.gz +0 -0
  124. package/min/persisters/persister-yjs/index.js +1 -1
  125. package/min/persisters/persister-yjs/index.js.gz +0 -0
  126. package/min/persisters/persister-yjs/with-schemas/index.js +1 -1
  127. package/min/persisters/persister-yjs/with-schemas/index.js.gz +0 -0
  128. package/min/persisters/with-schemas/index.js +1 -1
  129. package/min/persisters/with-schemas/index.js.gz +0 -0
  130. package/min/queries/index.js +1 -1
  131. package/min/queries/index.js.gz +0 -0
  132. package/min/queries/with-schemas/index.js +1 -1
  133. package/min/queries/with-schemas/index.js.gz +0 -0
  134. package/min/relationships/index.js +1 -1
  135. package/min/relationships/index.js.gz +0 -0
  136. package/min/relationships/with-schemas/index.js +1 -1
  137. package/min/relationships/with-schemas/index.js.gz +0 -0
  138. package/min/store/index.js +1 -1
  139. package/min/store/index.js.gz +0 -0
  140. package/min/store/with-schemas/index.js +1 -1
  141. package/min/store/with-schemas/index.js.gz +0 -0
  142. package/min/synchronizers/index.js +1 -1
  143. package/min/synchronizers/index.js.gz +0 -0
  144. package/min/synchronizers/synchronizer-broadcast-channel/index.js +1 -1
  145. package/min/synchronizers/synchronizer-broadcast-channel/index.js.gz +0 -0
  146. package/min/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js +1 -1
  147. package/min/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js.gz +0 -0
  148. package/min/synchronizers/synchronizer-local/index.js +1 -1
  149. package/min/synchronizers/synchronizer-local/index.js.gz +0 -0
  150. package/min/synchronizers/synchronizer-local/with-schemas/index.js +1 -1
  151. package/min/synchronizers/synchronizer-local/with-schemas/index.js.gz +0 -0
  152. package/min/synchronizers/synchronizer-ws-client/index.js +1 -1
  153. package/min/synchronizers/synchronizer-ws-client/index.js.gz +0 -0
  154. package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js +1 -1
  155. package/min/synchronizers/synchronizer-ws-client/with-schemas/index.js.gz +0 -0
  156. package/min/synchronizers/synchronizer-ws-server/index.js +1 -1
  157. package/min/synchronizers/synchronizer-ws-server/index.js.gz +0 -0
  158. package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js +1 -1
  159. package/min/synchronizers/synchronizer-ws-server/with-schemas/index.js.gz +0 -0
  160. package/min/synchronizers/synchronizer-ws-server-durable-object/index.js +1 -1
  161. package/min/synchronizers/synchronizer-ws-server-durable-object/index.js.gz +0 -0
  162. package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +1 -1
  163. package/min/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js.gz +0 -0
  164. package/min/synchronizers/synchronizer-ws-server-simple/index.js +1 -1
  165. package/min/synchronizers/synchronizer-ws-server-simple/index.js.gz +0 -0
  166. package/min/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js +1 -1
  167. package/min/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js.gz +0 -0
  168. package/min/synchronizers/with-schemas/index.js +1 -1
  169. package/min/synchronizers/with-schemas/index.js.gz +0 -0
  170. package/min/ui-react-inspector/index.js +1 -1
  171. package/min/ui-react-inspector/index.js.gz +0 -0
  172. package/min/ui-react-inspector/with-schemas/index.js +1 -1
  173. package/min/ui-react-inspector/with-schemas/index.js.gz +0 -0
  174. package/min/with-schemas/index.js +1 -1
  175. package/min/with-schemas/index.js.gz +0 -0
  176. package/omni/index.js +115 -67
  177. package/omni/with-schemas/index.js +115 -67
  178. package/package.json +13 -13
  179. package/persisters/index.js +29 -12
  180. package/persisters/persister-automerge/index.js +17 -9
  181. package/persisters/persister-automerge/with-schemas/index.js +17 -9
  182. package/persisters/persister-browser/index.js +34 -10
  183. package/persisters/persister-browser/with-schemas/index.js +34 -10
  184. package/persisters/persister-cr-sqlite-wasm/index.js +29 -12
  185. package/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +29 -12
  186. package/persisters/persister-durable-object-sql-storage/index.js +29 -12
  187. package/persisters/persister-durable-object-sql-storage/with-schemas/index.js +29 -12
  188. package/persisters/persister-durable-object-storage/index.js +19 -11
  189. package/persisters/persister-durable-object-storage/with-schemas/index.js +19 -11
  190. package/persisters/persister-electric-sql/index.js +29 -12
  191. package/persisters/persister-electric-sql/with-schemas/index.js +29 -12
  192. package/persisters/persister-expo-sqlite/index.js +29 -12
  193. package/persisters/persister-expo-sqlite/with-schemas/index.js +29 -12
  194. package/persisters/persister-file/index.js +34 -10
  195. package/persisters/persister-file/with-schemas/index.js +34 -10
  196. package/persisters/persister-indexed-db/index.js +17 -9
  197. package/persisters/persister-indexed-db/with-schemas/index.js +17 -9
  198. package/persisters/persister-libsql/index.js +29 -12
  199. package/persisters/persister-libsql/with-schemas/index.js +29 -12
  200. package/persisters/persister-partykit-client/index.js +44 -11
  201. package/persisters/persister-partykit-client/with-schemas/index.js +44 -11
  202. package/persisters/persister-partykit-server/index.js +39 -4
  203. package/persisters/persister-partykit-server/with-schemas/index.js +39 -4
  204. package/persisters/persister-pglite/index.js +29 -12
  205. package/persisters/persister-pglite/with-schemas/index.js +29 -12
  206. package/persisters/persister-postgres/index.js +29 -12
  207. package/persisters/persister-postgres/with-schemas/index.js +29 -12
  208. package/persisters/persister-powersync/index.js +29 -12
  209. package/persisters/persister-powersync/with-schemas/index.js +29 -12
  210. package/persisters/persister-react-native-mmkv/index.js +17 -9
  211. package/persisters/persister-react-native-mmkv/with-schemas/index.js +17 -9
  212. package/persisters/persister-react-native-sqlite/index.js +29 -12
  213. package/persisters/persister-react-native-sqlite/with-schemas/index.js +29 -12
  214. package/persisters/persister-remote/index.js +17 -9
  215. package/persisters/persister-remote/with-schemas/index.js +17 -9
  216. package/persisters/persister-sqlite-bun/index.js +29 -12
  217. package/persisters/persister-sqlite-bun/with-schemas/index.js +29 -12
  218. package/persisters/persister-sqlite-wasm/index.js +29 -12
  219. package/persisters/persister-sqlite-wasm/with-schemas/index.js +29 -12
  220. package/persisters/persister-sqlite3/index.js +29 -12
  221. package/persisters/persister-sqlite3/with-schemas/index.js +29 -12
  222. package/persisters/persister-yjs/index.js +19 -11
  223. package/persisters/persister-yjs/with-schemas/index.js +19 -11
  224. package/persisters/with-schemas/index.js +29 -12
  225. package/queries/index.js +15 -14
  226. package/queries/with-schemas/index.js +15 -14
  227. package/readme.md +10 -2
  228. package/relationships/index.js +13 -12
  229. package/relationships/with-schemas/index.js +13 -12
  230. package/releases.md +1 -1
  231. package/store/index.js +74 -60
  232. package/store/with-schemas/index.js +74 -60
  233. package/synchronizers/index.js +17 -9
  234. package/synchronizers/synchronizer-broadcast-channel/index.js +17 -9
  235. package/synchronizers/synchronizer-broadcast-channel/with-schemas/index.js +17 -9
  236. package/synchronizers/synchronizer-local/index.js +19 -11
  237. package/synchronizers/synchronizer-local/with-schemas/index.js +19 -11
  238. package/synchronizers/synchronizer-ws-client/index.js +31 -10
  239. package/synchronizers/synchronizer-ws-client/with-schemas/index.js +31 -10
  240. package/synchronizers/synchronizer-ws-server/index.js +34 -13
  241. package/synchronizers/synchronizer-ws-server/with-schemas/index.js +34 -13
  242. package/synchronizers/synchronizer-ws-server-durable-object/index.js +31 -10
  243. package/synchronizers/synchronizer-ws-server-durable-object/with-schemas/index.js +31 -10
  244. package/synchronizers/synchronizer-ws-server-simple/index.js +11 -10
  245. package/synchronizers/synchronizer-ws-server-simple/with-schemas/index.js +11 -10
  246. package/synchronizers/with-schemas/index.js +17 -9
  247. package/ui-react-inspector/index.js +91 -61
  248. package/ui-react-inspector/with-schemas/index.js +91 -61
  249. package/with-schemas/index.js +92 -64
@@ -71,19 +71,20 @@ const objEnsure = (obj, id, getDefaultValue) => {
71
71
  return obj[id];
72
72
  };
73
73
 
74
- const mapNew = (entries) => new Map(entries);
75
- const mapGet = (map, key) => map?.get(key);
76
- const mapForEach = (map, cb) =>
77
- collForEach(map, (value, key) => cb(key, value));
78
- const mapSet = (map, key, value) =>
79
- isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
80
- const mapEnsure = (map, key, getDefaultValue, hadExistingValue) => {
81
- if (!collHas(map, key)) {
82
- mapSet(map, key, getDefaultValue());
74
+ const map = Map;
75
+ const mapNew = (entries) => new map(entries);
76
+ const mapGet = (map2, key) => map2?.get(key);
77
+ const mapForEach = (map2, cb) =>
78
+ collForEach(map2, (value, key) => cb(key, value));
79
+ const mapSet = (map2, key, value) =>
80
+ isUndefined(value) ? (collDel(map2, key), map2) : map2?.set(key, value);
81
+ const mapEnsure = (map2, key, getDefaultValue, hadExistingValue) => {
82
+ if (!collHas(map2, key)) {
83
+ mapSet(map2, key, getDefaultValue());
83
84
  } else {
84
- hadExistingValue?.(mapGet(map, key));
85
+ hadExistingValue?.(mapGet(map2, key));
85
86
  }
86
- return mapGet(map, key);
87
+ return mapGet(map2, key);
87
88
  };
88
89
  const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
89
90
  ifNotUndefined(
@@ -285,6 +286,11 @@ const createCustomPersister = (
285
286
  ? store.applyChanges
286
287
  : store.setContent)(contentOrChanges);
287
288
  };
289
+ const saveAfterMutated = async () => {
290
+ if (isAutoSaving() && store.hadMutated?.()) {
291
+ await save();
292
+ }
293
+ };
288
294
  const load = async (initialContent) => {
289
295
  /* istanbul ignore else */
290
296
  if (status != 2 /* Saving */) {
@@ -309,6 +315,7 @@ const createCustomPersister = (
309
315
  },
310
316
  );
311
317
  setStatus(0 /* Idle */);
318
+ await saveAfterMutated();
312
319
  });
313
320
  }
314
321
  return persister;
@@ -327,6 +334,7 @@ const createCustomPersister = (
327
334
  loads++;
328
335
  setContentOrChanges(changes ?? content);
329
336
  setStatus(0 /* Idle */);
337
+ await saveAfterMutated();
330
338
  }
331
339
  } else {
332
340
  await load();
@@ -94,21 +94,22 @@ const objValues = (obj) => object.values(obj);
94
94
  const objSize = (obj) => size(objIds(obj));
95
95
  const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
96
96
 
97
- const mapNew = (entries) => new Map(entries);
98
- const mapGet = (map, key) => map?.get(key);
99
- const mapForEach = (map, cb) =>
100
- collForEach(map, (value, key) => cb(key, value));
97
+ const map = Map;
98
+ const mapNew = (entries) => new map(entries);
99
+ const mapGet = (map2, key) => map2?.get(key);
100
+ const mapForEach = (map2, cb) =>
101
+ collForEach(map2, (value, key) => cb(key, value));
101
102
  const mapMap = (coll, cb) =>
102
103
  arrayMap([...(coll?.entries() ?? [])], ([key, value]) => cb(value, key));
103
- const mapSet = (map, key, value) =>
104
- isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
105
- const mapEnsure = (map, key, getDefaultValue, hadExistingValue) => {
106
- if (!collHas(map, key)) {
107
- mapSet(map, key, getDefaultValue());
104
+ const mapSet = (map2, key, value) =>
105
+ isUndefined(value) ? (collDel(map2, key), map2) : map2?.set(key, value);
106
+ const mapEnsure = (map2, key, getDefaultValue, hadExistingValue) => {
107
+ if (!collHas(map2, key)) {
108
+ mapSet(map2, key, getDefaultValue());
108
109
  } else {
109
- hadExistingValue?.(mapGet(map, key));
110
+ hadExistingValue?.(mapGet(map2, key));
110
111
  }
111
- return mapGet(map, key);
112
+ return mapGet(map2, key);
112
113
  };
113
114
  const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
114
115
  ifNotUndefined(
@@ -320,6 +321,11 @@ const createCustomPersister = (
320
321
  ? store.applyChanges
321
322
  : store.setContent)(contentOrChanges);
322
323
  };
324
+ const saveAfterMutated = async () => {
325
+ if (isAutoSaving() && store.hadMutated?.()) {
326
+ await save();
327
+ }
328
+ };
323
329
  const load = async (initialContent) => {
324
330
  /* istanbul ignore else */
325
331
  if (status != 2 /* Saving */) {
@@ -344,6 +350,7 @@ const createCustomPersister = (
344
350
  },
345
351
  );
346
352
  setStatus(0 /* Idle */);
353
+ await saveAfterMutated();
347
354
  });
348
355
  }
349
356
  return persister;
@@ -362,6 +369,7 @@ const createCustomPersister = (
362
369
  loads++;
363
370
  setContentOrChanges(changes ?? content);
364
371
  setStatus(0 /* Idle */);
372
+ await saveAfterMutated();
365
373
  }
366
374
  } else {
367
375
  await load();
@@ -479,7 +487,16 @@ const jsonParse = JSON.parse;
479
487
  const jsonStringWithUndefined = (obj) =>
480
488
  jsonString(obj, (_key, value) => (isUndefined(value) ? UNDEFINED : value));
481
489
  const jsonParseWithUndefined = (str) =>
482
- jsonParse(str, (_key, value) => (value === UNDEFINED ? void 0 : value));
490
+ // JSON.parse reviver removes properties with undefined values
491
+ replaceUndefinedString(jsonParse(str));
492
+ const replaceUndefinedString = (obj) =>
493
+ obj === UNDEFINED
494
+ ? void 0
495
+ : isArray(obj)
496
+ ? arrayMap(obj, replaceUndefinedString)
497
+ : isObject(obj)
498
+ ? objMap(obj, replaceUndefinedString)
499
+ : obj;
483
500
 
484
501
  const textEncoder = /* @__PURE__ */ new GLOBAL.TextEncoder();
485
502
  const getHash = (string) => {
package/queries/index.js CHANGED
@@ -112,24 +112,25 @@ const objIsEqual = (
112
112
  );
113
113
  };
114
114
 
115
- const mapNew = (entries) => new Map(entries);
116
- const mapKeys = (map) => [...(map?.keys() ?? [])];
117
- const mapGet = (map, key) => map?.get(key);
118
- const mapForEach = (map, cb) =>
119
- collForEach(map, (value, key) => cb(key, value));
120
- const mapSet = (map, key, value) =>
121
- isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
122
- const mapEnsure = (map, key, getDefaultValue, hadExistingValue) => {
123
- if (!collHas(map, key)) {
124
- mapSet(map, key, getDefaultValue());
115
+ const map = Map;
116
+ const mapNew = (entries) => new map(entries);
117
+ const mapKeys = (map2) => [...(map2?.keys() ?? [])];
118
+ const mapGet = (map2, key) => map2?.get(key);
119
+ const mapForEach = (map2, cb) =>
120
+ collForEach(map2, (value, key) => cb(key, value));
121
+ const mapSet = (map2, key, value) =>
122
+ isUndefined(value) ? (collDel(map2, key), map2) : map2?.set(key, value);
123
+ const mapEnsure = (map2, key, getDefaultValue, hadExistingValue) => {
124
+ if (!collHas(map2, key)) {
125
+ mapSet(map2, key, getDefaultValue());
125
126
  } else {
126
- hadExistingValue?.(mapGet(map, key));
127
+ hadExistingValue?.(mapGet(map2, key));
127
128
  }
128
- return mapGet(map, key);
129
+ return mapGet(map2, key);
129
130
  };
130
- const mapToObj = (map, valueMapper, excludeMapValue, excludeObjValue) => {
131
+ const mapToObj = (map2, valueMapper, excludeMapValue, excludeObjValue) => {
131
132
  const obj = {};
132
- collForEach(map, (mapValue, id) => {
133
+ collForEach(map2, (mapValue, id) => {
133
134
  {
134
135
  const objValue = mapValue;
135
136
  {
@@ -112,24 +112,25 @@ const objIsEqual = (
112
112
  );
113
113
  };
114
114
 
115
- const mapNew = (entries) => new Map(entries);
116
- const mapKeys = (map) => [...(map?.keys() ?? [])];
117
- const mapGet = (map, key) => map?.get(key);
118
- const mapForEach = (map, cb) =>
119
- collForEach(map, (value, key) => cb(key, value));
120
- const mapSet = (map, key, value) =>
121
- isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
122
- const mapEnsure = (map, key, getDefaultValue, hadExistingValue) => {
123
- if (!collHas(map, key)) {
124
- mapSet(map, key, getDefaultValue());
115
+ const map = Map;
116
+ const mapNew = (entries) => new map(entries);
117
+ const mapKeys = (map2) => [...(map2?.keys() ?? [])];
118
+ const mapGet = (map2, key) => map2?.get(key);
119
+ const mapForEach = (map2, cb) =>
120
+ collForEach(map2, (value, key) => cb(key, value));
121
+ const mapSet = (map2, key, value) =>
122
+ isUndefined(value) ? (collDel(map2, key), map2) : map2?.set(key, value);
123
+ const mapEnsure = (map2, key, getDefaultValue, hadExistingValue) => {
124
+ if (!collHas(map2, key)) {
125
+ mapSet(map2, key, getDefaultValue());
125
126
  } else {
126
- hadExistingValue?.(mapGet(map, key));
127
+ hadExistingValue?.(mapGet(map2, key));
127
128
  }
128
- return mapGet(map, key);
129
+ return mapGet(map2, key);
129
130
  };
130
- const mapToObj = (map, valueMapper, excludeMapValue, excludeObjValue) => {
131
+ const mapToObj = (map2, valueMapper, excludeMapValue, excludeObjValue) => {
131
132
  const obj = {};
132
- collForEach(map, (mapValue, id) => {
133
+ collForEach(map2, (mapValue, id) => {
133
134
  {
134
135
  const objValue = mapValue;
135
136
  {
package/readme.md CHANGED
@@ -1,4 +1,12 @@
1
- <link rel="preload" as="image" href="https://tinybase.org/react.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/indexeddb.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/browser.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/cloudflare.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/postgresql.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/pglite.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/sqlite.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/bun.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/expo.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/electric.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/turso.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/powersync.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/partykit.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/yjs.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/crsqlite.png"><link rel="preload" as="image" href="https://tinybase.org/automerge.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/zod.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/typebox.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/valibot.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/arktype.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/yup.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/effect.svg?asImg"><link rel="preload" as="image" href="https://img.shields.io/github/stars/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=GitHub&amp;labelColor=%23d81b60&amp;color=%23333"><link rel="preload" as="image" href="https://img.shields.io/badge/Bluesky-Follow-blue?style=for-the-badge&amp;logo=bluesky&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%230285FF"><link rel="preload" as="image" href="https://img.shields.io/badge/%2F%20Twitter-Follow-blue?style=for-the-badge&amp;logo=x&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%23000"><link rel="preload" as="image" href="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&amp;logo=discord&amp;logoColor=%23fff&amp;label=Discord&amp;labelColor=%233131e8&amp;color=%23333"><link rel="preload" as="image" href="https://img.shields.io/github/discussions/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Ideas&amp;labelColor=%23d81b60&amp;color=%23333"><link rel="preload" as="image" href="https://img.shields.io/github/issues/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Issues&amp;labelColor=%23d81b60&amp;color=%23333"><link rel="preload" as="image" href="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&amp;logo=Vitest&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%2387c305"><link rel="preload" as="image" href="https://img.shields.io/npm/v/tinybase?style=for-the-badge&amp;logo=npm&amp;logoColor=%23fff&amp;labelColor=%23bd0005&amp;color=%23333"><link rel="preload" as="image" href="https://tinybase.org/ui-react-dom.webp"><link rel="preload" as="image" href="https://tinybase.org/inspector.webp"><link rel="preload" as="image" href="https://github.com/fastrepl.png?size=48"><link rel="preload" as="image" href="https://github.com/expo.png?size=48"><link rel="preload" as="image" href="https://github.com/dylmye.png?size=48"><link rel="preload" as="image" href="https://github.com/ComputelessComputer.png?size=48"><link rel="preload" as="image" href="https://github.com/cancelself.png?size=48"><link rel="preload" as="image" href="https://github.com/cpojer.png?size=48"><link rel="preload" as="image" href="https://github.com/beekeeb.png?size=48"><link rel="preload" as="image" href="https://github.com/WonderPanda.png?size=48"><link rel="preload" as="image" href="https://github.com/arpitBhalla.png?size=48"><link rel="preload" as="image" href="https://github.com/behrends.png?size=48"><link rel="preload" as="image" href="https://github.com/betomoedano.png?size=48"><link rel="preload" as="image" href="https://github.com/brentvatne.png?size=48"><link rel="preload" as="image" href="https://github.com/byCedric.png?size=48"><link rel="preload" as="image" href="https://github.com/circadian-risk.png?size=48"><link rel="preload" as="image" href="https://github.com/cubecull.png?size=48"><link rel="preload" as="image" href="https://github.com/erwinkn.png?size=48"><link rel="preload" as="image" href="https://github.com/ezra-en.png?size=48"><link rel="preload" as="image" href="https://github.com/feychenie.png?size=48"><link rel="preload" as="image" href="https://github.com/flaming-codes.png?size=48"><link rel="preload" as="image" href="https://github.com/fostertheweb.png?size=48"><link rel="preload" as="image" href="https://github.com/Giulio987.png?size=48"><link rel="preload" as="image" href="https://github.com/hi-ogawa.png?size=48"><link rel="preload" as="image" href="https://github.com/itsdevcoffee.png?size=48"><link rel="preload" as="image" href="https://github.com/jbolda.png?size=48"><link rel="preload" as="image" href="https://github.com/Kayoo-asso.png?size=48"><link rel="preload" as="image" href="https://github.com/kotofurumiya.png?size=48"><link rel="preload" as="image" href="https://github.com/Kudo.png?size=48"><link rel="preload" as="image" href="https://github.com/learn-anything.png?size=48"><link rel="preload" as="image" href="https://github.com/lluc.png?size=48"><link rel="preload" as="image" href="https://github.com/marksteve.png?size=48"><link rel="preload" as="image" href="https://github.com/miking-the-viking.png?size=48"><link rel="preload" as="image" href="https://github.com/mjamesderocher.png?size=48"><link rel="preload" as="image" href="https://github.com/mouktardev.png?size=48"><link rel="preload" as="image" href="https://github.com/nickmessing.png?size=48"><link rel="preload" as="image" href="https://github.com/nikitavoloboev.png?size=48"><link rel="preload" as="image" href="https://github.com/nkzw-tech.png?size=48"><link rel="preload" as="image" href="https://github.com/palerdot.png?size=48"><link rel="preload" as="image" href="https://github.com/PorcoRosso85.png?size=48"><link rel="preload" as="image" href="https://github.com/primodiumxyz.png?size=48"><link rel="preload" as="image" href="https://github.com/shaneosullivan.png?size=48"><link rel="preload" as="image" href="https://github.com/sudo-self.png?size=48"><link rel="preload" as="image" href="https://github.com/SuperSonicHub1.png?size=48"><link rel="preload" as="image" href="https://github.com/threepointone.png?size=48"><link rel="preload" as="image" href="https://github.com/uptonking.png?size=48"><link rel="preload" as="image" href="https://github.com/ViktorZhurbin.png?size=48"><link rel="preload" as="image" href="https://github.com/wilkerlucio.png?size=48"><link rel="preload" as="image" href="https://synclets.org/favicon.svg?asImg"><link rel="preload" as="image" href="https://tinywidgets.org/favicon.svg?asImg"><link rel="preload" as="image" href="https://tinytick.org/favicon.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/youtube.webp"><section id="hero"><h2 id="a-reactive-data-store-sync-engine">A <em>reactive</em> data store &amp; <span><em>sync</em> engine</span></h2></section><p><a href="https://tinybase.org/guides/releases/#v7-3"><em>NEW!</em> v7.3 release</a></p><p><span id="one-with">&quot;The one with state hooks!&quot;</span></p><p><a class="start" href="https://tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://tinybase.org/demos/">Try the demos</a></p><p><a href="https://tinybase.org/api/the-essentials/creating-stores/store/">Read the docs</a></p><hr><section><h2 id="it-s-reactive">It&#x27;s <em>Reactive</em></h2><p>TinyBase lets you <a href="#register-granular-listeners">listen to changes</a> made to any part of your data. This means your app will be fast, since you only spend rendering cycles on things that change. The optional <a href="#call-hooks-to-bind-to-data">bindings to React</a> and <a href="#pre-built-reactive-components">pre-built components</a> let you easily build fully reactive UIs on top of TinyBase. You even get a built-in <a href="#set-checkpoints-for-an-undo-stack">undo stack</a>, and <a href="#an-inspector-for-your-data">developer tools</a>!</p></section><section><h2 id="it-s-database-like">It&#x27;s <em>Database-Like</em></h2><p>Consumer app? Enterprise app? Or even a game? Model <a href="#start-with-a-simple-key-value-store">key-value data</a> and <a href="#level-up-to-use-tabular-data">tabular data</a> with optional typed <a href="#apply-schemas-to-tables-values">schematization</a>, whatever its data structures. There are built-in <a href="#create-indexes-for-fast-lookups">indexing</a>, <a href="#define-metrics-and-aggregations">metric aggregation</a>, and tabular <a href="#model-table-relationships">relationships</a> APIs - and a powerful <a href="#build-complex-queries-with-tinyql">query engine</a> to select, join, filter, and group data (reactively!) without SQL.</p></section><section><h2 id="it-synchronizes">It <em>Synchronizes</em></h2><p>TinyBase has <a href="#synchronize-between-devices">native CRDT</a> support, meaning that you can deterministically <a href="https://tinybase.org/guides/synchronization/">synchronize</a> and merge data across multiple sources, clients, and servers. And although TinyBase is an in-memory data store, you can easily <a href="#persist-to-storage-databases-more">persist</a> your data to file, <a href="https://tinybase.org/api/persister-browser">browser storage</a>, <a href="https://tinybase.org/api/persister-indexed-db">IndexedDB</a>, <a href="https://tinybase.org/guides/persistence/database-persistence/">SQLite or PostgreSQL databases</a>, and <a href="https://tinybase.org/guides/persistence/third-party-crdt-persistence/">more</a>.</p></section><section><h2 id="it-s-built-for-a-local-first-world">It&#x27;s Built For A <em>Local-First</em> World</h2><p>TinyBase works anywhere that JavaScript does, but it&#x27;s especially great for local-first apps: where data is stored locally on the user&#x27;s device and that can be run offline. It&#x27;s tiny by name, tiny by nature: just <a href="#did-we-say-tiny">5.4kB - 12.1kB</a> and with no dependencies - yet <a href="#well-tested-and-documented">100% tested</a>, <a href="https://tinybase.org/guides/the-basics/getting-started/">fully documented</a>, and of course, <a href="https://github.com/tinyplex/tinybase">open source</a>!</p></section><hr><section id="friends"><h2 id="tinybase-works-great-on-its-own-but-also-plays-well-with-friends">TinyBase works great on its own, but also plays well with friends.</h2><div><a href="https://tinybase.org/guides/building-uis/getting-started-with-ui-react"><img src="https://tinybase.org/react.svg?asImg" width="48"> React</a></div><div><a href="https://tinybase.org/api/persister-indexed-db/functions/creation/createindexeddbpersister"><img src="https://tinybase.org/indexeddb.svg?asImg" width="48"> IndexedDB</a></div><div><a href="https://tinybase.org/api/persister-browser"><img src="https://tinybase.org/browser.svg?asImg" width="48"> OPFS</a></div><div><a href="https://tinybase.org/guides/integrations/cloudflare-durable-objects"><img src="https://tinybase.org/cloudflare.svg?asImg" width="48"> Cloudflare</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/postgresql.svg?asImg" width="48"> PostgreSQL</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/pglite.svg?asImg" width="48"> PGlite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/sqlite.svg?asImg" width="48"> SQLite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/bun.svg?asImg" width="48"> Bun SQLite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/expo.svg?asImg" width="48"> Expo SQLite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/electric.svg?asImg" width="48"> ElectricSQL</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/turso.svg?asImg" width="48"> Turso</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/powersync.svg?asImg" width="48"> PowerSync</a></div><div><a href="https://tinybase.org/api/persister-partykit-client"><img src="https://tinybase.org/partykit.svg?asImg" width="48"> PartyKit</a></div><div><a href="https://tinybase.org/api/persister-yjs/functions/creation/createyjspersister"><img src="https://tinybase.org/yjs.svg?asImg" width="48"> YJS</a></div><div><a href="https://tinybase.org/api/persister-cr-sqlite-wasm"><img src="https://tinybase.org/crsqlite.png" width="48"> CR-SQLite</a></div><div><a href="https://tinybase.org/api/persister-automerge"><img src="https://tinybase.org/automerge.svg?asImg" width="48"> Automerge</a></div><div><a href="https://tinybase.org/api/schematizer-zod/functions/creation/createzodschematizer"><img src="https://tinybase.org/zod.svg?asImg" width="48"> Zod</a></div><div><a href="https://tinybase.org/api/schematizer-typebox/functions/creation/createtypeboxschematizer"><img src="https://tinybase.org/typebox.svg?asImg" width="48"> TypeBox</a></div><div><a href="https://tinybase.org/api/schematizer-valibot/functions/creation/createvalibotschematizer"><img src="https://tinybase.org/valibot.svg?asImg" width="48"> Valibot</a></div><div><a href="https://tinybase.org/api/schematizer-arktype/functions/creation/createarktypeschematizer"><img src="https://tinybase.org/arktype.svg?asImg" width="48"> ArkType</a></div><div><a href="https://tinybase.org/api/schematizer-yup/functions/creation/createyupschematizer"><img src="https://tinybase.org/yup.svg?asImg" width="48"> Yup</a></div><div><a href="https://tinybase.org/api/schematizer-effect/functions/creation/createeffectschematizer"><img src="https://tinybase.org/effect.svg?asImg" width="48"> Effect</a></div><p>(Baffled by all these logos? Check out our <a href="https://tinybase.org/guides/the-basics/architectural-options">architectural options</a> guide to make sense of it all!)</p></section><hr><section id="follow"><a href="https://github.com/tinyplex/tinybase" target="_blank"><img src="https://img.shields.io/github/stars/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=GitHub&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="https://bsky.app/profile/tinybase.bsky.social"><img src="https://img.shields.io/badge/Bluesky-Follow-blue?style=for-the-badge&amp;logo=bluesky&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%230285FF"> </a><a href="https://x.com/tinybasejs" target="_blank"><img src="https://img.shields.io/badge/%2F%20Twitter-Follow-blue?style=for-the-badge&amp;logo=x&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%23000"> </a><a href="https://discord.com/invite/mGz3mevwP8" target="_blank"><img src="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&amp;logo=discord&amp;logoColor=%23fff&amp;label=Discord&amp;labelColor=%233131e8&amp;color=%23333"></a><br><a href="https://github.com/tinyplex/tinybase/discussions" target="_blank"><img src="https://img.shields.io/github/discussions/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Ideas&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="https://github.com/tinyplex/tinybase/issues" target="_blank"><img src="https://img.shields.io/github/issues/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Issues&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="#well-tested-and-documented"><img src="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&amp;logo=Vitest&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%2387c305"> </a><a href="https://www.npmjs.com/package/tinybase/v/7.3.1" target="_blank"><img src="https://img.shields.io/npm/v/tinybase?style=for-the-badge&amp;logo=npm&amp;logoColor=%23fff&amp;labelColor=%23bd0005&amp;color=%23333"></a></section><hr><section><h2 id="start-with-a-simple-key-value-store">Start with a simple key-value store.</h2><p>Creating a <a href="https://tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> requires just a simple call to the <a href="https://tinybase.org/api/the-essentials/creating-stores/createstore/"><code>createStore</code></a> function. Once you have one, you can easily set <a href="https://tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> in it by unique <a href="https://tinybase.org/api/common/type-aliases/identity/id/"><code>Id</code></a>. And of course you can easily get them back out again.</p><p>Read more about using keyed value data in <a href="https://tinybase.org/guides/the-basics/">The Basics</a> guide.</p></section>
1
+ <link rel="preload" as="image" href="https://tinybase.org/react.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/indexeddb.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/browser.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/cloudflare.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/postgresql.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/pglite.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/sqlite.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/bun.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/expo.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/electric.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/turso.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/powersync.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/partykit.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/yjs.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/crsqlite.png"><link rel="preload" as="image" href="https://tinybase.org/automerge.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/zod.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/typebox.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/valibot.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/arktype.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/yup.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/effect.svg?asImg"><link rel="preload" as="image" href="https://img.shields.io/github/stars/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=GitHub&amp;labelColor=%23d81b60&amp;color=%23333"><link rel="preload" as="image" href="https://img.shields.io/badge/Bluesky-Follow-blue?style=for-the-badge&amp;logo=bluesky&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%230285FF"><link rel="preload" as="image" href="https://img.shields.io/badge/%2F%20Twitter-Follow-blue?style=for-the-badge&amp;logo=x&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%23000"><link rel="preload" as="image" href="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&amp;logo=discord&amp;logoColor=%23fff&amp;label=Discord&amp;labelColor=%233131e8&amp;color=%23333"><link rel="preload" as="image" href="https://img.shields.io/github/discussions/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Ideas&amp;labelColor=%23d81b60&amp;color=%23333"><link rel="preload" as="image" href="https://img.shields.io/github/issues/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Issues&amp;labelColor=%23d81b60&amp;color=%23333"><link rel="preload" as="image" href="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&amp;logo=Vitest&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%2387c305"><link rel="preload" as="image" href="https://img.shields.io/npm/v/tinybase?style=for-the-badge&amp;logo=npm&amp;logoColor=%23fff&amp;labelColor=%23bd0005&amp;color=%23333"><link rel="preload" as="image" href="https://tinybase.org/ui-react-dom.webp"><link rel="preload" as="image" href="https://tinybase.org/inspector.webp"><link rel="preload" as="image" href="https://github.com/fastrepl.png?size=48"><link rel="preload" as="image" href="https://github.com/expo.png?size=48"><link rel="preload" as="image" href="https://github.com/dylmye.png?size=48"><link rel="preload" as="image" href="https://github.com/ComputelessComputer.png?size=48"><link rel="preload" as="image" href="https://github.com/cancelself.png?size=48"><link rel="preload" as="image" href="https://github.com/cpojer.png?size=48"><link rel="preload" as="image" href="https://github.com/beekeeb.png?size=48"><link rel="preload" as="image" href="https://github.com/WonderPanda.png?size=48"><link rel="preload" as="image" href="https://github.com/arpitBhalla.png?size=48"><link rel="preload" as="image" href="https://github.com/behrends.png?size=48"><link rel="preload" as="image" href="https://github.com/betomoedano.png?size=48"><link rel="preload" as="image" href="https://github.com/brentvatne.png?size=48"><link rel="preload" as="image" href="https://github.com/byCedric.png?size=48"><link rel="preload" as="image" href="https://github.com/circadian-risk.png?size=48"><link rel="preload" as="image" href="https://github.com/cubecull.png?size=48"><link rel="preload" as="image" href="https://github.com/erwinkn.png?size=48"><link rel="preload" as="image" href="https://github.com/ezra-en.png?size=48"><link rel="preload" as="image" href="https://github.com/feychenie.png?size=48"><link rel="preload" as="image" href="https://github.com/flaming-codes.png?size=48"><link rel="preload" as="image" href="https://github.com/fostertheweb.png?size=48"><link rel="preload" as="image" href="https://github.com/Giulio987.png?size=48"><link rel="preload" as="image" href="https://github.com/hi-ogawa.png?size=48"><link rel="preload" as="image" href="https://github.com/itsdevcoffee.png?size=48"><link rel="preload" as="image" href="https://github.com/jbolda.png?size=48"><link rel="preload" as="image" href="https://github.com/Kayoo-asso.png?size=48"><link rel="preload" as="image" href="https://github.com/kotofurumiya.png?size=48"><link rel="preload" as="image" href="https://github.com/Kudo.png?size=48"><link rel="preload" as="image" href="https://github.com/learn-anything.png?size=48"><link rel="preload" as="image" href="https://github.com/lluc.png?size=48"><link rel="preload" as="image" href="https://github.com/marksteve.png?size=48"><link rel="preload" as="image" href="https://github.com/miking-the-viking.png?size=48"><link rel="preload" as="image" href="https://github.com/mjamesderocher.png?size=48"><link rel="preload" as="image" href="https://github.com/mouktardev.png?size=48"><link rel="preload" as="image" href="https://github.com/nickmessing.png?size=48"><link rel="preload" as="image" href="https://github.com/nikitavoloboev.png?size=48"><link rel="preload" as="image" href="https://github.com/nkzw-tech.png?size=48"><link rel="preload" as="image" href="https://github.com/palerdot.png?size=48"><link rel="preload" as="image" href="https://github.com/PorcoRosso85.png?size=48"><link rel="preload" as="image" href="https://github.com/primodiumxyz.png?size=48"><link rel="preload" as="image" href="https://github.com/shaneosullivan.png?size=48"><link rel="preload" as="image" href="https://github.com/sudo-self.png?size=48"><link rel="preload" as="image" href="https://github.com/SuperSonicHub1.png?size=48"><link rel="preload" as="image" href="https://github.com/threepointone.png?size=48"><link rel="preload" as="image" href="https://github.com/uptonking.png?size=48"><link rel="preload" as="image" href="https://github.com/ViktorZhurbin.png?size=48"><link rel="preload" as="image" href="https://github.com/wilkerlucio.png?size=48"><link rel="preload" as="image" href="https://synclets.org/favicon.svg?asImg"><link rel="preload" as="image" href="https://tinywidgets.org/favicon.svg?asImg"><link rel="preload" as="image" href="https://tinytick.org/favicon.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/youtube.webp"><section id="hero"><h2 id="a-reactive-data-store-sync-engine">A <em>reactive</em> data store &amp; <span><em>sync</em> engine</span></h2></section><p><a href="https://tinybase.org/guides/releases/#v7-3"><em>NEW!</em> v7.3 release</a></p><p><span id="one-with">&quot;The one with state hooks!&quot;</span></p><p><a class="start" href="https://tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://tinybase.org/demos/">Try the demos</a></p><p><a href="https://tinybase.org/api/the-essentials/creating-stores/store/">Read the docs</a></p><hr><section><h2 id="let-s-build-local-first-apps">Let&#x27;s build <em>local-first</em> apps</h2><p>Create a todo list, a chat app, a drawing tool, or a tic-tac-toe game - with sync &amp; persistence! - in less than 60 seconds.</p></section>
2
+
3
+ ```bash
4
+ > npm create tinybase@latest
5
+
6
+ 📦 Creating your project...
7
+ ```
8
+
9
+ <hr><section><h2 id="it-s-reactive">It&#x27;s <em>Reactive</em></h2><p>TinyBase lets you <a href="#register-granular-listeners">listen to changes</a> made to any part of your data. This means your app will be fast, since you only spend rendering cycles on things that change. The optional <a href="#call-hooks-to-bind-to-data">bindings to React</a> and <a href="#pre-built-reactive-components">pre-built components</a> let you easily build fully reactive UIs on top of TinyBase. You even get a built-in <a href="#set-checkpoints-for-an-undo-stack">undo stack</a>, and <a href="#an-inspector-for-your-data">developer tools</a>!</p></section><section><h2 id="it-s-database-like">It&#x27;s <em>Database-Like</em></h2><p>Consumer app? Enterprise app? Or even a game? Model <a href="#start-with-a-simple-key-value-store">key-value data</a> and <a href="#level-up-to-use-tabular-data">tabular data</a> with optional typed <a href="#apply-schemas-to-tables-values">schematization</a>, whatever its data structures. There are built-in <a href="#create-indexes-for-fast-lookups">indexing</a>, <a href="#define-metrics-and-aggregations">metric aggregation</a>, and tabular <a href="#model-table-relationships">relationships</a> APIs - and a powerful <a href="#build-complex-queries-with-tinyql">query engine</a> to select, join, filter, and group data (reactively!) without SQL.</p></section><section><h2 id="it-synchronizes">It <em>Synchronizes</em></h2><p>TinyBase has <a href="#synchronize-between-devices">native CRDT</a> support, meaning that you can deterministically <a href="https://tinybase.org/guides/synchronization/">synchronize</a> and merge data across multiple sources, clients, and servers. And although TinyBase is an in-memory data store, you can easily <a href="#persist-to-storage-databases-more">persist</a> your data to file, <a href="https://tinybase.org/api/persister-browser">browser storage</a>, <a href="https://tinybase.org/api/persister-indexed-db">IndexedDB</a>, <a href="https://tinybase.org/guides/persistence/database-persistence/">SQLite or PostgreSQL databases</a>, and <a href="https://tinybase.org/guides/persistence/third-party-crdt-persistence/">more</a>.</p></section><section><h2 id="it-s-built-for-a-local-first-world">It&#x27;s Built For A <em>Local-First</em> World</h2><p>TinyBase works anywhere that JavaScript does, but it&#x27;s especially great for local-first apps: where data is stored locally on the user&#x27;s device and that can be run offline. It&#x27;s tiny by name, tiny by nature: just <a href="#did-we-say-tiny">5.4kB - 12.1kB</a> and with no dependencies - yet <a href="#well-tested-and-documented">100% tested</a>, <a href="https://tinybase.org/guides/the-basics/getting-started/">fully documented</a>, and of course, <a href="https://github.com/tinyplex/tinybase">open source</a>!</p></section><hr><section id="friends"><h2 id="tinybase-works-great-on-its-own-but-also-plays-well-with-friends">TinyBase works great on its own, but also plays well with friends.</h2><div><a href="https://tinybase.org/guides/building-uis/getting-started-with-ui-react"><img src="https://tinybase.org/react.svg?asImg" width="48"> React</a></div><div><a href="https://tinybase.org/api/persister-indexed-db/functions/creation/createindexeddbpersister"><img src="https://tinybase.org/indexeddb.svg?asImg" width="48"> IndexedDB</a></div><div><a href="https://tinybase.org/api/persister-browser"><img src="https://tinybase.org/browser.svg?asImg" width="48"> OPFS</a></div><div><a href="https://tinybase.org/guides/integrations/cloudflare-durable-objects"><img src="https://tinybase.org/cloudflare.svg?asImg" width="48"> Cloudflare</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/postgresql.svg?asImg" width="48"> PostgreSQL</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/pglite.svg?asImg" width="48"> PGlite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/sqlite.svg?asImg" width="48"> SQLite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/bun.svg?asImg" width="48"> Bun SQLite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/expo.svg?asImg" width="48"> Expo SQLite</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/electric.svg?asImg" width="48"> ElectricSQL</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/turso.svg?asImg" width="48"> Turso</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/powersync.svg?asImg" width="48"> PowerSync</a></div><div><a href="https://tinybase.org/api/persister-partykit-client"><img src="https://tinybase.org/partykit.svg?asImg" width="48"> PartyKit</a></div><div><a href="https://tinybase.org/api/persister-yjs/functions/creation/createyjspersister"><img src="https://tinybase.org/yjs.svg?asImg" width="48"> YJS</a></div><div><a href="https://tinybase.org/api/persister-cr-sqlite-wasm"><img src="https://tinybase.org/crsqlite.png" width="48"> CR-SQLite</a></div><div><a href="https://tinybase.org/api/persister-automerge"><img src="https://tinybase.org/automerge.svg?asImg" width="48"> Automerge</a></div><div><a href="https://tinybase.org/api/schematizer-zod/functions/creation/createzodschematizer"><img src="https://tinybase.org/zod.svg?asImg" width="48"> Zod</a></div><div><a href="https://tinybase.org/api/schematizer-typebox/functions/creation/createtypeboxschematizer"><img src="https://tinybase.org/typebox.svg?asImg" width="48"> TypeBox</a></div><div><a href="https://tinybase.org/api/schematizer-valibot/functions/creation/createvalibotschematizer"><img src="https://tinybase.org/valibot.svg?asImg" width="48"> Valibot</a></div><div><a href="https://tinybase.org/api/schematizer-arktype/functions/creation/createarktypeschematizer"><img src="https://tinybase.org/arktype.svg?asImg" width="48"> ArkType</a></div><div><a href="https://tinybase.org/api/schematizer-yup/functions/creation/createyupschematizer"><img src="https://tinybase.org/yup.svg?asImg" width="48"> Yup</a></div><div><a href="https://tinybase.org/api/schematizer-effect/functions/creation/createeffectschematizer"><img src="https://tinybase.org/effect.svg?asImg" width="48"> Effect</a></div><p>(Baffled by all these logos? Check out our <a href="https://tinybase.org/guides/the-basics/architectural-options">architectural options</a> guide to make sense of it all!)</p></section><hr><section id="follow"><a href="https://github.com/tinyplex/tinybase" target="_blank"><img src="https://img.shields.io/github/stars/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=GitHub&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="https://bsky.app/profile/tinybase.bsky.social"><img src="https://img.shields.io/badge/Bluesky-Follow-blue?style=for-the-badge&amp;logo=bluesky&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%230285FF"> </a><a href="https://x.com/tinybasejs" target="_blank"><img src="https://img.shields.io/badge/%2F%20Twitter-Follow-blue?style=for-the-badge&amp;logo=x&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%23000"> </a><a href="https://discord.com/invite/mGz3mevwP8" target="_blank"><img src="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&amp;logo=discord&amp;logoColor=%23fff&amp;label=Discord&amp;labelColor=%233131e8&amp;color=%23333"></a><br><a href="https://github.com/tinyplex/tinybase/discussions" target="_blank"><img src="https://img.shields.io/github/discussions/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Ideas&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="https://github.com/tinyplex/tinybase/issues" target="_blank"><img src="https://img.shields.io/github/issues/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Issues&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="#well-tested-and-documented"><img src="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&amp;logo=Vitest&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%2387c305"> </a><a href="https://www.npmjs.com/package/tinybase/v/7.3.3" target="_blank"><img src="https://img.shields.io/npm/v/tinybase?style=for-the-badge&amp;logo=npm&amp;logoColor=%23fff&amp;labelColor=%23bd0005&amp;color=%23333"></a></section><hr><section><h2 id="start-with-a-simple-key-value-store">Start with a simple key-value store.</h2><p>Creating a <a href="https://tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> requires just a simple call to the <a href="https://tinybase.org/api/the-essentials/creating-stores/createstore/"><code>createStore</code></a> function. Once you have one, you can easily set <a href="https://tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> in it by unique <a href="https://tinybase.org/api/common/type-aliases/identity/id/"><code>Id</code></a>. And of course you can easily get them back out again.</p><p>Read more about using keyed value data in <a href="https://tinybase.org/guides/the-basics/">The Basics</a> guide.</p></section>
2
10
 
3
11
  ```js
4
12
  import {createStore} from 'tinybase';
@@ -275,4 +283,4 @@ console.log(store.getCell('pets', 'felix', 'sold'));
275
283
  // -> false
276
284
  ```
277
285
 
278
- <section><h2 id="did-we-say-tiny">Did we say tiny?</h2><p>If you use the basic <a href="https://tinybase.org/api/store/"><code>store</code></a> module alone, you&#x27;ll only add a gzipped <em>5.4kB</em> to your app. Incrementally add the other modules as you need more functionality, or get it all for <em>12.1kB</em>.</p><p>The optional <a href="https://tinybase.org/api/ui-react/"><code>ui-react</code></a> module is just <em>5.5kB</em>, the ui-react-dom components are another <em>3.8kB</em>, and everything is super fast. Life is easy when you have zero dependencies!</p><p>Read more about how TinyBase is structured and packaged in the <a href="https://tinybase.org/guides/how-tinybase-is-built/architecture/">Architecture</a> guide.</p></section><div class="table"><table class="fixed"><tbody><tr><th> </th><th>Minified .js.gz</th><th>Source .js</th></tr><tr><th class="right"><a href="https://tinybase.org/api/store/">tinybase/store</a> (minimal)</th><td>5.4kB</td><td>54.6kB</td></tr><tr><th class="right">tinybase (complete)</th><td>12.1kB</td><td>127.0kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react/">ui-react</a></th><td>5.5kB</td><td>59.8kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react-dom/">ui-react-dom</a></th><td>3.8kB</td><td>34.0kB</td></tr></tbody></table></div><section><h2 id="well-tested-and-documented">Well tested and documented.</h2><p>TinyBase has <em>100.0%</em> test coverage, including the code throughout the documentation - even on this page! The guides, demos, and API examples are designed to make it as easy as possible for you to get your TinyBase-powered app up and running.</p><p>Read more about how TinyBase is tested in the Unit <a href="https://tinybase.org/guides/how-tinybase-is-built/testing/">Testing</a> guide.</p></section><div class="table"><table class="fixed"><tbody><tr><th width="30%"> </th><th>Total</th><th>Tested</th><th>Coverage</th></tr><tr><th class="right">Lines</th><td>2,408</td><td>2,408</td><td>100.0%</td></tr><tr><th class="right">Statements</th><td>2,617</td><td>2,617</td><td>100.0%</td></tr><tr><th class="right">Functions</th><td>1,046</td><td>1,046</td><td>100.0%</td></tr><tr><th class="right">Branches</th><td>906</td><td>906</td><td>100.0%</td></tr><tr><th class="right">Tests</th><td colspan="3">7,286</td></tr><tr><th class="right">Assertions</th><td colspan="3">32,322</td></tr></tbody></table></div><hr><section id="sponsors"><h2 id="proud-to-be-supported-by">Proud to be supported by:</h2><a href="https://github.com/fastrepl" target="_blank"><img src="https://github.com/fastrepl.png?size=48" title="fastrepl" width="48" height="48"></a><a href="https://github.com/expo" target="_blank"><img src="https://github.com/expo.png?size=48" title="expo" width="48" height="48"></a><a href="https://github.com/dylmye" target="_blank"><img src="https://github.com/dylmye.png?size=48" title="dylmye" width="48" height="48"></a><a href="https://github.com/ComputelessComputer" target="_blank"><img src="https://github.com/ComputelessComputer.png?size=48" title="ComputelessComputer" width="48" height="48"></a><a href="https://github.com/cancelself" target="_blank"><img src="https://github.com/cancelself.png?size=48" title="cancelself" width="48" height="48"></a><a href="https://github.com/cpojer" target="_blank"><img src="https://github.com/cpojer.png?size=48" title="cpojer" width="48" height="48"></a><a href="https://github.com/beekeeb" target="_blank"><img src="https://github.com/beekeeb.png?size=48" title="beekeeb" width="48" height="48"></a><a href="https://github.com/WonderPanda" target="_blank"><img src="https://github.com/WonderPanda.png?size=48" title="WonderPanda" width="48" height="48"></a><a href="https://github.com/arpitBhalla" target="_blank"><img src="https://github.com/arpitBhalla.png?size=48" title="arpitBhalla" width="48" height="48"></a></section><section id="users"><h2 id="excited-to-be-used-by">Excited to be used by:</h2><a href="https://github.com/behrends" target="_blank"><img src="https://github.com/behrends.png?size=48" title="behrends" width="48" height="48"></a><a href="https://github.com/betomoedano" target="_blank"><img src="https://github.com/betomoedano.png?size=48" title="betomoedano" width="48" height="48"></a><a href="https://github.com/brentvatne" target="_blank"><img src="https://github.com/brentvatne.png?size=48" title="brentvatne" width="48" height="48"></a><a href="https://github.com/byCedric" target="_blank"><img src="https://github.com/byCedric.png?size=48" title="byCedric" width="48" height="48"></a><a href="https://github.com/circadian-risk" target="_blank"><img src="https://github.com/circadian-risk.png?size=48" title="circadian-risk" width="48" height="48"></a><a href="https://github.com/cpojer" target="_blank"><img src="https://github.com/cpojer.png?size=48" title="cpojer" width="48" height="48"></a><a href="https://github.com/cubecull" target="_blank"><img src="https://github.com/cubecull.png?size=48" title="cubecull" width="48" height="48"></a><a href="https://github.com/erwinkn" target="_blank"><img src="https://github.com/erwinkn.png?size=48" title="erwinkn" width="48" height="48"></a><a href="https://github.com/expo" target="_blank"><img src="https://github.com/expo.png?size=48" title="expo" width="48" height="48"></a><a href="https://github.com/ezra-en" target="_blank"><img src="https://github.com/ezra-en.png?size=48" title="ezra-en" width="48" height="48"></a><a href="https://github.com/feychenie" target="_blank"><img src="https://github.com/feychenie.png?size=48" title="feychenie" width="48" height="48"></a><a href="https://github.com/flaming-codes" target="_blank"><img src="https://github.com/flaming-codes.png?size=48" title="flaming-codes" width="48" height="48"></a><a href="https://github.com/fostertheweb" target="_blank"><img src="https://github.com/fostertheweb.png?size=48" title="fostertheweb" width="48" height="48"></a><a href="https://github.com/Giulio987" target="_blank"><img src="https://github.com/Giulio987.png?size=48" title="Giulio987" width="48" height="48"></a><a href="https://github.com/hi-ogawa" target="_blank"><img src="https://github.com/hi-ogawa.png?size=48" title="hi-ogawa" width="48" height="48"></a><a href="https://github.com/itsdevcoffee" target="_blank"><img src="https://github.com/itsdevcoffee.png?size=48" title="itsdevcoffee" width="48" height="48"></a><a href="https://github.com/jbolda" target="_blank"><img src="https://github.com/jbolda.png?size=48" title="jbolda" width="48" height="48"></a><a href="https://github.com/Kayoo-asso" target="_blank"><img src="https://github.com/Kayoo-asso.png?size=48" title="Kayoo-asso" width="48" height="48"></a><a href="https://github.com/kotofurumiya" target="_blank"><img src="https://github.com/kotofurumiya.png?size=48" title="kotofurumiya" width="48" height="48"></a><a href="https://github.com/Kudo" target="_blank"><img src="https://github.com/Kudo.png?size=48" title="Kudo" width="48" height="48"></a><a href="https://github.com/learn-anything" target="_blank"><img src="https://github.com/learn-anything.png?size=48" title="learn-anything" width="48" height="48"></a><a href="https://github.com/lluc" target="_blank"><img src="https://github.com/lluc.png?size=48" title="lluc" width="48" height="48"></a><a href="https://github.com/marksteve" target="_blank"><img src="https://github.com/marksteve.png?size=48" title="marksteve" width="48" height="48"></a><a href="https://github.com/miking-the-viking" target="_blank"><img src="https://github.com/miking-the-viking.png?size=48" title="miking-the-viking" width="48" height="48"></a><a href="https://github.com/mjamesderocher" target="_blank"><img src="https://github.com/mjamesderocher.png?size=48" title="mjamesderocher" width="48" height="48"></a><a href="https://github.com/mouktardev" target="_blank"><img src="https://github.com/mouktardev.png?size=48" title="mouktardev" width="48" height="48"></a><a href="https://github.com/nickmessing" target="_blank"><img src="https://github.com/nickmessing.png?size=48" title="nickmessing" width="48" height="48"></a><a href="https://github.com/nikitavoloboev" target="_blank"><img src="https://github.com/nikitavoloboev.png?size=48" title="nikitavoloboev" width="48" height="48"></a><a href="https://github.com/nkzw-tech" target="_blank"><img src="https://github.com/nkzw-tech.png?size=48" title="nkzw-tech" width="48" height="48"></a><a href="https://github.com/palerdot" target="_blank"><img src="https://github.com/palerdot.png?size=48" title="palerdot" width="48" height="48"></a><a href="https://github.com/PorcoRosso85" target="_blank"><img src="https://github.com/PorcoRosso85.png?size=48" title="PorcoRosso85" width="48" height="48"></a><a href="https://github.com/primodiumxyz" target="_blank"><img src="https://github.com/primodiumxyz.png?size=48" title="primodiumxyz" width="48" height="48"></a><a href="https://github.com/shaneosullivan" target="_blank"><img src="https://github.com/shaneosullivan.png?size=48" title="shaneosullivan" width="48" height="48"></a><a href="https://github.com/sudo-self" target="_blank"><img src="https://github.com/sudo-self.png?size=48" title="sudo-self" width="48" height="48"></a><a href="https://github.com/SuperSonicHub1" target="_blank"><img src="https://github.com/SuperSonicHub1.png?size=48" title="SuperSonicHub1" width="48" height="48"></a><a href="https://github.com/threepointone" target="_blank"><img src="https://github.com/threepointone.png?size=48" title="threepointone" width="48" height="48"></a><a href="https://github.com/uptonking" target="_blank"><img src="https://github.com/uptonking.png?size=48" title="uptonking" width="48" height="48"></a><a href="https://github.com/ViktorZhurbin" target="_blank"><img src="https://github.com/ViktorZhurbin.png?size=48" title="ViktorZhurbin" width="48" height="48"></a><a href="https://github.com/wilkerlucio" target="_blank"><img src="https://github.com/wilkerlucio.png?size=48" title="wilkerlucio" width="48" height="48"></a><a href="https://github.com/WonderPanda" target="_blank"><img src="https://github.com/WonderPanda.png?size=48" title="WonderPanda" width="48" height="48"></a></section><hr><p><a class="start" href="https://tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://tinybase.org/demos/">Try the demos</a></p><p><a href="https://tinybase.org/api/the-essentials/creating-stores/store/">Read the docs</a></p><hr><section id="family"><h2 id="meet-the-family">Meet the family</h2><p>TinyBase is part of a group of small libraries designed to help make rich client and local-first apps easier to build. Check out the others!</p><p><a href="https://synclets.org" target="_blank"><img src="https://synclets.org/favicon.svg?asImg" width="48"><br><b>Synclets</b></a><br>An open, storage-agnostic, sync engine development kit.</p><p><a href="https://tinywidgets.org" target="_blank"><img src="https://tinywidgets.org/favicon.svg?asImg" width="48"><br><b>TinyWidgets</b></a><br>A collection of tiny, reusable, UI components.</p><p><a href="https://tinytick.org" target="_blank"><img src="https://tinytick.org/favicon.svg?asImg" width="48"><br><b>TinyTick</b></a><br>A tiny but very useful task orchestrator.</p></section><hr><section id="about"><h2 id="about">About</h2><p>Modern apps deserve better. Why trade reactive user experiences to be able to use relational data? Or sacrifice features for bundle size? And why does the cloud do all the work <a href="https://localfirstweb.dev/" target="_blank">anyway</a>?</p><p>Building TinyBase was originally an interesting exercise for <a rel="me" href="https://tripleodeon.com">me</a> in API design, minification, and documentation. But now it has taken on a life of its own, and has grown beyond my wildest expectations.</p><p>It could not have been built without these great <a href="https://tinybase.org/guides/how-tinybase-is-built/credits/#giants">projects</a> and <a href="https://tinybase.org/guides/how-tinybase-is-built/credits/#and-friends">friends</a>, and I hope you enjoy using it as much as I do building it!</p></section><section id="story"><h2 id="the-story">The story</h2><a href="https://youtu.be/hXL7OkW-Prk?t=1232" target="_blank"><img src="https://tinybase.org/youtube.webp"></a></section>
286
+ <section><h2 id="did-we-say-tiny">Did we say tiny?</h2><p>If you use the basic <a href="https://tinybase.org/api/store/"><code>store</code></a> module alone, you&#x27;ll only add a gzipped <em>5.4kB</em> to your app. Incrementally add the other modules as you need more functionality, or get it all for <em>12.1kB</em>.</p><p>The optional <a href="https://tinybase.org/api/ui-react/"><code>ui-react</code></a> module is just <em>5.5kB</em>, the ui-react-dom components are another <em>3.8kB</em>, and everything is super fast. Life is easy when you have zero dependencies!</p><p>Read more about how TinyBase is structured and packaged in the <a href="https://tinybase.org/guides/how-tinybase-is-built/architecture/">Architecture</a> guide.</p></section><div class="table"><table class="fixed"><tbody><tr><th> </th><th>Minified .js.gz</th><th>Source .js</th></tr><tr><th class="right"><a href="https://tinybase.org/api/store/">tinybase/store</a> (minimal)</th><td>5.4kB</td><td>54.6kB</td></tr><tr><th class="right">tinybase (complete)</th><td>12.1kB</td><td>127.0kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react/">ui-react</a></th><td>5.5kB</td><td>59.8kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react-dom/">ui-react-dom</a></th><td>3.8kB</td><td>34.0kB</td></tr></tbody></table></div><section><h2 id="well-tested-and-documented">Well tested and documented.</h2><p>TinyBase has <em>100.0%</em> test coverage, including the code throughout the documentation - even on this page! The guides, demos, and API examples are designed to make it as easy as possible for you to get your TinyBase-powered app up and running.</p><p>Read more about how TinyBase is tested in the Unit <a href="https://tinybase.org/guides/how-tinybase-is-built/testing/">Testing</a> guide.</p></section><div class="table"><table class="fixed"><tbody><tr><th width="30%"> </th><th>Total</th><th>Tested</th><th>Coverage</th></tr><tr><th class="right">Lines</th><td>2,408</td><td>2,408</td><td>100.0%</td></tr><tr><th class="right">Statements</th><td>2,617</td><td>2,617</td><td>100.0%</td></tr><tr><th class="right">Functions</th><td>1,046</td><td>1,046</td><td>100.0%</td></tr><tr><th class="right">Branches</th><td>906</td><td>906</td><td>100.0%</td></tr><tr><th class="right">Tests</th><td colspan="3">7,291</td></tr><tr><th class="right">Assertions</th><td colspan="3">32,336</td></tr></tbody></table></div><hr><section id="sponsors"><h2 id="proud-to-be-supported-by">Proud to be supported by:</h2><a href="https://github.com/fastrepl" target="_blank"><img src="https://github.com/fastrepl.png?size=48" title="fastrepl" width="48" height="48"></a><a href="https://github.com/expo" target="_blank"><img src="https://github.com/expo.png?size=48" title="expo" width="48" height="48"></a><a href="https://github.com/dylmye" target="_blank"><img src="https://github.com/dylmye.png?size=48" title="dylmye" width="48" height="48"></a><a href="https://github.com/ComputelessComputer" target="_blank"><img src="https://github.com/ComputelessComputer.png?size=48" title="ComputelessComputer" width="48" height="48"></a><a href="https://github.com/cancelself" target="_blank"><img src="https://github.com/cancelself.png?size=48" title="cancelself" width="48" height="48"></a><a href="https://github.com/cpojer" target="_blank"><img src="https://github.com/cpojer.png?size=48" title="cpojer" width="48" height="48"></a><a href="https://github.com/beekeeb" target="_blank"><img src="https://github.com/beekeeb.png?size=48" title="beekeeb" width="48" height="48"></a><a href="https://github.com/WonderPanda" target="_blank"><img src="https://github.com/WonderPanda.png?size=48" title="WonderPanda" width="48" height="48"></a><a href="https://github.com/arpitBhalla" target="_blank"><img src="https://github.com/arpitBhalla.png?size=48" title="arpitBhalla" width="48" height="48"></a></section><section id="users"><h2 id="excited-to-be-used-by">Excited to be used by:</h2><a href="https://github.com/behrends" target="_blank"><img src="https://github.com/behrends.png?size=48" title="behrends" width="48" height="48"></a><a href="https://github.com/betomoedano" target="_blank"><img src="https://github.com/betomoedano.png?size=48" title="betomoedano" width="48" height="48"></a><a href="https://github.com/brentvatne" target="_blank"><img src="https://github.com/brentvatne.png?size=48" title="brentvatne" width="48" height="48"></a><a href="https://github.com/byCedric" target="_blank"><img src="https://github.com/byCedric.png?size=48" title="byCedric" width="48" height="48"></a><a href="https://github.com/circadian-risk" target="_blank"><img src="https://github.com/circadian-risk.png?size=48" title="circadian-risk" width="48" height="48"></a><a href="https://github.com/cpojer" target="_blank"><img src="https://github.com/cpojer.png?size=48" title="cpojer" width="48" height="48"></a><a href="https://github.com/cubecull" target="_blank"><img src="https://github.com/cubecull.png?size=48" title="cubecull" width="48" height="48"></a><a href="https://github.com/erwinkn" target="_blank"><img src="https://github.com/erwinkn.png?size=48" title="erwinkn" width="48" height="48"></a><a href="https://github.com/expo" target="_blank"><img src="https://github.com/expo.png?size=48" title="expo" width="48" height="48"></a><a href="https://github.com/ezra-en" target="_blank"><img src="https://github.com/ezra-en.png?size=48" title="ezra-en" width="48" height="48"></a><a href="https://github.com/feychenie" target="_blank"><img src="https://github.com/feychenie.png?size=48" title="feychenie" width="48" height="48"></a><a href="https://github.com/flaming-codes" target="_blank"><img src="https://github.com/flaming-codes.png?size=48" title="flaming-codes" width="48" height="48"></a><a href="https://github.com/fostertheweb" target="_blank"><img src="https://github.com/fostertheweb.png?size=48" title="fostertheweb" width="48" height="48"></a><a href="https://github.com/Giulio987" target="_blank"><img src="https://github.com/Giulio987.png?size=48" title="Giulio987" width="48" height="48"></a><a href="https://github.com/hi-ogawa" target="_blank"><img src="https://github.com/hi-ogawa.png?size=48" title="hi-ogawa" width="48" height="48"></a><a href="https://github.com/itsdevcoffee" target="_blank"><img src="https://github.com/itsdevcoffee.png?size=48" title="itsdevcoffee" width="48" height="48"></a><a href="https://github.com/jbolda" target="_blank"><img src="https://github.com/jbolda.png?size=48" title="jbolda" width="48" height="48"></a><a href="https://github.com/Kayoo-asso" target="_blank"><img src="https://github.com/Kayoo-asso.png?size=48" title="Kayoo-asso" width="48" height="48"></a><a href="https://github.com/kotofurumiya" target="_blank"><img src="https://github.com/kotofurumiya.png?size=48" title="kotofurumiya" width="48" height="48"></a><a href="https://github.com/Kudo" target="_blank"><img src="https://github.com/Kudo.png?size=48" title="Kudo" width="48" height="48"></a><a href="https://github.com/learn-anything" target="_blank"><img src="https://github.com/learn-anything.png?size=48" title="learn-anything" width="48" height="48"></a><a href="https://github.com/lluc" target="_blank"><img src="https://github.com/lluc.png?size=48" title="lluc" width="48" height="48"></a><a href="https://github.com/marksteve" target="_blank"><img src="https://github.com/marksteve.png?size=48" title="marksteve" width="48" height="48"></a><a href="https://github.com/miking-the-viking" target="_blank"><img src="https://github.com/miking-the-viking.png?size=48" title="miking-the-viking" width="48" height="48"></a><a href="https://github.com/mjamesderocher" target="_blank"><img src="https://github.com/mjamesderocher.png?size=48" title="mjamesderocher" width="48" height="48"></a><a href="https://github.com/mouktardev" target="_blank"><img src="https://github.com/mouktardev.png?size=48" title="mouktardev" width="48" height="48"></a><a href="https://github.com/nickmessing" target="_blank"><img src="https://github.com/nickmessing.png?size=48" title="nickmessing" width="48" height="48"></a><a href="https://github.com/nikitavoloboev" target="_blank"><img src="https://github.com/nikitavoloboev.png?size=48" title="nikitavoloboev" width="48" height="48"></a><a href="https://github.com/nkzw-tech" target="_blank"><img src="https://github.com/nkzw-tech.png?size=48" title="nkzw-tech" width="48" height="48"></a><a href="https://github.com/palerdot" target="_blank"><img src="https://github.com/palerdot.png?size=48" title="palerdot" width="48" height="48"></a><a href="https://github.com/PorcoRosso85" target="_blank"><img src="https://github.com/PorcoRosso85.png?size=48" title="PorcoRosso85" width="48" height="48"></a><a href="https://github.com/primodiumxyz" target="_blank"><img src="https://github.com/primodiumxyz.png?size=48" title="primodiumxyz" width="48" height="48"></a><a href="https://github.com/shaneosullivan" target="_blank"><img src="https://github.com/shaneosullivan.png?size=48" title="shaneosullivan" width="48" height="48"></a><a href="https://github.com/sudo-self" target="_blank"><img src="https://github.com/sudo-self.png?size=48" title="sudo-self" width="48" height="48"></a><a href="https://github.com/SuperSonicHub1" target="_blank"><img src="https://github.com/SuperSonicHub1.png?size=48" title="SuperSonicHub1" width="48" height="48"></a><a href="https://github.com/threepointone" target="_blank"><img src="https://github.com/threepointone.png?size=48" title="threepointone" width="48" height="48"></a><a href="https://github.com/uptonking" target="_blank"><img src="https://github.com/uptonking.png?size=48" title="uptonking" width="48" height="48"></a><a href="https://github.com/ViktorZhurbin" target="_blank"><img src="https://github.com/ViktorZhurbin.png?size=48" title="ViktorZhurbin" width="48" height="48"></a><a href="https://github.com/wilkerlucio" target="_blank"><img src="https://github.com/wilkerlucio.png?size=48" title="wilkerlucio" width="48" height="48"></a><a href="https://github.com/WonderPanda" target="_blank"><img src="https://github.com/WonderPanda.png?size=48" title="WonderPanda" width="48" height="48"></a></section><hr><p><a class="start" href="https://tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://tinybase.org/demos/">Try the demos</a></p><p><a href="https://tinybase.org/api/the-essentials/creating-stores/store/">Read the docs</a></p><hr><section id="family"><h2 id="meet-the-family">Meet the family</h2><p>TinyBase is part of a group of small libraries designed to help make rich client and local-first apps easier to build. Check out the others!</p><p><a href="https://synclets.org" target="_blank"><img src="https://synclets.org/favicon.svg?asImg" width="48"><br><b>Synclets</b></a><br>An open, storage-agnostic, sync engine development kit.</p><p><a href="https://tinywidgets.org" target="_blank"><img src="https://tinywidgets.org/favicon.svg?asImg" width="48"><br><b>TinyWidgets</b></a><br>A collection of tiny, reusable, UI components.</p><p><a href="https://tinytick.org" target="_blank"><img src="https://tinytick.org/favicon.svg?asImg" width="48"><br><b>TinyTick</b></a><br>A tiny but very useful task orchestrator.</p></section><hr><section id="about"><h2 id="about">About</h2><p>Modern apps deserve better. Why trade reactive user experiences to be able to use relational data? Or sacrifice features for bundle size? And why does the cloud do all the work <a href="https://localfirstweb.dev/" target="_blank">anyway</a>?</p><p>Building TinyBase was originally an interesting exercise for <a rel="me" href="https://tripleodeon.com">me</a> in API design, minification, and documentation. But now it has taken on a life of its own, and has grown beyond my wildest expectations.</p><p>It could not have been built without these great <a href="https://tinybase.org/guides/how-tinybase-is-built/credits/#giants">projects</a> and <a href="https://tinybase.org/guides/how-tinybase-is-built/credits/#and-friends">friends</a>, and I hope you enjoy using it as much as I do building it!</p></section><section id="story"><h2 id="the-story">The story</h2><a href="https://youtu.be/hXL7OkW-Prk?t=1232" target="_blank"><img src="https://tinybase.org/youtube.webp"></a></section>
@@ -37,20 +37,21 @@ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
37
37
  const object = Object;
38
38
  const objFreeze = object.freeze;
39
39
 
40
- const mapNew = (entries) => new Map(entries);
41
- const mapKeys = (map) => [...(map?.keys() ?? [])];
42
- const mapGet = (map, key) => map?.get(key);
43
- const mapForEach = (map, cb) =>
44
- collForEach(map, (value, key) => cb(key, value));
45
- const mapSet = (map, key, value) =>
46
- isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
47
- const mapEnsure = (map, key, getDefaultValue, hadExistingValue) => {
48
- if (!collHas(map, key)) {
49
- mapSet(map, key, getDefaultValue());
40
+ const map = Map;
41
+ const mapNew = (entries) => new map(entries);
42
+ const mapKeys = (map2) => [...(map2?.keys() ?? [])];
43
+ const mapGet = (map2, key) => map2?.get(key);
44
+ const mapForEach = (map2, cb) =>
45
+ collForEach(map2, (value, key) => cb(key, value));
46
+ const mapSet = (map2, key, value) =>
47
+ isUndefined(value) ? (collDel(map2, key), map2) : map2?.set(key, value);
48
+ const mapEnsure = (map2, key, getDefaultValue, hadExistingValue) => {
49
+ if (!collHas(map2, key)) {
50
+ mapSet(map2, key, getDefaultValue());
50
51
  } else {
51
- hadExistingValue?.(mapGet(map, key));
52
+ hadExistingValue?.(mapGet(map2, key));
52
53
  }
53
- return mapGet(map, key);
54
+ return mapGet(map2, key);
54
55
  };
55
56
  const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
56
57
  ifNotUndefined(
@@ -37,20 +37,21 @@ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
37
37
  const object = Object;
38
38
  const objFreeze = object.freeze;
39
39
 
40
- const mapNew = (entries) => new Map(entries);
41
- const mapKeys = (map) => [...(map?.keys() ?? [])];
42
- const mapGet = (map, key) => map?.get(key);
43
- const mapForEach = (map, cb) =>
44
- collForEach(map, (value, key) => cb(key, value));
45
- const mapSet = (map, key, value) =>
46
- isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
47
- const mapEnsure = (map, key, getDefaultValue, hadExistingValue) => {
48
- if (!collHas(map, key)) {
49
- mapSet(map, key, getDefaultValue());
40
+ const map = Map;
41
+ const mapNew = (entries) => new map(entries);
42
+ const mapKeys = (map2) => [...(map2?.keys() ?? [])];
43
+ const mapGet = (map2, key) => map2?.get(key);
44
+ const mapForEach = (map2, cb) =>
45
+ collForEach(map2, (value, key) => cb(key, value));
46
+ const mapSet = (map2, key, value) =>
47
+ isUndefined(value) ? (collDel(map2, key), map2) : map2?.set(key, value);
48
+ const mapEnsure = (map2, key, getDefaultValue, hadExistingValue) => {
49
+ if (!collHas(map2, key)) {
50
+ mapSet(map2, key, getDefaultValue());
50
51
  } else {
51
- hadExistingValue?.(mapGet(map, key));
52
+ hadExistingValue?.(mapGet(map2, key));
52
53
  }
53
- return mapGet(map, key);
54
+ return mapGet(map2, key);
54
55
  };
55
56
  const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
56
57
  ifNotUndefined(
package/releases.md CHANGED
@@ -339,7 +339,7 @@ export class MyDurableObject extends WsServerDurableObject {
339
339
  }
340
340
  ```
341
341
 
342
- <p>You can get started quickly with this architecture using the <a href="https://github.com/tinyplex/vite-tinybase-ts-react-sync-durable-object">new Vite template</a> that accompanies this release.</p><h2 id="server-reference-implementation">Server Reference Implementation</h2><p>Unrelated to Durable Objects, this release also includes the new <a href="https://tinybase.org/api/synchronizer-ws-server-simple/"><code>synchronizer-ws-server-simple</code></a> module that contains a simple server implementation called <a href="https://tinybase.org/api/synchronizer-ws-server-simple/interfaces/server/wsserversimple/"><code>WsServerSimple</code></a>. Without the complications of listeners, persistence, or statistics, this is more suitable to be used as a reference implementation for other server environments.</p><h2 id="architectural-guide">Architectural Guide</h2><p>To go with this release, we have added new documentation on ways in which you can use TinyBase in an app architecture. Check it out in the new <a href="https://tinybase.org/guides/the-basics/architectural-options/">Architectural Options</a> guide.</p><p>We&#x27;ve also started a new section of documentation for describing integrations, of which the <a href="https://tinybase.org/guides/integrations/cloudflare-durable-objects/">Cloudflare Durable Objects</a> guide, of course, is the first new entry!</p><hr><h1 id="v5-3">v5.3</h1><p>This release is focussed on a few API improvements and quality-of-life changes. These include:</p><h2 id="react-ssr-support">React SSR support</h2><p>Thanks to contributor <a href="https://github.com/muhajirdev">Muhammad Muhajir</a> for ensuring that TinyBase runs in server-side rendering environments!</p><h2 id="in-the-persisters-module">In the <a href="https://tinybase.org/api/persisters/"><code>persisters</code></a> module...</h2><p>All <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> objects now expose information about whether they are loading or saving. To access this <a href="https://tinybase.org/api/persisters/enumerations/lifecycle/status/"><code>Status</code></a>, use:</p><ul><li>The <a href="https://tinybase.org/api/persisters/interfaces/persister/persister/methods/lifecycle/getstatus/"><code>getStatus</code></a> method, which will return 0 when it is idle, 1 when it is loading, and 2 when it is saving.</li><li>The <a href="https://tinybase.org/api/persisters/interfaces/persister/persister/methods/listener/addstatuslistener/"><code>addStatusListener</code></a> method, which lets you add a <a href="https://tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function and which is called whenever the status changes.</li></ul><p>These make it possible to track background load and save activities, so that, for example, you can show a status-bar spinner of asynchronous persistence activity.</p><h2 id="in-the-synchronizers-module">In the <a href="https://tinybase.org/api/synchronizers/"><code>synchronizers</code></a> module...</h2><p>Synchronizers are a sub-class of <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>, so all <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a> objects now also have:</p><ul><li>The <a href="https://tinybase.org/api/persisters/interfaces/persister/persister/methods/lifecycle/getstatus/"><code>getStatus</code></a> method, which will return 0 when it is idle, 1 when it is &#x27;loading&#x27; (ie inbound syncing), and 2 when it is &#x27;saving&#x27; (ie outbound syncing).</li><li>The <a href="https://tinybase.org/api/persisters/interfaces/persister/persister/methods/listener/addstatuslistener/"><code>addStatusListener</code></a> method, which lets you add a <a href="https://tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function and which is called whenever the status changes.</li></ul><h2 id="in-the-ui-react-module">In the <a href="https://tinybase.org/api/ui-react/"><code>ui-react</code></a> module...</h2><p>There are corresponding hooks so that you can build these status changes into a React UI easily:</p><ul><li>The <a href="https://tinybase.org/api/ui-react/functions/persister-hooks/usepersisterstatus/"><code>usePersisterStatus</code></a> hook, which will return the status for an explicitly provided, or context-derived <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/persister-hooks/usepersisterstatuslistener/"><code>usePersisterStatusListener</code></a> hook, which lets you add your own <a href="https://tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function to a <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/persister-hooks/usepersister/"><code>usePersister</code></a> hook, which lets you get direct access to a <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> from within your UI.</li></ul><p>And correspondingly for Synchronizers:</p><ul><li>The <a href="https://tinybase.org/api/ui-react/functions/synchronizer-hooks/usesynchronizerstatus/"><code>useSynchronizerStatus</code></a> hook, which will return the status for an explicitly provided, or context-derived <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a>.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/synchronizer-hooks/usesynchronizerstatuslistener/"><code>useSynchronizerStatusListener</code></a> hook, which lets you add your own <a href="https://tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function to a <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a>.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/synchronizer-hooks/usesynchronizer/"><code>useSynchronizer</code></a> hook, which lets you get direct access to a <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a> from within your UI.</li></ul><p>In addition, this module also now includes hooks for injecting objects into the Provider context scope imperatively, much like the existing <a href="https://tinybase.org/api/ui-react/functions/store-hooks/useprovidestore/"><code>useProvideStore</code></a> hook:</p><ul><li>The <a href="https://tinybase.org/api/ui-react/functions/metrics-hooks/useprovidemetrics/"><code>useProvideMetrics</code></a> hook, which lets you imperatively register <a href="https://tinybase.org/api/metrics/interfaces/metrics/metrics/"><code>Metrics</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/indexes-hooks/useprovideindexes/"><code>useProvideIndexes</code></a> hook, which lets you register <a href="https://tinybase.org/api/indexes/interfaces/indexes/indexes/"><code>Indexes</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/relationships-hooks/useproviderelationships/"><code>useProvideRelationships</code></a> hook, which lets you register <a href="https://tinybase.org/api/relationships/interfaces/relationships/relationships/"><code>Relationships</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/queries-hooks/useprovidequeries/"><code>useProvideQueries</code></a> hook, which lets you register <a href="https://tinybase.org/api/queries/interfaces/queries/queries/"><code>Queries</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/checkpoints-hooks/useprovidecheckpoints/"><code>useProvideCheckpoints</code></a> hook, which lets you register <a href="https://tinybase.org/api/checkpoints/interfaces/checkpoints/checkpoints/"><code>Checkpoints</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/persister-hooks/useprovidepersister/"><code>useProvidePersister</code></a> hook, which lets you register <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/synchronizer-hooks/useprovidesynchronizer/"><code>useProvideSynchronizer</code></a> hook, which lets you register <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a> objects.</li></ul><p>All of these new methods have extensive documentation, each with examples to show how to use them.</p><p>Please provide feedback on this new release on GitHub!</p><hr><h1 id="v5-2">v5.2</h1><p>This release introduces new Persisters for... PostgreSQL! TinyBase now has two new <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> modules:</p><ul><li>The <a href="https://tinybase.org/api/persister-postgres/"><code>persister-postgres</code></a> module provides the <a href="https://tinybase.org/api/persister-postgres/interfaces/persister/postgrespersister/"><code>PostgresPersister</code></a>, which uses the excellent <a href="https://github.com/porsager/postgres"><code>postgres</code></a> module to bind to regular PostgreSQL databases, generally on a server.</li><li>The <a href="https://tinybase.org/api/persister-pglite/"><code>persister-pglite</code></a> module provides the <a href="https://tinybase.org/api/persister-pglite/interfaces/persister/pglitepersister/"><code>PglitePersister</code></a>, which uses the new and exciting <a href="https://github.com/electric-sql/pglite"><code>pglite</code></a> module for running PostgreSQL... in a browser!</li></ul><p>Conceptually, things behave in the same way as they do for the various SQLite persisters. Simply use the <a href="https://tinybase.org/api/persister-postgres/functions/creation/createpostgrespersister/"><code>createPostgresPersister</code></a> function (or the similar <a href="https://tinybase.org/api/the-essentials/persisting-stores/createpglitepersister/"><code>createPglitePersister</code></a> function) to persist your TinyBase data:</p>
342
+ <p>You can get started quickly with this architecture using the Durable Objects option in the <a href="https://github.com/tinyplex/create-tinybase"><code>create-tinybase</code> tool</a>.</p><h2 id="server-reference-implementation">Server Reference Implementation</h2><p>Unrelated to Durable Objects, this release also includes the new <a href="https://tinybase.org/api/synchronizer-ws-server-simple/"><code>synchronizer-ws-server-simple</code></a> module that contains a simple server implementation called <a href="https://tinybase.org/api/synchronizer-ws-server-simple/interfaces/server/wsserversimple/"><code>WsServerSimple</code></a>. Without the complications of listeners, persistence, or statistics, this is more suitable to be used as a reference implementation for other server environments.</p><h2 id="architectural-guide">Architectural Guide</h2><p>To go with this release, we have added new documentation on ways in which you can use TinyBase in an app architecture. Check it out in the new <a href="https://tinybase.org/guides/the-basics/architectural-options/">Architectural Options</a> guide.</p><p>We&#x27;ve also started a new section of documentation for describing integrations, of which the <a href="https://tinybase.org/guides/integrations/cloudflare-durable-objects/">Cloudflare Durable Objects</a> guide, of course, is the first new entry!</p><hr><h1 id="v5-3">v5.3</h1><p>This release is focussed on a few API improvements and quality-of-life changes. These include:</p><h2 id="react-ssr-support">React SSR support</h2><p>Thanks to contributor <a href="https://github.com/muhajirdev">Muhammad Muhajir</a> for ensuring that TinyBase runs in server-side rendering environments!</p><h2 id="in-the-persisters-module">In the <a href="https://tinybase.org/api/persisters/"><code>persisters</code></a> module...</h2><p>All <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> objects now expose information about whether they are loading or saving. To access this <a href="https://tinybase.org/api/persisters/enumerations/lifecycle/status/"><code>Status</code></a>, use:</p><ul><li>The <a href="https://tinybase.org/api/persisters/interfaces/persister/persister/methods/lifecycle/getstatus/"><code>getStatus</code></a> method, which will return 0 when it is idle, 1 when it is loading, and 2 when it is saving.</li><li>The <a href="https://tinybase.org/api/persisters/interfaces/persister/persister/methods/listener/addstatuslistener/"><code>addStatusListener</code></a> method, which lets you add a <a href="https://tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function and which is called whenever the status changes.</li></ul><p>These make it possible to track background load and save activities, so that, for example, you can show a status-bar spinner of asynchronous persistence activity.</p><h2 id="in-the-synchronizers-module">In the <a href="https://tinybase.org/api/synchronizers/"><code>synchronizers</code></a> module...</h2><p>Synchronizers are a sub-class of <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>, so all <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a> objects now also have:</p><ul><li>The <a href="https://tinybase.org/api/persisters/interfaces/persister/persister/methods/lifecycle/getstatus/"><code>getStatus</code></a> method, which will return 0 when it is idle, 1 when it is &#x27;loading&#x27; (ie inbound syncing), and 2 when it is &#x27;saving&#x27; (ie outbound syncing).</li><li>The <a href="https://tinybase.org/api/persisters/interfaces/persister/persister/methods/listener/addstatuslistener/"><code>addStatusListener</code></a> method, which lets you add a <a href="https://tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function and which is called whenever the status changes.</li></ul><h2 id="in-the-ui-react-module">In the <a href="https://tinybase.org/api/ui-react/"><code>ui-react</code></a> module...</h2><p>There are corresponding hooks so that you can build these status changes into a React UI easily:</p><ul><li>The <a href="https://tinybase.org/api/ui-react/functions/persister-hooks/usepersisterstatus/"><code>usePersisterStatus</code></a> hook, which will return the status for an explicitly provided, or context-derived <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/persister-hooks/usepersisterstatuslistener/"><code>usePersisterStatusListener</code></a> hook, which lets you add your own <a href="https://tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function to a <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/persister-hooks/usepersister/"><code>usePersister</code></a> hook, which lets you get direct access to a <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> from within your UI.</li></ul><p>And correspondingly for Synchronizers:</p><ul><li>The <a href="https://tinybase.org/api/ui-react/functions/synchronizer-hooks/usesynchronizerstatus/"><code>useSynchronizerStatus</code></a> hook, which will return the status for an explicitly provided, or context-derived <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a>.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/synchronizer-hooks/usesynchronizerstatuslistener/"><code>useSynchronizerStatusListener</code></a> hook, which lets you add your own <a href="https://tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function to a <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a>.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/synchronizer-hooks/usesynchronizer/"><code>useSynchronizer</code></a> hook, which lets you get direct access to a <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a> from within your UI.</li></ul><p>In addition, this module also now includes hooks for injecting objects into the Provider context scope imperatively, much like the existing <a href="https://tinybase.org/api/ui-react/functions/store-hooks/useprovidestore/"><code>useProvideStore</code></a> hook:</p><ul><li>The <a href="https://tinybase.org/api/ui-react/functions/metrics-hooks/useprovidemetrics/"><code>useProvideMetrics</code></a> hook, which lets you imperatively register <a href="https://tinybase.org/api/metrics/interfaces/metrics/metrics/"><code>Metrics</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/indexes-hooks/useprovideindexes/"><code>useProvideIndexes</code></a> hook, which lets you register <a href="https://tinybase.org/api/indexes/interfaces/indexes/indexes/"><code>Indexes</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/relationships-hooks/useproviderelationships/"><code>useProvideRelationships</code></a> hook, which lets you register <a href="https://tinybase.org/api/relationships/interfaces/relationships/relationships/"><code>Relationships</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/queries-hooks/useprovidequeries/"><code>useProvideQueries</code></a> hook, which lets you register <a href="https://tinybase.org/api/queries/interfaces/queries/queries/"><code>Queries</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/checkpoints-hooks/useprovidecheckpoints/"><code>useProvideCheckpoints</code></a> hook, which lets you register <a href="https://tinybase.org/api/checkpoints/interfaces/checkpoints/checkpoints/"><code>Checkpoints</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/persister-hooks/useprovidepersister/"><code>useProvidePersister</code></a> hook, which lets you register <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> objects.</li><li>The <a href="https://tinybase.org/api/ui-react/functions/synchronizer-hooks/useprovidesynchronizer/"><code>useProvideSynchronizer</code></a> hook, which lets you register <a href="https://tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a> objects.</li></ul><p>All of these new methods have extensive documentation, each with examples to show how to use them.</p><p>Please provide feedback on this new release on GitHub!</p><hr><h1 id="v5-2">v5.2</h1><p>This release introduces new Persisters for... PostgreSQL! TinyBase now has two new <a href="https://tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> modules:</p><ul><li>The <a href="https://tinybase.org/api/persister-postgres/"><code>persister-postgres</code></a> module provides the <a href="https://tinybase.org/api/persister-postgres/interfaces/persister/postgrespersister/"><code>PostgresPersister</code></a>, which uses the excellent <a href="https://github.com/porsager/postgres"><code>postgres</code></a> module to bind to regular PostgreSQL databases, generally on a server.</li><li>The <a href="https://tinybase.org/api/persister-pglite/"><code>persister-pglite</code></a> module provides the <a href="https://tinybase.org/api/persister-pglite/interfaces/persister/pglitepersister/"><code>PglitePersister</code></a>, which uses the new and exciting <a href="https://github.com/electric-sql/pglite"><code>pglite</code></a> module for running PostgreSQL... in a browser!</li></ul><p>Conceptually, things behave in the same way as they do for the various SQLite persisters. Simply use the <a href="https://tinybase.org/api/persister-postgres/functions/creation/createpostgrespersister/"><code>createPostgresPersister</code></a> function (or the similar <a href="https://tinybase.org/api/the-essentials/persisting-stores/createpglitepersister/"><code>createPglitePersister</code></a> function) to persist your TinyBase data:</p>
343
343
 
344
344
  ```js
345
345
  import postgres from 'postgres';