tinybase 7.1.0-beta.1 → 7.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@types/schematizers/schematizer-typebox/index.d.ts +116 -0
- package/@types/schematizers/schematizer-typebox/with-schemas/index.d.ts +8 -0
- package/@types/schematizers/schematizer-zod/with-schemas/index.d.ts +1 -4
- package/index.js +2 -1
- package/mergeable-store/index.js +2 -1
- package/mergeable-store/with-schemas/index.js +2 -1
- package/min/schematizers/schematizer-typebox/index.js +1 -0
- package/min/schematizers/schematizer-typebox/index.js.gz +0 -0
- package/min/schematizers/schematizer-typebox/with-schemas/index.js +1 -0
- package/min/schematizers/schematizer-typebox/with-schemas/index.js.gz +0 -0
- package/omni/index.js +2 -1
- package/omni/with-schemas/index.js +2 -1
- package/package.json +41 -1
- package/queries/index.js +2 -1
- package/queries/with-schemas/index.js +2 -1
- package/readme.md +2 -2
- package/releases.md +25 -1
- package/schematizers/schematizer-typebox/index.js +106 -0
- package/schematizers/schematizer-typebox/with-schemas/index.js +106 -0
- package/store/index.js +2 -1
- package/store/with-schemas/index.js +2 -1
- package/ui-react-dom/index.js +2 -1
- package/ui-react-dom/with-schemas/index.js +2 -1
- package/ui-react-inspector/index.js +2 -1
- package/ui-react-inspector/with-schemas/index.js +2 -1
- package/with-schemas/index.js +2 -1
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The schematizer-typebox module provides conversion utilities for TypeBox
|
|
3
|
+
* schemas.
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
* @module schematizer-typebox
|
|
6
|
+
* @since v7.1.0
|
|
7
|
+
*/
|
|
8
|
+
import type {TablesSchema, ValuesSchema} from '../../store/index.d.ts';
|
|
9
|
+
import type {Schematizer} from '../index.d.ts';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The TypeBoxSchematizer interface represents a schematizer specifically for
|
|
13
|
+
* converting TypeBox schemas into TinyBase schemas.
|
|
14
|
+
* @category Schematizer
|
|
15
|
+
* @since v7.1.0
|
|
16
|
+
*/
|
|
17
|
+
export interface TypeBoxSchematizer extends Schematizer {
|
|
18
|
+
/**
|
|
19
|
+
* The toTablesSchema method converts a mapping of TypeBox object schemas into a
|
|
20
|
+
* TinyBase TablesSchema.
|
|
21
|
+
*
|
|
22
|
+
* This method extracts basic type information (string, number, boolean),
|
|
23
|
+
* default values, and nullable flags from TypeBox schemas. Complex validation
|
|
24
|
+
* rules like min/max, patterns, formats, and custom validators are ignored.
|
|
25
|
+
* @param schemas - A mapping of table IDs to TypeBox object schemas.
|
|
26
|
+
* @returns A TinyBase TablesSchema.
|
|
27
|
+
* @example
|
|
28
|
+
* This example converts TypeBox schemas to TinyBase format.
|
|
29
|
+
*
|
|
30
|
+
* ```js
|
|
31
|
+
* import {Type} from '@sinclair/typebox';
|
|
32
|
+
* import {createStore} from 'tinybase';
|
|
33
|
+
* import {createTypeBoxSchematizer} from 'tinybase/schematizers/schematizer-typebox';
|
|
34
|
+
*
|
|
35
|
+
* const schematizer = createTypeBoxSchematizer();
|
|
36
|
+
*
|
|
37
|
+
* const tablesSchema = schematizer.toTablesSchema({
|
|
38
|
+
* pets: Type.Object({
|
|
39
|
+
* species: Type.String(),
|
|
40
|
+
* age: Type.Number(),
|
|
41
|
+
* sold: Type.Boolean({default: false}),
|
|
42
|
+
* }),
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* const store = createStore().setTablesSchema(tablesSchema);
|
|
46
|
+
* store.setRow('pets', 'fido', {species: 'dog', age: 3});
|
|
47
|
+
* console.log(store.getRow('pets', 'fido'));
|
|
48
|
+
* // -> {species: 'dog', age: 3, sold: false}
|
|
49
|
+
* ```
|
|
50
|
+
* @category Conversion
|
|
51
|
+
* @since v7.1.0
|
|
52
|
+
*/
|
|
53
|
+
toTablesSchema(schemas: {[tableId: string]: any}): TablesSchema;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The toValuesSchema method converts a mapping of TypeBox schemas into a
|
|
57
|
+
* TinyBase ValuesSchema.
|
|
58
|
+
*
|
|
59
|
+
* This method extracts basic type information (string, number, boolean),
|
|
60
|
+
* default values, and nullable flags from TypeBox schemas.
|
|
61
|
+
* @param schemas - A mapping of value IDs to TypeBox schemas.
|
|
62
|
+
* @returns A TinyBase ValuesSchema.
|
|
63
|
+
* @example
|
|
64
|
+
* This example converts TypeBox schemas to TinyBase ValuesSchema format.
|
|
65
|
+
*
|
|
66
|
+
* ```js
|
|
67
|
+
* import {Type} from '@sinclair/typebox';
|
|
68
|
+
* import {createStore} from 'tinybase';
|
|
69
|
+
* import {createTypeBoxSchematizer} from 'tinybase/schematizers/schematizer-typebox';
|
|
70
|
+
*
|
|
71
|
+
* const schematizer = createTypeBoxSchematizer();
|
|
72
|
+
*
|
|
73
|
+
* const valuesSchema = schematizer.toValuesSchema({
|
|
74
|
+
* theme: Type.String({default: 'light'}),
|
|
75
|
+
* count: Type.Number(),
|
|
76
|
+
* isOpen: Type.Boolean(),
|
|
77
|
+
* });
|
|
78
|
+
*
|
|
79
|
+
* const store = createStore().setValuesSchema(valuesSchema);
|
|
80
|
+
* store.setValue('count', 42);
|
|
81
|
+
* console.log(store.getValues());
|
|
82
|
+
* // -> {theme: 'light', count: 42}
|
|
83
|
+
* ```
|
|
84
|
+
* @category Conversion
|
|
85
|
+
* @since v7.1.0
|
|
86
|
+
*/
|
|
87
|
+
toValuesSchema(schemas: {[valueId: string]: any}): ValuesSchema;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The createTypeBoxSchematizer function creates a TypeBoxSchematizer object
|
|
92
|
+
* that can convert TypeBox schemas into TinyBase schemas.
|
|
93
|
+
*
|
|
94
|
+
* The schematizer is stateless and can be reused for multiple conversions.
|
|
95
|
+
* @returns A new TypeBoxSchematizer instance.
|
|
96
|
+
* @example
|
|
97
|
+
* This example creates a TypeBox schematizer and uses it to convert schemas.
|
|
98
|
+
*
|
|
99
|
+
* ```js
|
|
100
|
+
* import {Type} from '@sinclair/typebox';
|
|
101
|
+
* import {createTypeBoxSchematizer} from 'tinybase/schematizers/schematizer-typebox';
|
|
102
|
+
*
|
|
103
|
+
* const schematizer = createTypeBoxSchematizer();
|
|
104
|
+
*
|
|
105
|
+
* const tablesSchema = schematizer.toTablesSchema({
|
|
106
|
+
* pets: Type.Object({
|
|
107
|
+
* species: Type.String(),
|
|
108
|
+
* }),
|
|
109
|
+
* });
|
|
110
|
+
* console.log(tablesSchema);
|
|
111
|
+
* // -> {pets: {species: {type: 'string'}}}
|
|
112
|
+
* ```
|
|
113
|
+
* @category Creation
|
|
114
|
+
* @since v7.1.0
|
|
115
|
+
*/
|
|
116
|
+
export function createTypeBoxSchematizer(): TypeBoxSchematizer;
|
package/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const FUNCTION = getTypeOf(getTypeOf);
|
|
|
7
7
|
const TYPE = 'type';
|
|
8
8
|
const DEFAULT = 'default';
|
|
9
9
|
const ALLOW_NULL = 'allowNull';
|
|
10
|
+
const NULL = 'null';
|
|
10
11
|
const SUM = 'sum';
|
|
11
12
|
const AVG = 'avg';
|
|
12
13
|
const MIN = 'min';
|
|
@@ -94,7 +95,7 @@ const arrayShift = (array) => array.shift();
|
|
|
94
95
|
|
|
95
96
|
const getCellOrValueType = (cellOrValue) => {
|
|
96
97
|
if (isNull(cellOrValue)) {
|
|
97
|
-
return
|
|
98
|
+
return NULL;
|
|
98
99
|
}
|
|
99
100
|
const type = getTypeOf(cellOrValue);
|
|
100
101
|
return isTypeStringOrBoolean(type) ||
|
package/mergeable-store/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const FUNCTION = getTypeOf(getTypeOf);
|
|
|
7
7
|
const TYPE = 'type';
|
|
8
8
|
const DEFAULT = 'default';
|
|
9
9
|
const ALLOW_NULL = 'allowNull';
|
|
10
|
+
const NULL = 'null';
|
|
10
11
|
const LISTENER = 'Listener';
|
|
11
12
|
const SET = 'set';
|
|
12
13
|
const ADD = 'add';
|
|
@@ -63,7 +64,7 @@ const tryCatch = async (action, then1, then2) => {
|
|
|
63
64
|
|
|
64
65
|
const getCellOrValueType = (cellOrValue) => {
|
|
65
66
|
if (isNull(cellOrValue)) {
|
|
66
|
-
return
|
|
67
|
+
return NULL;
|
|
67
68
|
}
|
|
68
69
|
const type = getTypeOf(cellOrValue);
|
|
69
70
|
return isTypeStringOrBoolean(type) ||
|
|
@@ -7,6 +7,7 @@ const FUNCTION = getTypeOf(getTypeOf);
|
|
|
7
7
|
const TYPE = 'type';
|
|
8
8
|
const DEFAULT = 'default';
|
|
9
9
|
const ALLOW_NULL = 'allowNull';
|
|
10
|
+
const NULL = 'null';
|
|
10
11
|
const LISTENER = 'Listener';
|
|
11
12
|
const SET = 'set';
|
|
12
13
|
const ADD = 'add';
|
|
@@ -63,7 +64,7 @@ const tryCatch = async (action, then1, then2) => {
|
|
|
63
64
|
|
|
64
65
|
const getCellOrValueType = (cellOrValue) => {
|
|
65
66
|
if (isNull(cellOrValue)) {
|
|
66
|
-
return
|
|
67
|
+
return NULL;
|
|
67
68
|
}
|
|
68
69
|
const type = getTypeOf(cellOrValue);
|
|
69
70
|
return isTypeStringOrBoolean(type) ||
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t=t=>typeof t,e=t(""),r=t(!0),n=t(0),o="type",s="default",c="null",l=t=>(e,r,n)=>t(e)?n?.():r(e),u=t=>null==t,f=l(u),p=l(t=>void 0===t),a=Object,y=t=>a.getPrototypeOf(t),i=a.entries,h=a.keys,m=a.freeze,d=(t=[])=>a.fromEntries(t),O=(t,e)=>((t,e)=>t.forEach(e))(i(t),([t,r])=>e(r,t)),b="anyOf",g=(t,e,r)=>{if(t?.[b]){const r=t[b],n=r.some(t=>t?.type===c),o=r.find(t=>t?.type!==c);if(n&&o)return g(o,e??t?.[s],!0)}return[t,e??t?.[s],r??!1]},v=()=>{const t=t=>{const[c,l,u]=g(t),f=c?.type;if(f!==e&&f!==n&&f!==r)return;const a={[o]:f};return p(l,t=>{a[s]=t}),u&&(a.allowNull=!0),a};return m({toTablesSchema:e=>{const r=d();return O(e,(e,n)=>{const o=d();var s;p(e?.properties,e=>O(e,(e,r)=>p(t(e),t=>{o[r]=t}))),(t=>!u(t)&&f(y(t),t=>t==a.prototype||u(y(t)),()=>!0))(s=o)&&0==(t=>h(t).length)(s)||(r[n]=o)}),r},toValuesSchema:e=>{const r=d();return O(e,(e,n)=>p(t(e),t=>{r[n]=t})),r}})};export{v as createTypeBoxSchematizer};
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t=t=>typeof t,e=t(""),r=t(!0),n=t(0),o="type",s="default",c="null",l=t=>(e,r,n)=>t(e)?n?.():r(e),u=t=>null==t,f=l(u),p=l(t=>void 0===t),a=Object,y=t=>a.getPrototypeOf(t),i=a.entries,h=a.keys,m=a.freeze,d=(t=[])=>a.fromEntries(t),O=(t,e)=>((t,e)=>t.forEach(e))(i(t),([t,r])=>e(r,t)),b="anyOf",g=(t,e,r)=>{if(t?.[b]){const r=t[b],n=r.some(t=>t?.type===c),o=r.find(t=>t?.type!==c);if(n&&o)return g(o,e??t?.[s],!0)}return[t,e??t?.[s],r??!1]},v=()=>{const t=t=>{const[c,l,u]=g(t),f=c?.type;if(f!==e&&f!==n&&f!==r)return;const a={[o]:f};return p(l,t=>{a[s]=t}),u&&(a.allowNull=!0),a};return m({toTablesSchema:e=>{const r=d();return O(e,(e,n)=>{const o=d();var s;p(e?.properties,e=>O(e,(e,r)=>p(t(e),t=>{o[r]=t}))),(t=>!u(t)&&f(y(t),t=>t==a.prototype||u(y(t)),()=>!0))(s=o)&&0==(t=>h(t).length)(s)||(r[n]=o)}),r},toValuesSchema:e=>{const r=d();return O(e,(e,n)=>p(t(e),t=>{r[n]=t})),r}})};export{v as createTypeBoxSchematizer};
|
|
Binary file
|
package/omni/index.js
CHANGED
|
@@ -19,6 +19,7 @@ const TRUE = 'true';
|
|
|
19
19
|
const TYPE = 'type';
|
|
20
20
|
const DEFAULT = 'default';
|
|
21
21
|
const ALLOW_NULL = 'allowNull';
|
|
22
|
+
const NULL = 'null';
|
|
22
23
|
const UTF8 = 'utf8';
|
|
23
24
|
const SUM = 'sum';
|
|
24
25
|
const AVG = 'avg';
|
|
@@ -151,7 +152,7 @@ const arrayWith = (array, index, value) => array.with(index, value);
|
|
|
151
152
|
|
|
152
153
|
const getCellOrValueType = (cellOrValue) => {
|
|
153
154
|
if (isNull(cellOrValue)) {
|
|
154
|
-
return
|
|
155
|
+
return NULL;
|
|
155
156
|
}
|
|
156
157
|
const type = getTypeOf(cellOrValue);
|
|
157
158
|
return isTypeStringOrBoolean(type) ||
|
|
@@ -19,6 +19,7 @@ const TRUE = 'true';
|
|
|
19
19
|
const TYPE = 'type';
|
|
20
20
|
const DEFAULT = 'default';
|
|
21
21
|
const ALLOW_NULL = 'allowNull';
|
|
22
|
+
const NULL = 'null';
|
|
22
23
|
const UTF8 = 'utf8';
|
|
23
24
|
const SUM = 'sum';
|
|
24
25
|
const AVG = 'avg';
|
|
@@ -151,7 +152,7 @@ const arrayWith = (array, index, value) => array.with(index, value);
|
|
|
151
152
|
|
|
152
153
|
const getCellOrValueType = (cellOrValue) => {
|
|
153
154
|
if (isNull(cellOrValue)) {
|
|
154
|
-
return
|
|
155
|
+
return NULL;
|
|
155
156
|
}
|
|
156
157
|
const type = getTypeOf(cellOrValue);
|
|
157
158
|
return isTypeStringOrBoolean(type) ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tinybase",
|
|
3
|
-
"version": "7.1.0-beta.
|
|
3
|
+
"version": "7.1.0-beta.2",
|
|
4
4
|
"author": "jamesgpearce",
|
|
5
5
|
"repository": "github:tinyplex/tinybase",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"@electric-sql/pglite": "^0.3.14",
|
|
27
27
|
"@libsql/client": "^0.15.15",
|
|
28
28
|
"@powersync/common": "^1.43.1",
|
|
29
|
+
"@sinclair/typebox": "^0.34.41",
|
|
29
30
|
"@sqlite.org/sqlite-wasm": "^3.50.4-build1",
|
|
30
31
|
"@vlcn.io/crsqlite-wasm": "^0.16.0",
|
|
31
32
|
"bun": "^1.3.3",
|
|
@@ -60,6 +61,9 @@
|
|
|
60
61
|
"@powersync/common": {
|
|
61
62
|
"optional": true
|
|
62
63
|
},
|
|
64
|
+
"@sinclair/typebox": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
63
67
|
"@sqlite.org/sqlite-wasm": {
|
|
64
68
|
"optional": true
|
|
65
69
|
},
|
|
@@ -314,6 +318,12 @@
|
|
|
314
318
|
"schematizers/with-schemas": [
|
|
315
319
|
"./@types/schematizers/with-schemas/index.d.ts"
|
|
316
320
|
],
|
|
321
|
+
"schematizers/schematizer-typebox": [
|
|
322
|
+
"./@types/schematizers/schematizer-typebox/index.d.ts"
|
|
323
|
+
],
|
|
324
|
+
"schematizers/schematizer-typebox/with-schemas": [
|
|
325
|
+
"./@types/schematizers/schematizer-typebox/with-schemas/index.d.ts"
|
|
326
|
+
],
|
|
317
327
|
"schematizers/schematizer-zod": [
|
|
318
328
|
"./@types/schematizers/schematizer-zod/index.d.ts"
|
|
319
329
|
],
|
|
@@ -584,6 +594,12 @@
|
|
|
584
594
|
"min/schematizers/with-schemas": [
|
|
585
595
|
"./@types/schematizers/with-schemas/index.d.ts"
|
|
586
596
|
],
|
|
597
|
+
"min/schematizers/schematizer-typebox": [
|
|
598
|
+
"./@types/schematizers/schematizer-typebox/index.d.ts"
|
|
599
|
+
],
|
|
600
|
+
"min/schematizers/schematizer-typebox/with-schemas": [
|
|
601
|
+
"./@types/schematizers/schematizer-typebox/with-schemas/index.d.ts"
|
|
602
|
+
],
|
|
587
603
|
"min/schematizers/schematizer-zod": [
|
|
588
604
|
"./@types/schematizers/schematizer-zod/index.d.ts"
|
|
589
605
|
],
|
|
@@ -1055,6 +1071,18 @@
|
|
|
1055
1071
|
"default": "./schematizers/index.js"
|
|
1056
1072
|
}
|
|
1057
1073
|
},
|
|
1074
|
+
"./schematizers/schematizer-typebox": {
|
|
1075
|
+
"default": {
|
|
1076
|
+
"types": "./@types/schematizers/schematizer-typebox/index.d.ts",
|
|
1077
|
+
"default": "./schematizers/schematizer-typebox/index.js"
|
|
1078
|
+
}
|
|
1079
|
+
},
|
|
1080
|
+
"./schematizers/schematizer-typebox/with-schemas": {
|
|
1081
|
+
"default": {
|
|
1082
|
+
"types": "./@types/schematizers/schematizer-typebox/with-schemas/index.d.ts",
|
|
1083
|
+
"default": "./schematizers/schematizer-typebox/index.js"
|
|
1084
|
+
}
|
|
1085
|
+
},
|
|
1058
1086
|
"./schematizers/schematizer-zod": {
|
|
1059
1087
|
"default": {
|
|
1060
1088
|
"types": "./@types/schematizers/schematizer-zod/index.d.ts",
|
|
@@ -1595,6 +1623,18 @@
|
|
|
1595
1623
|
"default": "./min/schematizers/index.js"
|
|
1596
1624
|
}
|
|
1597
1625
|
},
|
|
1626
|
+
"./min/schematizers/schematizer-typebox": {
|
|
1627
|
+
"default": {
|
|
1628
|
+
"types": "./@types/schematizers/schematizer-typebox/index.d.ts",
|
|
1629
|
+
"default": "./min/schematizers/schematizer-typebox/index.js"
|
|
1630
|
+
}
|
|
1631
|
+
},
|
|
1632
|
+
"./min/schematizers/schematizer-typebox/with-schemas": {
|
|
1633
|
+
"default": {
|
|
1634
|
+
"types": "./@types/schematizers/schematizer-typebox/with-schemas/index.d.ts",
|
|
1635
|
+
"default": "./min/schematizers/schematizer-typebox/index.js"
|
|
1636
|
+
}
|
|
1637
|
+
},
|
|
1598
1638
|
"./min/schematizers/schematizer-zod": {
|
|
1599
1639
|
"default": {
|
|
1600
1640
|
"types": "./@types/schematizers/schematizer-zod/index.d.ts",
|
package/queries/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const STRING = getTypeOf(EMPTY_STRING);
|
|
|
4
4
|
const BOOLEAN = getTypeOf(true);
|
|
5
5
|
const NUMBER = getTypeOf(0);
|
|
6
6
|
const FUNCTION = getTypeOf(getTypeOf);
|
|
7
|
+
const NULL = 'null';
|
|
7
8
|
const SUM = 'sum';
|
|
8
9
|
const AVG = 'avg';
|
|
9
10
|
const MIN = 'min';
|
|
@@ -173,7 +174,7 @@ const getAggregateValue = (
|
|
|
173
174
|
|
|
174
175
|
const getCellOrValueType = (cellOrValue) => {
|
|
175
176
|
if (isNull(cellOrValue)) {
|
|
176
|
-
return
|
|
177
|
+
return NULL;
|
|
177
178
|
}
|
|
178
179
|
const type = getTypeOf(cellOrValue);
|
|
179
180
|
return isTypeStringOrBoolean(type) ||
|
|
@@ -4,6 +4,7 @@ const STRING = getTypeOf(EMPTY_STRING);
|
|
|
4
4
|
const BOOLEAN = getTypeOf(true);
|
|
5
5
|
const NUMBER = getTypeOf(0);
|
|
6
6
|
const FUNCTION = getTypeOf(getTypeOf);
|
|
7
|
+
const NULL = 'null';
|
|
7
8
|
const SUM = 'sum';
|
|
8
9
|
const AVG = 'avg';
|
|
9
10
|
const MIN = 'min';
|
|
@@ -173,7 +174,7 @@ const getAggregateValue = (
|
|
|
173
174
|
|
|
174
175
|
const getCellOrValueType = (cellOrValue) => {
|
|
175
176
|
if (isNull(cellOrValue)) {
|
|
176
|
-
return
|
|
177
|
+
return NULL;
|
|
177
178
|
}
|
|
178
179
|
const type = getTypeOf(cellOrValue);
|
|
179
180
|
return isTypeStringOrBoolean(type) ||
|
package/readme.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<link rel="preload" as="image" href="https://beta.tinybase.org/react.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/indexeddb.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/browser.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/cloudflare.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/postgresql.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/pglite.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/sqlite.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/bun.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/expo.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/electric.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/turso.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/powersync.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/partykit.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/yjs.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/crsqlite.png"><link rel="preload" as="image" href="https://beta.tinybase.org/automerge.svg?asImg"><link rel="preload" as="image" href="https://img.shields.io/github/stars/tinyplex/tinybase?style=for-the-badge&logo=GitHub&logoColor=%23fff&label=GitHub&labelColor=%23d81b60&color=%23333"><link rel="preload" as="image" href="https://img.shields.io/badge/Bluesky-Follow-blue?style=for-the-badge&logo=bluesky&logoColor=%23fff&color=%23333&labelColor=%230285FF"><link rel="preload" as="image" href="https://img.shields.io/badge/%2F%20Twitter-Follow-blue?style=for-the-badge&logo=x&logoColor=%23fff&color=%23333&labelColor=%23000"><link rel="preload" as="image" href="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&logo=discord&logoColor=%23fff&label=Discord&labelColor=%233131e8&color=%23333"><link rel="preload" as="image" href="https://img.shields.io/github/discussions/tinyplex/tinybase?style=for-the-badge&logo=GitHub&logoColor=%23fff&label=Ideas&labelColor=%23d81b60&color=%23333"><link rel="preload" as="image" href="https://img.shields.io/github/issues/tinyplex/tinybase?style=for-the-badge&logo=GitHub&logoColor=%23fff&label=Issues&labelColor=%23d81b60&color=%23333"><link rel="preload" as="image" href="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&logo=Vitest&logoColor=%23fff&color=%23333&labelColor=%2387c305"><link rel="preload" as="image" href="https://img.shields.io/npm/v/tinybase?style=for-the-badge&logo=npm&logoColor=%23fff&labelColor=%23bd0005&color=%23333"><link rel="preload" as="image" href="https://beta.tinybase.org/ui-react-dom.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/inspector.webp"><link rel="preload" as="image" href="https://github.com/cpojer.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/beekeeb.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/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://beta.tinybase.org/youtube.webp"><section id="hero"><h2 id="a-reactive-data-store-sync-engine">A <em>reactive</em> data store & <span><em>sync</em> engine</span></h2></section><p><a href="https://beta.tinybase.org/guides/releases/#v7-0"><em>NEW!</em> v7.0 release</a></p><p><span id="one-with">"The one with <code>NULL</code>!"</span></p><p><a class="start" href="https://beta.tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://beta.tinybase.org/demos/">Try the demos</a></p><p><a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/">Read the docs</a></p><hr><section><h2 id="it-s-reactive">It's <em>Reactive</em></h2><p>TinyBase lets you <a href="#register-granular-listeners">listen to changes</a> made to any part of your data. This means your app will be fast, since you only spend rendering cycles on things that change. The optional <a href="#call-hooks-to-bind-to-data">bindings to React</a> and <a href="#pre-built-reactive-components">pre-built components</a> let you easily build fully reactive UIs on top of TinyBase. You even get a built-in <a href="#set-checkpoints-for-an-undo-stack">undo stack</a>, and <a href="#an-inspector-for-your-data">developer tools</a>!</p></section><section><h2 id="it-s-database-like">It'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://beta.tinybase.org/guides/synchronization/">synchronize</a> and merge data across multiple sources, clients, and servers. And although TinyBase is an in-memory data store, you can easily <a href="#persist-to-storage-databases-more">persist</a> your data to file, <a href="https://beta.tinybase.org/api/persister-browser">browser storage</a>, <a href="https://beta.tinybase.org/api/persister-indexed-db">IndexedDB</a>, <a href="https://beta.tinybase.org/guides/persistence/database-persistence/">SQLite or PostgreSQL databases</a>, and <a href="https://beta.tinybase.org/guides/persistence/third-party-crdt-persistence/">more</a>.</p></section><section><h2 id="it-s-built-for-a-local-first-world">It's Built For A <em>Local-First</em> World</h2><p>TinyBase works anywhere that JavaScript does, but it's especially great for local-first apps: where data is stored locally on the user's device and that can be run offline. It's tiny by name, tiny by nature: just <a href="#did-we-say-tiny">5.4kB - 11.8kB</a> and with no dependencies - yet <a href="#well-tested-and-documented">100% tested</a>, <a href="https://beta.tinybase.org/guides/the-basics/getting-started/">fully documented</a>, and of course, <a href="https://github.com/tinyplex/tinybase">open source</a>!</p></section><hr><section id="friends"><h2 id="tinybase-works-great-on-its-own-but-also-plays-well-with-friends">TinyBase works great on its own, but also plays well with friends.</h2><div><a href="https://beta.tinybase.org/guides/building-uis/getting-started-with-ui-react"><img src="https://beta.tinybase.org/react.svg?asImg" width="48"> React</a></div><div><a href="https://beta.tinybase.org/api/persister-indexed-db/functions/creation/createindexeddbpersister"><img src="https://beta.tinybase.org/indexeddb.svg?asImg" width="48"> IndexedDB</a></div><div><a href="https://beta.tinybase.org/api/persister-browser"><img src="https://beta.tinybase.org/browser.svg?asImg" width="48"> OPFS</a></div><div><a href="https://beta.tinybase.org/guides/integrations/cloudflare-durable-objects"><img src="https://beta.tinybase.org/cloudflare.svg?asImg" width="48"> Cloudflare</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/postgresql.svg?asImg" width="48"> PostgreSQL</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/pglite.svg?asImg" width="48"> PGlite</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/sqlite.svg?asImg" width="48"> SQLite</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/bun.svg?asImg" width="48"> Bun SQLite</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/expo.svg?asImg" width="48"> Expo SQLite</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/electric.svg?asImg" width="48"> ElectricSQL</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/turso.svg?asImg" width="48"> Turso</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/powersync.svg?asImg" width="48"> PowerSync</a></div><div><a href="https://beta.tinybase.org/api/persister-partykit-client"><img src="https://beta.tinybase.org/partykit.svg?asImg" width="48"> PartyKit</a></div><div><a href="https://beta.tinybase.org/api/persister-yjs/functions/creation/createyjspersister"><img src="https://beta.tinybase.org/yjs.svg?asImg" width="48"> YJS</a></div><div><a href="https://beta.tinybase.org/api/persister-cr-sqlite-wasm"><img src="https://beta.tinybase.org/crsqlite.png" width="48"> CR-SQLite</a></div><div><a href="https://beta.tinybase.org/api/persister-automerge"><img src="https://beta.tinybase.org/automerge.svg?asImg" width="48"> Automerge</a></div><p>(Baffled by all these logos? Check out our <a href="https://beta.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&logo=GitHub&logoColor=%23fff&label=GitHub&labelColor=%23d81b60&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&logo=bluesky&logoColor=%23fff&color=%23333&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&logo=x&logoColor=%23fff&color=%23333&labelColor=%23000"> </a><a href="https://discord.com/invite/mGz3mevwP8" target="_blank"><img src="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&logo=discord&logoColor=%23fff&label=Discord&labelColor=%233131e8&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&logo=GitHub&logoColor=%23fff&label=Ideas&labelColor=%23d81b60&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&logo=GitHub&logoColor=%23fff&label=Issues&labelColor=%23d81b60&color=%23333"> </a><a href="#well-tested-and-documented"><img src="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&logo=Vitest&logoColor=%23fff&color=%23333&labelColor=%2387c305"> </a><a href="https://www.npmjs.com/package/tinybase/v/7.1.0-beta.0" target="_blank"><img src="https://img.shields.io/npm/v/tinybase?style=for-the-badge&logo=npm&logoColor=%23fff&labelColor=%23bd0005&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://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> requires just a simple call to the <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/createstore/"><code>createStore</code></a> function. Once you have one, you can easily set <a href="https://beta.tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> in it by unique <a href="https://beta.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://beta.tinybase.org/guides/the-basics/">The Basics</a> guide.</p></section>
|
|
1
|
+
<link rel="preload" as="image" href="https://beta.tinybase.org/react.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/indexeddb.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/browser.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/cloudflare.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/postgresql.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/pglite.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/sqlite.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/bun.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/expo.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/electric.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/turso.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/powersync.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/partykit.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/yjs.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/crsqlite.png"><link rel="preload" as="image" href="https://beta.tinybase.org/automerge.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/zod.svg?asImg"><link rel="preload" as="image" href="https://beta.tinybase.org/typebox.svg?asImg"><link rel="preload" as="image" href="https://img.shields.io/github/stars/tinyplex/tinybase?style=for-the-badge&logo=GitHub&logoColor=%23fff&label=GitHub&labelColor=%23d81b60&color=%23333"><link rel="preload" as="image" href="https://img.shields.io/badge/Bluesky-Follow-blue?style=for-the-badge&logo=bluesky&logoColor=%23fff&color=%23333&labelColor=%230285FF"><link rel="preload" as="image" href="https://img.shields.io/badge/%2F%20Twitter-Follow-blue?style=for-the-badge&logo=x&logoColor=%23fff&color=%23333&labelColor=%23000"><link rel="preload" as="image" href="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&logo=discord&logoColor=%23fff&label=Discord&labelColor=%233131e8&color=%23333"><link rel="preload" as="image" href="https://img.shields.io/github/discussions/tinyplex/tinybase?style=for-the-badge&logo=GitHub&logoColor=%23fff&label=Ideas&labelColor=%23d81b60&color=%23333"><link rel="preload" as="image" href="https://img.shields.io/github/issues/tinyplex/tinybase?style=for-the-badge&logo=GitHub&logoColor=%23fff&label=Issues&labelColor=%23d81b60&color=%23333"><link rel="preload" as="image" href="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&logo=Vitest&logoColor=%23fff&color=%23333&labelColor=%2387c305"><link rel="preload" as="image" href="https://img.shields.io/npm/v/tinybase?style=for-the-badge&logo=npm&logoColor=%23fff&labelColor=%23bd0005&color=%23333"><link rel="preload" as="image" href="https://beta.tinybase.org/ui-react-dom.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/inspector.webp"><link rel="preload" as="image" href="https://github.com/cpojer.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/beekeeb.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/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://beta.tinybase.org/youtube.webp"><section id="hero"><h2 id="a-reactive-data-store-sync-engine">A <em>reactive</em> data store & <span><em>sync</em> engine</span></h2></section><p><a href="https://beta.tinybase.org/guides/releases/#v7-1"><em>NEW!</em> v7.1 release</a></p><p><span id="one-with">"The one with Schematizers!"</span></p><p><a class="start" href="https://beta.tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://beta.tinybase.org/demos/">Try the demos</a></p><p><a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/">Read the docs</a></p><hr><section><h2 id="it-s-reactive">It's <em>Reactive</em></h2><p>TinyBase lets you <a href="#register-granular-listeners">listen to changes</a> made to any part of your data. This means your app will be fast, since you only spend rendering cycles on things that change. The optional <a href="#call-hooks-to-bind-to-data">bindings to React</a> and <a href="#pre-built-reactive-components">pre-built components</a> let you easily build fully reactive UIs on top of TinyBase. You even get a built-in <a href="#set-checkpoints-for-an-undo-stack">undo stack</a>, and <a href="#an-inspector-for-your-data">developer tools</a>!</p></section><section><h2 id="it-s-database-like">It'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://beta.tinybase.org/guides/synchronization/">synchronize</a> and merge data across multiple sources, clients, and servers. And although TinyBase is an in-memory data store, you can easily <a href="#persist-to-storage-databases-more">persist</a> your data to file, <a href="https://beta.tinybase.org/api/persister-browser">browser storage</a>, <a href="https://beta.tinybase.org/api/persister-indexed-db">IndexedDB</a>, <a href="https://beta.tinybase.org/guides/persistence/database-persistence/">SQLite or PostgreSQL databases</a>, and <a href="https://beta.tinybase.org/guides/persistence/third-party-crdt-persistence/">more</a>.</p></section><section><h2 id="it-s-built-for-a-local-first-world">It's Built For A <em>Local-First</em> World</h2><p>TinyBase works anywhere that JavaScript does, but it's especially great for local-first apps: where data is stored locally on the user's device and that can be run offline. It's tiny by name, tiny by nature: just <a href="#did-we-say-tiny">5.4kB - 11.8kB</a> and with no dependencies - yet <a href="#well-tested-and-documented">100% tested</a>, <a href="https://beta.tinybase.org/guides/the-basics/getting-started/">fully documented</a>, and of course, <a href="https://github.com/tinyplex/tinybase">open source</a>!</p></section><hr><section id="friends"><h2 id="tinybase-works-great-on-its-own-but-also-plays-well-with-friends">TinyBase works great on its own, but also plays well with friends.</h2><div><a href="https://beta.tinybase.org/guides/building-uis/getting-started-with-ui-react"><img src="https://beta.tinybase.org/react.svg?asImg" width="48"> React</a></div><div><a href="https://beta.tinybase.org/api/persister-indexed-db/functions/creation/createindexeddbpersister"><img src="https://beta.tinybase.org/indexeddb.svg?asImg" width="48"> IndexedDB</a></div><div><a href="https://beta.tinybase.org/api/persister-browser"><img src="https://beta.tinybase.org/browser.svg?asImg" width="48"> OPFS</a></div><div><a href="https://beta.tinybase.org/guides/integrations/cloudflare-durable-objects"><img src="https://beta.tinybase.org/cloudflare.svg?asImg" width="48"> Cloudflare</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/postgresql.svg?asImg" width="48"> PostgreSQL</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/pglite.svg?asImg" width="48"> PGlite</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/sqlite.svg?asImg" width="48"> SQLite</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/bun.svg?asImg" width="48"> Bun SQLite</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/expo.svg?asImg" width="48"> Expo SQLite</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/electric.svg?asImg" width="48"> ElectricSQL</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/turso.svg?asImg" width="48"> Turso</a></div><div><a href="https://beta.tinybase.org/guides/schemas-and-persistence/database-persistence"><img src="https://beta.tinybase.org/powersync.svg?asImg" width="48"> PowerSync</a></div><div><a href="https://beta.tinybase.org/api/persister-partykit-client"><img src="https://beta.tinybase.org/partykit.svg?asImg" width="48"> PartyKit</a></div><div><a href="https://beta.tinybase.org/api/persister-yjs/functions/creation/createyjspersister"><img src="https://beta.tinybase.org/yjs.svg?asImg" width="48"> YJS</a></div><div><a href="https://beta.tinybase.org/api/persister-cr-sqlite-wasm"><img src="https://beta.tinybase.org/crsqlite.png" width="48"> CR-SQLite</a></div><div><a href="https://beta.tinybase.org/api/persister-automerge"><img src="https://beta.tinybase.org/automerge.svg?asImg" width="48"> Automerge</a></div><div><a href="https://beta.tinybase.org/api/schematizer-zod/functions/creation/createzodschematizer"><img src="https://beta.tinybase.org/zod.svg?asImg" width="48"> Zod</a></div><div><a href="https://beta.tinybase.org/api/schematizer-typebox/functions/creation/createtypeboxschematizer"><img src="https://beta.tinybase.org/typebox.svg?asImg" width="48"> TypeBox</a></div><p>(Baffled by all these logos? Check out our <a href="https://beta.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&logo=GitHub&logoColor=%23fff&label=GitHub&labelColor=%23d81b60&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&logo=bluesky&logoColor=%23fff&color=%23333&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&logo=x&logoColor=%23fff&color=%23333&labelColor=%23000"> </a><a href="https://discord.com/invite/mGz3mevwP8" target="_blank"><img src="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&logo=discord&logoColor=%23fff&label=Discord&labelColor=%233131e8&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&logo=GitHub&logoColor=%23fff&label=Ideas&labelColor=%23d81b60&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&logo=GitHub&logoColor=%23fff&label=Issues&labelColor=%23d81b60&color=%23333"> </a><a href="#well-tested-and-documented"><img src="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&logo=Vitest&logoColor=%23fff&color=%23333&labelColor=%2387c305"> </a><a href="https://www.npmjs.com/package/tinybase/v/7.1.0-beta.1" target="_blank"><img src="https://img.shields.io/npm/v/tinybase?style=for-the-badge&logo=npm&logoColor=%23fff&labelColor=%23bd0005&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://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> requires just a simple call to the <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/createstore/"><code>createStore</code></a> function. Once you have one, you can easily set <a href="https://beta.tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> in it by unique <a href="https://beta.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://beta.tinybase.org/guides/the-basics/">The Basics</a> guide.</p></section>
|
|
2
2
|
|
|
3
3
|
```js
|
|
4
4
|
import {createStore} from 'tinybase';
|
|
@@ -275,4 +275,4 @@ console.log(store.getCell('pets', 'felix', 'sold'));
|
|
|
275
275
|
// -> false
|
|
276
276
|
```
|
|
277
277
|
|
|
278
|
-
<section><h2 id="did-we-say-tiny">Did we say tiny?</h2><p>If you use the basic <a href="https://beta.tinybase.org/api/store/"><code>store</code></a> module alone, you'll only add a gzipped <em>5.4kB</em> to your app. Incrementally add the other modules as you need more functionality, or get it all for <em>11.8kB</em>.</p><p>The optional <a href="https://beta.tinybase.org/api/ui-react/"><code>ui-react</code></a> module is just <em>5.2kB</em>, the ui-react-dom components are another <em>3.7kB</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://beta.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://beta.tinybase.org/api/store/">tinybase/store</a> (minimal)</th><td>5.4kB</td><td>54.5kB</td></tr><tr><th class="right">tinybase (complete)</th><td>11.8kB</td><td>123.4kB</td></tr><tr><th class="right"><a href="https://beta.tinybase.org/api/ui-react/">ui-react</a></th><td>5.2kB</td><td>55.6kB</td></tr><tr><th class="right"><a href="https://beta.tinybase.org/api/ui-react-dom/">ui-react-dom</a></th><td>3.7kB</td><td>32.8kB</td></tr></tbody></table></div><section><h2 id="well-tested-and-documented">Well tested and documented.</h2><p>TinyBase has <em>100.0%</em> test coverage, including the code throughout the documentation - even on this page! The guides, demos, and API examples are designed to make it as easy as possible for you to get your TinyBase-powered app up and running.</p><p>Read more about how TinyBase is tested in the Unit <a href="https://beta.tinybase.org/guides/how-tinybase-is-built/testing/">Testing</a> guide.</p></section><div class="table"><table class="fixed"><tbody><tr><th width="30%"> </th><th>Total</th><th>Tested</th><th>Coverage</th></tr><tr><th class="right">Lines</th><td>2,340</td><td>2,340</td><td>100.0%</td></tr><tr><th class="right">Statements</th><td>2,533</td><td>2,533</td><td>100.0%</td></tr><tr><th class="right">Functions</th><td>1,010</td><td>1,010</td><td>100.0%</td></tr><tr><th class="right">Branches</th><td>892</td><td>892</td><td>100.0%</td></tr><tr><th class="right">Tests</th><td colspan="3">7,101</td></tr><tr><th class="right">Assertions</th><td colspan="3">31,961</td></tr></tbody></table></div><hr><section id="sponsors"><h2 id="proud-to-be-sponsored-by">Proud to be sponsored by:</h2><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/expo" target="_blank"><img src="https://github.com/expo.png?size=48" title="expo" 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/cancelself" target="_blank"><img src="https://github.com/cancelself.png?size=48" title="cancelself" 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://beta.tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://beta.tinybase.org/demos/">Try the demos</a></p><p><a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/">Read the docs</a></p><hr><section id="family"><h2 id="meet-the-family">Meet the family</h2><p>TinyBase is part of a group of small libraries designed to help make rich client and local-first apps easier to build. Check out the others!</p><p><a href="https://synclets.org" target="_blank"><img src="https://synclets.org/favicon.svg?asImg" width="48"><br><b>Synclets</b></a><br>An open, storage-agnostic, sync engine development kit.</p><p><a href="https://tinywidgets.org" target="_blank"><img src="https://tinywidgets.org/favicon.svg?asImg" width="48"><br><b>TinyWidgets</b></a><br>A collection of tiny, reusable, UI components.</p><p><a href="https://tinytick.org" target="_blank"><img src="https://tinytick.org/favicon.svg?asImg" width="48"><br><b>TinyTick</b></a><br>A tiny but very useful task orchestrator.</p></section><hr><section id="about"><h2 id="about">About</h2><p>Modern apps deserve better. Why trade reactive user experiences to be able to use relational data? Or sacrifice features for bundle size? And why does the cloud do all the work <a href="https://localfirstweb.dev/" target="_blank">anyway</a>?</p><p>Building TinyBase was originally an interesting exercise for <a rel="me" href="https://tripleodeon.com">me</a> in API design, minification, and documentation. But now it has taken on a life of its own, and has grown beyond my wildest expectations.</p><p>It could not have been built without these great <a href="https://beta.tinybase.org/guides/how-tinybase-is-built/credits/#giants">projects</a> and <a href="https://beta.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://beta.tinybase.org/youtube.webp"></a></section>
|
|
278
|
+
<section><h2 id="did-we-say-tiny">Did we say tiny?</h2><p>If you use the basic <a href="https://beta.tinybase.org/api/store/"><code>store</code></a> module alone, you'll only add a gzipped <em>5.4kB</em> to your app. Incrementally add the other modules as you need more functionality, or get it all for <em>11.8kB</em>.</p><p>The optional <a href="https://beta.tinybase.org/api/ui-react/"><code>ui-react</code></a> module is just <em>5.2kB</em>, the ui-react-dom components are another <em>3.7kB</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://beta.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://beta.tinybase.org/api/store/">tinybase/store</a> (minimal)</th><td>5.4kB</td><td>54.6kB</td></tr><tr><th class="right">tinybase (complete)</th><td>11.8kB</td><td>123.4kB</td></tr><tr><th class="right"><a href="https://beta.tinybase.org/api/ui-react/">ui-react</a></th><td>5.2kB</td><td>55.6kB</td></tr><tr><th class="right"><a href="https://beta.tinybase.org/api/ui-react-dom/">ui-react-dom</a></th><td>3.7kB</td><td>32.8kB</td></tr></tbody></table></div><section><h2 id="well-tested-and-documented">Well tested and documented.</h2><p>TinyBase has <em>100.0%</em> test coverage, including the code throughout the documentation - even on this page! The guides, demos, and API examples are designed to make it as easy as possible for you to get your TinyBase-powered app up and running.</p><p>Read more about how TinyBase is tested in the Unit <a href="https://beta.tinybase.org/guides/how-tinybase-is-built/testing/">Testing</a> guide.</p></section><div class="table"><table class="fixed"><tbody><tr><th width="30%"> </th><th>Total</th><th>Tested</th><th>Coverage</th></tr><tr><th class="right">Lines</th><td>2,341</td><td>2,341</td><td>100.0%</td></tr><tr><th class="right">Statements</th><td>2,534</td><td>2,534</td><td>100.0%</td></tr><tr><th class="right">Functions</th><td>1,010</td><td>1,010</td><td>100.0%</td></tr><tr><th class="right">Branches</th><td>892</td><td>892</td><td>100.0%</td></tr><tr><th class="right">Tests</th><td colspan="3">7,128</td></tr><tr><th class="right">Assertions</th><td colspan="3">31,997</td></tr></tbody></table></div><hr><section id="sponsors"><h2 id="proud-to-be-sponsored-by">Proud to be sponsored by:</h2><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/expo" target="_blank"><img src="https://github.com/expo.png?size=48" title="expo" 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/cancelself" target="_blank"><img src="https://github.com/cancelself.png?size=48" title="cancelself" 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://beta.tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://beta.tinybase.org/demos/">Try the demos</a></p><p><a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/">Read the docs</a></p><hr><section id="family"><h2 id="meet-the-family">Meet the family</h2><p>TinyBase is part of a group of small libraries designed to help make rich client and local-first apps easier to build. Check out the others!</p><p><a href="https://synclets.org" target="_blank"><img src="https://synclets.org/favicon.svg?asImg" width="48"><br><b>Synclets</b></a><br>An open, storage-agnostic, sync engine development kit.</p><p><a href="https://tinywidgets.org" target="_blank"><img src="https://tinywidgets.org/favicon.svg?asImg" width="48"><br><b>TinyWidgets</b></a><br>A collection of tiny, reusable, UI components.</p><p><a href="https://tinytick.org" target="_blank"><img src="https://tinytick.org/favicon.svg?asImg" width="48"><br><b>TinyTick</b></a><br>A tiny but very useful task orchestrator.</p></section><hr><section id="about"><h2 id="about">About</h2><p>Modern apps deserve better. Why trade reactive user experiences to be able to use relational data? Or sacrifice features for bundle size? And why does the cloud do all the work <a href="https://localfirstweb.dev/" target="_blank">anyway</a>?</p><p>Building TinyBase was originally an interesting exercise for <a rel="me" href="https://tripleodeon.com">me</a> in API design, minification, and documentation. But now it has taken on a life of its own, and has grown beyond my wildest expectations.</p><p>It could not have been built without these great <a href="https://beta.tinybase.org/guides/how-tinybase-is-built/credits/#giants">projects</a> and <a href="https://beta.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://beta.tinybase.org/youtube.webp"></a></section>
|
package/releases.md
CHANGED
|
@@ -1,8 +1,32 @@
|
|
|
1
|
-
<link rel="preload" as="image" href="https://beta.tinybase.org/inspector.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/partykit.gif"><link rel="preload" as="image" href="https://beta.tinybase.org/ui-react-dom.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/store-inspector.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/car-analysis.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/movie-database.webp"><p>This is a reverse chronological list of the major TinyBase releases, with highlighted features.</p><hr><h1 id="v7-
|
|
1
|
+
<link rel="preload" as="image" href="https://beta.tinybase.org/inspector.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/partykit.gif"><link rel="preload" as="image" href="https://beta.tinybase.org/ui-react-dom.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/store-inspector.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/car-analysis.webp"><link rel="preload" as="image" href="https://beta.tinybase.org/movie-database.webp"><p>This is a reverse chronological list of the major TinyBase releases, with highlighted features.</p><hr><h1 id="v7-1">v7.1</h1><p>This release introduces <strong>Schematizers</strong>, a new system for converting schemas from popular validation libraries into TinyBase's schema format.</p><h2 id="schematizers">Schematizers</h2><p>Schematizers provide a bridge between external schema validation libraries (like Zod) and TinyBase's <a href="https://beta.tinybase.org/api/store/type-aliases/schema/tablesschema/"><code>TablesSchema</code></a> and <a href="https://beta.tinybase.org/api/store/type-aliases/schema/valuesschema/"><code>ValuesSchema</code></a> formats. Instead of manually writing TinyBase schemas, you can now convert existing schemas at runtime:</p>
|
|
2
2
|
|
|
3
3
|
```js
|
|
4
4
|
import {createStore} from 'tinybase';
|
|
5
|
+
import {createZodSchematizer} from 'tinybase/schematizers/schematizer-zod';
|
|
6
|
+
import {z} from 'zod';
|
|
5
7
|
|
|
8
|
+
const schematizer = createZodSchematizer();
|
|
9
|
+
|
|
10
|
+
const zodSchema = {
|
|
11
|
+
pets: z.object({
|
|
12
|
+
species: z.string(),
|
|
13
|
+
age: z.number(),
|
|
14
|
+
sold: z.boolean().default(false),
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const schematizedStore = createStore().setTablesSchema(
|
|
19
|
+
schematizer.toTablesSchema(zodSchema),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
schematizedStore.setRow('pets', 'fido', {species: 'dog', age: 3});
|
|
23
|
+
console.log(schematizedStore.getRow('pets', 'fido'));
|
|
24
|
+
// -> {species: 'dog', age: 3, sold: false}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
<p>Schematizers perform best-effort conversions, extracting basic type information (string, number, boolean), defaults, and nullable settings from your schemas.</p><p>This release includes support for Zod via the <a href="https://beta.tinybase.org/api/schematizer-zod/functions/creation/createzodschematizer/"><code>createZodSchematizer</code></a> function and TypeBox via the <a href="https://beta.tinybase.org/api/schematizer-typebox/functions/creation/createtypeboxschematizer/"><code>createTypeBoxSchematizer</code></a> function, with support for additional libraries planned for future releases.</p><p>For more information, see the <a href="https://beta.tinybase.org/guides/schemas/using-schematizers/">Using Schematizers</a> guide.</p><hr><h1 id="v7-0">v7.0</h1><p>This important (and slightly breaking!) release adds support for <code>null</code> as a valid <a href="https://beta.tinybase.org/api/store/type-aliases/store/cell/"><code>Cell</code></a> and <a href="https://beta.tinybase.org/api/store/type-aliases/store/value/"><code>Value</code></a> type, alongside <code>string</code>, <code>number</code>, and <code>boolean</code>.</p><h2 id="null-type-support">Null Type Support</h2><p>You can now set Cells and <a href="https://beta.tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> to <code>null</code>:</p>
|
|
28
|
+
|
|
29
|
+
```js
|
|
6
30
|
const store = createStore();
|
|
7
31
|
store.setCell('pets', 'fido', 'species', 'dog');
|
|
8
32
|
store.setCell('pets', 'fido', 'color', null);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const getTypeOf = (thing) => typeof thing;
|
|
2
|
+
const EMPTY_STRING = '';
|
|
3
|
+
const STRING = getTypeOf(EMPTY_STRING);
|
|
4
|
+
const BOOLEAN = getTypeOf(true);
|
|
5
|
+
const NUMBER = getTypeOf(0);
|
|
6
|
+
const TYPE = 'type';
|
|
7
|
+
const DEFAULT = 'default';
|
|
8
|
+
const ALLOW_NULL = 'allowNull';
|
|
9
|
+
const NULL = 'null';
|
|
10
|
+
|
|
11
|
+
const getIfNotFunction = (predicate) => (value, then, otherwise) =>
|
|
12
|
+
predicate(value) ? otherwise?.() : then(value);
|
|
13
|
+
const isNullish = (thing) => thing == null;
|
|
14
|
+
const isUndefined = (thing) => thing === void 0;
|
|
15
|
+
const ifNotNullish = getIfNotFunction(isNullish);
|
|
16
|
+
const ifNotUndefined = getIfNotFunction(isUndefined);
|
|
17
|
+
const size = (arrayOrString) => arrayOrString.length;
|
|
18
|
+
|
|
19
|
+
const arrayForEach = (array, cb) => array.forEach(cb);
|
|
20
|
+
|
|
21
|
+
const object = Object;
|
|
22
|
+
const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
|
|
23
|
+
const objEntries = object.entries;
|
|
24
|
+
const isObject = (obj) =>
|
|
25
|
+
!isNullish(obj) &&
|
|
26
|
+
ifNotNullish(
|
|
27
|
+
getPrototypeOf(obj),
|
|
28
|
+
(objPrototype) =>
|
|
29
|
+
objPrototype == object.prototype ||
|
|
30
|
+
isNullish(getPrototypeOf(objPrototype)),
|
|
31
|
+
|
|
32
|
+
/* istanbul ignore next */
|
|
33
|
+
() => true,
|
|
34
|
+
);
|
|
35
|
+
const objIds = object.keys;
|
|
36
|
+
const objFreeze = object.freeze;
|
|
37
|
+
const objNew = (entries = []) => object.fromEntries(entries);
|
|
38
|
+
const objForEach = (obj, cb) =>
|
|
39
|
+
arrayForEach(objEntries(obj), ([id, value]) => cb(value, id));
|
|
40
|
+
const objSize = (obj) => size(objIds(obj));
|
|
41
|
+
const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
|
|
42
|
+
|
|
43
|
+
const ANY_OF = 'anyOf';
|
|
44
|
+
const unwrapSchema = (schema, defaultValue, allowNull) => {
|
|
45
|
+
if (schema?.[ANY_OF]) {
|
|
46
|
+
const types = schema[ANY_OF];
|
|
47
|
+
const hasNull = types.some((t) => t?.type === NULL);
|
|
48
|
+
const nonNullType = types.find((t) => t?.type !== NULL);
|
|
49
|
+
if (hasNull && nonNullType) {
|
|
50
|
+
return unwrapSchema(nonNullType, defaultValue ?? schema?.[DEFAULT], true);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return [schema, defaultValue ?? schema?.[DEFAULT], allowNull ?? false];
|
|
54
|
+
};
|
|
55
|
+
const createTypeBoxSchematizer = () => {
|
|
56
|
+
const toTablesSchema = (schemas) => {
|
|
57
|
+
const tablesSchema = objNew();
|
|
58
|
+
objForEach(schemas, (typeBoxSchema, tableId) => {
|
|
59
|
+
const tableSchema = objNew();
|
|
60
|
+
ifNotUndefined(typeBoxSchema?.properties, (properties) =>
|
|
61
|
+
objForEach(properties, (cellTypeBoxSchema, cellId) =>
|
|
62
|
+
ifNotUndefined(
|
|
63
|
+
toCellOrValueSchema(cellTypeBoxSchema),
|
|
64
|
+
(cellSchema) => {
|
|
65
|
+
tableSchema[cellId] = cellSchema;
|
|
66
|
+
},
|
|
67
|
+
),
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
if (!objIsEmpty(tableSchema)) {
|
|
71
|
+
tablesSchema[tableId] = tableSchema;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return tablesSchema;
|
|
75
|
+
};
|
|
76
|
+
const toValuesSchema = (schemas) => {
|
|
77
|
+
const valuesSchema = objNew();
|
|
78
|
+
objForEach(schemas, (typeBoxSchema, valueId) =>
|
|
79
|
+
ifNotUndefined(toCellOrValueSchema(typeBoxSchema), (valueSchema) => {
|
|
80
|
+
valuesSchema[valueId] = valueSchema;
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
return valuesSchema;
|
|
84
|
+
};
|
|
85
|
+
const toCellOrValueSchema = (typeBoxSchema) => {
|
|
86
|
+
const [schema, defaultValue, allowNull] = unwrapSchema(typeBoxSchema);
|
|
87
|
+
const type = schema?.type;
|
|
88
|
+
if (type !== STRING && type !== NUMBER && type !== BOOLEAN) {
|
|
89
|
+
return void 0;
|
|
90
|
+
}
|
|
91
|
+
const cellOrValueSchema = {[TYPE]: type};
|
|
92
|
+
ifNotUndefined(defaultValue, (defaultValue2) => {
|
|
93
|
+
cellOrValueSchema[DEFAULT] = defaultValue2;
|
|
94
|
+
});
|
|
95
|
+
if (allowNull) {
|
|
96
|
+
cellOrValueSchema[ALLOW_NULL] = true;
|
|
97
|
+
}
|
|
98
|
+
return cellOrValueSchema;
|
|
99
|
+
};
|
|
100
|
+
return objFreeze({
|
|
101
|
+
toTablesSchema,
|
|
102
|
+
toValuesSchema,
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export {createTypeBoxSchematizer};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const getTypeOf = (thing) => typeof thing;
|
|
2
|
+
const EMPTY_STRING = '';
|
|
3
|
+
const STRING = getTypeOf(EMPTY_STRING);
|
|
4
|
+
const BOOLEAN = getTypeOf(true);
|
|
5
|
+
const NUMBER = getTypeOf(0);
|
|
6
|
+
const TYPE = 'type';
|
|
7
|
+
const DEFAULT = 'default';
|
|
8
|
+
const ALLOW_NULL = 'allowNull';
|
|
9
|
+
const NULL = 'null';
|
|
10
|
+
|
|
11
|
+
const getIfNotFunction = (predicate) => (value, then, otherwise) =>
|
|
12
|
+
predicate(value) ? otherwise?.() : then(value);
|
|
13
|
+
const isNullish = (thing) => thing == null;
|
|
14
|
+
const isUndefined = (thing) => thing === void 0;
|
|
15
|
+
const ifNotNullish = getIfNotFunction(isNullish);
|
|
16
|
+
const ifNotUndefined = getIfNotFunction(isUndefined);
|
|
17
|
+
const size = (arrayOrString) => arrayOrString.length;
|
|
18
|
+
|
|
19
|
+
const arrayForEach = (array, cb) => array.forEach(cb);
|
|
20
|
+
|
|
21
|
+
const object = Object;
|
|
22
|
+
const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
|
|
23
|
+
const objEntries = object.entries;
|
|
24
|
+
const isObject = (obj) =>
|
|
25
|
+
!isNullish(obj) &&
|
|
26
|
+
ifNotNullish(
|
|
27
|
+
getPrototypeOf(obj),
|
|
28
|
+
(objPrototype) =>
|
|
29
|
+
objPrototype == object.prototype ||
|
|
30
|
+
isNullish(getPrototypeOf(objPrototype)),
|
|
31
|
+
|
|
32
|
+
/* istanbul ignore next */
|
|
33
|
+
() => true,
|
|
34
|
+
);
|
|
35
|
+
const objIds = object.keys;
|
|
36
|
+
const objFreeze = object.freeze;
|
|
37
|
+
const objNew = (entries = []) => object.fromEntries(entries);
|
|
38
|
+
const objForEach = (obj, cb) =>
|
|
39
|
+
arrayForEach(objEntries(obj), ([id, value]) => cb(value, id));
|
|
40
|
+
const objSize = (obj) => size(objIds(obj));
|
|
41
|
+
const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
|
|
42
|
+
|
|
43
|
+
const ANY_OF = 'anyOf';
|
|
44
|
+
const unwrapSchema = (schema, defaultValue, allowNull) => {
|
|
45
|
+
if (schema?.[ANY_OF]) {
|
|
46
|
+
const types = schema[ANY_OF];
|
|
47
|
+
const hasNull = types.some((t) => t?.type === NULL);
|
|
48
|
+
const nonNullType = types.find((t) => t?.type !== NULL);
|
|
49
|
+
if (hasNull && nonNullType) {
|
|
50
|
+
return unwrapSchema(nonNullType, defaultValue ?? schema?.[DEFAULT], true);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return [schema, defaultValue ?? schema?.[DEFAULT], allowNull ?? false];
|
|
54
|
+
};
|
|
55
|
+
const createTypeBoxSchematizer = () => {
|
|
56
|
+
const toTablesSchema = (schemas) => {
|
|
57
|
+
const tablesSchema = objNew();
|
|
58
|
+
objForEach(schemas, (typeBoxSchema, tableId) => {
|
|
59
|
+
const tableSchema = objNew();
|
|
60
|
+
ifNotUndefined(typeBoxSchema?.properties, (properties) =>
|
|
61
|
+
objForEach(properties, (cellTypeBoxSchema, cellId) =>
|
|
62
|
+
ifNotUndefined(
|
|
63
|
+
toCellOrValueSchema(cellTypeBoxSchema),
|
|
64
|
+
(cellSchema) => {
|
|
65
|
+
tableSchema[cellId] = cellSchema;
|
|
66
|
+
},
|
|
67
|
+
),
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
if (!objIsEmpty(tableSchema)) {
|
|
71
|
+
tablesSchema[tableId] = tableSchema;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return tablesSchema;
|
|
75
|
+
};
|
|
76
|
+
const toValuesSchema = (schemas) => {
|
|
77
|
+
const valuesSchema = objNew();
|
|
78
|
+
objForEach(schemas, (typeBoxSchema, valueId) =>
|
|
79
|
+
ifNotUndefined(toCellOrValueSchema(typeBoxSchema), (valueSchema) => {
|
|
80
|
+
valuesSchema[valueId] = valueSchema;
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
return valuesSchema;
|
|
84
|
+
};
|
|
85
|
+
const toCellOrValueSchema = (typeBoxSchema) => {
|
|
86
|
+
const [schema, defaultValue, allowNull] = unwrapSchema(typeBoxSchema);
|
|
87
|
+
const type = schema?.type;
|
|
88
|
+
if (type !== STRING && type !== NUMBER && type !== BOOLEAN) {
|
|
89
|
+
return void 0;
|
|
90
|
+
}
|
|
91
|
+
const cellOrValueSchema = {[TYPE]: type};
|
|
92
|
+
ifNotUndefined(defaultValue, (defaultValue2) => {
|
|
93
|
+
cellOrValueSchema[DEFAULT] = defaultValue2;
|
|
94
|
+
});
|
|
95
|
+
if (allowNull) {
|
|
96
|
+
cellOrValueSchema[ALLOW_NULL] = true;
|
|
97
|
+
}
|
|
98
|
+
return cellOrValueSchema;
|
|
99
|
+
};
|
|
100
|
+
return objFreeze({
|
|
101
|
+
toTablesSchema,
|
|
102
|
+
toValuesSchema,
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export {createTypeBoxSchematizer};
|
package/store/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const FUNCTION = getTypeOf(getTypeOf);
|
|
|
7
7
|
const TYPE = 'type';
|
|
8
8
|
const DEFAULT = 'default';
|
|
9
9
|
const ALLOW_NULL = 'allowNull';
|
|
10
|
+
const NULL = 'null';
|
|
10
11
|
const LISTENER = 'Listener';
|
|
11
12
|
const ADD = 'add';
|
|
12
13
|
const HAS = 'Has';
|
|
@@ -62,7 +63,7 @@ const arrayShift = (array) => array.shift();
|
|
|
62
63
|
|
|
63
64
|
const getCellOrValueType = (cellOrValue) => {
|
|
64
65
|
if (isNull(cellOrValue)) {
|
|
65
|
-
return
|
|
66
|
+
return NULL;
|
|
66
67
|
}
|
|
67
68
|
const type = getTypeOf(cellOrValue);
|
|
68
69
|
return isTypeStringOrBoolean(type) ||
|
|
@@ -7,6 +7,7 @@ const FUNCTION = getTypeOf(getTypeOf);
|
|
|
7
7
|
const TYPE = 'type';
|
|
8
8
|
const DEFAULT = 'default';
|
|
9
9
|
const ALLOW_NULL = 'allowNull';
|
|
10
|
+
const NULL = 'null';
|
|
10
11
|
const LISTENER = 'Listener';
|
|
11
12
|
const ADD = 'add';
|
|
12
13
|
const HAS = 'Has';
|
|
@@ -62,7 +63,7 @@ const arrayShift = (array) => array.shift();
|
|
|
62
63
|
|
|
63
64
|
const getCellOrValueType = (cellOrValue) => {
|
|
64
65
|
if (isNull(cellOrValue)) {
|
|
65
|
-
return
|
|
66
|
+
return NULL;
|
|
66
67
|
}
|
|
67
68
|
const type = getTypeOf(cellOrValue);
|
|
68
69
|
return isTypeStringOrBoolean(type) ||
|
package/ui-react-dom/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const STRING = getTypeOf(EMPTY_STRING);
|
|
|
10
10
|
const BOOLEAN = getTypeOf(true);
|
|
11
11
|
const NUMBER = getTypeOf(0);
|
|
12
12
|
const FUNCTION = getTypeOf(getTypeOf);
|
|
13
|
+
const NULL = 'null';
|
|
13
14
|
const LISTENER = 'Listener';
|
|
14
15
|
const RESULT = 'Result';
|
|
15
16
|
const GET = 'get';
|
|
@@ -400,7 +401,7 @@ const useResultSortedRowIds = (
|
|
|
400
401
|
|
|
401
402
|
const getCellOrValueType = (cellOrValue) => {
|
|
402
403
|
if (isNull(cellOrValue)) {
|
|
403
|
-
return
|
|
404
|
+
return NULL;
|
|
404
405
|
}
|
|
405
406
|
const type = getTypeOf(cellOrValue);
|
|
406
407
|
return isTypeStringOrBoolean(type) ||
|
|
@@ -10,6 +10,7 @@ const STRING = getTypeOf(EMPTY_STRING);
|
|
|
10
10
|
const BOOLEAN = getTypeOf(true);
|
|
11
11
|
const NUMBER = getTypeOf(0);
|
|
12
12
|
const FUNCTION = getTypeOf(getTypeOf);
|
|
13
|
+
const NULL = 'null';
|
|
13
14
|
const LISTENER = 'Listener';
|
|
14
15
|
const RESULT = 'Result';
|
|
15
16
|
const GET = 'get';
|
|
@@ -400,7 +401,7 @@ const useResultSortedRowIds = (
|
|
|
400
401
|
|
|
401
402
|
const getCellOrValueType = (cellOrValue) => {
|
|
402
403
|
if (isNull(cellOrValue)) {
|
|
403
|
-
return
|
|
404
|
+
return NULL;
|
|
404
405
|
}
|
|
405
406
|
const type = getTypeOf(cellOrValue);
|
|
406
407
|
return isTypeStringOrBoolean(type) ||
|
|
@@ -44,6 +44,7 @@ const FUNCTION = getTypeOf(getTypeOf);
|
|
|
44
44
|
const TYPE = 'type';
|
|
45
45
|
const DEFAULT = 'default';
|
|
46
46
|
const ALLOW_NULL = 'allowNull';
|
|
47
|
+
const NULL = 'null';
|
|
47
48
|
const LISTENER = 'Listener';
|
|
48
49
|
const RESULT = 'Result';
|
|
49
50
|
const GET = 'get';
|
|
@@ -663,7 +664,7 @@ const createSessionPersister = (store, storageName, onIgnoredError) =>
|
|
|
663
664
|
|
|
664
665
|
const getCellOrValueType = (cellOrValue) => {
|
|
665
666
|
if (isNull(cellOrValue)) {
|
|
666
|
-
return
|
|
667
|
+
return NULL;
|
|
667
668
|
}
|
|
668
669
|
const type = getTypeOf(cellOrValue);
|
|
669
670
|
return isTypeStringOrBoolean(type) ||
|
|
@@ -44,6 +44,7 @@ const FUNCTION = getTypeOf(getTypeOf);
|
|
|
44
44
|
const TYPE = 'type';
|
|
45
45
|
const DEFAULT = 'default';
|
|
46
46
|
const ALLOW_NULL = 'allowNull';
|
|
47
|
+
const NULL = 'null';
|
|
47
48
|
const LISTENER = 'Listener';
|
|
48
49
|
const RESULT = 'Result';
|
|
49
50
|
const GET = 'get';
|
|
@@ -663,7 +664,7 @@ const createSessionPersister = (store, storageName, onIgnoredError) =>
|
|
|
663
664
|
|
|
664
665
|
const getCellOrValueType = (cellOrValue) => {
|
|
665
666
|
if (isNull(cellOrValue)) {
|
|
666
|
-
return
|
|
667
|
+
return NULL;
|
|
667
668
|
}
|
|
668
669
|
const type = getTypeOf(cellOrValue);
|
|
669
670
|
return isTypeStringOrBoolean(type) ||
|
package/with-schemas/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const FUNCTION = getTypeOf(getTypeOf);
|
|
|
7
7
|
const TYPE = 'type';
|
|
8
8
|
const DEFAULT = 'default';
|
|
9
9
|
const ALLOW_NULL = 'allowNull';
|
|
10
|
+
const NULL = 'null';
|
|
10
11
|
const SUM = 'sum';
|
|
11
12
|
const AVG = 'avg';
|
|
12
13
|
const MIN = 'min';
|
|
@@ -94,7 +95,7 @@ const arrayShift = (array) => array.shift();
|
|
|
94
95
|
|
|
95
96
|
const getCellOrValueType = (cellOrValue) => {
|
|
96
97
|
if (isNull(cellOrValue)) {
|
|
97
|
-
return
|
|
98
|
+
return NULL;
|
|
98
99
|
}
|
|
99
100
|
const type = getTypeOf(cellOrValue);
|
|
100
101
|
return isTypeStringOrBoolean(type) ||
|