fimo 0.17.0 → 0.19.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.
Files changed (164) hide show
  1. package/assets/astro/components/DateTime.astro +22 -0
  2. package/assets/astro/components/index.d.ts +1 -0
  3. package/assets/astro/components/index.js +1 -0
  4. package/assets/content-templates/shared/types.eta +2 -0
  5. package/assets/skills/fimo-cli/SKILL.md +8 -6
  6. package/assets/skills/fimo-cli/references/branches.md +2 -2
  7. package/assets/skills/fimo-cli/references/content.md +2 -2
  8. package/assets/skills/fimo-cli/references/deploy.md +17 -9
  9. package/assets/skills/fimo-cli/references/hosting.md +114 -0
  10. package/assets/skills/fimo-cli/references/init.md +13 -6
  11. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +2 -0
  12. package/assets/skills/fimo-cli/references/locales.md +38 -14
  13. package/assets/skills/fimo-cli/references/pages.md +70 -0
  14. package/assets/skills/fimo-cli/references/preview.md +26 -20
  15. package/assets/skills/fimo-cli/references/webhooks.md +1 -1
  16. package/assets/skills/fimo-code/SKILL.md +11 -0
  17. package/assets/skills/fimo-code/assets/react-router-locales/LocaleLayout.tsx +12 -0
  18. package/assets/skills/fimo-code/assets/react-router-locales/routes.ts +7 -6
  19. package/assets/skills/fimo-code/references/best-practices/astro.md +47 -0
  20. package/assets/skills/fimo-code/references/best-practices/next.md +42 -0
  21. package/assets/skills/fimo-code/references/best-practices/sveltekit.md +17 -0
  22. package/assets/skills/fimo-code/references/content/richtext.md +5 -0
  23. package/assets/skills/fimo-code/references/content/schema.md +4 -1
  24. package/assets/skills/fimo-code/references/frameworks/astro.md +5 -3
  25. package/assets/skills/fimo-code/references/frameworks/hosting.md +5 -2
  26. package/assets/skills/fimo-code/references/frameworks/next/app-router.md +6 -0
  27. package/assets/skills/fimo-code/references/frameworks/next/locales.md +12 -2
  28. package/assets/skills/fimo-code/references/frameworks/next.md +7 -0
  29. package/assets/skills/fimo-code/references/frameworks/react-router.md +15 -7
  30. package/assets/skills/fimo-code/references/frameworks/sveltekit.md +15 -8
  31. package/assets/skills/fimo-code/references/labels.md +9 -1
  32. package/assets/skills/fimo-code/references/locales.md +8 -2
  33. package/assets/skills/fimo-code/references/migrations/react-router-route-ownership.md +93 -0
  34. package/assets/skills/fimo-code/references/ui.md +21 -2
  35. package/assets/skills/fimo-migration/SKILL.md +276 -51
  36. package/assets/skills/fimo-migration/references/content.md +119 -35
  37. package/assets/skills/fimo-migration/references/decision.md +72 -0
  38. package/assets/skills/fimo-migration/references/forms.md +38 -6
  39. package/assets/skills/fimo-migration/references/frameworks/nextjs.md +179 -23
  40. package/assets/skills/fimo-migration/references/import-contract.md +71 -19
  41. package/assets/skills/fimo-migration/references/manifest.md +11 -161
  42. package/assets/skills/fimo-migration/references/media.md +33 -1
  43. package/assets/skills/fimo-migration/references/platforms.md +26 -2
  44. package/assets/skills/fimo-migration/references/qa.md +167 -13
  45. package/assets/skills/fimo-migration/references/workers/content-execution.md +39 -0
  46. package/assets/skills/fimo-migration/references/workers/content-planner.md +64 -0
  47. package/assets/skills/fimo-migration/references/workers/framework.md +37 -0
  48. package/assets/skills/fimo-migration/references/workers/validator.md +25 -0
  49. package/assets/skills/fimo-migration/references/workers.md +82 -0
  50. package/assets/skills/fimo-migration/references/workflow.md +140 -192
  51. package/assets/skills/fimo-migration/scripts/apply-decision.mjs +534 -0
  52. package/assets/skills/fimo-migration/scripts/build-canonical-manifest.mjs +7 -4
  53. package/assets/skills/fimo-migration/scripts/write-migration-report.mjs +191 -4
  54. package/assets/skills/fimo-studio/references/ai-chat.md +1 -1
  55. package/assets/skills/fimo-studio/references/cms.md +25 -7
  56. package/assets/skills/fimo-studio/references/webhooks.md +1 -1
  57. package/assets/sveltekit/components/DateTime.svelte +35 -0
  58. package/assets/sveltekit/components/FimoProvider.svelte +2 -2
  59. package/assets/sveltekit/components/index.d.ts +1 -0
  60. package/assets/sveltekit/components/index.js +1 -0
  61. package/dist/build/next/config.d.ts +4 -1
  62. package/dist/build/next/config.js +21 -5
  63. package/dist/build/sveltekit/vite.d.ts +3 -4
  64. package/dist/build/sveltekit/vite.js +3 -4
  65. package/dist/build/vite/plugins/runtime-env.d.ts +2 -1
  66. package/dist/build/vite/plugins/runtime-env.js +14 -10
  67. package/dist/cli/bundle.json +2 -2
  68. package/dist/cli/index.js +113 -108
  69. package/dist/runtime/app/FimoProviders.js +25 -14
  70. package/dist/runtime/app/prefetch.d.ts +3 -1
  71. package/dist/runtime/app/prefetch.js +11 -55
  72. package/dist/runtime/astro/preview.js +7 -9
  73. package/dist/runtime/content/client/internal.js +1 -0
  74. package/dist/runtime/i18n/locale.d.ts +6 -3
  75. package/dist/runtime/i18n/locale.js +16 -41
  76. package/dist/runtime/next/client-runtime.js +5 -1
  77. package/dist/runtime/next/client.d.ts +3 -2
  78. package/dist/runtime/next/client.js +2 -1
  79. package/dist/runtime/next/labels.d.ts +2 -2
  80. package/dist/runtime/next/labels.js +2 -2
  81. package/dist/runtime/next/preview.d.ts +13 -0
  82. package/dist/runtime/next/preview.js +34 -0
  83. package/dist/runtime/next/primitives/server.d.ts +2 -0
  84. package/dist/runtime/next/primitives/server.js +8 -0
  85. package/dist/runtime/next/provider.d.ts +5 -0
  86. package/dist/runtime/next/provider.js +17 -3
  87. package/dist/runtime/next/server-runtime.js +4 -1
  88. package/dist/runtime/next/server.d.ts +1 -1
  89. package/dist/runtime/next/server.js +1 -1
  90. package/dist/runtime/paths/get-fimo-paths.d.ts +6 -5
  91. package/dist/runtime/paths/get-fimo-paths.js +43 -42
  92. package/dist/runtime/preview/location.d.ts +19 -2
  93. package/dist/runtime/preview/location.js +16 -2
  94. package/dist/runtime/primitives/index.d.ts +1 -0
  95. package/dist/runtime/primitives/index.js +1 -0
  96. package/dist/runtime/react/primitives/editable/DateTime.d.ts +4 -0
  97. package/dist/runtime/react/primitives/editable/DateTime.js +13 -0
  98. package/dist/runtime/react/primitives/renderers/DateRenderer.d.ts +7 -1
  99. package/dist/runtime/react/primitives/renderers/DateRenderer.js +11 -8
  100. package/dist/runtime/react-router/{routes.d.ts → legacy/routes.d.ts} +6 -1
  101. package/dist/runtime/react-router/{routes.js → legacy/routes.js} +22 -7
  102. package/dist/runtime/routes/index.d.ts +162 -0
  103. package/dist/runtime/routes/index.js +335 -0
  104. package/dist/runtime/routing/AppRoutesProvider.js +4 -3
  105. package/dist/runtime/seo/resolver.d.ts +5 -0
  106. package/dist/runtime/seo/resolver.js +10 -42
  107. package/dist/runtime/shared/fimo-config.types.d.ts +14 -13
  108. package/dist/runtime/shared/preview-location.d.ts +1 -22
  109. package/dist/runtime/shared/preview-location.js +5 -93
  110. package/dist/runtime/sveltekit/preview.d.ts +12 -3
  111. package/dist/runtime/sveltekit/preview.js +13 -8
  112. package/dist/runtime/templates.d.ts +19 -0
  113. package/dist/runtime/templates.js +33 -0
  114. package/dist/scripts/sync-forms.js +1 -1
  115. package/dist/scripts/sync-schemas.js +1 -4
  116. package/dist/scripts/validate-fimo-config.js +5 -1
  117. package/dist/scripts/validate-page-registry.d.ts +2 -0
  118. package/dist/scripts/validate-page-registry.js +167 -0
  119. package/dist/scripts/validate-route-metadata.js +132 -41
  120. package/package.json +10 -5
  121. package/templates/astro/.fimo/config.json +13 -5
  122. package/templates/astro/AGENTS.md +5 -1
  123. package/templates/astro/astro.config.mjs +7 -0
  124. package/templates/astro/pnpm-workspace.yaml +0 -3
  125. package/templates/astro/src/components/ProjectOverview.astro +9 -6
  126. package/templates/astro/src/layouts/Base.astro +1 -1
  127. package/templates/astro/src/locales.ts +4 -0
  128. package/templates/astro/src/pages/[locale]/index.astro +19 -0
  129. package/templates/astro/src/pages/[locale]/projects/[slug].astro +35 -0
  130. package/templates/astro/src/pages/[locale]/projects/index.astro +19 -0
  131. package/templates/astro/src/pages/index.astro +5 -2
  132. package/templates/astro/src/pages/projects/[slug].astro +4 -2
  133. package/templates/astro/src/pages/projects/index.astro +5 -2
  134. package/templates/nextjs/.fimo/config.json +2 -1
  135. package/templates/nextjs/AGENTS.md +5 -0
  136. package/templates/nextjs/src/app/(default)/layout.tsx +10 -0
  137. package/templates/nextjs/src/app/[locale]/layout.tsx +22 -0
  138. package/templates/nextjs/src/app/[locale]/page.tsx +1 -0
  139. package/templates/nextjs/src/components/Document.tsx +26 -0
  140. package/templates/nextjs/src/components/FimoPreviewBridge.tsx +13 -0
  141. package/templates/nextjs/src/locales.ts +13 -0
  142. package/templates/react-router/.fimo/config.json +3 -6
  143. package/templates/react-router/AGENTS.md +4 -0
  144. package/templates/react-router/package.json +1 -1
  145. package/templates/react-router/pnpm-workspace.yaml +1 -3
  146. package/templates/react-router/react-router.config.ts +4 -10
  147. package/templates/react-router/src/pages/LocaleLayout.tsx +12 -0
  148. package/templates/react-router/src/root.tsx +2 -4
  149. package/templates/react-router/src/routes.ts +5 -3
  150. package/templates/sveltekit/.fimo/config.json +2 -1
  151. package/templates/sveltekit/AGENTS.md +5 -0
  152. package/templates/sveltekit/src/app.html +1 -1
  153. package/templates/sveltekit/src/hooks.server.ts +11 -0
  154. package/templates/sveltekit/src/locales.ts +8 -0
  155. package/templates/sveltekit/src/params/locale.ts +5 -0
  156. package/templates/sveltekit/src/routes/+layout.server.ts +6 -1
  157. package/templates/sveltekit/src/routes/+layout.svelte +5 -0
  158. package/assets/skills/fimo-migration/references/inventory/coordinator.md +0 -40
  159. package/assets/skills/fimo-migration/references/inventory/locales/next-intl.md +0 -39
  160. package/assets/skills/fimo-migration/references/inventory/locales.md +0 -41
  161. package/assets/skills/fimo-migration/scripts/inventory/locales/next-intl.mjs +0 -459
  162. package/templates/nextjs/src/app/layout.tsx +0 -17
  163. /package/templates/nextjs/src/app/{page.tsx → (default)/page.tsx} +0 -0
  164. /package/templates/sveltekit/src/routes/{+page.svelte → [[locale=locale]]/+page.svelte} +0 -0
@@ -0,0 +1,22 @@
1
+ ---
2
+ import { getFimoSource } from 'fimo/astro';
3
+
4
+ interface Props {
5
+ value: globalThis.Date | String | string | number | null | undefined;
6
+ locale?: string;
7
+ options?: Intl.DateTimeFormatOptions;
8
+ [key: string]: unknown;
9
+ }
10
+
11
+ const { value, locale, options, ...props } = Astro.props;
12
+ const rawValue = value instanceof String ? value.toString() : value;
13
+ const date = rawValue == null ? null : new globalThis.Date(rawValue as string | number | globalThis.Date);
14
+ const validDate = date && !Number.isNaN(date.getTime()) ? date : null;
15
+ // The whole instant, not just the day: a `datetime` field exists to name a
16
+ // moment, and truncating it here would throw the time away on every page.
17
+ const dateTime = validDate?.toISOString();
18
+ const content = validDate?.toLocaleString(locale, options ?? { dateStyle: 'medium', timeStyle: 'short' });
19
+ const source = getFimoSource(value);
20
+ ---
21
+
22
+ {validDate && <time {...props} datetime={dateTime} data-fimo-source={source}>{content}</time>}
@@ -1,5 +1,6 @@
1
1
  export { default as Boolean } from './Boolean.astro';
2
2
  export { default as Date } from './Date.astro';
3
+ export { default as DateTime } from './DateTime.astro';
3
4
  export { default as Image } from './Image.astro';
4
5
  export { default as Json } from './Json.astro';
5
6
  export { default as RichText } from './RichText.astro';
@@ -1,5 +1,6 @@
1
1
  export { default as Boolean } from './Boolean.astro';
2
2
  export { default as Date } from './Date.astro';
3
+ export { default as DateTime } from './DateTime.astro';
3
4
  export { default as Image } from './Image.astro';
4
5
  export { default as Json } from './Json.astro';
5
6
  export { default as RichText } from './RichText.astro';
@@ -97,6 +97,7 @@ function getTypeForField(field) {
97
97
  case 'boolean':
98
98
  return 'FimoBoolean';
99
99
  case 'date':
100
+ case 'datetime':
100
101
  return 'string';
101
102
  case 'json':
102
103
  return 'Record<string, any>';
@@ -126,6 +127,7 @@ function getInputTypeForField(field) {
126
127
  case 'boolean':
127
128
  return 'boolean';
128
129
  case 'date':
130
+ case 'datetime':
129
131
  return 'string';
130
132
  case 'json':
131
133
  return 'Record<string, unknown>';
@@ -15,7 +15,7 @@ This skill describes **what the CLI does and the workflows it drives**. For the
15
15
 
16
16
  Use `fimo <command> --help` for full flag details on any command.
17
17
 
18
- > **Webhooks are beta.** Verify a destination with `fimo webhooks test <id> --wait` and inspect its delivery history before depending on it in production.
18
+ > Verify a destination with `fimo webhooks test <id> --wait` and inspect its delivery history before depending on it in production.
19
19
 
20
20
  ## Running the CLI
21
21
 
@@ -60,11 +60,11 @@ pnpm dev # run the app locally (use the pr
60
60
  fimo credits # inspect the owning org's AI credit balance (read-only)
61
61
  fimo history list # inspect this Branch's restore points
62
62
  fimo validate # run all checks + codegen; fails on missing DB labels
63
- fimo deploy # ON-DEMAND: hosted preview / shareable link (runs validate internally)
63
+ fimo deploy # ON-DEMAND: hosted project preview (runs validate internally)
64
64
  fimo deploy --publish # ON-DEMAND: publish live (only when the developer says "ship it")
65
65
  ```
66
66
 
67
- The working loop is local: run the app with the project's package-manager `dev` script (`pnpm dev` / `npm run dev` / `yarn dev` / `bun dev` — match the lockfile), ask the developer what they want, edit, and iterate against the live localhost server. Outside the first-time onboarding rule below, `fimo deploy` is **not** a required final step — reach for it only when the developer wants a hosted preview, a shareable link, or to go live, and only on their signal (see `references/deploy.md`).
67
+ The working loop is local: run the app with the project's package-manager `dev` script (`pnpm dev` / `npm run dev` / `yarn dev` / `bun dev` — match the lockfile), ask the developer what they want, edit, and iterate against the live localhost server. Outside the first-time onboarding rule below, `fimo deploy` is **not** a required final step — reach for it only when the developer wants a hosted project preview or to go live, and only on their signal (see `references/deploy.md`).
68
68
 
69
69
  `fimo validate` is the single entrypoint for "prove this project is ready" — it covers schema/form codegen, route metadata checks, lint, and missing label checks for `i18n.defaultLocale` from `.fimo/config.json` (fallback: `en`). Use `fimo labels set` / `set-many` to create or update label values in the DB. The underlying phases are also available individually under the hidden `fimo scripts` namespace for advanced/debug use.
70
70
 
@@ -75,7 +75,8 @@ Keep `fimo validate --json` at the front of the project's `build` script, which
75
75
  Load the matching reference when the user's request fires its trigger. Recipes that involve writing code also need the `fimo-code` skill's package references — they're called out where relevant.
76
76
 
77
77
  - "Create a new Fimo project / scaffold a site / start a new website / add the opt-in content starter / link an existing project locally" → `references/init.md`
78
- - "Add a content type / blog / products / pages / CMS" → `references/content.md` (workflow) **+ run `fimo skills get fimo-code --ref content/schema` and load the detected framework reference**
78
+ - "Add a content type / blog / products / content schemas / CMS" → `references/content.md` (workflow) **+ run `fimo skills get fimo-code --ref content/schema` and load the detected framework reference**
79
+ - "Declare Pages routes / configure Pages sources or route params / control what Studio shows for a route" → `references/pages.md`
79
80
  - "Add a contact / signup / feedback / newsletter form" → `references/forms.md` (workflow) **+ run `fimo skills get fimo-code --ref forms` for the JSON spec and generated client**
80
81
  - "View form submissions / who filled out the contact form / inspect what users sent / how many signups" → `references/forms.md` § Reading submissions
81
82
  - "Upload an image / hero / cover / existing media file" → `references/assets.md` (workflow: upload, browse, open, delete) **+ run `fimo skills get fimo-code --ref assets` for the `FimoMedia` shape and rendering**
@@ -84,6 +85,7 @@ Load the matching reference when the user's request fires its trigger. Recipes t
84
85
  - "Enable locales / configure default locale / integrate an existing locale system" → `references/locales.md` **+ run `fimo skills get fimo-code --ref locales` and load the detected framework locale reference**
85
86
  - "What's in this project / show the project structure / describe the project / what schemas does it have / how many routes / project tree / show me what's here" → `references/describe.md`
86
87
  - "Deploy / publish / go live / push my changes" → `references/deploy.md`
88
+ - "Add a redirect / security headers / CSP / HSTS / clean URLs / trailing slash" → `references/hosting.md`
87
89
  - "Get the preview URL / open the preview / what's the URL for this Branch / refresh the preview link / I just want to see the site / the preview URL stopped working" → `references/preview.md`
88
90
  - "Schedule a command / cron / nightly publish / recurring checks / `fimo schedules`" → `references/schedules.md`
89
91
  - "Set env vars / configure API keys / add project secrets / local `.env.local` / `fimo vars` / `fimo secrets`" → `references/project-vars-and-secrets.md`
@@ -117,7 +119,7 @@ These fire at specific moments in the project lifecycle. **Surface them proactiv
117
119
  - **When `fimo init` created or scaffolded a new project (create-new path, including a Studio-supplied `--project-id`)** → after init and context loading succeed, run the single first-preview deploy and return the preview and dashboard links — see `references/init.md` § Create the first hosted preview. That deploy is also the sandbox warm-up; never run a separate warm-up deploy. Skip it only if the user explicitly said not to deploy. Linking a project with existing code and migrations keep their own approval rules.
118
120
  - **Right after `fimo init`** → suggest `fimo rename "<Display Name>"` to set a human-readable name (the default post-init name is an auto-generated slug). Infer the name from what the user is building (e.g. "Acme Coffee" for a café, "Jane Doe Portfolio" for a personal site). See `references/init.md`.
119
121
  - **Right after `fimo init`** → start the app locally with the project's package-manager `dev` script (`pnpm dev` / `npm run dev` / `yarn dev` / `bun dev`) in the background. This localhost server with live reload is your iteration loop — edit, show, repeat. No deploy is needed to see local changes. If the initiating request did not say what to build, ask the developer — after the first preview on the create-new path, never as a blocker before initializing.
120
- - **When a user-visible unit of work looks done outside first-time onboarding** → **offer** to deploy (`fimo deploy` for a hosted preview / shareable link, `fimo deploy --publish` to go live) and run it only after the developer confirms — or immediately if they ask. Never deploy ordinary edits on your own. See `references/deploy.md`.
122
+ - **When a user-visible unit of work looks done outside first-time onboarding** → **offer** to deploy (`fimo deploy` for a hosted project preview, `fimo deploy --publish` to go live) and run it only after the developer confirms — or immediately if they ask. Never deploy ordinary edits on your own. See `references/deploy.md`.
121
123
  - **Optional, outside new-project onboarding (its first preview already warms the sandbox), if you already know a deploy is coming** → warm the sandbox early with `fimo deploy -m "chore: init" &` in the background so the one-time ~15-30s provision + dep install happens while you work and the real deploy lands warm (~4-10s). This is a perf optimization, not a requirement. See `references/deploy.md` § Warm the sandbox early in a session.
122
124
  - **Iterative code-only deploys** → once you are deploying, `fimo deploy --no-restart` skips the sandbox dev-server restart on HMR-safe edits. See `references/deploy.md` § Skipping the dev-server restart for when it's safe.
123
125
  - **You need the current preview URL but haven't changed code** (opening it, screenshotting it, handing it to another tool, the previous URL expired) → `fimo preview url`, never a no-op `fimo deploy`. See `references/preview.md`.
@@ -131,7 +133,7 @@ These fire at specific moments in the project lifecycle. **Surface them proactiv
131
133
  - **Editing `.fimo/project.json`** — read-only; it's the link between local and remote project. Treat as a generated file.
132
134
  - **Treating `fimo deploy` as the working loop or a required final step** — the loop is local (`pnpm dev` etc.). Deploy commits + pushes + round-trips the sandbox; it's for hosted previews / going live, on-demand. Iterate locally and deploy at logical breakpoints. See `references/deploy.md`.
133
135
  - **Deploying without the developer asking or confirming** — new-project onboarding authorizes exactly one automatic first preview deploy (unless the user said not to deploy); every other deploy is offer-then-confirm. Don't auto-deploy after finishing an ordinary edit.
134
- - **Running `fimo deploy` just to get a fresh preview URL** — that's a commit + push + sandbox sync for what should be a sub-second read. Use `fimo preview url` instead. See `references/preview.md`.
136
+ - **Running `fimo deploy` just to get the current preview URL** — that's a commit + push + sandbox sync when only destination resolution is needed. Use `fimo preview url` instead. See `references/preview.md`.
135
137
  - **Using `fimo deploy --publish` casually** — `--publish` makes the site live to the public. Plain `fimo deploy` (preview) is the default. Use `--publish` only when the user says "ship it" / "go live" / "publish".
136
138
  - **Bare `fimo init` in a non-interactive shell** — will hang. Always pass `[dir]`, `--no-install` (or `--install`), `--no-skills` (or `--skills`), and `--org`/`--agents` as needed explicitly when scripted.
137
139
  - **Using a starter on an existing project** — `--starter` is create-new only. Keep `--project-id` flows blank and use explicit content/form/label commands when changing an existing project.
@@ -26,7 +26,7 @@ fimo --branch <name> <command> # peek at another Branch for one command (does n
26
26
 
27
27
  | Command | git analogue | What it does |
28
28
  | ----------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
29
- | `fimo branch` | `git branch` | List Branches (current marked `*`). `-v` adds preview URLs + deleted Branches. |
29
+ | `fimo branch` | `git branch` | List Branches (current marked `*`). `-v` includes deleted Branches. |
30
30
  | `fimo branch <name>` | `git branch <name>` | Create a Branch off the current one. `--from <branch>` forks from a different parent. Provisions DB + sandbox + preview + R2 prefix. |
31
31
  | `fimo branch -d <name>` | `git branch -d` | Delete a Branch — tears down its sandbox, Neon branch, and R2 prefix. Refuses `main` and `prod`. |
32
32
  | `fimo checkout <name>` | `git checkout` | Switch to a Branch (checks out the matching git branch; the app derives its Branch from that branch at startup). `-b` creates + switches; `--from <branch>` sets the parent. |
@@ -55,7 +55,7 @@ All of these accept the global `--branch` override; legacy `--env` remains an al
55
55
  fimo checkout -b feat/seo # branch off main: git branch + Branch provisioned
56
56
  # …generate / edit code, schemas, content, translations…
57
57
  fimo deploy -m "feat: seo pass" # deploy a preview of the feat/seo Branch
58
- fimo preview url # fresh URL to open / screenshot the feat/seo preview
58
+ fimo preview url # canonical URL to open / screenshot the feat/seo preview
59
59
  fimo status # see what changed vs main, surface by surface
60
60
  fimo checkout main # back to main
61
61
  fimo merge feat/seo # merge the Branch back into main (resolve conflicts)
@@ -2,12 +2,12 @@
2
2
 
3
3
  > Package contract: load the version-locked `fimo-code` skill with `fimo skills get fimo-code`, then fetch its nested content and detected-framework references for schema JSON, entry values, generated clients, and imports.
4
4
 
5
- This file covers the **CLI workflow** for content. Use it when the user wants to add a content type (blog, products, pages) or manage Singles and entries.
5
+ This file covers the **CLI workflow** for content schemas, Singles, and entries. Use it when the user wants to add a content type (blog, products, reusable content) or manage content records. For route metadata shown in Studio Pages, load `references/pages.md`.
6
6
 
7
7
  ## Choose the write path first
8
8
 
9
9
  - Exactly one homepage, settings document, About page, or campaign page → declare `"isSingleton": true` and write it with `fimo singles update <TypeName>`.
10
- - Repeated posts, products, team members, or reusable pages → keep a collection and create rows with `fimo entries create <TypeName>`.
10
+ - Repeated posts, products, team members, or other reusable records → keep a collection and create rows with `fimo entries create <TypeName>`.
11
11
 
12
12
  Never remove `isSingleton: true` merely because `fimo entries create` rejects the type. `entries` and `singles` are separate command namespaces; inspect `fimo singles --help` when the content is one-off.
13
13
 
@@ -1,14 +1,14 @@
1
1
  # Deploy pipeline
2
2
 
3
- **`fimo deploy` is on-demand, not the working loop and not a required final step.** The loop is local: run the app with the project's package-manager `dev` script (`pnpm dev` / `npm run dev` / `yarn dev` / `bun dev` — match the lockfile), iterate with the developer, and let live reload show changes. Reach for `fimo deploy` only when the developer wants a **hosted preview**, a **shareable link**, or to **go live** — and only on their signal. New-project onboarding counts as the signal for its single automatic first preview deploy (see `references/init.md` § Create the first hosted preview). It commits everything, pushes to the current Branch, and round-trips that Branch's sandbox (install + restart); it's a milestone command, not a save step. Batch related edits into one deploy; never deploy after every change.
3
+ **`fimo deploy` is on-demand, not the working loop and not a required final step.** The loop is local: run the app with the project's package-manager `dev` script (`pnpm dev` / `npm run dev` / `yarn dev` / `bun dev` — match the lockfile), iterate with the developer, and let live reload show changes. Reach for `fimo deploy` only when the developer wants a **hosted preview**, a **project-member preview link**, or to **go live** — and only on their signal. New-project onboarding counts as the signal for its single automatic first preview deploy (see `references/init.md` § Create the first hosted preview). It commits everything, pushes to the current Branch, and round-trips that Branch's sandbox (install + restart); it's a milestone command, not a save step. Batch related edits into one deploy; never deploy after every change.
4
4
 
5
- > **Local vs hosted.** The local dev server is localhost only. The Fimo **dashboard preview** and the **shareable preview URL** are served by the deployed sandbox — so if the developer wants to see the site in the dashboard or send someone a link, that requires a `fimo deploy`.
5
+ > **Local vs hosted.** The local dev server is localhost only. The Fimo **dashboard preview** and the authenticated **project-member preview URL** are served by the deployed sandbox — so if the developer wants to see the site in the dashboard or send another project member a link, that requires a `fimo deploy`.
6
6
 
7
7
  `fimo deploy` uses the current Branch. New projects start on `main`; `release/*` is read-only, and `--publish` only runs from `main`. See `references/branches.md` for the multi-Branch workflow.
8
8
 
9
9
  Before deploying, Fimo fast-forwards a clean checkout that is behind and stops on dirty-behind or diverged branches. This syncs the whole branch, including config commits from Studio or locale commands.
10
10
 
11
- > **Just need the current preview URL?** That's `fimo preview url` — sub-second, no commit, no push. See `references/preview.md`. `fimo deploy` is only for pushing code changes.
11
+ > **Just need the current preview URL?** That's `fimo preview url` — no commit or push. A cold sandbox can still take time to resolve. See `references/preview.md`. `fimo deploy` is only for pushing code changes.
12
12
 
13
13
  ## Commands
14
14
 
@@ -35,13 +35,16 @@ fimo deploy -m "<commit message>" --publish --json
35
35
 
36
36
  Read these fields from `data`:
37
37
 
38
- | Field | Destination |
39
- | --------------- | ----------------------------------------------------------- |
40
- | `preview_url` | Shareable preview. Its token expires, so do not persist it. |
41
- | `dashboard_url` | Stable, authenticated Fimo project and Branch page. |
42
- | `app_url` | Public live site, returned after a successful `--publish`. |
38
+ | Field | Destination |
39
+ | -------------------- | ---------------------------------------------------------------- |
40
+ | `preview_url` | Stable, authenticated full-screen viewer for project members. |
41
+ | `sandbox_url` | Short-lived raw site URL for agents, curl, and screenshot tools. |
42
+ | `sandbox_expires_at` | Expiry of the raw sandbox URL. |
43
+ | `studio_url` | Stable, authenticated Fimo Studio project and Branch page. |
44
+ | `dashboard_url` | Deprecated compatibility alias for `studio_url`. |
45
+ | `app_url` | Public live site, returned after a successful `--publish`. |
43
46
 
44
- When reporting the result, present the raw values as named Markdown links. If no code changed and you only need fresh destinations, use `fimo preview url --json` instead of deploying again.
47
+ When reporting the result, open `preview_url` for a person and use `sandbox_url` for machine reads. If no code changed and you only need fresh destinations, use `fimo preview url --json` instead of deploying again.
45
48
 
46
49
  Public project variables managed with `fimo vars add` and `fimo vars update` are injected into preview/build/deploy runtimes. Project secrets are not injected into app builds; agents request secrets separately through their own config. See `references/project-vars-and-secrets.md`.
47
50
 
@@ -57,6 +60,9 @@ needed, load the `fimo-code` skill's framework reference:
57
60
  connector and the explicit catch-all used only by plain Vite `BrowserRouter`
58
61
  SPAs; Astro's `fimo()` integration lives in `references/frameworks/astro.md`.
59
62
 
63
+ Redirects, response headers, and URL shape belong in
64
+ `.fimo/config.json#hosting` — see `references/hosting.md`.
65
+
60
66
  ## Warm the sandbox early in a session (optional)
61
67
 
62
68
  This is a **performance optimization, only worth doing when you already know a deploy is coming** (the developer asked to publish, or you're confident they'll want a hosted preview soon). If you're just iterating locally, skip it — don't deploy pre-emptively. New-project onboarding never needs it: its automatic first preview deploy is the warm-up.
@@ -118,6 +124,8 @@ curl -H 'Accept: text/markdown' https://your-site/ # content negotiation
118
124
  curl https://your-site/?format=md # query param
119
125
  ```
120
126
 
127
+ This is a hosting capability: Fimo generates the `.md`, content-negotiation, and `?format=md` responses for supported built pages. Application code must not reimplement any of them — in particular, never add a route that fetches the app's own public URL to convert it to Markdown. For a dynamic page, render Markdown from the same server-side data the page itself uses when the framework supports that; otherwise report the capability as unresolved instead of building a self-fetching route.
128
+
121
129
  ## Recovering from Git drift
122
130
 
123
131
  Most stale states are caught before deploy changes or commits files. Follow the emitted hint: clean a dirty checkout, or reconcile a diverged branch. A push can still lose a race if the remote advances after preflight:
@@ -0,0 +1,114 @@
1
+ # Hosting: how a published project is served
2
+
3
+ Declare redirects, headers, rewrites, and URL shape in
4
+ `.fimo/config.json#hosting`. This is the only place Fimo reads them from.
5
+
6
+ ## Fields
7
+
8
+ ```json
9
+ {
10
+ "hosting": {
11
+ "redirects": [{ "source": "/", "destination": "/fr", "permanent": false }],
12
+ "rewrites": [{ "source": "/blog/:slug", "destination": "/posts/:slug" }],
13
+ "headers": [
14
+ {
15
+ "source": "/(.*)",
16
+ "headers": [{ "key": "X-Frame-Options", "value": "DENY" }]
17
+ }
18
+ ],
19
+ "cleanUrls": true,
20
+ "trailingSlash": false
21
+ }
22
+ }
23
+ ```
24
+
25
+ | Field | Effect |
26
+ | --------------- | ------------------------------------------------------------------- |
27
+ | `redirects` | Send the browser elsewhere. `permanent: true` is 308, otherwise 307 |
28
+ | ↳ `statusCode` | Use instead of `permanent` for an exact 301, 302, 307, or 308 |
29
+ | `rewrites` | Serve a different path without changing the URL |
30
+ | `headers` | Add response headers on matching paths |
31
+ | `cleanUrls` | Serve `/about` for `/about.html` and 308 the extension away |
32
+ | `trailingSlash` | `true` requires a trailing slash, `false` forbids one |
33
+
34
+ Every field is optional. Only what you declare is emitted.
35
+
36
+ ## Matching
37
+
38
+ `source` matches the pathname only, never the query string.
39
+
40
+ | Pattern | Matches |
41
+ | --------------- | -------------------------------------- |
42
+ | `/about` | exactly that path |
43
+ | `/blog/:slug` | one segment, captured as `slug` |
44
+ | `/proxy/:rest*` | any number of segments, including none |
45
+ | `/(.*)` | everything |
46
+
47
+ Captured names are reusable in `destination`: `/blog/:slug` →
48
+ `/posts/:slug`. `destination` may be an absolute path or an external URL.
49
+
50
+ ## Conditions
51
+
52
+ Any redirect, rewrite, or header rule can require more than a path match. `has`
53
+ applies the rule only when every condition holds; `missing` only when none of
54
+ them are present.
55
+
56
+ ```json
57
+ {
58
+ "redirects": [
59
+ {
60
+ "source": "/(.*)",
61
+ "has": [{ "type": "header", "key": "x-vercel-ip-country", "value": "GB" }],
62
+ "destination": "/uk/:path*"
63
+ }
64
+ ],
65
+ "rewrites": [
66
+ {
67
+ "source": "/",
68
+ "missing": [{ "type": "cookie", "key": "consent" }],
69
+ "destination": "/consent"
70
+ }
71
+ ]
72
+ }
73
+ ```
74
+
75
+ | `type` | Matches on |
76
+ | -------- | ---------------------------------------------------- |
77
+ | `header` | a request header, including CDN-injected geo headers |
78
+ | `cookie` | a cookie |
79
+ | `query` | a query parameter |
80
+ | `host` | the hostname the request arrived on — takes no `key` |
81
+
82
+ Omit `value` to match on presence alone, as the `consent` cookie above does.
83
+
84
+ **Prefer doing this in the application when it can.** Middleware, a loader, or a
85
+ server component can be run and tested locally; a condition here only takes
86
+ effect once published, so a mistake is found in production. Reach for `has` when
87
+ the app cannot act — a redirect that must happen before any code runs, or a
88
+ header on a static asset.
89
+
90
+ ## Rules
91
+
92
+ - **Prefer the framework's own router.** Use `hosting` for what the router
93
+ cannot express: cross-origin moves, security headers, host-level URL shape.
94
+ Do not mirror `.fimo/config.json#routes` here.
95
+ - **`permanent: true` is cached by browsers and hard to take back.** Omitting it
96
+ gives a temporary redirect, which is the one you can change your mind about.
97
+ Set it only when the old URL is genuinely retired. Reach for `statusCode` only
98
+ when you need a literal 301 or 302; it wins over `permanent`.
99
+ - **With `cleanUrls: true`, drop the extension everywhere.** A `source` or
100
+ `destination` of `/about.html` will not match; write `/about`.
101
+ - **Set `trailingSlash` on any site with more than one page.** Leaving it unset
102
+ serves `/about` and `/about/` as separate URLs, which search engines index as
103
+ duplicates.
104
+ - **An empty `hosting: {}` means no platform routing**, which is different from
105
+ omitting `hosting` entirely — that leaves legacy SPA behaviour untouched.
106
+ - **Not supported:** cron jobs (use `fimo schedules`), image optimization (use
107
+ Fimo media), per-function runtime settings, deployment regions.
108
+
109
+ ## Verify
110
+
111
+ `fimo validate` rejects an unknown `hosting` key, so a typo fails locally
112
+ rather than silently doing nothing in production. Behaviour itself only takes
113
+ effect once published — check the live URL after `fimo deploy --publish`, not
114
+ the preview.
@@ -72,9 +72,16 @@ fimo init my-svelte-site --framework sveltekit --org <organizationId>
72
72
  ```
73
73
 
74
74
  Each shell includes its framework adapter, hosted-preview connector, and
75
- `.fimo/config.json#runtime.framework`. The Astro shell also includes a minimal
76
- content-backed example with static, on-demand, and dynamic routes plus an English default locale;
77
- the other shells intentionally contain no schema, labels, or designed website.
75
+ `.fimo/config.json#runtime.framework`, plus an application-owned optional locale
76
+ boundary that keeps the default locale unprefixed. The Astro shell also includes a minimal
77
+ content-backed example with static, on-demand, and dynamic routes; the other shells intentionally
78
+ contain no schema, labels, or designed website.
79
+
80
+ Set the primary locale from the request: when several are explicitly named, use the first as default;
81
+ if none is requested, keep `en` and tell the user. Update `.fimo/config.json#i18n`, the framework-native
82
+ locale boundary, matcher, and HTML language default. Do not keep `en` solely because the shell starts
83
+ there. Do not add `/en`, a language picker, global path-prefix configuration, or localized schemas unless
84
+ the site needs them.
78
85
  After init, load the project rules and `fimo-code` to build the requested site.
79
86
  If you replace a shell's code with a site that uses another framework or none,
80
87
  fix `runtime.framework` in the same change
@@ -93,7 +100,7 @@ Pass `--project-id <id>` to set up a known Fimo project. If the project has no c
93
100
 
94
101
  - The selected project shell: React Router by default, Astro with `--framework astro`, Next.js App Router with `--framework nextjs`, or SvelteKit with `--framework sveltekit`
95
102
  - `.fimo/project.json` — links this directory to the remote project (read-only after creation)
96
- - `.fimo/config.json` — project, route, locale, SEO, and agent policy
103
+ - `.fimo/config.json` — project, optional Studio Pages route metadata, locale, SEO, and agent policy
97
104
  - `.fimo/agents/` — versioned agent bundles
98
105
  - `.env` — framework-specific tenant content API URLs for local development
99
106
  - `AGENTS.md` + `CLAUDE.md` — project rules (from the template) read by AGENTS.md-compatible tools and Claude Code. Both point the agent at `fimo skills get` to load the real skills on demand.
@@ -128,7 +135,7 @@ fimo rename "Acme Coffee"
128
135
  pnpm dev & # or npm run dev / yarn dev / bun dev — the project's package manager
129
136
  ```
130
137
 
131
- Outside the first-preview path below, when a unit of work looks done, **offer** to deploy (`fimo deploy` for a hosted preview / shareable link, `fimo deploy --publish` to go live) and run it only after the developer confirms.
138
+ Outside the first-preview path below, when a unit of work looks done, **offer** to deploy (`fimo deploy` for a hosted project preview, `fimo deploy --publish` to go live) and run it only after the developer confirms.
132
139
 
133
140
  ## Load the project context
134
141
 
@@ -152,7 +159,7 @@ Whenever `fimo init` created or scaffolded a new project — including a Studio-
152
159
  fimo deploy -m "chore: first preview" --json
153
160
  ```
154
161
 
155
- `-m` is required because you run non-interactively; the deploy validates, commits pending changes, pushes, and syncs the hosted preview. It is also the sandbox warm-up — never run a separate warm-up deploy on this path. Read `data.preview_url` and `data.dashboard_url` from the envelope and return both links. If the initiating request described a concrete site, build a minimal meaningful first screen before this single deploy; otherwise deploy the scaffolded site as-is and then ask what to build.
162
+ `-m` is required because you run non-interactively; the deploy validates, commits pending changes, pushes, and syncs the hosted preview. It is also the sandbox warm-up — never run a separate warm-up deploy on this path. Read `data.preview_url` and `data.studio_url` from the envelope and return both links. `data.dashboard_url` remains a deprecated compatibility alias for `data.studio_url`. If the initiating request described a concrete site, build a minimal meaningful first screen before this single deploy; otherwise deploy the scaffolded site as-is and then ask what to build.
156
163
 
157
164
  This first deploy creates a preview only — never add `--publish`, and treat every later deploy as offer-then-confirm. The rule does not apply when `init` cloned a project with existing code or when the work is a migration; those paths keep their normal deployment approval rules.
158
165
 
@@ -247,3 +247,5 @@ Visual/content QA before publish:
247
247
  ```bash
248
248
  fimo integrations run firecrawl scrape --url "$(fimo preview url)" --formats markdown,links --json
249
249
  ```
250
+
251
+ Because command substitution captures stdout, `fimo preview url` emits the raw `sandbox_url` in this example. For JSON workflows, pass `data.sandbox_url` to Firecrawl and refresh it after `data.sandbox_expires_at`. The stable `data.preview_url` is an authenticated browser viewer and is not the Firecrawl destination.
@@ -19,17 +19,13 @@ These commands update the selected Branch through the locale lifecycle API. The
19
19
 
20
20
  If a mutation exits with code `2` and `data.code` is `LOCALE_APPLIED_SYNC_REQUIRED`, the remote operation succeeded (`data.applied` is `true`) but the local fast-forward did not. **Do not retry the locale command.** Run the commands in `data.sync.recovery`, resolve the checkout, and confirm with `fimo status` or `fimo locales list`.
21
21
 
22
- Edit `.fimo/config.json` only for declarative routing behavior:
22
+ Edit `.fimo/config.json` only for declarative locale and route metadata:
23
23
 
24
24
  ```jsonc
25
25
  {
26
26
  "i18n": {
27
27
  "defaultLocale": "en",
28
28
  "locales": ["en"],
29
- "routing": {
30
- "strategy": "path-prefix", // only supported strategy: /es/about for Spanish; default locale can stay /about
31
- "prefixDefaultLocale": false, // when false, omit /en for the default locale
32
- },
33
29
  },
34
30
  }
35
31
  ```
@@ -37,7 +33,7 @@ Edit `.fimo/config.json` only for declarative routing behavior:
37
33
  - `defaultLocale` is the locale used by `fimo validate`, `fimo labels set` without `--locale`, and content commands without `--locale`. Change it with `fimo locales set-default`.
38
34
  - `locales` must include `defaultLocale`. Add and remove values with `fimo locales add` and `fimo locales remove`.
39
35
  - Locale tags should be structurally valid, for example `en`, `es`, `pt-BR`, or `zh-Hans`.
40
- - `routing.strategy` currently supports `path-prefix`.
36
+ - New projects do not need a global routing strategy. The route contract declares locale placement with `/:locale`; legacy `i18n.routing.strategy` values are read only for compatibility while migrating.
41
37
  - If multiple locales are configured, create or update labels and localized content for every configured locale. Create schemas with `i18n: { "enabled": false }` only once.
42
38
 
43
39
  `fimo locales remove` permanently deletes that locale's stored entries and labels.
@@ -55,38 +51,66 @@ Validation checks:
55
51
  - malformed locale tags
56
52
  - `defaultLocale` missing from `locales`
57
53
  - unsupported routing strategies
58
- - canonical routes in `.fimo/config.json` that claim reserved locale prefixes, for example `/es`
59
- - top-level dynamic routes that could capture locale prefixes unless the project uses Fimo's React Router helper
54
+ - routes in `.fimo/config.json` that hardcode a locale prefix, for example `/es/pricing`
55
+ - two routes that answer the same URL once the locale segment is removed
56
+ - a `:locale` segment that is not first, or that declares `schema`, `queryField`, `displayField`
57
+ - an entry param declared `optional`, or missing `schema` / `queryField`
58
+ - top-level dynamic routes other than `:locale` that could capture locale prefixes
60
59
  - missing default-locale DB labels
61
60
 
62
61
  ## Route Metadata Rule
63
62
 
64
- Keep `.fimo/config.json#routes` canonical and unlocalized:
63
+ Write the locale into a route's path with the reserved `:locale` segment, never as a literal prefix. The descriptor `type` is optional: `locale` infers `"locale"`, while every other parameter defaults to `"entry"`:
65
64
 
66
65
  ```json
67
66
  {
68
67
  "routes": {
68
+ "blog-post": {
69
+ "label": "Blog post",
70
+ "path": "/:locale/blog/:slug",
71
+ "params": {
72
+ "locale": { "type": "locale", "optional": true },
73
+ "slug": { "schema": "BlogPost", "queryField": "slug", "displayField": "title" }
74
+ }
75
+ },
69
76
  "pricing": {
70
77
  "label": "Pricing",
71
- "path": "/pricing"
78
+ "path": "/:locale/pricing",
79
+ "params": { "locale": { "type": "locale", "optional": true } }
72
80
  }
73
81
  }
74
82
  }
75
83
  ```
76
84
 
77
- Do not add `/es/pricing` as a second Fimo route. The route selector localizes canonical routes for the active preview locale. In React Router projects, use the package helper:
85
+ | Declared path | `params.locale` | URLs the route answers |
86
+ | --------------------- | ----------------------------------------- | --------------------------------------------------- |
87
+ | `/:locale/blog/:slug` | omitted | `/blog/hello` for `en`, `/fr/blog/bonjour` for `fr` |
88
+ | `/:locale/blog/:slug` | `{ "type": "locale", "optional": false }` | `/en/blog/hello` and `/fr/blog/bonjour` |
89
+ | `/:locale/pricing` | omitted | `/pricing` for `en`, `/fr/pricing` for `fr` |
90
+
91
+ - `locale` is reserved. It is read from the URL, so it never takes `schema` or `queryField` and never becomes a CMS query. Every other param is content-backed and needs both.
92
+ - `optional: true` means omit the configured default locale from the URL. With `i18n.defaultLocale: "en"`, `/pricing` is English and `/fr/pricing` is French.
93
+ - `optional: false` prefixes every locale, including the default (`/en/pricing` and `/fr/pricing`). Changing `i18n.defaultLocale` chooses the fallback locale; it does not by itself change this prefix policy.
94
+ - A route with no `:locale` segment stays application-owned. Studio shows it once and neither adds nor interprets a locale segment.
95
+ - Do not add `/es/pricing` as a second route. A locale segment does not make two routes distinct.
96
+
97
+ Register the same shape in the router. React Router spells the omittable segment `:locale?`:
78
98
 
79
99
  ```ts
80
- import { fimoRoutes } from 'fimo/react-router/routes';
100
+ route(':locale?/blog/:slug', './pages/BlogPost.tsx');
81
101
  ```
82
102
 
83
- For every framework, the application owns its URL scheme and passes the resolved locale into Fimo. Canonical route metadata is optional unless the project wants Fimo Studio route selection/navigation.
103
+ These canonical entries are also the optional metadata used by Studio Pages. See `references/pages.md` for content-backed `params` and declared `sources`.
104
+
105
+ For every framework, the application owns its URL scheme, resolves the locale, and passes it into Fimo. Studio stores the locale the app reports for the current location — including when only the locale changed — and reads content in it. Route metadata is optional unless the project wants Fimo Studio route selection/navigation.
106
+
107
+ Astro and Next express the same optional-locale semantic with paired native filesystem route trees: an unprefixed default-locale tree and a prefixed non-default tree. Neither framework supports an optional single-segment filesystem folder.
84
108
 
85
109
  ## Migrate An Existing Locale System
86
110
 
87
111
  Inspect the existing locale provider, route table, switcher, redirects, and public URLs before editing configuration. Preserve working URL behavior during the migration.
88
112
 
89
- Preserve the existing locale provider, router, switcher, redirects, and public URLs. Use framework helpers only when they fit that architecture. Next.js projects run `fimo skills get fimo-code --ref frameworks/next/locales`; React Router projects load the React Router setup reference; Astro projects run `fimo skills get fimo-code --ref frameworks/astro` and pass the page-resolved locale into server reads and `getLabels`.
113
+ Preserve the existing locale provider, router, switcher, redirects, and public URLs. Next.js projects run `fimo skills get fimo-code --ref frameworks/next/locales`; React Router projects load the React Router setup reference and its focused route-ownership migration when upgrading; Astro projects run `fimo skills get fimo-code --ref frameworks/astro` and pass the page-resolved locale into server reads and `getLabels`.
90
114
 
91
115
  ## Labels And Content
92
116
 
@@ -0,0 +1,70 @@
1
+ # Pages route metadata
2
+
3
+ Pages can mirror the application's routes in Fimo Studio. It gives editors a route tree and, for each selected route, a page-shaped workspace for its Labels, Single, bound entries, and Collection results. The CLI writes this optional metadata to `.fimo/config.json` under `routes.<id>`; it does not replace the application router or move or duplicate content.
4
+
5
+ ## Route shape
6
+
7
+ A route has three separate parts:
8
+
9
+ - `path` is the URL pattern, such as `/blog/:slug`.
10
+ - `params` optionally binds path placeholders to Collection entries so Studio can select a concrete route in the page header.
11
+ - `sources` optionally names the Labels, Single, and Collection results editors manage after selecting a route.
12
+
13
+ Each param key matches a `:placeholder` in `path`. `schema` selects the Collection, `queryField` is the entry field stored in the URL, and `displayField` is the field Studio shows to editors. Use `id` or the built-in `slug` for `queryField`; a custom URL field must set both `"required": true` and `"unique": true` in its schema. Params resolve in path order, so a later param query may use an earlier selection:
14
+
15
+ ```bash
16
+ fimo pages set <id> --path '/shop/:category/:product' --params '{"category":{"schema":"Category","queryField":"slug","displayField":"name"},"product":{"schema":"Product","queryField":"slug","displayField":"name","query":{"where":{"category":"$params.category.id"},"sort":"name"}}}'
17
+ ```
18
+
19
+ `sources` is a named object under `routes.<id>.sources`. It is not an array or a route definition. Keep its keys stable and descriptive:
20
+
21
+ ```json
22
+ {
23
+ "copy": {
24
+ "type": "labels",
25
+ "match": ["blog.*"]
26
+ },
27
+ "settings": {
28
+ "type": "single",
29
+ "schema": "BlogSettings"
30
+ },
31
+ "relatedPosts": {
32
+ "type": "collection",
33
+ "schema": "BlogPost",
34
+ "query": {
35
+ "where": {
36
+ "category": "$params.slug.category"
37
+ },
38
+ "sort": "-publishedAt",
39
+ "limit": 4
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ Pass that same object as JSON:
46
+
47
+ ```bash
48
+ fimo pages set <id> --sources '{"copy":{"type":"labels","match":["blog.*"]},"settings":{"type":"single","schema":"BlogSettings"},"relatedPosts":{"type":"collection","schema":"BlogPost","query":{"where":{"category":"$params.slug.category"},"sort":"-publishedAt","limit":4}}}'
49
+ ```
50
+
51
+ The three source types select matching Labels, one-off Singles, or Collection results. A Collection source's optional `query` uses the normal content query shape.
52
+
53
+ ## Params queries and source queries
54
+
55
+ Both use the normal content query shape and may read an earlier bound value with `$params.<param>.<field>`, but they run at different stages and narrow different things:
56
+
57
+ - A dependent param query runs while Studio resolves the header selectors. On `/shop/:category/:product`, the product query narrows which products can become the `:product` URL segment after a category is chosen.
58
+ - A Collection source query runs after Studio has resolved and selected the route. On `/blog/:slug`, `relatedPosts` uses the selected post's `$params.slug.category` to narrow the entries shown in that route's editor; it does not create more routes.
59
+
60
+ ## Commands
61
+
62
+ ```bash
63
+ fimo pages list
64
+ fimo pages list --expand
65
+ fimo pages set <id> --path /about --label About
66
+ fimo pages set <id> --clear-params
67
+ fimo pages set <id> --clear-sources
68
+ fimo pages rename <id> <new-id>
69
+ fimo pages delete <id>
70
+ ```