@ultimat3/cli 29.4.0 → 30.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/CLAUDE.md +64 -40
- package/README.md +61 -11
- package/package.json +42 -28
- package/src/affected-tests.ts +97 -0
- package/src/affected-unowned.ts +43 -0
- package/src/affected.ts +25 -6
- package/src/app-boundaries.ts +29 -1
- package/src/app-evals.ts +12 -4
- package/src/app-load-unresolved.ts +62 -0
- package/src/app-load.ts +30 -37
- package/src/app-mcp.ts +14 -2
- package/src/app-module-graph.ts +232 -0
- package/src/app-reload-graph.ts +2 -2
- package/src/app-root.ts +37 -1
- package/src/bin.ts +1 -0
- package/src/boundary-findings.ts +6 -0
- package/src/budgets-freshness.ts +32 -0
- package/src/budgets.ts +20 -1
- package/src/build-capture-env.ts +9 -0
- package/src/cdp-shot-a11y.ts +2 -39
- package/src/ci-tested.ts +243 -0
- package/src/client-emit-customer-runtime.ts +139 -0
- package/src/client-emit-customer.ts +108 -0
- package/src/client-emit-drift.ts +72 -0
- package/src/client-emit-header.ts +67 -0
- package/src/client-emit-schemas.ts +175 -0
- package/src/client-emit-types.ts +121 -0
- package/src/client-emit-vendor.ts +146 -0
- package/src/client-errors-routes.ts +229 -0
- package/src/client-errors-script.ts +74 -0
- package/src/client-vitals-route.ts +197 -0
- package/src/client-vitals-script.ts +56 -0
- package/src/cmd-affected.ts +23 -0
- package/src/cmd-build-spec.ts +7 -1
- package/src/cmd-build.ts +35 -9
- package/src/cmd-ci-spec.ts +42 -6
- package/src/cmd-ci.ts +99 -2
- package/src/cmd-client-customer.ts +134 -0
- package/src/cmd-client-source.ts +81 -0
- package/src/cmd-client-spec.ts +48 -0
- package/src/cmd-client-write.ts +41 -0
- package/src/cmd-client.ts +111 -0
- package/src/cmd-db-recount.ts +120 -0
- package/src/cmd-db-spec.ts +36 -6
- package/src/cmd-db.ts +11 -3
- package/src/cmd-deploy-compose.ts +61 -3
- package/src/cmd-deploy-drain.ts +10 -2
- package/src/cmd-deploy-helm.ts +11 -0
- package/src/cmd-deploy-preflight.ts +118 -0
- package/src/cmd-deploy-spec.ts +58 -6
- package/src/cmd-deploy-verify.ts +380 -0
- package/src/cmd-deploy.ts +42 -9
- package/src/cmd-docs.ts +34 -4
- package/src/cmd-doctor.ts +66 -9
- package/src/cmd-drill-spec.ts +25 -0
- package/src/cmd-drill.ts +176 -0
- package/src/cmd-env-init.ts +102 -0
- package/src/cmd-env-spec.ts +10 -3
- package/src/cmd-env.ts +15 -10
- package/src/cmd-errors-recent.ts +60 -0
- package/src/cmd-errors-spec.ts +9 -1
- package/src/cmd-errors.ts +4 -0
- package/src/cmd-exercise-spec.ts +19 -0
- package/src/cmd-exercise.ts +129 -0
- package/src/cmd-generate-spec.ts +9 -1
- package/src/cmd-generate.ts +32 -27
- package/src/cmd-graph-load.ts +97 -0
- package/src/cmd-graph-spec.ts +16 -0
- package/src/cmd-graph.ts +73 -0
- package/src/cmd-i18n.ts +4 -1
- package/src/cmd-impact-spec.ts +13 -0
- package/src/cmd-impact.ts +64 -0
- package/src/cmd-jobs-resolve.ts +76 -0
- package/src/cmd-jobs-spec.ts +21 -2
- package/src/cmd-jobs.ts +10 -6
- package/src/cmd-mail-spec.ts +28 -0
- package/src/cmd-mail.ts +70 -0
- package/src/cmd-mcp-lock.ts +69 -0
- package/src/cmd-mcp-spec.ts +23 -4
- package/src/cmd-mcp.ts +17 -3
- package/src/cmd-new-spec.ts +8 -1
- package/src/cmd-new.ts +61 -9
- package/src/cmd-planned.ts +0 -6
- package/src/cmd-repro-spec.ts +31 -0
- package/src/cmd-repro.ts +174 -0
- package/src/cmd-stop-spec.ts +21 -0
- package/src/cmd-stop.ts +166 -0
- package/src/cmd-test-spec.ts +17 -4
- package/src/cmd-test.ts +70 -14
- package/src/cmd-upgrade-spec.ts +26 -0
- package/src/cmd-upgrade.ts +274 -0
- package/src/cmd-verify-spec.ts +3 -3
- package/src/db-backfill.ts +6 -0
- package/src/db-diagnostics.ts +106 -0
- package/src/db-generate.ts +9 -0
- package/src/db-reset-template.ts +1 -1
- package/src/db-rolling.ts +45 -0
- package/src/db-seed-generate.ts +188 -0
- package/src/deploy-verify-findings.ts +98 -0
- package/src/deploy-verify-flags.ts +109 -0
- package/src/deploy-verify-grade.ts +185 -0
- package/src/deploy-verify-queues.ts +53 -0
- package/src/dev-boot.ts +35 -15
- package/src/dev-child-watch.ts +16 -4
- package/src/dev-dashboard-guard.ts +8 -1
- package/src/dev-dashboard.ts +7 -0
- package/src/dev-lock-identity.ts +61 -0
- package/src/dev-lock-port-holder.ts +80 -0
- package/src/dev-lock-steal.ts +124 -0
- package/src/dev-lock.ts +92 -120
- package/src/dev-mail-templates.ts +51 -0
- package/src/dev-rebuild.ts +26 -2
- package/src/dev-route-table.ts +17 -0
- package/src/dev-supervisor.ts +5 -2
- package/src/dev-watch-tree.ts +11 -10
- package/src/dev-watch.ts +1 -1
- package/src/dispatch.ts +29 -6
- package/src/docs-section.ts +69 -0
- package/src/docs-sources.ts +100 -0
- package/src/doctor-auth.ts +11 -2
- package/src/doctor-chart-alerts.ts +55 -0
- package/src/doctor-pooler.ts +107 -0
- package/src/doctor-rolling.ts +35 -0
- package/src/doctor-row-security.ts +40 -0
- package/src/document-options.ts +13 -0
- package/src/drill-sync-lane.ts +25 -0
- package/src/drill-targets.ts +39 -0
- package/src/duplicate-packages.ts +1 -1
- package/src/env-production.ts +93 -0
- package/src/error-codes-shot.ts +59 -0
- package/src/error-codes-tooling.ts +29 -0
- package/src/error-codes.ts +100 -54
- package/src/error-contract.ts +2 -2
- package/src/errors.ts +22 -3
- package/src/exercise-database.ts +99 -0
- package/src/exercise-findings.ts +159 -0
- package/src/exercise-overrides.ts +42 -0
- package/src/exercise-registration.ts +58 -0
- package/src/exercise-static.ts +88 -0
- package/src/exercise-subject.ts +69 -0
- package/src/failure-capture-boot.ts +30 -0
- package/src/framework-env.ts +7 -1
- package/src/framework-schema.ts +72 -5
- package/src/generate-catalog-locales.ts +19 -0
- package/src/generate-chart-alerts.ts +156 -0
- package/src/generate-feature-required.ts +65 -0
- package/src/generate-feature.ts +83 -6
- package/src/generate-files.ts +24 -0
- package/src/generate-format-written.ts +32 -0
- package/src/generate-kinds.ts +6 -0
- package/src/generate-sign-in-config.ts +100 -0
- package/src/generate-sign-in-manifest.ts +28 -0
- package/src/generate-sign-in-mode.ts +101 -0
- package/src/generate-sign-in.ts +250 -0
- package/src/generate-write.ts +44 -7
- package/src/hand-rolled-socket.ts +72 -0
- package/src/i18n-app-key-shapes.ts +29 -0
- package/src/i18n-audit.ts +10 -3
- package/src/i18n-registration.ts +18 -3
- package/src/index.ts +2 -0
- package/src/island-bundle.ts +4 -3
- package/src/island-disposer.ts +116 -0
- package/src/island-realtime-state.ts +34 -6
- package/src/island-realtime.ts +6 -2
- package/src/island-routes.ts +3 -2
- package/src/isr-query-advice.ts +6 -11
- package/src/isr-query-guard.ts +4 -3
- package/src/job-budget.ts +95 -0
- package/src/jobs-json.ts +11 -0
- package/src/lint-findings.ts +104 -0
- package/src/local-cli.ts +34 -4
- package/src/loopback-host.ts +2 -2
- package/src/mail-preview-findings.ts +24 -0
- package/src/mcp-errors.ts +82 -2
- package/src/mcp-host.ts +11 -1
- package/src/mcp-lock-findings.ts +57 -0
- package/src/measure-paths.ts +12 -4
- package/src/measure-scope.ts +27 -13
- package/src/messages-client.ts +23 -0
- package/src/messages-db.ts +56 -0
- package/src/messages-gate.ts +107 -0
- package/src/messages-repro.ts +11 -0
- package/src/messages-shot.ts +51 -0
- package/src/messages-upgrade.ts +45 -0
- package/src/messages.ts +53 -178
- package/src/metrics-endpoint.ts +23 -5
- package/src/new-shapes-generate.ts +71 -0
- package/src/new-shapes.ts +63 -0
- package/src/openapi-compile-ir.ts +68 -0
- package/src/openapi-compile-schema.ts +284 -0
- package/src/openapi-compile.ts +273 -0
- package/src/openapi-refuse.ts +45 -0
- package/src/otlp-export.ts +2 -1
- package/src/output-findings.ts +123 -0
- package/src/output.ts +32 -8
- package/src/package-boundaries.ts +110 -0
- package/src/page-pins.ts +23 -0
- package/src/plain-routes.ts +13 -0
- package/src/prerender-entries.ts +59 -0
- package/src/prerender-heaviest.ts +27 -0
- package/src/prerender-preload.ts +6 -0
- package/src/prerender-report.ts +12 -0
- package/src/prerender-seo-reads.ts +38 -0
- package/src/prerender-served.ts +22 -7
- package/src/prerender-vitals.ts +42 -0
- package/src/prerender.ts +61 -32
- package/src/pwa-artifacts.ts +4 -3
- package/src/pwa-manifest-locales.ts +1 -1
- package/src/registry.ts +18 -0
- package/src/repro-bundle.ts +65 -0
- package/src/repro-errors.ts +47 -0
- package/src/repro-job.ts +72 -0
- package/src/repro-literal.ts +41 -0
- package/src/repro-request.ts +48 -0
- package/src/repro-write.ts +100 -0
- package/src/retain-sweep.ts +27 -0
- package/src/retained-assets-boot.ts +113 -0
- package/src/retained-assets-layout.ts +110 -0
- package/src/retained-assets-read.ts +142 -0
- package/src/retained-assets-sweep.ts +70 -0
- package/src/retained-assets.ts +171 -0
- package/src/revalidated-response.ts +8 -5
- package/src/role-replicator.ts +7 -1
- package/src/role-start-devices.ts +119 -0
- package/src/role-start-types.ts +6 -0
- package/src/role-start.ts +22 -5
- package/src/role-sync.ts +7 -1
- package/src/route-islands.ts +42 -0
- package/src/route-table.ts +2 -1
- package/src/row-security-boot.ts +58 -0
- package/src/row-security-wanted.ts +32 -0
- package/src/runtime-admin.ts +0 -1
- package/src/runtime-assets-site-cache.ts +55 -0
- package/src/runtime-assets-site.ts +136 -0
- package/src/runtime-assets.ts +99 -55
- package/src/runtime-bindings.ts +19 -3
- package/src/runtime-cache.ts +23 -14
- package/src/runtime-isr-outcome.ts +114 -60
- package/src/runtime-purge.ts +14 -2
- package/src/runtime-queue.ts +31 -4
- package/src/runtime-render-document.ts +204 -0
- package/src/runtime-render.ts +48 -198
- package/src/runtime-replica-position.ts +62 -0
- package/src/runtime-replica.ts +18 -3
- package/src/runtime-s3-path-style.ts +17 -0
- package/src/runtime-services.ts +19 -6
- package/src/runtime-statement-bound.ts +22 -0
- package/src/runtime-storage-upload.ts +9 -0
- package/src/runtime-storage.ts +41 -81
- package/src/schema-diff-views.ts +54 -0
- package/src/schema-diff.ts +21 -3
- package/src/schema-drift.ts +28 -9
- package/src/schema-dump-drift.ts +91 -7
- package/src/script-csp.ts +1 -1
- package/src/seo-cards.ts +26 -0
- package/src/seo-routes.ts +22 -8
- package/src/serve-boot.ts +54 -21
- package/src/serve-drain.ts +1 -0
- package/src/serve-env.ts +26 -8
- package/src/serve-retire.ts +12 -6
- package/src/serve-web.ts +42 -4
- package/src/serve.ts +9 -7
- package/src/site-asset-routes.ts +7 -1
- package/src/site-config.ts +4 -0
- package/src/site-llms-pages.ts +106 -0
- package/src/site-llms.ts +64 -0
- package/src/site-seo-write.ts +4 -2
- package/src/site-seo.ts +55 -6
- package/src/source-mtime.ts +50 -0
- package/src/static-capture-errors.ts +41 -0
- package/src/static-capture.ts +56 -0
- package/src/static-cards-serve.ts +39 -0
- package/src/static-cards.ts +93 -0
- package/src/static-document.ts +14 -13
- package/src/static-images.ts +115 -0
- package/src/stream-hole-scope.ts +55 -0
- package/src/style-bundle.ts +1 -1
- package/src/style-routes.ts +3 -2
- package/src/sw-precache-plan.ts +2 -2
- package/src/sw-routes.ts +2 -2
- package/src/templates/action-tests.ts +306 -0
- package/src/templates/action.ts +81 -269
- package/src/templates/backfill.ts +1 -1
- package/src/templates/entity.ts +21 -5
- package/src/templates/github/ci.yml.ts +8 -9
- package/src/templates/guard-bare-error.ts +2 -2
- package/src/templates/guard-error-declared.ts +263 -0
- package/src/templates/guard-native-confirm.ts +132 -0
- package/src/templates/guard-raw-fetch.ts +151 -0
- package/src/templates/guard-raw-interval.ts +121 -0
- package/src/templates/guard-repo-raw-sql.ts +71 -2
- package/src/templates/job.ts +1 -1
- package/src/templates/naming.ts +5 -0
- package/src/templates/pinned/docker-compose.yml +6 -0
- package/src/templates/pinned-images.ts +8 -0
- package/src/templates/policy.ts +85 -2
- package/src/templates/query.ts +70 -13
- package/src/templates/resource-create.ts +3 -1
- package/src/templates/resource-form-island.ts +15 -4
- package/src/templates/resource-page-db.ts +83 -0
- package/src/templates/resource-page.ts +161 -52
- package/src/templates/route.ts +4 -6
- package/src/templates/scaffold-app.ts +3 -0
- package/src/templates/scaffold-auth.ts +2 -1
- package/src/templates/scaffold-bin.ts +5 -52
- package/src/templates/scaffold-claude-agents.ts +19 -19
- package/src/templates/scaffold-claude-commands.ts +28 -31
- package/src/templates/scaffold-claude.ts +26 -23
- package/src/templates/scaffold-container-compose.ts +6 -1
- package/src/templates/scaffold-container.ts +24 -4
- package/src/templates/scaffold-dashboard-bare.ts +3 -3
- package/src/templates/scaffold-dashboard-example-tests.ts +49 -9
- package/src/templates/scaffold-dashboard-example-view.ts +156 -0
- package/src/templates/scaffold-dashboard-example.ts +43 -131
- package/src/templates/scaffold-dashboard-shared.ts +3 -7
- package/src/templates/scaffold-db-client.ts +20 -6
- package/src/templates/scaffold-db-package.ts +5 -14
- package/src/templates/scaffold-docs.ts +73 -57
- package/src/templates/scaffold-domain-package.ts +18 -14
- package/src/templates/scaffold-entries.ts +7 -2
- package/src/templates/scaffold-exercise.ts +37 -0
- package/src/templates/scaffold-guards.ts +13 -1
- package/src/templates/scaffold-helm-alerts.ts +234 -0
- package/src/templates/scaffold-helm-templates.ts +7 -5
- package/src/templates/scaffold-helm.ts +46 -12
- package/src/templates/scaffold-i18n.ts +6 -2
- package/src/templates/scaffold-mcp-endpoint.ts +182 -0
- package/src/templates/scaffold-mcp-json.ts +31 -0
- package/src/templates/scaffold-mcp-package.ts +59 -56
- package/src/templates/scaffold-repo.ts +7 -2
- package/src/templates/scaffold-shell.ts +45 -79
- package/src/templates/scaffold-test-services.ts +13 -5
- package/src/templates/shapes/api-keys.ts +170 -0
- package/src/templates/shapes/api.ts +101 -0
- package/src/templates/shapes/blog-site.ts +340 -0
- package/src/templates/shapes/blog-slice.ts +265 -0
- package/src/templates/shapes/blog.ts +114 -0
- package/src/templates/shapes/dashboard-detail.ts +242 -0
- package/src/templates/shapes/dashboard.ts +53 -0
- package/src/templates/shapes/index.ts +17 -0
- package/src/templates/shapes/overlay.ts +99 -0
- package/src/templates/shapes/shared-edits.ts +46 -0
- package/src/templates/sign-in-action-tests.ts +237 -0
- package/src/templates/sign-in-authenticator.ts +112 -0
- package/src/templates/sign-in-oidc.ts +189 -0
- package/src/templates/sign-in-pages.ts +148 -0
- package/src/templates/sign-in-password.ts +216 -0
- package/src/templates/sign-in-shared.ts +268 -0
- package/src/templates/slice-foundation.ts +70 -15
- package/src/test-batches.ts +1 -1
- package/src/test-database.ts +1 -1
- package/src/test-shards.ts +7 -1
- package/src/test-workers.ts +18 -12
- package/src/tool-gate-names.ts +34 -0
- package/src/upgrade-agents-link.ts +49 -0
- package/src/upgrade-bun-floor.ts +225 -0
- package/src/upgrade-gate.ts +228 -0
- package/src/upgrade-pins.ts +63 -0
- package/src/upgrade-plan.ts +214 -0
- package/src/upgrade-registry.ts +53 -0
- package/src/upgrade-report.ts +139 -0
- package/src/upgrade-root.ts +74 -0
- package/src/verify-budgets-build.ts +118 -0
- package/src/verify-checks.ts +67 -24
- package/src/verify-coverage-run.ts +1 -1
- package/src/verify-e2e-lane.ts +41 -0
- package/src/verify-exercise.ts +64 -0
- package/src/verify-floor.ts +41 -0
- package/src/verify-merge.ts +19 -4
- package/src/verify-role-load.ts +2 -0
- package/src/verify-run.ts +28 -8
- package/src/verify-shard.ts +12 -2
- package/src/verify-skip-ceiling.ts +87 -0
- package/src/verify-step.ts +5 -0
- package/src/verify-tests.ts +25 -5
- package/src/view-drift.ts +55 -0
- package/src/worker-bundle.ts +3 -2
- package/src/workspace-graph.ts +38 -19
- package/src/write-generated.ts +43 -0
- package/src/zone-boot.ts +20 -0
- package/wiki/Actions.md +342 -0
- package/wiki/Admin-Dashboard.md +432 -0
- package/wiki/Agents.md +958 -0
- package/wiki/Auth.md +195 -0
- package/wiki/Bare-VM.md +111 -0
- package/wiki/Batching-And-Preloading.md +136 -0
- package/wiki/Building-Your-Own-Base.md +203 -0
- package/wiki/CI-Parallel-Gate.md +220 -0
- package/wiki/CLI-Reference.md +1894 -0
- package/wiki/Caching-And-Invalidation.md +255 -0
- package/wiki/Client-Data.md +194 -0
- package/wiki/Client-Navigation.md +513 -0
- package/wiki/Compared.md +93 -0
- package/wiki/Configuration.md +868 -0
- package/wiki/Contributing.md +12 -0
- package/wiki/Deploy-Recipes.md +122 -0
- package/wiki/Deployment.md +508 -0
- package/wiki/Entities-And-Migrations.md +1116 -0
- package/wiki/FAQ.md +175 -0
- package/wiki/Feature-Flags.md +65 -0
- package/wiki/Getting-Started.md +221 -0
- package/wiki/Home.md +160 -0
- package/wiki/I18n.md +239 -0
- package/wiki/Installation.md +206 -0
- package/wiki/Interface-Rules.md +339 -0
- package/wiki/Jobs-And-Workflows.md +783 -0
- package/wiki/Known-Gaps.md +185 -0
- package/wiki/MCP-And-AI.md +753 -0
- package/wiki/Mail.md +138 -0
- package/wiki/Migrating-An-Existing-App.md +594 -0
- package/wiki/Migrating-From-Django.md +54 -0
- package/wiki/Migrating-From-Laravel.md +53 -0
- package/wiki/Migrating-From-Node-Drizzle.md +53 -0
- package/wiki/Migrating-From-Rails.md +53 -0
- package/wiki/Migrations-And-Backfills.md +552 -0
- package/wiki/Money.md +338 -0
- package/wiki/N-Plus-One-Detection.md +197 -0
- package/wiki/Notify.md +208 -0
- package/wiki/Observability.md +245 -0
- package/wiki/Outbound-HTTP.md +109 -0
- package/wiki/PWA-And-Offline.md +343 -0
- package/wiki/Policies-And-Authz.md +251 -0
- package/wiki/Project-Layout.md +150 -0
- package/wiki/Queries-And-Live-Queries.md +429 -0
- package/wiki/Realtime.md +734 -0
- package/wiki/Resource-Management.md +121 -0
- package/wiki/Routes-And-Render-Modes.md +521 -0
- package/wiki/SEO.md +288 -0
- package/wiki/Scheduled-Tasks.md +175 -0
- package/wiki/Scraping.md +493 -0
- package/wiki/Shapes.md +63 -0
- package/wiki/Stability.md +97 -0
- package/wiki/Static-Assets.md +166 -0
- package/wiki/Storage-And-Uploads.md +404 -0
- package/wiki/Testing.md +1314 -0
- package/wiki/The-Eight-Primitives.md +247 -0
- package/wiki/Theming.md +362 -0
- package/wiki/Timezones-And-Dates.md +194 -0
- package/wiki/Troubleshooting.md +163 -0
- package/wiki/Tutorial-01-First-App.md +289 -0
- package/wiki/Tutorial-02-First-Feature.md +339 -0
- package/wiki/Tutorial-03-Auth-And-Admin.md +379 -0
- package/wiki/Tutorial-04-Jobs-And-Realtime.md +263 -0
- package/wiki/Tutorial-05-Deploy-Free.md +231 -0
- package/wiki/Tutorial-06-Growing-Up.md +158 -0
- package/wiki/UI-Components.md +156 -0
- package/wiki/Upgrading.md +3667 -0
- package/src/stored-object-headers.ts +0 -43
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Stability
|
|
2
|
+
|
|
3
|
+
**From v30: at most one major every 90 days, the previous major gets security fixes for 6 months after its successor, and a removal is deprecated for at least one minor first.** Each rule is refused by a script, not remembered by a person — the table at the bottom names the code.
|
|
4
|
+
|
|
5
|
+
**Next major window:** opens on `2027-02-05`, 90 days after 30.0.0 (2026-11-07). The bump that ships a major rewrites this line (`scripts/release.ts`).
|
|
6
|
+
|
|
7
|
+
## What is covered
|
|
8
|
+
|
|
9
|
+
A breaking change to any of these needs a major, and a major waits for its window.
|
|
10
|
+
|
|
11
|
+
| Surface | Where it is defined |
|
|
12
|
+
|---|---|
|
|
13
|
+
| the eight primitive shapes: `entity`, `policy`, `action`, `mutator`, `query`, `job`, `route`, `task` | [The eight primitives](The-Eight-Primitives), `PRIMITIVE_KINDS` in `packages/core/src/registrar.ts` |
|
|
14
|
+
| the `x` CLI: every command, every flag, and the `--json` envelope each prints | [CLI reference](CLI-Reference) |
|
|
15
|
+
| every shipped `X_*` code: its name and its meaning. A code is never renamed or reused | [Error codes](Error-Codes) |
|
|
16
|
+
| the package tier table | `scripts/lib/tiers.ts`, [Project layout](Project-Layout#framework-package-tiers) |
|
|
17
|
+
| `app.config.ts` field names: renaming or removing one | [Configuration](Configuration) |
|
|
18
|
+
| every export a package's `src/index.ts` names and its README documents | each package's `README.md` |
|
|
19
|
+
| the Bun floor | `engines` in every `package.json`; it moves only in a scheduled major, or by the security exception |
|
|
20
|
+
|
|
21
|
+
## What is not covered
|
|
22
|
+
|
|
23
|
+
| Not covered | Why |
|
|
24
|
+
|---|---|
|
|
25
|
+
| an export no README documents, and any deep import (`@ultimat3/x/src/...`) | not a public surface; it can change in a minor |
|
|
26
|
+
| `.x/` — the build cache, generated manifests, snapshots | regenerated by the CLI; never hand-edited, never read by an app |
|
|
27
|
+
| the exact wording of a `cause:` or `fix:` line | the code is the contract; the text improves in any release |
|
|
28
|
+
| a gate verdict getting stricter | a new `x verify` rule that reds an app waits on `next` like any break |
|
|
29
|
+
| performance figures and budgets | measurements, re-measured each release ([Routes and render modes](Routes-And-Render-Modes#budgets)) |
|
|
30
|
+
|
|
31
|
+
Never "stable forever": a covered surface can change, in a scheduled major, with its entry in [Upgrading](Upgrading).
|
|
32
|
+
|
|
33
|
+
| Bump | Means | Examples |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| **major** | a covered surface changed incompatibly | a removed config field, a renamed CLI flag, a changed primitive field, a narrowed tier |
|
|
36
|
+
| **minor** | additive: old code still compiles and still passes `x verify` | a new optional field, a new command, a new driver behind an existing interface, a new `@deprecated` alias |
|
|
37
|
+
| **patch** | no surface change | a bug fix, a perf change, a corrected `fix:` line |
|
|
38
|
+
|
|
39
|
+
## Cadence
|
|
40
|
+
|
|
41
|
+
| Release | When | Branch | npm dist-tag |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| major | at most once per 90 days from v30, counted from the previous major's `CHANGELOG.md` heading date | `next`, merged into `main` when the window opens | `latest` |
|
|
44
|
+
| minor | weekly, when something shipped | `main` | `latest` |
|
|
45
|
+
| patch to the current major | as needed | `main` | `latest` |
|
|
46
|
+
| patch to the previous major | security fixes only, until 6 months after its successor shipped | `release/<major>.x` | `maint-<major>` |
|
|
47
|
+
| prerelease of the next major — **planned, nothing ships one yet** | `release-tag.yml` cuts only `X.Y.Z` release commits, so no workflow publishes from `next` | `next` | `next` (`scripts/dist-tag.ts` already names it) |
|
|
48
|
+
|
|
49
|
+
v30 is the exception that starts the clock: it carries every break queued before the promise existed, and `scripts/release.ts` does not refuse it.
|
|
50
|
+
|
|
51
|
+
## The support window
|
|
52
|
+
|
|
53
|
+
| Major | Status | Security fixes until |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| the current major (`npm view @ultimat3/core version`) | every fix | its successor ships, then 6 months more |
|
|
56
|
+
| the previous major | security fixes, as patches on `release/<major>.x` | 6 months after the current major's `## X.0.0` date |
|
|
57
|
+
| anything older | none | [Upgrading](Upgrading), one major per `x upgrade` run |
|
|
58
|
+
|
|
59
|
+
**Convention, not enforced:** `release/<major>.x` is cut by hand at each major and kept at that major's newest minor; no script cuts or checks it. Once it exists, a patch is `latest` while its major is current and `maint-<major>` once its successor ships. `scripts/dist-tag.ts` decides the tag from the registry's `latest`, and `npm publish` never runs without it.
|
|
60
|
+
|
|
61
|
+
## Deprecation
|
|
62
|
+
|
|
63
|
+
A removal or a rename ships its alias, marked `@deprecated`, on `main` for at least one minor before a major takes it away. The rule compares each package's `src/index.ts` export names against the previous release tag: a name that is gone must have carried `@deprecated` there. Runtime deprecation logging is not part of this — it was deleted once, for good reason ([Upgrading](Upgrading)).
|
|
64
|
+
|
|
65
|
+
## Where a break waits
|
|
66
|
+
|
|
67
|
+
| Branch | Holds |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `main` | minors and patches only while the window is closed; a `BREAKING —` changelog entry there is refused |
|
|
70
|
+
| `next` | every breaking change waiting for the window. **Convention, not enforced:** it merges `main` weekly, by hand, so it never falls behind a fix; `ci.yml` gates every push to it |
|
|
71
|
+
| `release/<major>.x` | the previous major's security patches |
|
|
72
|
+
|
|
73
|
+
A change with both kinds of edit splits into two pull requests: the non-breaking half to `main`, the break to `next`.
|
|
74
|
+
|
|
75
|
+
## The security exception
|
|
76
|
+
|
|
77
|
+
A security fix that cannot be made non-breaking may ship a major inside the window. It is the only exception — "critical bug" is not one, or it would be used every week.
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
bun run scripts/release.ts --bump major --security GHSA-xxxx-xxxx-xxxx --dry-run --json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The advisory id (a `GHSA-…` or `CVE-…`) is recorded under the section heading in `CHANGELOG.md` as `> **Security exception:** \`<id>\``, and the bump commit's body carries `Security-Exception: <id>`. The same recorded line lets a removal skip its deprecation minor.
|
|
84
|
+
|
|
85
|
+
## Who decides
|
|
86
|
+
|
|
87
|
+
The maintainer bot judges whether a release is due and which kind (`.dz/briefs/release-due.md`), inside this window: it cannot cut a major the window refuses, because `scripts/release.ts` refuses it before any file moves, `release.ts --check` refuses it again before a tag is cut, and the gate refuses a dated section that broke it.
|
|
88
|
+
|
|
89
|
+
## How each rule is enforced
|
|
90
|
+
|
|
91
|
+
| Rule | Refused by | Code |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| one major per 90 days | `scripts/release.ts --bump`, `--check`, and the gate's `boundaries` step | `X_RELEASE_MAJOR_WINDOW` |
|
|
94
|
+
| no break on `main` while the window is closed | `bun run changelog-check` and the gate, on the pull request's base branch | `X_BREAKING_ON_MAIN` |
|
|
95
|
+
| a removal was deprecated first | `bun run scripts/deprecation-window.ts` and the gate | `X_RELEASE_UNDEPRECATED_REMOVAL` |
|
|
96
|
+
| every release from 30.0.0 opens with Highlights, the Release body | `bun run changelog-check` and the gate | `X_CHANGELOG_HIGHLIGHTS_MISSING` |
|
|
97
|
+
| a maintenance publish never moves `latest` | `scripts/dist-tag.ts` in `release.yml`; `scripts/registry-audit.ts` audits `latest` and each `maint-*` tag | `X_REGISTRY_LATEST_DRIFT` |
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Static assets
|
|
2
|
+
|
|
3
|
+
**A public file lives in `apps/web/site/assets/`, and a page names it with `asset()`.** One call
|
|
4
|
+
returns a content-hashed URL, served `public, max-age=31536000, immutable` by `x dev` and the
|
|
5
|
+
container alike, and copied into the static export under the same name. `As of 2026-09-25` (22.3.0).
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { asset } from '@ultimat3/render';
|
|
9
|
+
import { Image } from '@ultimat3/ui';
|
|
10
|
+
|
|
11
|
+
<Image
|
|
12
|
+
src={asset('assets/hero-1280.jpg')}
|
|
13
|
+
alt=""
|
|
14
|
+
width={1280}
|
|
15
|
+
height={720}
|
|
16
|
+
sizes="(max-width: 700px) 100vw, 1280px"
|
|
17
|
+
priority
|
|
18
|
+
sources={{
|
|
19
|
+
avif: [
|
|
20
|
+
{ src: asset('assets/hero-640.avif'), width: 640 },
|
|
21
|
+
{ src: asset('assets/hero-1280.avif'), width: 1280 },
|
|
22
|
+
],
|
|
23
|
+
webp: [
|
|
24
|
+
{ src: asset('assets/hero-640.webp'), width: 640 },
|
|
25
|
+
{ src: asset('assets/hero-1280.webp'), width: 1280 },
|
|
26
|
+
],
|
|
27
|
+
}}
|
|
28
|
+
/>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`asset('assets/hero-640.avif')` → `/assets/hero-640.3f2a1b9c.avif`.
|
|
32
|
+
|
|
33
|
+
## The rules
|
|
34
|
+
|
|
35
|
+
| Rule | Enforced by |
|
|
36
|
+
|---|---|
|
|
37
|
+
| the path starts with `assets/` and ends in a served extension | the type: `AssetPath` is `` `assets/${string}.${AssetExtension}` ``, so `asset('hero.avif')` and `asset('assets/x.txt')` are TS2345 |
|
|
38
|
+
| the file exists | `X_ASSET_MISSING`, thrown while the page renders, so `x build --target static` fails on it and `x dev` shows it |
|
|
39
|
+
| no `..`, no empty segment, no backslash | `assetPathProblem()`, the same check in the page, the table and the route |
|
|
40
|
+
| only the hashed URL is served | `/assets/hero.avif` is 404; so is a hash that no longer matches the bytes (a document from an earlier build) |
|
|
41
|
+
| the URL changes when the bytes change | the hash is xxHash32 of the file, re-read when its mtime or size changes, with no watcher and no restart |
|
|
42
|
+
| an earlier build's URL survives a deploy | a static host keeps the old hashed file because nothing deletes it. The container answers it only with `assets.retain` in `app.config.ts`, which reads it from a shared disk on a miss ([Deployment](Deployment#hashed-assets-across-a-deploy--assetsretain)); without it, the stale hash is the 404 above |
|
|
43
|
+
|
|
44
|
+
Call `asset()` in a page or a server component, never in an island. A browser has no asset table, so
|
|
45
|
+
there it throws `X_ASSET_MISSING`: pass the URL to the island as a prop instead.
|
|
46
|
+
|
|
47
|
+
## From a stylesheet
|
|
48
|
+
|
|
49
|
+
Sass has the same function, over the same table: `asset('assets/…')` inside `url()` compiles to the
|
|
50
|
+
hashed URL, in `x dev`, the container and `x build --target static` alike.
|
|
51
|
+
|
|
52
|
+
```scss
|
|
53
|
+
@font-face {
|
|
54
|
+
font-family: Inter;
|
|
55
|
+
src: url(asset('assets/fonts/inter-var.woff2')) format('woff2');
|
|
56
|
+
font-display: swap;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.hero { background-image: url(asset('assets/hero-1280.avif')); }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
→ `src: url("/assets/fonts/inter-var.9c1d2e3f.woff2") format("woff2")`. A missing file or a path
|
|
63
|
+
outside `assets/` is `X_ASSET_MISSING` at compile time, naming the path — not a Sass stack. The Sass
|
|
64
|
+
disk cache re-checks every asset a cached sheet named, so a replaced font is never served under its
|
|
65
|
+
old hash. Sass has no table without an app loaded, so a unit test that compiles such a sheet
|
|
66
|
+
installs one with `setAssetResolver`, as below.
|
|
67
|
+
|
|
68
|
+
## Served types
|
|
69
|
+
|
|
70
|
+
| Extension | `content-type` |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `avif` | `image/avif` |
|
|
73
|
+
| `webp` | `image/webp` |
|
|
74
|
+
| `png` | `image/png` |
|
|
75
|
+
| `jpg`, `jpeg` | `image/jpeg` |
|
|
76
|
+
| `gif` | `image/gif` |
|
|
77
|
+
| `svg` | `image/svg+xml` |
|
|
78
|
+
| `ico` | `image/x-icon` |
|
|
79
|
+
| `woff2` | `font/woff2` |
|
|
80
|
+
| `mp4` | `video/mp4` |
|
|
81
|
+
| `webm` | `video/webm` |
|
|
82
|
+
| `vtt` | `text/vtt; charset=utf-8` |
|
|
83
|
+
|
|
84
|
+
Any other file under `assets/` (a `.psd`, a `README.md`) is not served and not copied.
|
|
85
|
+
|
|
86
|
+
**Byte ranges are answered.** `Range: bytes=…` gets a `206` with `content-range`, and an
|
|
87
|
+
unsatisfiable range gets a `416`. Safari will not play a `<video>` without this.
|
|
88
|
+
|
|
89
|
+
## Where it happens
|
|
90
|
+
|
|
91
|
+
| Question | Answer |
|
|
92
|
+
|---|---|
|
|
93
|
+
| the table | `packages/cli/src/site-assets.ts`: one table per app root, installed into `asset()` by `loadApp` |
|
|
94
|
+
| the route | `packages/cli/src/site-asset-routes.ts`: `GET /assets/*file`, mounted by `assetRoutes()`, which both `x dev` and the container compose |
|
|
95
|
+
| the export | `writeSiteAssets(root, out)` copies every asset to `out/assets/…/<name>.<hash>.<ext>` |
|
|
96
|
+
| the helper | `packages/render/src/asset.ts`: `asset()`, `setAssetResolver()`, `assetPathProblem()` |
|
|
97
|
+
|
|
98
|
+
`favicon.ico` stays at `apps/web/site/favicon.ico` and the install icon at `apps/web/site/icon.png`.
|
|
99
|
+
Browsers ask for those at fixed URLs, so they are not hashed.
|
|
100
|
+
|
|
101
|
+
## `<Image>`
|
|
102
|
+
|
|
103
|
+
| Prop | Meaning |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `src` | the fallback rendition every browser decodes |
|
|
106
|
+
| `alt` | required. `""` for a decorative image, on purpose |
|
|
107
|
+
| `width` + `height`, **or** `aspectRatio` (`'16 / 9'`) | required. A box is always reserved: neither, one dimension alone, or both forms together is `X_UI_INVALID_VALUE` |
|
|
108
|
+
| `variants` | widths (or densities) of `src`'s own encoding, rendered as the `<img>`'s `srcset` |
|
|
109
|
+
| `sources` | `{ avif?, webp? }`, each a width list. Renders a `<picture>` with AVIF first, then WebP, then the `<img>` |
|
|
110
|
+
| `sizes` | applies to every set |
|
|
111
|
+
| `priority` | the LCP image: `loading="eager"` + `fetchpriority="high"`. At most one per route. Never lazy |
|
|
112
|
+
|
|
113
|
+
Everything else is `loading="lazy"`, `fetchpriority="auto"` and `decoding="async"`.
|
|
114
|
+
|
|
115
|
+
## Responsive images in a static export
|
|
116
|
+
|
|
117
|
+
`responsiveImage()` from `@ultimat3/seo` mints `?w=&f=` URLs, which only `/media` answers — a dumb
|
|
118
|
+
file server ignores the query and hands back the full original under `<source type="image/webp">`.
|
|
119
|
+
So under `x build --target static` every candidate is a FILE instead: `/_img/<source hash>-<width>.<ext>`,
|
|
120
|
+
written through core's pipeline after the documents render, one per width in every offered format.
|
|
121
|
+
`As of 2026-11`.
|
|
122
|
+
|
|
123
|
+
| Rule | Detail |
|
|
124
|
+
|---|---|
|
|
125
|
+
| the `src` | a file the export holds — an `asset('assets/hero.png')` URL. Anything else is `X_IMAGE_SOURCE_UNREADABLE` at build; an absolute `https://` URL keeps its query URL for a CDN that answers one |
|
|
126
|
+
| the widths | capped at the source's own (`usableWidths`), never an upscale |
|
|
127
|
+
| the formats | `webp` and the source's encoding. `avif` at a static build is `X_IMAGE_UNSUPPORTED`, a build error, never a dead `<source>` |
|
|
128
|
+
| what is written | only the candidates an EXPORTED document names: a page rendered just to be weighed writes nothing |
|
|
129
|
+
| a served page | keeps the `?w=&f=` URLs, which `/assets` answers itself — [below](#responsive-images-on-a-served-page). The seam is installed by the export alone |
|
|
130
|
+
|
|
131
|
+
The name is the source's content hash, so a changed image is a new URL and every file can be served
|
|
132
|
+
`immutable`. `examples/dummy`'s landing page (`apps/web/site/page.tsx`) is the worked example.
|
|
133
|
+
|
|
134
|
+
## Responsive images on a served page
|
|
135
|
+
|
|
136
|
+
`x dev` and the container answer the same candidates on `/assets/<name>.<hash>.<ext>?w=&f=`: the
|
|
137
|
+
variant is resized and re-encoded through the pipeline `/media` uses (core's, or the
|
|
138
|
+
`ImageTransformDriver` the boot was handed), with its own `content-type` and
|
|
139
|
+
`public, max-age=31536000, immutable`. `As of 2026-11`.
|
|
140
|
+
|
|
141
|
+
| Rule | Detail |
|
|
142
|
+
|---|---|
|
|
143
|
+
| the widths | exactly the `srcset`'s: `usableWidths(intrinsic, DEFAULT_WIDTHS)` — never an upscale |
|
|
144
|
+
| the formats | `DEFAULT_FORMATS` (`webp`), or none for the source's own encoding |
|
|
145
|
+
| anything else | `?w=321`, `?f=avif`, `?f=jpeg`, any `?q=`, a `?w=` on an SVG: `404 X_ASSET_VARIANT_UNDECLARED`, before a pixel is decoded. A public URL is never a resize service; an upload under `/media` answers any width |
|
|
146
|
+
| a custom `widths` | not served for a site asset; drop the option, or store the image and use `/media` |
|
|
147
|
+
| the cache | one decode per variant per content hash, in memory, least recently used out past 64 MiB; a burst of first visitors is one decode |
|
|
148
|
+
| a stale hash | the plain route's answer, query or not |
|
|
149
|
+
|
|
150
|
+
## In a unit test
|
|
151
|
+
|
|
152
|
+
A test that renders a page calling `asset()` without loading the app installs a table itself:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { setAssetResolver } from '@ultimat3/render';
|
|
156
|
+
|
|
157
|
+
beforeAll(() => setAssetResolver((path) => `/${path}`));
|
|
158
|
+
afterAll(() => setAssetResolver(undefined));
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Screenshots
|
|
162
|
+
|
|
163
|
+
`x shot <route> --locale en` photographs `/en/<route>` with `Accept-Language: en`. With no
|
|
164
|
+
`--locale`, `Accept-Language` is still pinned to the app's default locale. `x shot --matrix`
|
|
165
|
+
photographs every site route in every locale, in light and dark, at 390 and 1440 px, into
|
|
166
|
+
`.x/shot/matrix/`, with an `index.html` contact sheet. See [CLI reference](CLI-Reference#x-shot).
|