fimo 0.8.0 → 0.9.0-experimental.10

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 (218) hide show
  1. package/assets/agent-templates/content-translator/scripts/write-locale-files.ts +66 -0
  2. package/assets/agents-starter/claude/settings.json +19 -0
  3. package/assets/content-templates/hooks-template.eta +4 -2
  4. package/assets/content-templates/types-template.eta +67 -1
  5. package/assets/skills/fimo/SKILL.md +1 -1
  6. package/assets/skills/fimo/references/content.md +86 -15
  7. package/assets/skills/fimo/references/translations.md +75 -0
  8. package/assets/skills/fimo-cli/SKILL.md +6 -2
  9. package/assets/skills/fimo-cli/references/content.md +61 -2
  10. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +20 -4
  11. package/assets/skills/fimo-cli/references/integrations.md +5 -1
  12. package/assets/skills/fimo-cli/references/webhooks.md +162 -0
  13. package/assets/skills/fimo-migration/SKILL.md +24 -2
  14. package/assets/skills/fimo-migration/references/content.md +24 -0
  15. package/assets/skills/fimo-migration/references/manifest.md +46 -0
  16. package/assets/skills/fimo-migration/references/pages.md +234 -0
  17. package/assets/skills/fimo-migration/references/qa.md +24 -2
  18. package/assets/skills/fimo-migration/references/workflow.md +12 -1
  19. package/assets/skills/fimo-migration/references/wrap.md +662 -0
  20. package/assets/skills/fimo-studio/SKILL.md +5 -3
  21. package/assets/skills/fimo-studio/references/cms.md +9 -1
  22. package/assets/skills/fimo-studio/references/visual-editing.md +5 -3
  23. package/assets/skills/fimo-studio/references/webhooks.md +42 -0
  24. package/dist/build/vite/plugins/translations.d.ts +2 -8
  25. package/dist/build/vite/plugins/translations.js +31 -131
  26. package/dist/cli/bundle.json +1 -1
  27. package/dist/cli/index.js +1337 -189
  28. package/dist/runtime/app/FimoProviders.d.ts +1 -11
  29. package/dist/runtime/app/FimoProviders.js +31 -30
  30. package/dist/runtime/astro/index.d.ts +2 -0
  31. package/dist/runtime/astro/index.js +3 -0
  32. package/dist/runtime/astro/server.d.ts +3 -0
  33. package/dist/runtime/astro/server.js +6 -0
  34. package/dist/runtime/content/client/internal.js +1 -0
  35. package/dist/runtime/content/client/types.d.ts +16 -0
  36. package/dist/runtime/core/BuiltWithBadge.d.ts +2 -0
  37. package/dist/runtime/core/BuiltWithBadge.js +68 -0
  38. package/dist/runtime/i18n/FimoLocaleContext.js +1 -0
  39. package/dist/runtime/next/FimoNextProviders.d.ts +24 -0
  40. package/dist/runtime/next/FimoNextProviders.js +20 -0
  41. package/dist/runtime/next/FimoNextScripts.d.ts +10 -0
  42. package/dist/runtime/next/FimoNextScripts.js +19 -0
  43. package/dist/runtime/next/index.d.ts +14 -0
  44. package/dist/runtime/next/index.js +14 -0
  45. package/dist/runtime/next/server.d.ts +2 -0
  46. package/dist/runtime/next/server.js +4 -0
  47. package/dist/runtime/nuxt/composables.d.ts +9 -0
  48. package/dist/runtime/nuxt/composables.js +57 -0
  49. package/dist/runtime/nuxt/index.d.ts +3 -0
  50. package/dist/runtime/nuxt/index.js +6 -0
  51. package/dist/runtime/nuxt/server.d.ts +3 -0
  52. package/dist/runtime/nuxt/server.js +6 -0
  53. package/dist/runtime/primitives/components/RichText.d.ts +5 -1
  54. package/dist/runtime/primitives/components/RichText.js +2 -2
  55. package/dist/runtime/primitives/labels-hook.d.ts +33 -0
  56. package/dist/runtime/primitives/labels-hook.js +41 -0
  57. package/dist/runtime/primitives/labels-store.d.ts +12 -0
  58. package/dist/runtime/primitives/labels-store.js +60 -0
  59. package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +5 -3
  60. package/dist/runtime/primitives/lib/useFimoLiveValue.js +11 -4
  61. package/dist/runtime/primitives/translations.d.ts +1 -27
  62. package/dist/runtime/primitives/translations.js +7 -85
  63. package/dist/runtime/react/FimoSpaProviders.d.ts +36 -0
  64. package/dist/runtime/react/FimoSpaProviders.js +122 -0
  65. package/dist/runtime/react/index.d.ts +35 -0
  66. package/dist/runtime/react/index.js +40 -0
  67. package/dist/runtime/react/spa-content-cache.d.ts +38 -0
  68. package/dist/runtime/react/spa-content-cache.js +64 -0
  69. package/dist/runtime/remix/FimoRemixProviders.d.ts +16 -0
  70. package/dist/runtime/remix/FimoRemixProviders.js +12 -0
  71. package/dist/runtime/remix/FimoRemixScripts.d.ts +10 -0
  72. package/dist/runtime/remix/FimoRemixScripts.js +19 -0
  73. package/dist/runtime/remix/index.d.ts +12 -0
  74. package/dist/runtime/remix/index.js +11 -0
  75. package/dist/runtime/remix/server.d.ts +2 -0
  76. package/dist/runtime/remix/server.js +2 -0
  77. package/dist/runtime/seo/neutral.d.ts +22 -0
  78. package/dist/runtime/seo/neutral.js +17 -0
  79. package/dist/runtime/shared/display-routes.d.ts +14 -0
  80. package/dist/runtime/shared/display-routes.js +25 -0
  81. package/dist/runtime/shared/fimo-config.server.d.ts +0 -1
  82. package/dist/runtime/shared/fimo-config.server.js +1 -13
  83. package/dist/runtime/shared/fimo-config.types.d.ts +2 -0
  84. package/dist/runtime/shared/i18n-messages.d.ts +29 -0
  85. package/dist/runtime/shared/i18n-messages.js +79 -0
  86. package/dist/runtime/shared/labels-fetch.pure.d.ts +17 -0
  87. package/dist/runtime/shared/labels-fetch.pure.js +71 -0
  88. package/dist/runtime/shared/labels-fetch.server.d.ts +7 -0
  89. package/dist/runtime/shared/labels-fetch.server.js +97 -0
  90. package/dist/runtime/shared/labels-t.pure.d.ts +2 -0
  91. package/dist/runtime/shared/labels-t.pure.js +10 -0
  92. package/dist/runtime/strapi/client.d.ts +30 -0
  93. package/dist/runtime/strapi/client.js +132 -0
  94. package/dist/runtime/strapi/index.d.ts +5 -0
  95. package/dist/runtime/strapi/index.js +6 -0
  96. package/dist/runtime/strapi/reshape.d.ts +50 -0
  97. package/dist/runtime/strapi/reshape.js +121 -0
  98. package/dist/runtime/svelte/index.d.ts +3 -0
  99. package/dist/runtime/svelte/index.js +7 -0
  100. package/dist/runtime/svelte/server.d.ts +3 -0
  101. package/dist/runtime/svelte/server.js +6 -0
  102. package/dist/runtime/vue/index.d.ts +3 -0
  103. package/dist/runtime/vue/index.js +5 -0
  104. package/dist/runtime/vue/server.d.ts +3 -0
  105. package/dist/runtime/vue/server.js +6 -0
  106. package/dist/runtime/wrapped/FimoFileLink.d.ts +17 -0
  107. package/dist/runtime/wrapped/FimoFileLink.js +19 -0
  108. package/dist/runtime/wrapped/FimoMediaImage.d.ts +14 -0
  109. package/dist/runtime/wrapped/FimoMediaImage.js +20 -0
  110. package/dist/runtime/wrapped/FimoMediaVideo.d.ts +14 -0
  111. package/dist/runtime/wrapped/FimoMediaVideo.js +20 -0
  112. package/dist/runtime/wrapped/FimoRichTextBlock.d.ts +26 -0
  113. package/dist/runtime/wrapped/FimoRichTextBlock.js +22 -0
  114. package/dist/runtime/wrapped/FimoText.d.ts +22 -0
  115. package/dist/runtime/wrapped/FimoText.js +20 -0
  116. package/dist/runtime/wrapped/WrappedContentContext.d.ts +28 -0
  117. package/dist/runtime/wrapped/WrappedContentContext.js +30 -0
  118. package/dist/runtime/wrapped/WrappedProviders.d.ts +33 -0
  119. package/dist/runtime/wrapped/WrappedProviders.js +101 -0
  120. package/dist/runtime/wrapped/content-fetch.pure.d.ts +20 -0
  121. package/dist/runtime/wrapped/content-fetch.pure.js +106 -0
  122. package/dist/runtime/wrapped/dom.d.ts +4 -0
  123. package/dist/runtime/wrapped/dom.js +23 -0
  124. package/dist/runtime/wrapped/server.d.ts +80 -0
  125. package/dist/runtime/wrapped/server.js +207 -0
  126. package/dist/scripts/apply-wrap-templates.d.ts +61 -0
  127. package/dist/scripts/apply-wrap-templates.js +137 -0
  128. package/dist/scripts/apply-wrap.d.ts +73 -0
  129. package/dist/scripts/apply-wrap.js +340 -0
  130. package/dist/scripts/cms/discover.d.ts +2 -0
  131. package/dist/scripts/cms/discover.js +17 -0
  132. package/dist/scripts/cms/example-content.d.ts +33 -0
  133. package/dist/scripts/cms/example-content.js +165 -0
  134. package/dist/scripts/cms/strapi/detect.d.ts +2 -0
  135. package/dist/scripts/cms/strapi/detect.js +186 -0
  136. package/dist/scripts/cms/strapi/index.d.ts +3 -0
  137. package/dist/scripts/cms/strapi/index.js +25 -0
  138. package/dist/scripts/cms/strapi/list-source.d.ts +17 -0
  139. package/dist/scripts/cms/strapi/list-source.js +90 -0
  140. package/dist/scripts/cms/strapi/schema-map.d.ts +9 -0
  141. package/dist/scripts/cms/strapi/schema-map.js +289 -0
  142. package/dist/scripts/cms/strapi/shapes.d.ts +25 -0
  143. package/dist/scripts/cms/strapi/shapes.js +48 -0
  144. package/dist/scripts/cms/strapi/touchpoints.d.ts +31 -0
  145. package/dist/scripts/cms/strapi/touchpoints.js +145 -0
  146. package/dist/scripts/cms/strapi/wire-client.d.ts +15 -0
  147. package/dist/scripts/cms/strapi/wire-client.js +107 -0
  148. package/dist/scripts/cms/strapi/wiring.d.ts +17 -0
  149. package/dist/scripts/cms/strapi/wiring.js +46 -0
  150. package/dist/scripts/cms/types.d.ts +145 -0
  151. package/dist/scripts/cms/types.js +11 -0
  152. package/dist/scripts/detect-framework.d.ts +39 -0
  153. package/dist/scripts/detect-framework.js +139 -0
  154. package/dist/scripts/draft-rows.d.ts +19 -0
  155. package/dist/scripts/draft-rows.js +178 -0
  156. package/dist/scripts/draft-schemas.d.ts +27 -0
  157. package/dist/scripts/draft-schemas.js +247 -0
  158. package/dist/scripts/extract-translations.js +16 -11
  159. package/dist/scripts/frameworks/astro/routes.d.ts +3 -0
  160. package/dist/scripts/frameworks/astro/routes.js +44 -0
  161. package/dist/scripts/frameworks/astro/template-style.d.ts +7 -0
  162. package/dist/scripts/frameworks/astro/template-style.js +19 -0
  163. package/dist/scripts/frameworks/discover.d.ts +83 -0
  164. package/dist/scripts/frameworks/discover.js +288 -0
  165. package/dist/scripts/frameworks/discovered-route.d.ts +9 -0
  166. package/dist/scripts/frameworks/discovered-route.js +17 -0
  167. package/dist/scripts/frameworks/next/rewire.d.ts +43 -0
  168. package/dist/scripts/frameworks/next/rewire.js +282 -0
  169. package/dist/scripts/frameworks/next/routes.d.ts +30 -0
  170. package/dist/scripts/frameworks/next/routes.js +176 -0
  171. package/dist/scripts/frameworks/next/wiring.d.ts +33 -0
  172. package/dist/scripts/frameworks/next/wiring.js +186 -0
  173. package/dist/scripts/frameworks/nuxt/routes.d.ts +3 -0
  174. package/dist/scripts/frameworks/nuxt/routes.js +38 -0
  175. package/dist/scripts/frameworks/nuxt/template-style.d.ts +9 -0
  176. package/dist/scripts/frameworks/nuxt/template-style.js +27 -0
  177. package/dist/scripts/frameworks/remix/routes.d.ts +3 -0
  178. package/dist/scripts/frameworks/remix/routes.js +36 -0
  179. package/dist/scripts/frameworks/support.d.ts +75 -0
  180. package/dist/scripts/frameworks/support.js +165 -0
  181. package/dist/scripts/frameworks/sveltekit/routes.d.ts +3 -0
  182. package/dist/scripts/frameworks/sveltekit/routes.js +35 -0
  183. package/dist/scripts/frameworks/sveltekit/template-style.d.ts +9 -0
  184. package/dist/scripts/frameworks/sveltekit/template-style.js +54 -0
  185. package/dist/scripts/frameworks/vite/routes.d.ts +20 -0
  186. package/dist/scripts/frameworks/vite/routes.js +143 -0
  187. package/dist/scripts/frameworks/vite/wiring.d.ts +22 -0
  188. package/dist/scripts/frameworks/vite/wiring.js +144 -0
  189. package/dist/scripts/i18n-namespace.d.ts +27 -0
  190. package/dist/scripts/i18n-namespace.js +155 -0
  191. package/dist/scripts/lib/humanize.d.ts +14 -0
  192. package/dist/scripts/lib/humanize.js +54 -0
  193. package/dist/scripts/lib/validation-report.d.ts +1 -3
  194. package/dist/scripts/lib/validation-report.js +3 -9
  195. package/dist/scripts/render-parity/capture.d.ts +64 -0
  196. package/dist/scripts/render-parity/capture.js +436 -0
  197. package/dist/scripts/render-parity/compare.d.ts +59 -0
  198. package/dist/scripts/render-parity/compare.js +0 -0
  199. package/dist/scripts/render-parity/normalize-html.d.ts +13 -0
  200. package/dist/scripts/render-parity/normalize-html.js +223 -0
  201. package/dist/scripts/render-parity/types.d.ts +41 -0
  202. package/dist/scripts/render-parity/types.js +1 -0
  203. package/dist/scripts/routes/bindings.d.ts +93 -0
  204. package/dist/scripts/routes/bindings.js +117 -0
  205. package/dist/scripts/routes/label-prefixes.d.ts +49 -0
  206. package/dist/scripts/routes/label-prefixes.js +136 -0
  207. package/dist/scripts/routes/module-resolve.d.ts +20 -0
  208. package/dist/scripts/routes/module-resolve.js +78 -0
  209. package/dist/scripts/routes/page-structure.d.ts +72 -0
  210. package/dist/scripts/routes/page-structure.js +234 -0
  211. package/dist/scripts/scan-wrappable.d.ts +200 -0
  212. package/dist/scripts/scan-wrappable.js +1355 -0
  213. package/dist/scripts/validate-route-metadata.js +11 -0
  214. package/dist/scripts/validate-schemas.js +42 -1
  215. package/package.json +88 -4
  216. package/release.json +2 -2
  217. package/templates/react-router/package.json +1 -1
  218. package/templates/react-router/translations/en.json +1 -0
@@ -0,0 +1,121 @@
1
+ // Native `fimo/strapi` read adapter — the generic reshape from Fimo entries
2
+ // (as `fetchEntries` returns them) into the Strapi-v5 response shape a wrapped
3
+ // Strapi frontend's components read. Value-inspection based, so it is generic:
4
+ // no content-type or field names are hardcoded. Relation POPULATION (turning a
5
+ // reference handle into a nested object) is resolved one level up in the client
6
+ // — this module reshapes a single entry's own field values.
7
+ /** ProseMirror/TipTap doc → plain text (Strapi richtext is a string; string
8
+ * consumers like read-time estimates must never receive an object). */
9
+ function docToText(node) {
10
+ if (!node || typeof node !== 'object') {
11
+ return '';
12
+ }
13
+ const record = node;
14
+ if (typeof record.text === 'string') {
15
+ return record.text;
16
+ }
17
+ if (Array.isArray(record.content)) {
18
+ return record.content.map(docToText).join(' ').trim();
19
+ }
20
+ return '';
21
+ }
22
+ function isRichTextDoc(value) {
23
+ return Boolean(value) && typeof value === 'object' && value.type === 'doc';
24
+ }
25
+ /** A Fimo media value (seeded/loaded as `{ url, alt, width, height, … }`). */
26
+ function isMedia(value) {
27
+ return (Boolean(value) &&
28
+ typeof value === 'object' &&
29
+ !Array.isArray(value) &&
30
+ typeof value.url === 'string');
31
+ }
32
+ function reshapeMedia(value) {
33
+ return {
34
+ url: value.url,
35
+ alternativeText: value.alt ?? value.alternativeText ?? null,
36
+ ...(typeof value.width === 'number' ? { width: value.width } : {}),
37
+ ...(typeof value.height === 'number' ? { height: value.height } : {}),
38
+ ...(typeof value.name === 'string' ? { name: value.name } : {}),
39
+ ...(typeof value.mime === 'string' ? { mime: value.mime } : {}),
40
+ };
41
+ }
42
+ function reshapeValue(value) {
43
+ if (isRichTextDoc(value)) {
44
+ return docToText(value);
45
+ }
46
+ if (isMedia(value)) {
47
+ return reshapeMedia(value);
48
+ }
49
+ return value; // scalars, arrays, reference handles pass through
50
+ }
51
+ /** Reshape one block item: drop Fimo-internal `_key`/`_type` (exposing `_key` as
52
+ * Strapi's `id`), keep everything else — `__component` passes through, nested
53
+ * structural fields recurse per the manifest, leaves are value-inspected. */
54
+ function reshapeBlockItem(item, shape) {
55
+ if (!item || typeof item !== 'object' || Array.isArray(item)) {
56
+ return {};
57
+ }
58
+ const record = item;
59
+ const nested = shape.variants ? (shape.variants[String(record._type)] ?? {}) : (shape.fields ?? {});
60
+ const out = {};
61
+ if (typeof record._key === 'string') {
62
+ out.id = record._key;
63
+ }
64
+ for (const [key, value] of Object.entries(record)) {
65
+ if (key === '_key' || key === '_type') {
66
+ continue;
67
+ }
68
+ out[key] = reshapeFieldValue(value, nested[key]);
69
+ }
70
+ return out;
71
+ }
72
+ /** Reshape a single field value against its manifest entry. No entry → a leaf. */
73
+ function reshapeFieldValue(value, shape) {
74
+ if (!shape) {
75
+ return reshapeValue(value);
76
+ }
77
+ if (shape.kind === 'many-ref') {
78
+ // Array invariant for to-many relations: null/undefined → [], a stray
79
+ // single handle → [handle]. Items are leaves (populated relation objects
80
+ // or reference handles), never block items.
81
+ const items = Array.isArray(value) ? value : value == null ? [] : [value];
82
+ return items.map(reshapeValue);
83
+ }
84
+ const items = Array.isArray(value) ? value : [];
85
+ if (shape.kind === 'single') {
86
+ return items.length > 0 ? reshapeBlockItem(items[0], shape) : null;
87
+ }
88
+ return items.map((item) => reshapeBlockItem(item, shape));
89
+ }
90
+ function reshapeEntryData(data, shapes) {
91
+ const out = {};
92
+ for (const [field, value] of Object.entries(data)) {
93
+ out[field] = reshapeFieldValue(value, shapes[field]);
94
+ }
95
+ return out;
96
+ }
97
+ /** One Fimo entry → one Strapi-v5 item (`id` + `documentId` + reshaped fields). */
98
+ export function fimoEntryToStrapiItem(entry, shapes = {}) {
99
+ return { id: entry.id, documentId: entry.id, ...reshapeEntryData(entry.data, shapes) };
100
+ }
101
+ /** Fimo entries → a Strapi-v5 collection envelope (`{ data, meta.pagination }`). */
102
+ export function fimoEntriesToStrapiList(entries, options = {}) {
103
+ const data = entries.map((entry) => fimoEntryToStrapiItem(entry, options.shapes));
104
+ const total = options.total ?? data.length;
105
+ const pageSize = options.pageSize ?? (data.length || 1);
106
+ return {
107
+ data,
108
+ meta: {
109
+ pagination: {
110
+ page: options.page ?? 1,
111
+ pageSize,
112
+ pageCount: pageSize > 0 ? Math.max(1, Math.ceil(total / pageSize)) : 1,
113
+ total,
114
+ },
115
+ },
116
+ };
117
+ }
118
+ /** Fimo entry → a Strapi-v5 single/singleton envelope (`{ data, meta }`). */
119
+ export function fimoEntryToStrapiSingle(entry, shapes = {}) {
120
+ return { data: entry ? fimoEntryToStrapiItem(entry, shapes) : null, meta: {} };
121
+ }
@@ -0,0 +1,3 @@
1
+ export { fimoLabelAttrs, fimoMediaAttrs, FIMO_SOURCE_ATTR } from '../wrapped/dom.js';
2
+ export { makeFimoT } from '../shared/labels-t.pure.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,7 @@
1
+ // fimo/svelte — CLIENT-SAFE surface for .svelte components (they hydrate:
2
+ // importing the server barrel here pulls node builtins into the client
3
+ // bundle, the exact class the Nuxt dogfood broke on). Server loaders live in
4
+ // fimo/svelte/server, called from +layout.server.ts / +page.server.ts —
5
+ // SvelteKit's own server-only convention.
6
+ export { fimoLabelAttrs, fimoMediaAttrs, FIMO_SOURCE_ATTR } from '../wrapped/dom.js';
7
+ export { makeFimoT } from '../shared/labels-t.pure.js';
@@ -0,0 +1,3 @@
1
+ export * from '../wrapped/server.js';
2
+ export { fimoLabelAttrs, fimoMediaAttrs } from '../wrapped/dom.js';
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,6 @@
1
+ // fimo/svelte/server — SvelteKit adapter, server surface. The loaders are
2
+ // framework-neutral (SvelteKit needs no React): call them in server-side code
3
+ // (frontmatter / load functions / useAsyncData) and render values with the
4
+ // DOM attribute helpers so edit mode can select the elements.
5
+ export * from '../wrapped/server.js';
6
+ export { fimoLabelAttrs, fimoMediaAttrs } from '../wrapped/dom.js';
@@ -0,0 +1,3 @@
1
+ export { fimoLabelAttrs, fimoMediaAttrs, FIMO_SOURCE_ATTR } from '../wrapped/dom.js';
2
+ export { makeFimoT } from '../shared/labels-t.pure.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ // fimo/vue — CLIENT-SAFE surface for Vue SFCs (same rule as fimo/svelte:
2
+ // never re-export the server barrel from a surface component code imports).
3
+ // Server loaders live in fimo/vue/server.
4
+ export { fimoLabelAttrs, fimoMediaAttrs, FIMO_SOURCE_ATTR } from '../wrapped/dom.js';
5
+ export { makeFimoT } from '../shared/labels-t.pure.js';
@@ -0,0 +1,3 @@
1
+ export * from '../wrapped/server.js';
2
+ export { fimoLabelAttrs, fimoMediaAttrs } from '../wrapped/dom.js';
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,6 @@
1
+ // fimo/vue/server — Vue adapter, server surface. The loaders are
2
+ // framework-neutral (Vue needs no React): call them in server-side code
3
+ // (frontmatter / load functions / useAsyncData) and render values with the
4
+ // DOM attribute helpers so edit mode can select the elements.
5
+ export * from '../wrapped/server.js';
6
+ export { fimoLabelAttrs, fimoMediaAttrs } from '../wrapped/dom.js';
@@ -0,0 +1,17 @@
1
+ import { type ComponentPropsWithoutRef, type ReactNode } from 'react';
2
+ type FimoFileLinkProps = Omit<ComponentPropsWithoutRef<'a'>, 'id'> & {
3
+ /** WrappedMedia entry key, e.g. `home.whitepaper`. Seeded at migration time. */
4
+ id: string;
5
+ children?: ReactNode;
6
+ };
7
+ /**
8
+ * Wraps a hardcoded file link (pdf, zip, ...) so the file becomes replaceable
9
+ * in Fimo. The original `href` stays in code as the fallback:
10
+ *
11
+ * <FimoFileLink id="home.whitepaper" href="/whitepaper.pdf">
12
+ * <FimoText id="home.whitepaper.cta">Download the whitepaper</FimoText>
13
+ * </FimoFileLink>
14
+ */
15
+ export declare function FimoFileLink({ id, href, children, ...props }: FimoFileLinkProps): import("react/jsx-runtime").JSX.Element;
16
+ export {};
17
+ //# sourceMappingURL=FimoFileLink.d.ts.map
@@ -0,0 +1,19 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { FIMO_SOURCE } from '../primitives/lib/index.js';
4
+ import { useWrappedMedia } from './WrappedContentContext.js';
5
+ /**
6
+ * Wraps a hardcoded file link (pdf, zip, ...) so the file becomes replaceable
7
+ * in Fimo. The original `href` stays in code as the fallback:
8
+ *
9
+ * <FimoFileLink id="home.whitepaper" href="/whitepaper.pdf">
10
+ * <FimoText id="home.whitepaper.cta">Download the whitepaper</FimoText>
11
+ * </FimoFileLink>
12
+ */
13
+ export function FimoFileLink({ id, href, children, ...props }) {
14
+ const media = useWrappedMedia(id);
15
+ if (media) {
16
+ return (_jsx("a", { href: media.url, "data-fimo-source": media[FIMO_SOURCE], ...props, children: children }));
17
+ }
18
+ return (_jsx("a", { href: href, ...props, children: children }));
19
+ }
@@ -0,0 +1,14 @@
1
+ import { type ComponentPropsWithoutRef } from 'react';
2
+ type FimoMediaImageProps = Omit<ComponentPropsWithoutRef<'img'>, 'id' | 'children'> & {
3
+ /** WrappedMedia entry key, e.g. `home.hero.image`. Seeded at migration time. */
4
+ id: string;
5
+ };
6
+ /**
7
+ * Wraps a hardcoded image so it becomes replaceable in Fimo. The original
8
+ * `src` stays in code as the fallback until the WrappedMedia entry resolves:
9
+ *
10
+ * <FimoMediaImage id="home.hero.image" src="/images/dashboard.png" alt="Dashboard" width={1200} height={630} />
11
+ */
12
+ export declare function FimoMediaImage({ id, src, alt, ...props }: FimoMediaImageProps): import("react/jsx-runtime").JSX.Element | null;
13
+ export {};
14
+ //# sourceMappingURL=FimoMediaImage.d.ts.map
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Image } from '../primitives/components/Image.js';
4
+ import { useWrappedMedia } from './WrappedContentContext.js';
5
+ /**
6
+ * Wraps a hardcoded image so it becomes replaceable in Fimo. The original
7
+ * `src` stays in code as the fallback until the WrappedMedia entry resolves:
8
+ *
9
+ * <FimoMediaImage id="home.hero.image" src="/images/dashboard.png" alt="Dashboard" width={1200} height={630} />
10
+ */
11
+ export function FimoMediaImage({ id, src, alt, ...props }) {
12
+ const media = useWrappedMedia(id);
13
+ if (media) {
14
+ return _jsx(Image, { value: media, alt: alt, ...props });
15
+ }
16
+ if (!src) {
17
+ return null;
18
+ }
19
+ return _jsx("img", { src: src, alt: alt, ...props });
20
+ }
@@ -0,0 +1,14 @@
1
+ import { type ComponentPropsWithoutRef } from 'react';
2
+ type FimoMediaVideoProps = Omit<ComponentPropsWithoutRef<'video'>, 'id' | 'children'> & {
3
+ /** WrappedMedia entry key, e.g. `home.demo.video`. Seeded at migration time. */
4
+ id: string;
5
+ };
6
+ /**
7
+ * Wraps a hardcoded video so it becomes replaceable in Fimo. The original
8
+ * `src` stays in code as the fallback until the WrappedMedia entry resolves:
9
+ *
10
+ * <FimoMediaVideo id="home.demo.video" src="/demo.mp4" autoPlay muted loop />
11
+ */
12
+ export declare function FimoMediaVideo({ id, src, autoPlay, loop, muted, playsInline, ...props }: FimoMediaVideoProps): import("react/jsx-runtime").JSX.Element | null;
13
+ export {};
14
+ //# sourceMappingURL=FimoMediaVideo.d.ts.map
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Video } from '../primitives/components/Video.js';
4
+ import { useWrappedMedia } from './WrappedContentContext.js';
5
+ /**
6
+ * Wraps a hardcoded video so it becomes replaceable in Fimo. The original
7
+ * `src` stays in code as the fallback until the WrappedMedia entry resolves:
8
+ *
9
+ * <FimoMediaVideo id="home.demo.video" src="/demo.mp4" autoPlay muted loop />
10
+ */
11
+ export function FimoMediaVideo({ id, src, autoPlay, loop, muted, playsInline, ...props }) {
12
+ const media = useWrappedMedia(id);
13
+ if (media) {
14
+ return _jsx(Video, { value: media, autoPlay: autoPlay, loop: loop, muted: muted, playsInline: playsInline, ...props });
15
+ }
16
+ if (!src) {
17
+ return null;
18
+ }
19
+ return _jsx("video", { src: src, autoPlay: autoPlay, loop: loop, muted: muted, playsInline: playsInline, ...props });
20
+ }
@@ -0,0 +1,26 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type FimoRichTextComponents } from '../primitives/lib/index.js';
3
+ interface FimoRichTextBlockProps {
4
+ /** WrappedRichText entry key, e.g. `home.hero.subtitle`. Seeded at migration time. */
5
+ id: string;
6
+ /** The original formatted markup — rendered when the entry is absent. */
7
+ children?: ReactNode;
8
+ components?: FimoRichTextComponents;
9
+ className?: string;
10
+ /** Wrapper element — `span` when the block sits inside a `<p>` (a div
11
+ * there is invalid HTML and breaks hydration). */
12
+ as?: 'div' | 'span';
13
+ }
14
+ /**
15
+ * Wraps formatted text (bold, italic, underline, links) so it becomes
16
+ * editable with marks in Fimo. Seeding converts the original markup to
17
+ * TipTap JSON; the renderer emits the same tags back. The original JSX
18
+ * stays in code as the fallback:
19
+ *
20
+ * <FimoRichTextBlock id="home.hero.subtitle">
21
+ * <p>We help teams <strong>ship faster</strong> and <em>stay safe</em>.</p>
22
+ * </FimoRichTextBlock>
23
+ */
24
+ export declare function FimoRichTextBlock({ id, children, components, className, as }: FimoRichTextBlockProps): import("react/jsx-runtime").JSX.Element;
25
+ export {};
26
+ //# sourceMappingURL=FimoRichTextBlock.d.ts.map
@@ -0,0 +1,22 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
+ import { RichText } from '../primitives/components/RichText.js';
4
+ import { FimoRichText } from '../primitives/lib/index.js';
5
+ import { useWrappedRichText } from './WrappedContentContext.js';
6
+ /**
7
+ * Wraps formatted text (bold, italic, underline, links) so it becomes
8
+ * editable with marks in Fimo. Seeding converts the original markup to
9
+ * TipTap JSON; the renderer emits the same tags back. The original JSX
10
+ * stays in code as the fallback:
11
+ *
12
+ * <FimoRichTextBlock id="home.hero.subtitle">
13
+ * <p>We help teams <strong>ship faster</strong> and <em>stay safe</em>.</p>
14
+ * </FimoRichTextBlock>
15
+ */
16
+ export function FimoRichTextBlock({ id, children, components, className, as }) {
17
+ const entry = useWrappedRichText(id);
18
+ if (!entry) {
19
+ return _jsx(_Fragment, { children: children });
20
+ }
21
+ return (_jsx(RichText, { value: new FimoRichText(entry.content, entry.source), components: components, className: className, as: as }));
22
+ }
@@ -0,0 +1,22 @@
1
+ import { type ComponentPropsWithoutRef, type ElementType } from 'react';
2
+ type FimoTextProps<T extends ElementType = 'span'> = {
3
+ /** Label key, e.g. `home.hero.title`. Seeded at migration time. */
4
+ id: string;
5
+ /** The original hardcoded string — rendered when the key has no value. */
6
+ children?: string;
7
+ as?: T;
8
+ } & Omit<ComponentPropsWithoutRef<T>, 'id' | 'as' | 'children'>;
9
+ /**
10
+ * Wraps a hardcoded string so it becomes editable in Fimo. The original
11
+ * string stays in code as the fallback:
12
+ *
13
+ * <h1><FimoText id="home.hero.title">Ship your site in hours</FimoText></h1>
14
+ *
15
+ * For attribute strings use the two-argument label function instead:
16
+ *
17
+ * const { t } = useLabels();
18
+ * <input placeholder={String(t('home.newsletter.placeholder', 'Your work email'))} />
19
+ */
20
+ export declare function FimoText<T extends ElementType = 'span'>({ id, children, as, ...props }: FimoTextProps<T>): import("react/jsx-runtime").JSX.Element;
21
+ export {};
22
+ //# sourceMappingURL=FimoText.d.ts.map
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Text } from '../primitives/components/Text.js';
4
+ import { useLabels } from '../primitives/labels-hook.js';
5
+ /**
6
+ * Wraps a hardcoded string so it becomes editable in Fimo. The original
7
+ * string stays in code as the fallback:
8
+ *
9
+ * <h1><FimoText id="home.hero.title">Ship your site in hours</FimoText></h1>
10
+ *
11
+ * For attribute strings use the two-argument label function instead:
12
+ *
13
+ * const { t } = useLabels();
14
+ * <input placeholder={String(t('home.newsletter.placeholder', 'Your work email'))} />
15
+ */
16
+ export function FimoText({ id, children, as, ...props }) {
17
+ const { t } = useLabels();
18
+ const textProps = { value: t(id, children), as, ...props };
19
+ return _jsx(Text, { ...textProps });
20
+ }
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { FIMO_SOURCE, FimoMedia, type FimoRichTextContent } from '../primitives/lib/index.js';
3
+ export interface WrappedMediaEntry {
4
+ url: string;
5
+ alt?: string;
6
+ name?: string;
7
+ mime?: string;
8
+ width?: number;
9
+ height?: number;
10
+ /** data-fimo-source path, e.g. `WrappedMedia.<entryId>.image` */
11
+ source: string;
12
+ }
13
+ export interface WrappedRichTextEntry {
14
+ content: FimoRichTextContent;
15
+ /** data-fimo-source path, e.g. `WrappedRichText.<entryId>.body` */
16
+ source: string;
17
+ }
18
+ export interface WrappedContentValue {
19
+ media: Record<string, WrappedMediaEntry>;
20
+ richText: Record<string, WrappedRichTextEntry>;
21
+ }
22
+ export declare function WrappedContentProvider({ media, richText, children, }: Partial<WrappedContentValue> & {
23
+ children?: React.ReactNode;
24
+ }): import("react/jsx-runtime").JSX.Element;
25
+ export declare function useWrappedMedia(id: string): FimoMedia | null;
26
+ export declare function useWrappedRichText(id: string): WrappedRichTextEntry | null;
27
+ export { FIMO_SOURCE };
28
+ //# sourceMappingURL=WrappedContentContext.d.ts.map
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useMemo } from 'react';
4
+ import { FIMO_SOURCE, FimoMedia } from '../primitives/lib/index.js';
5
+ const emptyValue = { media: {}, richText: {} };
6
+ const WrappedContentContext = createContext(emptyValue);
7
+ export function WrappedContentProvider({ media, richText, children, }) {
8
+ const value = useMemo(() => ({ media: media ?? {}, richText: richText ?? {} }), [media, richText]);
9
+ return _jsx(WrappedContentContext.Provider, { value: value, children: children });
10
+ }
11
+ export function useWrappedMedia(id) {
12
+ const { media } = useContext(WrappedContentContext);
13
+ const entry = media[id];
14
+ if (!entry) {
15
+ return null;
16
+ }
17
+ return new FimoMedia({
18
+ url: entry.url,
19
+ alt: entry.alt ?? '',
20
+ name: entry.name ?? id,
21
+ mime: entry.mime ?? '',
22
+ width: entry.width,
23
+ height: entry.height,
24
+ }, entry.source);
25
+ }
26
+ export function useWrappedRichText(id) {
27
+ const { richText } = useContext(WrappedContentContext);
28
+ return richText[id] ?? null;
29
+ }
30
+ export { FIMO_SOURCE };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import type { FimoConfig } from '../shared/fimo-config.types.js';
3
+ import { type WrappedMediaEntry, type WrappedRichTextEntry } from './WrappedContentContext.js';
4
+ export interface WrappedLabels {
5
+ dictionaries: Record<string, Record<string, string>>;
6
+ defaultLocale: string;
7
+ locales?: string[];
8
+ updatedAt?: string | null;
9
+ signature: string;
10
+ }
11
+ /** Framework navigation adapter: the ONLY thing an adapter must supply. */
12
+ export interface WrappedNavigation {
13
+ pathname: string | null;
14
+ navigate: (to: string) => void;
15
+ }
16
+ export interface WrappedProvidersProps {
17
+ config: FimoConfig;
18
+ labels?: WrappedLabels;
19
+ media?: Record<string, WrappedMediaEntry>;
20
+ richText?: Record<string, WrappedRichTextEntry>;
21
+ locale?: string;
22
+ navigation: WrappedNavigation;
23
+ children?: React.ReactNode;
24
+ }
25
+ /**
26
+ * Framework-neutral providers for WRAPPED (adopted) apps. Adapters
27
+ * (fimo/next, fimo/remix, ...) supply only the navigation hooks; everything
28
+ * else — label hydration, locale resolution, preview bridge, error boundary —
29
+ * is shared. Content arrives as serializable props from the wrapped server
30
+ * loaders.
31
+ */
32
+ export declare function WrappedProviders({ config, labels, media, richText, locale, navigation, children }: WrappedProvidersProps): import("react/jsx-runtime").JSX.Element;
33
+ //# sourceMappingURL=WrappedProviders.d.ts.map
@@ -0,0 +1,101 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4
+ import { Suspense, useCallback, useEffect, useMemo, useState } from 'react';
5
+ import { ErrorBoundary } from 'react-error-boundary';
6
+ import { DataSourcesProvider } from '../content/DataSourcesProvider.js';
7
+ import { AppErrorBoundary, onError } from '../core/AppErrorBoundary.js';
8
+ import { FimoLocaleProvider } from '../i18n/FimoLocaleContext.js';
9
+ import { getFimoTextDirection, resolveFimoLocale, toHtmlLang } from '../i18n/locale.js';
10
+ import { ScreenshotProvider } from '../iframe/ScreenshotProvider.js';
11
+ import { hydrateLabels } from '../primitives/labels-store.js';
12
+ import { getDisplayRoutes } from '../shared/display-routes.js';
13
+ import { WrappedContentProvider } from './WrappedContentContext.js';
14
+ function toLabelState(labels) {
15
+ return {
16
+ dictionaries: labels.dictionaries,
17
+ defaultLocale: labels.defaultLocale,
18
+ signature: labels.signature,
19
+ updatedAt: labels.updatedAt ?? null,
20
+ };
21
+ }
22
+ function PreviewBridge({ config, navigation }) {
23
+ const { pathname, navigate } = navigation;
24
+ const localeResolution = useMemo(() => resolveFimoLocale({ pathname: pathname ?? undefined }, config), [pathname, config]);
25
+ const sendRoutes = useCallback(() => {
26
+ window.parent.postMessage({ type: 'nav/routes', payload: { routes: getDisplayRoutes(config) } }, '*');
27
+ }, [config]);
28
+ const sendLocationChange = useCallback(() => {
29
+ window.parent.postMessage({
30
+ type: 'nav/locationChange',
31
+ payload: {
32
+ path: pathname,
33
+ routePath: localeResolution.routePath,
34
+ locale: localeResolution.locale,
35
+ },
36
+ }, '*');
37
+ }, [pathname, localeResolution.locale, localeResolution.routePath]);
38
+ useEffect(sendRoutes, [sendRoutes]);
39
+ useEffect(sendLocationChange, [sendLocationChange]);
40
+ useEffect(() => {
41
+ const handleMessage = (event) => {
42
+ const type = event.data?.type;
43
+ const payload = event.data?.payload;
44
+ switch (type) {
45
+ case 'nav/navigate':
46
+ if (payload?.to) {
47
+ navigate(payload.to);
48
+ }
49
+ return;
50
+ case 'nav/read-routes':
51
+ sendRoutes();
52
+ sendLocationChange();
53
+ return;
54
+ }
55
+ };
56
+ window.addEventListener('message', handleMessage);
57
+ return () => {
58
+ window.removeEventListener('message', handleMessage);
59
+ };
60
+ }, [navigate, sendRoutes, sendLocationChange]);
61
+ return null;
62
+ }
63
+ /**
64
+ * Framework-neutral providers for WRAPPED (adopted) apps. Adapters
65
+ * (fimo/next, fimo/remix, ...) supply only the navigation hooks; everything
66
+ * else — label hydration, locale resolution, preview bridge, error boundary —
67
+ * is shared. Content arrives as serializable props from the wrapped server
68
+ * loaders.
69
+ */
70
+ export function WrappedProviders({ config, labels, media, richText, locale, navigation, children }) {
71
+ // Wrapped apps have no QueryClientProvider of their own; ScreenshotProvider
72
+ // (and future data-refresh machinery) need one, so the adapter owns it.
73
+ const [queryClient] = useState(() => new QueryClient());
74
+ useState(() => {
75
+ if (labels) {
76
+ hydrateLabels(toLabelState(labels));
77
+ }
78
+ return null;
79
+ });
80
+ useEffect(() => {
81
+ if (labels) {
82
+ hydrateLabels(toLabelState(labels));
83
+ }
84
+ }, [labels]);
85
+ const pathname = navigation.pathname;
86
+ const localeResolution = useMemo(() => resolveFimoLocale({ pathname: pathname ?? undefined }, config), [pathname, config]);
87
+ const activeLocale = locale ?? localeResolution.locale;
88
+ const activeDir = getFimoTextDirection(activeLocale);
89
+ useEffect(() => {
90
+ if (typeof document === 'undefined') {
91
+ return;
92
+ }
93
+ document.documentElement.lang = toHtmlLang(activeLocale);
94
+ document.documentElement.dir = activeDir;
95
+ }, [activeDir, activeLocale]);
96
+ return (_jsx(ErrorBoundary, { FallbackComponent: AppErrorBoundary, onError: onError, children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(FimoLocaleProvider, { value: {
97
+ ...localeResolution,
98
+ locale: activeLocale,
99
+ dir: activeDir,
100
+ }, children: _jsx(WrappedContentProvider, { media: media, richText: richText, children: _jsx(DataSourcesProvider, { children: _jsxs(ScreenshotProvider, { children: [_jsx(PreviewBridge, { config: config, navigation: navigation }), _jsx(Suspense, { children: children })] }) }) }) }) }) }));
101
+ }
@@ -0,0 +1,20 @@
1
+ import type { WrappedMediaEntry, WrappedRichTextEntry } from './WrappedContentContext.js';
2
+ export interface WrappedEntryRow {
3
+ id: string;
4
+ data: Record<string, unknown>;
5
+ }
6
+ /** Every published row of a content type, paginated to the end. Returns []
7
+ * when the API is unreachable so wrapped sites keep their fallbacks. */
8
+ export declare function fetchAllWrappedRows(apiUrl: string, typeName: string): Promise<WrappedEntryRow[]>;
9
+ /** WrappedMedia rows → key → media entry (the FimoMediaImage/Video id map). */
10
+ export declare function mapWrappedMedia(rows: WrappedEntryRow[]): Record<string, WrappedMediaEntry>;
11
+ /** WrappedRichText rows → key → TipTap content (the FimoRichTextBlock map). */
12
+ export declare function mapWrappedRichText(rows: WrappedEntryRow[]): Record<string, WrappedRichTextEntry>;
13
+ export interface WrappedContent {
14
+ media: Record<string, WrappedMediaEntry>;
15
+ richText: Record<string, WrappedRichTextEntry>;
16
+ }
17
+ /** Both plumbing maps in one round: what a client-rendered wrapped app needs
18
+ * so Studio edits to rich text and media are LIVE, not fallback-only. */
19
+ export declare function fetchWrappedContent(apiUrl: string): Promise<WrappedContent>;
20
+ //# sourceMappingURL=content-fetch.pure.d.ts.map