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
@@ -1,22 +1,27 @@
1
1
  # Preview URL (without deploying)
2
2
 
3
- **Use `fimo preview url` whenever you need the current preview link — to open it, screenshot it, hand it to another tool, or verify a change you've already deployed. Never trigger a `fimo deploy` just to refresh a URL.**
3
+ **Use `fimo preview url` whenever you need the current hosted preview — to open it, screenshot it, hand it to another tool, or verify a change you already deployed. Never trigger `fimo deploy` just to retrieve a URL.**
4
4
 
5
- `fimo deploy` is a milestone command: it commits, pushes, syncs the sandbox, and only then prints the preview URL. `fimo preview url` skips all of that. It calls the API directly, gets a fresh 15-min token, and prints the URL. No commit, no push, no restart. Sub-second on a warm sandbox.
5
+ `fimo deploy` commits, pushes, and syncs the sandbox before it prints destinations. `fimo preview url` skips those deployment steps and only resolves the current Branch's preview destinations.
6
6
 
7
7
  ## Commands
8
8
 
9
9
  ```bash
10
- fimo preview url # URL for the current Branch (from git)
11
- fimo --branch feat/redesign preview url # URL for a specific Branch
10
+ fimo preview url # current Branch (from git)
11
+ fimo --branch feat/redesign preview url # specific Branch
12
12
  fimo preview url --branch main --json # structured output for agents / scripts
13
+ fimo preview url --all # print every destination as named raw URLs
14
+ curl -L "$(fimo preview url)" # fetch the raw sandbox preview
13
15
  ```
14
16
 
15
- `--env <name>` remains a compatibility alias for `--branch <name>`. The API and
16
- JSON response still use the legacy `env` field and `/env/` dashboard path.
17
+ `--env <name>` remains a compatibility alias for `--branch <name>`. The API and JSON response still use the legacy `env` field and `/env/` dashboard path.
17
18
 
18
- - **Interactive mode** shows named Preview and Fimo links. When piped, it prints only the raw preview URL, so `fimo preview url | xargs open` and `curl "$(fimo preview url)"` keep working.
19
- - **JSON mode** (or `FIMO_OUTPUT=json`) emits the standard envelope:
19
+ ## Human and machine behavior
20
+
21
+ - **Interactive terminal:** shows the stable `preview_url` and `studio_url` as named links. `preview_url` opens a full-screen Fimo viewer and requires a logged-in user with access to the project.
22
+ - **Piped or captured output:** prints only the short-lived `sandbox_url`. This preserves commands such as `curl -L "$(fimo preview url)"` and gives browsers, screenshot tools, and crawlers the directly fetchable site.
23
+ - **`--all`:** prints `preview_url`, `studio_url`, `sandbox_url`, and `sandbox_expires_at` as named raw values for a person inspecting every destination.
24
+ - **JSON mode** (or `FIMO_OUTPUT=json`): returns both destinations explicitly:
20
25
 
21
26
  ```json
22
27
  {
@@ -26,32 +31,33 @@ JSON response still use the legacy `env` field and `/env/` dashboard path.
26
31
  "data": {
27
32
  "project_id": "prj_abc",
28
33
  "env": "main",
29
- "preview_url": "https://...",
30
- "dashboard_url": "https://fimo.ai/app/projects/prj_abc/env/main/preview",
31
- "expires_at": "2026-06-02T18:42:00.000Z"
34
+ "preview_url": "https://fimo.ai/preview/prj_abc/main",
35
+ "sandbox_url": "https://preview.provider.example/session",
36
+ "sandbox_expires_at": "2026-08-20T18:42:00.000Z",
37
+ "studio_url": "https://fimo.ai/app/projects/prj_abc/env/main/preview",
38
+ "dashboard_url": "https://fimo.ai/app/projects/prj_abc/env/main/preview"
32
39
  }
33
40
  }
34
41
  ```
35
42
 
36
- Agents should read `data.preview_url` or `data.dashboard_url`, never parse the human output. The dashboard URL is stable; `expires_at` is the preview token's hard deadline. If you're caching the preview URL for more than ~10 minutes, re-run the command.
43
+ Agents must use `data.sandbox_url` for curl, Firecrawl, screenshots, and other machine reads. Use `data.preview_url` for the authenticated full-screen viewer and `data.studio_url` for the Branch inside Fimo Studio. `data.dashboard_url` is a deprecated compatibility alias for `data.studio_url`. The raw sandbox URL expires; resolve it again when `sandbox_expires_at` is near or has passed. The stable human URLs do not need to be regenerated.
37
44
 
38
45
  ## When to use it
39
46
 
40
- - **You changed something with `fimo deploy` and now want to look at it** — `fimo preview url` then open the URL.
41
- - **You need a URL for a screenshot, an agent-browser session, an analytics check, or a manual smoke test** — go straight here.
42
- - **You're polling the preview in a loop** — call `fimo preview url` once per loop body. Within ~5 minutes the API reuses the same token (cheap), beyond that you'll get a fresh one automatically.
43
- - **The previous URL stopped working** — the 15-min token expired. Re-run `fimo preview url`, don't redeploy.
47
+ - **You deployed a change and want to inspect it** — open the interactive `preview_url`.
48
+ - **An agent or tool needs to read the site** — pipe the command or use `data.sandbox_url` from JSON.
49
+ - **The raw URL expired** — run `fimo preview url` again; do not redeploy.
44
50
 
45
51
  ## When NOT to use it
46
52
 
47
- - **You changed code and want it on the preview** — that's still `fimo deploy`. `fimo preview url` only returns a URL; it doesn't push your local edits.
48
- - **You need the live, published URL** (the `*.fimo.site` or custom domain) — that comes from `fimo deploy --publish` / `fimo publish` and lives on the project, not in this command. See `references/deploy.md` and `references/domains.md`.
53
+ - **You changed code and want it on the preview** — use `fimo deploy`. This command only retrieves destinations.
54
+ - **You need the live published URL** — use `fimo deploy --publish` or `fimo publish`; see `references/deploy.md` and `references/domains.md`.
49
55
 
50
56
  ## Cold sandbox case
51
57
 
52
- If the Branch's sandbox has been torn down (long idle period, explicit teardown), the first `fimo preview url` lazy-provisions one — same ~60–90 s cost a `fimo deploy` would have paid. Subsequent calls are sub-second again. You don't need to do anything special; just wait it out.
58
+ Resolving `sandbox_url` may take roughly 60–90 seconds when an idle sandbox must be provisioned or restarted. The stable `preview_url` performs the same authenticated resolution when a project member opens it.
53
59
 
54
60
  ## See also
55
61
 
56
- - `references/deploy.md` — when you actually need to push code.
62
+ - `references/deploy.md` — when you need to push code.
57
63
  - `references/branches.md` — Branch semantics and the global `--branch <name>` flag.
@@ -1,6 +1,6 @@
1
1
  # Outbound webhooks
2
2
 
3
- > **Beta:** Test each destination and inspect its delivery history before depending on it in production.
3
+ > Test each destination and inspect its delivery history before depending on it in production.
4
4
 
5
5
  Use `fimo webhooks` to send project events to external HTTPS endpoints. The CLI and Studio edit the same project-wide configurations and delivery history. The CLI has no provider presets: inspect the destination's API documentation, then pass its URL, headers, and JSON body explicitly.
6
6
 
@@ -14,6 +14,12 @@ Use this skill for code that consumes the version-locked `fimo` package in the c
14
14
 
15
15
  Use the project-installed CLI for local inspection, code generation, and validation (`pnpm exec fimo`, `npm exec fimo`, `yarn fimo`, or `bunx --no-install fimo`, matching the lockfile). If that runner tries to install packages even though dependencies already exist, invoke the local `node_modules/.bin/fimo` executable instead. Load the `fimo-cli` skill for remote operational workflows such as schema pushes, label writes, entry mutations, and deploys. If the skill is not already available locally, fetch it with `npx fimo@latest skills get fimo-cli`.
16
16
 
17
+ Fimo API values may be class-backed tracked objects, not plain JSON. Keep them
18
+ as-is on the server. Before passing them to a `'use client'` prop or a
19
+ plain-JSON consumer such as Markdown, RSS, or JSON-LD, use the generated
20
+ serializer and hydrate them in the client when the generated client requires
21
+ it. Load the framework reference for the exact boundary.
22
+
17
23
  ## Orient before writing
18
24
 
19
25
  1. Run the project-installed `fimo describe --json` in a linked project and read `data.framework.slug`, schemas, locales, and tree. If the project is not linked yet, inspect `package.json` and the app directory instead.
@@ -35,6 +41,10 @@ Framework routing:
35
41
  - Nuxt, Remix, Vue, or another hosting-only setup → `references/frameworks/hosting.md`. Do not invent an SDK adapter that the installed package does not export.
36
42
  - No framework (static generator, plain HTML, a build script) → `references/frameworks/hosting.md` § `runtime`: leave `runtime.framework` unset.
37
43
 
44
+ For public-site performance or navigation work, also load the matching
45
+ `references/best-practices/astro.md`, `references/best-practices/sveltekit.md`,
46
+ or `references/best-practices/next.md` reference.
47
+
38
48
  When a project's framework version is uncertain, load
39
49
  `references/frameworks/compatibility.md`. Use the project's installed version
40
50
  and the documented adapter range; do not assume that a framework profile means
@@ -60,6 +70,7 @@ Each reference defines one package contract. Fetch it when the task reaches that
60
70
  - Media values, `<Image>`, `<StaticImage>` → `references/assets.md`
61
71
  - Static editable copy: `Label`, `t()`, providers, and server label readers → `references/labels.md`
62
72
  - Locale ownership and framework handoff → `references/locales.md`
73
+ - Upgrading a React Router app that imports `fimo/react-router/routes` → `references/migrations/react-router-route-ownership.md`
63
74
  - Astro connector and output/adapter contract → `references/frameworks/astro.md`
64
75
  - Framework detection, production routing, and hosting adapters → `references/frameworks/hosting.md`
65
76
  - Major visual work → `references/design.md`
@@ -0,0 +1,12 @@
1
+ import { FimoProviders } from 'fimo/react-router';
2
+ import { Outlet, useParams } from 'react-router';
3
+
4
+ export default function LocaleLayout() {
5
+ const { locale } = useParams();
6
+
7
+ return (
8
+ <FimoProviders locale={locale}>
9
+ <Outlet />
10
+ </FimoProviders>
11
+ );
12
+ }
@@ -1,11 +1,12 @@
1
1
  import type { RouteConfig } from '@react-router/dev/routes';
2
- import { index, route } from '@react-router/dev/routes';
3
- import { fimoRoutes } from 'fimo/react-router/routes';
2
+ import { layout, route } from '@react-router/dev/routes';
4
3
 
5
4
  const routes = [
6
- index('./pages/Index.tsx', { id: 'home' }),
7
- route('pricing', './pages/Pricing.tsx', { id: 'pricing' }),
8
- route('blog/:slug', './pages/BlogPost.tsx', { id: 'blog-post' }),
5
+ layout('./pages/LocaleLayout.tsx', [
6
+ route(':locale?', './pages/Index.tsx', { id: 'home' }),
7
+ route(':locale?/pricing', './pages/Pricing.tsx', { id: 'pricing' }),
8
+ route(':locale?/blog/:slug', './pages/BlogPost.tsx', { id: 'blog-post' }),
9
+ ]),
9
10
  ] satisfies RouteConfig;
10
11
 
11
- export default fimoRoutes(routes) satisfies RouteConfig;
12
+ export default routes;
@@ -0,0 +1,47 @@
1
+ # Astro website best practices
2
+
3
+ Load `references/frameworks/astro.md` first.
4
+
5
+ - Put the document shell, navigation, and shared metadata in a layout.
6
+ - Render the H1, primary copy, canonical, and crawlable links in the initial HTML.
7
+ - Pass tracked Fimo values intact to Fimo components; use `String(value)` only for attributes and URLs. Flattening removes Studio's edit target.
8
+ - Start independent Fimo reads with `Promise.all`; do not repeat page reads in children.
9
+ - Ship no client JavaScript for static content. Use `client:visible` or `client:idle` below the fold; reserve `client:load` for immediately required interaction.
10
+ - Use `server:defer` only for slow, secondary, or personalized UI, with a stable fallback. Keep primary content and metadata outside server islands.
11
+ - Prerender when rebuild freshness is acceptable; render on demand when edits must appear immediately.
12
+ - Give images dimensions; eagerly load only the likely LCP image.
13
+ - Return a real 404 for a missing slug. Build one canonical from the public origin and normalized route, never the preview host.
14
+
15
+ ## Consider incremental static builds
16
+
17
+ For Astro 7.2+ sites with many `getStaticPaths()` pages:
18
+
19
+ ```js
20
+ import { defineConfig } from 'astro/config';
21
+ import { fimo } from 'fimo/astro/config';
22
+
23
+ export default defineConfig({
24
+ integrations: [fimo()],
25
+ experimental: { incrementalBuild: true },
26
+ build: { concurrency: 1 },
27
+ });
28
+ ```
29
+
30
+ ```astro
31
+ export async function getStaticPaths() {
32
+ const { items } = await Story.list({ limit: 100 });
33
+ return items.map((story) => ({
34
+ params: { slug: String(story.slug) },
35
+ props: { story },
36
+ cacheKey: story.updatedAt,
37
+ }));
38
+ }
39
+ ```
40
+
41
+ - The `cacheKey` must change for every rendered data dependency, including shared labels, settings, and related entries. A slug is not an invalidation key.
42
+ - Persist `node_modules/.astro/` between builds. Use `astro build --force` after middleware changes or to ignore the cache.
43
+ - Keep build concurrency at `1`. Pages with server islands also need a stable `ASTRO_KEY`.
44
+
45
+ Verify production HTML, valid and missing slugs, canonical output, shipped scripts, API waterfalls, and image sizing. For incremental builds, prove one unchanged and one invalidated path.
46
+
47
+ Sources: [incremental builds](https://docs.astro.build/en/reference/experimental-flags/incremental-build/) and [server islands](https://docs.astro.build/en/guides/server-islands/).
@@ -0,0 +1,42 @@
1
+ # Next.js website best practices
2
+
3
+ Load `references/frameworks/next.md` and the matching router reference first. Instant Navigations apply only to Next 16.3+ App Router projects.
4
+
5
+ - Use Server Components by default and keep Client Components at interactive leaves.
6
+ - Keep root layouts cheap; put slow page-specific Fimo reads in the page or a nested component.
7
+ - Start independent reads together. Server Components should call generated Fimo modules directly, not application Route Handlers.
8
+ - Keep tracked Fimo values intact in Server Components. Use generated `serialize()`/`hydrate()` at JSON prop boundaries. Generated client hooks are already hydrated; pass their values directly to Fimo components.
9
+ - Render the H1, primary copy, canonical, and crawlable links in the server result. Do not repeat the read after hydration.
10
+ - Give images dimensions; prioritize only the likely LCP image.
11
+
12
+ ## Instant Navigations
13
+
14
+ ```ts
15
+ import type { NextConfig } from 'next';
16
+ import { withFimo } from 'fimo/next/config';
17
+
18
+ const nextConfig: NextConfig = {
19
+ cacheComponents: true,
20
+ partialPrefetching: true,
21
+ };
22
+
23
+ export default withFimo(nextConfig);
24
+ ```
25
+
26
+ Choose per blocking Fimo read:
27
+
28
+ - **Stream:** use `Suspense` for fresh or slow data. Prefer this when Studio edits must appear immediately.
29
+ - **Cache:** use `use cache` only with a publication-aware lifetime and tag invalidation.
30
+ - **Block:** set `instant = false` as low as possible when partial UI is misleading.
31
+
32
+ Keep default `<Link>` prefetching. Use `prefetch={true}` only for a few high-intent links; large lists can overload the content API. Prefetch rendering must be side-effect free.
33
+
34
+ Use `instant = true` to find blocking code, then verify with `next build` and `next start`; development does not prefetch. Inspect the shell and streams with Navigation Inspector.
35
+
36
+ - Call `notFound()` for a missing slug.
37
+ - Build one canonical from `metadataBase` and the normalized route, never the preview host.
38
+ - Avoid duplicate content reads between `generateMetadata` and the page.
39
+
40
+ Verify valid and missing slugs, canonical and initial HTML, shipped JavaScript, duplicate reads, image sizing, instant shell rendering, streaming, freshness, and bounded prefetching.
41
+
42
+ Sources: [Instant Navigations](https://nextjs.org/blog/next-16-3-instant-navigations), [`partialPrefetching`](https://github.com/vercel/next.js/blob/canary/docs/01-app/03-api-reference/05-config/01-next-config-js/partialPrefetching.mdx), and [`instant`](https://github.com/vercel/next.js/blob/canary/docs/01-app/03-api-reference/03-file-conventions/02-route-segment-config/instant.mdx).
@@ -0,0 +1,17 @@
1
+ # SvelteKit website best practices
2
+
3
+ Load `references/frameworks/sveltekit.md` first.
4
+
5
+ - Keep shared navigation, labels, and metadata in layouts; keep slow page data in the narrowest `+page.server.ts` or `+layout.server.ts`.
6
+ - Pass the request `event`. Serialize generated Fimo values at the load boundary and render them with Fimo components, which restore their Studio editing metadata. Do not flatten tracked values first.
7
+ - Start independent reads together. Use `await parent()` only for a real parent-data dependency.
8
+ - Await primary content. Stream only slow, non-essential promises; add a stable `{#await}` fallback, an error branch, and an early rejection handler when the promise does not use SvelteKit's `fetch`.
9
+ - Render the H1, primary copy, canonical, and crawlable links during SSR. Do not disable SSR or repeat the read after hydration.
10
+ - Keep browser JavaScript at interactive leaves.
11
+ - Use request-time loads when edits must appear immediately. Prerender or cache only when rebuild or invalidation behavior is explicit.
12
+ - Give images dimensions; eagerly load only the likely LCP image.
13
+ - Call `error(404, ...)` for a missing slug. Build one canonical from the configured public origin and normalized route, never the preview host.
14
+
15
+ Verify the production server response, valid and missing slugs, canonical output, streamed errors, shipped JavaScript, API waterfalls, and image sizing.
16
+
17
+ Source: [SvelteKit load and streaming](https://svelte.dev/docs/kit/load).
@@ -26,6 +26,11 @@ Marks: `bold`, `italic`, `underline`, `strike`, `code`, and `link`.
26
26
 
27
27
  Use semantic nodes instead of flattening long content into paragraphs. Render the returned value with the framework's `<RichText>` primitive so source metadata survives.
28
28
 
29
+ Richtext and other API values may carry class-backed tracking metadata. Values
30
+ rendered by server Fimo primitives can stay intact. Serialize them before a
31
+ plain-JSON consumer (Markdown, RSS, JSON-LD) or a client prop, then use the
32
+ generated client hydration helper where required.
33
+
29
34
  ## Entry payload
30
35
 
31
36
  CLI entry writes put every value, including the collection slug, under `data`:
@@ -56,12 +56,15 @@ Never declare `id`, `entryId`, `documentId`, `slug`, `locale`, `createdAt`, `upd
56
56
  | `richtext` | Tiptap JSONContent | formatted content |
57
57
  | `number` | number | quantities and ordering fields |
58
58
  | `boolean` | boolean | flags |
59
- | `date` | ISO date string | dates/timestamps |
59
+ | `date` | ISO date string | calendar days; loose about the form |
60
+ | `datetime` | ISO instant with offset | exact moments (`2026-08-13T09:30:00Z`) |
60
61
  | `media` | media object or array | images, video, files |
61
62
  | `json` | JSON | structured metadata |
62
63
  | `reference` | `{ "id": "..." }` or array | links to another schema |
63
64
  | `blocks` | ordered object array | nested/repeatable sections |
64
65
 
66
+ A `datetime` value must carry `Z` or `±HH:MM`; a bare day or a naive local time is rejected. Render it with `<DateTime>`, which keeps the whole instant in the `<time datetime>` attribute, and a `date` with `<Date>`. `unique` is not supported on `datetime`.
67
+
65
68
  An enum string uses `options`; its optional `default` must be one of them:
66
69
 
67
70
  ```json
@@ -73,7 +73,7 @@ const [settings, stories, labels] = await Promise.all([
73
73
  }
74
74
  ```
75
75
 
76
- The native surface is `Text`, `RichText`, `Image`, `StaticImage`, `Video`, `Date`, `Boolean`, and `Json` (component table: `references/ui.md`). Pass tracked values whole so Studio can resolve their source; use `String(value)` only for attributes and URLs.
76
+ The native surface is `Text`, `RichText`, `Image`, `StaticImage`, `Video`, `Date`, `DateTime`, `Boolean`, and `Json` (component table: `references/ui.md`). Pass tracked values whole so Studio can resolve their source; use `String(value)` only for attributes and URLs.
77
77
 
78
78
  ## Forms
79
79
 
@@ -107,11 +107,13 @@ export async function getStaticPaths() {
107
107
 
108
108
  ## Locales
109
109
 
110
- The application resolves the locale — route prefix, middleware, domain, `Astro.currentLocale`, cookie, or its i18n library — and passes it to content reads and `getLabels({ locale })`. When a server read omits `locale`, the Fimo API resolves the project default; do not hardcode a fallback locale in application code. Astro needs no Fimo locale provider. Ownership rules: `references/locales.md`.
110
+ Configure Astro i18n from `.fimo/config.json#i18n` and use `Astro.currentLocale` for content reads, `getLabels({ locale })`, and `<html lang>`. The standard starter keeps the configured default locale unprefixed and prefixes the others. Existing applications may instead resolve locale through middleware, domains, cookies, or another application-owned strategy. Astro needs no Fimo locale provider. Ownership rules: `references/locales.md`.
111
+
112
+ The new-project shell pairs unprefixed default-locale pages with a parallel `[locale]` tree because Astro has no optional single-segment page filename. Add locales in `.fimo/config.json`; Astro's native i18n router validates the prefixed tree. Route metadata uses `/:locale` with `params.locale.optional: true`; Astro page files remain authoritative.
111
113
 
112
114
  ## Studio route catalog
113
115
 
114
- `.fimo/config.json#routes` is an optional catalog of pages for Studio navigation, not router configuration. Never replace or infer Astro's route files, redirects, middleware, or 404 behavior from it. Keep paths canonical and unlocalized, and describe dynamic segments with `params` so Studio can list entries:
116
+ `.fimo/config.json#routes` is an optional catalog of pages for Studio navigation, not router configuration. Never replace or infer Astro's route files, redirects, middleware, or 404 behavior from it. Keep routes without locale ownership canonical and unlocalized. For a locale-aware route, declare the reserved `/:locale` segment and mark it optional in `params`; describe other dynamic segments with `params` so Studio can list entries:
115
117
 
116
118
  ```json
117
119
  {
@@ -49,9 +49,12 @@ Locally, the app derives its env from the **git branch**: `fimo/vite`,
49
49
  API URL from `.fimo/project.json`
50
50
  (`projectId` + `tenantApiBaseUrl`, recorded once at `init`/`clone`/`link`) and
51
51
  expose the Vite, Next and public (`PUBLIC_*`) aliases plus `FIMO_ENV` /
52
- `NEXT_PUBLIC_FIMO_ENV` at startup. No env file is written on a switch, so a plain `git checkout` is a
52
+ `NEXT_PUBLIC_FIMO_ENV` at startup. The Vite connectors derive them during both
53
+ dev and production builds, and `withFimo` derives them in `next dev`, `next
54
+ build`, and `next start`, so a linked project builds and serves locally without
55
+ exporting them by hand. No env file is written on a switch, so a plain `git checkout` is a
53
56
  complete env switch. Never hardcode a tenant URL in application source. One
54
- rule, per variable: a value the user set explicitly (`.env`, shell, their own
57
+ rule, per variable: a non-empty value the user set explicitly (`.env`, shell, their own
55
58
  `define`) is left alone, and Fimo fills the variables they did not set.
56
59
 
57
60
  For a framework whose alias is not in that list yet, preserve or add its normal
@@ -76,6 +76,12 @@ This example demonstrates request-time rendering, not a recommended locale polic
76
76
 
77
77
  ## Client Components
78
78
 
79
+ When a Server Component passes Fimo content into a Client Component, it MUST
80
+ serialize with the generated server module and the Client Component MUST
81
+ hydrate with the matching generated `.client` module. Do not pass a raw Fimo
82
+ value merely because its enumerable fields look JSON-safe. No conversion is
83
+ needed while the value stays inside server rendering.
84
+
79
85
  Client Components use the generated `.client` module and `fimo/next/client`:
80
86
 
81
87
  ```tsx
@@ -33,6 +33,16 @@ When labels are not needed at that boundary, use `<FimoProvider locale={locale}>
33
33
  - Pages Router i18n: reuse `context.locale` in data functions and `router.locale`/page props on the client.
34
34
  - Default-only app: omit locale arguments and let Fimo use `.fimo/config.json#i18n.defaultLocale` (fallback `en`).
35
35
 
36
+ ## New-project boundary
37
+
38
+ Choose the primary locale from the user's request before building pages. Put the first explicitly requested locale in `.fimo/config.json#i18n.defaultLocale` and keep all requested locales in `i18n.locales`. That edit is the whole locale setup: `src/locales.ts` reads the file, so the default locale passed to `FimoProvider`, the `<html lang>` of each tree, and the set of prefixed URLs follow it. If the user gives no locale signal, keep `en` and state that choice. Never add `NEXT_PUBLIC_FIMO_DEFAULT_LOCALE` or `FIMO_DEFAULT_LOCALE`; the runtime ignores them by design.
39
+
40
+ The starter keeps default routes in an unprefixed `app/(default)` route group and a native `app/[locale]` tree for the other locales. Only a root layout may render `<html>`, so each tree owns its root layout and renders the shared `src/components/Document.tsx` with its locale: the unprefixed tree with `defaultLocale`, the prefixed tree with `params.locale`. The prefixed layout 404s a locale that is not in `prefixedLocales`, which is why the default locale has exactly one URL. For `/:locale/pricing`, `params.locale.optional: true` means omit the configured default locale: with `i18n.defaultLocale: "en"`, `/pricing` is English and `/fr/pricing` is French. With `optional: false`, both `/en/pricing` and `/fr/pricing` are prefixed. The default locale value chooses the fallback locale; `optional` independently controls URL prefixes. A route without `:locale` remains application-owned.
41
+
42
+ Next.js has no optional single-segment route folder, so mirror localized routes in both existing groups as the site grows. Astro uses the same paired native filesystem-tree shape for this semantic. Do not replace the trees with middleware, rewrites, an optional catch-all that captures the application route tree, or a Fimo route helper. The config route catalog describes the URL shapes for Studio; Next's `app` directory remains authoritative.
43
+
44
+ Keep the starter's client-only `src/components/FimoPreviewBridge.tsx` inside `Document`, so both trees mount it. It reads Next's native pathname/router, reports the settled locale to Studio, and lets Studio navigate through Next; do not move Next imports into Fimo's shared runtime.
45
+
36
46
  With `next-i18next`, keep its routing and translation provider for the strings it owns. Pass the same resolved locale to Fimo; do not replace the library or duplicate its route structure.
37
47
 
38
48
  Before creating non-default Fimo labels or content variants, confirm that those locales are enabled for the linked Fimo project. Load `fimo-cli` with its `locales` reference and run `fimo locales add <locale> --yes --json`; `.fimo/config.json` documents the application's locale policy, but `fimo validate` does not add project locales.
@@ -54,6 +64,6 @@ Fimo owns:
54
64
  - client content/label context after receiving the locale;
55
65
  - editable source metadata.
56
66
 
57
- Do not add `.fimo/config.json#routes` to a Next project yet. The current route-metadata validator expects React Router's `src/routes.ts`; a first-class Next Studio catalog and preview bridge are separate product work. Do not create a fake `src/routes.ts` to satisfy that check.
67
+ The new-project shell includes a small `.fimo/config.json#routes` catalog for Studio. It describes the page URLs but does not configure the App Router. Keep the `app` directory authoritative, and do not create a fake `src/routes.ts` or a universal Fimo route helper.
58
68
 
59
- Do not introduce `[locale]` segments, cookie routing, or domain routing unless the product request requires that URL strategy. Do not add a second locale provider when the existing one can supply the resolved locale to Fimo.
69
+ Do not introduce new locale middleware, cookie routing, or domain routing unless the product request requires that URL strategy. Do not add a second locale provider when the existing one can supply the resolved locale to Fimo.
@@ -82,6 +82,13 @@ Never write the registry by hand and never create alternate `*.schema.json` file
82
82
 
83
83
  ## Server and client boundaries
84
84
 
85
+ Next.js MUST receive generated serialized values across every Server-to-Client
86
+ Component prop boundary. Fimo values may be class-backed even when they look
87
+ JSON-shaped. Values that stay in Server Components may stay intact; values for
88
+ Client Components use the generated server `serialize()` and client
89
+ `hydrate()`. Plain-JSON outputs such as Markdown, RSS, and JSON-LD also use the
90
+ generated serialization rather than `JSON.stringify` as a conversion strategy.
91
+
85
92
  Forms follow the same boundary. Server actions and route handlers import the
86
93
  generated server form module; a Client Component imports its generated
87
94
  `.client.ts` module. Both expose `submitX(data)` and use the shared Fimo form
@@ -85,18 +85,24 @@ Keep the application's existing `Layout` details. Add only the Fimo provider and
85
85
 
86
86
  ## Routes and locales
87
87
 
88
- `fimoRoutes()` is an optional helper for Fimo's path-prefix locale convention:
88
+ React Router owns locale paths. Declare the optional locale segment directly so the default locale stays unprefixed:
89
89
 
90
90
  ```ts
91
91
  import type { RouteConfig } from '@react-router/dev/routes';
92
- import { index } from '@react-router/dev/routes';
93
- import { fimoRoutes } from 'fimo/react-router/routes';
94
-
95
- const routes = [index('./pages/Index.tsx', { id: 'home' })] satisfies RouteConfig;
96
- export default fimoRoutes(routes) satisfies RouteConfig;
92
+ import { layout, route } from '@react-router/dev/routes';
93
+
94
+ export default [
95
+ layout('./pages/LocaleLayout.tsx', [
96
+ route(':locale?', './pages/Index.tsx'),
97
+ route(':locale?/pricing', './pages/Pricing.tsx'),
98
+ route(':locale?/blog/:slug', './pages/BlogPost.tsx'),
99
+ ]),
100
+ ] satisfies RouteConfig;
97
101
  ```
98
102
 
99
- Custom locale routers can skip it and pass their resolved locale to `<FimoProviders locale={locale}>`. Use `FimoLink` only when the application adopts Fimo's locale-aware link behavior; otherwise preserve its links. Copyable path-prefix locale examples live in `assets/react-router-locales/`.
103
+ Read `locale` in an application layout and pass it to `<FimoProviders locale={locale}>`; omission resolves the configured default. Copy `assets/react-router-locales/routes.ts` and `LocaleLayout.tsx` for a complete boundary. For multilingual apps, move the root provider there instead of nesting providers. Preserve an existing locale library, and use `FimoLink` only when its locale-preserving behavior matches the app.
104
+
105
+ If an existing project imports `fimo/react-router/routes`, load `references/migrations/react-router-route-ownership.md` before changing it.
100
106
 
101
107
  ## Content and labels
102
108
 
@@ -122,6 +128,8 @@ Declare the runtime in `.fimo/config.json`:
122
128
 
123
129
  The optional `routes` object is Studio's semantic page catalog. Keep it aligned with application routes when the project uses Studio navigation, but do not treat it as the production router.
124
130
 
131
+ For new projects, apply `references/locales.md`, keep the starter's `:locale?` route, and describe it in Studio metadata as `/:locale` with `params.locale.optional: true`.
132
+
125
133
  ## Boundaries
126
134
 
127
135
  - Route modules and `meta` exports own routing and SEO.
@@ -74,24 +74,27 @@ do not import a Fimo environment variable or hardcode a tenant URL:
74
74
  // src/routes/+layout.server.ts
75
75
  import { getLabels } from 'fimo/sveltekit';
76
76
 
77
- export async function load(event) {
78
- // If the app resolves a locale from its URL or session, pass it:
79
- // const locale = resolveLocale(event.url); // your app's resolver
80
- // return { labels: await getLabels({ event, locale }) };
77
+ import { resolveLocale } from '../locales';
81
78
 
82
- // Otherwise, omit it and use the Fimo project default.
83
- return { labels: await getLabels({ event }) };
79
+ export async function load(event) {
80
+ const locale = resolveLocale(event.params);
81
+ return { locale, labels: await getLabels({ event, locale }) };
84
82
  }
85
83
  ```
86
84
 
87
85
  ```svelte
88
86
  <!-- src/routes/+layout.svelte -->
89
87
  <script lang="ts">
88
+ import { afterNavigate } from '$app/navigation';
90
89
  import { FimoProvider } from 'fimo/sveltekit/components';
91
90
  import type { LayoutData } from './$types';
92
91
  import type { Snippet } from 'svelte';
93
92
 
94
93
  let { data, children }: { data: LayoutData; children: Snippet } = $props();
94
+
95
+ afterNavigate(() => {
96
+ document.documentElement.lang = data.locale;
97
+ });
95
98
  </script>
96
99
 
97
100
  <FimoProvider labels={data.labels}>
@@ -101,7 +104,7 @@ export async function load(event) {
101
104
 
102
105
  Generated values are serialized at a `load` boundary and hydrated in the
103
106
  component that renders them. Use `Text`, `RichText`, `Image`, `Video`, `Date`,
104
- `Boolean`, `Json`, and `Number` from `fimo/sveltekit/components`. `Number`
107
+ `DateTime`, `Boolean`, `Json`, and `Number` from `fimo/sveltekit/components`. `Number`
105
108
  formats plain numeric values for display; numeric fields currently have no
106
109
  source metadata, so it is not a Studio-editable primitive.
107
110
 
@@ -128,7 +131,7 @@ export const actions = {
128
131
  `PUBLIC_FIMO_PREVIEW_SCRIPT_URL` from SvelteKit's dynamic public environment,
129
132
  loads that script once, delegates navigation to SvelteKit's `goto`, and
130
133
  refreshes data with `invalidateAll()`. Without that environment value it does
131
- nothing. Do not add a Fimo server hook or a second preview component.
134
+ nothing. Do not add a second preview component.
132
135
 
133
136
  ## Boundaries
134
137
 
@@ -136,3 +139,7 @@ nothing. Do not add a Fimo server hook or a second preview component.
136
139
  - `fimo/sveltekit/vite` owns dev source tagging only.
137
140
  - `FimoProvider` owns labels and the optional Studio preview bridge.
138
141
  - Do not add React, React Query, or a Vite SPA fallback to a SvelteKit project.
142
+
143
+ The starter uses SvelteKit's native `[[locale=locale]]` boundary and a matcher limited to configured, non-default locales, so unrelated top-level paths are not locales. `src/locales.ts` derives the default and prefixed set from `.fimo/config.json` and owns the shared locale resolver. Keep passing the tracked `event.params` object into that resolver from the root server layout so locale-crossing client navigation reruns labels.
144
+
145
+ For accessibility, SvelteKit's documented multilingual pattern renders `<html lang="%lang%">` through `src/hooks.server.ts#transformPageChunk`. The root layout updates the attribute after client navigation. Keep those seams aligned with the application's locale resolver. Keep `[[locale=locale]]` for an unprefixed default; use `[locale=locale]` only when every locale must be prefixed.
@@ -32,7 +32,7 @@ const items = [
32
32
 
33
33
  Do not use variables or interpolated expressions as label keys. Namespace literal keys by page/section/component, such as `hero.title`, `nav.signIn`, or `contact.form.submit`.
34
34
 
35
- Missing keys render as an empty tracked value. Run `fimo validate`, then create values with `fimo labels set` or `set-many`; do not add fallback copy to code.
35
+ Missing keys render as an empty tracked value. Run `fimo validate`, then create values with `fimo labels set` or `set-many`; do not add fallback copy to code (the one exception is a component that cannot mount under the provider — see "Provider mount" below).
36
36
 
37
37
  ## Framework adapters
38
38
 
@@ -46,6 +46,14 @@ The label contract is shared; acquisition differs by runtime:
46
46
 
47
47
  Load the matching framework reference before choosing a provider or server reader.
48
48
 
49
+ ## Provider mount
50
+
51
+ Components that render `Label` or call `useLabels()` MUST be mounted below the framework's `FimoProvider` (or the framework integration that supplies label context). Globally mounted components — cookie banners, toasts, consent dialogs injected near the document root — are the common escapees: outside the provider they render blank labels with no error.
52
+
53
+ If a component genuinely cannot be moved under the provider, use an explicit hardcoded, non-editable fallback and report that tradeoff to the user. Never ship silently blank copy.
54
+
55
+ When a label renders empty, check in order: (1) the key exists (`fimo validate`, `fimo labels list`), (2) the active locale has a value, (3) the component is under the provider. Add fallback copy only after those checks, and only in the cannot-mount case above.
56
+
49
57
  ## Locale behavior
50
58
 
51
59
  `.fimo/config.json#i18n.defaultLocale` selects the default (fallback `en`). The application resolves the active locale and gives it to the framework adapter. Create explicit label values for each configured locale the product supports.
@@ -13,7 +13,9 @@ The application owns locale resolution and routing. Fimo consumes the resolved l
13
13
  }
14
14
  ```
15
15
 
16
- Keep one locale unless the product asks for multilingual output. Locale tags should be structurally valid, such as `en`, `pt-BR`, or `zh-Hans`.
16
+ For new projects, derive the primary locale from the request; when several are explicit, the first one named is the default. Update `i18n.defaultLocale`, `i18n.locales`, the framework-native route boundary and matcher, and the document language default. If the user gives no locale signal, retain the starter default and state that choice.
17
+
18
+ Keep one locale unless the product asks for multilingual output. Keep it locale-ready without forcing `/en`, a language switcher, global path-prefix routing, or localized schemas. Locale tags should be structurally valid, such as `en`, `pt-BR`, or `zh-Hans`.
17
19
 
18
20
  For an already linked project, enable each locale in Fimo before writing non-default label or content variants. Load `fimo-cli` with its `locales` reference and run `fimo locales add <locale> --yes --json`; local config and `fimo validate` do not provision project locales. Do not change the application's route strategy to work around a missing locale.
19
21
 
@@ -22,6 +24,8 @@ For an already linked project, enable each locale in Fimo before writing non-def
22
24
  - Resolve locale from its router, route parameters, domain, request headers, middleware, cookie, existing i18n library, or user preference.
23
25
  - Keep its existing public URLs, redirects, links, `<html lang/dir>`, and SEO behavior.
24
26
  - Pass the resolved locale to Fimo's server reads and client provider.
27
+ - Keep the default locale separate from the URL prefix policy. `optional: true` means omit the configured default locale from the URL: with `defaultLocale: "en"`, `/pricing` is English and `/fr/pricing` is French. With `optional: false`, every locale is prefixed (`/en/pricing` and `/fr/pricing`).
28
+ - Treat routes without a `:locale` segment as application-owned. Fimo does not add or interpret a locale prefix for them.
25
29
  - Treat any optional Studio route catalog as framework-adapter-specific; load the framework reference before creating or changing one.
26
30
 
27
31
  ## Fimo responsibilities
@@ -39,4 +43,6 @@ For an already linked project, enable each locale in Fimo before writing non-def
39
43
  - React Router standard locale routing → load `references/frameworks/react-router.md`.
40
44
  - Vite + React/custom React router → load `references/frameworks/vite-react.md` and pass locale through its existing provider seam.
41
45
 
42
- Do not replace an existing locale system merely to add Fimo. Do not duplicate localized routes in the Studio catalog. Do not assume Fimo's route helpers are universal framework APIs.
46
+ Do not replace an existing locale system merely to add Fimo. Do not duplicate localized routes in the Studio catalog. Every framework resolves its active locale and passes it to Fimo through that framework's provider or server-read seam.
47
+
48
+ Astro and Next implement an optional locale boundary with paired native filesystem route trees: one unprefixed tree for the default locale and one prefixed tree for the other locales. Neither framework has an optional single-segment filesystem folder.