mythik 0.1.2 → 0.1.4
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/README.md +64 -16
- package/dist/actions/dispatcher.d.ts.map +1 -1
- package/dist/actions/dispatcher.js +21 -2
- package/dist/actions/dispatcher.js.map +1 -1
- package/dist/expressions/handlers/let.d.ts +6 -0
- package/dist/expressions/handlers/let.d.ts.map +1 -1
- package/dist/expressions/handlers/let.js +29 -4
- package/dist/expressions/handlers/let.js.map +1 -1
- package/dist/expressions/handlers/template.d.ts.map +1 -1
- package/dist/expressions/handlers/template.js +2 -1
- package/dist/expressions/handlers/template.js.map +1 -1
- package/dist/renderer/prop-schemas.js +1 -1
- package/dist/renderer/prop-schemas.js.map +1 -1
- package/dist/security/api-spec-validator.d.ts.map +1 -1
- package/dist/security/api-spec-validator.js +4 -0
- package/dist/security/api-spec-validator.js.map +1 -1
- package/dist/security/spec-validator.d.ts.map +1 -1
- package/dist/security/spec-validator.js +43 -31
- package/dist/security/spec-validator.js.map +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +3 -0
- package/dist/server.js.map +1 -1
- package/dist/spec-stores/sql-versioned.d.ts +38 -0
- package/dist/spec-stores/sql-versioned.d.ts.map +1 -0
- package/dist/spec-stores/sql-versioned.js +186 -0
- package/dist/spec-stores/sql-versioned.js.map +1 -0
- package/dist/spec-stores/sql.d.ts +21 -0
- package/dist/spec-stores/sql.d.ts.map +1 -0
- package/dist/spec-stores/sql.js +65 -0
- package/dist/spec-stores/sql.js.map +1 -0
- package/dist/spec-stores/sqlserver-versioned.d.ts +5 -30
- package/dist/spec-stores/sqlserver-versioned.d.ts.map +1 -1
- package/dist/spec-stores/sqlserver-versioned.js +16 -245
- package/dist/spec-stores/sqlserver-versioned.js.map +1 -1
- package/dist/spec-stores/sqlserver.d.ts +4 -11
- package/dist/spec-stores/sqlserver.d.ts.map +1 -1
- package/dist/spec-stores/sqlserver.js +16 -66
- package/dist/spec-stores/sqlserver.js.map +1 -1
- package/dist/sql/ddl.d.ts +7 -0
- package/dist/sql/ddl.d.ts.map +1 -0
- package/dist/sql/ddl.js +134 -0
- package/dist/sql/ddl.js.map +1 -0
- package/dist/sql/drivers/mysql.d.ts +25 -0
- package/dist/sql/drivers/mysql.d.ts.map +1 -0
- package/dist/sql/drivers/mysql.js +329 -0
- package/dist/sql/drivers/mysql.js.map +1 -0
- package/dist/sql/drivers/postgres.d.ts +30 -0
- package/dist/sql/drivers/postgres.d.ts.map +1 -0
- package/dist/sql/drivers/postgres.js +321 -0
- package/dist/sql/drivers/postgres.js.map +1 -0
- package/dist/sql/drivers/sqlite.d.ts +28 -0
- package/dist/sql/drivers/sqlite.d.ts.map +1 -0
- package/dist/sql/drivers/sqlite.js +369 -0
- package/dist/sql/drivers/sqlite.js.map +1 -0
- package/dist/sql/drivers/sqlserver.d.ts +46 -0
- package/dist/sql/drivers/sqlserver.d.ts.map +1 -0
- package/dist/sql/drivers/sqlserver.js +405 -0
- package/dist/sql/drivers/sqlserver.js.map +1 -0
- package/dist/sql/errors.d.ts +22 -0
- package/dist/sql/errors.d.ts.map +1 -0
- package/dist/sql/errors.js +27 -0
- package/dist/sql/errors.js.map +1 -0
- package/dist/sql/factory.d.ts +3 -0
- package/dist/sql/factory.d.ts.map +1 -0
- package/dist/sql/factory.js +24 -0
- package/dist/sql/factory.js.map +1 -0
- package/dist/sql/index.d.ts +17 -0
- package/dist/sql/index.d.ts.map +1 -0
- package/dist/sql/index.js +9 -0
- package/dist/sql/index.js.map +1 -0
- package/dist/sql/named-params.d.ts +8 -0
- package/dist/sql/named-params.d.ts.map +1 -0
- package/dist/sql/named-params.js +182 -0
- package/dist/sql/named-params.js.map +1 -0
- package/dist/sql/types.d.ts +49 -0
- package/dist/sql/types.d.ts.map +1 -0
- package/dist/sql/types.js +2 -0
- package/dist/sql/types.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/docs/consumer/README.md +1 -1
- package/docs/consumer/WHERE-TO-LOOK.md +4 -4
- package/docs/consumer/ai-context-api.md +44 -0
- package/docs/consumer/ai-context-primitives.md +3 -0
- package/docs/consumer/ai-context-runtime-semantics.md +8 -3
- package/docs/consumer/ai-context.md +123 -39
- package/docs/consumer/reference-doc.md +30 -8
- package/docs/wiki/compiled/README.md +1 -1
- package/docs/wiki/compiled/_lint.md +13 -8
- package/docs/wiki/compiled/action-fetch.md +7 -2
- package/docs/wiki/compiled/concept-action-chains.md +62 -24
- package/docs/wiki/compiled/concept-package-layout.md +11 -9
- package/docs/wiki/compiled/concept-public-package-names.md +24 -13
- package/docs/wiki/compiled/concept-shape-animations.md +1 -1
- package/docs/wiki/compiled/concept-spec-stores-catalog.md +28 -16
- package/docs/wiki/compiled/concept-transactions.md +20 -12
- package/docs/wiki/compiled/expression-let-ref.md +36 -18
- package/docs/wiki/compiled/expression-template.md +28 -17
- package/docs/wiki/compiled/path-ui-loading-error.md +5 -0
- package/docs/wiki/compiled/pattern-fetch-vs-datasources.md +5 -0
- package/docs/wiki/compiled/pattern-loading-content-empty.md +3 -2
- package/docs/wiki/compiled/primitive-select.md +16 -2
- package/package.json +25 -2
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
Public npm package names are unscoped:
|
|
15
15
|
|
|
16
16
|
- Runtime/core: `mythik`
|
|
17
|
-
-
|
|
17
|
+
- Node/server helpers from core: `mythik/server`
|
|
18
18
|
- React host/runtime: `mythik-react`
|
|
19
19
|
- CLI binary package: `mythik-cli` (binary command: `mythik`)
|
|
20
20
|
- Programmatic CLI API: `mythik-cli/api`
|
|
@@ -22,6 +22,21 @@ Public npm package names are unscoped:
|
|
|
22
22
|
|
|
23
23
|
Use `npm install mythik mythik-react` for a React app, `npm install -D mythik-cli` for CLI workflows, and add `mythik-server` only when building a Mythik-backed Node server. The `mythik` npm package bundles the AI documentation corpus under `node_modules/mythik/docs`; use `mythik docs path` to locate it after install or `mythik docs copy ./mythik-docs` to copy it into the current project.
|
|
24
24
|
|
|
25
|
+
Server-side SQL helpers, SQL drivers, and SQL-backed spec stores are imported from `mythik/server`, not from the browser-safe `mythik` entry. Supported SQL dialects are `sqlserver`, `postgres`, `mysql`, and `sqlite`.
|
|
26
|
+
|
|
27
|
+
Database runtime dependencies: SQL adapters (`mssql`, `pg`, `mysql2`, and `better-sqlite3`) are optional peer dependencies. Browser-only installs do not need them. SQL-backed stores and servers must install exactly the adapter for the selected database:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install mssql # SQL Server
|
|
31
|
+
npm install pg # PostgreSQL
|
|
32
|
+
npm install mysql2 # MySQL
|
|
33
|
+
npm install better-sqlite3 # SQLite
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
SQLite uses the native `better-sqlite3` adapter. npm warnings from that adapter's transitive native-build helpers are adapter-level install noise, not a Mythik runtime failure. Missing SQL adapter errors include the package name and exact install command for the selected dialect.
|
|
37
|
+
|
|
38
|
+
MySQL support targets MySQL 8.0.19+ for generated upsert SQL. Older MySQL deployments need an explicit custom SQL path or another supported dialect.
|
|
39
|
+
|
|
25
40
|
## Spec Structure
|
|
26
41
|
|
|
27
42
|
Every screen is a flat tree: `root` ID + `elements` map + optional `initialActions`:
|
|
@@ -88,6 +103,9 @@ Every screen is a flat tree: `root` ID + `elements` map + optional `initialActio
|
|
|
88
103
|
```bash
|
|
89
104
|
mythik docs path # Locate bundled AI documentation
|
|
90
105
|
mythik docs copy ./mythik-docs # Copy docs for an AI agent / local review
|
|
106
|
+
mythik init-store --dialect sqlite --target ./mythik.db # Create local SQL store tables
|
|
107
|
+
mythik init-store --dialect postgres --dry-run # Print SQL store DDL for review/apply
|
|
108
|
+
mythik init-store --dialect sqlserver --server localhost --database Mythik --user "$DB_USER" --password "$DB_PASSWORD" --encrypt false --trust-server-certificate
|
|
91
109
|
mythik manifest <screen> # See structural tree
|
|
92
110
|
mythik elements <screen> <id1,id2> # Get element details
|
|
93
111
|
mythik patch <screen> --from-file patch.json # Apply RFC 6902 patches
|
|
@@ -114,6 +132,36 @@ Do not edit database rows directly, do not call `SpecStore.save()` from app code
|
|
|
114
132
|
|
|
115
133
|
All commands accept `--json`, `--table <name>`, `--store`, `--url`, `--key`. Never pass API keys inline — use `.mythikrc` + env vars.
|
|
116
134
|
|
|
135
|
+
### CLI store configuration
|
|
136
|
+
|
|
137
|
+
The CLI can read and write specs from `memory`, `file`, `supabase`, `sqlserver`, `postgres`, `mysql`, and `sqlite` stores. SQL stores share the same commands and the same required edit loop: `manifest -> elements -> patch -> validate`.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# SQLite: local development, tests, demos, lightweight deployments
|
|
141
|
+
mythik init-store --dialect sqlite --target ./mythik.db
|
|
142
|
+
mythik push floor-editor --from-file specs/floor-editor.json --store sqlite --filename ./mythik.db --author ai-agent
|
|
143
|
+
mythik manifest floor-editor --store sqlite --filename ./mythik.db
|
|
144
|
+
mythik elements floor-editor page,title --store sqlite --filename ./mythik.db
|
|
145
|
+
mythik patch floor-editor --from-file patch.json --store sqlite --filename ./mythik.db --author ai-agent
|
|
146
|
+
mythik validate floor-editor --store sqlite --filename ./mythik.db
|
|
147
|
+
|
|
148
|
+
# PostgreSQL
|
|
149
|
+
mythik init-store --dialect postgres --dry-run
|
|
150
|
+
mythik patch floor-editor --from-file patch.json --store postgres --url "$DATABASE_URL" --author ai-agent
|
|
151
|
+
|
|
152
|
+
# MySQL
|
|
153
|
+
mythik init-store --dialect mysql --dry-run
|
|
154
|
+
mythik patch floor-editor --from-file patch.json --store mysql --url "$DATABASE_URL" --author ai-agent
|
|
155
|
+
|
|
156
|
+
# SQL Server
|
|
157
|
+
mythik init-store --dialect sqlserver --server localhost --database Mythik --user "$DB_USER" --password "$DB_PASSWORD" --encrypt false --trust-server-certificate
|
|
158
|
+
mythik patch floor-editor --from-file patch.json --store sqlserver --server localhost --database Mythik --user "$DB_USER" --password "$DB_PASSWORD" --author ai-agent
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Environment equivalents: `MYTHIK_STORE`, `MYTHIK_DATABASE_URL`, `MYTHIK_SQLITE_FILE`, `MYTHIK_SQLSERVER_SERVER`, `MYTHIK_SQLSERVER_DATABASE`, `MYTHIK_SQLSERVER_USER`, `MYTHIK_SQLSERVER_PASSWORD`, `MYTHIK_SQLSERVER_PORT`, `MYTHIK_SQLSERVER_TRUSTED_CONNECTION`, `MYTHIK_TABLE`, `MYTHIK_VERSIONS_TABLE`, `MYTHIK_ENVIRONMENTS_TABLE`, and `MYTHIK_SNAPSHOT_INTERVAL`.
|
|
162
|
+
|
|
163
|
+
`init-store --dry-run` prints the canonical idempotent DDL for the dialect. `init-store` can initialize reachable SQL stores directly, including SQL Server through explicit flags, while production teams may still apply the dry-run DDL through their normal deployment process. Runtime reads/writes do not silently create missing tables on first use.
|
|
164
|
+
|
|
117
165
|
### CLI is the only approved path for spec writes
|
|
118
166
|
|
|
119
167
|
Per reference-doc rule 248: three approved forms.
|
|
@@ -301,6 +349,11 @@ Extended: `locale`, `notation` (compact/scientific), `signDisplay` (always/excep
|
|
|
301
349
|
```json
|
|
302
350
|
{ "$let": { "total": { "$array": "count", "source": { "$state": "/items" } } }, "$in": { "$ref": "total" } }
|
|
303
351
|
```
|
|
352
|
+
`$ref` may also read nested values from an object binding with dot notation:
|
|
353
|
+
```json
|
|
354
|
+
{ "$let": { "user": { "$state": "/auth/user" } }, "$in": { "$ref": "user.name" } }
|
|
355
|
+
```
|
|
356
|
+
Inside the same `$let`, `$template` placeholders can read the same dotted binding paths, for example `${user.name}`.
|
|
304
357
|
**JSONB array format** (when stored in DB, order matters):
|
|
305
358
|
```json
|
|
306
359
|
{ "$let": [["filtered", { "$array": "filter", "source": { "$state": "/items" }, "where": { "field": "status", "eq": "active" } }], ["count", { "$array": "count", "source": { "$ref": "filtered" } }]], "$in": { "$ref": "count" } }
|
|
@@ -341,12 +394,14 @@ All primitives accept `style`, `visible`, and `permission`. Tokens are project-d
|
|
|
341
394
|
|
|
342
395
|
Wire to events with `on`: `{ "on": { "press": { "action": "...", "params": {...} } } }`
|
|
343
396
|
|
|
344
|
-
Arrays execute sequentially: `"press": [action1, action2, action3]
|
|
397
|
+
Arrays execute sequentially: `"press": [action1, action2, action3]`. Arrays may mix normal action bindings and transaction bindings; each entry runs in order and transactions are awaited before the next entry.
|
|
345
398
|
|
|
346
399
|
**Trap:** Action chains don't stop on failure — `validateForm` marks errors but does NOT halt the chain. Use `submitForm` with `formId` instead (validates + blocks if invalid). See [ai-context-patterns.md](ai-context-patterns.md).
|
|
347
400
|
|
|
348
401
|
Add `"fireAndForget": true` to dispatch without waiting (background re-fetch after closing modal).
|
|
349
402
|
|
|
403
|
+
Any action binding may include `params.skipIf`. Mythik resolves `skipIf` at dispatch time before resolving the rest of the params; when truthy, that action is skipped and the surrounding action chain continues.
|
|
404
|
+
|
|
350
405
|
### Action Reference
|
|
351
406
|
|
|
352
407
|
| Action | Params | Purpose |
|
|
@@ -386,6 +441,7 @@ Add `"fireAndForget": true` to dispatch without waiting (background re-fetch aft
|
|
|
386
441
|
- Empty strings in body → `null` (prevents DB errors)
|
|
387
442
|
- Sets `/ui/loading` while in flight
|
|
388
443
|
- On error: sets `/ui/lastError` with status and message
|
|
444
|
+
- Optional `errorTarget` writes the same structured error to a screen-owned path and clears that path on success. Use it for critical screen-load fetches instead of relying only on global `/ui/lastError`
|
|
389
445
|
- Auth headers auto-injected for `authDomains` URLs
|
|
390
446
|
|
|
391
447
|
### Transactions (Optimistic Updates)
|
|
@@ -539,14 +595,16 @@ Inside: `{ "$selection": "selected" }` (boolean), `{ "$selection": "count" }`. T
|
|
|
539
595
|
|
|
540
596
|
**Rule:** Don't mix both for the same data target. Pick one pattern per data source.
|
|
541
597
|
|
|
598
|
+
For critical `initialActions` fetches, set `params.errorTarget` to a screen-owned path (for example `/ui/loadErrors/orderForm`) and render a visible error state from that path. `/ui/lastError` is global and can be overwritten by unrelated fetches.
|
|
599
|
+
|
|
542
600
|
### Loading/Content/Empty Pattern
|
|
543
601
|
|
|
544
|
-
**With `initialActions` fetch** (uses `/ui/loading
|
|
602
|
+
**With `initialActions` fetch** (uses `/ui/loading`; critical loads should set `errorTarget`):
|
|
545
603
|
```json
|
|
546
604
|
"loading": { "visible": { "$and": [{ "$state": "/ui/loading" }, { "$not": { "$array": "count", "source": { "$state": "/items" } } }] } },
|
|
547
605
|
"content": { "visible": { "$array": "count", "source": { "$state": "/items" } } },
|
|
548
606
|
"empty": { "visible": { "$and": [{ "$not": { "$state": "/ui/loading" } }, { "$not": { "$array": "count", "source": { "$state": "/items" } } }] } },
|
|
549
|
-
"error": { "visible": { "$state": "/ui/
|
|
607
|
+
"error": { "visible": { "$state": "/ui/loadErrors/items" } }
|
|
550
608
|
```
|
|
551
609
|
|
|
552
610
|
**With `dataSources`** (uses auto-generated `/{target}Loading` and `/{target}Error`):
|
|
@@ -1135,35 +1193,46 @@ Quick reference: `type: "api"` at root, with `auth`, `catalogs`, `endpoints` obj
|
|
|
1135
1193
|
|
|
1136
1194
|
## Storage Setup
|
|
1137
1195
|
|
|
1138
|
-
Mythik stores specs in the consumer's
|
|
1196
|
+
Mythik stores specs in the consumer's selected store. Browser-safe stores (`MemorySpecStore`, `SupabaseSpecStore`, and their versioned/environment variants) are imported from `mythik`. Node-only SQL stores (`SqlSpecStore`, `SqlVersionedSpecStore`, `SqlEnvironmentStore`, `FileSpecStore`, and SQL Server compatibility classes) are imported from `mythik/server`.
|
|
1197
|
+
|
|
1198
|
+
SQL-backed stores support `sqlserver`, `postgres`, `mysql`, and `sqlite` through one `SqlDriver` boundary. The same three tables are involved across dialects:
|
|
1139
1199
|
|
|
1140
|
-
- **`screens`** (base, **REQUIRED**) — current spec per `id`. Used by every adapter
|
|
1141
|
-
- **`screen_versions`** (opt-in) — version history. Required
|
|
1142
|
-
- **`screen_environments`** (opt-in) — environment promotions. Required
|
|
1200
|
+
- **`screens`** (base, **REQUIRED**) — current spec per `id`. Used by every SQL/Supabase adapter.
|
|
1201
|
+
- **`screen_versions`** (opt-in but recommended) — version history. Required when the CLI runs with `--author`, when `runPush`/`runPatch` receives an `author`, or when code uses `SqlVersionedSpecStore` / `SupabaseVersionedSpecStore`.
|
|
1202
|
+
- **`screen_environments`** (opt-in but recommended) — environment promotions. Required for `history`, `diff`, `rollback`, `envs`, `promote`, and `SqlEnvironmentStore` / `SupabaseEnvironmentStore` workflows.
|
|
1143
1203
|
|
|
1144
|
-
|
|
1204
|
+
Use the CLI to bootstrap SQL store tables:
|
|
1145
1205
|
|
|
1146
|
-
|
|
1206
|
+
```bash
|
|
1207
|
+
mythik init-store --dialect sqlite --target ./mythik.db
|
|
1208
|
+
mythik init-store --dialect sqlserver --server localhost --database Mythik --user "$DB_USER" --password "$DB_PASSWORD" --encrypt false --trust-server-certificate
|
|
1209
|
+
mythik init-store --dialect postgres --dry-run
|
|
1210
|
+
mythik init-store --dialect mysql --dry-run
|
|
1211
|
+
```
|
|
1212
|
+
|
|
1213
|
+
`init-store --dry-run` prints the canonical idempotent DDL. `init-store` can initialize reachable SQL stores directly, including SQL Server through explicit flags. Production teams may still apply the dry-run DDL through their normal database deployment path. Runtime store reads/writes do not silently create missing tables.
|
|
1147
1214
|
|
|
1148
|
-
**
|
|
1215
|
+
**Authoritative since v0.1.0.** The framework's SQL stores require the columns below by name and meaning. Use the generated DDL where possible; if translating manually, preserve all columns, constraints, and uniqueness rules.
|
|
1216
|
+
|
|
1217
|
+
**Versioned stores extend the base store.** When `SqlVersionedSpecStore.saveVersion(id, doc, meta)` or `SupabaseVersionedSpecStore.saveVersion(id, doc, meta)` runs, it appends to `screen_versions` and updates `screens`. This means `screens` MUST exist for every consumer — there is no "versioning-only" mode that skips it.
|
|
1149
1218
|
|
|
1150
1219
|
### Table 0 — `screens` (current spec — REQUIRED for all stores)
|
|
1151
1220
|
|
|
1152
1221
|
| Column | Semantic type | Nullable | Default | Notes |
|
|
1153
1222
|
|---|---|---|---|---|
|
|
1154
1223
|
| `id` | short string (≤255) | NOT NULL | — | Spec identifier; PK. Framework reads/writes via `WHERE id = ?` |
|
|
1155
|
-
| `name` | short string (≤255) | NULL | — | Display name. Framework
|
|
1156
|
-
| `spec` | long
|
|
1157
|
-
| `version` | integer | NOT NULL | `1` | Incremented
|
|
1158
|
-
| `is_active` | boolean | NOT NULL | `true` | Framework
|
|
1224
|
+
| `name` | short string (≤255) | NULL | — | Display name. Framework inserts the same value as `id` by default. |
|
|
1225
|
+
| `spec` | JSON-capable long value | NOT NULL | — | Current spec. SQL Server and SQLite DDL store JSON as text; PostgreSQL uses `JSONB`; MySQL uses `JSON`. Generic SQL stores parse string values defensively. |
|
|
1226
|
+
| `version` | integer | NOT NULL | `1` | Incremented by the generic SQL store on every update. |
|
|
1227
|
+
| `is_active` | boolean | NOT NULL | `true` | Framework inserts active specs; current SQL store list operations do not filter by this column. |
|
|
1159
1228
|
| `created_at` | UTC timestamp | — | — | OPTIONAL — framework does not read or write this column. If you add it for consumer hygiene (audit trail), make it `NOT NULL` with a NOW UTC default; otherwise omit entirely. |
|
|
1160
|
-
| `updated_at` | UTC timestamp | NOT NULL | NOW UTC | Required.
|
|
1229
|
+
| `updated_at` | UTC timestamp/string | NOT NULL | NOW UTC | Required. The generic SQL store writes this value on insert and update; the database default covers manual/bootstrap inserts. |
|
|
1161
1230
|
|
|
1162
1231
|
**Constraints**:
|
|
1163
1232
|
- `PRIMARY KEY (id)` — required (every framework query filters by `id`)
|
|
1164
1233
|
|
|
1165
1234
|
**Indexes** (all RECOMMENDED, none framework-required):
|
|
1166
|
-
- `(is_active, id)` — useful for consumer queries filtering active screens. The framework's `list()` uses only `ORDER BY id`
|
|
1235
|
+
- `(is_active, id)` — useful for consumer queries filtering active screens. The framework's `list()` uses only `ORDER BY id` and does not filter by `is_active`, so this index is consumer-hygiene only.
|
|
1167
1236
|
|
|
1168
1237
|
### Table 1 — `screen_versions` (version history — opt-in: VersionedSpecStore)
|
|
1169
1238
|
|
|
@@ -1201,20 +1270,22 @@ Mythik stores specs in the consumer's database. Three tables are involved depend
|
|
|
1201
1270
|
**Constraints**:
|
|
1202
1271
|
- `PRIMARY KEY (screen_id, environment)` — one promotion record per `(spec, env)` pair; re-promote upserts via MERGE/UPSERT
|
|
1203
1272
|
|
|
1204
|
-
###
|
|
1273
|
+
### JSON column policy
|
|
1205
1274
|
|
|
1206
|
-
|
|
1275
|
+
Use the dialect-native JSON type when the dialect has one:
|
|
1207
1276
|
|
|
1208
|
-
-
|
|
1209
|
-
-
|
|
1277
|
+
- PostgreSQL / Supabase: `JSONB`
|
|
1278
|
+
- MySQL: `JSON`
|
|
1279
|
+
- SQL Server: `NVARCHAR(MAX)`
|
|
1280
|
+
- SQLite: `TEXT`
|
|
1210
1281
|
|
|
1211
|
-
SQL
|
|
1282
|
+
Generic SQL stores parse stored JSON defensively when the driver returns strings. Supabase's browser-safe REST stores consume PostgREST JSON as already-parsed objects, so Supabase tables should use `jsonb`, not `text`.
|
|
1212
1283
|
|
|
1213
|
-
###
|
|
1284
|
+
### Supabase trigger note
|
|
1214
1285
|
|
|
1215
|
-
|
|
1286
|
+
Generic SQL stores write `screens.updated_at` and `screens.version` directly. Supabase's browser-safe REST store updates only the `spec` field, so Supabase projects should keep the `BEFORE UPDATE` triggers below if they want `updated_at` and `version` to advance on Supabase REST writes.
|
|
1216
1287
|
|
|
1217
|
-
Recommended trigger pair on
|
|
1288
|
+
Recommended trigger pair on Supabase/PostgreSQL when using `SupabaseSpecStore`:
|
|
1218
1289
|
|
|
1219
1290
|
```sql
|
|
1220
1291
|
CREATE OR REPLACE FUNCTION screens_update_updated_at()
|
|
@@ -1232,16 +1303,17 @@ CREATE TRIGGER screens_version_trigger
|
|
|
1232
1303
|
FOR EACH ROW EXECUTE FUNCTION screens_increment_version();
|
|
1233
1304
|
```
|
|
1234
1305
|
|
|
1235
|
-
Trigger function names are arbitrary (use any unique name); the framework does not introspect them.
|
|
1306
|
+
Trigger function names are arbitrary (use any unique name); the framework does not introspect them. Plain PostgreSQL consumers using `SqlSpecStore` through `mythik/server` do not need these triggers for framework writes.
|
|
1236
1307
|
|
|
1237
|
-
`screen_versions` and `screen_environments` do NOT need such triggers — those tables are append-only / upsert-on-PK and the framework writes all columns explicitly on each INSERT/UPSERT
|
|
1308
|
+
`screen_versions` and `screen_environments` do NOT need such triggers — those tables are append-only / upsert-on-PK and the framework writes all columns explicitly on each INSERT/UPSERT.
|
|
1238
1309
|
|
|
1239
|
-
###
|
|
1310
|
+
### Initialization and idempotency
|
|
1240
1311
|
|
|
1241
|
-
|
|
1242
|
-
- SQL Server: `IF
|
|
1312
|
+
`mythik init-store` uses canonical idempotent DDL, so re-running it on a database that already has the tables does not fail and does not recreate existing tables. If translating the DDL manually into a deployment script, preserve the target dialect's "if not exists" guard:
|
|
1313
|
+
- SQL Server: `IF OBJECT_ID(N'...', N'U') IS NULL CREATE TABLE ...`
|
|
1243
1314
|
- Postgres / Supabase: `CREATE TABLE IF NOT EXISTS ...`
|
|
1244
1315
|
- MySQL / MariaDB: `CREATE TABLE IF NOT EXISTS ...`
|
|
1316
|
+
- SQLite: `CREATE TABLE IF NOT EXISTS ...`
|
|
1245
1317
|
|
|
1246
1318
|
### Verification (post-apply)
|
|
1247
1319
|
|
|
@@ -1255,29 +1327,33 @@ WHERE TABLE_NAME IN ('screens', 'screen_versions', 'screen_environments')
|
|
|
1255
1327
|
ORDER BY TABLE_NAME, ORDINAL_POSITION;
|
|
1256
1328
|
```
|
|
1257
1329
|
|
|
1258
|
-
Confirm:
|
|
1330
|
+
Confirm: 6 required columns for `screens` (`id`, `name`, `spec`, `version`, `is_active`, `updated_at`), 10 columns for `screen_versions` (`id` through `created_at`), and 5 columns for `screen_environments` (`screen_id` through `promoted_by`). `created_at` on `screens` is optional. If any required column is missing or has a wrong NULL/NOT NULL flag, abort and report — the framework's INSERT/SELECT/UPDATE will fail at runtime otherwise.
|
|
1259
1331
|
|
|
1260
|
-
On
|
|
1332
|
+
On Supabase projects using `SupabaseSpecStore`, additionally verify the two triggers on `screens` are present (`information_schema.triggers` WHERE `event_object_table = 'screens'`); without them, `updated_at` and `version` will not advance on Supabase REST writes.
|
|
1261
1333
|
|
|
1262
1334
|
### Custom table names
|
|
1263
1335
|
|
|
1264
1336
|
All three table names are independently configurable; overriding one does not require overriding the others:
|
|
1265
1337
|
|
|
1266
1338
|
```ts
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1339
|
+
import { createSqlDriver, SqlEnvironmentStore, SqlSpecStore, SqlVersionedSpecStore } from 'mythik/server';
|
|
1340
|
+
|
|
1341
|
+
const driver = createSqlDriver({ dialect: 'postgres', connection: process.env.DATABASE_URL });
|
|
1342
|
+
|
|
1343
|
+
new SqlSpecStore({ driver, table: 'my_screens' });
|
|
1344
|
+
new SqlVersionedSpecStore({ driver, table: 'my_screens', versionsTable: 'my_versions' });
|
|
1345
|
+
new SqlEnvironmentStore({ driver, table: 'my_envs' });
|
|
1270
1346
|
```
|
|
1271
1347
|
|
|
1272
|
-
|
|
1348
|
+
`SqlVersionedSpecStore` accepts both `table` from the base config and `versionsTable` from its own config, since it extends `SqlSpecStore`.
|
|
1273
1349
|
|
|
1274
1350
|
If a consumer overrides any name, AI applies the same schema under the consumer-chosen name.
|
|
1275
1351
|
|
|
1276
|
-
**Identifier safety scope**: SQL
|
|
1352
|
+
**Identifier safety scope**: generic SQL stores enforce identifier validation on configured table names (regex `/^[a-zA-Z_][a-zA-Z0-9_.]*$/`, max 128 chars). This blocks SQL injection via table-name interpolation before dialect quoting runs. Supabase stores do not validate configured table names; consumer code passing user-controlled table names to a Supabase store must validate them upstream.
|
|
1277
1353
|
|
|
1278
|
-
### Canonical reference
|
|
1354
|
+
### Canonical reference
|
|
1279
1355
|
|
|
1280
|
-
|
|
1356
|
+
The canonical SQL store DDL ships in the installed package. Use `mythik init-store --dialect <sqlserver|postgres|mysql|sqlite> --dry-run` or `getSqlStoreDdl(dialect)` from `mythik/server` to inspect it. Do not copy DDL from unrelated local artifacts.
|
|
1281
1357
|
|
|
1282
1358
|
### Schema evolution
|
|
1283
1359
|
|
|
@@ -1377,3 +1453,11 @@ When the framework changes the schema in a future version, this section will gai
|
|
|
1377
1453
|
87. DNA numeric seeds (`roundness`, `density`, `depth`, `formality`) are canonical `0–1` values. Generate `0.7`, not `70`. The runtime tolerates legacy `0–100` values by normalizing any numeric seed greater than `1` with `/100` during DNA derivation, including initial AppSpec load and runtime `updateTokens`.
|
|
1378
1454
|
88. API query endpoints can combine `pagination: "offset"` with `scopeFilter`. For generated counts, Mythik applies the scope filter to the source query before `COUNT(*)`, so paginated totals remain tenant-scoped. Prefer generated counts. If a custom `endpoint.count` is truly needed with `scopeFilter`, include `{{scopeWhere[:alias]}}` or `{{scopeAnd[:alias]}}`; Mythik expands the macro to the correct scope predicate and removes it for bypass roles. Other custom count SQL is left verbatim. Use `:alias` for JOIN/subquery counts, and do not reference internal scope params directly.
|
|
1379
1455
|
89. Transaction `confirm` failures from `fetch` preserve backend error details for `onError`. Read `/tx/error/message` for the best available message; when the backend returns `{ error: { code, message } }`, Mythik keeps that message, `code`, HTTP `status`, and raw `data` after rollback. Do not parse `/ui/lastError` from transaction specs.
|
|
1456
|
+
90. For SQL-backed stores and servers, use the generic `mythik/server` SQL boundary. Initialize tables with `mythik init-store --dialect <sqlserver|postgres|mysql|sqlite>` or inspect DDL with `--dry-run`; configure the CLI with `--store`, `--url`/`--filename`/SQL Server flags, or `MYTHIK_*` environment variables; and keep spec edits on the required `manifest -> elements -> patch --from-file -> validate` loop. Write custom API SQL in the selected dialect with Mythik named params (`@name`); Mythik does not translate custom SQL between dialects.
|
|
1457
|
+
91. Event arrays may mix normal actions and transaction bindings. Mythik executes them sequentially and awaits each transaction before continuing. Use this when a flow needs a small action before or after an optimistic transaction; do not wrap a transaction inside another transaction phase.
|
|
1458
|
+
92. `$ref` and `$template` placeholders can read nested values from `$let` object bindings with dot notation, for example `{ "$ref": "user.name" }` or `${user.name}`. If a dotted `$ref` segment is missing, runtime throws an unknown `$ref` error rather than silently returning undefined.
|
|
1459
|
+
93. Use `params.skipIf` for a dispatch-time action guard when an action should be skipped but the surrounding action chain should continue. `skipIf` is resolved before other params and is removed before the action handler runs. Do not use `skipIf` as a substitute for form validation or transaction rollback.
|
|
1460
|
+
94. For critical direct `fetch` actions, especially `initialActions` screen loads, set `params.errorTarget` to a screen-owned `/ui/...` path and render that path visibly. The fetch action still writes global `/ui/lastError`, but `/ui/lastError` is shared and can be overwritten by unrelated fetches. On success, Mythik clears the provided `errorTarget`.
|
|
1461
|
+
95. `select.options` accepts strings, `{ label, value }` objects, or catalog-shaped objects when `labelKey` and `valueKey` are provided. Example: `{ "options": { "$state": "/cat/services/data" }, "labelKey": "name", "valueKey": "id" }`. Values are emitted as strings from `on.change`; malformed option data renders disabled diagnostics instead of blank clickable rows or crashes.
|
|
1462
|
+
96. SQL adapters are optional peer dependencies, not installed-by-default runtime payload. Browser-only apps install `mythik mythik-react` without database drivers. SQL-backed stores/servers must install exactly one selected adapter: `mssql`, `pg`, `mysql2`, or `better-sqlite3`. SQLite uses native `better-sqlite3`; native-build helper warnings from that adapter are not Mythik runtime failures.
|
|
1463
|
+
97. Missing SQL adapter errors are actionable. The thrown `SqlDriverError` includes `packageName`, `installCommand`, and a message with the exact `npm install ...` command for the selected dialect.
|
|
@@ -311,7 +311,7 @@ Nested conditionals for multi-branch logic:
|
|
|
311
311
|
```
|
|
312
312
|
Interpolates values into a string. Supports two reference types:
|
|
313
313
|
- State paths: `${/user/name}` — reads from application state
|
|
314
|
-
- `$let` bindings: `${age}` — reads from a named binding defined with `$let`
|
|
314
|
+
- `$let` bindings: `${age}` or `${user.name}` — reads from a named binding defined with `$let`
|
|
315
315
|
|
|
316
316
|
### `$computed` — Registered function
|
|
317
317
|
```json
|
|
@@ -328,6 +328,15 @@ Calls a registered function with resolved arguments. **Prefer `$math`, `$array`,
|
|
|
328
328
|
```
|
|
329
329
|
Define a named value once, reference it multiple times. Avoids repetition.
|
|
330
330
|
|
|
331
|
+
`$ref` can read nested values from an object binding with dot notation:
|
|
332
|
+
```json
|
|
333
|
+
{
|
|
334
|
+
"$let": { "user": { "$state": "/auth/user" } },
|
|
335
|
+
"$in": { "$ref": "user.name" }
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
The same dotted binding lookup is available inside `$template` placeholders, for example `${user.name}`.
|
|
339
|
+
|
|
331
340
|
**Later bindings can reference earlier ones:**
|
|
332
341
|
```json
|
|
333
342
|
{
|
|
@@ -922,6 +931,7 @@ The `fetch` action supports:
|
|
|
922
931
|
- **Empty string sanitization:** Empty strings in body are automatically converted to `null` (prevents database errors for typed columns)
|
|
923
932
|
- **Loading state:** Sets `/ui/loading` to true while in flight, false when done
|
|
924
933
|
- **Error handling:** On failure, sets `/ui/lastError` with status and message
|
|
934
|
+
- **Screen-owned errors:** Optional `errorTarget` receives the same structured error and is cleared on success; use it for critical `initialActions` loads
|
|
925
935
|
|
|
926
936
|
```json
|
|
927
937
|
{
|
|
@@ -940,6 +950,10 @@ The `fetch` action supports:
|
|
|
940
950
|
}
|
|
941
951
|
```
|
|
942
952
|
|
|
953
|
+
Action arrays may also mix normal action bindings and transaction bindings. Mythik runs each entry in order and waits for a transaction to finish before dispatching the next entry.
|
|
954
|
+
|
|
955
|
+
Any action binding can include `params.skipIf`. Mythik resolves `skipIf` at dispatch time before the rest of the params; if it is truthy, that action is skipped and the surrounding action chain continues.
|
|
956
|
+
|
|
943
957
|
### Transactions (Optimistic Updates)
|
|
944
958
|
|
|
945
959
|
Use `transaction` for CRUD operations that need instant UI feedback. The framework takes a state snapshot, applies your changes instantly, then confirms with the server. On failure, it rolls back automatically.
|
|
@@ -1950,11 +1964,11 @@ Reference tokens or write custom values:
|
|
|
1950
1964
|
64. **CLI warns on unknown prop names** — `mythik push` and `mythik validate` check prop names against known schemas for all 38 primitives. Unknown props generate warnings (not errors) with Levenshtein suggestions: `⚠ unknown prop "inputType" for type "input" — did you mean "type"?`. Warnings don't block saves
|
|
1951
1965
|
65. **Use `audit` config for automatic change tracking** — endpoint-level config that auto-injects username and timestamp into CRUD INSERT and UPDATE operations. Column names are configurable per table. All fields are optional — only configured fields are injected. Audit values override client-sent values (prevents spoofing)
|
|
1952
1966
|
66. **Audit `timezone` for correct local timestamps** — set `"timezone": "America/El_Salvador"` (IANA string) in audit config. Without timezone, timestamps are UTC. Use timezone when the database stores local time. The framework converts using `Intl.DateTimeFormat` — works regardless of server location
|
|
1953
|
-
67. **CRUD queries are
|
|
1967
|
+
67. **CRUD queries are dialect-aware** — Generated CRUD routes compile through the active SQL driver. SQL Server uses trigger-safe identity retrieval; PostgreSQL/SQLite use `RETURNING` where available; MySQL uses the driver insert id path and targets MySQL 8.0.19+ for generated upsert SQL. Custom SQL remains dialect-native and is not translated between databases.
|
|
1954
1968
|
68. **CustomJWTProvider maps response paths explicitly** — `tokenPath`, `refreshTokenPath`, and `userPath` are dot paths against the full login/refresh response. `rolePath` and `rolesPath` are compat dual: plain keys (`"role"`, `"roles"`) resolve inside the extracted user object, dotted paths (`"user.role"`, `"data.user.role"`) resolve against the full response. If no role/roles are found, `defaultRole` is used and development logs a warning. HTTP errors read `response.error.message` first, then `response.message`
|
|
1955
1969
|
69. **ApiSpec is pure declarative — no connection, no secrets** — `createServer` receives database connection and JWT secret in `MythikServerConfig`, not in the ApiSpec. The ApiSpec only contains endpoints, catalogs, auth model (provider, policies, scopeFilter), and audit config. This allows the ApiSpec to be stored safely in the database
|
|
1956
1970
|
70. **Server loads api-spec from SpecStore** — `createServer({ spec: { store: myStore, id: 'my-api' }, database: {...}, auth: {...} })`. Supports three modes: file path (string), ApiSpec object (testing), or `{ store, id }` (database). The server never owns a SpecStore — the caller provides one
|
|
1957
|
-
71. **SpecStore table is configurable** — `new
|
|
1971
|
+
71. **SpecStore table is configurable** — Generic SQL stores use `new SqlSpecStore({ driver, table: 'api_specs' })` from `mythik/server`; Supabase uses `new SupabaseSpecStore({ ..., table: 'api_specs' })` from `mythik`. Default: `'screens'`. Enables separate tables for frontend specs and backend specs with different DB permissions.
|
|
1958
1972
|
72. **Api-specs are never served to the browser** — `GET /api/screens/:id` and `GET /api/app/:id` return 404 for documents with `type: "api"`. Prevents information disclosure of table names, SQL queries, and auth config
|
|
1959
1973
|
73. **CLI operates on api-specs automatically** — `mythik validate my-api`, `mythik pull my-api`, `mythik push my-api` detect `type: "api"` and use the apiHandler. Manifest shows catalogs, endpoints, auth config. Elements support dot-notation: `mythik elements my-api endpoints.records-crud`
|
|
1960
1974
|
74. **Use `mythik contract` for frontend↔backend validation** — `mythik contract --app app-demo --api records-api`. Cross-validates screen fetch URLs against api-spec endpoints. Supports multiple api-specs (comma-separated). Use `--api-table` when api-specs are in a separate table. Use `--base-url` to strip host from URLs. Use `--json` for CI/CD integration
|
|
@@ -1974,12 +1988,12 @@ Reference tokens or write custom values:
|
|
|
1974
1988
|
88. **Rollback creates new version, never rewrites history** — `executeRollback(specId, toVersion)` creates vN+1 with the content of the target version. All intermediate versions are preserved. Impact analysis shows lost changes with author attribution and affected environments. Moving an environment pointer is a separate operation via `envs --set`
|
|
1975
1989
|
89. **Lazy bootstrap for existing specs** — first versioned save on an existing spec with no history automatically creates v1 (snapshot of current spec), then saves the change as v2. No migration script needed. Specs without history continue working via base `SpecStore.load()`
|
|
1976
1990
|
90. **Use `navigateScreen` and `goBackScreen` in specs** — `navigateScreen` and `goBackScreen` are registered by MythikApp and call the AppEngine directly. The built-in `navigate` and `goBack` only set state intents. Always use `navigateScreen`/`goBackScreen` in specs for navigation that works. Example: `{ "action": "goBackScreen" }` goes back to the previous screen in the navigation history, regardless of which screen navigated to the current one
|
|
1977
|
-
91. **CLI `--table` flag overrides
|
|
1991
|
+
91. **CLI `--table` flag overrides the current spec table** — all commands accept `--table <name>` to read/write from a different base table. Use `--table api_specs` to operate on api-specs. The flag overrides the base table for Supabase, SQL Server, PostgreSQL, MySQL, and SQLite stores. Version and environment tables are configured separately with `MYTHIK_VERSIONS_TABLE`, `MYTHIK_ENVIRONMENTS_TABLE`, or the equivalent `.mythikrc` SQL settings.
|
|
1978
1992
|
92. **`push` and `patch` version automatically with `--author`** — when `--author` is provided, both commands use `VersionedSpecStore.saveVersion()` instead of `SpecStore.save()`. The version includes author, source type (`push`/`patch`), and optional `--description`. Without `--author`, commands work as before (no versioning). Example: `mythik patch screen-id --author alice --description "Fixed layout"`
|
|
1979
1993
|
93. **`mythik history` shows inline diffs** — each version in the history output shows the actual changes (before/after values), not just a summary. Uses `computeStructuralDiff` between consecutive versions. Example output: `~ element "btn" prop content: "Send" → "Submit"`
|
|
1980
1994
|
95. **`ai-context.md` is the AI-optimized spec reference** — compressed from this reference-doc (1145 lines vs 2658). Use ai-context.md for spec generation, reference-doc for full human reference. Validated via agent-based testing with progressive difficulty levels (L1-L4). Test scenarios in `../ai-context-test-scenarios.md`, results in `../ai-context-test-results.md` (framework-dev, not part of consumer publish surface)
|
|
1981
1995
|
|
|
1982
|
-
94. **
|
|
1996
|
+
94. **Generic SQL versioned stores are available** — `resolveVersionedStore` supports `sqlserver`, `postgres`, `mysql`, and `sqlite` store types. It creates a driver-backed `SqlVersionedSpecStore` (specs + version history) plus `SqlEnvironmentStore` (environment pointers). Requires `screens`, `screen_versions`, and `screen_environments`; initialize with `mythik init-store` or apply the DDL from `mythik init-store --dry-run`.
|
|
1983
1997
|
96. **SupabaseVersionedSpecStore available** — `resolveVersionedStore` supports `supabase` store type. Uses PostgREST REST API (no `@supabase/supabase-js` dependency). Same snapshot+patches pattern as SqlServer. Environment upsert uses `on_conflict=screen_id,environment` for PostgREST compatibility. Requires `screen_versions` and `screen_environments` tables created in Supabase dashboard
|
|
1984
1998
|
97. **`variant` is a universal prop** — any primitive can use `variant` when component variants are defined in `tokens.components.{type}.{variant}`. The validator accepts `variant` on all primitives (via `COMMON_PROPS`). The render engine resolves variants before passing props to the primitive
|
|
1985
1999
|
98. **Use DNA seeds for app identity** — define `tokens.dna` in AppSpec with 1-8 seed values. The framework derives all visual tokens (colors via OKLCH tonal palette, shape, typography, spacing, elevation, motion, opacity) plus auto dark mode. No manual color palette or radius scale needed — DNA generates it from `{ "primary": "#0D9488" }`
|
|
@@ -3043,7 +3057,7 @@ The current background and motion stack combines app-level `LayerBackground`, an
|
|
|
3043
3057
|
|
|
3044
3058
|
211. **`useShapeAnimations(ref, animations, options)` — Layer 3 web runner** — Exported from `mythik-react` via `packages/react/src/animation/useShapeAnimations.ts`. React hook for SVG-child animations (`<path>`/`<circle>`/`<rect>`/`<g>`…). Consumes the same `ElementAnimations` contract as `useElementAnimations` but narrowed to the `ambient` trigger ONLY; shape children have no hover/focus/active contract and no distinct mount ceremony. Attaches CSS animations via `el.style.animation` (surgical, preserves other inline styles); keyframes register once through the CSSOM singleton (zero `dangerouslySetInnerHTML`) and dedupe by hash so multiple shape instances with the same recipe share one CSS rule. Dev mode warns when non-ambient triggers are passed. Production silently ignores them. `options.recipes` SHOULD be stable for useMemo performance.
|
|
3045
3059
|
|
|
3046
|
-
212. **`useShapeAnimations(animations, options)` — Layer 3 RN runner** — Repository-preview implementation in `packages/react-native/src/animation/useShapeAnimations.ts`; it is not part of the
|
|
3060
|
+
212. **`useShapeAnimations(animations, options)` — Layer 3 RN runner** — Repository-preview implementation in `packages/react-native/src/animation/useShapeAnimations.ts`; it is not part of the supported npm publish surface yet. Reanimated parity of rule 211: returns `{ animatedProps }` that the consumer spreads onto `Animated.createAnimatedComponent(Path)` from `react-native-svg`. Uses the `HARD_PER_TRIGGER` (=6) fixed-pool `useSharedValue` pattern (`useSharedValueArray` helper, also exported) so React Hook count stays stable. Reuses `composeRNStyle(contributions, interpolate, interpolateColor)` shared with `useElementAnimations` — single composition pipeline for View-style and animated SVG props. Relies on `react-native-svg` v13+ auto-translating the transform array into SVG `transform="..."` strings. Same dev-mode non-ambient-trigger warning as the web hook.
|
|
3047
3061
|
|
|
3048
3062
|
213. **Cross-platform Layer 3 parity pins** — `buildCSSKeyframes` (web) and `buildReanimatedSpec` (RN) interpret the same resolved `AnimationSpec` identically on load-bearing invariants: duration agreement (ms count matches regardless of input form `'28s'`/`'28000'`), keyframe stop count (web `%` markers match RN `inputRange` length), direction semantic (`'alternate'` token ⇔ `timing.reverse=true`), iterations `'infinite'`/numeric count, animated-prop enumeration (`translateX/Y`/`rotateDeg`/`scale`).
|
|
3049
3063
|
|
|
@@ -3115,7 +3129,7 @@ The current background and motion stack combines app-level `LayerBackground`, an
|
|
|
3115
3129
|
243. **CRUD endpoint generates 3 routes from 1 declaration** — an endpoint with `crud: { table, primaryKey, insertable, updatable }` generates `POST <path>`, `PUT <path>/:id`, `DELETE <path>/:id`. Do not declare 3 endpoints. See `ai-context-runtime-semantics.md § 3.1`.
|
|
3116
3130
|
244. **`/api/auth/login` expects `{ username, password }`** — not `email`. Use `loginBody` template to map consumer email convention → framework username. See `ai-context-runtime-semantics.md § 3.2`.
|
|
3117
3131
|
245. **Query endpoints envelope responses in `{ data: [...] }`** — shape is `{ data, total?, page?, pageSize?, totals? }`. Consumer specs read `response.data` via state; envelope is NOT auto-unwrapped. See `ai-context-runtime-semantics.md § 3.3`.
|
|
3118
|
-
246. **Browser vs Server entries — `mythik` vs `mythik/server`** (v0.1.0). The default `mythik` entry is browser-safe by construction: zero transitive Node-only imports. `FileSpecStore`, `
|
|
3132
|
+
246. **Browser vs Server entries — `mythik` vs `mythik/server`** (v0.1.0). The default `mythik` entry is browser-safe by construction: zero transitive Node-only imports. `FileSpecStore`, generic SQL stores (`SqlSpecStore`, `SqlVersionedSpecStore`, `SqlEnvironmentStore`), SQL drivers (`createSqlDriver`, `getSqlStoreDdl`), and SQL Server compatibility stores live in `mythik/server`.
|
|
3119
3133
|
|
|
3120
3134
|
247. **`derive` and `dataSources` are processed at runtime per spec mount** (v0.1.0). When `spec.derive` is present, the framework instantiates a `DeriveEngine`, evaluates all derive paths in topological order at mount, and re-evaluates dirty paths reactively on state changes. Derive paths are protected: setState targeting a derive path errors at validate time and runtime. When `spec.dataSources` is present, the framework instantiates a `DataSourcesEngine`, performs initial fetches (deferred to reactive resolution when URL template deps are undefined), and re-fetches reactively when dependencies change. The action `refreshDataSource` (params: `{ id: string }`) is automatically registered for any spec with dataSources. URL templating requires the explicit `{ $template: '...' }` form — plain strings with `${...}` are NOT substituted (validator catches at load). See `ai-context-runtime-semantics.md` for lifecycle, ordering, error degradation, and state protection details.
|
|
3121
3135
|
|
|
@@ -3144,7 +3158,7 @@ Exit codes: 0 = no errors, 1 = errors found, 2 = runtime error (e.g., unreadable
|
|
|
3144
3158
|
|
|
3145
3159
|
See `ai-context.md` for spec-gen anti-patterns the AI must NOT generate.
|
|
3146
3160
|
|
|
3147
|
-
250. **Storage tables are
|
|
3161
|
+
250. **Storage tables are initialized explicitly, never silently at runtime** (v0.1.0). SQL-backed stores operate against three tables the consumer database must already have: `screens` (base, required), `screen_versions` (version history), and `screen_environments` (environment promotions). Use `mythik init-store --dialect <sqlserver|postgres|mysql|sqlite> --dry-run` to inspect canonical idempotent DDL, initialize a local SQLite file with `mythik init-store --dialect sqlite --target ./mythik.db`, or initialize a reachable SQL Server store with explicit `--server`, `--database`, `--user`, `--password`, `--encrypt`, and `--trust-server-certificate` flags. The same schema is described in `ai-context.md § Storage Setup`. Runtime reads/writes do not create missing tables. Production deployment scripts should verify required columns after apply.
|
|
3148
3162
|
251. **`security.exposeErrors` controls render error detail** (v0.1.0). Default is `true`; set `createMythik({ security: { exposeErrors: false } })` for production-like hosts that must avoid leaking error messages/stacks. `_error` render nodes write diagnostics to `/ui/renderErrors` only when exposure is enabled. Primitive/component exceptions are caught by `MythikRenderer`'s error boundary: development + exposed mode shows an overlay with message and component stack; production or `exposeErrors: false` shows a neutral placeholder. The overlay resets when the spec changes so a corrected spec can recover without remounting the host.
|
|
3149
3163
|
252. **Icon packs register through `plugins.setIconRenderer`** (v0.1.0). Mythik does not bundle Phosphor/Lucide/etc. Register one host-level renderer from `MythikApp.onPlugins`; the built-in `icon` primitive keeps identity behavior and calls the renderer with `{ name, size, weight, color, style }`. If the placeholder circle renders, verify `onPlugins` registered the renderer and the consumer is not validating against stale tarballs or source aliases.
|
|
3150
3164
|
253. **`overridePrimitive('icon')` returns a RenderNode, not JSX** (v0.1.0). Use it only for full primitive replacement. The renderer function must return `{ type, props, children }` with `_component` in props when targeting React. Returning `<Icon />` directly is not the primitive renderer contract and bypasses the built-in icon identity wrapper.
|
|
@@ -3204,3 +3218,11 @@ See `ai-context.md` for spec-gen anti-patterns the AI must NOT generate.
|
|
|
3204
3218
|
284. **DNA numeric seeds are canonical `0–1`, with legacy `0–100` normalization** - Generate `tokens.dna.roundness`, `density`, `depth`, and `formality` as `0–1` numbers (`0.7`, not `70`). The runtime normalizes numeric seed values greater than `1` by dividing by `100` inside DNA derivation, so initial AppSpec load and runtime `updateTokens` share the same backward-compatible behavior.
|
|
3205
3219
|
285. **Scoped pagination counts filter before aggregation** - Query endpoints may combine `pagination: "offset"` with `scopeFilter`. For generated counts, the server applies the scope filter to the query source first and then counts the scoped source, so the response `total` matches the same tenant/role slice as `data`. Prefer generated counts. If custom `endpoint.count` is truly needed with `scopeFilter`, it must include `{{scopeWhere[:alias]}}` or `{{scopeAnd[:alias]}}`; Mythik expands the macro to the correct scope predicate and removes it for bypass roles. Other custom count SQL is left verbatim. Specs should use `:alias` for JOIN/subquery counts and should not reference internal scope parameter names directly.
|
|
3206
3220
|
286. **Transaction fetch failures preserve backend error details** - When a transaction `confirm` uses `fetch` and the backend returns an HTTP error payload such as `{ error: { code, message } }`, `/tx/error` is written after rollback with the best backend message plus `code`, HTTP `status`, and raw `data`. `onError` should read `/tx/error/message`; transaction specs should not read global `/ui/lastError`.
|
|
3221
|
+
287. **SQL-backed stores and servers use one dialect-aware `mythik/server` boundary** - Import `createSqlDriver`, `SqlSpecStore`, `SqlVersionedSpecStore`, `SqlEnvironmentStore`, and `getSqlStoreDdl` from `mythik/server` for Node-side SQL work. Supported dialects are `sqlserver`, `postgres`, `mysql`, and `sqlite`. Initialize store tables with `mythik init-store --dialect <dialect>` for reachable SQL stores, `--target` for SQLite, or `--dry-run` for review/apply through a deployment process. SQL Server `init-store` accepts explicit `--server`, `--database`, `--user`, `--password`, `--encrypt`, and `--trust-server-certificate` flags. CLI commands share the same store flags/env vars and must keep existing-spec edits on the `manifest -> elements -> patch --from-file -> validate` loop. ApiSpec `dialect` controls generated CRUD/catalog/pagination/scope SQL; custom SQL remains dialect-native with Mythik named params (`@name`) and is not translated between dialects.
|
|
3222
|
+
288. **Event arrays may mix actions and transactions** - Event bindings can be a single action, a single transaction, or an array containing both normal action bindings and transaction bindings. Mythik executes the array sequentially and awaits each transaction before continuing. Transaction phases cannot contain nested transactions.
|
|
3223
|
+
289. **`$let` dotted references read nested binding values** - A `$ref` may target an object binding path such as `{ "$ref": "user.name" }`, and `$template` placeholders may read the same path as `${user.name}`. Use this for object values produced by `$let`; missing dotted `$ref` segments are invalid references and should be fixed instead of treated as optional data.
|
|
3224
|
+
290. **`params.skipIf` is a dispatch-time action guard** - Any action binding may include `params.skipIf`. Mythik resolves it before resolving the rest of the params; when truthy, the action is skipped and the action chain continues. The action handler never receives `skipIf`.
|
|
3225
|
+
291. **Direct `fetch` supports `errorTarget` for visible screen-load failures** - `fetch.params.errorTarget` writes HTTP/network errors to a consumer-owned state path and clears it on success. Use it for critical `initialActions` loads so the screen can render a local banner/empty state; `/ui/lastError` remains global compatibility state and can be overwritten by unrelated fetches.
|
|
3226
|
+
292. **`select` supports catalog keys and invalid-option diagnostics** - `select.options` may be strings, `{ label, value }`, or catalog-shaped objects when `labelKey`/`valueKey` are provided. Values emitted from the primitive are strings. Malformed option data renders as disabled diagnostics instead of blank clickable options or crashes, so AI-generated catalog bindings fail visibly.
|
|
3227
|
+
293. **SQL adapters are optional peer dependencies** - `mythik` does not install SQL drivers by default. Browser-only apps install `mythik mythik-react`. SQL-backed stores/servers must install exactly the selected adapter (`mssql`, `pg`, `mysql2`, or `better-sqlite3`). SQLite uses native `better-sqlite3`; warnings from its transitive native-build helpers are adapter-level install warnings, not Mythik runtime failures.
|
|
3228
|
+
294. **Missing SQL adapter errors are actionable** - If a SQL-backed store or server uses a dialect whose adapter package is not installed, Mythik throws `SqlDriverError` with `code: "SQL_DRIVER_DEPENDENCY_MISSING"`, `packageName`, `installCommand`, and a message containing the exact `npm install ...` command.
|
|
@@ -15,7 +15,7 @@ Compiled from `docs/consumer/` into **327 atomic articles**. The wiki is optimiz
|
|
|
15
15
|
## Publish notes
|
|
16
16
|
|
|
17
17
|
- Public package names are unscoped: `mythik`, `mythik-react`, `mythik-cli`, `mythik-server`.
|
|
18
|
-
- React Native work is a repository preview track, not part of the
|
|
18
|
+
- React Native work is a repository preview track, not part of the supported npm publish surface yet.
|
|
19
19
|
- The wiki metadata folder is not publish content.
|
|
20
20
|
- `docs/consumer` remains the canonical source.
|
|
21
21
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Lint Report -
|
|
2
|
-
|
|
3
|
-
Validation of cross-references, stale public references, and generated wiki shape after refreshing
|
|
1
|
+
# Lint Report - Event Binding Guard Refresh
|
|
2
|
+
|
|
3
|
+
Validation of cross-references, stale public references, and generated wiki shape after refreshing the compiled wiki delta from `docs/consumer` on 2026-05-09.
|
|
4
4
|
|
|
5
5
|
## Broken Cross-References
|
|
6
6
|
|
|
@@ -24,11 +24,16 @@ Validation of cross-references, stale public references, and generated wiki shap
|
|
|
24
24
|
- Migration pages removed: **yes** (`migration-*.md` no longer publish)
|
|
25
25
|
- Metadata folder publish status: **excluded**
|
|
26
26
|
|
|
27
|
-
## Key Refresh Additions
|
|
28
|
-
|
|
29
|
-
- `
|
|
30
|
-
-
|
|
31
|
-
- `
|
|
27
|
+
## Key Refresh Additions
|
|
28
|
+
|
|
29
|
+
- Dotted `$let` binding reads for `$ref` and `$template`
|
|
30
|
+
- Mixed event arrays containing actions plus transactions
|
|
31
|
+
- `params.skipIf` dispatch-time action guards
|
|
32
|
+
- Optional SQL adapter dependency wording
|
|
33
|
+
- Generic SQL store / driver package-layout pages
|
|
34
|
+
- `concept-public-package-names`
|
|
35
|
+
- `cli-existing-spec-edit-loop`
|
|
36
|
+
- `primitive-spatial-map`
|
|
32
37
|
- `concept-spatial-map-editor`
|
|
33
38
|
- `concept-spatial-map-zones`
|
|
34
39
|
- `concept-editor-sessions`
|
|
@@ -20,7 +20,8 @@ transactions, `GET` in `initialActions`). For reactive GETs, prefer
|
|
|
20
20
|
"method"?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE",
|
|
21
21
|
"headers"?: <object-or-$state>,
|
|
22
22
|
"body"?: <object-with-expressions>,
|
|
23
|
-
"target"?: "/state/path"
|
|
23
|
+
"target"?: "/state/path",
|
|
24
|
+
"errorTarget"?: "/ui/screen-owned-error-path"
|
|
24
25
|
}}
|
|
25
26
|
```
|
|
26
27
|
|
|
@@ -30,6 +31,9 @@ transactions, `GET` in `initialActions`). For reactive GETs, prefer
|
|
|
30
31
|
- **Empty strings in body → `null`** (prevents DB errors on typed columns).
|
|
31
32
|
- Sets `/ui/loading` to `true` while in flight; `false` when done.
|
|
32
33
|
- On error: writes `/ui/lastError` with status and message.
|
|
34
|
+
- If `errorTarget` is provided, writes the same structured error there and
|
|
35
|
+
clears it on success. Use this for critical `initialActions` screen loads
|
|
36
|
+
instead of relying only on global `/ui/lastError`.
|
|
33
37
|
- **Auth headers auto-injected** for URLs whose hostname matches
|
|
34
38
|
`auth.authDomains` — see [[@concept-auth-domains]].
|
|
35
39
|
|
|
@@ -50,7 +54,8 @@ POST with body:
|
|
|
50
54
|
"title": { "$state": "/form/title" },
|
|
51
55
|
"description": { "$state": "/form/description" }
|
|
52
56
|
},
|
|
53
|
-
"target": "/lastResult"
|
|
57
|
+
"target": "/lastResult",
|
|
58
|
+
"errorTarget": "/ui/loadErrors/taskCreate"
|
|
54
59
|
}}
|
|
55
60
|
```
|
|
56
61
|
|