fimo 0.8.0 → 0.9.0-experimental.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/content-templates/hooks-template.eta +4 -2
- package/assets/content-templates/types-template.eta +66 -1
- package/assets/skills/fimo/SKILL.md +1 -1
- package/assets/skills/fimo/references/content.md +86 -15
- package/assets/skills/fimo-cli/SKILL.md +6 -2
- package/assets/skills/fimo-cli/references/content.md +61 -2
- package/assets/skills/fimo-cli/references/integrations/firecrawl.md +20 -4
- package/assets/skills/fimo-cli/references/integrations.md +5 -1
- package/assets/skills/fimo-cli/references/webhooks.md +162 -0
- package/assets/skills/fimo-migration/SKILL.md +22 -2
- package/assets/skills/fimo-migration/references/content.md +24 -0
- package/assets/skills/fimo-migration/references/manifest.md +35 -0
- package/assets/skills/fimo-migration/references/qa.md +24 -2
- package/assets/skills/fimo-migration/references/workflow.md +12 -1
- package/assets/skills/fimo-migration/references/wrap.md +617 -0
- package/assets/skills/fimo-studio/SKILL.md +5 -3
- package/assets/skills/fimo-studio/references/cms.md +9 -1
- package/assets/skills/fimo-studio/references/visual-editing.md +5 -3
- package/assets/skills/fimo-studio/references/webhooks.md +42 -0
- package/dist/build/vite/plugins/translations.d.ts +2 -8
- package/dist/build/vite/plugins/translations.js +3 -121
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +1051 -144
- package/dist/runtime/app/FimoProviders.d.ts +1 -11
- package/dist/runtime/app/FimoProviders.js +2 -23
- package/dist/runtime/astro/index.d.ts +2 -0
- package/dist/runtime/astro/index.js +3 -0
- package/dist/runtime/astro/server.d.ts +3 -0
- package/dist/runtime/astro/server.js +6 -0
- package/dist/runtime/content/client/internal.js +1 -0
- package/dist/runtime/content/client/types.d.ts +16 -0
- package/dist/runtime/i18n/FimoLocaleContext.js +1 -0
- package/dist/runtime/next/FimoNextProviders.d.ts +24 -0
- package/dist/runtime/next/FimoNextProviders.js +20 -0
- package/dist/runtime/next/FimoNextScripts.d.ts +10 -0
- package/dist/runtime/next/FimoNextScripts.js +19 -0
- package/dist/runtime/next/index.d.ts +14 -0
- package/dist/runtime/next/index.js +14 -0
- package/dist/runtime/next/server.d.ts +2 -0
- package/dist/runtime/next/server.js +4 -0
- package/dist/runtime/nuxt/composables.d.ts +9 -0
- package/dist/runtime/nuxt/composables.js +57 -0
- package/dist/runtime/nuxt/index.d.ts +3 -0
- package/dist/runtime/nuxt/index.js +6 -0
- package/dist/runtime/nuxt/server.d.ts +3 -0
- package/dist/runtime/nuxt/server.js +6 -0
- package/dist/runtime/primitives/labels-hook.d.ts +33 -0
- package/dist/runtime/primitives/labels-hook.js +41 -0
- package/dist/runtime/primitives/labels-store.d.ts +12 -0
- package/dist/runtime/primitives/labels-store.js +60 -0
- package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +5 -3
- package/dist/runtime/primitives/lib/useFimoLiveValue.js +11 -4
- package/dist/runtime/primitives/translations.d.ts +1 -27
- package/dist/runtime/primitives/translations.js +7 -85
- package/dist/runtime/react/FimoSpaProviders.d.ts +36 -0
- package/dist/runtime/react/FimoSpaProviders.js +63 -0
- package/dist/runtime/react/index.d.ts +33 -0
- package/dist/runtime/react/index.js +39 -0
- package/dist/runtime/remix/FimoRemixProviders.d.ts +16 -0
- package/dist/runtime/remix/FimoRemixProviders.js +12 -0
- package/dist/runtime/remix/FimoRemixScripts.d.ts +10 -0
- package/dist/runtime/remix/FimoRemixScripts.js +19 -0
- package/dist/runtime/remix/index.d.ts +12 -0
- package/dist/runtime/remix/index.js +11 -0
- package/dist/runtime/remix/server.d.ts +2 -0
- package/dist/runtime/remix/server.js +2 -0
- package/dist/runtime/shared/display-routes.d.ts +14 -0
- package/dist/runtime/shared/display-routes.js +25 -0
- package/dist/runtime/shared/fimo-config.server.js +1 -0
- package/dist/runtime/shared/fimo-config.types.d.ts +2 -0
- package/dist/runtime/shared/i18n-messages.d.ts +29 -0
- package/dist/runtime/shared/i18n-messages.js +79 -0
- package/dist/runtime/shared/labels-fetch.pure.d.ts +17 -0
- package/dist/runtime/shared/labels-fetch.pure.js +71 -0
- package/dist/runtime/shared/labels-fetch.server.d.ts +7 -0
- package/dist/runtime/shared/labels-fetch.server.js +97 -0
- package/dist/runtime/shared/labels-t.pure.d.ts +2 -0
- package/dist/runtime/shared/labels-t.pure.js +10 -0
- package/dist/runtime/strapi/client.d.ts +30 -0
- package/dist/runtime/strapi/client.js +89 -0
- package/dist/runtime/strapi/index.d.ts +5 -0
- package/dist/runtime/strapi/index.js +6 -0
- package/dist/runtime/strapi/reshape.d.ts +46 -0
- package/dist/runtime/strapi/reshape.js +114 -0
- package/dist/runtime/svelte/index.d.ts +3 -0
- package/dist/runtime/svelte/index.js +7 -0
- package/dist/runtime/svelte/server.d.ts +3 -0
- package/dist/runtime/svelte/server.js +6 -0
- package/dist/runtime/vue/index.d.ts +3 -0
- package/dist/runtime/vue/index.js +5 -0
- package/dist/runtime/vue/server.d.ts +3 -0
- package/dist/runtime/vue/server.js +6 -0
- package/dist/runtime/wrapped/FimoFileLink.d.ts +17 -0
- package/dist/runtime/wrapped/FimoFileLink.js +19 -0
- package/dist/runtime/wrapped/FimoMediaImage.d.ts +14 -0
- package/dist/runtime/wrapped/FimoMediaImage.js +20 -0
- package/dist/runtime/wrapped/FimoMediaVideo.d.ts +14 -0
- package/dist/runtime/wrapped/FimoMediaVideo.js +20 -0
- package/dist/runtime/wrapped/FimoRichTextBlock.d.ts +23 -0
- package/dist/runtime/wrapped/FimoRichTextBlock.js +22 -0
- package/dist/runtime/wrapped/FimoText.d.ts +22 -0
- package/dist/runtime/wrapped/FimoText.js +20 -0
- package/dist/runtime/wrapped/WrappedContentContext.d.ts +28 -0
- package/dist/runtime/wrapped/WrappedContentContext.js +30 -0
- package/dist/runtime/wrapped/WrappedProviders.d.ts +33 -0
- package/dist/runtime/wrapped/WrappedProviders.js +101 -0
- package/dist/runtime/wrapped/dom.d.ts +4 -0
- package/dist/runtime/wrapped/dom.js +23 -0
- package/dist/runtime/wrapped/server.d.ts +77 -0
- package/dist/runtime/wrapped/server.js +237 -0
- package/dist/scripts/apply-wrap-templates.d.ts +61 -0
- package/dist/scripts/apply-wrap-templates.js +132 -0
- package/dist/scripts/apply-wrap.d.ts +46 -0
- package/dist/scripts/apply-wrap.js +278 -0
- package/dist/scripts/cms/discover.d.ts +2 -0
- package/dist/scripts/cms/discover.js +17 -0
- package/dist/scripts/cms/example-content.d.ts +33 -0
- package/dist/scripts/cms/example-content.js +163 -0
- package/dist/scripts/cms/strapi/detect.d.ts +2 -0
- package/dist/scripts/cms/strapi/detect.js +186 -0
- package/dist/scripts/cms/strapi/index.d.ts +3 -0
- package/dist/scripts/cms/strapi/index.js +25 -0
- package/dist/scripts/cms/strapi/list-source.d.ts +17 -0
- package/dist/scripts/cms/strapi/list-source.js +90 -0
- package/dist/scripts/cms/strapi/schema-map.d.ts +9 -0
- package/dist/scripts/cms/strapi/schema-map.js +279 -0
- package/dist/scripts/cms/strapi/shapes.d.ts +23 -0
- package/dist/scripts/cms/strapi/shapes.js +38 -0
- package/dist/scripts/cms/strapi/touchpoints.d.ts +31 -0
- package/dist/scripts/cms/strapi/touchpoints.js +145 -0
- package/dist/scripts/cms/strapi/wire-client.d.ts +15 -0
- package/dist/scripts/cms/strapi/wire-client.js +107 -0
- package/dist/scripts/cms/strapi/wiring.d.ts +17 -0
- package/dist/scripts/cms/strapi/wiring.js +46 -0
- package/dist/scripts/cms/types.d.ts +145 -0
- package/dist/scripts/cms/types.js +11 -0
- package/dist/scripts/detect-framework.d.ts +39 -0
- package/dist/scripts/detect-framework.js +133 -0
- package/dist/scripts/draft-rows.d.ts +19 -0
- package/dist/scripts/draft-rows.js +135 -0
- package/dist/scripts/draft-schemas.d.ts +27 -0
- package/dist/scripts/draft-schemas.js +188 -0
- package/dist/scripts/extract-translations.js +16 -11
- package/dist/scripts/frameworks/astro/routes.d.ts +3 -0
- package/dist/scripts/frameworks/astro/routes.js +55 -0
- package/dist/scripts/frameworks/astro/template-style.d.ts +7 -0
- package/dist/scripts/frameworks/astro/template-style.js +19 -0
- package/dist/scripts/frameworks/discover.d.ts +70 -0
- package/dist/scripts/frameworks/discover.js +178 -0
- package/dist/scripts/frameworks/next/rewire.d.ts +30 -0
- package/dist/scripts/frameworks/next/rewire.js +258 -0
- package/dist/scripts/frameworks/next/routes.d.ts +17 -0
- package/dist/scripts/frameworks/next/routes.js +134 -0
- package/dist/scripts/frameworks/next/wiring.d.ts +33 -0
- package/dist/scripts/frameworks/next/wiring.js +186 -0
- package/dist/scripts/frameworks/nuxt/routes.d.ts +3 -0
- package/dist/scripts/frameworks/nuxt/routes.js +54 -0
- package/dist/scripts/frameworks/nuxt/template-style.d.ts +9 -0
- package/dist/scripts/frameworks/nuxt/template-style.js +27 -0
- package/dist/scripts/frameworks/remix/routes.d.ts +3 -0
- package/dist/scripts/frameworks/remix/routes.js +50 -0
- package/dist/scripts/frameworks/support.d.ts +75 -0
- package/dist/scripts/frameworks/support.js +165 -0
- package/dist/scripts/frameworks/sveltekit/routes.d.ts +3 -0
- package/dist/scripts/frameworks/sveltekit/routes.js +50 -0
- package/dist/scripts/frameworks/sveltekit/template-style.d.ts +9 -0
- package/dist/scripts/frameworks/sveltekit/template-style.js +54 -0
- package/dist/scripts/frameworks/vite/routes.d.ts +15 -0
- package/dist/scripts/frameworks/vite/routes.js +93 -0
- package/dist/scripts/frameworks/vite/wiring.d.ts +10 -0
- package/dist/scripts/frameworks/vite/wiring.js +99 -0
- package/dist/scripts/i18n-namespace.d.ts +27 -0
- package/dist/scripts/i18n-namespace.js +155 -0
- package/dist/scripts/lib/validation-report.d.ts +1 -0
- package/dist/scripts/lib/validation-report.js +3 -0
- package/dist/scripts/render-parity/capture.d.ts +56 -0
- package/dist/scripts/render-parity/capture.js +366 -0
- package/dist/scripts/render-parity/compare.d.ts +59 -0
- package/dist/scripts/render-parity/compare.js +0 -0
- package/dist/scripts/render-parity/normalize-html.d.ts +13 -0
- package/dist/scripts/render-parity/normalize-html.js +223 -0
- package/dist/scripts/render-parity/types.d.ts +41 -0
- package/dist/scripts/render-parity/types.js +1 -0
- package/dist/scripts/scan-wrappable.d.ts +196 -0
- package/dist/scripts/scan-wrappable.js +1232 -0
- package/dist/scripts/validate-route-metadata.js +11 -0
- package/dist/scripts/validate-schemas.js +42 -1
- package/package.json +84 -4
- package/release.json +2 -2
- package/templates/react-router/package.json +1 -1
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
# Wrap Mode
|
|
2
|
+
|
|
3
|
+
Wrap mode is the default migration for a **source-backed, working JS codebase**.
|
|
4
|
+
The supported-framework list lives in the CLI, not in this document: `fimo init`
|
|
5
|
+
detects the framework and says whether it can adopt the site (and offers the
|
|
6
|
+
rebuild path when it cannot). The contract below is framework-neutral;
|
|
7
|
+
framework-specific notes live in the "Framework notes" section at the end.
|
|
8
|
+
The user's stack stays. Nothing is rebuilt. The migration is a mechanical
|
|
9
|
+
wrapping pass that makes existing content editable from Fimo, plus a mandatory
|
|
10
|
+
content-seeding pass so Fimo becomes the source of truth.
|
|
11
|
+
|
|
12
|
+
**Never rewrite routing, styling, structure, or component logic.** The final
|
|
13
|
+
diff must contain only: the one-time wiring, wrapper components, label calls,
|
|
14
|
+
config files, and lockfile/dependency changes. If a change does not make
|
|
15
|
+
content editable, it does not belong in a wrap migration.
|
|
16
|
+
|
|
17
|
+
## When wrap does NOT apply
|
|
18
|
+
|
|
19
|
+
- URL-only migrations (no code) → rebuild path (`fimo migrate <url>`).
|
|
20
|
+
- Builder exports / static HTML dumps → rebuild path.
|
|
21
|
+
- Codebases that do not build/run as-is → fix-first is the owner's call;
|
|
22
|
+
wrap assumes a working site.
|
|
23
|
+
- Non-JS backends (PHP/WordPress/Drupal) → not supported yet.
|
|
24
|
+
|
|
25
|
+
## Phases
|
|
26
|
+
|
|
27
|
+
### W0. Agent-driven run (default)
|
|
28
|
+
|
|
29
|
+
When YOU (the coding agent) are asked to migrate an adopted site, you own the
|
|
30
|
+
whole loop — the human's only remaining jobs are `fimo init` (done before you)
|
|
31
|
+
and the final `fimo deploy` (never yours). The deterministic machine does the
|
|
32
|
+
heavy lifting; you run it, relay the user's decisions, handle the judgment
|
|
33
|
+
items, and loop until the gates say done:
|
|
34
|
+
|
|
35
|
+
`fimo init` writes a starter `.fimo/migration/wrap/agent-prompt.md` and
|
|
36
|
+
`fimo migrate` regenerates it with the full work order — that file is the
|
|
37
|
+
source of truth at every step; the user's entry prompt just points to it.
|
|
38
|
+
|
|
39
|
+
1. Preflight: `npx fimo whoami`. If it fails, STOP and ask the user to run
|
|
40
|
+
`fimo login` — do not investigate credentials or probe backends.
|
|
41
|
+
2. Run `npx fimo migrate`. Non-interactive shells are the normal agent case:
|
|
42
|
+
it scans, wires, captures the render baseline, applies the safe transforms
|
|
43
|
+
(codemod), seeds staged labels, imports env keys, and detects collections
|
|
44
|
+
and external data sources. Recover mechanical failures yourself (missing
|
|
45
|
+
install, pnpm `minimumReleaseAgeExclude`, broken dev script) and re-run.
|
|
46
|
+
3. Read the output facts and `.fimo/migration/manifest.json` →
|
|
47
|
+
`wrap.dataSources`: entries marked `decidedBy: "default"` are USER
|
|
48
|
+
decisions that could not be asked in your shell. Ask the user in your chat
|
|
49
|
+
NOW — before any wrapping work (one question per host: keep live, or
|
|
50
|
+
ingest into Fimo?), update the manifest (`decision`, `decidedBy: "user"`),
|
|
51
|
+
and re-run `npx fimo migrate` if anything changed (idempotent).
|
|
52
|
+
4. Execute `.fimo/migration/wrap/agent-prompt.md`: the judgment items
|
|
53
|
+
(attributes, next/image, formatted text), the detected collection
|
|
54
|
+
candidates, and any user-approved ingestion. Collection candidates are
|
|
55
|
+
CLASSIFIED before anything is created: navigation links, style-bearing
|
|
56
|
+
lists, page furniture, and decorative imagery are NOT collections — ask
|
|
57
|
+
the user one batched question (candidate list + your recommendation),
|
|
58
|
+
keep-in-code candidates get their strings wrapped with `t()` (the array
|
|
59
|
+
stays), and only user-confirmed content lists become Fimo collections.
|
|
60
|
+
Candidates the scan annotated with REFERENCES (field values pointing at
|
|
61
|
+
another candidate's slugs/names) migrate with `reference` fields —
|
|
62
|
+
`{ "type": "reference", "target": "<Uid>" }`, `"many": true` for arrays,
|
|
63
|
+
`targets: [...]` for genuinely mixed slots — never as plain strings, and
|
|
64
|
+
their entries are created in dependency order (targets first, then
|
|
65
|
+
referencing entries carrying the recorded documentIds).
|
|
66
|
+
NAMING STANDARD (this is the judgment the whole flow exists for — hold
|
|
67
|
+
the bar): collection Uids are SINGULAR PascalCase DOMAIN terms — what the
|
|
68
|
+
site's owner would call one item — never the source variable or file name
|
|
69
|
+
when a better domain word exists (a `posts.json` of episode notes is
|
|
70
|
+
`Episode`, not `Post`; `items` rendered as staff cards is `TeamMember`).
|
|
71
|
+
Field names stay camelCase and faithful to the source unless the source
|
|
72
|
+
name is meaningless. Machine drafts under
|
|
73
|
+
`.fimo/migration/schema-drafts/` carry PROVISIONAL names precisely so you
|
|
74
|
+
rename them. Adopt them in ONE command:
|
|
75
|
+
`npx fimo schemas adopt-drafts --rename "Prov=Final,…" --drop "Junk,…"`
|
|
76
|
+
(copies kept drafts to src/schemas, rewrites reference targets through
|
|
77
|
+
the renames, renames the staged rows files in step, and pushes in
|
|
78
|
+
dependency order). Each draft carries `source`, `rowCount`, and a
|
|
79
|
+
`sample` row — classify and name from the drafts ALONE, without opening
|
|
80
|
+
the source data files. SEEDING is then ONE command for everything:
|
|
81
|
+
`npx fimo migrate seed`
|
|
82
|
+
— it seeds every `.fimo/migration/rows/*.rows.json` in
|
|
83
|
+
reference-dependency order (targets first, automatically, chunked at
|
|
84
|
+
1000 rows/request); the staged rows are already transformed (media
|
|
85
|
+
envelopes, richtext docs, dates) and the SERVER resolves reference
|
|
86
|
+
source values to documentIds, reporting per-field resolved/dangling
|
|
87
|
+
counts. Do not write mapping scripts, do not seed staged types
|
|
88
|
+
one-by-one, do not re-transform from the source files. PAGE REWIRING is
|
|
89
|
+
also mechanical where the shape is safe (Next app router): `fimo migrate`
|
|
90
|
+
switches pages rendering a staged collection to
|
|
91
|
+
`wrapCollection('<Uid>', sourceRows)` — a Fimo overlay onto the retained
|
|
92
|
+
source rows (per-field type-matched fallback, source order), in-code
|
|
93
|
+
arrays extracted to `src/data/*.json` first. `adopt-drafts` renames the
|
|
94
|
+
call-site uids in step. Only pages listed with a bail reason in the
|
|
95
|
+
migrate warnings need hand wiring — reuse the same `wrapCollection`
|
|
96
|
+
pattern there. Your FINAL REPORT must end with the naming table: every
|
|
97
|
+
collection Uid (with the source it came from) and every reference field
|
|
98
|
+
with its target type(s) and cardinality (single / many / polymorphic).
|
|
99
|
+
DANGLING references (source values pointing at targets that do not
|
|
100
|
+
exist) are handled at TWO layers: in the DATABASE store them null/empty
|
|
101
|
+
and document them in the manifest (`wrap.unresolvedReferences`) — never
|
|
102
|
+
invent placeholder targets; at RENDER time fall back per-field to the
|
|
103
|
+
raw source value (the retained fallback array's slug/string) whenever
|
|
104
|
+
the Fimo reference is null, so the page shows exactly what the source
|
|
105
|
+
site showed and render parity holds. Honest data AND honest rendering
|
|
106
|
+
are not in tension.
|
|
107
|
+
This deliberately differs from `content.md`'s rebuild-path rule ("prefer
|
|
108
|
+
modeling as a collection"): in wrap mode the user's code stays primary —
|
|
109
|
+
the rebuild rule does NOT apply here.
|
|
110
|
+
On simple sites the machine may leave NOTHING to do: the regenerated
|
|
111
|
+
prompt then says so explicitly ("already done by the machine") — your job
|
|
112
|
+
collapses to running the check and reporting. Never invent work the
|
|
113
|
+
prompt does not list.
|
|
114
|
+
When you start the dev server yourself, pin it to a free port (PORT env
|
|
115
|
+
or --port flag) — never the Fimo API's own port (apiUrl in
|
|
116
|
+
.fimo.settings.json; localhost:3000 in local dev). Next and Nuxt default
|
|
117
|
+
to 3000 and silently shadow the API for the whole machine.
|
|
118
|
+
5. Loop `npx fimo migrate wrap --check` after every batch of fixes until it
|
|
119
|
+
exits 0. Make the loop cheap: start the dev server once in the background
|
|
120
|
+
at the beginning of your work and pass it to every check with
|
|
121
|
+
`--server http://localhost:<port>` — the warm server recompiles
|
|
122
|
+
incrementally, so each check costs seconds instead of a cold boot. Never
|
|
123
|
+
recapture the baseline, never add a convenience exemption, never bypass a
|
|
124
|
+
gate. If the same gate fails twice with the same error, stop and report
|
|
125
|
+
honestly.
|
|
126
|
+
6. Report the summary and hand back: deploying is the user's call
|
|
127
|
+
(`npx fimo deploy` — never run it yourself).
|
|
128
|
+
|
|
129
|
+
### W1. Adopt
|
|
130
|
+
|
|
131
|
+
Connect the existing site to a Fimo project. From the site directory:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
fimo init # interactive: detects the framework, confirms the adopt
|
|
135
|
+
fimo init . -y # non-interactive (agents/CI): explicit dir = consent
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Adoption creates the project, writes `fimo-config.json` (`framework` +
|
|
139
|
+
scanned `routes` for the Studio page switcher), `.fimo.settings.json`, the
|
|
140
|
+
framework env flavor (`NEXT_PUBLIC_FIMO_API_URL`,
|
|
141
|
+
`NEXT_PUBLIC_FIMO_PREVIEW_SCRIPT_URL` for Next), wires the `fimo` git remote
|
|
142
|
+
into the existing repo, and pushes the site as-is. No template is copied.
|
|
143
|
+
|
|
144
|
+
If the user's config sets CSP headers with `frame-ancestors`, the Fimo Studio
|
|
145
|
+
origins must be permitted or the preview iframe will be blocked. Framework
|
|
146
|
+
quirks (preview origin allowlists, dev-server flags) are listed under
|
|
147
|
+
"Framework notes" at the end of this document.
|
|
148
|
+
|
|
149
|
+
Sites whose pages fetch external APIs server-side (GitHub, CMSes, analytics)
|
|
150
|
+
hang in the sandbox when their API keys are absent — the page never answers
|
|
151
|
+
and the preview proxy returns 502/504 while the dev server logs
|
|
152
|
+
`Request timed out … Retrying`. `fimo migrate` imports the keys declared in
|
|
153
|
+
the project's `.env`/`.env.local` into the Fimo project automatically
|
|
154
|
+
(sensitive-looking keys as secrets, the rest as variables; existing values
|
|
155
|
+
are never overwritten; Fimo-owned keys are skipped). If that step was
|
|
156
|
+
unavailable (not signed in), push them manually with
|
|
157
|
+
`fimo secrets set <KEY> <value>` / `fimo vars set`, then redeploy.
|
|
158
|
+
|
|
159
|
+
### W2. Scan + automatic wiring
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
fimo migrate # inside an adopted JS codebase this IS the wrap flow
|
|
163
|
+
fimo migrate --apply # + apply the provably-safe transforms automatically
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`--apply` performs the deterministic wraps itself in seconds — plain JSX
|
|
167
|
+
text → `FimoText` (whitespace preserved), `<img src="literal">` →
|
|
168
|
+
`FimoMediaImage`, file links → `FimoFileLink` — with deterministic key
|
|
169
|
+
naming and the generated labels staged AND seeded. The render-parity
|
|
170
|
+
baseline is always captured before any transform. Everything needing
|
|
171
|
+
judgment (attributes, formatted text, `next/image`, collections) is refused
|
|
172
|
+
with a reason and stays in the plan for the agent.
|
|
173
|
+
|
|
174
|
+
(`fimo migrate wrap` is the explicit form; `fimo migrate <url>` remains the
|
|
175
|
+
crawl-and-rebuild path for URL-only migrations.)
|
|
176
|
+
|
|
177
|
+
Writes `.fimo/migration/plan.json` (every unwrapped item with
|
|
178
|
+
`kind`/`file`/`line`/`preview`) and `.fimo/migration/wrap/agent-prompt.md`.
|
|
179
|
+
The scan finds hardcoded JSX text, `img`/`Image`/`video` sources, file links
|
|
180
|
+
(pdf/zip/docx/…), and user-visible attribute strings (`placeholder`, `title`,
|
|
181
|
+
`aria-label`). Content already inside Fimo wrappers or `t()` calls counts as
|
|
182
|
+
covered.
|
|
183
|
+
|
|
184
|
+
The command also performs the deterministic wiring itself: it adds the `fimo`
|
|
185
|
+
dependency (platform-pinned) and, for Next.js, inserts `allowedDevOrigins`
|
|
186
|
+
into the next config when missing. Run the project's package manager install
|
|
187
|
+
afterwards.
|
|
188
|
+
|
|
189
|
+
Known friction: pnpm ≥ 11 ships a `minimumReleaseAge` supply-chain policy
|
|
190
|
+
that refuses packages younger than the cutoff — experimental `fimo` builds
|
|
191
|
+
are minutes old by nature. If install fails with
|
|
192
|
+
`ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`, propose adding to the project's
|
|
193
|
+
`pnpm-workspace.yaml`:
|
|
194
|
+
|
|
195
|
+
```yaml
|
|
196
|
+
minimumReleaseAgeExclude:
|
|
197
|
+
- fimo
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### W3. Wire the layout (one-time)
|
|
201
|
+
|
|
202
|
+
- Root layout (Next.js app router):
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
import { FimoNextProviders, FimoNextScripts } from 'fimo/next';
|
|
206
|
+
import { loadFimoConfig, loadFimoLabels } from 'fimo/next/server';
|
|
207
|
+
|
|
208
|
+
const config = loadFimoConfig();
|
|
209
|
+
const labels = await loadFimoLabels();
|
|
210
|
+
// <head><FimoNextScripts /></head>
|
|
211
|
+
// <body><FimoNextProviders config={config} labels={labels}>{children}</FimoNextProviders></body>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
- React (framework-agnostic) uses `fimo/react`; React Router projects keep
|
|
215
|
+
`fimo/react-router`.
|
|
216
|
+
|
|
217
|
+
RSC rule: the wrapper primitives are client components. Server components may
|
|
218
|
+
render them directly as JSX children; do not call hooks like `useLabels()`
|
|
219
|
+
outside client components (`'use client'`).
|
|
220
|
+
|
|
221
|
+
### W4. Wrap
|
|
222
|
+
|
|
223
|
+
Work through `plan.json` item by item:
|
|
224
|
+
|
|
225
|
+
| Item kind | Wrap with |
|
|
226
|
+
| ----------------------------------- | -------------------------------------------------------------------------------------- |
|
|
227
|
+
| text (plain) | `<FimoText id="…">original text</FimoText>` |
|
|
228
|
+
| text (formatted: strong/em/u/links) | `<FimoRichTextBlock id="…">…original markup…</FimoRichTextBlock>` — marks must survive |
|
|
229
|
+
| attribute | `const { t } = useLabels()` then `placeholder={String(t('key', 'original value'))}` |
|
|
230
|
+
| image | `<FimoMediaImage id="…" src="/original.png" …/>` |
|
|
231
|
+
| video | `<FimoMediaVideo id="…" src="/original.mp4" …/>` |
|
|
232
|
+
| file-link | `<FimoFileLink id="…" href="/original.pdf">…</FimoFileLink>` |
|
|
233
|
+
|
|
234
|
+
Rules:
|
|
235
|
+
|
|
236
|
+
- The original value always stays inline as the fallback (child or prop). Wrap
|
|
237
|
+
fallbacks are deliberate: they keep the site rendering without Fimo
|
|
238
|
+
connectivity. This differs from Fimo-template projects, where inline
|
|
239
|
+
fallbacks are forbidden by lint — do not "fix" wrap fallbacks to match.
|
|
240
|
+
- Key naming: `<route>.<section>.<n>` — `home.hero.title`,
|
|
241
|
+
`pricing.plans.starter.description`. Stable, human-readable, no indexes
|
|
242
|
+
unless the content is genuinely a list.
|
|
243
|
+
- Repeated hardcoded arrays of 3+ structurally identical items (cards, tiles)
|
|
244
|
+
are still collections: model a schema + entries as in
|
|
245
|
+
`references/content.md`, render from `fetchEntries` (`fimo/next/server`).
|
|
246
|
+
Wrapping each array literal string individually is acceptable only as a
|
|
247
|
+
first pass and must be recorded as an unresolved modeling item.
|
|
248
|
+
|
|
249
|
+
### W5. Seed (MANDATORY)
|
|
250
|
+
|
|
251
|
+
Fallbacks are resilience, not storage. Every wrapped item is seeded into Fimo:
|
|
252
|
+
|
|
253
|
+
- Labels: every `FimoText`/`t()` key with its original string via
|
|
254
|
+
`fimo labels set-many --file <json>`.
|
|
255
|
+
- Media/files: `fimo assets upload <path>` per item, then a `WrappedMedia`
|
|
256
|
+
entry per wrapper id (`key` = wrapper id, `image` = the asset) via
|
|
257
|
+
`fimo schemas push` + `fimo entries create` (or, for anything beyond ~20
|
|
258
|
+
rows, `fimo entries create-many <Uid> --file <rows.json>` — a JSON array of
|
|
259
|
+
bare data objects, chunked through the batch endpoint with per-row
|
|
260
|
+
results; never loop single creates over a large collection).
|
|
261
|
+
- Collections with machine-staged rows: `fimo migrate seed` — one command
|
|
262
|
+
seeds every `.fimo/migration/rows/*.rows.json` in reference-dependency
|
|
263
|
+
order at 1000 rows/request. Each file's `references` descriptor has the
|
|
264
|
+
server resolve reference source values (slugs) to documentIds;
|
|
265
|
+
self-references within one file resolve only against rows already
|
|
266
|
+
inserted (earlier chunks), so a fully intra-file cycle surfaces as
|
|
267
|
+
dangling counts — record those in the manifest like any dangling
|
|
268
|
+
reference. (`fimo entries create-many <Uid> --file <rows.json>` remains
|
|
269
|
+
the per-type primitive for rows you build yourself.)
|
|
270
|
+
- Rich text: `WrappedRichText` entries (`key`, `body` = TipTap JSON converted
|
|
271
|
+
from the original markup; bold/italic/underline/link marks preserved).
|
|
272
|
+
|
|
273
|
+
A wrap migration whose labels/entries were never created in Fimo is
|
|
274
|
+
`draft-only`, exactly like a rebuild migration with un-imported seed JSON.
|
|
275
|
+
|
|
276
|
+
### W6. Verify — four machine-enforced gates
|
|
277
|
+
|
|
278
|
+
`fimo migrate wrap --check` is the definition of done. It fails until all
|
|
279
|
+
four gates pass:
|
|
280
|
+
|
|
281
|
+
1. **Coverage** — zero unwrapped items. Deliberate exceptions are recorded in
|
|
282
|
+
the ledger and the gate honors them: add to
|
|
283
|
+
`.fimo/migration/manifest.json` → `wrap.exemptions[]` an entry
|
|
284
|
+
`{ file, kind, preview, reason, status }` where `(file, kind, preview)`
|
|
285
|
+
matches the plan item exactly (a content change invalidates the exemption
|
|
286
|
+
so the item resurfaces).
|
|
287
|
+
2. **Render parity** — the check boots the project's dev server and compares
|
|
288
|
+
every route's rendered text, inline marks, media srcs, and link hrefs
|
|
289
|
+
against the pre-wrap baseline that `fimo migrate` captured
|
|
290
|
+
(`.fimo/migration/parity-baseline.json`). Drift is reported per route and
|
|
291
|
+
block. Dynamic routes are captured by substituting the project's default
|
|
292
|
+
locale for `[locale]`-style params (so an all-`[locale]` i18n site is
|
|
293
|
+
verified, not skipped); routes with content params (`[slug]`, `[id]`) that
|
|
294
|
+
have no safe default still skip — call those out as UNVERIFIED in the
|
|
295
|
+
handoff. In a monorepo, the baseline boot builds the app's workspace deps
|
|
296
|
+
first (root `build` / `turbo run build`) so `next dev` does not die on
|
|
297
|
+
`Cannot find module '@repo/…'`. Run the check right after wrapping (strict,
|
|
298
|
+
pre-seed) and again after seeding. If the baseline is missing, capture one
|
|
299
|
+
from the pre-wrap git state: `git stash && npx fimo migrate snapshot && git stash pop`.
|
|
300
|
+
Text the site renders dynamically BY DESIGN (live clock, visitor counter)
|
|
301
|
+
drifts on every capture: record `wrap.parityIgnores[]`
|
|
302
|
+
`{ pattern, reason }` in the manifest — a full-match regex both sides must
|
|
303
|
+
match to compare equal. A route rendering a keep-live external source
|
|
304
|
+
(`wrap.dataSources` decision `live`) drifts wholesale: record
|
|
305
|
+
`{ route, reason }` instead (counted as unverified, never silently
|
|
306
|
+
clean). Never use either form to hide drift caused by your edit.
|
|
307
|
+
3. **Seeding** — every wrapped key exists in the Fimo database (labels and
|
|
308
|
+
WrappedMedia/WrappedRichText entries), verified via the API. Fallbacks are
|
|
309
|
+
not storage. Labels-decision data files (below) are verified too via
|
|
310
|
+
their recorded `labelPrefix`.
|
|
311
|
+
4. **Wiring** — the root providers are mounted (framework marker file, e.g.
|
|
312
|
+
`FimoNextProviders` in the app-router layout, `FimoSpaProviders` in the
|
|
313
|
+
SPA entry, `FimoRemixProviders` in `app/root`, `fimoLabels` in the
|
|
314
|
+
SvelteKit root `+layout.server`). Without them every wrapped value renders
|
|
315
|
+
its fallback forever and no other gate notices — coverage counts wraps,
|
|
316
|
+
parity sees identical fallbacks, seeding is database-side. `fimo migrate`
|
|
317
|
+
applies this wiring itself for safe shapes (Next.js app router, Vite React
|
|
318
|
+
SPA); the gate enforces the rest. Enforced only once items are wrapped;
|
|
319
|
+
Next pages-router-only projects get a warning, not a failure.
|
|
320
|
+
|
|
321
|
+
**Config-driven sites** (all copy in a data file, templates render only
|
|
322
|
+
expressions): the scanner lists copy-bearing `.json`/`.yml` files and
|
|
323
|
+
markdown groups in the plan (`dataFiles`) and the coverage gate fails until
|
|
324
|
+
each has a decision in the manifest: `wrap.dataFiles[]`
|
|
325
|
+
`{ file, decision: "labels" | "entries" | "ignore", reason, labelPrefix? }`.
|
|
326
|
+
LOCAL CONTENT ALWAYS MIGRATES INTO FIMO — do not ask the user whether to
|
|
327
|
+
migrate local files (only external live sources are a user question).
|
|
328
|
+
`labels` = flat copy documents: seed each prose string as
|
|
329
|
+
`<labelPrefix><json.path>` (arrays by index) and deep-merge label values over
|
|
330
|
+
the parsed file at its server-side loader, keeping the file as fallback;
|
|
331
|
+
`entries` = repeated documents/structures, INCLUDING markdown blog posts:
|
|
332
|
+
the machine stages these as schema drafts + rows (a same-shaped group of ≥2
|
|
333
|
+
md/mdx docs → frontmatter parsed into typed fields, `body` kept verbatim as a
|
|
334
|
+
string so the site's own renderer still works, `slug` from the filename), so
|
|
335
|
+
you adopt them with `adopt-drafts` + `migrate seed` like any collection — no
|
|
336
|
+
hand-authoring, no re-parsing. Record the `entries` decision and rewire the
|
|
337
|
+
reading route to `fetchEntries()` with the files as fallback; `ignore` =
|
|
338
|
+
strictly non-content data (fixtures, geo payloads) — never a deferral.
|
|
339
|
+
GeoJSON/TopoJSON are auto-skipped.
|
|
340
|
+
|
|
341
|
+
Never bypass a failing gate (`--no-parity` / `--skip-seeding` are for the
|
|
342
|
+
owner to decide, not the agent). Additional manual checks:
|
|
343
|
+
|
|
344
|
+
- The site builds and runs **with its own toolchain** (`next build`,
|
|
345
|
+
`npm run dev`, …) — never assume Vite.
|
|
346
|
+
- Diff audit: the migration diff contains only wiring, wrappers, label calls,
|
|
347
|
+
config, and dependency changes.
|
|
348
|
+
- Then `fimo deploy` (allowed in wrap mode: it pushes the preview env and
|
|
349
|
+
boots the sandbox preview — it does not publish). Verify in Fimo Studio that
|
|
350
|
+
the preview renders and Edit mode can select and edit wrapped content, and
|
|
351
|
+
that an edited label round-trips (`fimo labels set <key> "new"` → reload →
|
|
352
|
+
rendered). `fimo publish` / `fimo deploy --publish` remain owner-only.
|
|
353
|
+
|
|
354
|
+
### W7. Unwire the previous CMS — the cutover (when scaffolded)
|
|
355
|
+
|
|
356
|
+
Injecting Fimo is only **half** a migration. If a CMS was scaffolded (W2/W5),
|
|
357
|
+
the site now READS example content from Fimo but is still **wired to the old
|
|
358
|
+
CMS**: the generated Fimo adapter falls back to it, the SDK/client is still
|
|
359
|
+
imported, and the CMS env is still present. The migration is not done until a
|
|
360
|
+
plain `pnpm dev` runs **purely on Fimo, with zero requests to the old CMS**.
|
|
361
|
+
That cutover is the "wow" — deliver it.
|
|
362
|
+
|
|
363
|
+
This phase is the agent's: every codebase talks to its CMS differently (bare
|
|
364
|
+
`fetch`, an SDK client, axios, GraphQL, RSC loaders, image hosts), so the
|
|
365
|
+
replacement needs judgment. The machine hands you the worklist; you do the work.
|
|
366
|
+
|
|
367
|
+
1. **Read the worklist.** `npx fimo migrate cutover` lists every remaining
|
|
368
|
+
coupling — SDK/client/type deps, source lines that reach the CMS (env /
|
|
369
|
+
content-type IDs / SDK import), and leftover env keys. The generated agent
|
|
370
|
+
prompt embeds the same list under **Unwire <CMS>**.
|
|
371
|
+
2. **Replace the data-access layer.** Prefer rewriting the CMS **client module**
|
|
372
|
+
(the one file that instantiates the SDK / holds the fetch helpers) into a
|
|
373
|
+
Fimo-backed adapter exposing the **same interface**, so every caller is fixed
|
|
374
|
+
by a single change. Read from Fimo with `fetchEntries` (`fimo/<framework>/server`).
|
|
375
|
+
3. **Sever the fallthrough.** The generated Fimo adapter falls back to the CMS
|
|
376
|
+
for unmapped reads — a scaffold crutch. Once the client is Fimo-backed, drop
|
|
377
|
+
the fallthrough so an unmapped read fails loudly, never silently hits the CMS.
|
|
378
|
+
4. **Remove the coupling.** Delete the CMS SDK/client/type dependencies and the
|
|
379
|
+
base-URL / token env, and fix any standalone routing the CMS handled (e.g. a
|
|
380
|
+
`/` → `/[locale]` redirect its middleware provided).
|
|
381
|
+
5. **Verify — the cutover gate.** `npx fimo migrate cutover --check` must report
|
|
382
|
+
a **clean** cutover (0 couplings). Then `pnpm dev` and confirm the network
|
|
383
|
+
tab shows **zero** requests to the old CMS. Record the cutover in the manifest.
|
|
384
|
+
|
|
385
|
+
Detection keys on actual CMS references, not filenames — a CMS client module you
|
|
386
|
+
rewrote to call Fimo reads as clean. Keep-live sites (the user chose NOT to
|
|
387
|
+
scaffold) skip this phase: the CMS stays the source of truth.
|
|
388
|
+
|
|
389
|
+
## Manifest
|
|
390
|
+
|
|
391
|
+
Record wrap mode in the canonical ledger (`references/manifest.md`): set
|
|
392
|
+
`mode: "wrap"` and fill the `wrap` block (framework, coverage counts, seeded
|
|
393
|
+
counts, wiring status). Routes/media/forms sections apply as usual — wrap mode
|
|
394
|
+
changes how content becomes editable, not the accounting obligations.
|
|
395
|
+
|
|
396
|
+
## Framework notes
|
|
397
|
+
|
|
398
|
+
One short block per wrappable framework. Add a block when the CLI gains a
|
|
399
|
+
framework — nothing above this section should name a specific framework.
|
|
400
|
+
|
|
401
|
+
### Next.js
|
|
402
|
+
|
|
403
|
+
- `fimo migrate` inserts `allowedDevOrigins: ['*.preview.fimo.ai']` into the
|
|
404
|
+
next config (named `nextConfig` bindings, `export default {` literals, and
|
|
405
|
+
`module.exports = {`); without it the sandbox preview serves a black iframe
|
|
406
|
+
with failing HMR websockets.
|
|
407
|
+
- `fimo migrate` also wires the app-router ROOT LAYOUT itself for safe shapes
|
|
408
|
+
(one default-exported function returning `<html>…<body>…{children}`):
|
|
409
|
+
imports, async, loader calls, `<FimoNextScripts />` in head, `{children}`
|
|
410
|
+
wrapped in `<FimoNextProviders>`. When it bails (unusual layout), the agent
|
|
411
|
+
prompt's section 0 carries the recipe and the bail reason; pages-router
|
|
412
|
+
projects (`pages/_app`) are always manual and only WARN in the wiring gate.
|
|
413
|
+
- Env flavor: `NEXT_PUBLIC_FIMO_API_URL`, `NEXT_PUBLIC_FIMO_PREVIEW_SCRIPT_URL`.
|
|
414
|
+
- Server components cannot call `useLabels()`: use `loadFimoT()` from
|
|
415
|
+
`fimo/next/server` for attribute strings.
|
|
416
|
+
- `next dev` rejects an unknown `--host` flag (fimopm only passes it to
|
|
417
|
+
Vite-family dev servers).
|
|
418
|
+
|
|
419
|
+
### Remix (v2)
|
|
420
|
+
|
|
421
|
+
- New Remix apps no longer exist (`create-remix` redirects to
|
|
422
|
+
create-react-router): this adapter targets the EXISTING remix-vite v2
|
|
423
|
+
fleet. Classic-compiler (`remix dev`) apps predate vite and are not
|
|
424
|
+
supported by the parity capture.
|
|
425
|
+
- The JSX codemod runs here (React guaranteed): `--apply` wraps plain text,
|
|
426
|
+
imgs and file links with `fimo/remix` imports automatically.
|
|
427
|
+
- Root wiring: a `loader` in `app/root.tsx` returns
|
|
428
|
+
`{ fimoConfig: loadFimoConfig(), fimoLabels: await loadFimoLabels() }`
|
|
429
|
+
(from `fimo/remix/server`); the `Layout` reads it with
|
|
430
|
+
`useRouteLoaderData<typeof loader>("root")` — GUARD the null case (error
|
|
431
|
+
boundaries render Layout without loader data) — and mounts
|
|
432
|
+
`<FimoRemixScripts />` in head plus
|
|
433
|
+
`<FimoRemixProviders config={…} labels={…}>{children}</FimoRemixProviders>`.
|
|
434
|
+
|
|
435
|
+
- React: the full wrapper set applies (`fimo/remix` re-exports it) plus
|
|
436
|
+
`FimoRemixProviders`/`FimoRemixScripts` for `app/root.tsx`.
|
|
437
|
+
- Env flavor: `FIMO_API_URL`, `FIMO_PREVIEW_SCRIPT_URL` (server-read).
|
|
438
|
+
- Routes: flat files under `app/routes` (dots are slashes, `$param` dynamic).
|
|
439
|
+
- Modern Remix dev runs on Vite (`--host` handled); classic `remix dev` honors HOST.
|
|
440
|
+
|
|
441
|
+
### Astro
|
|
442
|
+
|
|
443
|
+
- Server-loader + DOM-attrs based (no React needed): in frontmatter
|
|
444
|
+
`const t = await loadFimoT()` (from `fimo/astro/server`), render
|
|
445
|
+
`{t('key', 'fallback')}` with `{...fimoLabelAttrs('key')}` on the element.
|
|
446
|
+
- **Islands are NOT React by default** (Solid, Svelte, Preact all ship as
|
|
447
|
+
`.tsx`/`.svelte`): never import `fimo/next` wrappers there — the JSX
|
|
448
|
+
runtime differs and the build breaks. The `--apply` codemod skips JSX in
|
|
449
|
+
Astro projects for this reason. Recipe for a mounted island: the parent
|
|
450
|
+
`.astro` loads `t` server-side and passes label values as props; the
|
|
451
|
+
island renders the prop with a literal
|
|
452
|
+
`data-fimo-source="__labels.<locale>.<key>.value"` attribute (no import
|
|
453
|
+
needed — it is just a DOM attribute).
|
|
454
|
+
- Mixed text nodes (`Hi, I'm <b>Name</b>, a developer…`) wrap per text node:
|
|
455
|
+
each segment gets its own `<span {...fimoLabelAttrs(...)}>{t(...)}</span>`
|
|
456
|
+
(or the attrs go on the existing `<b>`/`<a>`), punctuation stays in the
|
|
457
|
+
segment it belongs to.
|
|
458
|
+
- Playground/demo components not referenced by any route: exempt them
|
|
459
|
+
(`wrap.exemptions`, reason "dead template code") instead of fabricating
|
|
460
|
+
editability for UI that never renders.
|
|
461
|
+
- Config-driven Astro themes (all copy in `src/data/*.json`) surface as
|
|
462
|
+
`dataFiles` in the plan — follow the data-file triage in W6.
|
|
463
|
+
- Env flavor: `PUBLIC_FIMO_API_URL`, `PUBLIC_FIMO_PREVIEW_SCRIPT_URL`.
|
|
464
|
+
- Routes: file-based under `src/pages` (`.astro`/`.md`/`.mdx`).
|
|
465
|
+
- `astro dev` needs `--host` (fimopm passes it); verify the preview origin
|
|
466
|
+
allowlist on the first real dogfood.
|
|
467
|
+
- Scanner coverage: `.astro` templates are text-scanned — frontmatter,
|
|
468
|
+
`<script>`/`<style>` bodies, `<title>` head metadata, and nested
|
|
469
|
+
`{expressions}` are excluded; what remains is real copy.
|
|
470
|
+
- `--apply` auto-wraps PLAIN TEXT NODES in `.astro` templates (injects the
|
|
471
|
+
`loadFimoT` head into the frontmatter, wraps `{t('key', 'fallback')}`,
|
|
472
|
+
stages + seeds the labels). Files that already bind their own `t` (i18n
|
|
473
|
+
libraries) are left whole. Attributes, media, mixed markup, and
|
|
474
|
+
collections stay agent work via the recipe above.
|
|
475
|
+
- pnpm >= 11 hard-fails installs on unapproved build scripts; adopt writes
|
|
476
|
+
`allowBuilds: { fimo: true }` into `pnpm-workspace.yaml` (the project's
|
|
477
|
+
own blocked deps — esbuild, sharp — are the owner's existing approvals).
|
|
478
|
+
|
|
479
|
+
### Nuxt (3+)
|
|
480
|
+
|
|
481
|
+
- Composable-based (SFCs are UNIVERSAL — they hydrate client-side, so never
|
|
482
|
+
import `fimo/nuxt/server` in a component; the nuxtship dogfood proved it
|
|
483
|
+
breaks `nuxt build` three different ways). In `<script setup>`:
|
|
484
|
+
|
|
485
|
+
```vue
|
|
486
|
+
<script setup>
|
|
487
|
+
import { useFimoT, fimoLabelAttrs } from 'fimo/nuxt';
|
|
488
|
+
const t = await useFimoT();
|
|
489
|
+
</script>
|
|
490
|
+
<template>
|
|
491
|
+
<h1 v-bind="fimoLabelAttrs('hero.title')">{{ t('hero.title', 'Fallback') }}</h1>
|
|
492
|
+
</template>
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
`useFimoT` fetches on the server only and hands the dictionary to the
|
|
496
|
+
client through the Nuxt payload (hydration-safe, one fetch per page).
|
|
497
|
+
`fimo/nuxt/server` remains for nitro server routes only.
|
|
498
|
+
|
|
499
|
+
- In-component arrays (pricing tiers, feature lists): keep the array, wrap
|
|
500
|
+
its copy strings with `t('key', 'fallback')` inside the array literal —
|
|
501
|
+
`t` is available above them in the same `<script setup>`.
|
|
502
|
+
- Env flavor: `NUXT_PUBLIC_FIMO_API_URL`, `NUXT_PUBLIC_FIMO_PREVIEW_SCRIPT_URL`.
|
|
503
|
+
- Routes: file-based under `pages/`. `nuxt dev` needs `--host`.
|
|
504
|
+
- Scanner coverage: `.vue` templates are text-scanned (template region only,
|
|
505
|
+
inline-svg `<title>` excluded); `<script setup>` arrays are
|
|
506
|
+
collection-scanned (nested copy like `button.text` counts).
|
|
507
|
+
- `--apply` auto-wraps PLAIN TEXT NODES in `.vue` templates (injects the
|
|
508
|
+
`useFimoT` head into `<script setup>`, wraps `{{ t('key', 'fallback') }}`,
|
|
509
|
+
stages + seeds the labels). Options-API files and files that bind their
|
|
510
|
+
own `t` (vue-i18n) are left whole for the agent; attributes, media, and
|
|
511
|
+
collections stay agent work.
|
|
512
|
+
- Parity capture: nuxi answers 503 while Vite builds — the boot probe waits
|
|
513
|
+
for a sub-500 response, so slow first compiles are fine.
|
|
514
|
+
|
|
515
|
+
### SvelteKit
|
|
516
|
+
|
|
517
|
+
- Load labels ONCE in `src/routes/+layout.server.js` (SvelteKit's own
|
|
518
|
+
server-only convention — no client-bundle risk):
|
|
519
|
+
|
|
520
|
+
```js
|
|
521
|
+
import { loadFimoLabels } from 'fimo/svelte/server';
|
|
522
|
+
export const load = async () => {
|
|
523
|
+
const bundle = await loadFimoLabels();
|
|
524
|
+
return { fimoLabels: bundle.dictionaries[bundle.defaultLocale] ?? {} };
|
|
525
|
+
};
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
Components build `t` locally from client-safe `fimo/svelte`:
|
|
529
|
+
pages/layouts via the data prop (`let { data } = $props()` in Svelte 5),
|
|
530
|
+
deep components via the page store (`$page.data.fimoLabels` /
|
|
531
|
+
`page.data` from `$app/state`):
|
|
532
|
+
|
|
533
|
+
```svelte
|
|
534
|
+
<script>
|
|
535
|
+
import { makeFimoT, fimoLabelAttrs } from 'fimo/svelte';
|
|
536
|
+
let { data } = $props();
|
|
537
|
+
const t = makeFimoT(data.fimoLabels);
|
|
538
|
+
</script>
|
|
539
|
+
<h1 {...fimoLabelAttrs('hero.title')}>{t('hero.title', 'Fallback')}</h1>
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Never import `fimo/svelte/server` in a `.svelte` file (components
|
|
543
|
+
hydrate; the server barrel reads fs).
|
|
544
|
+
Build `t` with the mode-agnostic form
|
|
545
|
+
`const t = makeFimoT($page.data.fimoLabels);` — a plain store read,
|
|
546
|
+
valid in BOTH legacy and runes components (labels are fixed per render,
|
|
547
|
+
no reactivity needed). Do NOT use `$derived(...)` (a single rune flips
|
|
548
|
+
the whole component to runes mode and any existing `$:` in it 500s) and
|
|
549
|
+
do NOT use `$: t = ...` (reactive statements run after init, so arrays
|
|
550
|
+
built at init see `t` undefined). In files with a
|
|
551
|
+
`<script lang="ts" module>` block, the import goes in the INSTANCE
|
|
552
|
+
script, never the module script (`$page` is illegal there).
|
|
553
|
+
|
|
554
|
+
- mdsvex blogs: `.md` post copy is markdown-ingestion territory (Tier 1b),
|
|
555
|
+
not wrap items; `+page.md` routes still discover and parity-capture.
|
|
556
|
+
- Env flavor: `PUBLIC_FIMO_API_URL` (SvelteKit's public prefix).
|
|
557
|
+
- Routes: `src/routes/**/+page.svelte` (+ `+page.md`); `(groups)` are
|
|
558
|
+
layout-only.
|
|
559
|
+
- Vite dev server (`--host` handled). `.svelte` templates are text-scanned.
|
|
560
|
+
- `--apply` auto-wraps PLAIN TEXT NODES in `.svelte` files (injects the
|
|
561
|
+
mode-agnostic head above into the instance script, wraps
|
|
562
|
+
`{t('key', 'fallback')}`, stages + seeds the labels) and writes
|
|
563
|
+
`src/routes/+layout.server.js` when the project has none. An EXISTING
|
|
564
|
+
root layout load is not touched — merging `fimoLabels` into it is your
|
|
565
|
+
work. Files binding their own `t` are left whole; attributes, media, and
|
|
566
|
+
collections stay agent work.
|
|
567
|
+
- Repo pitfalls seen in the wild: a checked-in FOREIGN lockfile (pnpm-lock
|
|
568
|
+
in an npm project) makes the capture spawn the wrong package manager —
|
|
569
|
+
align on one lockfile; a `master` default branch maps to a nonexistent
|
|
570
|
+
Fimo env — rename to `main` (or create the env) before data commands.
|
|
571
|
+
|
|
572
|
+
### Vite + React (SPA)
|
|
573
|
+
|
|
574
|
+
- Detection: a `vite` dependency plus `react` (no meta-framework). The react
|
|
575
|
+
dependency pins the JSX runtime, so the full JSX codemod runs here —
|
|
576
|
+
`--apply` wraps plain text, imgs, and file links with `fimo/react` imports.
|
|
577
|
+
Bare Vite without react (Solid, Preact, lit) stays agent work.
|
|
578
|
+
- One-time wiring: `fimo migrate` wraps the root render itself for the
|
|
579
|
+
mainstream entry shape (`createRoot(…).render(<JSX/>)` in `src/main.*` /
|
|
580
|
+
`src/index.*`). When it bails, mount the SPA providers yourself once around
|
|
581
|
+
the app root — there is no server pass; labels are fetched in the browser
|
|
582
|
+
and everything renders inline fallbacks until they resolve:
|
|
583
|
+
|
|
584
|
+
```tsx
|
|
585
|
+
import { FimoSpaProviders } from 'fimo/react';
|
|
586
|
+
import config from '../fimo-config.json';
|
|
587
|
+
|
|
588
|
+
<FimoSpaProviders
|
|
589
|
+
config={config}
|
|
590
|
+
apiUrl={import.meta.env.VITE_API_URL}
|
|
591
|
+
previewScriptUrl={import.meta.env.DEV ? import.meta.env.VITE_FIMO_PREVIEW_SCRIPT_URL : undefined}
|
|
592
|
+
>
|
|
593
|
+
<App />
|
|
594
|
+
</FimoSpaProviders>;
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
- Routes: no file convention — the scan reads LITERAL ABSOLUTE paths from
|
|
598
|
+
react-router (`<Route path="/x">` and `createBrowserRouter([{ path: '/x' }])`)
|
|
599
|
+
into the fimo-config route registry. Relative child paths, `index` routes,
|
|
600
|
+
and `*` wildcards are not resolved: add those to `fimo-config.json` routes
|
|
601
|
+
yourself (scanned routes only ever ADD, never overwrite).
|
|
602
|
+
- Parity caveat: a CSR dev server answers every route with the same HTML
|
|
603
|
+
shell, so the parity gate compares shells and passes vacuously. Coverage
|
|
604
|
+
and seeding carry the real signal; verify rendering in the browser.
|
|
605
|
+
- Env flavor: `VITE_API_URL`, `VITE_FIMO_PREVIEW_SCRIPT_URL` (Vite inlines
|
|
606
|
+
only `VITE_`-prefixed vars into client code).
|
|
607
|
+
|
|
608
|
+
### Vue (Vite SPA)
|
|
609
|
+
|
|
610
|
+
- v1: DOM-attrs + client-side label hydration; routes come from fimo-config
|
|
611
|
+
(no file convention to discover).
|
|
612
|
+
|
|
613
|
+
### Vite / React Router (native template)
|
|
614
|
+
|
|
615
|
+
- The template pipeline (virtual modules, `t()` extraction) predates wrap mode
|
|
616
|
+
and stays the canonical path for Fimo-created projects; wrap mode is for
|
|
617
|
+
adopted codebases.
|
|
@@ -6,9 +6,9 @@ description: >-
|
|
|
6
6
|
Triggers: "in Fimo Studio", "in the dashboard", "in the web app",
|
|
7
7
|
"how do I X in the UI", or screenshots of the dashboard. Topics
|
|
8
8
|
covered: dashboard content and CMS, publishing from the dashboard,
|
|
9
|
-
dashboard SEO/domain settings, visual editing, version
|
|
10
|
-
dashboard sharing/billing, and dashboard chat. Never describe
|
|
11
|
-
locations, buttons, or panels from memory — always read the relevant
|
|
9
|
+
dashboard SEO/domain settings, outbound webhooks, visual editing, version
|
|
10
|
+
history UI, dashboard sharing/billing, and dashboard chat. Never describe
|
|
11
|
+
UI locations, buttons, or panels from memory — always read the relevant
|
|
12
12
|
reference file first.
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -37,6 +37,7 @@ Read the relevant reference file when the user's question matches a topic.
|
|
|
37
37
|
| AI Chat | references/ai-chat.md | "What can the AI do?", "How do I give context?" |
|
|
38
38
|
| Code Editor | references/code-editor.md | "How do I edit code?", "Where are my files?" |
|
|
39
39
|
| SEO Settings | references/seo-settings.md | "How do I set up SEO?", "Favicon, title, share image" |
|
|
40
|
+
| Webhooks | references/webhooks.md | "React to forms", "Send events to another service" |
|
|
40
41
|
| Preview & Responsive | references/preview-and-responsive.md | "How does it look on mobile?", "How do I test sizes?" |
|
|
41
42
|
| Visual Editing | references/visual-editing.md | "Can I edit visually?", "How do I change colors?" |
|
|
42
43
|
| Version History | references/version-history.md | "How do I undo?", "How do I go back?" |
|
|
@@ -53,6 +54,7 @@ Read the relevant reference file when the user's question matches a topic.
|
|
|
53
54
|
| Custom domains | Publishing (must publish first), Billing (premium required) |
|
|
54
55
|
| Adding images | Media Library, AI Chat, Edit Mode |
|
|
55
56
|
| Content/CMS | AI Chat, Media Library |
|
|
57
|
+
| Webhooks | Project secrets, Forms, Publishing, Agents |
|
|
56
58
|
| Visual changes | Edit Mode (quick tweaks), AI Chat (bigger changes), Code Editor (full control) |
|
|
57
59
|
| Something went wrong | Version History, AI Chat |
|
|
58
60
|
| Working with others | Sharing, Collaboration |
|