tinybase 9.5.1 → 9.6.0

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 (151) hide show
  1. package/@types/omni/index.d.ts +4 -0
  2. package/@types/omni/with-schemas/index.d.ts +4 -0
  3. package/@types/persisters/index.d.ts +8 -1
  4. package/@types/persisters/persister-better-sqlite3/index.d.ts +178 -0
  5. package/@types/persisters/persister-better-sqlite3/with-schemas/index.d.ts +202 -0
  6. package/@types/persisters/persister-capacitor-sqlite/index.d.ts +181 -0
  7. package/@types/persisters/persister-capacitor-sqlite/with-schemas/index.d.ts +205 -0
  8. package/@types/persisters/persister-indexed-db/index.d.ts +17 -9
  9. package/@types/persisters/persister-indexed-db/with-schemas/index.d.ts +18 -10
  10. package/@types/persisters/persister-libsql/index.d.ts +27 -0
  11. package/@types/persisters/persister-libsql/with-schemas/index.d.ts +27 -0
  12. package/@types/persisters/persister-pg/index.d.ts +197 -0
  13. package/@types/persisters/persister-pg/with-schemas/index.d.ts +222 -0
  14. package/@types/persisters/persister-supabase/index.d.ts +201 -0
  15. package/@types/persisters/persister-supabase/with-schemas/index.d.ts +217 -0
  16. package/@types/persisters/with-schemas/index.d.ts +8 -1
  17. package/min/omni/index.js +1 -1
  18. package/min/omni/index.js.gz +0 -0
  19. package/min/omni/with-schemas/index.js +1 -1
  20. package/min/omni/with-schemas/index.js.gz +0 -0
  21. package/min/persisters/index.js +1 -1
  22. package/min/persisters/index.js.gz +0 -0
  23. package/min/persisters/persister-better-sqlite3/index.js +1 -0
  24. package/min/persisters/persister-better-sqlite3/index.js.gz +0 -0
  25. package/min/persisters/persister-better-sqlite3/with-schemas/index.js +1 -0
  26. package/min/persisters/persister-better-sqlite3/with-schemas/index.js.gz +0 -0
  27. package/min/persisters/persister-capacitor-sqlite/index.js +1 -0
  28. package/min/persisters/persister-capacitor-sqlite/index.js.gz +0 -0
  29. package/min/persisters/persister-capacitor-sqlite/with-schemas/index.js +1 -0
  30. package/min/persisters/persister-capacitor-sqlite/with-schemas/index.js.gz +0 -0
  31. package/min/persisters/persister-cr-sqlite-wasm/index.js +1 -1
  32. package/min/persisters/persister-cr-sqlite-wasm/index.js.gz +0 -0
  33. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +1 -1
  34. package/min/persisters/persister-cr-sqlite-wasm/with-schemas/index.js.gz +0 -0
  35. package/min/persisters/persister-durable-object-sql-storage/index.js +1 -1
  36. package/min/persisters/persister-durable-object-sql-storage/index.js.gz +0 -0
  37. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js +1 -1
  38. package/min/persisters/persister-durable-object-sql-storage/with-schemas/index.js.gz +0 -0
  39. package/min/persisters/persister-electric-sql/index.js +1 -1
  40. package/min/persisters/persister-electric-sql/index.js.gz +0 -0
  41. package/min/persisters/persister-electric-sql/with-schemas/index.js +1 -1
  42. package/min/persisters/persister-electric-sql/with-schemas/index.js.gz +0 -0
  43. package/min/persisters/persister-expo-sqlite/index.js +1 -1
  44. package/min/persisters/persister-expo-sqlite/index.js.gz +0 -0
  45. package/min/persisters/persister-expo-sqlite/with-schemas/index.js +1 -1
  46. package/min/persisters/persister-expo-sqlite/with-schemas/index.js.gz +0 -0
  47. package/min/persisters/persister-indexed-db/index.js +1 -1
  48. package/min/persisters/persister-indexed-db/index.js.gz +0 -0
  49. package/min/persisters/persister-indexed-db/with-schemas/index.js +1 -1
  50. package/min/persisters/persister-indexed-db/with-schemas/index.js.gz +0 -0
  51. package/min/persisters/persister-libsql/index.js +1 -1
  52. package/min/persisters/persister-libsql/index.js.gz +0 -0
  53. package/min/persisters/persister-libsql/with-schemas/index.js +1 -1
  54. package/min/persisters/persister-libsql/with-schemas/index.js.gz +0 -0
  55. package/min/persisters/persister-pg/index.js +1 -0
  56. package/min/persisters/persister-pg/index.js.gz +0 -0
  57. package/min/persisters/persister-pg/with-schemas/index.js +1 -0
  58. package/min/persisters/persister-pg/with-schemas/index.js.gz +0 -0
  59. package/min/persisters/persister-pglite/index.js +1 -1
  60. package/min/persisters/persister-pglite/index.js.gz +0 -0
  61. package/min/persisters/persister-pglite/with-schemas/index.js +1 -1
  62. package/min/persisters/persister-pglite/with-schemas/index.js.gz +0 -0
  63. package/min/persisters/persister-postgres/index.js +1 -1
  64. package/min/persisters/persister-postgres/index.js.gz +0 -0
  65. package/min/persisters/persister-postgres/with-schemas/index.js +1 -1
  66. package/min/persisters/persister-postgres/with-schemas/index.js.gz +0 -0
  67. package/min/persisters/persister-powersync/index.js +1 -1
  68. package/min/persisters/persister-powersync/index.js.gz +0 -0
  69. package/min/persisters/persister-powersync/with-schemas/index.js +1 -1
  70. package/min/persisters/persister-powersync/with-schemas/index.js.gz +0 -0
  71. package/min/persisters/persister-react-native-sqlite/index.js +1 -1
  72. package/min/persisters/persister-react-native-sqlite/index.js.gz +0 -0
  73. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js +1 -1
  74. package/min/persisters/persister-react-native-sqlite/with-schemas/index.js.gz +0 -0
  75. package/min/persisters/persister-sqlite-bun/index.js +1 -1
  76. package/min/persisters/persister-sqlite-bun/index.js.gz +0 -0
  77. package/min/persisters/persister-sqlite-bun/with-schemas/index.js +1 -1
  78. package/min/persisters/persister-sqlite-bun/with-schemas/index.js.gz +0 -0
  79. package/min/persisters/persister-sqlite-wasm/index.js +1 -1
  80. package/min/persisters/persister-sqlite-wasm/index.js.gz +0 -0
  81. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js +1 -1
  82. package/min/persisters/persister-sqlite-wasm/with-schemas/index.js.gz +0 -0
  83. package/min/persisters/persister-sqlite3/index.js +1 -1
  84. package/min/persisters/persister-sqlite3/index.js.gz +0 -0
  85. package/min/persisters/persister-sqlite3/with-schemas/index.js +1 -1
  86. package/min/persisters/persister-sqlite3/with-schemas/index.js.gz +0 -0
  87. package/min/persisters/persister-supabase/index.js +1 -0
  88. package/min/persisters/persister-supabase/index.js.gz +0 -0
  89. package/min/persisters/persister-supabase/with-schemas/index.js +1 -0
  90. package/min/persisters/persister-supabase/with-schemas/index.js.gz +0 -0
  91. package/min/persisters/with-schemas/index.js +1 -1
  92. package/min/persisters/with-schemas/index.js.gz +0 -0
  93. package/min/ui-svelte-dom/index.js +1 -1
  94. package/min/ui-svelte-dom/index.js.gz +0 -0
  95. package/min/ui-svelte-dom/with-schemas/index.js +1 -1
  96. package/min/ui-svelte-dom/with-schemas/index.js.gz +0 -0
  97. package/min/ui-svelte-inspector/index.js +1 -1
  98. package/min/ui-svelte-inspector/index.js.gz +0 -0
  99. package/min/ui-svelte-inspector/with-schemas/index.js +1 -1
  100. package/min/ui-svelte-inspector/with-schemas/index.js.gz +0 -0
  101. package/omni/index.js +269 -34
  102. package/omni/with-schemas/index.js +269 -34
  103. package/package.json +168 -8
  104. package/persisters/index.js +23 -7
  105. package/persisters/persister-better-sqlite3/index.js +1767 -0
  106. package/persisters/persister-better-sqlite3/with-schemas/index.js +1767 -0
  107. package/persisters/persister-capacitor-sqlite/index.js +1769 -0
  108. package/persisters/persister-capacitor-sqlite/with-schemas/index.js +1769 -0
  109. package/persisters/persister-cr-sqlite-wasm/index.js +20 -6
  110. package/persisters/persister-cr-sqlite-wasm/with-schemas/index.js +20 -6
  111. package/persisters/persister-durable-object-sql-storage/index.js +20 -7
  112. package/persisters/persister-durable-object-sql-storage/with-schemas/index.js +20 -7
  113. package/persisters/persister-electric-sql/index.js +20 -6
  114. package/persisters/persister-electric-sql/with-schemas/index.js +20 -6
  115. package/persisters/persister-expo-sqlite/index.js +20 -6
  116. package/persisters/persister-expo-sqlite/with-schemas/index.js +20 -6
  117. package/persisters/persister-indexed-db/index.js +48 -20
  118. package/persisters/persister-indexed-db/with-schemas/index.js +48 -20
  119. package/persisters/persister-libsql/index.js +20 -6
  120. package/persisters/persister-libsql/with-schemas/index.js +20 -6
  121. package/persisters/persister-pg/index.js +1905 -0
  122. package/persisters/persister-pg/with-schemas/index.js +1905 -0
  123. package/persisters/persister-pglite/index.js +20 -6
  124. package/persisters/persister-pglite/with-schemas/index.js +20 -6
  125. package/persisters/persister-postgres/index.js +20 -6
  126. package/persisters/persister-postgres/with-schemas/index.js +20 -6
  127. package/persisters/persister-powersync/index.js +27 -10
  128. package/persisters/persister-powersync/with-schemas/index.js +27 -10
  129. package/persisters/persister-react-native-sqlite/index.js +20 -6
  130. package/persisters/persister-react-native-sqlite/with-schemas/index.js +20 -6
  131. package/persisters/persister-sqlite-bun/index.js +20 -6
  132. package/persisters/persister-sqlite-bun/with-schemas/index.js +20 -6
  133. package/persisters/persister-sqlite-wasm/index.js +20 -6
  134. package/persisters/persister-sqlite-wasm/with-schemas/index.js +20 -6
  135. package/persisters/persister-sqlite3/index.js +20 -6
  136. package/persisters/persister-sqlite3/with-schemas/index.js +20 -6
  137. package/persisters/persister-supabase/index.js +883 -0
  138. package/persisters/persister-supabase/with-schemas/index.js +883 -0
  139. package/persisters/with-schemas/index.js +23 -7
  140. package/readme.md +3 -3
  141. package/releases.md +106 -1
  142. package/ui-solid-dom/index.js +0 -1
  143. package/ui-solid-dom/with-schemas/index.js +0 -1
  144. package/ui-solid-inspector/index.js +0 -1
  145. package/ui-solid-inspector/with-schemas/index.js +0 -1
  146. package/ui-svelte/index.js +1 -1
  147. package/ui-svelte/with-schemas/index.js +1 -1
  148. package/ui-svelte-dom/index.js +17 -49
  149. package/ui-svelte-dom/with-schemas/index.js +17 -49
  150. package/ui-svelte-inspector/index.js +23 -69
  151. package/ui-svelte-inspector/with-schemas/index.js +23 -69
@@ -876,9 +876,11 @@ const escapeId = (str) =>
876
876
  const escapeIds = (...ids) => escapeId(arrayJoin(ids, '_'));
877
877
  const escapeColumnNames = (...columnNames) =>
878
878
  arrayJoin(arrayMap(columnNames, escapeId), COMMA);
879
- const getPlaceholders = (array, offset = [1]) =>
879
+ const numberedPlaceholder = (offset) => '$' + offset[0]++;
880
+ const anonymousPlaceholder = () => '?';
881
+ const getPlaceholders = (array, getPlaceholder, offset = [1]) =>
880
882
  arrayJoin(
881
- arrayMap(array, () => '$' + offset[0]++),
883
+ arrayMap(array, () => getPlaceholder(offset)),
882
884
  COMMA,
883
885
  );
884
886
  const getWhereCondition = (tableName, condition = TRUE) =>
@@ -1015,6 +1017,7 @@ const getCommandFunctions = (
1015
1017
  managedTableNames,
1016
1018
  querySchema,
1017
1019
  columnType,
1020
+ getPlaceholder,
1018
1021
  upsert = defaultUpsert,
1019
1022
  encode,
1020
1023
  decode,
@@ -1225,7 +1228,7 @@ const getCommandFunctions = (
1225
1228
  DELETE_FROM +
1226
1229
  escapeId(tableName) +
1227
1230
  getWhereCondition(tableName, condition) +
1228
- `AND(${escapeId(rowIdColumnName)}=$1)`,
1231
+ `AND(${escapeId(rowIdColumnName)}=${getPlaceholder([1])})`,
1229
1232
  [rowId],
1230
1233
  );
1231
1234
  } else if (!isEmpty(settingColumnNames)) {
@@ -1244,6 +1247,7 @@ const getCommandFunctions = (
1244
1247
  encode ? encode(row[cellId]) : row[cellId],
1245
1248
  ),
1246
1249
  },
1250
+ getPlaceholder,
1247
1251
  currentColumnNames,
1248
1252
  );
1249
1253
  }
@@ -1277,13 +1281,14 @@ const getCommandFunctions = (
1277
1281
  rowIdColumnName,
1278
1282
  changingColumnNames,
1279
1283
  rows,
1284
+ getPlaceholder,
1280
1285
  currentColumnNames,
1281
1286
  );
1282
1287
  await executeCommand(
1283
1288
  DELETE_FROM +
1284
1289
  escapeId(tableName) +
1285
1290
  getWhereCondition(tableName, condition) + // eslint-disable-next-line max-len
1286
- `AND${escapeId(rowIdColumnName)}NOT IN(${getPlaceholders(deleteRowIds)})`,
1291
+ `AND${escapeId(rowIdColumnName)}NOT IN(${getPlaceholders(deleteRowIds, getPlaceholder)})`,
1287
1292
  deleteRowIds,
1288
1293
  );
1289
1294
  } else if (
@@ -1326,6 +1331,7 @@ const defaultUpsert = async (
1326
1331
  rowIdColumnName,
1327
1332
  changingColumnNames,
1328
1333
  rows,
1334
+ getPlaceholder,
1329
1335
  ) => {
1330
1336
  const offset = [1];
1331
1337
  await executeCommand(
@@ -1339,7 +1345,11 @@ const defaultUpsert = async (
1339
1345
  objToArray(
1340
1346
  rows,
1341
1347
  (row) =>
1342
- '($' + offset[0]++ + ',' + getPlaceholders(row, offset) + ')',
1348
+ '(' +
1349
+ getPlaceholder(offset) +
1350
+ ',' +
1351
+ getPlaceholders(row, getPlaceholder, offset) +
1352
+ ')',
1343
1353
  ),
1344
1354
  COMMA,
1345
1355
  ) +
@@ -1375,6 +1385,7 @@ const createJsonPersister = (
1375
1385
  thing,
1376
1386
  getThing,
1377
1387
  columnType,
1388
+ getPlaceholder,
1378
1389
  upsert,
1379
1390
  _encode,
1380
1391
  _decode,
@@ -1386,6 +1397,7 @@ const createJsonPersister = (
1386
1397
  managedTableNames,
1387
1398
  querySchema,
1388
1399
  columnType,
1400
+ getPlaceholder,
1389
1401
  upsert,
1390
1402
  void 0,
1391
1403
  void 0,
@@ -1453,6 +1465,7 @@ const createTabularPersister = (
1453
1465
  thing,
1454
1466
  getThing,
1455
1467
  columnType,
1468
+ getPlaceholder,
1456
1469
  upsert,
1457
1470
  encode,
1458
1471
  decode,
@@ -1464,6 +1477,7 @@ const createTabularPersister = (
1464
1477
  managedTableNames,
1465
1478
  querySchema,
1466
1479
  columnType,
1480
+ getPlaceholder,
1467
1481
  upsert,
1468
1482
  encode,
1469
1483
  decode,
@@ -1833,12 +1847,13 @@ const createCustomPostgreSqlPersister = (
1833
1847
  async (executeCommand2, managedTableNames) =>
1834
1848
  await executeCommand2(
1835
1849
  SELECT + // eslint-disable-next-line max-len
1836
- ` c.table_name tn,c.column_name cn,CASE WHEN tc.constraint_type IN('PRIMARY KEY','UNIQUE')AND(${SELECT} count(*) FROM information_schema.key_column_usage kcu2 ${WHERE} kcu2.constraint_schema=kcu.constraint_schema AND kcu2.constraint_name=kcu.constraint_name)=1 THEN 1 ELSE 0 END uq FROM information_schema.columns c LEFT JOIN information_schema.key_column_usage kcu ON kcu.table_schema=c.table_schema AND kcu.table_name=c.table_name AND kcu.column_name=c.column_name LEFT JOIN information_schema.table_constraints tc ON tc.constraint_schema=kcu.constraint_schema AND tc.constraint_name=kcu.constraint_name ${WHERE} c.table_schema='public'AND c.table_name IN(${getPlaceholders(managedTableNames)})`,
1850
+ ` c.table_name tn,c.column_name cn,CASE WHEN tc.constraint_type IN('PRIMARY KEY','UNIQUE')AND(${SELECT} count(*) FROM information_schema.key_column_usage kcu2 ${WHERE} kcu2.constraint_schema=kcu.constraint_schema AND kcu2.constraint_name=kcu.constraint_name)=1 THEN 1 ELSE 0 END uq FROM information_schema.columns c LEFT JOIN information_schema.key_column_usage kcu ON kcu.table_schema=c.table_schema AND kcu.table_name=c.table_name AND kcu.column_name=c.column_name LEFT JOIN information_schema.table_constraints tc ON tc.constraint_schema=kcu.constraint_schema AND tc.constraint_name=kcu.constraint_name ${WHERE} c.table_schema='public'AND c.table_name IN(${getPlaceholders(managedTableNames, numberedPlaceholder)})`,
1837
1851
  managedTableNames,
1838
1852
  ),
1839
1853
  thing,
1840
1854
  getThing,
1841
1855
  'text',
1856
+ numberedPlaceholder,
1842
1857
  void 0,
1843
1858
  (cellOrValue) => jsonString(cellOrValue),
1844
1859
  (field) => jsonParse(field),
@@ -1981,12 +1996,13 @@ const createCustomSqlitePersister = (
1981
1996
  async (executeCommand2, managedTableNames) =>
1982
1997
  await executeCommand2(
1983
1998
  SELECT + // eslint-disable-next-line max-len
1984
- ` t.name tn,c.name cn,c.pk OR EXISTS(${SELECT} 1 FROM ${PRAGMA}index_list(t.name)i,${PRAGMA}index_info(i.name)ii ${WHERE} i."unique"=1 AND ii.name=c.name AND(${SELECT} count(*) FROM ${PRAGMA}index_info(i.name))=1)uq FROM ${PRAGMA_TABLE}list()t,${PRAGMA_TABLE}info(t.name)c ${WHERE} t.schema='main'AND t.type IN('table','view')AND t.name IN(${getPlaceholders(managedTableNames)})ORDER BY t.name,c.name`,
1999
+ ` t.name tn,c.name cn,c.pk OR EXISTS(${SELECT} 1 FROM ${PRAGMA}index_list(t.name)i,${PRAGMA}index_info(i.name)ii ${WHERE} i."unique"=1 AND ii.name=c.name AND(${SELECT} count(*) FROM ${PRAGMA}index_info(i.name))=1)uq FROM ${PRAGMA_TABLE}list()t,${PRAGMA_TABLE}info(t.name)c ${WHERE} t.schema='main'AND t.type IN('table','view')AND t.name IN(${getPlaceholders(managedTableNames, anonymousPlaceholder)})ORDER BY t.name,c.name`,
1985
2000
  managedTableNames,
1986
2001
  ),
1987
2002
  thing,
1988
2003
  getThing,
1989
2004
  EMPTY_STRING,
2005
+ anonymousPlaceholder,
1990
2006
  upsert,
1991
2007
  (cellOrValue) =>
1992
2008
  isTrue(cellOrValue) ? 1 : isFalse(cellOrValue) ? 0 : cellOrValue,
package/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- <link rel="preload" as="image" href="https://tinybase.org/react.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/solid.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/svelte.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/shots/styled-chart-react-demo.png"><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/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/expo.png?size=48"><link rel="preload" as="image" href="https://github.com/braden-w.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/gonza224.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="local-first"><em>Local</em> first.</h2><h2 id="sync-on-demand"><em>Sync</em> on demand.</h2><h2 id="fast-always"><em>Fast</em> always.</h2><p>TinyBase is a reactive in-memory data store with persistence and synchronization for local-first JavaScript and TypeScript apps that need to feel instant, work offline, and stay consistent when they come back online.</p></section><p><a href="https://tinybase.org/guides/releases/#v9-5"><em>NEW!</em> v9.5 release</a></p><p><span id="one-with">&quot;The one with enums and unions!&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="your-first-tinybase-app">Your first <em>TinyBase</em> app</h2><p>Create a todo list, a chat app, a drawing tool, a charting app, or a tic-tac-toe game - with sync &amp; persistence! - in less than 60s.</p></section>
1
+ <link rel="preload" as="image" href="https://tinybase.org/react.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/solid.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/svelte.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/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/capacitor.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/turso.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/crsqlite.png"><link rel="preload" as="image" href="https://tinybase.org/electric.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/powersync.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/neon.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/supabase.svg?asImg"><link rel="preload" as="image" href="https://tinybase.org/cloudflare.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/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/shots/styled-chart-react-demo.png"><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/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/expo.png?size=48"><link rel="preload" as="image" href="https://github.com/braden-w.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/gonza224.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="local-first"><em>Local</em> first.</h2><h2 id="sync-on-demand"><em>Sync</em> on demand.</h2><h2 id="fast-always"><em>Fast</em> always.</h2><p>TinyBase is a reactive in-memory data store with persistence and synchronization for local-first JavaScript and TypeScript apps that need to feel instant, work offline, and stay consistent when they come back online.</p></section><p><a href="https://tinybase.org/guides/releases/#v9-6"><em>NEW!</em> v9.6 release</a></p><p><span id="one-with">&quot;The one with more persisters!&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="your-first-tinybase-app">Your first <em>TinyBase</em> app</h2><p>Create a todo list, a chat app, a drawing tool, a charting app, or a tic-tac-toe game - with sync &amp; persistence! - in less than 60s.</p></section>
2
2
 
3
3
  ```bash
4
4
  > npm create tinybase@latest
@@ -6,7 +6,7 @@
6
6
  📦 Creating your project...
7
7
  ```
8
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>, <a href="#pre-built-reactive-components">pre-built components</a>, and <a href="#local-first-data-visualizations">charts</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-or-a-database">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">7.3kB - 16.4kB</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><h3 id="ui-frameworks"><a href="https://tinybase.org/guides/">UI Frameworks</a></h3><div><a href="https://tinybase.org/guides/building-uis-with-react/getting-started-with-ui-react"><img src="https://tinybase.org/react.svg?asImg" width="48"> React</a></div><div><a href="https://tinybase.org/guides/building-uis-with-solid/getting-started-with-ui-solid"><img src="https://tinybase.org/solid.svg?asImg" width="48"> Solid</a></div><div><a href="https://tinybase.org/guides/building-uis-with-svelte/getting-started-with-ui-svelte"><img src="https://tinybase.org/svelte.svg?asImg" width="48"> Svelte</a></div><h3 id="storage-sync"><a href="https://tinybase.org/guides/persistence/">Storage &amp; Sync</a></h3><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><h3 id="schema-systems"><a href="https://tinybase.org/guides/schemas/using-schematizers/">Schema Systems</a></h3><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/9.5.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>
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>, <a href="#pre-built-reactive-components">pre-built components</a>, and <a href="#local-first-data-visualizations">charts</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-or-a-database">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">7.3kB - 16.4kB</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><h3 id="ui-frameworks"><a href="https://tinybase.org/guides/">UI Frameworks</a></h3><div><a href="https://tinybase.org/guides/building-uis-with-react/getting-started-with-ui-react"><img src="https://tinybase.org/react.svg?asImg" width="48"> React</a></div><div><a href="https://tinybase.org/guides/building-uis-with-solid/getting-started-with-ui-solid"><img src="https://tinybase.org/solid.svg?asImg" width="48"> Solid</a></div><div><a href="https://tinybase.org/guides/building-uis-with-svelte/getting-started-with-ui-svelte"><img src="https://tinybase.org/svelte.svg?asImg" width="48"> Svelte</a></div><h3 id="storage-sync"><a href="https://tinybase.org/guides/persistence/">Storage &amp; Sync</a></h3><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/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/capacitor.svg?asImg" width="48"> Capacitor</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/api/persister-cr-sqlite-wasm"><img src="https://tinybase.org/crsqlite.png" width="48"> CR-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/powersync.svg?asImg" width="48"> PowerSync</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/neon.svg?asImg" width="48"> Neon</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://tinybase.org/supabase.svg?asImg" width="48"> Supabase</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/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-automerge"><img src="https://tinybase.org/automerge.svg?asImg" width="48"> Automerge</a></div><h3 id="schema-systems"><a href="https://tinybase.org/guides/schemas/using-schematizers/">Schema Systems</a></h3><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/9.6.0" 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>
10
10
 
11
11
  ```js
12
12
  import {createStore} from 'tinybase';
@@ -283,4 +283,4 @@ console.log(store.getCell('pets', 'felix', 'sold'));
283
283
  // -> false
284
284
  ```
285
285
 
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>7.3kB</em> to your app. Incrementally add the other modules as you need more functionality, or get it all for <em>16.4kB</em>.</p><p>The optional <a href="https://tinybase.org/api/ui-react/"><code>ui-react</code></a> module is just <em>5.9kB</em>, the ui-react-dom components are another <em>4.3kB</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>7.3kB</td><td>79.8kB</td></tr><tr><th class="right">tinybase (complete)</th><td>16.4kB</td><td>187.8kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react/">ui-react</a></th><td>5.9kB</td><td>64.2kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react-dom/">ui-react-dom</a></th><td>4.3kB</td><td>38.4kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react-dom-charts/">ui-react-dom-charts</a></th><td>8.7kB</td><td>64.9kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-solid/">ui-solid</a></th><td>5.8kB</td><td>63.2kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-solid-dom/">ui-solid-dom</a></th><td>4.9kB</td><td>48.0kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-svelte/">ui-svelte</a></th><td>5.1kB</td><td>62.5kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-svelte-dom/">ui-svelte-dom</a></th><td>6.0kB</td><td>62.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 <a href="https://tinybase.org/api/">API</a> 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">Tested lines</th><td>5,117</td><td>5,117</td><td>100.0%</td></tr><tr><th class="right">Tested statements</th><td>5,537</td><td>5,537</td><td>100.0%</td></tr><tr><th class="right">Tested functions</th><td>2,428</td><td>2,428</td><td>100.0%</td></tr><tr><th class="right">Tested branches</th><td>1,791</td><td>1,791</td><td>100.0%</td></tr><tr><th class="right">Tests</th><td colspan="3">9,038</td></tr><tr><th class="right">Assertions</th><td colspan="3">38,107</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/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/expo" target="_blank"><img src="https://github.com/expo.png?size=48" title="expo" width="48" height="48"></a><a href="https://github.com/braden-w" target="_blank"><img src="https://github.com/braden-w.png?size=48" title="braden-w" 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/gonza224" target="_blank"><img src="https://github.com/gonza224.png?size=48" title="gonza224" 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](/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>7.3kB</em> to your app. Incrementally add the other modules as you need more functionality, or get it all for <em>16.4kB</em>.</p><p>The optional <a href="https://tinybase.org/api/ui-react/"><code>ui-react</code></a> module is just <em>5.9kB</em>, the ui-react-dom components are another <em>4.3kB</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>7.3kB</td><td>79.8kB</td></tr><tr><th class="right">tinybase (complete)</th><td>16.4kB</td><td>187.8kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react/">ui-react</a></th><td>5.9kB</td><td>64.2kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react-dom/">ui-react-dom</a></th><td>4.3kB</td><td>38.4kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-react-dom-charts/">ui-react-dom-charts</a></th><td>8.7kB</td><td>64.9kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-solid/">ui-solid</a></th><td>5.8kB</td><td>63.2kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-solid-dom/">ui-solid-dom</a></th><td>4.9kB</td><td>48.0kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-svelte/">ui-svelte</a></th><td>5.1kB</td><td>62.5kB</td></tr><tr><th class="right"><a href="https://tinybase.org/api/ui-svelte-dom/">ui-svelte-dom</a></th><td>6.0kB</td><td>61.7kB</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 <a href="https://tinybase.org/api/">API</a> 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">Tested lines</th><td>5,117</td><td>5,117</td><td>100.0%</td></tr><tr><th class="right">Tested statements</th><td>5,537</td><td>5,537</td><td>100.0%</td></tr><tr><th class="right">Tested functions</th><td>2,428</td><td>2,428</td><td>100.0%</td></tr><tr><th class="right">Tested branches</th><td>1,791</td><td>1,791</td><td>100.0%</td></tr><tr><th class="right">Tests</th><td colspan="3">9,465</td></tr><tr><th class="right">Assertions</th><td colspan="3">39,661</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/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/expo" target="_blank"><img src="https://github.com/expo.png?size=48" title="expo" width="48" height="48"></a><a href="https://github.com/braden-w" target="_blank"><img src="https://github.com/braden-w.png?size=48" title="braden-w" 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/gonza224" target="_blank"><img src="https://github.com/gonza224.png?size=48" title="gonza224" 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](/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>
package/releases.md CHANGED
@@ -1,8 +1,113 @@
1
- <link rel="preload" as="image" href="https://tinybase.org/shots/styled-chart-react-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/axis-overrides-react-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/sortedtableinhtmltable-solid-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/inspector-solid-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/editablevalueview-solid-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/sortedtableinhtmltable-svelte-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/inspector-svelte-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/editablevalueview-svelte-full-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/inspector-react-demo.png"><link rel="preload" as="image" href="https://tinybase.org/partykit.gif"><link rel="preload" as="image" href="https://tinybase.org/shots/sortedtableinhtmltable-react-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/car-analysis-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/movie-database-demo.png"><p>This is a reverse chronological list of the major TinyBase releases, with highlighted features.</p><hr><h1 id="v9-5">v9.5</h1><h2 id="schema-enums">Schema Enums</h2><p><a href="https://tinybase.org/api/store/type-aliases/schema/cellschema/"><code>CellSchema</code></a> and <a href="https://tinybase.org/api/store/type-aliases/schema/valueschema/"><code>ValueSchema</code></a> can now use an <code>enum</code> property instead of <code>type</code> to allow only specific primitive values (as requested in issue <a href="https://github.com/tinyplex/tinybase/issues/38">#38</a>). Enums must be non-empty, can mix strings, finite numbers, and booleans, and continue to use <code>allowNull</code> when <code>null</code> is also valid.</p>
1
+ <link rel="preload" as="image" href="https://tinybase.org/shots/styled-chart-react-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/axis-overrides-react-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/sortedtableinhtmltable-solid-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/inspector-solid-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/editablevalueview-solid-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/sortedtableinhtmltable-svelte-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/inspector-svelte-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/editablevalueview-svelte-full-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/inspector-react-demo.png"><link rel="preload" as="image" href="https://tinybase.org/partykit.gif"><link rel="preload" as="image" href="https://tinybase.org/shots/sortedtableinhtmltable-react-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/car-analysis-demo.png"><link rel="preload" as="image" href="https://tinybase.org/shots/movie-database-demo.png"><p>This is a reverse chronological list of the major TinyBase releases, with highlighted features.</p><hr><h1 id="v9-6">v9.6</h1><h2 id="in-summary">In Summary</h2><ul><li><a href="#postgresql-via-pg">A new Persister for <code>pg</code></a>, the standard PostgreSQL driver for Node.js - and the hosted services, like Neon, compatible with it.</li><li><a href="#supabase">A new Persister for Supabase</a>, which uses its REST <a href="https://tinybase.org/api/">API</a> and Realtime rather than a database connection.</li><li><a href="#sqlite-via-better-sqlite3">A new Persister for <code>better-sqlite3</code></a>, the popular synchronous SQLite module for Node.js.</li><li><a href="#sqlite-in-capacitor">A new Persister for Capacitor</a>&#x27;s SQLite plugin, for local databases in native iOS and Android apps.</li><li><a href="#mergeablestore-support-for-indexeddb">MergeableStore support for IndexedDB</a>, closing a gap amongst the browser Persisters.</li><li><a href="#sql-placeholders">SQL built the way each database wants it</a>, which fixes the <a href="https://tinybase.org/api/persister-powersync/interfaces/persister/powersyncpersister/"><code>PowerSyncPersister</code></a> with PowerSync&#x27;s Node SDK.</li></ul><p>And more!</p><h2 id="postgresql-via-pg">PostgreSQL, via <code>pg</code></h2><p>The new <a href="https://tinybase.org/api/persister-pg/"><code>persister-pg</code></a> module provides the <a href="https://tinybase.org/api/persister-pg/interfaces/persister/pgpersister/"><code>PgPersister</code></a>, which binds to PostgreSQL databases with the <a href="https://github.com/brianc/node-postgres"><code>pg</code></a> module - the de facto standard PostgreSQL driver for Node.js.</p><p>It joins the existing <a href="https://tinybase.org/api/persister-postgres/interfaces/persister/postgrespersister/"><code>PostgresPersister</code></a> and <a href="https://tinybase.org/api/persister-pglite/interfaces/persister/pglitepersister/"><code>PglitePersister</code></a>, and is the one to reach for with hosted services that offer a <code>pg</code>-compatible driver. <a href="https://neon.com/">Neon</a>, for example, has a serverless driver whose <code>Pool</code> and <code>Client</code> objects can be passed straight to the <a href="https://tinybase.org/api/persister-pg/functions/creation/createpgpersister/"><code>createPgPersister</code></a> function, so you can persist a <a href="https://tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> from an edge runtime that cannot open a TCP connection.</p>
2
2
 
3
3
  ```js
4
+ import {Pool} from 'pg';
4
5
  import {createStore} from 'tinybase';
6
+ import {createPgPersister} from 'tinybase/persisters/persister-pg';
5
7
 
8
+ const nodePgPool = new Pool({
9
+ connectionString: 'postgres://localhost:5432/tinybase',
10
+ });
11
+ const nodePgStore = createStore().setTables({pets: {fido: {species: 'dog'}}});
12
+ const nodePgPersister = await createPgPersister(
13
+ nodePgStore,
14
+ nodePgPool,
15
+ 'my_tinybase',
16
+ );
17
+
18
+ await nodePgPersister.save();
19
+ console.log((await nodePgPool.query('SELECT * FROM my_tinybase;')).rows);
20
+ // -> [{_id: '_', store: '[{"pets":{"fido":{"species":"dog"}}},{}]'}]
21
+
22
+ await nodePgPool.query('UPDATE my_tinybase SET store = $1 WHERE _id = $2;', [
23
+ '[{"pets":{"felix":{"species":"cat"}}},{}]',
24
+ '_',
25
+ ]);
26
+ await nodePgPersister.load();
27
+ console.log(nodePgStore.getTables());
28
+ // -> {pets: {felix: {species: 'cat'}}}
29
+
30
+ await nodePgPersister.destroy();
31
+ await nodePgPool.query('DROP TABLE my_tinybase;');
32
+ await nodePgPool.end();
33
+ ```
34
+
35
+ <p>Both JSON and tabular modes are supported, as is reactive auto-loading, and a <a href="https://tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/"><code>MergeableStore</code></a> can be persisted in JSON mode. There&#x27;s more information in the documentation for the new <a href="https://tinybase.org/api/persister-pg/"><code>persister-pg</code></a> module.</p><h2 id="supabase">Supabase</h2><p>Also new is the <a href="https://tinybase.org/api/persister-supabase/"><code>persister-supabase</code></a> module, which provides the <a href="https://tinybase.org/api/persister-supabase/interfaces/persister/supabasepersister/"><code>SupabasePersister</code></a> (as requested in issue <a href="https://github.com/tinyplex/tinybase/issues/204">#204</a>). Pass the <a href="https://tinybase.org/api/persister-supabase/functions/creation/createsupabasepersister/"><code>createSupabasePersister</code></a> function the client you get back from Supabase&#x27;s <code>createClient</code> function, and your <a href="https://tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> is persisted to a table in your project:</p>
36
+
37
+ ```js ignore
38
+ import {createClient} from '@supabase/supabase-js';
39
+ import {createStore} from 'tinybase';
40
+ import {createSupabasePersister} from 'tinybase/persisters/persister-supabase';
41
+
42
+ const supabase = createClient('https://my-project.supabase.co', 'anon-key');
43
+ const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
44
+ const persister = createSupabasePersister(store, supabase, 'my_tinybase');
45
+
46
+ await persister.save();
47
+ await persister.startAutoLoad();
48
+ ```
49
+
50
+ <p>Unlike the other PostgreSQL Persisters, this one goes through Supabase&#x27;s REST <a href="https://tinybase.org/api/">API</a> rather than connecting to the database. So it runs in a browser or edge runtime, your row-level security policies apply to what it reads and writes, and the <a href="https://tinybase.org/api/persisters/interfaces/persister/persister/methods/load/startautoload/"><code>startAutoLoad</code></a> method hears about other clients&#x27; changes over Supabase Realtime instead of polling. In return, only the JSON serialization mode is available, since the REST <a href="https://tinybase.org/api/">API</a> cannot run the arbitrary SQL that tabular mapping needs.</p><p>It also issues no DDL at all, unlike its siblings. <a href="https://tinybase.org/api/queries/type-aliases/definition/where/"><code>Where</code></a> they create tables, add and drop columns as Cells come and go, and install their own change-notification triggers, this one touches nothing but a single row. You create the table and its policies yourself and they stay exactly as you left them, and the <a href="https://tinybase.org/api/persister-supabase/"><code>persister-supabase</code></a> module documentation has the SQL to do it.</p><h2 id="sqlite-via-better-sqlite3">SQLite, via <code>better-sqlite3</code></h2><p>The new <a href="https://tinybase.org/api/persister-better-sqlite3/"><code>persister-better-sqlite3</code></a> module provides the <a href="https://tinybase.org/api/persister-better-sqlite3/interfaces/persister/bettersqlite3persister/"><code>BetterSqlite3Persister</code></a>, which binds to a local SQLite database with the popular synchronous <a href="https://github.com/WiseLibs/better-sqlite3"><code>better-sqlite3</code></a> module:</p>
51
+
52
+ ```js
53
+ import Database from 'better-sqlite3';
54
+ import {createBetterSqlite3Persister} from 'tinybase/persisters/persister-better-sqlite3';
55
+
56
+ const betterDb = new Database(':memory:');
57
+ const betterStore = createStore().setTables({pets: {fido: {species: 'dog'}}});
58
+ const betterPersister = createBetterSqlite3Persister(
59
+ betterStore,
60
+ betterDb,
61
+ 'my_tinybase',
62
+ );
63
+
64
+ await betterPersister.save();
65
+ console.log(betterDb.prepare('SELECT * FROM my_tinybase;').all());
66
+ // -> [{_id: '_', store: '[{"pets":{"fido":{"species":"dog"}}},{}]'}]
67
+
68
+ await betterPersister.destroy();
69
+ betterDb.close();
70
+ ```
71
+
72
+ <p>Since <code>better-sqlite3</code> does not signal when the database changes underneath it, automatic loading polls. There&#x27;s more information in the documentation for the new <a href="https://tinybase.org/api/persister-better-sqlite3/"><code>persister-better-sqlite3</code></a> module.</p><h2 id="sqlite-in-capacitor">SQLite In Capacitor</h2><p>The new <a href="https://tinybase.org/api/persister-capacitor-sqlite/"><code>persister-capacitor-sqlite</code></a> module provides the <a href="https://tinybase.org/api/persister-capacitor-sqlite/interfaces/persister/capacitorsqlitepersister/"><code>CapacitorSqlitePersister</code></a>, which binds to a SQLite database in a Capacitor app via the <a href="https://github.com/capacitor-community/sqlite"><code>@capacitor-community/sqlite</code></a> plugin (as requested in issue <a href="https://github.com/tinyplex/tinybase/issues/219">#219</a>). Both JSON and tabular modes work, as does persisting a <a href="https://tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/"><code>MergeableStore</code></a> in JSON mode.</p>
73
+
74
+ ```js ignore
75
+ import {CapacitorSQLite, SQLiteConnection} from '@capacitor-community/sqlite';
76
+ import {createStore} from 'tinybase';
77
+ import {createCapacitorSqlitePersister} from 'tinybase/persisters/persister-capacitor-sqlite';
78
+
79
+ const sqlite = new SQLiteConnection(CapacitorSQLite);
80
+ const db = await sqlite.createConnection(
81
+ 'my.db',
82
+ false,
83
+ 'no-encryption',
84
+ 1,
85
+ false,
86
+ );
87
+ await db.open();
88
+
89
+ const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
90
+ const persister = createCapacitorSqlitePersister(store, db, 'my_tinybase');
91
+ await persister.save();
92
+ ```
93
+
94
+ <p>Note that this module&#x27;s tests run against a mocked plugin, since it needs a native iOS or Android runtime that a Node test suite cannot provide. Its SQL behavior is shared with the other SQLite Persisters and well covered by them, but the binding to the plugin itself is not exercised on a device, so please report anything that behaves differently in a real app.</p><h2 id="mergeablestore-support-for-indexeddb"><a href="https://tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/"><code>MergeableStore</code></a> Support For IndexedDB</h2><p>The <a href="https://tinybase.org/api/persister-indexed-db/interfaces/persister/indexeddbpersister/"><code>IndexedDbPersister</code></a> can now persist a <a href="https://tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/"><code>MergeableStore</code></a>, closing a gap that had made IndexedDB the odd one out amongst the browser Persisters (as requested in issue <a href="https://github.com/tinyplex/tinybase/issues/203">#203</a>). The <a href="https://tinybase.org/api/persister-browser/interfaces/persister/sessionpersister/"><code>SessionPersister</code></a>, <a href="https://tinybase.org/api/persister-browser/interfaces/persister/localpersister/"><code>LocalPersister</code></a> and <a href="https://tinybase.org/api/persister-browser/interfaces/persister/opfspersister/"><code>OpfsPersister</code></a> could all already do this; now the browser&#x27;s most capable storage can too.</p>
95
+
96
+ ```js ignore
97
+ import {createMergeableStore} from 'tinybase';
98
+ import {createIndexedDbPersister} from 'tinybase/persisters/persister-indexed-db';
99
+
100
+ const store = createMergeableStore().setTables({
101
+ pets: {fido: {species: 'dog'}},
102
+ });
103
+ const persister = createIndexedDbPersister(store, 'petStore');
104
+
105
+ await persister.save();
106
+ ```
107
+
108
+ <p>A regular <a href="https://tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> continues to use the &#x27;t&#x27; and &#x27;v&#x27; object stores exactly as before, and a <a href="https://tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/"><code>MergeableStore</code></a> uses a new one called &#x27;m&#x27;, so databases written by previous versions are upgraded in place with their content intact.</p><h2 id="sql-placeholders">SQL Placeholders</h2><p>TinyBase used to generate PostgreSQL&#x27;s numbered <code>$1</code> placeholders for every database, and then rewrite them for the SQLite Persisters that objected. SQL is now built with the placeholder style each database family actually wants, so the stricter drivers work without anyone having to patch statements after the fact. That is what makes the new <a href="https://tinybase.org/api/persister-better-sqlite3/interfaces/persister/bettersqlite3persister/"><code>BetterSqlite3Persister</code></a> possible at all; it also means the <a href="https://tinybase.org/api/persister-durable-object-sql-storage/interfaces/persister/durableobjectsqlstoragepersister/"><code>DurableObjectSqlStoragePersister</code></a> no longer needs the workaround it carried, and that the <a href="https://tinybase.org/api/persister-powersync/interfaces/persister/powersyncpersister/"><code>PowerSyncPersister</code></a> now works with PowerSync&#x27;s Node SDK, which it previously did not.</p><hr><h1 id="v9-5">v9.5</h1><h2 id="schema-enums">Schema Enums</h2><p><a href="https://tinybase.org/api/store/type-aliases/schema/cellschema/"><code>CellSchema</code></a> and <a href="https://tinybase.org/api/store/type-aliases/schema/valueschema/"><code>ValueSchema</code></a> can now use an <code>enum</code> property instead of <code>type</code> to allow only specific primitive values (as requested in issue <a href="https://github.com/tinyplex/tinybase/issues/38">#38</a>). Enums must be non-empty, can mix strings, finite numbers, and booleans, and continue to use <code>allowNull</code> when <code>null</code> is also valid.</p>
109
+
110
+ ```js
6
111
  const enumStore = createStore().setValuesSchema({
7
112
  status: {enum: ['available', 'adopted'], default: 'available'},
8
113
  rating: {enum: ['good', 5, true], allowNull: true},
@@ -577,7 +577,6 @@ const getQueriesCellComponentProps = (queries, queryId) => ({
577
577
  const getCallbackOrUndefined = (callback, test) => (test ? callback : void 0);
578
578
  const getParams = (...args) => args;
579
579
  const useCells = (defaultCellIds, customCells, defaultCellComponent) =>
580
- // eslint-disable-next-line solid/reactivity
581
580
  createMemo(() => {
582
581
  const customCellIds = getValue(customCells);
583
582
  const cellIds = getValue(customCellIds) ?? getValue(defaultCellIds);
@@ -577,7 +577,6 @@ const getQueriesCellComponentProps = (queries, queryId) => ({
577
577
  const getCallbackOrUndefined = (callback, test) => (test ? callback : void 0);
578
578
  const getParams = (...args) => args;
579
579
  const useCells = (defaultCellIds, customCells, defaultCellComponent) =>
580
- // eslint-disable-next-line solid/reactivity
581
580
  createMemo(() => {
582
581
  const customCellIds = getValue(customCells);
583
582
  const cellIds = getValue(customCellIds) ?? getValue(defaultCellIds);
@@ -4042,7 +4042,6 @@ const getQueriesCellComponentProps = (queries, queryId) => ({
4042
4042
  const getCallbackOrUndefined = (callback, test) => (test ? callback : void 0);
4043
4043
  const getParams = (...args) => args;
4044
4044
  const useCells = (defaultCellIds, customCells, defaultCellComponent) =>
4045
- // eslint-disable-next-line solid/reactivity
4046
4045
  createMemo(() => {
4047
4046
  const customCellIds = getValue(customCells);
4048
4047
  const cellIds = getValue(customCellIds) ?? getValue(defaultCellIds);
@@ -4042,7 +4042,6 @@ const getQueriesCellComponentProps = (queries, queryId) => ({
4042
4042
  const getCallbackOrUndefined = (callback, test) => (test ? callback : void 0);
4043
4043
  const getParams = (...args) => args;
4044
4044
  const useCells = (defaultCellIds, customCells, defaultCellComponent) =>
4045
- // eslint-disable-next-line solid/reactivity
4046
4045
  createMemo(() => {
4047
4046
  const customCellIds = getValue(customCells);
4048
4047
  const cellIds = getValue(customCellIds) ?? getValue(defaultCellIds);
@@ -88,7 +88,7 @@ const objDel = (obj, id) => {
88
88
 
89
89
  const TINYBASE_CONTEXT_KEY = TINYBASE + '_uisc';
90
90
 
91
- /* functions.svelte.ts generated by Svelte v5.56.9 */
91
+ /* functions.svelte.ts generated by Svelte v5.57.0 */
92
92
 
93
93
  class ReactiveHandle {
94
94
  #get;
@@ -88,7 +88,7 @@ const objDel = (obj, id) => {
88
88
 
89
89
  const TINYBASE_CONTEXT_KEY = TINYBASE + '_uisc';
90
90
 
91
- /* functions.svelte.ts generated by Svelte v5.56.9 */
91
+ /* functions.svelte.ts generated by Svelte v5.57.0 */
92
92
 
93
93
  class ReactiveHandle {
94
94
  #get;