The Cell is the base class for schema-driven data models in Zzz. The goals are still evolving, but a main idea is to have fully reactive state that can be flexibly snapshotted and reinstantiated in a typesafe, extensible system that uses normal Svelte patterns.
The design aims for:
- Integration with Svelte's reactivity, encouraging single-depth inheritance with Svelte class patterns for both persistent and ephemeral state - Schema-driven parsing/validation and JSON serialization/deserialization (supporting snapshot and restore/replay patterns) via Zod - Custom property encoding/decoding for complex types, and no boilerplate for schema-inferrable properties - Lifecycle management with generic instantiation/registration and disposal (conceptually a WIP, partially implemented) - Runtime type metadata for reflection
Cells are automatically registered in the global registry by id,
making them discoverable and referenceable throughout the system.
Each cell has common properties including id and created/updated timestamps.
There are currently a lot of rough edges and missing features! My hope is that this could be generic enough to extract to a library, but it's not there yet. I assume there's a really nice design in this space that takes full advantage of Svelte runes.
Many things will be possible with this pattern, but it's still a work in progress.
generics
TSchema
z.ZodTypez.ZodTypeinheritance
cid
id
type Uuid
created
type Datetime
updated
type Datetime
schema
type TSchema
schema_keys
type Array<SchemaKeys<TSchema>>
field_schemas
type Map<SchemaKeys<TSchema>, z.ZodType>
field_schema_info
type Map<SchemaKeys<TSchema>, SchemaClassInfo | null>
json
type z.output<TSchema>
json_serialized
type string
json_parsed
type z.ZodSafeParseResult<z.output<TSchema>>
app
type Frontend
decoders
Type-safe decoders for custom field decoding. Override in subclasses to handle special field types.
Each decoder function takes a value of any type and should either: 1. Return a value (including null) to be assigned to the property 2. Return undefined to use the default decoding behavior 3. Return HANDLED to indicate the decoder has fully processed the property (virtual properties MUST return HANDLED if they exist in schema but not in class)
type CellValueDecoder<TSchema>
created_date
type Date
created_formatted_short_date
type string
created_formatted_datetime
type string
created_formatted_time
type string
updated_date
type Date
updated_formatted_short_date
type string
updated_formatted_datetime
type string
updated_formatted_time
type string
constructor
type new <TSchema extends z.ZodType = ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>>(schema: TSchema, options: CellOptions<TSchema>): Cell<TSchema>
schema
TSchemaoptions
CellOptions<TSchema>init
Initialize the instance with options.json data if provided.
Must be called before using the instance -
the current pattern is calling it at the end of subclass constructors.
We should investigate deferring to callers so e.g. instantiating from the registry would init automatically, subclasses need no init logic (which can get unwieldy with inheritance), and then callers could always do custom init patterns if they wanted.
Can't be called automatically by the Cell's constructor because the subclass' constructor needs to run first to support field initialization. A design goal behind the Cell is to support normal TS and Svelte patterns with the most power and least intrusion. (there's a balance to find from Zzz's POV)
type (): void
voiddispose
Clean up resources when this cell is no longer needed.
type (): void
void[Symbol.dispose]
This is not supported in Safari, don't rely on this yet. Uncomment temporarily to experiment in dev.
type (): void
voidregister
Register this cell in the global cell registry. Called automatically by init().
type (): void
voidunregister
Unregister this cell from the global cell registry. Called automatically by dispose().
type (): void
voidtoJSON
For Svelte's $snapshot.
type (): output<TSchema>
output<TSchema>to_json
Encodes the cell's serializable state as JSON.
Use the derived cell.json if you don't need a fresh copy.
type (): output<TSchema>
output<TSchema>set_json
Apply JSON data to this instance.
Overwrites all properties including 'id'.
Special-cases created and updated for synchronization.
type (value: input<TSchema> | undefined): void
value
input<TSchema> | undefinedvoidset_json_partial
Update only the specified properties on this instance. Preserves current values for any properties not included in the input.
type (partial_value: Partial<input<TSchema>>): void
partial_value
Partial<input<TSchema>>voidencode_property
Encode a value during serialization. Can be overridden for custom encoding logic.
Defaults to Svelte's $state.snapshot,
which handles most cases and uses toJSON when available,
so overriding to_json is sufficient for most cases before overriding encode.
type (value: unknown, _key: string): unknown
value
unknown_key
stringunknowndecode_property
Decode a value based on its schema type information. This handles instantiating classes, transforming arrays, and special types.
Complex property types might require custom handling in parser functions rather than using this general decoding mechanism.
type <K extends SchemaKeys<TSchema>>(value: unknown, key: K): any
value
unknownkey
Kanyassign_property
Process a single schema property during JSON deserialization. This method handles the workflow for mapping schema properties to instance properties.
Flow: 1. If a decoder exists for this property, try to use it 2. If decoder returns HANDLED, consider the property fully handled (short circuit) 3. If decoder returns a value other than HANDLED or undefined, use that value 4. If decoder returns undefined, fall through to standard decoding 5. For properties not directly represented in the class instance but defined in the schema, the decoder MUST return HANDLED to indicate proper handling
type (key: SchemaKeys<TSchema>, value: unknown): void
key
SchemaKeys<TSchema>value
unknownvoidclone
Generic clone method that works for any subclass.
type (json?: input<TSchema> | undefined, options?: CellOptions<TSchema> | undefined): this
json?
input<TSchema> | undefinedoptions?
CellOptions<TSchema> | undefinedthis