tinybase 7.0.1 → 7.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The schematizers module provides utilities for converting schemas from
3
+ * popular validation libraries into TinyBase's schema format.
4
+ *
5
+ * Schematizers perform "best-effort" conversion, extracting basic type
6
+ * information (string, number, boolean) and default values while discarding
7
+ * complex validation rules that TinyBase doesn't support.
8
+ * @packageDocumentation
9
+ * @module schematizers
10
+ * @since v7.1.0
11
+ */
12
+ import type {TablesSchema, ValuesSchema} from '../store/index.d.ts';
13
+
14
+ /**
15
+ * The Schematizer interface represents a schema converter that can transform
16
+ * external validation library schemas into TinyBase TablesSchema and
17
+ * ValuesSchema formats.
18
+ * @category Schematizer
19
+ * @since v7.1.0
20
+ */
21
+ export interface Schematizer {
22
+ /**
23
+ * The toTablesSchema method converts a mapping of external schemas into a
24
+ * TinyBase TablesSchema.
25
+ * @param schemas - A mapping of table IDs to external schema objects.
26
+ * @returns A TinyBase TablesSchema.
27
+ * @category Conversion
28
+ * @since v7.1.0
29
+ */
30
+ toTablesSchema(schemas: any): TablesSchema;
31
+
32
+ /**
33
+ * The toValuesSchema method converts a mapping of external schemas into a
34
+ * TinyBase ValuesSchema.
35
+ * @param schemas - A mapping of value IDs to external schema objects.
36
+ * @returns A TinyBase ValuesSchema.
37
+ * @category Conversion
38
+ * @since v7.1.0
39
+ */
40
+ toValuesSchema(schemas: any): ValuesSchema;
41
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The schematizer-zod module provides conversion utilities for Zod schemas.
3
+ * @packageDocumentation
4
+ * @module schematizer-zod
5
+ * @since v7.1.0
6
+ */
7
+ import type {TablesSchema, ValuesSchema} from '../../store/index.d.ts';
8
+ import type {Schematizer} from '../index.d.ts';
9
+
10
+ /**
11
+ * The ZodSchematizer interface represents a schematizer specifically for
12
+ * converting Zod schemas into TinyBase schemas.
13
+ * @category Schematizer
14
+ * @since v7.1.0
15
+ */
16
+ export interface ZodSchematizer extends Schematizer {
17
+ /**
18
+ * The toTablesSchema method converts a mapping of Zod object schemas into a
19
+ * TinyBase TablesSchema.
20
+ *
21
+ * This method extracts basic type information (string, number, boolean),
22
+ * default values, and nullable flags from Zod schemas. Complex validation
23
+ * rules like min/max, regex patterns, refinements, and transforms are ignored.
24
+ * @param schemas - A mapping of table IDs to Zod object schemas.
25
+ * @returns A TinyBase TablesSchema.
26
+ * @example
27
+ * This example converts Zod schemas to TinyBase format.
28
+ *
29
+ * ```js
30
+ * import {createStore} from 'tinybase';
31
+ * import {createZodSchematizer} from 'tinybase/schematizers/schematizer-zod';
32
+ * import {z} from 'zod';
33
+ *
34
+ * const schematizer = createZodSchematizer();
35
+ *
36
+ * const tablesSchema = schematizer.toTablesSchema({
37
+ * pets: z.object({
38
+ * species: z.string(),
39
+ * age: z.number(),
40
+ * sold: z.boolean().default(false),
41
+ * }),
42
+ * });
43
+ *
44
+ * const store = createStore().setTablesSchema(tablesSchema);
45
+ * store.setRow('pets', 'fido', {species: 'dog', age: 3});
46
+ * console.log(store.getRow('pets', 'fido'));
47
+ * // -> {species: 'dog', age: 3, sold: false}
48
+ * ```
49
+ * @category Conversion
50
+ * @since v7.1.0
51
+ */
52
+ toTablesSchema(schemas: {[tableId: string]: any}): TablesSchema;
53
+
54
+ /**
55
+ * The toValuesSchema method converts a mapping of Zod schemas into a TinyBase
56
+ * ValuesSchema.
57
+ *
58
+ * This method extracts basic type information and default values from Zod
59
+ * schemas.
60
+ * @param schemas - A mapping of value IDs to Zod schemas.
61
+ * @returns A TinyBase ValuesSchema.
62
+ * @example
63
+ * This example converts Zod value schemas.
64
+ *
65
+ * ```js
66
+ * import {createStore} from 'tinybase';
67
+ * import {createZodSchematizer} from 'tinybase/schematizers/schematizer-zod';
68
+ * import {z} from 'zod';
69
+ *
70
+ * const schematizer = createZodSchematizer();
71
+ *
72
+ * const valuesSchema = schematizer.toValuesSchema({
73
+ * theme: z.string().default('light'),
74
+ * count: z.number(),
75
+ * });
76
+ *
77
+ * const store = createStore().setValuesSchema(valuesSchema);
78
+ * console.log(store.getValues());
79
+ * // -> {theme: 'light'}
80
+ * ```
81
+ * @category Conversion
82
+ * @since v7.1.0
83
+ */
84
+ toValuesSchema(schemas: {[valueId: string]: any}): ValuesSchema;
85
+ }
86
+
87
+ /**
88
+ * The createZodSchematizer function creates a ZodSchematizer object that can
89
+ * convert Zod schemas into TinyBase schemas.
90
+ *
91
+ * The schematizer is stateless and can be reused for multiple conversions.
92
+ * @returns A new ZodSchematizer instance.
93
+ * @example
94
+ * This example creates a Zod schematizer and uses it to convert schemas.
95
+ *
96
+ * ```js
97
+ * import {createZodSchematizer} from 'tinybase/schematizers/schematizer-zod';
98
+ * import {z} from 'zod';
99
+ *
100
+ * const schematizer = createZodSchematizer();
101
+ *
102
+ * const tablesSchema = schematizer.toTablesSchema({
103
+ * pets: z.object({
104
+ * species: z.string(),
105
+ * }),
106
+ * });
107
+ * console.log(tablesSchema);
108
+ * // -> {pets: {species: {type: 'string'}}}
109
+ * ```
110
+ * @category Creation
111
+ * @since v7.1.0
112
+ */
113
+ export function createZodSchematizer(): ZodSchematizer;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The schematizer-zod module provides conversion utilities for Zod schemas.
3
+ * @packageDocumentation
4
+ * @module schematizer-zod
5
+ * @since v7.1.0
6
+ */
7
+ export type {
8
+ ZodSchematizer,
9
+ createZodSchematizer,
10
+ } from '../../schematizer-zod/index.d.ts';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The schematizers module provides utilities for converting schemas from
3
+ * popular validation libraries into TinyBase's schema format.
4
+ *
5
+ * Schematizers perform "best-effort" conversion, extracting basic type
6
+ * information (string, number, boolean) and default values while discarding
7
+ * complex validation rules that TinyBase doesn't support.
8
+ * @packageDocumentation
9
+ * @module schematizers
10
+ * @since v7.1.0
11
+ */
12
+ export type {Schematizer} from '../index.d.ts';
package/agents.md CHANGED
@@ -341,3 +341,147 @@ npx vitest run ./test/unit/documentation.test.ts --retry=0
341
341
  2. **Guide Content**: Edit markdown files in `/site/guides/`
342
342
  3. **Release Notes**: Edit `/site/guides/16_releases.md` (not `/releases.md`)
343
343
  4. **Always run documentation tests** after changes to verify examples work
344
+
345
+ ## Creating New Schematizers
346
+
347
+ Schematizers convert external schema validation libraries (like Zod) to TinyBase
348
+ schemas. Follow this pattern:
349
+
350
+ ### Module Structure
351
+
352
+ ```
353
+ src/@types/schematizers/schematizer-{library}/
354
+ index.d.ts # Type definitions
355
+ docs.js # Documentation
356
+ with-schemas/
357
+ index.d.ts # Re-exports for schema-aware variants
358
+ src/schematizers/schematizer-{library}/
359
+ index.ts # Implementation
360
+ ```
361
+
362
+ ### Factory Pattern
363
+
364
+ ```typescript
365
+ export const createZodSchematizer: typeof createZodSchematizerDecl = () => {
366
+ const toTablesSchema = (schemas: {[tableId: string]: any}): TablesSchema => {
367
+ // Best-effort conversion logic
368
+ };
369
+
370
+ const toValuesSchema = (schemas: {[valueId: string]: any}): ValuesSchema => {
371
+ // Best-effort conversion logic
372
+ };
373
+
374
+ return objFreeze({
375
+ toTablesSchema,
376
+ toValuesSchema,
377
+ });
378
+ };
379
+ ```
380
+
381
+ ### Conversion Strategy
382
+
383
+ - Extract basic types only: `string`, `number`, `boolean`
384
+ - Handle defaults via schema introspection
385
+ - Support nullable and optional modifiers
386
+ - **Ignore** complex types (arrays, objects, etc.) - they won't appear in output
387
+ - Use recursive unwrapping for wrapper types (e.g., `ZodOptional`, `ZodNullable`,
388
+ `ZodDefault`)
389
+
390
+ ### Implementation Idioms
391
+
392
+ - Use `objForEach` for iteration, not `for...in` loops
393
+ - Use `ifNotUndefined` for conditional logic
394
+ - Use `objIsEmpty` to filter out empty table schemas
395
+ - Extract string constants to module-level (e.g., `TYPE`, `DEFAULT`,
396
+ `ALLOW_NULL`)
397
+ - Freeze the returned schematizer object with `objFreeze`
398
+
399
+ ### Example Conversion Logic
400
+
401
+ ```typescript
402
+ const unwrap = (
403
+ schema: any,
404
+ defaultValue?: any,
405
+ allowNull?: boolean,
406
+ ): [any, any, boolean] => {
407
+ const typeName = schema._def?.typeName;
408
+ return typeName === ZOD_OPTIONAL
409
+ ? unwrap(schema._def.innerType, defaultValue, allowNull)
410
+ : typeName === ZOD_NULLABLE
411
+ ? unwrap(schema._def.innerType, defaultValue, true)
412
+ : typeName === ZOD_DEFAULT
413
+ ? unwrap(schema._def.innerType, schema._def.defaultValue(), allowNull)
414
+ : [schema, defaultValue, allowNull ?? false];
415
+ };
416
+ ```
417
+
418
+ ### Build Configuration
419
+
420
+ - Add module to `ALL_MODULES` array in `gulpfile.mjs`
421
+ - Add peer dependency to `package.json` (marked as optional)
422
+ - Add as dev dependency for testing
423
+
424
+ ### Testing
425
+
426
+ - Create comprehensive test suite in
427
+ `test/unit/schematizers/schematizer-{library}.test.ts`
428
+ - Test basic type conversion, defaults, nullable, optional
429
+ - Test unsupported types are filtered out
430
+ - Test integration with actual TinyBase stores
431
+ - Inline schemas directly in test calls (no intermediate variables unless needed
432
+ multiple times)
433
+
434
+ ### Documentation Testing
435
+
436
+ Add library import to `test/unit/documentation.test.ts`:
437
+
438
+ ```typescript
439
+ import * as z from 'zod';
440
+ import * as TinyBaseSchematizersZod from 'tinybase/schematizers/schematizer-zod';
441
+
442
+ (globalThis as any).modules = {
443
+ ...
444
+ 'tinybase/schematizers/schematizer-zod': TinyBaseSchematizersZod,
445
+ zod: z,
446
+ };
447
+ ```
448
+
449
+ ## Guide Writing Best Practices
450
+
451
+ ### Examples Run Sequentially
452
+
453
+ All code examples in a guide file are concatenated and executed as a test:
454
+
455
+ - Use unique variable names (`store`, `store2`, `store3`) to avoid redeclaration
456
+ - First example includes all imports, later examples reuse them
457
+ - Clean up between examples if needed (`store.delTables()`)
458
+
459
+ ### Inline Simple Values
460
+
461
+ - Prefer inline schemas/data in method calls over intermediate variables
462
+ - Only extract to variables when used multiple times
463
+ - Keeps examples concise and focused
464
+
465
+ ### Guide Chains
466
+
467
+ - Each guide's summary should link to the next guide in sequence
468
+ - Pattern: "For that we proceed to the [Next Topic] guide."
469
+ - Creates a natural learning path
470
+
471
+ ## Release Notes Updates
472
+
473
+ When adding a new feature:
474
+
475
+ 1. **Update `/site/guides/16_releases.md`** (NOT `/releases.md`):
476
+ - Add new version section at the top
477
+ - Include working code example that will be tested
478
+ - Link to relevant guide if applicable
479
+ - Use past releases as template for structure
480
+
481
+ 2. **Update `/site/home/index.md`**:
482
+ - Update the "NEW!" link to point to new version:
483
+ `<a href='/guides/releases/#v7-1'>`
484
+ - Update the tagline:
485
+ `<span id="one-with">"The one with Schematizers!"</span>`
486
+
487
+ 3. **Generated files update automatically** during build process
@@ -0,0 +1 @@
1
+
Binary file
@@ -0,0 +1 @@
1
+ const e=e=>typeof e,t=e(""),n=e(!0),r=e(0),o="type",l="default",f=e=>(t,n,r)=>e(t)?r?.():n(t),s=e=>null==e,a=f(s),p=f(e=>void 0===e),u=Object,c=e=>u.getPrototypeOf(e),y=u.entries,d=u.keys,i=u.freeze,h=(e=[])=>u.fromEntries(e),T=(e,t)=>((e,t)=>e.forEach(t))(y(e),([e,n])=>t(n,e)),b=(e,t,n)=>{const r=e?.def?.type;return"optional"===r?b(e.def.innerType,t,n):"nullable"===r?b(e.def.innerType,t,!0):r===l?b(e.def.innerType,e.def.defaultValue,n):[e,t,n??!1]},m=()=>{const e=e=>{const[f,s,a]=b(e),u=f?.type;if(u!==t&&u!==r&&u!==n)return;const c={[o]:u};return p(s,e=>{c[l]=e}),a&&(c.allowNull=!0),c};return i({toTablesSchema:t=>{const n=h();return T(t,(t,r)=>{const o=h();var l;p(t?.def?.shape,t=>T(t,(t,n)=>p(e(t),e=>{o[n]=e}))),(e=>!s(e)&&a(c(e),e=>e==u.prototype||s(c(e)),()=>!0))(l=o)&&0==(e=>d(e).length)(l)||(n[r]=o)}),n},toValuesSchema:t=>{const n=h();return T(t,(t,r)=>p(e(t),e=>{n[r]=e})),n}})};export{m as createZodSchematizer};
@@ -0,0 +1 @@
1
+ const e=e=>typeof e,t=e(""),n=e(!0),r=e(0),o="type",l="default",f=e=>(t,n,r)=>e(t)?r?.():n(t),s=e=>null==e,a=f(s),p=f(e=>void 0===e),u=Object,c=e=>u.getPrototypeOf(e),y=u.entries,d=u.keys,i=u.freeze,h=(e=[])=>u.fromEntries(e),T=(e,t)=>((e,t)=>e.forEach(t))(y(e),([e,n])=>t(n,e)),b=(e,t,n)=>{const r=e?.def?.type;return"optional"===r?b(e.def.innerType,t,n):"nullable"===r?b(e.def.innerType,t,!0):r===l?b(e.def.innerType,e.def.defaultValue,n):[e,t,n??!1]},m=()=>{const e=e=>{const[f,s,a]=b(e),u=f?.type;if(u!==t&&u!==r&&u!==n)return;const c={[o]:u};return p(s,e=>{c[l]=e}),a&&(c.allowNull=!0),c};return i({toTablesSchema:t=>{const n=h();return T(t,(t,r)=>{const o=h();var l;p(t?.def?.shape,t=>T(t,(t,n)=>p(e(t),e=>{o[n]=e}))),(e=>!s(e)&&a(c(e),e=>e==u.prototype||s(c(e)),()=>!0))(l=o)&&0==(e=>d(e).length)(l)||(n[r]=o)}),n},toValuesSchema:t=>{const n=h();return T(t,(t,r)=>p(e(t),e=>{n[r]=e})),n}})};export{m as createZodSchematizer};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tinybase",
3
- "version": "7.0.1",
3
+ "version": "7.1.0-beta.1",
4
4
  "author": "jamesgpearce",
5
5
  "repository": "github:tinyplex/tinybase",
6
6
  "license": "MIT",
@@ -41,7 +41,8 @@
41
41
  "react-native-sqlite-storage": "^6.0.1",
42
42
  "sqlite3": "^5.1.7",
43
43
  "ws": "^8.18.3",
44
- "yjs": "^13.6.27"
44
+ "yjs": "^13.6.27",
45
+ "zod": "^4.1.13"
45
46
  },
46
47
  "peerDependenciesMeta": {
47
48
  "@automerge/automerge-repo": {
@@ -106,6 +107,9 @@
106
107
  },
107
108
  "yjs": {
108
109
  "optional": true
110
+ },
111
+ "zod": {
112
+ "optional": true
109
113
  }
110
114
  },
111
115
  "main": "./index.js",
@@ -304,6 +308,18 @@
304
308
  "relationships/with-schemas": [
305
309
  "./@types/relationships/with-schemas/index.d.ts"
306
310
  ],
311
+ "schematizers": [
312
+ "./@types/schematizers/index.d.ts"
313
+ ],
314
+ "schematizers/with-schemas": [
315
+ "./@types/schematizers/with-schemas/index.d.ts"
316
+ ],
317
+ "schematizers/schematizer-zod": [
318
+ "./@types/schematizers/schematizer-zod/index.d.ts"
319
+ ],
320
+ "schematizers/schematizer-zod/with-schemas": [
321
+ "./@types/schematizers/schematizer-zod/with-schemas/index.d.ts"
322
+ ],
307
323
  "store": [
308
324
  "./@types/store/index.d.ts"
309
325
  ],
@@ -562,6 +578,18 @@
562
578
  "min/relationships/with-schemas": [
563
579
  "./@types/relationships/with-schemas/index.d.ts"
564
580
  ],
581
+ "min/schematizers": [
582
+ "./@types/schematizers/index.d.ts"
583
+ ],
584
+ "min/schematizers/with-schemas": [
585
+ "./@types/schematizers/with-schemas/index.d.ts"
586
+ ],
587
+ "min/schematizers/schematizer-zod": [
588
+ "./@types/schematizers/schematizer-zod/index.d.ts"
589
+ ],
590
+ "min/schematizers/schematizer-zod/with-schemas": [
591
+ "./@types/schematizers/schematizer-zod/with-schemas/index.d.ts"
592
+ ],
565
593
  "min/store": [
566
594
  "./@types/store/index.d.ts"
567
595
  ],
@@ -1015,6 +1043,30 @@
1015
1043
  "default": "./relationships/index.js"
1016
1044
  }
1017
1045
  },
1046
+ "./schematizers": {
1047
+ "default": {
1048
+ "types": "./@types/schematizers/index.d.ts",
1049
+ "default": "./schematizers/index.js"
1050
+ }
1051
+ },
1052
+ "./schematizers/with-schemas": {
1053
+ "default": {
1054
+ "types": "./@types/schematizers/with-schemas/index.d.ts",
1055
+ "default": "./schematizers/index.js"
1056
+ }
1057
+ },
1058
+ "./schematizers/schematizer-zod": {
1059
+ "default": {
1060
+ "types": "./@types/schematizers/schematizer-zod/index.d.ts",
1061
+ "default": "./schematizers/schematizer-zod/index.js"
1062
+ }
1063
+ },
1064
+ "./schematizers/schematizer-zod/with-schemas": {
1065
+ "default": {
1066
+ "types": "./@types/schematizers/schematizer-zod/with-schemas/index.d.ts",
1067
+ "default": "./schematizers/schematizer-zod/index.js"
1068
+ }
1069
+ },
1018
1070
  "./store": {
1019
1071
  "default": {
1020
1072
  "types": "./@types/store/index.d.ts",
@@ -1531,6 +1583,30 @@
1531
1583
  "default": "./min/relationships/index.js"
1532
1584
  }
1533
1585
  },
1586
+ "./min/schematizers": {
1587
+ "default": {
1588
+ "types": "./@types/schematizers/index.d.ts",
1589
+ "default": "./min/schematizers/index.js"
1590
+ }
1591
+ },
1592
+ "./min/schematizers/with-schemas": {
1593
+ "default": {
1594
+ "types": "./@types/schematizers/with-schemas/index.d.ts",
1595
+ "default": "./min/schematizers/index.js"
1596
+ }
1597
+ },
1598
+ "./min/schematizers/schematizer-zod": {
1599
+ "default": {
1600
+ "types": "./@types/schematizers/schematizer-zod/index.d.ts",
1601
+ "default": "./min/schematizers/schematizer-zod/index.js"
1602
+ }
1603
+ },
1604
+ "./min/schematizers/schematizer-zod/with-schemas": {
1605
+ "default": {
1606
+ "types": "./@types/schematizers/schematizer-zod/with-schemas/index.d.ts",
1607
+ "default": "./min/schematizers/schematizer-zod/index.js"
1608
+ }
1609
+ },
1534
1610
  "./min/store": {
1535
1611
  "default": {
1536
1612
  "types": "./@types/store/index.d.ts",