mythik 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +4 -0
- package/README.md +97 -2
- package/dist/actions/dispatcher.d.ts +46 -0
- package/dist/actions/dispatcher.d.ts.map +1 -0
- package/dist/actions/dispatcher.js +366 -0
- package/dist/actions/dispatcher.js.map +1 -0
- package/dist/actions/middleware.d.ts +27 -0
- package/dist/actions/middleware.d.ts.map +1 -0
- package/dist/actions/middleware.js +37 -0
- package/dist/actions/middleware.js.map +1 -0
- package/dist/actions/transaction-engine.d.ts +13 -0
- package/dist/actions/transaction-engine.d.ts.map +1 -0
- package/dist/actions/transaction-engine.js +96 -0
- package/dist/actions/transaction-engine.js.map +1 -0
- package/dist/app/app-engine.d.ts +106 -0
- package/dist/app/app-engine.d.ts.map +1 -0
- package/dist/app/app-engine.js +413 -0
- package/dist/app/app-engine.js.map +1 -0
- package/dist/auth/cross-tab.d.ts +24 -0
- package/dist/auth/cross-tab.d.ts.map +1 -0
- package/dist/auth/cross-tab.js +117 -0
- package/dist/auth/cross-tab.js.map +1 -0
- package/dist/auth/engine.d.ts +16 -0
- package/dist/auth/engine.d.ts.map +1 -0
- package/dist/auth/engine.js +225 -0
- package/dist/auth/engine.js.map +1 -0
- package/dist/auth/persistence.d.ts +21 -0
- package/dist/auth/persistence.d.ts.map +1 -0
- package/dist/auth/persistence.js +97 -0
- package/dist/auth/persistence.js.map +1 -0
- package/dist/auth/providers/custom-jwt.d.ts +41 -0
- package/dist/auth/providers/custom-jwt.d.ts.map +1 -0
- package/dist/auth/providers/custom-jwt.js +165 -0
- package/dist/auth/providers/custom-jwt.js.map +1 -0
- package/dist/auth/providers/mock.d.ts +7 -0
- package/dist/auth/providers/mock.d.ts.map +1 -0
- package/dist/auth/providers/mock.js +52 -0
- package/dist/auth/providers/mock.js.map +1 -0
- package/dist/auth/providers/supabase.d.ts +90 -0
- package/dist/auth/providers/supabase.d.ts.map +1 -0
- package/dist/auth/providers/supabase.js +102 -0
- package/dist/auth/providers/supabase.js.map +1 -0
- package/dist/auth/rate-limiter.d.ts +29 -0
- package/dist/auth/rate-limiter.d.ts.map +1 -0
- package/dist/auth/rate-limiter.js +67 -0
- package/dist/auth/rate-limiter.js.map +1 -0
- package/dist/auth/refresh-engine.d.ts +25 -0
- package/dist/auth/refresh-engine.d.ts.map +1 -0
- package/dist/auth/refresh-engine.js +59 -0
- package/dist/auth/refresh-engine.js.map +1 -0
- package/dist/auth/types.d.ts +89 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +2 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/contract/endpoint-map.d.ts +20 -0
- package/dist/contract/endpoint-map.d.ts.map +1 -0
- package/dist/contract/endpoint-map.js +57 -0
- package/dist/contract/endpoint-map.js.map +1 -0
- package/dist/contract/engine.d.ts +12 -0
- package/dist/contract/engine.d.ts.map +1 -0
- package/dist/contract/engine.js +80 -0
- package/dist/contract/engine.js.map +1 -0
- package/dist/contract/extractor.d.ts +7 -0
- package/dist/contract/extractor.d.ts.map +1 -0
- package/dist/contract/extractor.js +133 -0
- package/dist/contract/extractor.js.map +1 -0
- package/dist/contract/index.d.ts +4 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +2 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/contract/matcher.d.ts +13 -0
- package/dist/contract/matcher.d.ts.map +1 -0
- package/dist/contract/matcher.js +57 -0
- package/dist/contract/matcher.js.map +1 -0
- package/dist/contract/rules/endpoints-exist.d.ts +3 -0
- package/dist/contract/rules/endpoints-exist.d.ts.map +1 -0
- package/dist/contract/rules/endpoints-exist.js +29 -0
- package/dist/contract/rules/endpoints-exist.js.map +1 -0
- package/dist/contract/rules/fields-valid.d.ts +3 -0
- package/dist/contract/rules/fields-valid.d.ts.map +1 -0
- package/dist/contract/rules/fields-valid.js +39 -0
- package/dist/contract/rules/fields-valid.js.map +1 -0
- package/dist/contract/rules/params-match.d.ts +3 -0
- package/dist/contract/rules/params-match.d.ts.map +1 -0
- package/dist/contract/rules/params-match.js +40 -0
- package/dist/contract/rules/params-match.js.map +1 -0
- package/dist/contract/rules/permissions-consistent.d.ts +3 -0
- package/dist/contract/rules/permissions-consistent.d.ts.map +1 -0
- package/dist/contract/rules/permissions-consistent.js +52 -0
- package/dist/contract/rules/permissions-consistent.js.map +1 -0
- package/dist/contract/types.d.ts +66 -0
- package/dist/contract/types.d.ts.map +1 -0
- package/dist/contract/types.js +2 -0
- package/dist/contract/types.js.map +1 -0
- package/dist/data/data-sources.d.ts +26 -0
- package/dist/data/data-sources.d.ts.map +1 -0
- package/dist/data/data-sources.js +218 -0
- package/dist/data/data-sources.js.map +1 -0
- package/dist/data/fetch.d.ts +29 -0
- package/dist/data/fetch.d.ts.map +1 -0
- package/dist/data/fetch.js +63 -0
- package/dist/data/fetch.js.map +1 -0
- package/dist/data/offline.d.ts +29 -0
- package/dist/data/offline.d.ts.map +1 -0
- package/dist/data/offline.js +48 -0
- package/dist/data/offline.js.map +1 -0
- package/dist/data/realtime.d.ts +21 -0
- package/dist/data/realtime.d.ts.map +1 -0
- package/dist/data/realtime.js +40 -0
- package/dist/data/realtime.js.map +1 -0
- package/dist/derive/evaluator.d.ts +19 -0
- package/dist/derive/evaluator.d.ts.map +1 -0
- package/dist/derive/evaluator.js +59 -0
- package/dist/derive/evaluator.js.map +1 -0
- package/dist/derive/topo-sort.d.ts +10 -0
- package/dist/derive/topo-sort.d.ts.map +1 -0
- package/dist/derive/topo-sort.js +36 -0
- package/dist/derive/topo-sort.js.map +1 -0
- package/dist/design/animation/cascade-types.d.ts +23 -0
- package/dist/design/animation/cascade-types.d.ts.map +1 -0
- package/dist/design/animation/cascade-types.js +2 -0
- package/dist/design/animation/cascade-types.js.map +1 -0
- package/dist/design/animation/cascade.d.ts +4 -0
- package/dist/design/animation/cascade.d.ts.map +1 -0
- package/dist/design/animation/cascade.js +73 -0
- package/dist/design/animation/cascade.js.map +1 -0
- package/dist/design/animation/css-keyframes.d.ts +8 -0
- package/dist/design/animation/css-keyframes.d.ts.map +1 -0
- package/dist/design/animation/css-keyframes.js +72 -0
- package/dist/design/animation/css-keyframes.js.map +1 -0
- package/dist/design/animation/index.d.ts +14 -0
- package/dist/design/animation/index.d.ts.map +1 -0
- package/dist/design/animation/index.js +9 -0
- package/dist/design/animation/index.js.map +1 -0
- package/dist/design/animation/keyframes-builder.d.ts +40 -0
- package/dist/design/animation/keyframes-builder.d.ts.map +1 -0
- package/dist/design/animation/keyframes-builder.js +140 -0
- package/dist/design/animation/keyframes-builder.js.map +1 -0
- package/dist/design/animation/reanimated-spec.d.ts +16 -0
- package/dist/design/animation/reanimated-spec.d.ts.map +1 -0
- package/dist/design/animation/reanimated-spec.js +162 -0
- package/dist/design/animation/reanimated-spec.js.map +1 -0
- package/dist/design/animation/reduced-motion.d.ts +3 -0
- package/dist/design/animation/reduced-motion.d.ts.map +1 -0
- package/dist/design/animation/reduced-motion.js +54 -0
- package/dist/design/animation/reduced-motion.js.map +1 -0
- package/dist/design/animation/resolver.d.ts +3 -0
- package/dist/design/animation/resolver.d.ts.map +1 -0
- package/dist/design/animation/resolver.js +86 -0
- package/dist/design/animation/resolver.js.map +1 -0
- package/dist/design/animation/types.d.ts +109 -0
- package/dist/design/animation/types.d.ts.map +1 -0
- package/dist/design/animation/types.js +7 -0
- package/dist/design/animation/types.js.map +1 -0
- package/dist/design/animation/validator.d.ts +44 -0
- package/dist/design/animation/validator.d.ts.map +1 -0
- package/dist/design/animation/validator.js +169 -0
- package/dist/design/animation/validator.js.map +1 -0
- package/dist/design/background/blobs/catalog.d.ts +10 -0
- package/dist/design/background/blobs/catalog.d.ts.map +1 -0
- package/dist/design/background/blobs/catalog.js +63 -0
- package/dist/design/background/blobs/catalog.js.map +1 -0
- package/dist/design/background/blobs/index.d.ts +4 -0
- package/dist/design/background/blobs/index.d.ts.map +1 -0
- package/dist/design/background/blobs/index.js +5 -0
- package/dist/design/background/blobs/index.js.map +1 -0
- package/dist/design/background/blobs/resolver.d.ts +16 -0
- package/dist/design/background/blobs/resolver.d.ts.map +1 -0
- package/dist/design/background/blobs/resolver.js +301 -0
- package/dist/design/background/blobs/resolver.js.map +1 -0
- package/dist/design/background/blobs/types.d.ts +112 -0
- package/dist/design/background/blobs/types.d.ts.map +1 -0
- package/dist/design/background/blobs/types.js +27 -0
- package/dist/design/background/blobs/types.js.map +1 -0
- package/dist/design/background/grain.d.ts +3 -0
- package/dist/design/background/grain.d.ts.map +1 -0
- package/dist/design/background/grain.js +23 -0
- package/dist/design/background/grain.js.map +1 -0
- package/dist/design/background/index.d.ts +8 -0
- package/dist/design/background/index.d.ts.map +1 -0
- package/dist/design/background/index.js +8 -0
- package/dist/design/background/index.js.map +1 -0
- package/dist/design/background/layers.d.ts +3 -0
- package/dist/design/background/layers.d.ts.map +1 -0
- package/dist/design/background/layers.js +23 -0
- package/dist/design/background/layers.js.map +1 -0
- package/dist/design/background/patterns/chevron.d.ts +8 -0
- package/dist/design/background/patterns/chevron.d.ts.map +1 -0
- package/dist/design/background/patterns/chevron.js +10 -0
- package/dist/design/background/patterns/chevron.js.map +1 -0
- package/dist/design/background/patterns/crosshatch.d.ts +8 -0
- package/dist/design/background/patterns/crosshatch.d.ts.map +1 -0
- package/dist/design/background/patterns/crosshatch.js +12 -0
- package/dist/design/background/patterns/crosshatch.js.map +1 -0
- package/dist/design/background/patterns/diagonal.d.ts +8 -0
- package/dist/design/background/patterns/diagonal.d.ts.map +1 -0
- package/dist/design/background/patterns/diagonal.js +7 -0
- package/dist/design/background/patterns/diagonal.js.map +1 -0
- package/dist/design/background/patterns/dots.d.ts +7 -0
- package/dist/design/background/patterns/dots.d.ts.map +1 -0
- package/dist/design/background/patterns/dots.js +9 -0
- package/dist/design/background/patterns/dots.js.map +1 -0
- package/dist/design/background/patterns/grid.d.ts +7 -0
- package/dist/design/background/patterns/grid.d.ts.map +1 -0
- package/dist/design/background/patterns/grid.js +8 -0
- package/dist/design/background/patterns/grid.js.map +1 -0
- package/dist/design/background/patterns/index.d.ts +8 -0
- package/dist/design/background/patterns/index.d.ts.map +1 -0
- package/dist/design/background/patterns/index.js +8 -0
- package/dist/design/background/patterns/index.js.map +1 -0
- package/dist/design/background/patterns/iso.d.ts +7 -0
- package/dist/design/background/patterns/iso.d.ts.map +1 -0
- package/dist/design/background/patterns/iso.js +11 -0
- package/dist/design/background/patterns/iso.js.map +1 -0
- package/dist/design/background/patterns/resolver.d.ts +3 -0
- package/dist/design/background/patterns/resolver.d.ts.map +1 -0
- package/dist/design/background/patterns/resolver.js +56 -0
- package/dist/design/background/patterns/resolver.js.map +1 -0
- package/dist/design/background/primitives/gradient.d.ts +3 -0
- package/dist/design/background/primitives/gradient.d.ts.map +1 -0
- package/dist/design/background/primitives/gradient.js +68 -0
- package/dist/design/background/primitives/gradient.js.map +1 -0
- package/dist/design/background/primitives/image.d.ts +3 -0
- package/dist/design/background/primitives/image.d.ts.map +1 -0
- package/dist/design/background/primitives/image.js +12 -0
- package/dist/design/background/primitives/image.js.map +1 -0
- package/dist/design/background/primitives/index.d.ts +4 -0
- package/dist/design/background/primitives/index.d.ts.map +1 -0
- package/dist/design/background/primitives/index.js +4 -0
- package/dist/design/background/primitives/index.js.map +1 -0
- package/dist/design/background/primitives/solid.d.ts +8 -0
- package/dist/design/background/primitives/solid.d.ts.map +1 -0
- package/dist/design/background/primitives/solid.js +15 -0
- package/dist/design/background/primitives/solid.js.map +1 -0
- package/dist/design/background/resolver.d.ts +3 -0
- package/dist/design/background/resolver.d.ts.map +1 -0
- package/dist/design/background/resolver.js +20 -0
- package/dist/design/background/resolver.js.map +1 -0
- package/dist/design/background/sanitizer.d.ts +2 -0
- package/dist/design/background/sanitizer.d.ts.map +1 -0
- package/dist/design/background/sanitizer.js +54 -0
- package/dist/design/background/sanitizer.js.map +1 -0
- package/dist/design/deep-tokens.d.ts +125 -0
- package/dist/design/deep-tokens.d.ts.map +1 -0
- package/dist/design/deep-tokens.js +115 -0
- package/dist/design/deep-tokens.js.map +1 -0
- package/dist/design/dna.d.ts +7 -0
- package/dist/design/dna.d.ts.map +1 -0
- package/dist/design/dna.js +210 -0
- package/dist/design/dna.js.map +1 -0
- package/dist/design/identity/color.d.ts +8 -0
- package/dist/design/identity/color.d.ts.map +1 -0
- package/dist/design/identity/color.js +64 -0
- package/dist/design/identity/color.js.map +1 -0
- package/dist/design/identity/elevation.d.ts +8 -0
- package/dist/design/identity/elevation.d.ts.map +1 -0
- package/dist/design/identity/elevation.js +31 -0
- package/dist/design/identity/elevation.js.map +1 -0
- package/dist/design/identity/index.d.ts +12 -0
- package/dist/design/identity/index.d.ts.map +1 -0
- package/dist/design/identity/index.js +14 -0
- package/dist/design/identity/index.js.map +1 -0
- package/dist/design/identity/shape.d.ts +4 -0
- package/dist/design/identity/shape.d.ts.map +1 -0
- package/dist/design/identity/shape.js +23 -0
- package/dist/design/identity/shape.js.map +1 -0
- package/dist/design/identity/surface.d.ts +18 -0
- package/dist/design/identity/surface.d.ts.map +1 -0
- package/dist/design/identity/surface.js +125 -0
- package/dist/design/identity/surface.js.map +1 -0
- package/dist/design/identity/types.d.ts +280 -0
- package/dist/design/identity/types.d.ts.map +1 -0
- package/dist/design/identity/types.js +21 -0
- package/dist/design/identity/types.js.map +1 -0
- package/dist/design/identity/typography.d.ts +7 -0
- package/dist/design/identity/typography.d.ts.map +1 -0
- package/dist/design/identity/typography.js +42 -0
- package/dist/design/identity/typography.js.map +1 -0
- package/dist/design/identity-resolver.d.ts +15 -0
- package/dist/design/identity-resolver.d.ts.map +1 -0
- package/dist/design/identity-resolver.js +52 -0
- package/dist/design/identity-resolver.js.map +1 -0
- package/dist/design/oklch.d.ts +10 -0
- package/dist/design/oklch.d.ts.map +1 -0
- package/dist/design/oklch.js +61 -0
- package/dist/design/oklch.js.map +1 -0
- package/dist/design/palette.d.ts +26 -0
- package/dist/design/palette.d.ts.map +1 -0
- package/dist/design/palette.js +73 -0
- package/dist/design/palette.js.map +1 -0
- package/dist/design/presets.d.ts +18 -0
- package/dist/design/presets.d.ts.map +1 -0
- package/dist/design/presets.js +2 -0
- package/dist/design/presets.js.map +1 -0
- package/dist/design/recipes/animations.d.ts +11 -0
- package/dist/design/recipes/animations.d.ts.map +1 -0
- package/dist/design/recipes/animations.js +180 -0
- package/dist/design/recipes/animations.js.map +1 -0
- package/dist/design/recipes/backgrounds.d.ts +3 -0
- package/dist/design/recipes/backgrounds.d.ts.map +1 -0
- package/dist/design/recipes/backgrounds.js +152 -0
- package/dist/design/recipes/backgrounds.js.map +1 -0
- package/dist/design/recipes/index.d.ts +2 -0
- package/dist/design/recipes/index.d.ts.map +1 -0
- package/dist/design/recipes/index.js +2 -0
- package/dist/design/recipes/index.js.map +1 -0
- package/dist/design/surface-to-css.d.ts +57 -0
- package/dist/design/surface-to-css.d.ts.map +1 -0
- package/dist/design/surface-to-css.js +130 -0
- package/dist/design/surface-to-css.js.map +1 -0
- package/dist/design/surface-to-rn.d.ts +57 -0
- package/dist/design/surface-to-rn.d.ts.map +1 -0
- package/dist/design/surface-to-rn.js +133 -0
- package/dist/design/surface-to-rn.js.map +1 -0
- package/dist/design/tokens.d.ts +67 -0
- package/dist/design/tokens.d.ts.map +1 -0
- package/dist/design/tokens.js +36 -0
- package/dist/design/tokens.js.map +1 -0
- package/dist/device/context.d.ts +13 -0
- package/dist/device/context.d.ts.map +1 -0
- package/dist/device/context.js +2 -0
- package/dist/device/context.js.map +1 -0
- package/dist/editor-session/clone.d.ts +4 -0
- package/dist/editor-session/clone.d.ts.map +1 -0
- package/dist/editor-session/clone.js +55 -0
- package/dist/editor-session/clone.js.map +1 -0
- package/dist/editor-session/engine.d.ts +21 -0
- package/dist/editor-session/engine.d.ts.map +1 -0
- package/dist/editor-session/engine.js +375 -0
- package/dist/editor-session/engine.js.map +1 -0
- package/dist/editor-session/persistence.d.ts +8 -0
- package/dist/editor-session/persistence.d.ts.map +1 -0
- package/dist/editor-session/persistence.js +89 -0
- package/dist/editor-session/persistence.js.map +1 -0
- package/dist/editor-session/types.d.ts +90 -0
- package/dist/editor-session/types.d.ts.map +1 -0
- package/dist/editor-session/types.js +2 -0
- package/dist/editor-session/types.js.map +1 -0
- package/dist/editor-session/validators.d.ts +5 -0
- package/dist/editor-session/validators.d.ts.map +1 -0
- package/dist/editor-session/validators.js +106 -0
- package/dist/editor-session/validators.js.map +1 -0
- package/dist/elements/composer.d.ts +109 -0
- package/dist/elements/composer.d.ts.map +1 -0
- package/dist/elements/composer.js +129 -0
- package/dist/elements/composer.js.map +1 -0
- package/dist/export/csv.d.ts +3 -0
- package/dist/export/csv.d.ts.map +1 -0
- package/dist/export/csv.js +16 -0
- package/dist/export/csv.js.map +1 -0
- package/dist/export/download.d.ts +2 -0
- package/dist/export/download.d.ts.map +1 -0
- package/dist/export/download.js +13 -0
- package/dist/export/download.js.map +1 -0
- package/dist/export/format.d.ts +3 -0
- package/dist/export/format.d.ts.map +1 -0
- package/dist/export/format.js +43 -0
- package/dist/export/format.js.map +1 -0
- package/dist/export/types.d.ts +22 -0
- package/dist/export/types.d.ts.map +1 -0
- package/dist/export/types.js +2 -0
- package/dist/export/types.js.map +1 -0
- package/dist/expressions/deep-resolve.d.ts +4 -0
- package/dist/expressions/deep-resolve.d.ts.map +1 -0
- package/dist/expressions/deep-resolve.js +20 -0
- package/dist/expressions/deep-resolve.js.map +1 -0
- package/dist/expressions/handlers/array.d.ts +19 -0
- package/dist/expressions/handlers/array.d.ts.map +1 -0
- package/dist/expressions/handlers/array.js +161 -0
- package/dist/expressions/handlers/array.js.map +1 -0
- package/dist/expressions/handlers/auth.d.ts +13 -0
- package/dist/expressions/handlers/auth.d.ts.map +1 -0
- package/dist/expressions/handlers/auth.js +90 -0
- package/dist/expressions/handlers/auth.js.map +1 -0
- package/dist/expressions/handlers/bind.d.ts +22 -0
- package/dist/expressions/handlers/bind.d.ts.map +1 -0
- package/dist/expressions/handlers/bind.js +57 -0
- package/dist/expressions/handlers/bind.js.map +1 -0
- package/dist/expressions/handlers/breakpoint.d.ts +10 -0
- package/dist/expressions/handlers/breakpoint.d.ts.map +1 -0
- package/dist/expressions/handlers/breakpoint.js +39 -0
- package/dist/expressions/handlers/breakpoint.js.map +1 -0
- package/dist/expressions/handlers/computed.d.ts +3 -0
- package/dist/expressions/handlers/computed.d.ts.map +1 -0
- package/dist/expressions/handlers/computed.js +20 -0
- package/dist/expressions/handlers/computed.js.map +1 -0
- package/dist/expressions/handlers/cond.d.ts +3 -0
- package/dist/expressions/handlers/cond.d.ts.map +1 -0
- package/dist/expressions/handlers/cond.js +57 -0
- package/dist/expressions/handlers/cond.js.map +1 -0
- package/dist/expressions/handlers/date.d.ts +14 -0
- package/dist/expressions/handlers/date.d.ts.map +1 -0
- package/dist/expressions/handlers/date.js +95 -0
- package/dist/expressions/handlers/date.js.map +1 -0
- package/dist/expressions/handlers/format.d.ts +19 -0
- package/dist/expressions/handlers/format.d.ts.map +1 -0
- package/dist/expressions/handlers/format.js +93 -0
- package/dist/expressions/handlers/format.js.map +1 -0
- package/dist/expressions/handlers/group.d.ts +25 -0
- package/dist/expressions/handlers/group.d.ts.map +1 -0
- package/dist/expressions/handlers/group.js +85 -0
- package/dist/expressions/handlers/group.js.map +1 -0
- package/dist/expressions/handlers/i18n.d.ts +8 -0
- package/dist/expressions/handlers/i18n.d.ts.map +1 -0
- package/dist/expressions/handlers/i18n.js +35 -0
- package/dist/expressions/handlers/i18n.js.map +1 -0
- package/dist/expressions/handlers/index.d.ts +4 -0
- package/dist/expressions/handlers/index.d.ts.map +1 -0
- package/dist/expressions/handlers/index.js +52 -0
- package/dist/expressions/handlers/index.js.map +1 -0
- package/dist/expressions/handlers/let.d.ts +4 -0
- package/dist/expressions/handlers/let.d.ts.map +1 -0
- package/dist/expressions/handlers/let.js +36 -0
- package/dist/expressions/handlers/let.js.map +1 -0
- package/dist/expressions/handlers/logic.d.ts +27 -0
- package/dist/expressions/handlers/logic.d.ts.map +1 -0
- package/dist/expressions/handlers/logic.js +52 -0
- package/dist/expressions/handlers/logic.js.map +1 -0
- package/dist/expressions/handlers/math.d.ts +13 -0
- package/dist/expressions/handlers/math.d.ts.map +1 -0
- package/dist/expressions/handlers/math.js +58 -0
- package/dist/expressions/handlers/math.js.map +1 -0
- package/dist/expressions/handlers/platform.d.ts +13 -0
- package/dist/expressions/handlers/platform.d.ts.map +1 -0
- package/dist/expressions/handlers/platform.js +37 -0
- package/dist/expressions/handlers/platform.js.map +1 -0
- package/dist/expressions/handlers/prop.d.ts +10 -0
- package/dist/expressions/handlers/prop.d.ts.map +1 -0
- package/dist/expressions/handlers/prop.js +18 -0
- package/dist/expressions/handlers/prop.js.map +1 -0
- package/dist/expressions/handlers/selection.d.ts +10 -0
- package/dist/expressions/handlers/selection.d.ts.map +1 -0
- package/dist/expressions/handlers/selection.js +33 -0
- package/dist/expressions/handlers/selection.js.map +1 -0
- package/dist/expressions/handlers/state.d.ts +3 -0
- package/dist/expressions/handlers/state.d.ts.map +1 -0
- package/dist/expressions/handlers/state.js +8 -0
- package/dist/expressions/handlers/state.js.map +1 -0
- package/dist/expressions/handlers/switch.d.ts +15 -0
- package/dist/expressions/handlers/switch.d.ts.map +1 -0
- package/dist/expressions/handlers/switch.js +31 -0
- package/dist/expressions/handlers/switch.js.map +1 -0
- package/dist/expressions/handlers/template.d.ts +3 -0
- package/dist/expressions/handlers/template.d.ts.map +1 -0
- package/dist/expressions/handlers/template.js +23 -0
- package/dist/expressions/handlers/template.js.map +1 -0
- package/dist/expressions/handlers/token.d.ts +3 -0
- package/dist/expressions/handlers/token.d.ts.map +1 -0
- package/dist/expressions/handlers/token.js +40 -0
- package/dist/expressions/handlers/token.js.map +1 -0
- package/dist/expressions/handlers/unique-id.d.ts +11 -0
- package/dist/expressions/handlers/unique-id.d.ts.map +1 -0
- package/dist/expressions/handlers/unique-id.js +52 -0
- package/dist/expressions/handlers/unique-id.js.map +1 -0
- package/dist/expressions/registry.d.ts +8 -0
- package/dist/expressions/registry.d.ts.map +1 -0
- package/dist/expressions/registry.js +35 -0
- package/dist/expressions/registry.js.map +1 -0
- package/dist/expressions/resolver.d.ts +15 -0
- package/dist/expressions/resolver.d.ts.map +1 -0
- package/dist/expressions/resolver.js +56 -0
- package/dist/expressions/resolver.js.map +1 -0
- package/dist/factory.d.ts +56 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +265 -0
- package/dist/factory.js.map +1 -0
- package/dist/fetch/framework-fetch.d.ts +12 -0
- package/dist/fetch/framework-fetch.d.ts.map +1 -0
- package/dist/fetch/framework-fetch.js +36 -0
- package/dist/fetch/framework-fetch.js.map +1 -0
- package/dist/fetch/interceptors/auth.d.ts +19 -0
- package/dist/fetch/interceptors/auth.d.ts.map +1 -0
- package/dist/fetch/interceptors/auth.js +66 -0
- package/dist/fetch/interceptors/auth.js.map +1 -0
- package/dist/fetch/interceptors/logging.d.ts +8 -0
- package/dist/fetch/interceptors/logging.d.ts.map +1 -0
- package/dist/fetch/interceptors/logging.js +40 -0
- package/dist/fetch/interceptors/logging.js.map +1 -0
- package/dist/fetch/interceptors/retry.d.ts +20 -0
- package/dist/fetch/interceptors/retry.d.ts.map +1 -0
- package/dist/fetch/interceptors/retry.js +34 -0
- package/dist/fetch/interceptors/retry.js.map +1 -0
- package/dist/fetch/interceptors/timeout.d.ts +7 -0
- package/dist/fetch/interceptors/timeout.d.ts.map +1 -0
- package/dist/fetch/interceptors/timeout.js +20 -0
- package/dist/fetch/interceptors/timeout.js.map +1 -0
- package/dist/fetch/types.d.ts +30 -0
- package/dist/fetch/types.d.ts.map +1 -0
- package/dist/fetch/types.js +2 -0
- package/dist/fetch/types.js.map +1 -0
- package/dist/forms/engine.d.ts +3 -0
- package/dist/forms/engine.d.ts.map +1 -0
- package/dist/forms/engine.js +167 -0
- package/dist/forms/engine.js.map +1 -0
- package/dist/forms/types.d.ts +30 -0
- package/dist/forms/types.d.ts.map +1 -0
- package/dist/forms/types.js +2 -0
- package/dist/forms/types.js.map +1 -0
- package/dist/i18n/engine.d.ts +15 -0
- package/dist/i18n/engine.d.ts.map +1 -0
- package/dist/i18n/engine.js +61 -0
- package/dist/i18n/engine.js.map +1 -0
- package/dist/index.d.ts +161 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +106 -0
- package/dist/index.js.map +1 -0
- package/dist/interactions/data-operations.d.ts +51 -0
- package/dist/interactions/data-operations.d.ts.map +1 -0
- package/dist/interactions/data-operations.js +64 -0
- package/dist/interactions/data-operations.js.map +1 -0
- package/dist/interactions/drag-drop.d.ts +14 -0
- package/dist/interactions/drag-drop.d.ts.map +1 -0
- package/dist/interactions/drag-drop.js +35 -0
- package/dist/interactions/drag-drop.js.map +1 -0
- package/dist/interactions/export.d.ts +24 -0
- package/dist/interactions/export.d.ts.map +1 -0
- package/dist/interactions/export.js +44 -0
- package/dist/interactions/export.js.map +1 -0
- package/dist/interactions/history.d.ts +16 -0
- package/dist/interactions/history.d.ts.map +1 -0
- package/dist/interactions/history.js +52 -0
- package/dist/interactions/history.js.map +1 -0
- package/dist/motion/engine.d.ts +47 -0
- package/dist/motion/engine.d.ts.map +1 -0
- package/dist/motion/engine.js +81 -0
- package/dist/motion/engine.js.map +1 -0
- package/dist/navigation/router.d.ts +36 -0
- package/dist/navigation/router.d.ts.map +1 -0
- package/dist/navigation/router.js +51 -0
- package/dist/navigation/router.js.map +1 -0
- package/dist/permissions/evaluator.d.ts +15 -0
- package/dist/permissions/evaluator.d.ts.map +1 -0
- package/dist/permissions/evaluator.js +32 -0
- package/dist/permissions/evaluator.js.map +1 -0
- package/dist/plugins/loader.d.ts +30 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +87 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/reference/generator.d.ts +25 -0
- package/dist/reference/generator.d.ts.map +1 -0
- package/dist/reference/generator.js +808 -0
- package/dist/reference/generator.js.map +1 -0
- package/dist/renderer/deps.d.ts +24 -0
- package/dist/renderer/deps.d.ts.map +1 -0
- package/dist/renderer/deps.js +150 -0
- package/dist/renderer/deps.js.map +1 -0
- package/dist/renderer/engine.d.ts +15 -0
- package/dist/renderer/engine.d.ts.map +1 -0
- package/dist/renderer/engine.js +1097 -0
- package/dist/renderer/engine.js.map +1 -0
- package/dist/renderer/lazy-paths.d.ts +14 -0
- package/dist/renderer/lazy-paths.d.ts.map +1 -0
- package/dist/renderer/lazy-paths.js +63 -0
- package/dist/renderer/lazy-paths.js.map +1 -0
- package/dist/renderer/prop-schemas.d.ts +17 -0
- package/dist/renderer/prop-schemas.d.ts.map +1 -0
- package/dist/renderer/prop-schemas.js +81 -0
- package/dist/renderer/prop-schemas.js.map +1 -0
- package/dist/renderer/registry.d.ts +10 -0
- package/dist/renderer/registry.d.ts.map +1 -0
- package/dist/renderer/registry.js +22 -0
- package/dist/renderer/registry.js.map +1 -0
- package/dist/renderer/variants.d.ts +54 -0
- package/dist/renderer/variants.d.ts.map +1 -0
- package/dist/renderer/variants.js +105 -0
- package/dist/renderer/variants.js.map +1 -0
- package/dist/runtime/mount-spec-runtime.d.ts +59 -0
- package/dist/runtime/mount-spec-runtime.d.ts.map +1 -0
- package/dist/runtime/mount-spec-runtime.js +73 -0
- package/dist/runtime/mount-spec-runtime.js.map +1 -0
- package/dist/security/api-spec-validator.d.ts +13 -0
- package/dist/security/api-spec-validator.d.ts.map +1 -0
- package/dist/security/api-spec-validator.js +347 -0
- package/dist/security/api-spec-validator.js.map +1 -0
- package/dist/security/app-spec-validator.d.ts +4 -0
- package/dist/security/app-spec-validator.d.ts.map +1 -0
- package/dist/security/app-spec-validator.js +200 -0
- package/dist/security/app-spec-validator.js.map +1 -0
- package/dist/security/identifier-guard.d.ts +3 -0
- package/dist/security/identifier-guard.d.ts.map +1 -0
- package/dist/security/identifier-guard.js +15 -0
- package/dist/security/identifier-guard.js.map +1 -0
- package/dist/security/identity-token-validator.d.ts +3 -0
- package/dist/security/identity-token-validator.d.ts.map +1 -0
- package/dist/security/identity-token-validator.js +121 -0
- package/dist/security/identity-token-validator.js.map +1 -0
- package/dist/security/index.d.ts +14 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +8 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/protection-registry.d.ts +24 -0
- package/dist/security/protection-registry.d.ts.map +1 -0
- package/dist/security/protection-registry.js +35 -0
- package/dist/security/protection-registry.js.map +1 -0
- package/dist/security/rate-limiter.d.ts +23 -0
- package/dist/security/rate-limiter.d.ts.map +1 -0
- package/dist/security/rate-limiter.js +44 -0
- package/dist/security/rate-limiter.js.map +1 -0
- package/dist/security/spec-signing.d.ts +23 -0
- package/dist/security/spec-signing.d.ts.map +1 -0
- package/dist/security/spec-signing.js +62 -0
- package/dist/security/spec-signing.js.map +1 -0
- package/dist/security/spec-validator.d.ts +60 -0
- package/dist/security/spec-validator.d.ts.map +1 -0
- package/dist/security/spec-validator.js +903 -0
- package/dist/security/spec-validator.js.map +1 -0
- package/dist/security/state-protection.d.ts +23 -0
- package/dist/security/state-protection.d.ts.map +1 -0
- package/dist/security/state-protection.js +49 -0
- package/dist/security/state-protection.js.map +1 -0
- package/dist/security/url-whitelist.d.ts +14 -0
- package/dist/security/url-whitelist.d.ts.map +1 -0
- package/dist/security/url-whitelist.js +37 -0
- package/dist/security/url-whitelist.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +8 -0
- package/dist/server.js.map +1 -0
- package/dist/spec-engine/app-elements.d.ts +5 -0
- package/dist/spec-engine/app-elements.d.ts.map +1 -0
- package/dist/spec-engine/app-elements.js +36 -0
- package/dist/spec-engine/app-elements.js.map +1 -0
- package/dist/spec-engine/app-manifest.d.ts +3 -0
- package/dist/spec-engine/app-manifest.d.ts.map +1 -0
- package/dist/spec-engine/app-manifest.js +132 -0
- package/dist/spec-engine/app-manifest.js.map +1 -0
- package/dist/spec-engine/elements.d.ts +8 -0
- package/dist/spec-engine/elements.d.ts.map +1 -0
- package/dist/spec-engine/elements.js +18 -0
- package/dist/spec-engine/elements.js.map +1 -0
- package/dist/spec-engine/engine.d.ts +3 -0
- package/dist/spec-engine/engine.d.ts.map +1 -0
- package/dist/spec-engine/engine.js +76 -0
- package/dist/spec-engine/engine.js.map +1 -0
- package/dist/spec-engine/handlers/api-handler.d.ts +5 -0
- package/dist/spec-engine/handlers/api-handler.d.ts.map +1 -0
- package/dist/spec-engine/handlers/api-handler.js +111 -0
- package/dist/spec-engine/handlers/api-handler.js.map +1 -0
- package/dist/spec-engine/handlers/app-handler.d.ts +4 -0
- package/dist/spec-engine/handlers/app-handler.d.ts.map +1 -0
- package/dist/spec-engine/handlers/app-handler.js +41 -0
- package/dist/spec-engine/handlers/app-handler.js.map +1 -0
- package/dist/spec-engine/handlers/index.d.ts +8 -0
- package/dist/spec-engine/handlers/index.d.ts.map +1 -0
- package/dist/spec-engine/handlers/index.js +17 -0
- package/dist/spec-engine/handlers/index.js.map +1 -0
- package/dist/spec-engine/handlers/screen-handler.d.ts +4 -0
- package/dist/spec-engine/handlers/screen-handler.d.ts.map +1 -0
- package/dist/spec-engine/handlers/screen-handler.js +34 -0
- package/dist/spec-engine/handlers/screen-handler.js.map +1 -0
- package/dist/spec-engine/manifest.d.ts +11 -0
- package/dist/spec-engine/manifest.d.ts.map +1 -0
- package/dist/spec-engine/manifest.js +76 -0
- package/dist/spec-engine/manifest.js.map +1 -0
- package/dist/spec-engine/types.d.ts +61 -0
- package/dist/spec-engine/types.d.ts.map +1 -0
- package/dist/spec-engine/types.js +2 -0
- package/dist/spec-engine/types.js.map +1 -0
- package/dist/spec-stores/file.d.ts +12 -0
- package/dist/spec-stores/file.d.ts.map +1 -0
- package/dist/spec-stores/file.js +32 -0
- package/dist/spec-stores/file.js.map +1 -0
- package/dist/spec-stores/memory-versioned.d.ts +22 -0
- package/dist/spec-stores/memory-versioned.d.ts.map +1 -0
- package/dist/spec-stores/memory-versioned.js +125 -0
- package/dist/spec-stores/memory-versioned.js.map +1 -0
- package/dist/spec-stores/memory.d.ts +10 -0
- package/dist/spec-stores/memory.d.ts.map +1 -0
- package/dist/spec-stores/memory.js +31 -0
- package/dist/spec-stores/memory.js.map +1 -0
- package/dist/spec-stores/sqlserver-versioned.d.ts +44 -0
- package/dist/spec-stores/sqlserver-versioned.d.ts.map +1 -0
- package/dist/spec-stores/sqlserver-versioned.js +253 -0
- package/dist/spec-stores/sqlserver-versioned.js.map +1 -0
- package/dist/spec-stores/sqlserver.d.ts +27 -0
- package/dist/spec-stores/sqlserver.d.ts.map +1 -0
- package/dist/spec-stores/sqlserver.js +78 -0
- package/dist/spec-stores/sqlserver.js.map +1 -0
- package/dist/spec-stores/supabase-versioned.d.ts +38 -0
- package/dist/spec-stores/supabase-versioned.d.ts.map +1 -0
- package/dist/spec-stores/supabase-versioned.js +197 -0
- package/dist/spec-stores/supabase-versioned.js.map +1 -0
- package/dist/spec-stores/supabase.d.ts +18 -0
- package/dist/spec-stores/supabase.d.ts.map +1 -0
- package/dist/spec-stores/supabase.js +68 -0
- package/dist/spec-stores/supabase.js.map +1 -0
- package/dist/state/reserved-paths.d.ts +41 -0
- package/dist/state/reserved-paths.d.ts.map +1 -0
- package/dist/state/reserved-paths.js +40 -0
- package/dist/state/reserved-paths.js.map +1 -0
- package/dist/state/store.d.ts +18 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/store.js +114 -0
- package/dist/state/store.js.map +1 -0
- package/dist/storage/supabase.d.ts +37 -0
- package/dist/storage/supabase.d.ts.map +1 -0
- package/dist/storage/supabase.js +22 -0
- package/dist/storage/supabase.js.map +1 -0
- package/dist/storage/types.d.ts +22 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/storage/upload-action.d.ts +22 -0
- package/dist/storage/upload-action.d.ts.map +1 -0
- package/dist/storage/upload-action.js +117 -0
- package/dist/storage/upload-action.js.map +1 -0
- package/dist/storage/url.d.ts +17 -0
- package/dist/storage/url.d.ts.map +1 -0
- package/dist/storage/url.js +48 -0
- package/dist/storage/url.js.map +1 -0
- package/dist/streaming/compiler.d.ts +26 -0
- package/dist/streaming/compiler.d.ts.map +1 -0
- package/dist/streaming/compiler.js +54 -0
- package/dist/streaming/compiler.js.map +1 -0
- package/dist/streaming/patch.d.ts +19 -0
- package/dist/streaming/patch.d.ts.map +1 -0
- package/dist/streaming/patch.js +139 -0
- package/dist/streaming/patch.js.map +1 -0
- package/dist/types.d.ts +443 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/util/to-array.d.ts +2 -0
- package/dist/util/to-array.d.ts.map +1 -0
- package/dist/util/to-array.js +14 -0
- package/dist/util/to-array.js.map +1 -0
- package/dist/utils/levenshtein.d.ts +3 -0
- package/dist/utils/levenshtein.d.ts.map +1 -0
- package/dist/utils/levenshtein.js +29 -0
- package/dist/utils/levenshtein.js.map +1 -0
- package/dist/validation/validators.d.ts +20 -0
- package/dist/validation/validators.d.ts.map +1 -0
- package/dist/validation/validators.js +138 -0
- package/dist/validation/validators.js.map +1 -0
- package/dist/versioning/compute-patches.d.ts +7 -0
- package/dist/versioning/compute-patches.d.ts.map +1 -0
- package/dist/versioning/compute-patches.js +62 -0
- package/dist/versioning/compute-patches.js.map +1 -0
- package/dist/versioning/index.d.ts +12 -0
- package/dist/versioning/index.d.ts.map +1 -0
- package/dist/versioning/index.js +7 -0
- package/dist/versioning/index.js.map +1 -0
- package/dist/versioning/promote-gate.d.ts +12 -0
- package/dist/versioning/promote-gate.d.ts.map +1 -0
- package/dist/versioning/promote-gate.js +166 -0
- package/dist/versioning/promote-gate.js.map +1 -0
- package/dist/versioning/rollback.d.ts +26 -0
- package/dist/versioning/rollback.d.ts.map +1 -0
- package/dist/versioning/rollback.js +67 -0
- package/dist/versioning/rollback.js.map +1 -0
- package/dist/versioning/structural-diff.d.ts +8 -0
- package/dist/versioning/structural-diff.d.ts.map +1 -0
- package/dist/versioning/structural-diff.js +287 -0
- package/dist/versioning/structural-diff.js.map +1 -0
- package/dist/versioning/types.d.ts +90 -0
- package/dist/versioning/types.d.ts.map +1 -0
- package/dist/versioning/types.js +2 -0
- package/dist/versioning/types.js.map +1 -0
- package/dist/visibility/evaluator.d.ts +12 -0
- package/dist/visibility/evaluator.d.ts.map +1 -0
- package/dist/visibility/evaluator.js +76 -0
- package/dist/visibility/evaluator.js.map +1 -0
- package/dist/watchers/engine.d.ts +19 -0
- package/dist/watchers/engine.d.ts.map +1 -0
- package/dist/watchers/engine.js +24 -0
- package/dist/watchers/engine.js.map +1 -0
- package/docs/consumer/README.md +44 -0
- package/docs/consumer/WHERE-TO-LOOK.md +94 -0
- package/docs/consumer/ai-context-api.md +195 -0
- package/docs/consumer/ai-context-custom-elements.md +249 -0
- package/docs/consumer/ai-context-patterns.md +254 -0
- package/docs/consumer/ai-context-primitives.md +839 -0
- package/docs/consumer/ai-context-runtime-semantics.md +1075 -0
- package/docs/consumer/ai-context.md +1374 -0
- package/docs/consumer/reference-doc.md +3201 -0
- package/docs/llms.txt +17 -0
- package/docs/wiki/compiled/README.md +33 -0
- package/docs/wiki/compiled/_gaps.md +52 -0
- package/docs/wiki/compiled/_index.md +354 -0
- package/docs/wiki/compiled/_inventory.md +2986 -0
- package/docs/wiki/compiled/_lint.md +66 -0
- package/docs/wiki/compiled/_unmapped.md +3 -0
- package/docs/wiki/compiled/action-apply-preset.md +63 -0
- package/docs/wiki/compiled/action-copy-clipboard.md +45 -0
- package/docs/wiki/compiled/action-drawer.md +50 -0
- package/docs/wiki/compiled/action-export.md +66 -0
- package/docs/wiki/compiled/action-fetch.md +87 -0
- package/docs/wiki/compiled/action-form-control.md +55 -0
- package/docs/wiki/compiled/action-login.md +71 -0
- package/docs/wiki/compiled/action-modal.md +61 -0
- package/docs/wiki/compiled/action-navigate.md +72 -0
- package/docs/wiki/compiled/action-open-url.md +38 -0
- package/docs/wiki/compiled/action-refresh-data-source.md +51 -0
- package/docs/wiki/compiled/action-selection.md +55 -0
- package/docs/wiki/compiled/action-set-locale.md +44 -0
- package/docs/wiki/compiled/action-set-state.md +61 -0
- package/docs/wiki/compiled/action-show-notification.md +65 -0
- package/docs/wiki/compiled/action-submit-form.md +69 -0
- package/docs/wiki/compiled/action-toggle-theme.md +50 -0
- package/docs/wiki/compiled/action-update-tokens.md +63 -0
- package/docs/wiki/compiled/action-upload-file.md +87 -0
- package/docs/wiki/compiled/antipattern-action-chain-no-stop.md +49 -0
- package/docs/wiki/compiled/antipattern-all-filter-wildcard.md +59 -0
- package/docs/wiki/compiled/antipattern-auth-domains-port.md +47 -0
- package/docs/wiki/compiled/antipattern-background-blobs-prop.md +62 -0
- package/docs/wiki/compiled/antipattern-background-css-token.md +53 -0
- package/docs/wiki/compiled/antipattern-checkbox-toggle-value.md +42 -0
- package/docs/wiki/compiled/antipattern-crud-id-collision.md +66 -0
- package/docs/wiki/compiled/antipattern-derive-server-pagination.md +58 -0
- package/docs/wiki/compiled/antipattern-element-variant-top-level.md +57 -0
- package/docs/wiki/compiled/antipattern-event-expression.md +55 -0
- package/docs/wiki/compiled/antipattern-input-type-name.md +43 -0
- package/docs/wiki/compiled/antipattern-mix-fetch-and-datasources.md +48 -0
- package/docs/wiki/compiled/antipattern-modal-drawer-visible.md +57 -0
- package/docs/wiki/compiled/antipattern-motion-entrance-token.md +53 -0
- package/docs/wiki/compiled/antipattern-overflow-hidden-with-shadow.md +50 -0
- package/docs/wiki/compiled/antipattern-required-if-equals.md +59 -0
- package/docs/wiki/compiled/antipattern-row-literal.md +70 -0
- package/docs/wiki/compiled/antipattern-row-template-capture.md +42 -0
- package/docs/wiki/compiled/antipattern-store-save-bypass.md +72 -0
- package/docs/wiki/compiled/antipattern-style-block-duplication.md +56 -0
- package/docs/wiki/compiled/antipattern-submit-form-in-tx-confirm.md +56 -0
- package/docs/wiki/compiled/cli-app-spec.md +53 -0
- package/docs/wiki/compiled/cli-config.md +46 -0
- package/docs/wiki/compiled/cli-contract.md +73 -0
- package/docs/wiki/compiled/cli-delete.md +37 -0
- package/docs/wiki/compiled/cli-docs.md +44 -0
- package/docs/wiki/compiled/cli-elements.md +39 -0
- package/docs/wiki/compiled/cli-existing-spec-edit-loop.md +24 -0
- package/docs/wiki/compiled/cli-history.md +38 -0
- package/docs/wiki/compiled/cli-lint.md +77 -0
- package/docs/wiki/compiled/cli-manifest.md +43 -0
- package/docs/wiki/compiled/cli-overview.md +77 -0
- package/docs/wiki/compiled/cli-patch.md +85 -0
- package/docs/wiki/compiled/cli-programmatic-api.md +73 -0
- package/docs/wiki/compiled/cli-pull.md +39 -0
- package/docs/wiki/compiled/cli-push.md +91 -0
- package/docs/wiki/compiled/cli-tokens.md +38 -0
- package/docs/wiki/compiled/cli-toon.md +44 -0
- package/docs/wiki/compiled/cli-validate.md +52 -0
- package/docs/wiki/compiled/cli-versioning-author.md +58 -0
- package/docs/wiki/compiled/concept-action-chains.md +65 -0
- package/docs/wiki/compiled/concept-action-middleware.md +55 -0
- package/docs/wiki/compiled/concept-animation-build-css.md +43 -0
- package/docs/wiki/compiled/concept-animation-build-rn.md +44 -0
- package/docs/wiki/compiled/concept-animation-caps.md +38 -0
- package/docs/wiki/compiled/concept-animation-cascade.md +89 -0
- package/docs/wiki/compiled/concept-animation-null-semantics.md +55 -0
- package/docs/wiki/compiled/concept-animation-recipes.md +67 -0
- package/docs/wiki/compiled/concept-animation-triggers.md +54 -0
- package/docs/wiki/compiled/concept-animations-engine.md +78 -0
- package/docs/wiki/compiled/concept-api-audit.md +67 -0
- package/docs/wiki/compiled/concept-api-auth.md +67 -0
- package/docs/wiki/compiled/concept-api-catalogs.md +44 -0
- package/docs/wiki/compiled/concept-api-crud-endpoint.md +90 -0
- package/docs/wiki/compiled/concept-api-endpoint-properties.md +40 -0
- package/docs/wiki/compiled/concept-api-endpoints-overview.md +57 -0
- package/docs/wiki/compiled/concept-api-handler-endpoint.md +56 -0
- package/docs/wiki/compiled/concept-api-login-body-contract.md +47 -0
- package/docs/wiki/compiled/concept-api-param-properties.md +44 -0
- package/docs/wiki/compiled/concept-api-public-endpoint.md +33 -0
- package/docs/wiki/compiled/concept-api-query-endpoint.md +53 -0
- package/docs/wiki/compiled/concept-api-scope-filter.md +59 -0
- package/docs/wiki/compiled/concept-api-spec.md +70 -0
- package/docs/wiki/compiled/concept-app-auto-state-paths.md +59 -0
- package/docs/wiki/compiled/concept-app-spec.md +89 -0
- package/docs/wiki/compiled/concept-auth-config.md +71 -0
- package/docs/wiki/compiled/concept-auth-domains.md +55 -0
- package/docs/wiki/compiled/concept-auth-security.md +58 -0
- package/docs/wiki/compiled/concept-auth-state-paths.md +48 -0
- package/docs/wiki/compiled/concept-auto-dark-mode.md +55 -0
- package/docs/wiki/compiled/concept-background-caps.md +42 -0
- package/docs/wiki/compiled/concept-background-layer-kinds.md +80 -0
- package/docs/wiki/compiled/concept-background-recipes.md +53 -0
- package/docs/wiki/compiled/concept-background-stack.md +55 -0
- package/docs/wiki/compiled/concept-blob-layer.md +92 -0
- package/docs/wiki/compiled/concept-blob-motion.md +58 -0
- package/docs/wiki/compiled/concept-blob-shapes-catalog.md +45 -0
- package/docs/wiki/compiled/concept-cli-tokens-inspect.md +38 -0
- package/docs/wiki/compiled/concept-component-variants.md +89 -0
- package/docs/wiki/compiled/concept-cross-tab-sync.md +35 -0
- package/docs/wiki/compiled/concept-css-vs-motion.md +46 -0
- package/docs/wiki/compiled/concept-custom-detection-pattern.md +49 -0
- package/docs/wiki/compiled/concept-custom-element-action-props.md +81 -0
- package/docs/wiki/compiled/concept-custom-element-black-box.md +56 -0
- package/docs/wiki/compiled/concept-custom-element-cache.md +39 -0
- package/docs/wiki/compiled/concept-custom-element-error-boundary.md +33 -0
- package/docs/wiki/compiled/concept-custom-element-prop-cascade.md +60 -0
- package/docs/wiki/compiled/concept-custom-element-repeat.md +53 -0
- package/docs/wiki/compiled/concept-custom-elements.md +71 -0
- package/docs/wiki/compiled/concept-custom-jwt-provider.md +63 -0
- package/docs/wiki/compiled/concept-customize-action.md +33 -0
- package/docs/wiki/compiled/concept-customize-cli-lint-rule.md +30 -0
- package/docs/wiki/compiled/concept-customize-expression-handler.md +30 -0
- package/docs/wiki/compiled/concept-customize-plugin.md +43 -0
- package/docs/wiki/compiled/concept-customize-server-middleware.md +36 -0
- package/docs/wiki/compiled/concept-customize-spec-store.md +42 -0
- package/docs/wiki/compiled/concept-customize-validator-rule.md +35 -0
- package/docs/wiki/compiled/concept-customize-versioned-store.md +37 -0
- package/docs/wiki/compiled/concept-data-sources-lifecycle.md +61 -0
- package/docs/wiki/compiled/concept-data-sources.md +96 -0
- package/docs/wiki/compiled/concept-debugging-runtime-pointers.md +45 -0
- package/docs/wiki/compiled/concept-derive-datasources-mount-order.md +72 -0
- package/docs/wiki/compiled/concept-derive.md +67 -0
- package/docs/wiki/compiled/concept-dna-seeds.md +79 -0
- package/docs/wiki/compiled/concept-editor-commit.md +37 -0
- package/docs/wiki/compiled/concept-editor-save.md +18 -0
- package/docs/wiki/compiled/concept-editor-sessions.md +23 -0
- package/docs/wiki/compiled/concept-element-children-slot.md +54 -0
- package/docs/wiki/compiled/concept-element-definition.md +60 -0
- package/docs/wiki/compiled/concept-element-key.md +56 -0
- package/docs/wiki/compiled/concept-element-prop-definition.md +54 -0
- package/docs/wiki/compiled/concept-element-properties.md +81 -0
- package/docs/wiki/compiled/concept-element-render-node.md +62 -0
- package/docs/wiki/compiled/concept-element-variants.md +67 -0
- package/docs/wiki/compiled/concept-environment-store.md +46 -0
- package/docs/wiki/compiled/concept-export-action.md +56 -0
- package/docs/wiki/compiled/concept-expression-contexts.md +56 -0
- package/docs/wiki/compiled/concept-expression-timing.md +56 -0
- package/docs/wiki/compiled/concept-fetch-interceptors.md +49 -0
- package/docs/wiki/compiled/concept-file-upload-overview.md +55 -0
- package/docs/wiki/compiled/concept-fire-and-forget.md +45 -0
- package/docs/wiki/compiled/concept-font-loading.md +52 -0
- package/docs/wiki/compiled/concept-form-state-paths.md +55 -0
- package/docs/wiki/compiled/concept-forms.md +89 -0
- package/docs/wiki/compiled/concept-identity-accent-application.md +48 -0
- package/docs/wiki/compiled/concept-identity-animations.md +48 -0
- package/docs/wiki/compiled/concept-identity-border-elevation-override.md +56 -0
- package/docs/wiki/compiled/concept-identity-color-scheme.md +74 -0
- package/docs/wiki/compiled/concept-identity-color-weight.md +50 -0
- package/docs/wiki/compiled/concept-identity-glass-rn.md +46 -0
- package/docs/wiki/compiled/concept-identity-gradients.md +56 -0
- package/docs/wiki/compiled/concept-identity-heading-color.md +40 -0
- package/docs/wiki/compiled/concept-identity-helpers.md +61 -0
- package/docs/wiki/compiled/concept-identity-icons.md +46 -0
- package/docs/wiki/compiled/concept-identity-images.md +36 -0
- package/docs/wiki/compiled/concept-identity-label-style.md +36 -0
- package/docs/wiki/compiled/concept-identity-overview.md +72 -0
- package/docs/wiki/compiled/concept-identity-radius-pattern.md +39 -0
- package/docs/wiki/compiled/concept-identity-surface.md +62 -0
- package/docs/wiki/compiled/concept-identity-text-decoration.md +48 -0
- package/docs/wiki/compiled/concept-identity-typography-hierarchy.md +40 -0
- package/docs/wiki/compiled/concept-initial-actions.md +82 -0
- package/docs/wiki/compiled/concept-interactive-states.md +72 -0
- package/docs/wiki/compiled/concept-keyframe-snapshot.md +52 -0
- package/docs/wiki/compiled/concept-layer-background.md +80 -0
- package/docs/wiki/compiled/concept-motion-field.md +77 -0
- package/docs/wiki/compiled/concept-mount-spec-runtime.md +47 -0
- package/docs/wiki/compiled/concept-mythik-renderer.md +76 -0
- package/docs/wiki/compiled/concept-navigation-dirty-guard.md +23 -0
- package/docs/wiki/compiled/concept-navigation.md +75 -0
- package/docs/wiki/compiled/concept-package-layout.md +35 -0
- package/docs/wiki/compiled/concept-path-references.md +53 -0
- package/docs/wiki/compiled/concept-pattern-primitives.md +54 -0
- package/docs/wiki/compiled/concept-preset-dropdown-pattern.md +52 -0
- package/docs/wiki/compiled/concept-presets.md +49 -0
- package/docs/wiki/compiled/concept-primitive-prop-schemas.md +53 -0
- package/docs/wiki/compiled/concept-primitives-overview.md +49 -0
- package/docs/wiki/compiled/concept-promote-gate.md +47 -0
- package/docs/wiki/compiled/concept-prop-cascade.md +76 -0
- package/docs/wiki/compiled/concept-public-package-names.md +33 -0
- package/docs/wiki/compiled/concept-query-envelope.md +55 -0
- package/docs/wiki/compiled/concept-reduced-motion.md +38 -0
- package/docs/wiki/compiled/concept-register-presets.md +44 -0
- package/docs/wiki/compiled/concept-render-error-visibility.md +57 -0
- package/docs/wiki/compiled/concept-repeat-grouped.md +72 -0
- package/docs/wiki/compiled/concept-repeat-selection.md +61 -0
- package/docs/wiki/compiled/concept-repeat.md +81 -0
- package/docs/wiki/compiled/concept-role-access.md +61 -0
- package/docs/wiki/compiled/concept-rollback.md +36 -0
- package/docs/wiki/compiled/concept-rules-catalog.md +49 -0
- package/docs/wiki/compiled/concept-screen-definition.md +51 -0
- package/docs/wiki/compiled/concept-screen-outlet.md +46 -0
- package/docs/wiki/compiled/concept-session-persistence.md +41 -0
- package/docs/wiki/compiled/concept-shape-animations.md +66 -0
- package/docs/wiki/compiled/concept-skeleton-auto.md +58 -0
- package/docs/wiki/compiled/concept-skeleton-manual.md +47 -0
- package/docs/wiki/compiled/concept-source-of-truth-references.md +37 -0
- package/docs/wiki/compiled/concept-source-reading-misleading.md +37 -0
- package/docs/wiki/compiled/concept-spatial-map-editor.md +22 -0
- package/docs/wiki/compiled/concept-spatial-map-zones.md +18 -0
- package/docs/wiki/compiled/concept-spec-engine.md +47 -0
- package/docs/wiki/compiled/concept-spec-store-interface.md +59 -0
- package/docs/wiki/compiled/concept-spec-store-layering.md +51 -0
- package/docs/wiki/compiled/concept-spec-stores-catalog.md +66 -0
- package/docs/wiki/compiled/concept-spec-structure.md +94 -0
- package/docs/wiki/compiled/concept-spec-types.md +76 -0
- package/docs/wiki/compiled/concept-state-change-animation.md +73 -0
- package/docs/wiki/compiled/concept-state-policies.md +44 -0
- package/docs/wiki/compiled/concept-state-protection.md +51 -0
- package/docs/wiki/compiled/concept-storage-adapter.md +69 -0
- package/docs/wiki/compiled/concept-storage-custom-names.md +69 -0
- package/docs/wiki/compiled/concept-storage-evolution.md +32 -0
- package/docs/wiki/compiled/concept-storage-idempotency.md +35 -0
- package/docs/wiki/compiled/concept-storage-overview.md +81 -0
- package/docs/wiki/compiled/concept-storage-postgres-jsonb.md +53 -0
- package/docs/wiki/compiled/concept-storage-postgres-triggers.md +60 -0
- package/docs/wiki/compiled/concept-storage-table-environments.md +40 -0
- package/docs/wiki/compiled/concept-storage-table-screens.md +44 -0
- package/docs/wiki/compiled/concept-storage-table-versions.md +50 -0
- package/docs/wiki/compiled/concept-storage-verification.md +57 -0
- package/docs/wiki/compiled/concept-template-children-marker.md +56 -0
- package/docs/wiki/compiled/concept-template-interpolation.md +60 -0
- package/docs/wiki/compiled/concept-templates-vs-variants.md +80 -0
- package/docs/wiki/compiled/concept-templates.md +93 -0
- package/docs/wiki/compiled/concept-token-categories.md +58 -0
- package/docs/wiki/compiled/concept-token-system.md +61 -0
- package/docs/wiki/compiled/concept-transaction-phase-timing.md +47 -0
- package/docs/wiki/compiled/concept-transaction-rollback.md +38 -0
- package/docs/wiki/compiled/concept-transaction-snapshot.md +37 -0
- package/docs/wiki/compiled/concept-transactions.md +72 -0
- package/docs/wiki/compiled/concept-validation-checks.md +63 -0
- package/docs/wiki/compiled/concept-validators-catalog.md +76 -0
- package/docs/wiki/compiled/concept-versioned-store.md +65 -0
- package/docs/wiki/compiled/concept-versioning-snapshots-patches.md +61 -0
- package/docs/wiki/compiled/concept-visibility.md +55 -0
- package/docs/wiki/compiled/concept-web-only-recipes.md +37 -0
- package/docs/wiki/compiled/concept-where-to-look.md +78 -0
- package/docs/wiki/compiled/expression-and-or-not.md +68 -0
- package/docs/wiki/compiled/expression-array.md +111 -0
- package/docs/wiki/compiled/expression-auth.md +83 -0
- package/docs/wiki/compiled/expression-binditem.md +52 -0
- package/docs/wiki/compiled/expression-bindstate.md +63 -0
- package/docs/wiki/compiled/expression-breakpoint.md +71 -0
- package/docs/wiki/compiled/expression-computed.md +52 -0
- package/docs/wiki/compiled/expression-cond.md +78 -0
- package/docs/wiki/compiled/expression-date.md +66 -0
- package/docs/wiki/compiled/expression-format.md +79 -0
- package/docs/wiki/compiled/expression-group.md +84 -0
- package/docs/wiki/compiled/expression-i18n.md +53 -0
- package/docs/wiki/compiled/expression-item-index.md +72 -0
- package/docs/wiki/compiled/expression-let-ref.md +87 -0
- package/docs/wiki/compiled/expression-math.md +67 -0
- package/docs/wiki/compiled/expression-platform.md +68 -0
- package/docs/wiki/compiled/expression-prop.md +89 -0
- package/docs/wiki/compiled/expression-selection.md +58 -0
- package/docs/wiki/compiled/expression-state.md +70 -0
- package/docs/wiki/compiled/expression-switch.md +68 -0
- package/docs/wiki/compiled/expression-template.md +71 -0
- package/docs/wiki/compiled/expression-token.md +67 -0
- package/docs/wiki/compiled/path-app-screens.md +55 -0
- package/docs/wiki/compiled/path-data-source-paths.md +44 -0
- package/docs/wiki/compiled/path-forms.md +38 -0
- package/docs/wiki/compiled/path-login.md +57 -0
- package/docs/wiki/compiled/path-navigation.md +62 -0
- package/docs/wiki/compiled/path-presets-available.md +44 -0
- package/docs/wiki/compiled/path-tokens.md +56 -0
- package/docs/wiki/compiled/path-tx-result-error.md +56 -0
- package/docs/wiki/compiled/path-ui-device.md +53 -0
- package/docs/wiki/compiled/path-ui-loading-error.md +40 -0
- package/docs/wiki/compiled/path-ui-modals-drawers.md +46 -0
- package/docs/wiki/compiled/path-ui-selected-row.md +92 -0
- package/docs/wiki/compiled/path-uploads.md +32 -0
- package/docs/wiki/compiled/pattern-cross-screen-data-flow.md +83 -0
- package/docs/wiki/compiled/pattern-fetch-vs-datasources.md +63 -0
- package/docs/wiki/compiled/pattern-file-upload-auto.md +61 -0
- package/docs/wiki/compiled/pattern-file-upload-manual.md +59 -0
- package/docs/wiki/compiled/pattern-form-validation-cross-field.md +58 -0
- package/docs/wiki/compiled/pattern-form-validation.md +58 -0
- package/docs/wiki/compiled/pattern-fullstack-coherence.md +49 -0
- package/docs/wiki/compiled/pattern-git-vs-db-versioning.md +55 -0
- package/docs/wiki/compiled/pattern-identity-aware-spec.md +70 -0
- package/docs/wiki/compiled/pattern-loading-content-empty.md +66 -0
- package/docs/wiki/compiled/pattern-login-body-template.md +47 -0
- package/docs/wiki/compiled/pattern-login-screen.md +83 -0
- package/docs/wiki/compiled/pattern-push-vs-patch.md +54 -0
- package/docs/wiki/compiled/pattern-reusable-components.md +67 -0
- package/docs/wiki/compiled/pattern-tx-create.md +76 -0
- package/docs/wiki/compiled/pattern-tx-delete.md +50 -0
- package/docs/wiki/compiled/pattern-tx-toggle.md +45 -0
- package/docs/wiki/compiled/pattern-tx-update.md +68 -0
- package/docs/wiki/compiled/primitive-accordion.md +46 -0
- package/docs/wiki/compiled/primitive-area-chart.md +35 -0
- package/docs/wiki/compiled/primitive-audio-player.md +27 -0
- package/docs/wiki/compiled/primitive-bar-chart.md +34 -0
- package/docs/wiki/compiled/primitive-box.md +58 -0
- package/docs/wiki/compiled/primitive-button.md +55 -0
- package/docs/wiki/compiled/primitive-camera.md +39 -0
- package/docs/wiki/compiled/primitive-checkbox.md +62 -0
- package/docs/wiki/compiled/primitive-divider.md +31 -0
- package/docs/wiki/compiled/primitive-drawer.md +44 -0
- package/docs/wiki/compiled/primitive-file-upload.md +65 -0
- package/docs/wiki/compiled/primitive-grid.md +48 -0
- package/docs/wiki/compiled/primitive-icon.md +106 -0
- package/docs/wiki/compiled/primitive-image.md +49 -0
- package/docs/wiki/compiled/primitive-input.md +81 -0
- package/docs/wiki/compiled/primitive-kanban-board.md +30 -0
- package/docs/wiki/compiled/primitive-line-chart.md +33 -0
- package/docs/wiki/compiled/primitive-list.md +34 -0
- package/docs/wiki/compiled/primitive-modal.md +51 -0
- package/docs/wiki/compiled/primitive-pie-chart.md +32 -0
- package/docs/wiki/compiled/primitive-screen-outlet.md +42 -0
- package/docs/wiki/compiled/primitive-screen.md +43 -0
- package/docs/wiki/compiled/primitive-scroll.md +33 -0
- package/docs/wiki/compiled/primitive-select.md +76 -0
- package/docs/wiki/compiled/primitive-signature.md +40 -0
- package/docs/wiki/compiled/primitive-skeleton.md +48 -0
- package/docs/wiki/compiled/primitive-slider.md +47 -0
- package/docs/wiki/compiled/primitive-spacer.md +33 -0
- package/docs/wiki/compiled/primitive-spatial-map.md +26 -0
- package/docs/wiki/compiled/primitive-stack.md +46 -0
- package/docs/wiki/compiled/primitive-table.md +127 -0
- package/docs/wiki/compiled/primitive-tabs.md +52 -0
- package/docs/wiki/compiled/primitive-text.md +59 -0
- package/docs/wiki/compiled/primitive-textarea.md +44 -0
- package/docs/wiki/compiled/primitive-toast-container.md +44 -0
- package/docs/wiki/compiled/primitive-toggle.md +46 -0
- package/docs/wiki/compiled/primitive-touchable.md +40 -0
- package/docs/wiki/compiled/primitive-wizard.md +43 -0
- package/package.json +58 -8
|
@@ -0,0 +1,1075 @@
|
|
|
1
|
+
# Mythik — Runtime Semantics
|
|
2
|
+
|
|
3
|
+
> Read when debugging runtime behavior or building CRUD / auth / table features.
|
|
4
|
+
> Companion to `ai-context.md` — read that first.
|
|
5
|
+
|
|
6
|
+
**Purpose**: runtime-behavior contract. Expression timing, reserved state paths, server API contracts, matcher semantics, store coordination, workflow paradigms.
|
|
7
|
+
|
|
8
|
+
**When to read**: your spec validates but behavior at runtime surprises. Or you're building a feature (CRUD, auth, table with row actions) and need the contract before composing.
|
|
9
|
+
|
|
10
|
+
**NOT here**: spec-gen rules (see `ai-context.md`), primitive prop tables (see `ai-context-primitives.md`), custom element authoring (see `ai-context-custom-elements.md`).
|
|
11
|
+
|
|
12
|
+
## Top behaviors to understand first
|
|
13
|
+
|
|
14
|
+
1. 🔴 [`/ui/selectedRow` magic path (§2.1)](#21-uiselectedrow--blocker-1)
|
|
15
|
+
2. 🔴 [CRUD 1-endpoint 3-route auto-generation (§3.1)](#31-crud--one-endpoint-three-routes--blocker-3)
|
|
16
|
+
3. 🟢 [dataSources + derive lifecycle (§5.2 + §5.3)](#52-datasources-lifecycle) — SHIPPED v0.1.0 Item E
|
|
17
|
+
4. 🟢 [authDomains hostname-only matching (§4.1)](#41-authdomains-hostname-only--blocker-5)
|
|
18
|
+
|
|
19
|
+
These five behaviors caused the most source-reading in the 2026-04 consumer-simulation experiment. If you read only one section of this doc, read these.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Expression Resolution Timing
|
|
24
|
+
|
|
25
|
+
When the framework resolves `$state`, `$template`, `$prop`, `$auth`, and other expressions varies by surface (where the expression lives in the spec). This matrix is the foundation of every debugging session involving "why is my `$state` returning stale / wrong data?".
|
|
26
|
+
|
|
27
|
+
### 1.1 Resolution Timing Matrix
|
|
28
|
+
|
|
29
|
+
| Surface | Binding Location | Resolution Timing | Context Source | Rationale |
|
|
30
|
+
|---|---|---|---|---|
|
|
31
|
+
| Spatial item press | `spatial-map.onItemPress` | **Lazy** - at item press via `lazyActionPaths` | Dispatch context + item from `/ui/selectedSpatialItem` | Renderer wraps spec ActionBindings into a function via `createContextDispatcher`; engine keeps raw at render; dispatcher resolves at press |
|
|
32
|
+
| Spatial item edit | `spatial-map.onItemChange` | **Lazy** - at edit commit via `lazyActionPaths` | Dispatch context + item change from `/ui/spatialItemChange` | Renderer wraps spec ActionBindings into a function via `createContextDispatcher`; engine keeps raw at render; dispatcher resolves after drag drop or keyboard move |
|
|
33
|
+
| Spatial zone press | `spatial-map.onZonePress` | **Lazy** - at zone press via `lazyActionPaths` | Dispatch context + zone from `/ui/selectedSpatialZone` | Renderer wraps spec ActionBindings into a function via `createContextDispatcher`; engine keeps raw at render; dispatcher resolves at press |
|
|
34
|
+
| Spatial zone edit | `spatial-map.onZoneChange` | **Lazy** - at edit commit via `lazyActionPaths` | Dispatch context + zone change from `/ui/spatialZoneChange` | Renderer wraps spec ActionBindings into a function via `createContextDispatcher`; engine keeps raw at render; dispatcher resolves after drag/resize drop or keyboard move/resize |
|
|
35
|
+
| Spatial canvas press | `spatial-map.onCanvasPress` | **Lazy** - at SVG canvas press via `lazyActionPaths` | Dispatch context + canvas point from `/ui/spatialCanvasPress` | Renderer writes canvas context to `canvasPressPath` before dispatch; item handlers stop propagation |
|
|
36
|
+
| Editor session commit | `editorCommit.params.changes[].value` | **Lazy** - at action dispatch | Current state and prior lazy spatial contexts | Dispatcher deep-resolves commit params immediately before the history engine applies the atomic tracked-path edit |
|
|
37
|
+
| Direct props | `element.props.*` | **Eager** — at render | Render context | Props become HTML/RN attributes; must be concrete at render |
|
|
38
|
+
| Event binding (outside repeat) | `element.on.<event>` | **Lazy** — at press/dispatch | Dispatch context | Action params need current state, not render-time snapshot |
|
|
39
|
+
| Event binding (inside repeat) | `element.on.<event>` | **Eager** for `$item`/`$index` shape + params | Item context + dispatch context | `$item` binds to the row being rendered; outer wrapping is eager, inner `$state` still resolves per dispatch |
|
|
40
|
+
| Event binding as `$prop` | `element.on.<event>: { $prop: "..." }` | **Eager** outer shape (for Layer 3 propagation) + lazy inner | Prop cascade + dispatch | Custom-element action propagation needs consumer's binding at render; inner state/template stay press-time |
|
|
41
|
+
| Column actions | `columns[].actions[].onPress` | **Lazy** — at press via `lazyActionPaths` | Dispatch context + row from `/ui/selectedRow` | Primitive declares lazy paths; engine keeps raw at render; dispatcher resolves at press |
|
|
42
|
+
| Row click | `onRowClick` | **Lazy** — at click via `lazyActionPaths` | Dispatch context + row from `/ui/selectedRow` | Renderer wraps spec ActionBindings into a function via `createRowDispatcher`; engine keeps raw at render; dispatcher resolves at click |
|
|
43
|
+
| `$template` in action params | action params | **Lazy** — at dispatch | Action dispatch context | Template's nested expressions resolve with dispatch-time state |
|
|
44
|
+
| `$template` in element props | prop values | **Eager** — at render | Render context | Props need concrete string at render |
|
|
45
|
+
| `initialActions[]` params | spec-level | **Eager** at spec mount | Mount context | Runs once at mount; state then stable for subsequent renders |
|
|
46
|
+
| Transaction `before` | transaction phase | **Eager** at dispatch start | Dispatch context | Pre-network; fires before optimistic |
|
|
47
|
+
| Transaction `optimistic` | transaction phase | **Eager** at dispatch | Dispatch + optimistic state | State changes applied synchronously |
|
|
48
|
+
| Transaction `onSuccess` / `onError` | transaction phase | **Eager** at network resolve/reject | Dispatch + response | Response available in resolver context |
|
|
49
|
+
| Form bindings | `$bindState` | **Eager read** at render + write on input change | Render + event | Bidirectional binding |
|
|
50
|
+
|
|
51
|
+
### 1.2 `element.on` — lazy event bindings
|
|
52
|
+
|
|
53
|
+
**Contract:** Outside a `repeat`, event bindings in `element.on.<eventName>` are stored raw by the renderer. The action dispatcher resolves inner `$state` / `$template` at press/dispatch time, not render time.
|
|
54
|
+
|
|
55
|
+
**Why it matters:** `onClick: [{ action: "fetch", params: { url: { "$template": "/api/items/${ /ui/selectedId }" }}}]` — the `$template` reads `/ui/selectedId` at *click* time. If the user clicked a different row between render and click, the click reads the later value. Correct behavior for typical event flows.
|
|
56
|
+
|
|
57
|
+
**Special cases:**
|
|
58
|
+
- **Inside a `repeat`** — the binding wrapper is eagerly resolved so `$item` / `$index` can bind to the row being rendered. Inner `$state` / `$template` inside `params` stay lazy (press-time) unless they reference `$item` directly.
|
|
59
|
+
- **`$prop` bindings** — when the binding itself is `{ $prop: "onAction" }` (custom-element Layer 3 propagation), the `$prop` is resolved eagerly so the consumer's supplied action chain replaces it. Inner expressions inside that chain stay lazy.
|
|
60
|
+
- **`TransactionBinding`** — passed through verbatim; transaction engine resolves phases at their respective times.
|
|
61
|
+
|
|
62
|
+
Implementation: `packages/core/src/renderer/engine.ts:996-1049`.
|
|
63
|
+
|
|
64
|
+
### 1.3 Column actions — lazy resolution at press time
|
|
65
|
+
|
|
66
|
+
**Contract:** Actions declared inside `columns[].actions[].onPress` resolve their inner `$state` / `$template` / `$auth` expressions **at press time**, not render time. Row context flows via the framework-managed `/ui/selectedRow` magic path (see §2.1 + §5.1).
|
|
67
|
+
|
|
68
|
+
**Canonical pattern:**
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"type": "table",
|
|
73
|
+
"props": {
|
|
74
|
+
"data": { "$state": "/items" },
|
|
75
|
+
"columns": [{
|
|
76
|
+
"actions": [{
|
|
77
|
+
"icon": "pencil-simple",
|
|
78
|
+
"onPress": [{
|
|
79
|
+
"action": "openModal",
|
|
80
|
+
"params": {
|
|
81
|
+
"id": "edit-modal",
|
|
82
|
+
"itemId": { "$state": "/ui/selectedRow/id" }
|
|
83
|
+
}
|
|
84
|
+
}]
|
|
85
|
+
}]
|
|
86
|
+
}]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
When the user clicks the action:
|
|
92
|
+
1. Framework writes the clicked row to `/ui/selectedRow` (via `createRowDispatcher` at `packages/react/src/runtime/row-dispatcher.ts`).
|
|
93
|
+
2. Dispatcher resolves `itemId: { $state: "/ui/selectedRow/id" }` against the just-written value.
|
|
94
|
+
3. `openModal` action receives the correct `itemId` for the clicked row.
|
|
95
|
+
|
|
96
|
+
**Mechanism:** Primitives declare `lazyActionPaths` in `PRIMITIVE_PROP_SCHEMAS`. Table declares `['columns[].actions[].onPress']`. The engine consults this declaration in `resolvePropsWithContext` (`engine.ts:167-186`) and keeps matched subtrees raw — `resolveDeep` does NOT walk into them. Similarly, `scanDeps` does NOT register state paths inside lazy subtrees as render dependencies, so cache invalidation is not triggered by row-context state changes.
|
|
97
|
+
|
|
98
|
+
**Any `$state` path works.** The lazy contract is path-agnostic — the resolver evaluates whatever `$state` path it sees at press time. `/ui/selectedRow/*` is canonical for row-context reads, but column actions can also read `/auth/user/...`, `/preferences/*`, or any other state path.
|
|
99
|
+
|
|
100
|
+
**Two-step workaround (legacy pattern, still works):**
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
"onPress": [
|
|
104
|
+
{ "action": "openModal", "params": { "id": "edit-modal" } }
|
|
105
|
+
]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The modal content reads `/ui/selectedRow/*` via `$state` separately. Pre-v0.1.0 specs that wrote this workaround for the prior eager-resolution bug continue to work.
|
|
109
|
+
|
|
110
|
+
**Implementation references:** `packages/core/src/renderer/engine.ts:167-186` (`resolvePropsWithContext`); `packages/core/src/renderer/prop-schemas.ts` (`table.lazyActionPaths`); `packages/core/src/renderer/lazy-paths.ts` (parser + matcher).
|
|
111
|
+
|
|
112
|
+
### 1.4 `$prop` cascade (Layer 3 custom elements)
|
|
113
|
+
|
|
114
|
+
**Contract:** Inside a custom-element render tree, `$prop` references are resolved eagerly at each cascade level with the consumer's supplied values. Nesting pushes a new prop context; the element's own `$prop` reads its merged props.
|
|
115
|
+
|
|
116
|
+
**Why eager:** custom-element composition requires the consumer's values (action chains, data, style tokens) to substitute into the render tree at expansion time. Lazy resolution would break Layer 3 propagation.
|
|
117
|
+
|
|
118
|
+
**Inner expressions:** `$state` / `$template` inside a consumer-supplied `$prop` action chain stay lazy (resolved at dispatch). See reference-doc rule 239.
|
|
119
|
+
|
|
120
|
+
Implementation: `packages/core/src/expressions/handlers/prop.ts`.
|
|
121
|
+
|
|
122
|
+
### 1.5 `$template` interpolation
|
|
123
|
+
|
|
124
|
+
**Contract:** Resolved at the consumption site. `$template` in a prop value resolves at render; `$template` in an action param resolves at dispatch. Nested expressions (`$state`, `$auth`, `$math`) inside the template resolve with the template's execution context.
|
|
125
|
+
|
|
126
|
+
**Examples:**
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{ "props": { "src": { "$template": "/avatars/${ /auth/user/id }.png" } } }
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Resolves at render with current `/auth/user/id`.
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{ "action": "fetch", "params": { "url": { "$template": "/api/items/${ /ui/selectedId }" } } }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Resolves at dispatch with current `/ui/selectedId`.
|
|
139
|
+
|
|
140
|
+
Implementation: `packages/core/src/expressions/handlers/template.ts`.
|
|
141
|
+
|
|
142
|
+
### 1.6 Transaction phase timing
|
|
143
|
+
|
|
144
|
+
**Contract:** Transaction bindings fire their phases at distinct moments:
|
|
145
|
+
|
|
146
|
+
- **`before`** — eager at dispatch start. Side-effects that must NOT be rolled back (closeModal, navigate). Runs before any network call (reference-doc rule 13).
|
|
147
|
+
- **`optimistic`** — eager at dispatch. State changes applied synchronously; UI reflects the change immediately. Rolled back on `onError`.
|
|
148
|
+
- **`onSuccess`** — eager at network resolve. Response available in resolver context. UPDATE transactions typically omit `onSuccess` — the optimistic state is already correct; re-fetch causes visible flash (reference-doc rule 14).
|
|
149
|
+
- **`onError`** — eager at network reject. Optimistic state reverted via snapshot BEFORE this phase runs. Error available in resolver context.
|
|
150
|
+
|
|
151
|
+
**Internal phase (not consumer-visible):** a `snapshot` phase captures the state immediately before `optimistic`, enabling rollback. Consumers never invoke `snapshot` directly.
|
|
152
|
+
|
|
153
|
+
Implementation: `packages/core/src/actions/transaction-engine.ts`.
|
|
154
|
+
|
|
155
|
+
### 1.7 Form bindings (`$bindState`)
|
|
156
|
+
|
|
157
|
+
**Contract:** Two-way binding. At render, the input value is read from the state path (eager). On input change, the new value is written to the state path (event-time).
|
|
158
|
+
|
|
159
|
+
**Example:**
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{ "type": "input", "props": { "value": { "$bindState": "/form/username" } } }
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The input reads `/form/username` at render and writes back on every change event. There is no "resolve at press" concept — the framework wires both directions at render.
|
|
166
|
+
|
|
167
|
+
Implementation: `packages/core/src/forms/engine.ts` + renderer integration in `packages/react/src/MythikRenderer.tsx`.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 2. Framework-Reserved State Paths
|
|
172
|
+
|
|
173
|
+
Several state paths are written by the framework itself, not by consumer specs. Reading them works; writing them from a spec is usually a mistake — the framework overwrites, or state invariants break. This section documents the framework-managed paths, their write-owner, lifetime, and canonical read patterns.
|
|
174
|
+
|
|
175
|
+
### 2.1 `/ui/selectedRow` 🔴 BLOCKER #1
|
|
176
|
+
|
|
177
|
+
**Row context model**: a row interaction (column action OR direct `onRowClick`) writes the row data to `/ui/selectedRow` immediately before dispatching the action chain. Downstream actions and elements (modal content, detail panels) read fresh row context via `$state` or `$template` against `/ui/selectedRow/*`. Single-selection scope per screen — see multi-table caveat below.
|
|
178
|
+
|
|
179
|
+
**Write-owner:** `packages/react/src/runtime/row-dispatcher.ts` (the `createRowDispatcher` helper used by `MythikRenderer.tsx`'s table-specific wiring). When a user clicks a table column action OR triggers `onRowClick`, the helper writes the clicked row's data to `/ui/selectedRow` *immediately before* dispatching the action:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
export function createRowDispatcher(
|
|
183
|
+
store: StateStore,
|
|
184
|
+
dispatchAction: (binding: EventBinding) => void,
|
|
185
|
+
rowPath: string = RESERVED_PATHS.SELECTED_ROW,
|
|
186
|
+
): (binding: EventBinding | undefined, row?: Record<string, unknown>) => void {
|
|
187
|
+
const dispatchWithContext = createContextDispatcher<Record<string, unknown>>(
|
|
188
|
+
store,
|
|
189
|
+
dispatchAction,
|
|
190
|
+
rowPath,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
return (binding, row) => {
|
|
194
|
+
dispatchWithContext(binding, row || undefined);
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Lifetime:** persists until the next row interaction dispatch (column action or direct `onRowClick`). No auto-clear on modal close, screen navigate, or tab switch. A stale `/ui/selectedRow` from a previous click is normal state.
|
|
200
|
+
|
|
201
|
+
**Scope:** singleton per screen. Two tables on the same screen share the path — the most recently clicked row wins. The framework does not namespace per-table today.
|
|
202
|
+
|
|
203
|
+
**Read patterns (canonical):**
|
|
204
|
+
|
|
205
|
+
In a downstream element (e.g., modal content opened by the action):
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"type": "text",
|
|
210
|
+
"props": {
|
|
211
|
+
"content": { "$template": "Editing: ${ /ui/selectedRow/name }" }
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Or in the action's own params (column actions and onRowClick both resolve `$state` lazily at click time via the table's lazyActionPaths — see §1.3) or in a subsequent action's params (which run after the row write):
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"action": "fetch",
|
|
221
|
+
"params": {
|
|
222
|
+
"url": { "$template": "/api/items/${ /ui/selectedRow/id }" }
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Anti-pattern — `$row` does not exist:**
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{ "content": { "$row": "name" } }
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
There is no `$row` expression. `$item` exists for `repeat` contexts, but tables use a different iteration model and `$item` does not apply inside column cells. Use `/ui/selectedRow` for post-click row data.
|
|
234
|
+
|
|
235
|
+
**Multi-table caveat:** if your screen has two tables with row actions, both tables write to `/ui/selectedRow`. There is no per-table row path today. If multi-table row isolation is required, the framework would need a `selection.rowPath` config option (not in scope for v0.1).
|
|
236
|
+
|
|
237
|
+
See also §5.1 for the row-write-then-dispatch order and §1.3 for why action params can read the freshly written row lazily at press time.
|
|
238
|
+
|
|
239
|
+
### Spatial item context model
|
|
240
|
+
|
|
241
|
+
`spatial-map` writes the activated item context to `/ui/selectedSpatialItem` immediately before dispatching JSON `onItemPress` actions. The payload is domain-neutral: `kind`, `mode`, `itemId`, `zoneId`, `status`, `label`, `position`, `rotation`, `shape`, `metadata`, `item`, and optional `zone`.
|
|
242
|
+
|
|
243
|
+
`onItemPress` params resolve lazily at press time, so `$state: "/ui/selectedSpatialItem/itemId"` reads the item just pressed. `selectedItemPath` can override the default path when a screen needs isolated spatial maps.
|
|
244
|
+
|
|
245
|
+
### Spatial zone context model
|
|
246
|
+
|
|
247
|
+
`spatial-map` writes the activated/selected zone context to `/ui/selectedSpatialZone` immediately before dispatching JSON `onZonePress` actions. The payload is domain-neutral: `kind`, `mode`, `zoneId`, optional `label`, `position`, `rotation`, optional `transform`, optional `localBounds`, `shape`, `metadata`, and full `zone`.
|
|
248
|
+
|
|
249
|
+
`onZonePress` params resolve lazily at press time, so `$state: "/ui/selectedSpatialZone/zoneId"` reads the zone just pressed. `selectedZonePath` can override the default path for isolated editors. Programmatic function callbacks pass through and own selected visual state through `selectedZoneId` or direct store writes.
|
|
250
|
+
|
|
251
|
+
`onCanvasPress` writes canvas context before dispatching JSON actions. The default write path is `/ui/spatialCanvasPress`; set `canvasPressPath` to isolate a specific editor, for example `/ui/floorEditor/canvasPress`. The payload is domain-neutral: `kind: "canvas"`, `mode`, `point`, `viewBox`, optional `zoneId`, and optional `zone`. Use it for generic click-to-place flows: enter a consumer-owned placement mode, read `canvasPressPath/point`, build a pending item, append it to the consumer-owned items array, then select/draft it externally.
|
|
252
|
+
|
|
253
|
+
`onCanvasPress` can clear the selected item/zone and/or dispatch its action. `interactionPolicy.clearSelectionOnCanvasPress` controls clearing; dispatch does not depend on clearing. The primitive does not open drawers, modals, menus, or inspectors itself; compose those externally with actions and state.
|
|
254
|
+
|
|
255
|
+
### Spatial item edit changes
|
|
256
|
+
|
|
257
|
+
`spatial-map` writes edit-change context to `itemChangePath` before dispatching JSON `onItemChange`. The default path is `/ui/spatialItemChange`; use `itemChangePath` to isolate multiple maps.
|
|
258
|
+
|
|
259
|
+
Runtime-generated `changeType` values are `move`, `resize`, and `rotate`. JSON-composed editor flows may also write `update`, `create`, `duplicate`, or `delete` as consumer-owned lifecycle records.
|
|
260
|
+
|
|
261
|
+
The context is domain-neutral: `kind`, `changeType`, `itemId`, `previousItem`, `nextItem`, `previousPosition`, `position`, `delta`, optional `zoneId`, and optional `zone`. Resize contexts include `previousTransform`, `transform`, `previousLocalBounds`, and `localBounds`; rotate contexts include `previousRotation` and `rotation`; all runtime edits include complete `previousItem` and `nextItem`. Runtime contexts normalize transform values with the active edit policy, so `minScale`/`maxScale` in `editPolicy` are reflected in emitted metadata.
|
|
262
|
+
|
|
263
|
+
`onItemChange` is a lazy action path. `$state` expressions inside action params resolve after the change context is written. The JSON-first persistence pattern for runtime edits is `$array: "replace"` using `/ui/spatialItemChange/nextItem` or the configured custom path. Use plain `setState` for non-undoable persistence; wrap the same value in `editorCommit` when the edit should participate in undo/redo/dirty state.
|
|
264
|
+
|
|
265
|
+
### Spatial zone edit changes
|
|
266
|
+
|
|
267
|
+
`spatial-map` writes zone edit-change context to `zoneChangePath` before dispatching JSON `onZoneChange`. The default path is `/ui/spatialZoneChange`; use `zoneChangePath` to isolate multiple maps.
|
|
268
|
+
|
|
269
|
+
Runtime zone edits emit `changeType: "move"` or `changeType: "resize"`. The context is domain-neutral: `kind`, `changeType`, `zoneId`, `previousZone`, `nextZone`, `previousPosition`, `position`, `delta`, `previousTransform`, `transform`, `previousRotation`, `rotation`, `previousLocalBounds`, `localBounds`, and `zone`.
|
|
270
|
+
|
|
271
|
+
Runtime zone movement writes `nextZone.position`; runtime zone resize writes `nextZone.transform.scaleX/scaleY`; both preserve `nextZone.shape`. This keeps rect, circle, ellipse, polygon, and path zones on the same transform-layer model and leaves polygon/path point editing as a separate capability. Zone drag, zone resize handles, and keyboard zone edits use the same snap/guides resolver pattern as item editing. The zone movement snap anchor is the center of transformed derived zone bounds, or `position` when no bounds exist. `onZoneChange` is a lazy action path; persist with `$array: "replace"` using `/ui/spatialZoneChange/nextZone` or the configured custom path. Use plain `setState` for non-undoable persistence; wrap the same value in `editorCommit` when the edit should participate in undo/redo/dirty state.
|
|
272
|
+
|
|
273
|
+
### Editor session history
|
|
274
|
+
|
|
275
|
+
`editorSessions` is the generic runtime for JSON-first editing surfaces that need undo, redo, discard, validation, and dirty state. Declare it at the spec root and track only durable document paths:
|
|
276
|
+
|
|
277
|
+
```json
|
|
278
|
+
"editorSessions": {
|
|
279
|
+
"floor-layout": {
|
|
280
|
+
"paths": ["/layout/items", "/layout/zones"],
|
|
281
|
+
"maxHistory": 50,
|
|
282
|
+
"persistence": {
|
|
283
|
+
"url": "/api/floor-layout",
|
|
284
|
+
"method": "PUT",
|
|
285
|
+
"body": "trackedPaths"
|
|
286
|
+
},
|
|
287
|
+
"validators": [
|
|
288
|
+
{ "type": "arrayUniqueField", "path": "/layout/items", "field": "id" },
|
|
289
|
+
{ "type": "arrayUniqueField", "path": "/layout/zones", "field": "id" }
|
|
290
|
+
]
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
The framework writes metadata to `/ui/editorSessions/<id>` and protects that subtree from consumer `setState`. Read `dirty`, `canUndo`, `canRedo`, `undoDepth`, `redoDepth`, `lastCommitLabel`, `status`, `saveStatus`, `saveError`, `lastSaveAttemptAt`, and `validation` for toolbars and save banners. Do not track `/ui/*` drafts, selected objects, modal flags, placement modes, or other transient editor state as document paths.
|
|
296
|
+
|
|
297
|
+
Use `editorCommit` for one atomic undoable edit. For spatial editors, keep using the primitive's lazy change contexts and wrap the same replacement value you would otherwise pass to `setState`:
|
|
298
|
+
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"action": "editorCommit",
|
|
302
|
+
"params": {
|
|
303
|
+
"session": "floor-layout",
|
|
304
|
+
"label": "Update item",
|
|
305
|
+
"changes": [
|
|
306
|
+
{
|
|
307
|
+
"path": "/layout/items",
|
|
308
|
+
"value": {
|
|
309
|
+
"$array": "replace",
|
|
310
|
+
"source": { "$state": "/layout/items" },
|
|
311
|
+
"where": { "field": "id", "eq": { "$state": "/ui/spatialItemChange/itemId" } },
|
|
312
|
+
"value": { "$state": "/ui/spatialItemChange/nextItem" }
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
]
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
`editorUndo` and `editorRedo` restore tracked document paths and update `/ui/editorSessions/<id>` metadata. Consumer UI state is intentionally not part of the engine; clear or resync selected/draft paths in the same action chain when stale inspector state would be confusing. `editorDiscard` restores the last marked-saved snapshot and clears history. `editorCommit` with `validate: true` validates after applying the edit and does not roll back automatically; commit, undo, redo, and discard clear stale validation metadata unless validation is explicitly requested again.
|
|
321
|
+
|
|
322
|
+
For normal persistence, configure `editorSessions.<id>.persistence` once and dispatch `editorSave`:
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
{
|
|
326
|
+
"action": "editorSave",
|
|
327
|
+
"params": {
|
|
328
|
+
"session": "floor-layout"
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
`editorSave` captures the current tracked-path snapshot, builds the payload from that snapshot, checks the resolved URL with the renderer's URL guard, persists through the host `fetcher`, and marks only that sent snapshot as saved after success. It does not dispatch the built-in `fetch` action internally and does not read `/ui/lastError`; that avoids races with data sources or unrelated fetches. It also does not re-run action middleware or rate limiting as a nested dispatcher call. If the user edits while the save is in flight, the saved snapshot is recorded but the current document remains dirty.
|
|
334
|
+
|
|
335
|
+
Default persistence is `method: "PUT"` and `body: "trackedPaths"`, which sends tracked paths as a nested object that preserves state shape, for example `{ "layout": { "items": [...], "zones": [...] } }`. Use `body: "snapshot"` for `{ "paths": { "/layout/items": [...] } }`, or a custom object body when the backend needs a specific envelope. Headers from the session config and per-call `editorSave` params are merged; per-call keys win.
|
|
336
|
+
|
|
337
|
+
Save payloads are editor documents, so `editorSave` does not deep-sanitize empty strings or nested values. Empty strings can be meaningful labels. If a backend needs domain-specific coercion, use a custom `body` expression or perform that coercion in the backend.
|
|
338
|
+
|
|
339
|
+
When `persistence.target` is set, the response JSON is written to that state path after a successful save. If the target lives inside a tracked path, the framework applies the same response value to the captured saved snapshot before marking clean, so server-returned metadata such as `/layout/savedAt` does not immediately make the editor dirty. Failed saves never mark clean; they leave `dirty: true`, set `status: "error"` when the document is still dirty, and expose `saveStatus`, `saveError`, and `lastSaveAttemptAt`. A later document edit clears stale save errors. Reserve `editorMarkSaved` for advanced/low-level integrations that have already completed persistence successfully outside `editorSave`.
|
|
340
|
+
|
|
341
|
+
### Editor session dirty navigation guard
|
|
342
|
+
|
|
343
|
+
Use `navigation.editorSessionGuard` in an `AppSpec` when app navigation must be blocked while one or more editor sessions are dirty:
|
|
344
|
+
|
|
345
|
+
```json
|
|
346
|
+
{
|
|
347
|
+
"navigation": {
|
|
348
|
+
"type": "sidebar",
|
|
349
|
+
"initialScreen": "floor-editor",
|
|
350
|
+
"editorSessionGuard": {
|
|
351
|
+
"enabled": true,
|
|
352
|
+
"sessions": ["floor-layout"],
|
|
353
|
+
"pendingPath": "/ui/navigationGuard/pending"
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
The AppEngine reads `/ui/editorSessions/<id>/dirty` at navigation time. If a guarded session is dirty, `navigateScreen` or `goBackScreen` does not change screens; instead the engine writes a pending object to `pendingPath` with `kind: "editor-session-dirty"`, the action (`"navigateScreen"` or `"goBackScreen"`), target screen/params when applicable, and `dirtySessions`.
|
|
360
|
+
|
|
361
|
+
The framework is headless here: render your own confirmation UI from the pending state. `navigationGuardCancel` clears the pending state. `navigationGuardSaveAndProceed` is the normal save-first action for persisted editor sessions: it calls the currently mounted `EditorSessionEngine.save({ session })` for each pending dirty session, then continues only if those sessions become clean. `navigationGuardProceed` is non-destructive and only continues after the pending sessions are already clean, so treat it as a low-level retry for advanced flows that saved elsewhere. `navigationGuardDiscardAndProceed` explicitly abandons unsaved tracked-path changes by delegating to the mounted `EditorSessionEngine.discard(sessionId)` for each pending dirty session, then continues.
|
|
362
|
+
|
|
363
|
+
In React hosts, `editorSave` needs a fetch transport. Auth-enabled `MythikApp` instances use the framework fetch produced by auth interceptors. Non-auth apps can pass `fetcher` directly to `MythikApp`; `editorSave` and `navigationGuardSaveAndProceed` use that function instead of the global `/ui/lastError`-based fetch action.
|
|
364
|
+
|
|
365
|
+
`blockNavigation`, `blockGoBack`, and `blockBrowserUnload` default to blocking when the guard is enabled. Browser unload uses the native browser prompt and cannot display custom text. Custom `pendingPath` values must be concrete, consumer-owned `/ui/<segment>` paths and must not collide with reserved framework paths such as `/ui/editorSessions/*`, `/ui/spatialItemChange`, or `/ui/selectedRow`.
|
|
366
|
+
|
|
367
|
+
### 2.2 `/ui/device/*`
|
|
368
|
+
|
|
369
|
+
The framework auto-tracks device context and writes to `/ui/device/*`:
|
|
370
|
+
|
|
371
|
+
- `/ui/device/viewportWidth`, `/ui/device/viewportHeight` — updated on resize
|
|
372
|
+
- `/ui/device/platform` — `"web"` | `"ios"` | `"android"`
|
|
373
|
+
- `/ui/device/orientation` — `"portrait"` | `"landscape"` (updated on orientation change)
|
|
374
|
+
- `/ui/device/colorScheme` — `"light"` | `"dark"` (OS color scheme)
|
|
375
|
+
|
|
376
|
+
**Read pattern:** prefer the dedicated expressions `$breakpoint` (for responsive values), `$platform` (for cross-platform branching) over direct state reads. These expressions abstract over the paths and handle default fallbacks (reference-doc rule 37).
|
|
377
|
+
|
|
378
|
+
**Write-owner:** device context hook (React-side). Not configurable by consumer specs.
|
|
379
|
+
|
|
380
|
+
Implementation: `packages/core/src/device/context.ts` (interface), React-side provider writes values.
|
|
381
|
+
|
|
382
|
+
### 2.3 `/ui/modals/{id}` and `/ui/drawers/{id}`
|
|
383
|
+
|
|
384
|
+
**Write-owner:** framework. When an `openModal` action fires, the engine writes `true` to `/ui/modals/<id>`; `closeModal` writes `false`. Same pattern for drawers at `/ui/drawers/<id>`.
|
|
385
|
+
|
|
386
|
+
**Read-owner:** framework. The renderer reads the path to determine modal/drawer visibility.
|
|
387
|
+
|
|
388
|
+
**Consumer contract:** do NOT set `visible` prop on modals or drawers — the engine manages visibility via `/ui/modals/{id}` automatically (reference-doc rule 10).
|
|
389
|
+
|
|
390
|
+
Implementation: `packages/core/src/actions/dispatcher.ts:103-116` (openModal/closeModal/openDrawer/closeDrawer handlers) + renderer modal wiring.
|
|
391
|
+
|
|
392
|
+
### 2.4 `/ui/loading`, `/ui/lastError`, and dataSources loading/error paths
|
|
393
|
+
|
|
394
|
+
**`/ui/loading`** — `fetch` action writes `true` at request start, `false` at resolve. Shared across fetch actions; for fine-grained tracking, use per-target state writes in your own action chains.
|
|
395
|
+
|
|
396
|
+
**`/ui/lastError`** — `fetch` action writes the error message on failure, cleared on next successful fetch.
|
|
397
|
+
|
|
398
|
+
**dataSources auto-managed paths (post-Item-E wire):**
|
|
399
|
+
- `/{target}Loading` — `true` during in-flight request, `false` after resolve/reject
|
|
400
|
+
- `/{target}Error` — error message on failure, `null` on success
|
|
401
|
+
|
|
402
|
+
For a dataSource with `target: "/rooms"`, the framework writes `/roomsLoading` + `/roomsError` automatically.
|
|
403
|
+
|
|
404
|
+
Implementation: `packages/core/src/data/data-sources.ts:76-86` (loadingPath / errorPath derivation + write on fetch start).
|
|
405
|
+
|
|
406
|
+
### 2.5 `/login/*`
|
|
407
|
+
|
|
408
|
+
**Write-owner:** consumer specs via `$bindState: "/login/username"`, `"/login/password"` on input elements. Auto-cleared on logout action (reference-doc rule 47) — credentials never persist after logout.
|
|
409
|
+
|
|
410
|
+
**Convention:** framework examples use `/login/username` + `/login/password`. The `login` action accepts these via `$state`:
|
|
411
|
+
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"action": "login",
|
|
415
|
+
"params": {
|
|
416
|
+
"username": { "$state": "/login/username" },
|
|
417
|
+
"password": { "$state": "/login/password" }
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
For email-convention apps, use `loginBody` template to map email → username at the spec level — see §3.2.
|
|
423
|
+
|
|
424
|
+
### 2.6 Forms state paths (`<formId>.*`)
|
|
425
|
+
|
|
426
|
+
When a form is declared in `spec.forms`, the framework reserves the `<formId>.*` subtree in state for form field values, validation state, and form-level flags. Internal keys like `__valid`, `__touched`, `__errors` are framework-owned.
|
|
427
|
+
|
|
428
|
+
**Read patterns:** use `$formValid` and `$formField` expressions instead of direct state reads — they abstract over the internal flag paths and future-proof against framework changes.
|
|
429
|
+
|
|
430
|
+
Implementation: `packages/core/src/forms/engine.ts`.
|
|
431
|
+
|
|
432
|
+
### 2.7 Upload state paths
|
|
433
|
+
|
|
434
|
+
The `upload` action reserves per-upload state paths for upload lifecycle state (active upload ID, progress, error, result). The exact path layout lives alongside the upload action handler.
|
|
435
|
+
|
|
436
|
+
**Write-owner:** framework. Do not write these from consumer specs.
|
|
437
|
+
|
|
438
|
+
Implementation: `packages/core/src/actions/dispatcher.ts` (upload action handler — search for `upload` in the dispatcher's action map).
|
|
439
|
+
|
|
440
|
+
### 2.8 Render errors and `security.exposeErrors`
|
|
441
|
+
|
|
442
|
+
There are two render-error surfaces:
|
|
443
|
+
|
|
444
|
+
- **Renderer `_error` nodes** — emitted by the render engine for spec/resolution failures. When `security.exposeErrors !== false`, `MythikRenderer` renders the `_error` placeholder and writes diagnostics to `/ui/renderErrors`.
|
|
445
|
+
- **Thrown primitive/component exceptions** — caught by `MythikRenderer`'s render error boundary. In development with `exposeErrors !== false`, the boundary shows a visible overlay with the error message and component stack. In production or with `exposeErrors: false`, it renders a neutral placeholder without details.
|
|
446
|
+
|
|
447
|
+
The boundary resets when the `spec` prop changes. A corrected spec can recover from a previous thrown render exception without remounting the host app.
|
|
448
|
+
|
|
449
|
+
Host setup:
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
const svc = createMythik({ security: { exposeErrors: false } });
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Spec authors do not configure this in JSON specs; it is a host/runtime security setting.
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
## 3. Server API Contracts
|
|
460
|
+
|
|
461
|
+
The Mythik server (ApiSpec-driven) exposes a set of conventions for request/response shapes, auto-generated routes, and security invariants. This section documents the contracts so consumer specs + AI can compose correctly without reverse-engineering `server.ts`.
|
|
462
|
+
|
|
463
|
+
### 3.1 CRUD — one endpoint, three routes 🔴 BLOCKER #3
|
|
464
|
+
|
|
465
|
+
**Contract:** a single endpoint declaration with `crud: { table, primaryKey, insertable, updatable }` generates **three** routes automatically:
|
|
466
|
+
|
|
467
|
+
- `POST <path>` — insert a new row (body filtered to `insertable` fields)
|
|
468
|
+
- `PUT <path>/:id` — update a row (body filtered to `updatable` fields, `:id` matches `primaryKey`)
|
|
469
|
+
- `DELETE <path>/:id` — delete a row (by primary key)
|
|
470
|
+
|
|
471
|
+
**Canonical declaration:**
|
|
472
|
+
|
|
473
|
+
```json
|
|
474
|
+
{
|
|
475
|
+
"endpoints": {
|
|
476
|
+
"rooms": {
|
|
477
|
+
"path": "/api/rooms",
|
|
478
|
+
"crud": {
|
|
479
|
+
"table": "Rooms",
|
|
480
|
+
"primaryKey": "id",
|
|
481
|
+
"insertable": ["name", "capacity", "location"],
|
|
482
|
+
"updatable": ["name", "capacity", "location"]
|
|
483
|
+
},
|
|
484
|
+
"audit": {
|
|
485
|
+
"createdBy": "createdByUser",
|
|
486
|
+
"createdAt": "createdAt",
|
|
487
|
+
"updatedBy": "updatedByUser",
|
|
488
|
+
"updatedAt": "updatedAt"
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
This ONE endpoint produces three Express routes. Do NOT declare three endpoints.
|
|
496
|
+
|
|
497
|
+
**Anti-pattern (collides):**
|
|
498
|
+
|
|
499
|
+
```json
|
|
500
|
+
{
|
|
501
|
+
"endpoints": {
|
|
502
|
+
"room-create": { "path": "/api/rooms", "method": "POST", "crud": { ... } },
|
|
503
|
+
"room-update": { "path": "/api/rooms/:id", "method": "PUT", "crud": { ... } },
|
|
504
|
+
"room-delete": { "path": "/api/rooms/:id", "method": "DELETE", "crud": { ... } }
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Each endpoint's `crud:{}` is processed independently. `room-update` at `/api/rooms/:id` + auto-append `/:id` → `PUT /api/rooms/:id/:id` (broken). Every CRUD endpoint also registers the POST route at `<path>` — collisions compound. Consumer-facing symptom: routes clash in Express; requests return 404 or match the wrong handler.
|
|
510
|
+
|
|
511
|
+
**`filterFields` behavior:** fields in the request body NOT listed in `insertable` (for POST) or `updatable` (for PUT) are silently dropped. This is a security feature — clients cannot inject arbitrary columns (e.g., `isAdmin: true`). Audit fields should NOT appear in `insertable`/`updatable` — the framework writes them post-filter (see audit below).
|
|
512
|
+
|
|
513
|
+
**Audit config — un-spoofable fields:** when `endpoint.audit` is configured, the server writes the JWT-derived user + timestamp to the audit columns on INSERT/UPDATE. These fields bypass `filterFields` (framework writes them after filtering). Clients cannot forge `createdBy` / `updatedBy` / `createdAt` / `updatedAt`. This is CV4 in the 2026-04 experiment validations — confirmed secure-by-design.
|
|
514
|
+
|
|
515
|
+
Implementation: `packages/server/src/server.ts:549-686` (the `if (endpoint.crud)` block — POST at 585, PUT at 640, DELETE at 685, audit field injection at 568-571 and 593-596).
|
|
516
|
+
|
|
517
|
+
### 3.2 `/api/auth/login` body contract
|
|
518
|
+
|
|
519
|
+
**Expected request body:** `{ "username": string, "password": string }` — **not `email`**.
|
|
520
|
+
|
|
521
|
+
**Response on missing fields:** HTTP 400 with:
|
|
522
|
+
|
|
523
|
+
```json
|
|
524
|
+
{ "error": { "code": "VALIDATION_FAILED", "message": "username and password are required" } }
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Response on success:** JWT + refresh token shape (exact fields depend on provider config; check your `auth.provider` response shape).
|
|
528
|
+
|
|
529
|
+
**Why `username` and not `email`:** the framework supports non-email username auth (many internal apps use employee ID, LDAP username, etc.). Consumer specs with email convention should use `loginBody` template to map at the spec level:
|
|
530
|
+
|
|
531
|
+
```json
|
|
532
|
+
{
|
|
533
|
+
"auth": {
|
|
534
|
+
"loginBody": {
|
|
535
|
+
"username": { "$state": "/login/email" },
|
|
536
|
+
"password": { "$state": "/login/password" }
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
The `loginBody` template is resolved at login dispatch — consumer's email field value becomes the server's `username` field value. Server sees `{ username: <email-string>, password: <pw> }` and validates against the users table's `usernameColumn` (which can be an email column).
|
|
543
|
+
|
|
544
|
+
Implementation: `packages/server/src/server.ts:104-116`.
|
|
545
|
+
|
|
546
|
+
### 3.3 Query endpoint response envelope
|
|
547
|
+
|
|
548
|
+
**Contract:** all query endpoints (type `query` in ApiSpec) return responses in this envelope shape:
|
|
549
|
+
|
|
550
|
+
```json
|
|
551
|
+
{
|
|
552
|
+
"data": [ /* row objects */ ],
|
|
553
|
+
"total": 42,
|
|
554
|
+
"page": 1,
|
|
555
|
+
"pageSize": 20,
|
|
556
|
+
"totals": { "total_amount": 1250.50 }
|
|
557
|
+
}
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
- `data` — always present, always an array (may be empty)
|
|
561
|
+
- `total`, `page`, `pageSize` — present when the endpoint has pagination config
|
|
562
|
+
- `totals` — present when the endpoint has totals config (SUM/AVG aggregates)
|
|
563
|
+
|
|
564
|
+
**Consumer contract:** the envelope is NOT auto-unwrapped. Specs reading the response must target `response.data`:
|
|
565
|
+
|
|
566
|
+
```json
|
|
567
|
+
{
|
|
568
|
+
"action": "fetch",
|
|
569
|
+
"params": {
|
|
570
|
+
"url": "/api/rooms/query",
|
|
571
|
+
"target": "/rooms"
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
Setting `target: "/rooms"` writes the entire envelope to `/rooms`. Consumer reads via `$state: "/rooms/data"` at consumption sites.
|
|
577
|
+
|
|
578
|
+
If you only want the data array in state, use a two-step action chain: first `fetch` with no `target` (captures in transient), second `setState` writing `response.data` to your desired path.
|
|
579
|
+
|
|
580
|
+
Implementation: `packages/server/src/server.ts:497-511` (envelope construction: `data` at 497, optional `total`/`page`/`pageSize` at 499-504, optional `totals` at 506-509).
|
|
581
|
+
|
|
582
|
+
### 3.4 `scopeFilter` + `bypassRoles`
|
|
583
|
+
|
|
584
|
+
**`scopeFilter`:** a SQL WHERE clause template injected server-side on query + update + delete operations, resolved against JWT claims. Prevents cross-tenant row access.
|
|
585
|
+
|
|
586
|
+
**Example** (conceptual):
|
|
587
|
+
|
|
588
|
+
```json
|
|
589
|
+
{
|
|
590
|
+
"endpoints": {
|
|
591
|
+
"rooms": {
|
|
592
|
+
"scopeFilter": "tenant_id = :jwt.tenant_id",
|
|
593
|
+
"bypassRoles": ["admin"]
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
For role `admin`, the filter is NOT applied (admin sees all rows). Any other role sees only rows matching their JWT's `tenant_id` claim.
|
|
600
|
+
|
|
601
|
+
**Security invariant:** `scopeFilter` applies to UPDATE and DELETE, not just SELECT. A user cannot update or delete rows outside their scope — the filter is appended to the WHERE clause of those queries. Combined with audit fields (§3.1), this gives a defense-in-depth posture for multi-tenant apps.
|
|
602
|
+
|
|
603
|
+
Implementation: `packages/server/src/server.ts:607-630` (scopeFilter in PUT), `:653-675` (scopeFilter in DELETE), plus equivalent logic in query endpoints (search `buildScopeWhereClause` for all call sites).
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## 4. Matcher Semantics
|
|
608
|
+
|
|
609
|
+
### 4.1 `authDomains` — hostname-only 🟢 BLOCKER #5
|
|
610
|
+
|
|
611
|
+
**Contract:** auth headers (Bearer tokens) are auto-injected on fetch/submitForm requests when the URL's hostname matches any entry in `authDomains`. Port is stripped; only the hostname is compared.
|
|
612
|
+
|
|
613
|
+
**Matching rules:**
|
|
614
|
+
|
|
615
|
+
| `authDomains` entry | Matches | Does NOT match |
|
|
616
|
+
|---|---|---|
|
|
617
|
+
| `"api.example.com"` | `https://api.example.com/...` (any port) | `https://notapi.example.com`, `https://example.com` |
|
|
618
|
+
| `"example.com"` | `https://example.com`, `https://api.example.com`, `https://foo.example.com` (exact + subdomain) | `https://notexample.com` |
|
|
619
|
+
| `"localhost"` | `http://localhost:5173/...`, `http://localhost:3010/...`, `http://localhost/...` | `http://127.0.0.1` |
|
|
620
|
+
| `"localhost:5173"` | nothing (port is stripped from the URL side, but the domain entry literally contains `:5173` which is never the hostname of any URL) | everything |
|
|
621
|
+
|
|
622
|
+
**Mechanism:** `new URL(fetchUrl).hostname` comparison. Port stripping is a side-effect of the URL API — `.hostname` excludes the port. Subdomain matching: an entry `"example.com"` matches any URL whose hostname ends with `.example.com` (note the leading dot in the comparison — prevents `"api.com"` from matching `"notapi.com"`).
|
|
623
|
+
|
|
624
|
+
**Dev-mode guidance:** configure `authDomains: ["localhost"]` (no port). Tokens inject on any localhost port during dev.
|
|
625
|
+
|
|
626
|
+
**URL scheme filter:** only `http://` and `https://` URLs are considered. Relative paths (`/api/rooms`), `file:`, `data:`, and other schemes return `false` before matching — auth headers are not injected on those requests.
|
|
627
|
+
|
|
628
|
+
Implementation: `packages/core/src/fetch/interceptors/auth.ts:17-28`.
|
|
629
|
+
|
|
630
|
+
### 4.2 Contract URL template matching
|
|
631
|
+
|
|
632
|
+
When ApiSpec endpoints declare URL templates (e.g., `/api/items/:id`), the Contract subsystem matches incoming requests against the templates and extracts params. The same expression engine resolves `$state`, `$template`, `$auth` used elsewhere in the framework.
|
|
633
|
+
|
|
634
|
+
**Contract:** template resolution uses the same pipeline as fetch action params. Path params, query params, and body expressions all go through the resolver — no special "contract-only" expression evaluation rules.
|
|
635
|
+
|
|
636
|
+
Implementation: `packages/core/src/contract/matcher.ts` (matching) + `packages/core/src/contract/extractor.ts` (param extraction) + `packages/core/src/contract/engine.ts` (orchestration).
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
## 5. Store Coordination Patterns
|
|
641
|
+
|
|
642
|
+
The framework coordinates state writes across the store, expression resolver, action dispatcher, and persistence layer in specific orders. Understanding these orders closes the gap between "my action fired" and "my state reads the data I expected".
|
|
643
|
+
|
|
644
|
+
### 5.1 `dispatchAction` — row-write-then-dispatch
|
|
645
|
+
|
|
646
|
+
**Contract:** when a user triggers a row interaction (column action OR direct `onRowClick`), the framework:
|
|
647
|
+
|
|
648
|
+
1. Writes the clicked row object to `/ui/selectedRow` via the `createRowDispatcher` helper at `packages/react/src/runtime/row-dispatcher.ts`. Triggered by column actions AND direct `onRowClick`.
|
|
649
|
+
2. Dispatches the action chain (with `$state` / `$template` params resolved lazily at click time via `lazyActionPaths` — see §1.3)
|
|
650
|
+
|
|
651
|
+
The order is fixed in the `createRowDispatcher` helper (used by `MythikRenderer`'s table-specific wiring):
|
|
652
|
+
|
|
653
|
+
```ts
|
|
654
|
+
const dispatchWithContext = createContextDispatcher<Record<string, unknown>>(
|
|
655
|
+
store,
|
|
656
|
+
dispatchAction,
|
|
657
|
+
RESERVED_PATHS.SELECTED_ROW,
|
|
658
|
+
);
|
|
659
|
+
|
|
660
|
+
return (binding, row) => {
|
|
661
|
+
dispatchWithContext(binding, row || undefined);
|
|
662
|
+
};
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
**Implication:** any `$state: "/ui/selectedRow/..."` read that fires AFTER this function returns (subsequent actions in the chain, modal content rendered in response, etc.) sees the fresh row. The action's own params also resolve lazily at click time (via `lazyActionPaths` — see §1.3), so `$state: "/ui/selectedRow/..."` in `onPress` / `onRowClick` params correctly reads the freshly-written row.
|
|
666
|
+
|
|
667
|
+
**Consumer consequences — patterns that work cleanly:**
|
|
668
|
+
|
|
669
|
+
- Open a modal on row click → modal content reads `/ui/selectedRow` at render → fresh row
|
|
670
|
+
- Fire a second action AFTER `openModal` in the same onPress chain → reads fresh row
|
|
671
|
+
- Template interpolation inside the modal (`$template` with `/ui/selectedRow/*`) → fresh row
|
|
672
|
+
|
|
673
|
+
**Patterns that break:**
|
|
674
|
+
|
|
675
|
+
- Multiple parallel tables writing to `/ui/selectedRow` and expecting isolation (last write wins)
|
|
676
|
+
- Any code path that writes to `/ui/selectedRow` directly (framework reserved — see rule 241)
|
|
677
|
+
|
|
678
|
+
### 5.2 `dataSources` lifecycle
|
|
679
|
+
|
|
680
|
+
**Status marker:** ✅ SHIPPED v0.1.0 Item E. Wired via internal `mountSpecRuntime` helper called from `MythikRenderer` (web + RN) per spec mount. See §9 for full lifecycle ordering and re-mount safety.
|
|
681
|
+
|
|
682
|
+
**Contract:**
|
|
683
|
+
|
|
684
|
+
- **Mount:** at spec mount, the framework instantiates a DataSourcesEngine with the spec's `dataSources` config + state store + resolver
|
|
685
|
+
- **Dependency tracking:** the engine runs `scanDeps` on each dataSource's `url`, `params`, `headers` to extract referenced state paths. These become the dataSource's deps
|
|
686
|
+
- **Auto re-fetch:** when the store fires a write to any declared dep, the engine re-fetches the dataSource (debounced to coalesce rapid writes when `debounce` is configured)
|
|
687
|
+
- **`emptyWhileLoading`:** when `true`, the target state path is cleared to `null` at fetch start. When `false` (default), the old data stays visible during the fetch
|
|
688
|
+
- **Manual refresh:** the `refreshDataSource` action forces a re-fetch by dataSource id:
|
|
689
|
+
```json
|
|
690
|
+
{ "action": "refreshDataSource", "params": { "id": "rooms" } }
|
|
691
|
+
```
|
|
692
|
+
- **Loading/error paths:** `/{target}Loading` + `/{target}Error` are auto-managed (see §2.4)
|
|
693
|
+
- **`trigger: "auto"` vs `"manual"`:** auto-reactive by default; `manual` skips auto re-fetch (only `refreshDataSource` action triggers)
|
|
694
|
+
|
|
695
|
+
**Example declaration:**
|
|
696
|
+
|
|
697
|
+
```json
|
|
698
|
+
{
|
|
699
|
+
"dataSources": {
|
|
700
|
+
"rooms": {
|
|
701
|
+
"url": "/api/rooms/query",
|
|
702
|
+
"params": { "filter": { "$state": "/filters/status" } },
|
|
703
|
+
"target": "/rooms",
|
|
704
|
+
"emptyWhileLoading": false,
|
|
705
|
+
"trigger": "auto",
|
|
706
|
+
"debounce": 300
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
On any write to `/filters/status`, the engine re-fetches (300ms debounce) and writes the response envelope (§3.3) to `/rooms`. Consumer reads the list via `$state: "/rooms/data"`.
|
|
713
|
+
|
|
714
|
+
Implementation: `packages/core/src/data/data-sources.ts` (engine factory, `scanDeps` invocation, `refreshDataSource` action definition).
|
|
715
|
+
|
|
716
|
+
### 5.3 `derive` evaluation order
|
|
717
|
+
|
|
718
|
+
**Status marker:** ✅ SHIPPED v0.1.0 Item E. Wired via internal `mountSpecRuntime` helper. See §9 for re-entrant safety, error degradation, and state protection details.
|
|
719
|
+
|
|
720
|
+
**Contract:**
|
|
721
|
+
|
|
722
|
+
- **Mount:** the framework builds a dependency graph from `spec.derive` entries, runs topological sort (`packages/core/src/derive/evaluator.ts:26`), throws `Circular dependency detected in derive` if cyclic
|
|
723
|
+
- **Dirty tracking:** on every state write, only the subset of derive nodes transitively depending on the changed path re-evaluate
|
|
724
|
+
- **`protectedPaths`:** the state guard blocks actions from writing directly to paths owned by a derive. Actions that `setState` on a protected path are rejected (the state guard returns the write path to the caller via `getProtectedPaths`)
|
|
725
|
+
- **Order vs `initialActions`:** derive evaluates synchronously at mount (in topological order, before `initialActions` async IIFE runs). `initialActions` writes state independently; the derive engine subscribes to the store and recomputes reactively when those writes land. No ordering coordination needed — engines self-sufficient. dataSources with URL templates depending on `initialActions` output use skip-on-undefined-URL-deps (§9) to defer the initial fetch until deps resolve
|
|
726
|
+
|
|
727
|
+
**Example declaration:**
|
|
728
|
+
|
|
729
|
+
```json
|
|
730
|
+
{
|
|
731
|
+
"derive": {
|
|
732
|
+
"/stats/activeCount": {
|
|
733
|
+
"$array": "count",
|
|
734
|
+
"source": { "$state": "/items" },
|
|
735
|
+
"where": { "$eq": [{ "$item": "status" }, "active"] }
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
`/stats/activeCount` is read-only from consumer specs (attempts to `setState` on it are blocked). Writes to `/items` trigger re-evaluation.
|
|
742
|
+
|
|
743
|
+
Implementation: `packages/core/src/derive/evaluator.ts` (`topologicalSort` at line 26, cycle detection at line 37-39, `getProtectedPaths` at line 19 + 116).
|
|
744
|
+
|
|
745
|
+
### 5.4 SpecStore layering — `save` vs `saveVersion` vs CLI patch
|
|
746
|
+
|
|
747
|
+
The persistence layer has distinct paths used at different levels. Understanding the layering prevents bypassing validation and keeps spec writes inside the validated CLI / engine path.
|
|
748
|
+
|
|
749
|
+
- **`store.save(id, doc)`** - low-level persistence primitive. Accepts `doc: unknown`. No validation. Called by validated orchestration after checks succeed. **Never called from application code** - treat as `@internal`. Calling `store.save()` from your app bypasses validation and produces silently-broken specs.
|
|
750
|
+
- **`store.saveVersion(id, doc, meta)`** - versioned write. Writes a row to `screen_versions` table and updates the current spec. Enables diff/rollback/promote/bisect.
|
|
751
|
+
- **`SpecEngine.patch(id, patches)`** - validated orchestration. Applies RFC-6902 patches, runs DocumentHandler validation, short-circuits on error, and persists the patched document through `store.save`.
|
|
752
|
+
- **CLI/API `mythik push` / `runPush`** - validates and handles `--author` / `author` by writing through `saveVersion` when the resolved store is versioned.
|
|
753
|
+
- **CLI/API `mythik patch` / `runPatch`** - uses `SpecEngine.patch` for patch application + validation. Without `author`, it persists through the normal `store.save` path. With a versioned store + `author`, it captures the patched document and writes once through `saveVersion`, so lazy bootstrap preserves the pre-patch current spec as v1 and the patch becomes the next version. JSON/TOON success output includes `versioned: boolean` and `version?: number`.
|
|
754
|
+
|
|
755
|
+
**Consumer rule (to be enforced by Item I linter):** never call `store.save()` from application code. Use:
|
|
756
|
+
|
|
757
|
+
- `mythik push <id>` / `mythik patch <id>` for interactive/shell work
|
|
758
|
+
- `runPush` / `runPatch` from `mythik-cli/api` for programmatic work (Item F exposes these as public exports)
|
|
759
|
+
|
|
760
|
+
Implementation:
|
|
761
|
+
|
|
762
|
+
- `packages/core/src/spec-engine/types.ts:8-13` (SpecStore interface — `save`, `load`, `list`, `delete`)
|
|
763
|
+
- `packages/core/src/spec-engine/engine.ts` (patch validate and base persist flow)
|
|
764
|
+
- `packages/cli/src/commands/push.ts` (CLI push versioning path)
|
|
765
|
+
- `packages/cli/src/commands/patch.ts` (CLI patch versioning path)
|
|
766
|
+
|
|
767
|
+
**Implementation location per store type** (as of v0.1.0):
|
|
768
|
+
|
|
769
|
+
- Browser-safe stores (`MemorySpecStore`, `SupabaseSpecStore`, `MemoryVersionedSpecStore`, `SupabaseVersionedSpecStore`, `MemoryEnvironmentStore`, `SupabaseEnvironmentStore`) — import from `mythik` (main entry).
|
|
770
|
+
- Node-only stores (`FileSpecStore`, `SqlServerSpecStore`, `SqlServerVersionedSpecStore`, `SqlServerEnvironmentStore`) — import from `mythik/server`.
|
|
771
|
+
|
|
772
|
+
The `SpecStore` interface contract (signature, behavior, save-vs-validate layering) is identical across entries. Only the import path changes.
|
|
773
|
+
|
|
774
|
+
### 5.5 Transaction rollback mechanics
|
|
775
|
+
|
|
776
|
+
**Contract:** at dispatch start, the transaction engine captures a store snapshot via `store.getSnapshot()` immediately before the `optimistic` phase runs. If the network call rejects (`onError`), the snapshot is restored before `onError` actions execute.
|
|
777
|
+
|
|
778
|
+
**Phase rollback semantics:**
|
|
779
|
+
|
|
780
|
+
| Phase | Rolled back on error? | Runs if network fails? |
|
|
781
|
+
|---|---|---|
|
|
782
|
+
| `before` | **No** — side-effects persist (closeModal, navigate) | Yes — runs first, before any network |
|
|
783
|
+
| `optimistic` | **Yes** — state snapshot restored | Yes — applied, then potentially reverted |
|
|
784
|
+
| `onSuccess` | No — only runs if network succeeded | No — skipped on network failure |
|
|
785
|
+
| `onError` | No — runs AFTER rollback | Yes — sees restored state |
|
|
786
|
+
|
|
787
|
+
**Implications:**
|
|
788
|
+
|
|
789
|
+
- Do NOT put data mutations in `before` — they persist through rollback
|
|
790
|
+
- Do NOT put navigation in `optimistic` — rollback does not un-navigate
|
|
791
|
+
- `onError` sees the pre-optimistic state (rollback has already happened by the time onError runs)
|
|
792
|
+
|
|
793
|
+
Implementation: `packages/core/src/actions/transaction-engine.ts` (phases: `before` at line 47-50, snapshot at 52-53, `optimistic` at 55-58, `onSuccess` at 79-81, `onError` at 94-99).
|
|
794
|
+
|
|
795
|
+
---
|
|
796
|
+
|
|
797
|
+
## 6. Workflow Paradigms
|
|
798
|
+
|
|
799
|
+
The framework supports two axes of workflow choice: **how you modify specs** (push vs patch) and **how you track history** (git vs DB versioning). Each axis has independent trade-offs; most teams pick one paradigm per axis and commit to it.
|
|
800
|
+
|
|
801
|
+
### 6.1 Push vs patch — file-first vs DB-first
|
|
802
|
+
|
|
803
|
+
**Push paradigm:**
|
|
804
|
+
|
|
805
|
+
- Specs live in git under `specs/*.json`
|
|
806
|
+
- Modify locally, run `mythik push <id>`, CLI sends the full spec doc to the DB
|
|
807
|
+
- Diff-reviewable in CI (normal git diff on the JSON file)
|
|
808
|
+
- Full-spec bandwidth cost per write
|
|
809
|
+
|
|
810
|
+
**Patch paradigm:**
|
|
811
|
+
|
|
812
|
+
- Specs live in the DB; local files are optional (working copy)
|
|
813
|
+
- Modify via `mythik patch <id> --from-file patch.json` for shell-safe surgical writes
|
|
814
|
+
- ~11x token efficiency vs full push (framework-internal measurement for typical single-element edits)
|
|
815
|
+
- Requires `mythik pull <id>` to sync any local `specs/*.json` snapshot after a DB patch
|
|
816
|
+
|
|
817
|
+
**Decision table:**
|
|
818
|
+
|
|
819
|
+
| Use case | Recommended paradigm | Rationale |
|
|
820
|
+
|---|---|---|
|
|
821
|
+
| Specs committed to git, CI gating | Push | Git log is the source of truth |
|
|
822
|
+
| Single-spec surgical edit | Patch | Token efficiency |
|
|
823
|
+
| Runtime admin UI editing specs | Patch (DB-first) | DB IS the source of truth |
|
|
824
|
+
| Multi-environment deploy (dev→staging→prod) | Push + DB versioning (§6.2) | Git for dev, versioned promote for env move |
|
|
825
|
+
| Large refactor across many specs | Push | Bulk easier; patch chains get fragile |
|
|
826
|
+
|
|
827
|
+
**Mixing warning:** do not `patch` and later `push` from stale `specs/*.json`. In DB-first workflows, the DB is source of truth; local files are bootstrap/snapshots only until refreshed from `mythik pull <id>`. Current CLI pull exports to stdout, so write that output back with a UTF-8-safe shell/CI step before committing local specs.
|
|
828
|
+
|
|
829
|
+
**Input note:** `mythik patch --from-file <path>` is the preferred cross-shell path. `--from-file <path>` wins over ambient non-TTY stdin; use `--from-file -` or pipe without `--from-file` when stdin is intentional.
|
|
830
|
+
|
|
831
|
+
### 6.2 Git-backed vs DB-versioned history
|
|
832
|
+
|
|
833
|
+
**Git-backed history:**
|
|
834
|
+
|
|
835
|
+
- Specs in repo, `git log` + `git blame` serve as audit trail
|
|
836
|
+
- No `--author` flag needed on push/patch
|
|
837
|
+
- CLI writes via `store.save` (unversioned path, see §5.4)
|
|
838
|
+
- Best for: single-env apps, dev-loop iteration, specs-as-code
|
|
839
|
+
|
|
840
|
+
**DB-versioned history:**
|
|
841
|
+
|
|
842
|
+
- `--author` flag on push/patch activates `store.saveVersion` (see §5.4)
|
|
843
|
+
- Writes a row to `screen_versions` table (requires the declarative storage schema from `ai-context.md` Storage Setup)
|
|
844
|
+
- Enables: `mythik diff <id>`, `mythik rollback <id>`, `mythik promote <from>→<to>`, `mythik bisect`
|
|
845
|
+
- Audit trail queryable in SQL (who changed what, when)
|
|
846
|
+
- Best for: multi-environment deployments, runtime admin UI (admin edits bypass git), compliance requirements
|
|
847
|
+
|
|
848
|
+
**When to enable DB versioning:**
|
|
849
|
+
|
|
850
|
+
| Signal | Recommendation |
|
|
851
|
+
|---|---|
|
|
852
|
+
| Single dev env, specs in git | Skip. Git is enough. |
|
|
853
|
+
| Separate dev + staging + prod DBs | Enable. Use `mythik promote` for env moves. |
|
|
854
|
+
| Admin UI that edits specs at runtime | Enable. Git can't capture runtime edits. |
|
|
855
|
+
| Compliance (SOX, HIPAA, etc. asking "who changed screen X on date Y") | Enable. Native SQL audit query beats git log. |
|
|
856
|
+
|
|
857
|
+
**Storage note:** DB versioning requires the `screen_versions` and `screen_environments` tables. Mythik does not auto-create them; apply the declarative schema from `ai-context.md` Storage Setup in the consumer database before using versioned stores.
|
|
858
|
+
|
|
859
|
+
---
|
|
860
|
+
|
|
861
|
+
## 7. Common Scenarios
|
|
862
|
+
|
|
863
|
+
Each scenario: problem shape → root cause → canonical solution.
|
|
864
|
+
|
|
865
|
+
### 7.1 Reading row data in a column action
|
|
866
|
+
|
|
867
|
+
**Problem:** column action needs to read the clicked row's id (or any other field).
|
|
868
|
+
|
|
869
|
+
**Root:** §1.3 — column action params resolve lazily at press time; framework writes the clicked row to `/ui/selectedRow` before dispatch.
|
|
870
|
+
|
|
871
|
+
**Canonical solution:** read `/ui/selectedRow/*` directly via `$state` in the action's params.
|
|
872
|
+
|
|
873
|
+
```json
|
|
874
|
+
"onPress": [{
|
|
875
|
+
"action": "openModal",
|
|
876
|
+
"params": {
|
|
877
|
+
"id": "edit-modal",
|
|
878
|
+
"itemId": { "$state": "/ui/selectedRow/id" }
|
|
879
|
+
}
|
|
880
|
+
}]
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
The `$state` resolves at click time against the just-written `/ui/selectedRow`.
|
|
884
|
+
|
|
885
|
+
**Alternative (two-step pattern, still valid):** open a modal first; the modal content reads `/ui/selectedRow` separately. Useful when the action chain is generic and the consumer reads row context downstream.
|
|
886
|
+
|
|
887
|
+
```json
|
|
888
|
+
"onPress": [
|
|
889
|
+
{ "action": "openModal", "params": { "id": "edit-modal" } }
|
|
890
|
+
]
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
### 7.2 Why my `$state` in action params used to resolve stale (pre-v0.1.0)
|
|
894
|
+
|
|
895
|
+
**Pre-v0.1.0 problem:** `{ action: "setState", params: { value: { "$state": "/some/path" } } }` inside a column action used the render-time value, not the click-time value. Bug F9 in the v49 audit.
|
|
896
|
+
|
|
897
|
+
**v0.1.0 fix:** column action params now resolve at press time via `lazyActionPaths` declaration on the table primitive (see §1.3).
|
|
898
|
+
|
|
899
|
+
**If your spec used the two-step workaround for this bug:** both the workaround and the direct `$state` pattern now work. Direct `$state` is canonical going forward; the workaround remains valid (no migration required).
|
|
900
|
+
|
|
901
|
+
**If your spec was hitting the bug without a workaround:** the bug is silently fixed. No code change required on your end.
|
|
902
|
+
|
|
903
|
+
### 7.3 My CRUD endpoint collides with itself
|
|
904
|
+
|
|
905
|
+
**Problem:** declared `room-create`, `room-update`, `room-delete` endpoints, each with `crud:{}`. Server logs show route collision or `:id/:id` double-append.
|
|
906
|
+
|
|
907
|
+
**Root:** §3.1 — each `crud:{}` declaration synthesizes three routes. Three endpoints → nine routes → collision.
|
|
908
|
+
|
|
909
|
+
**Solution:** ONE endpoint at `/api/rooms` with `crud: { insertable, updatable, table, primaryKey }`. Framework synthesizes `POST /api/rooms`, `PUT /api/rooms/:id`, `DELETE /api/rooms/:id`.
|
|
910
|
+
|
|
911
|
+
### 7.4 Auth works in prod but not dev with `localhost:5173`
|
|
912
|
+
|
|
913
|
+
**Problem:** `authDomains: ["localhost:5173"]` silently fails to inject auth headers.
|
|
914
|
+
|
|
915
|
+
**Root:** §4.1 — matcher uses `parsed.hostname` (strips port). Entry `"localhost:5173"` never matches any URL's hostname (which is just `"localhost"`).
|
|
916
|
+
|
|
917
|
+
**Solution:** `authDomains: ["localhost"]`. Matches all localhost ports (5173, 3010, etc.).
|
|
918
|
+
|
|
919
|
+
### 7.5 Wiring a reactive data source with a debounced filter
|
|
920
|
+
|
|
921
|
+
**Status:** post-Item-E only. Pre-Item-E, use `initialActions + fetch + setState` instead (see `ai-context.md` fetch/dataSources decision guide).
|
|
922
|
+
|
|
923
|
+
**Problem (post-Item-E):** want a rooms list that re-fetches when a status filter changes, debounced to avoid hammering the server.
|
|
924
|
+
|
|
925
|
+
**Root:** §5.2 — `dataSources` engine tracks deps via `scanDeps`, auto re-fetches on dep writes, supports `debounce`.
|
|
926
|
+
|
|
927
|
+
**Solution:**
|
|
928
|
+
|
|
929
|
+
```json
|
|
930
|
+
{
|
|
931
|
+
"dataSources": {
|
|
932
|
+
"rooms": {
|
|
933
|
+
"url": "/api/rooms/query",
|
|
934
|
+
"params": { "status": { "$state": "/filters/status" } },
|
|
935
|
+
"target": "/rooms",
|
|
936
|
+
"debounce": 300
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
Any write to `/filters/status` triggers re-fetch after 300ms idle. Read `/rooms/data` (envelope — §3.3) for the list.
|
|
943
|
+
|
|
944
|
+
### 7.6 Choosing push vs patch for my team's workflow
|
|
945
|
+
|
|
946
|
+
**Problem:** team unsure whether to commit specs to git (push flow) or edit directly in DB (patch flow).
|
|
947
|
+
|
|
948
|
+
**Root:** §6.1 — two valid paradigms with distinct trade-offs.
|
|
949
|
+
|
|
950
|
+
**Solution (decision tree):**
|
|
951
|
+
|
|
952
|
+
- Specs change via PR review? → **Push.**
|
|
953
|
+
- Specs change via admin UI at runtime? → **Patch** (DB is truth).
|
|
954
|
+
- Multiple environments with promote flow? → **Push to dev + DB versioning + `mythik promote` for env moves.**
|
|
955
|
+
- Single dev, fast iteration? → Either works; default to push (git is cheap).
|
|
956
|
+
|
|
957
|
+
### 7.7 Login form with email convention
|
|
958
|
+
|
|
959
|
+
**Problem:** app uses email as identifier; `/api/auth/login` expects `username`.
|
|
960
|
+
|
|
961
|
+
**Root:** §3.2 — server expects `{ username, password }` by design. Maps via `loginBody` template.
|
|
962
|
+
|
|
963
|
+
**Solution:**
|
|
964
|
+
|
|
965
|
+
```json
|
|
966
|
+
{
|
|
967
|
+
"auth": {
|
|
968
|
+
"loginBody": {
|
|
969
|
+
"username": { "$state": "/login/email" },
|
|
970
|
+
"password": { "$state": "/login/password" }
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
Login spec binds input to `/login/email`; `loginBody` maps it to `username` at dispatch. Server sees `{ username: <email>, password: <pw> }`, validates against users table.
|
|
977
|
+
|
|
978
|
+
---
|
|
979
|
+
|
|
980
|
+
## 8. Appendix
|
|
981
|
+
|
|
982
|
+
### 8.1 File path references by component
|
|
983
|
+
|
|
984
|
+
**Core renderer:**
|
|
985
|
+
- `packages/core/src/renderer/engine.ts:167-186` — `resolvePropsWithContext` (eager prop resolution)
|
|
986
|
+
- `packages/core/src/renderer/engine.ts:996-1049` — `element.on` lazy path + `$prop` special-case + repeat eager wrapping
|
|
987
|
+
- `packages/react/src/MythikRenderer.tsx:284-297` — table-specific wiring (createRowDispatcher invocation + onRowClick ActionBinding wrap)
|
|
988
|
+
- `packages/react/src/runtime/row-dispatcher.ts` — `createRowDispatcher` helper (row-write-then-dispatch implementation)
|
|
989
|
+
|
|
990
|
+
**Expression handlers:**
|
|
991
|
+
- `packages/core/src/expressions/handlers/prop.ts` — `$prop` cascade
|
|
992
|
+
- `packages/core/src/expressions/handlers/template.ts` — `$template`
|
|
993
|
+
- `packages/core/src/expressions/handlers/bind.ts` — `$item`, `$index`, `$bindItem`
|
|
994
|
+
|
|
995
|
+
**Actions + transactions:**
|
|
996
|
+
- `packages/core/src/actions/dispatcher.ts:103-116` — openModal / closeModal / openDrawer / closeDrawer handlers
|
|
997
|
+
- `packages/core/src/actions/transaction-engine.ts` — transaction phases
|
|
998
|
+
|
|
999
|
+
**Data + derive engines:**
|
|
1000
|
+
- `packages/core/src/data/data-sources.ts` — dataSources engine (post-Item-E wire)
|
|
1001
|
+
- `packages/core/src/derive/evaluator.ts` — derive engine (post-Item-E wire)
|
|
1002
|
+
|
|
1003
|
+
**Forms + device:**
|
|
1004
|
+
- `packages/core/src/forms/engine.ts` — form bindings + reserved state paths
|
|
1005
|
+
- `packages/core/src/device/context.ts` — DeviceContext interface
|
|
1006
|
+
|
|
1007
|
+
**Fetch + auth:**
|
|
1008
|
+
- `packages/core/src/fetch/interceptors/auth.ts:17-28` — authDomains matcher
|
|
1009
|
+
|
|
1010
|
+
**Server:**
|
|
1011
|
+
- `packages/server/src/server.ts:104-116` — `/api/auth/login` endpoint
|
|
1012
|
+
- `packages/server/src/server.ts:497-511` — query envelope
|
|
1013
|
+
- `packages/server/src/server.ts:549-686` — CRUD auto-routes (POST 585, PUT 640, DELETE 685, audit injection 568-571 + 593-596)
|
|
1014
|
+
- `packages/server/src/server.ts:607-630` — scopeFilter in PUT
|
|
1015
|
+
- `packages/server/src/server.ts:653-675` — scopeFilter in DELETE
|
|
1016
|
+
|
|
1017
|
+
**Spec engine + stores:**
|
|
1018
|
+
- `packages/core/src/spec-engine/types.ts:8-13` — `SpecStore` interface
|
|
1019
|
+
- `packages/core/src/spec-engine/engine.ts` (patch validate and base persist flow)
|
|
1020
|
+
- `packages/cli/src/commands/push.ts` (CLI push versioning path)
|
|
1021
|
+
- `packages/cli/src/commands/patch.ts` (CLI patch versioning path)
|
|
1022
|
+
|
|
1023
|
+
**Contract:**
|
|
1024
|
+
- `packages/core/src/contract/matcher.ts` — URL template matcher
|
|
1025
|
+
- `packages/core/src/contract/extractor.ts` — param extraction
|
|
1026
|
+
- `packages/core/src/contract/engine.ts` — contract orchestration
|
|
1027
|
+
|
|
1028
|
+
### 8.2 Finding ID cross-index
|
|
1029
|
+
|
|
1030
|
+
| Finding ID | Section | Blocker # | Type |
|
|
1031
|
+
|---|---|---|---|
|
|
1032
|
+
| F3 | §4.1 | #5 | Matcher doc |
|
|
1033
|
+
| F4 (canonical reads) | §2.1 | #1 | Reserved path |
|
|
1034
|
+
| F4 (timing workaround) | §1.3 | #2 (timing) | Expression timing |
|
|
1035
|
+
| F5 | §3.1 | #3 | Server contract |
|
|
1036
|
+
| F9 | §1.3, §5.1 | #2 | Timing (runtime fix via Item D) |
|
|
1037
|
+
| F10 | §5.2, §5.3 | #4 | Wiring — ✅ SHIPPED v0.1.0 Item E |
|
|
1038
|
+
| F14 | §6.1 | — | Workflow paradigm |
|
|
1039
|
+
| F15.c | §6.2 | — | Workflow paradigm |
|
|
1040
|
+
| F17 | §3.2 | — | Server contract |
|
|
1041
|
+
| F18 | §3.3 | — | Server contract |
|
|
1042
|
+
| CV4 | §3.1 (audit fields un-spoofable) | — | Positive validation |
|
|
1043
|
+
|
|
1044
|
+
### 8.3 `reference-doc.md` rules added by this document
|
|
1045
|
+
|
|
1046
|
+
- Rule 241 — `/ui/selectedRow` is framework-reserved (§2.1)
|
|
1047
|
+
- Rule 242 — Column action expressions resolve eagerly (current behavior) (§1.3)
|
|
1048
|
+
- Rule 243 — CRUD endpoint generates 3 routes from 1 declaration (§3.1)
|
|
1049
|
+
- Rule 244 — `/api/auth/login` expects `{ username, password }` (§3.2)
|
|
1050
|
+
- Rule 245 — Query endpoints envelope responses in `{ data: [...] }` (§3.3)
|
|
1051
|
+
|
|
1052
|
+
## 9. `derive` and `dataSources` lifecycle (v0.1.0 — Item E)
|
|
1053
|
+
|
|
1054
|
+
**Mount/unmount scope**: per `MythikRenderer` instance via `useEffect` with deps `[spec, dispatcher, svc, fetcher]`. Spec change → unmount old runtime, mount new. Same spec reference → no remount.
|
|
1055
|
+
|
|
1056
|
+
**Internal mount order** (inside `mountSpecRuntime`):
|
|
1057
|
+
1. `DeriveEngine.mount()` — sync evaluation in topological order; writes derive paths to store.
|
|
1058
|
+
2. Subscribe `derive.onStateChange` to store — reactive recompute on state changes.
|
|
1059
|
+
3. `protectionRegistry.contribute(derivePaths)` — derive paths now blocked from setState.
|
|
1060
|
+
4. `dispatcher.registerAction(dataSources.getActionDefinition())` — `refreshDataSource` available.
|
|
1061
|
+
5. `DataSourcesEngine.mount()` — initial fetches with skip-on-undefined-URL-deps.
|
|
1062
|
+
|
|
1063
|
+
**Renderer useEffect order**: state subscription useEffect is declared BEFORE `mountSpecRuntime` useEffect. React fires useEffects in declaration order, so the subscription is attached first; deriveEngine.mount()'s synchronous writes are then captured by that listener and trigger an initial-paint re-render. (Item E close-what-you-surface fix `9f3f94f`.)
|
|
1064
|
+
|
|
1065
|
+
**Skip-on-undefined-URL-deps**: if a dataSource's URL `$template` references state that's undefined/null/empty at mount time, the initial fetch is skipped and `/{target}Deferred: true` is set. The existing reactive subscription catches up when deps resolve. Makes engines self-sufficient — no coordination with initialActions needed.
|
|
1066
|
+
|
|
1067
|
+
**URL templating contract**: `DataSourceConfig.url` accepts a literal string OR an expression object (`{ $template: '/api/${/path}' }` or `{ $state: '/some/path' }`). Plain strings are returned LITERAL by the resolver — `${...}` in plain strings is NOT substituted. Validator (load-time) flags plain strings containing `${...}` as an error pointing to the `$template` form.
|
|
1068
|
+
|
|
1069
|
+
**Re-entrant safety**: derive recompute writes fire the store subscription, which calls `onStateChange` recursively. This is intentional (chained derives need to cascade — B depending on A's output sees A's write and recomputes). Infinite loops are prevented structurally: topo-sort at mount throws on circular deps; a derive's own write doesn't make itself dirty (its deps don't include its own path).
|
|
1070
|
+
|
|
1071
|
+
**Error degradation**: `DeriveEngine.evaluatePath` wraps each evaluation in try/catch. On error: `console.error` with the path name, leave path unwritten (consumer reads undefined), continue with other derives. Reactive recompute on subsequent state changes can recover.
|
|
1072
|
+
|
|
1073
|
+
**State protection**: derive paths are contributed via RAII handle to `protectionRegistry`; `stateGuard` reads via lazy callback. Validator catches `setState → derive path` at load (8 new derive/dataSources checks); dispatcher catches at runtime via `stateGuard.assertCanWrite`. Defense in depth.
|
|
1074
|
+
|
|
1075
|
+
**Re-mount safety (navigation)**: `dispatcher.registerAction` uses `Map.set` (silent overwrite). Re-mounting a spec with the same dataSources on the same dispatcher does not throw "action already registered". DataSourcesEngine's `refresh()` early-returns if the engine has been unmounted.
|