Shared RouteVN domain model package.
Repo rules and contribution expectations are in GUIDELINES.md.
Schema compatibility maintenance rules are in docs/schema-compatibility.md.
This repo is intended to be the single source of truth for:
- state validation
- command payload validation
- state-aware command preconditions
- command-to-state reduction
It is intentionally not responsible for:
- Insieme transport
- Insieme storage
- partition routing
- actors, tokens, client timestamps
Those stay in the client and server repos.
SCHEMA_VERSION;
validateState({ state });
validatePayload({ type, payload });
validateAgainstState({
state,
command: { type, payload },
});
processCommand({
state,
command: { type, payload },
});SCHEMA_VERSION is the exported schema version constant for persisted command
compatibility.
Validation functions return:
{
valid: true;
}or:
{
valid: false,
error: {
kind: "state" | "payload" | "precondition" | "invariant",
code: "payload_validation_failed",
message: "payload.data.foo is not allowed",
path: "payload.data.foo", // only when available
details: {}, // only when available
},
}processCommand() returns:
{ valid: true, state: nextState }Design rules:
- no classes
- pure functions whenever possible
- command payload shape is validated separately from state-aware preconditions
SCHEMA_VERSIONis the source of truth for persisted command schema versioningSCHEMA_VERSIONmust stay aligned with the minor version frompackage.json- patch releases must not change persisted schema compatibility
bun run test:compatis the required compatibility gate for model changesprocessCommand()is the authoritative state transition- model state should contain project-owned runtime data only
- app-owned metadata like project id, name, and description should stay out of this package
projectmay start empty; fields likeresolutionare optional until the model starts owning them- random ids across RouteVN should use
nanoidwith the RouteVN base58 variant; deterministic derived tokens such as partition hashes are a separate case
src/
index.js
errors.js
helpers.js
model.js
tests/
model-api.test.js
command-direct-coverage.test.js
project.create.spec.yaml
story-and-scenes.spec.yaml
scenes-advanced.spec.yaml
sections-and-lines.spec.yaml
images.spec.yaml
sounds-and-videos.spec.yaml
animations.spec.yaml
fonts-and-colors.spec.yaml
transforms-variables-textstyles.spec.yaml
characters-and-layouts.spec.yaml
state-validation.spec.yaml
animations-drift.test.js
command-sequences.test.js
Current RouteVN files:
src/internal/project/commands.jssrc/internal/project/state.js
should map into this package like this:
src/errors.js- internal domain error factories
src/helpers.js- tiny pure shared helpers
src/model.js- state validation
- invariants
- command definitions
- payload validation
- state-aware validation
- reduction
src/index.js- public exports only
projection.js should stay in the app repos for now. It is downstream of the
domain model and is still tied to current app/repository needs.
Client:
- validate payload before submit when useful
- optionally run
processCommand()for optimistic apply - send to Insieme transport
Server:
- validate payload at submit boundary
- validate against current state before commit
- commit event to storage
- use
processCommand()for authoritative projection
This repo uses Bun + Vitest + Puty.
- runner:
bunx vitest run - package script:
bun run test - benchmark script:
bun run bench - YAML specs live in
tests/**/*.spec.yaml - JS sequence tests live in
tests/**/*.test.js
There are 2 test styles:
-
Command contract specs
- treat commands as pure functions
- validate one call at a time
- assert exact input/output or expected invalid result
- include a direct command coverage matrix for the full public registry
- examples:
-
Command sequence tests
- apply a sequence of commands
- assert the full state after each step
- also assert the previous state was not mutated
- use these for reducer flows that are easier to reason about as a tape
- example:
YAML Puty specs use tests/support/putyApi.js as a
small adapter so the declarative throws: assertions can stay concise while the
real public API returns { valid: ... } result objects.
Compatibility fixtures live under tests/compat/schema-<n>/.
payloads/fixtures are frozen command payload shapes for that schema versionstates/fixtures are frozen persisted-state snapshots for that schema versionstreams/fixtures are frozen command sequences for that schema version- current tests must continue to validate/replay every archived compatibility fixture from the same or older schema versions
- current schema payload coverage must include
minimal.yamlandfull.yamlfor every public command type
See also:
Current animation update tween properties support either:
keyframesauto: { duration, easing }
Currently implemented command types:
project.createstory.updatescene.createscene.updatescene.deletescene.movesection.createsection.updatesection.deletesection.moveline.createline.update_actionsline.deleteline.moveimage.createimage.updateimage.deleteimage.movespritesheet.createspritesheet.updatespritesheet.deletespritesheet.movesound.createsound.updatesound.deletesound.movevideo.createvideo.updatevideo.deletevideo.moveanimation.createanimation.updateanimation.deleteanimation.movefont.createfont.updatefont.deletefont.movecolor.createcolor.updatecolor.deletecolor.movetransform.createtransform.updatetransform.deletetransform.movevariable.createvariable.updatevariable.deletevariable.movetextStyle.createtextStyle.updatetextStyle.deletetextStyle.movecharacter.createcharacter.updatecharacter.deletecharacter.movelayout.createlayout.updatelayout.deletelayout.movecharacter.sprite.createcharacter.sprite.updatecharacter.sprite.deletecharacter.sprite.movelayout.element.createlayout.element.updatelayout.element.deletelayout.element.movecontrol.createcontrol.updatecontrol.deletecontrol.movecontrol.element.createcontrol.element.updatecontrol.element.deletecontrol.element.move
The rest of the future command surface should be added only when full validation, preconditions, reducer behavior, and tests are added together.