fimo 0.14.0 → 0.15.0-staging.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.
Files changed (199) hide show
  1. package/README.md +1 -0
  2. package/assets/astro/components/Boolean.astro +14 -0
  3. package/assets/astro/components/Date.astro +23 -0
  4. package/assets/astro/components/Image.astro +79 -0
  5. package/assets/astro/components/Json.astro +14 -0
  6. package/assets/astro/components/RichText.astro +17 -0
  7. package/assets/astro/components/StaticImage.astro +66 -0
  8. package/assets/astro/components/Text.astro +23 -0
  9. package/assets/astro/components/Video.astro +47 -0
  10. package/assets/astro/components/index.d.ts +8 -0
  11. package/assets/astro/components/index.js +8 -0
  12. package/assets/content-templates/shared/server.eta +56 -0
  13. package/assets/content-templates/sveltekit/content.eta +86 -0
  14. package/assets/skills/fimo/SKILL.md +13 -4
  15. package/assets/skills/fimo-cli/SKILL.md +28 -28
  16. package/assets/skills/fimo-cli/references/account.md +0 -2
  17. package/assets/skills/fimo-cli/references/agent-setup.md +7 -9
  18. package/assets/skills/fimo-cli/references/agents.md +0 -2
  19. package/assets/skills/fimo-cli/references/analytics.md +0 -2
  20. package/assets/skills/fimo-cli/references/assets.md +2 -4
  21. package/assets/skills/fimo-cli/references/branches.md +14 -15
  22. package/assets/skills/fimo-cli/references/content.md +9 -11
  23. package/assets/skills/fimo-cli/references/credits.md +0 -2
  24. package/assets/skills/fimo-cli/references/deploy.md +6 -7
  25. package/assets/skills/fimo-cli/references/describe.md +1 -3
  26. package/assets/skills/fimo-cli/references/domains.md +0 -2
  27. package/assets/skills/fimo-cli/references/forms.md +5 -7
  28. package/assets/skills/fimo-cli/references/history.md +0 -2
  29. package/assets/skills/fimo-cli/references/init.md +34 -26
  30. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +0 -2
  31. package/assets/skills/fimo-cli/references/integrations.md +0 -2
  32. package/assets/skills/fimo-cli/references/invite.md +0 -2
  33. package/assets/skills/fimo-cli/references/labels.md +5 -7
  34. package/assets/skills/fimo-cli/references/locales.md +2 -4
  35. package/assets/skills/fimo-cli/references/mcp.md +2 -4
  36. package/assets/skills/fimo-cli/references/media.md +0 -2
  37. package/assets/skills/fimo-cli/references/preview.md +0 -2
  38. package/assets/skills/fimo-cli/references/project-vars-and-secrets.md +1 -3
  39. package/assets/skills/fimo-cli/references/projects.md +1 -3
  40. package/assets/skills/fimo-cli/references/schedules.md +0 -2
  41. package/assets/skills/fimo-cli/references/support.md +0 -2
  42. package/assets/skills/fimo-cli/references/webhooks.md +0 -2
  43. package/assets/skills/fimo-code/SKILL.md +11 -3
  44. package/assets/skills/fimo-code/references/assets.md +2 -2
  45. package/assets/skills/fimo-code/references/content/clients.md +5 -1
  46. package/assets/skills/fimo-code/references/content.md +3 -1
  47. package/assets/skills/fimo-code/references/frameworks/astro.md +127 -0
  48. package/assets/skills/fimo-code/references/frameworks/compatibility.md +19 -0
  49. package/assets/skills/fimo-code/references/frameworks/hosting.md +15 -3
  50. package/assets/skills/fimo-code/references/frameworks/react-router.md +37 -209
  51. package/assets/skills/fimo-code/references/frameworks/sveltekit.md +110 -0
  52. package/assets/skills/fimo-code/references/frameworks/vite-react.md +35 -166
  53. package/assets/skills/fimo-code/references/labels.md +16 -6
  54. package/assets/skills/fimo-code/references/locales.md +3 -1
  55. package/assets/skills/fimo-code/references/ui.md +19 -15
  56. package/assets/skills/fimo-migration/SKILL.md +99 -146
  57. package/assets/skills/fimo-migration/references/frameworks/nextjs.md +26 -0
  58. package/assets/skills/fimo-migration/references/inventory/coordinator.md +40 -0
  59. package/assets/skills/fimo-migration/references/inventory/locales/next-intl.md +39 -0
  60. package/assets/skills/fimo-migration/references/inventory/locales.md +41 -0
  61. package/assets/skills/fimo-migration/references/workflow.md +3 -2
  62. package/assets/skills/fimo-migration/scripts/inventory/locales/next-intl.mjs +459 -0
  63. package/assets/skills/fimo-studio/SKILL.md +1 -1
  64. package/assets/skills/fimo-studio/references/project-creation.md +10 -18
  65. package/assets/starters/fimo-site/template/.fimo/agents/content-guide/capabilities.yaml +0 -1
  66. package/assets/starters/fimo-site/template/.fimo/agents/site-review/capabilities.yaml +0 -1
  67. package/assets/sveltekit/components/Boolean.svelte +19 -0
  68. package/assets/sveltekit/components/Date.svelte +33 -0
  69. package/assets/sveltekit/components/FimoProvider.svelte +35 -0
  70. package/assets/sveltekit/components/Image.svelte +80 -0
  71. package/assets/sveltekit/components/Json.svelte +18 -0
  72. package/assets/sveltekit/components/Label.svelte +16 -0
  73. package/assets/sveltekit/components/Number.svelte +21 -0
  74. package/assets/sveltekit/components/RichText.svelte +19 -0
  75. package/assets/sveltekit/components/Text.svelte +30 -0
  76. package/assets/sveltekit/components/Video.svelte +37 -0
  77. package/assets/sveltekit/components/index.d.ts +10 -0
  78. package/assets/sveltekit/components/index.js +10 -0
  79. package/dist/build/astro/config.d.ts +4 -0
  80. package/dist/build/astro/config.js +64 -0
  81. package/dist/build/next/config.js +16 -0
  82. package/dist/build/sveltekit/config.d.ts +6 -0
  83. package/dist/build/sveltekit/config.js +8 -0
  84. package/dist/build/sveltekit/data-id.d.ts +3 -0
  85. package/dist/build/sveltekit/data-id.js +171 -0
  86. package/dist/build/sveltekit/vite.d.ts +13 -0
  87. package/dist/build/sveltekit/vite.js +15 -0
  88. package/dist/build/vite/index.js +2 -0
  89. package/dist/build/vite/plugins/data-id.d.ts +9 -0
  90. package/dist/build/vite/plugins/data-id.js +6 -1
  91. package/dist/build/vite/plugins/runtime-env.d.ts +21 -0
  92. package/dist/build/vite/plugins/runtime-env.js +68 -0
  93. package/dist/cli/bundle.json +1 -1
  94. package/dist/cli/index.js +108 -101
  95. package/dist/runtime/app/FimoProviders.d.ts +1 -1
  96. package/dist/runtime/app/FimoProviders.js +11 -5
  97. package/dist/runtime/astro/internal.d.ts +6 -0
  98. package/dist/runtime/astro/internal.js +16 -0
  99. package/dist/runtime/astro/preview.d.ts +14 -0
  100. package/dist/runtime/astro/preview.js +103 -0
  101. package/dist/runtime/astro/render-rich-text.d.ts +2 -0
  102. package/dist/runtime/astro/render-rich-text.js +1 -0
  103. package/dist/runtime/astro/server-runtime.d.ts +3 -0
  104. package/dist/runtime/astro/server-runtime.js +20 -0
  105. package/dist/runtime/astro/server.d.ts +15 -0
  106. package/dist/runtime/astro/server.js +14 -0
  107. package/dist/runtime/content/client/collection-core.d.ts +2 -17
  108. package/dist/runtime/content/client/collection-core.js +15 -8
  109. package/dist/runtime/content/client/core-types.d.ts +96 -0
  110. package/dist/runtime/content/client/core-types.js +1 -0
  111. package/dist/runtime/content/client/internal.d.ts +4 -4
  112. package/dist/runtime/content/client/internal.js +4 -3
  113. package/dist/runtime/content/client/runtime.d.ts +1 -1
  114. package/dist/runtime/content/client/server-content-client.d.ts +3 -3
  115. package/dist/runtime/content/client/server-content-client.js +2 -29
  116. package/dist/runtime/content/client/singleton-core.d.ts +2 -9
  117. package/dist/runtime/content/client/singleton-core.js +9 -4
  118. package/dist/runtime/content/client/types.d.ts +5 -115
  119. package/dist/runtime/content/index.d.ts +3 -3
  120. package/dist/runtime/labels/fetch.js +5 -3
  121. package/dist/runtime/next/client.d.ts +2 -1
  122. package/dist/runtime/next/facade.d.ts +1 -1
  123. package/dist/runtime/next/provider.js +1 -1
  124. package/dist/runtime/next/server-runtime.js +1 -1
  125. package/dist/runtime/next/server.d.ts +5 -4
  126. package/dist/runtime/paths/get-fimo-paths.js +8 -3
  127. package/dist/runtime/preview/bridge.d.ts +8 -0
  128. package/dist/runtime/preview/bridge.js +20 -0
  129. package/dist/runtime/preview/location.d.ts +23 -0
  130. package/dist/runtime/preview/location.js +93 -0
  131. package/dist/runtime/preview/routes.d.ts +10 -0
  132. package/dist/runtime/preview/routes.js +29 -0
  133. package/dist/runtime/primitives/index.d.ts +4 -1
  134. package/dist/runtime/primitives/index.js +1 -0
  135. package/dist/runtime/primitives/lib/image-optimization.d.ts +27 -2
  136. package/dist/runtime/primitives/lib/image-optimization.js +40 -0
  137. package/dist/runtime/primitives/lib/index.d.ts +1 -1
  138. package/dist/runtime/primitives/lib/primitives.d.ts +0 -54
  139. package/dist/runtime/primitives/lib/primitives.js +6 -0
  140. package/dist/runtime/primitives/lib/render-rich-text.d.ts +3 -0
  141. package/dist/runtime/primitives/lib/render-rich-text.js +112 -0
  142. package/dist/runtime/react/primitives/contracts.d.ts +40 -2
  143. package/dist/runtime/react/primitives/renderers/ImageRenderer.js +15 -34
  144. package/dist/runtime/react/primitives/renderers/RichTextRenderer.d.ts +2 -1
  145. package/dist/runtime/react/primitives/renderers/StaticImage.js +13 -30
  146. package/dist/runtime/routing/AppRoutesProvider.js +20 -8
  147. package/dist/runtime/shared/env-identity.d.ts +43 -0
  148. package/dist/runtime/shared/env-identity.js +88 -0
  149. package/dist/runtime/shared/local-runtime-env.d.ts +65 -0
  150. package/dist/runtime/shared/local-runtime-env.js +169 -0
  151. package/dist/runtime/{react-router → shared}/preview-location.d.ts +7 -13
  152. package/dist/runtime/{react-router → shared}/preview-location.js +26 -27
  153. package/dist/runtime/sveltekit/content.d.ts +25 -0
  154. package/dist/runtime/sveltekit/content.js +33 -0
  155. package/dist/runtime/sveltekit/context-contract.d.ts +5 -0
  156. package/dist/runtime/sveltekit/context-contract.js +2 -0
  157. package/dist/runtime/sveltekit/context.d.ts +8 -0
  158. package/dist/runtime/sveltekit/context.js +25 -0
  159. package/dist/runtime/sveltekit/index.d.ts +7 -0
  160. package/dist/runtime/sveltekit/index.js +4 -0
  161. package/dist/runtime/sveltekit/internal.d.ts +6 -0
  162. package/dist/runtime/sveltekit/internal.js +12 -0
  163. package/dist/runtime/sveltekit/labels.d.ts +16 -0
  164. package/dist/runtime/sveltekit/labels.js +13 -0
  165. package/dist/runtime/sveltekit/preview.d.ts +19 -0
  166. package/dist/runtime/sveltekit/preview.js +77 -0
  167. package/dist/runtime/sveltekit/runtime.d.ts +8 -0
  168. package/dist/runtime/sveltekit/runtime.js +17 -0
  169. package/dist/runtime/templates.d.ts +1 -1
  170. package/dist/runtime/templates.js +1 -1
  171. package/dist/runtime/vite/Label.d.ts +13 -0
  172. package/dist/runtime/vite/Label.js +16 -0
  173. package/dist/scripts/extract-translations.js +103 -43
  174. package/dist/scripts/sync-forms.js +1 -1
  175. package/dist/scripts/sync-schemas.js +83 -16
  176. package/package.json +57 -2
  177. package/release.json +2 -2
  178. package/templates/nextjs/AGENTS.md +10 -5
  179. package/templates/nextjs/_gitignore +1 -0
  180. package/templates/react-router/AGENTS.md +4 -3
  181. package/templates/react-router/package.json +1 -1
  182. package/templates/sveltekit/.fimo/config.json +15 -0
  183. package/templates/sveltekit/AGENTS.md +36 -0
  184. package/templates/sveltekit/CLAUDE.md +5 -0
  185. package/templates/sveltekit/_gitignore +16 -0
  186. package/templates/sveltekit/package.json +28 -0
  187. package/templates/sveltekit/pnpm-workspace.yaml +4 -0
  188. package/templates/sveltekit/src/app.html +11 -0
  189. package/templates/sveltekit/src/routes/+layout.server.ts +8 -0
  190. package/templates/sveltekit/src/routes/+layout.svelte +12 -0
  191. package/templates/sveltekit/src/routes/+page.svelte +48 -0
  192. package/templates/sveltekit/svelte.config.js +5 -0
  193. package/templates/sveltekit/tsconfig.json +14 -0
  194. package/templates/sveltekit/vite.config.ts +5 -0
  195. /package/assets/content-templates/{form-template.eta → forms/react.eta} +0 -0
  196. /package/assets/content-templates/{next-client-template.eta → next/client.eta} +0 -0
  197. /package/assets/content-templates/{next-server-template.eta → next/server.eta} +0 -0
  198. /package/assets/content-templates/{hooks-template.eta → react/client.eta} +0 -0
  199. /package/assets/content-templates/{types-template.eta → shared/types.eta} +0 -0
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes, SvelteHTMLElements } from 'svelte/elements';
3
+
4
+ import { getFimoSource } from 'fimo/sveltekit';
5
+
6
+ type Props = Omit<HTMLAttributes<HTMLElement>, 'children'> & {
7
+ value: unknown;
8
+ as?: keyof SvelteHTMLElements;
9
+ [key: string]: unknown;
10
+ };
11
+
12
+ let { value, as = 'span', ...props }: Props = $props();
13
+ const source = $derived(getFimoSource(value));
14
+ </script>
15
+
16
+ {#if value != null}
17
+ <svelte:element this={as} {...props} data-fimo-source={source}>{JSON.stringify(value)}</svelte:element>
18
+ {/if}
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { useLabels } from 'fimo/sveltekit';
3
+ import type { ComponentProps } from 'svelte';
4
+
5
+ import Text from './Text.svelte';
6
+
7
+ type Props = Omit<ComponentProps<typeof Text>, 'value'> & {
8
+ value: string;
9
+ };
10
+
11
+ let { value, ...props }: Props = $props();
12
+ const labels = useLabels();
13
+ const label = $derived(labels.t(value));
14
+ </script>
15
+
16
+ <Text {...props} value={label} />
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes, SvelteHTMLElements } from 'svelte/elements';
3
+
4
+ // Content numbers stay plain JS numbers (there is no FimoNumber wrapper), so
5
+ // this primitive has no source to expose: it formats for display only and is
6
+ // not editable in the preview.
7
+ type Props = Omit<HTMLAttributes<HTMLElement>, 'children'> & {
8
+ value: number | null | undefined;
9
+ as?: keyof SvelteHTMLElements;
10
+ locale?: string;
11
+ options?: Intl.NumberFormatOptions;
12
+ [key: string]: unknown;
13
+ };
14
+
15
+ let { value, as = 'span', locale, options, ...props }: Props = $props();
16
+ const rendered = $derived(value != null && !Number.isNaN(value) ? value.toLocaleString(locale, options) : null);
17
+ </script>
18
+
19
+ {#if rendered != null}
20
+ <svelte:element this={as} {...props}>{rendered}</svelte:element>
21
+ {/if}
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+
4
+ import type { FimoRichText } from 'fimo/sveltekit';
5
+ import { getFimoSource } from 'fimo/sveltekit';
6
+ import { renderRichTextHtml } from 'fimo/sveltekit/internal';
7
+
8
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
9
+ value: FimoRichText | null | undefined;
10
+ };
11
+
12
+ let { value, ...props }: Props = $props();
13
+ const source = $derived(getFimoSource(value));
14
+ const html = $derived(renderRichTextHtml(value?.content));
15
+ </script>
16
+
17
+ {#if value}
18
+ <div {...props} data-fimo-source={source} data-fimo-richtext="">{@html html}</div>
19
+ {/if}
@@ -0,0 +1,30 @@
1
+ <script lang="ts">
2
+ import type { HTMLAttributes, SvelteHTMLElements } from 'svelte/elements';
3
+
4
+ import type { FimoString } from 'fimo/sveltekit';
5
+ import { getFimoParts, getFimoSource } from 'fimo/sveltekit';
6
+
7
+ type Props = Omit<HTMLAttributes<HTMLElement>, 'children'> & {
8
+ value: FimoString | string | null | undefined;
9
+ as?: keyof SvelteHTMLElements;
10
+ [key: string]: unknown;
11
+ };
12
+
13
+ let { value, as = 'span', ...props }: Props = $props();
14
+ const parts = $derived(getFimoParts(value));
15
+ const source = $derived(getFimoSource(value));
16
+ </script>
17
+
18
+ <svelte:element this={as} {...props} data-fimo-source={source}>
19
+ {#if parts && parts.length > 1}
20
+ {#each parts as part}
21
+ {#if part.source}
22
+ <span data-fimo-source={part.source}>{part.text}</span>
23
+ {:else}
24
+ {part.text}
25
+ {/if}
26
+ {/each}
27
+ {:else}
28
+ {String(value ?? '')}
29
+ {/if}
30
+ </svelte:element>
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import type { HTMLVideoAttributes } from 'svelte/elements';
3
+
4
+ import type { FimoMedia } from 'fimo/sveltekit';
5
+ import { getFimoSource } from 'fimo/sveltekit';
6
+
7
+ type Props = Omit<HTMLVideoAttributes, 'src' | 'width' | 'height' | 'children'> & {
8
+ value: FimoMedia | null | undefined;
9
+ overrideSrc?: string;
10
+ };
11
+
12
+ let {
13
+ value,
14
+ overrideSrc,
15
+ autoplay = true,
16
+ loop = true,
17
+ muted = true,
18
+ playsinline = true,
19
+ ...props
20
+ }: Props = $props();
21
+ const source = $derived(getFimoSource(value));
22
+ </script>
23
+
24
+ {#if value}
25
+ <!-- svelte-ignore a11y_media_has_caption -->
26
+ <video
27
+ {...props}
28
+ src={overrideSrc ?? value.url}
29
+ width={value.width}
30
+ height={value.height}
31
+ {autoplay}
32
+ {loop}
33
+ {muted}
34
+ {playsinline}
35
+ data-fimo-source={source}
36
+ ></video>
37
+ {/if}
@@ -0,0 +1,10 @@
1
+ export { default as Boolean } from './Boolean.svelte';
2
+ export { default as Date } from './Date.svelte';
3
+ export { default as FimoProvider } from './FimoProvider.svelte';
4
+ export { default as Image } from './Image.svelte';
5
+ export { default as Json } from './Json.svelte';
6
+ export { default as Label } from './Label.svelte';
7
+ export { default as Number } from './Number.svelte';
8
+ export { default as RichText } from './RichText.svelte';
9
+ export { default as Text } from './Text.svelte';
10
+ export { default as Video } from './Video.svelte';
@@ -0,0 +1,10 @@
1
+ export { default as Boolean } from './Boolean.svelte';
2
+ export { default as Date } from './Date.svelte';
3
+ export { default as FimoProvider } from './FimoProvider.svelte';
4
+ export { default as Image } from './Image.svelte';
5
+ export { default as Json } from './Json.svelte';
6
+ export { default as Label } from './Label.svelte';
7
+ export { default as Number } from './Number.svelte';
8
+ export { default as RichText } from './RichText.svelte';
9
+ export { default as Text } from './Text.svelte';
10
+ export { default as Video } from './Video.svelte';
@@ -0,0 +1,4 @@
1
+ import type { AstroIntegration } from 'astro';
2
+ /** Connect an Astro app to Fimo preview and hosted server rendering. */
3
+ export declare function fimo(): AstroIntegration;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1,64 @@
1
+ import { createRequire } from 'node:module';
2
+ import { fileURLToPath } from 'node:url';
3
+ import astroHostingAdapter from '@astrojs/vercel';
4
+ import { getConfigPreviewRoutes } from '../../runtime/preview/routes.js';
5
+ import { getConfigServer } from '../../runtime/shared/fimo-config.server.js';
6
+ import runtimeEnvPlugin from '../vite/plugins/runtime-env.js';
7
+ const require = createRequire(import.meta.url);
8
+ const astroHostingEntrypoint = require.resolve('@astrojs/vercel/entrypoint');
9
+ function serializeForModule(value) {
10
+ return (JSON.stringify(value) ?? 'undefined')
11
+ .replaceAll('<', '\\u003c')
12
+ .replaceAll('\u2028', '\\u2028')
13
+ .replaceAll('\u2029', '\\u2029');
14
+ }
15
+ function createFimoHostingAdapter() {
16
+ const adapter = astroHostingAdapter();
17
+ const configDone = adapter.hooks['astro:config:done'];
18
+ if (configDone) {
19
+ adapter.hooks['astro:config:done'] = (options) => {
20
+ configDone({
21
+ ...options,
22
+ setAdapter: (resolvedAdapter) => options.setAdapter({
23
+ ...resolvedAdapter,
24
+ serverEntrypoint: astroHostingEntrypoint,
25
+ }),
26
+ });
27
+ };
28
+ }
29
+ return adapter;
30
+ }
31
+ /** Connect an Astro app to Fimo preview and hosted server rendering. */
32
+ export function fimo() {
33
+ return {
34
+ name: 'fimo:astro',
35
+ hooks: {
36
+ 'astro:config:setup': ({ config, injectScript, updateConfig }) => {
37
+ const hasVercelAdapter = config.integrations?.some((integration) => integration.name === '@astrojs/vercel' || integration.name.startsWith('@astrojs/vercel/'));
38
+ if (config.output === 'server' && !config.adapter && !hasVercelAdapter) {
39
+ // Astro copies config.adapter into its adapter lifecycle before setup
40
+ // hooks run. Registering the same object as an integration ensures
41
+ // its config:done hook calls setAdapter for the server build.
42
+ const adapter = createFimoHostingAdapter();
43
+ updateConfig({ adapter, integrations: [adapter] });
44
+ }
45
+ // Astro is Vite underneath: the same plugin that points a Vite app at
46
+ // the git branch's env does it here, exposing `PUBLIC_FIMO_API_URL`.
47
+ // `as never` sidesteps a TS "excessive stack depth" on Astro's
48
+ // DeepPartial<AstroConfig> vs Vite's Plugin type; the shape is the
49
+ // documented `updateConfig({ vite: { plugins } })`.
50
+ updateConfig({ vite: { plugins: [runtimeEnvPlugin()] } });
51
+ const fimoConfig = getConfigServer(fileURLToPath(config.root));
52
+ const routes = getConfigPreviewRoutes(fimoConfig);
53
+ injectScript('page', [
54
+ "import { connectAstroPreview } from 'fimo/astro/internal';",
55
+ 'connectAstroPreview({',
56
+ ' previewScriptUrl: import.meta.env.PUBLIC_FIMO_PREVIEW_SCRIPT_URL,',
57
+ ` routes: ${serializeForModule(routes)},`,
58
+ ` i18n: ${serializeForModule(fimoConfig.i18n)},`,
59
+ '});',
60
+ ].join('\n'));
61
+ },
62
+ },
63
+ };
64
+ }
@@ -1,3 +1,4 @@
1
+ import { findStaleFimoOverride, resolveLocalRuntimeEnv, staleOverrideMessage, } from '../../runtime/shared/local-runtime-env.js';
1
2
  const NEXT_DEVELOPMENT_PHASE = 'phase-development-server';
2
3
  const PREVIEW_ORIGINS_ENV = 'FIMO_PREVIEW_ALLOWED_ORIGINS';
3
4
  function readPreviewOrigins() {
@@ -20,6 +21,21 @@ export function withFimo(applicationConfig) {
20
21
  if (phase !== NEXT_DEVELOPMENT_PHASE) {
21
22
  return config;
22
23
  }
24
+ // Next has already loaded `.env*` into `process.env` by the time this runs,
25
+ // so "unset" here means neither the platform, the shell, nor the user's own
26
+ // env files supplied it — only then does the git branch decide, per key.
27
+ const derived = resolveLocalRuntimeEnv({ cwd: process.cwd() });
28
+ if (derived) {
29
+ const stale = findStaleFimoOverride(process.env, derived);
30
+ if (stale) {
31
+ console.warn(staleOverrideMessage(stale));
32
+ }
33
+ for (const [key, value] of Object.entries(derived.values)) {
34
+ if (!process.env[key]) {
35
+ process.env[key] = value;
36
+ }
37
+ }
38
+ }
23
39
  const previewOrigins = readPreviewOrigins();
24
40
  if (previewOrigins.length === 0) {
25
41
  return config;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Configure a SvelteKit project for Fimo hosting without exposing the hosting
3
+ * provider in the generated application.
4
+ */
5
+ export declare function fimo(): import("@sveltejs/kit").Adapter;
6
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1,8 @@
1
+ import adapter from '@sveltejs/adapter-vercel';
2
+ /**
3
+ * Configure a SvelteKit project for Fimo hosting without exposing the hosting
4
+ * provider in the generated application.
5
+ */
6
+ export function fimo() {
7
+ return adapter({ runtime: 'nodejs24.x' });
8
+ }
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from 'vite';
2
+ export default function svelteDataIdPlugin(): Plugin;
3
+ //# sourceMappingURL=data-id.d.ts.map
@@ -0,0 +1,171 @@
1
+ import { createRequire } from 'node:module';
2
+ import { join } from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { getLineColumn } from '../vite/plugins/data-id.js';
5
+ // Native DOM elements are always taggable. Fimo's editable primitives are the
6
+ // only component exception: they forward arbitrary element attributes to the
7
+ // native element they render, so tagging them gives Studio the precise source
8
+ // location without leaking data-fimo-id props into arbitrary user components.
9
+ const TAGGABLE_ELEMENT_TYPES = new Set(['RegularElement', 'SvelteElement']);
10
+ const FIMO_PRIMITIVE_EXPORTS = new Set(['Text', 'Image', 'RichText']);
11
+ const FIMO_COMPONENTS_MODULE = 'fimo/sveltekit/components';
12
+ const EXCLUDED_ID_SEGMENTS = ['/node_modules/', '/.svelte-kit/', 'components/ui/', '.fimo/ui/'];
13
+ export default function svelteDataIdPlugin() {
14
+ let config;
15
+ let compilerLoad;
16
+ // Svelte is owned by the consuming app, never by fimo: resolve the compiler
17
+ // from the project root so tagging parses with the exact Svelte version
18
+ // that later compiles the file.
19
+ function loadCompiler() {
20
+ compilerLoad ??= (async () => {
21
+ try {
22
+ const projectRequire = createRequire(join(config.root, 'package.json'));
23
+ const compilerUrl = pathToFileURL(projectRequire.resolve('svelte/compiler')).href;
24
+ // The require condition can point at a CJS bundle; depending on the
25
+ // named-export lexer, `parse` may only be reachable via `default`.
26
+ const imported = (await import(compilerUrl));
27
+ const compiler = typeof imported.parse === 'function' ? imported : imported.default;
28
+ if (typeof compiler?.parse !== 'function') {
29
+ throw new Error('svelte/compiler does not expose parse()');
30
+ }
31
+ return compiler;
32
+ }
33
+ catch (error) {
34
+ config.logger.warn(`[fimo] data-fimo-id tagging disabled: svelte/compiler is not resolvable from ${config.root} (${String(error)})`);
35
+ return null;
36
+ }
37
+ })();
38
+ return compilerLoad;
39
+ }
40
+ return {
41
+ name: 'vite-plugin-svelte-data-id',
42
+ enforce: 'pre',
43
+ configResolved(resolvedConfig) {
44
+ config = resolvedConfig;
45
+ },
46
+ async transform(code, id) {
47
+ if (config.command === 'build') {
48
+ return null;
49
+ }
50
+ // Query'd sub-requests (`+page.svelte?svelte&type=style…`) carry
51
+ // compiled non-Svelte content and never end with `.svelte`.
52
+ if (!id.endsWith('.svelte')) {
53
+ return null;
54
+ }
55
+ if (EXCLUDED_ID_SEGMENTS.some((segment) => id.includes(segment))) {
56
+ return null;
57
+ }
58
+ const compiler = await loadCompiler();
59
+ if (!compiler) {
60
+ return null;
61
+ }
62
+ let parsed;
63
+ try {
64
+ parsed = compiler.parse(code, { modern: true });
65
+ }
66
+ catch {
67
+ // Invalid Svelte: leave the file untouched so vite-plugin-svelte
68
+ // reports the real syntax error against the original source.
69
+ return null;
70
+ }
71
+ const relativePath = id.startsWith(`${config.root}/`) ? id.slice(config.root.length + 1) : id;
72
+ const insertions = [];
73
+ const primitiveComponents = collectFimoPrimitiveComponents(parsed.instance, parsed.module);
74
+ collectInsertions(parsed.fragment, code, relativePath, primitiveComponents, insertions);
75
+ if (insertions.length === 0) {
76
+ return null;
77
+ }
78
+ insertions.sort((a, b) => b.offset - a.offset);
79
+ let transformed = code;
80
+ for (const insertion of insertions) {
81
+ transformed = transformed.slice(0, insertion.offset) + insertion.value + transformed.slice(insertion.offset);
82
+ }
83
+ return { code: transformed, map: null };
84
+ },
85
+ };
86
+ }
87
+ function collectInsertions(node, code, relativePath, primitiveComponents, insertions) {
88
+ if (!node || typeof node !== 'object') {
89
+ return;
90
+ }
91
+ if (Array.isArray(node)) {
92
+ for (const item of node) {
93
+ collectInsertions(item, code, relativePath, primitiveComponents, insertions);
94
+ }
95
+ return;
96
+ }
97
+ const element = node;
98
+ if (typeof element.type === 'string' &&
99
+ (TAGGABLE_ELEMENT_TYPES.has(element.type) ||
100
+ (element.type === 'Component' && typeof element.name === 'string' && primitiveComponents.has(element.name))) &&
101
+ typeof element.start === 'number' &&
102
+ typeof element.name === 'string' &&
103
+ !hasExplicitId(element.attributes)) {
104
+ const { line, column } = getLineColumn(code, element.start);
105
+ insertions.push({
106
+ // `start` points at `<`, so this lands right after the tag name — also
107
+ // valid for `<svelte:element>`, whose `name` is the literal pseudo-tag.
108
+ offset: element.start + 1 + element.name.length,
109
+ value: ` data-fimo-id="${relativePath}#${line}-${column}"`,
110
+ });
111
+ }
112
+ for (const [key, child] of Object.entries(node)) {
113
+ // `metadata` is compiler-internal bookkeeping and may hold
114
+ // back-references; `parent` would make the walk cyclic.
115
+ if (key === 'parent' || key === 'metadata') {
116
+ continue;
117
+ }
118
+ collectInsertions(child, code, relativePath, primitiveComponents, insertions);
119
+ }
120
+ }
121
+ function collectFimoPrimitiveComponents(...instances) {
122
+ const names = new Set();
123
+ for (const instance of instances) {
124
+ if (!instance || typeof instance !== 'object') {
125
+ continue;
126
+ }
127
+ const content = instance.content;
128
+ if (!content || typeof content !== 'object') {
129
+ continue;
130
+ }
131
+ const body = content.body;
132
+ if (!Array.isArray(body)) {
133
+ continue;
134
+ }
135
+ for (const statement of body) {
136
+ if (!statement || typeof statement !== 'object') {
137
+ continue;
138
+ }
139
+ const declaration = statement;
140
+ const source = declaration.source;
141
+ if (declaration.type !== 'ImportDeclaration' || source?.value !== FIMO_COMPONENTS_MODULE) {
142
+ continue;
143
+ }
144
+ if (!Array.isArray(declaration.specifiers)) {
145
+ continue;
146
+ }
147
+ for (const specifier of declaration.specifiers) {
148
+ if (!specifier || typeof specifier !== 'object') {
149
+ continue;
150
+ }
151
+ const imported = specifier;
152
+ if (imported.type === 'ImportSpecifier' &&
153
+ typeof imported.imported?.name === 'string' &&
154
+ FIMO_PRIMITIVE_EXPORTS.has(imported.imported.name) &&
155
+ typeof imported.local?.name === 'string') {
156
+ names.add(imported.local.name);
157
+ }
158
+ }
159
+ }
160
+ }
161
+ return names;
162
+ }
163
+ function hasExplicitId(attributes) {
164
+ if (!Array.isArray(attributes)) {
165
+ return false;
166
+ }
167
+ return attributes.some((attribute) => {
168
+ const attr = attribute;
169
+ return attr.type === 'Attribute' && attr.name === 'data-fimo-id';
170
+ });
171
+ }
@@ -0,0 +1,13 @@
1
+ import type { PluginOption } from 'vite';
2
+ /**
3
+ * Narrow SvelteKit build connector. Points the dev server at the git branch's
4
+ * Fimo env (`PUBLIC_FIMO_API_URL`, `FIMO_ENV`), and tags native Svelte
5
+ * template elements with deterministic `data-fimo-id="<path>#<line>-<column>"`
6
+ * attributes during `vite dev` so the Fimo preview can map DOM nodes back to
7
+ * source. Explicit `data-fimo-id` attributes are preserved and production
8
+ * builds are untouched.
9
+ *
10
+ * Usage in the app's vite.config.ts: `plugins: [fimo(), sveltekit()]`.
11
+ */
12
+ export declare function fimo(): PluginOption[];
13
+ //# sourceMappingURL=vite.d.ts.map
@@ -0,0 +1,15 @@
1
+ import runtimeEnvPlugin from '../vite/plugins/runtime-env.js';
2
+ import svelteDataIdPlugin from './data-id.js';
3
+ /**
4
+ * Narrow SvelteKit build connector. Points the dev server at the git branch's
5
+ * Fimo env (`PUBLIC_FIMO_API_URL`, `FIMO_ENV`), and tags native Svelte
6
+ * template elements with deterministic `data-fimo-id="<path>#<line>-<column>"`
7
+ * attributes during `vite dev` so the Fimo preview can map DOM nodes back to
8
+ * source. Explicit `data-fimo-id` attributes are preserved and production
9
+ * builds are untouched.
10
+ *
11
+ * Usage in the app's vite.config.ts: `plugins: [fimo(), sveltekit()]`.
12
+ */
13
+ export function fimo() {
14
+ return [runtimeEnvPlugin(), svelteDataIdPlugin()];
15
+ }
@@ -5,6 +5,7 @@ import dataIdPlugin from './plugins/data-id.js';
5
5
  import fimoConfigPlugin from './plugins/fimo-config.js';
6
6
  import overlayPlugin from './plugins/overlay.js';
7
7
  import robotsPlugin from './plugins/robots.js';
8
+ import runtimeEnvPlugin from './plugins/runtime-env.js';
8
9
  import seoPlugin from './plugins/seo.js';
9
10
  import serverConfigPlugin from './plugins/server-config.js';
10
11
  import sitemapPlugin from './plugins/sitemap.js';
@@ -137,6 +138,7 @@ function bundleFimoIntoSsrPlugin() {
137
138
  // NOTE: dataIdPlugin must run before anything else to capture valid line numbers.
138
139
  export function fimo(opts = {}) {
139
140
  const plugins = [
141
+ runtimeEnvPlugin(),
140
142
  bundleFimoIntoSsrPlugin(),
141
143
  contentSyncPlugin(),
142
144
  serverConfigPlugin(),
@@ -1,3 +1,12 @@
1
1
  import type { Plugin } from 'vite';
2
2
  export default function dataIdPlugin(): Plugin;
3
+ /**
4
+ * 1-based line and 0-based column of `offset` in `code`. Shared with the
5
+ * SvelteKit data-id plugin: both derive the stable `<path>#<line>-<column>`
6
+ * id from it, so the convention must not change independently.
7
+ */
8
+ export declare function getLineColumn(code: string, offset: number): {
9
+ line: number;
10
+ column: number;
11
+ };
3
12
  //# sourceMappingURL=data-id.d.ts.map
@@ -78,7 +78,12 @@ export default function dataIdPlugin() {
78
78
  },
79
79
  };
80
80
  }
81
- function getLineColumn(code, offset) {
81
+ /**
82
+ * 1-based line and 0-based column of `offset` in `code`. Shared with the
83
+ * SvelteKit data-id plugin: both derive the stable `<path>#<line>-<column>`
84
+ * id from it, so the convention must not change independently.
85
+ */
86
+ export function getLineColumn(code, offset) {
82
87
  let line = 1;
83
88
  let column = 0;
84
89
  for (let i = 0; i < offset && i < code.length; i++) {
@@ -0,0 +1,21 @@
1
+ import { type Plugin } from 'vite';
2
+ /**
3
+ * Point the app at the Fimo env of the current git branch.
4
+ *
5
+ * One rule, per variable: anything already set — by the process env (sandbox,
6
+ * shell) or the user's own `.env*` files, read through Vite's `loadEnv` — is
7
+ * left alone; derivation fills only what is missing. A value a user wrote by
8
+ * hand is an override, and this plugin must never win over it.
9
+ *
10
+ * Two injection paths, both needed:
11
+ * - `process.env`, so Vite's own `VITE_*` exposure, `loadEnv`, and server-side
12
+ * code (`getFimoPaths`, SSR) all see the value.
13
+ * - `define` for the two keys the browser bundle reads. Fimo's own template
14
+ * `define`s them from `loadEnv` at user-config time — before any plugin can
15
+ * run — which yields `undefined` on a bare checkout; a plugin's `define`
16
+ * merges over the user's, so this is what makes the client see the derived
17
+ * URL. Only for keys nothing else set, so the user's own `define` stays
18
+ * authoritative.
19
+ */
20
+ export default function runtimeEnvPlugin(): Plugin;
21
+ //# sourceMappingURL=runtime-env.d.ts.map
@@ -0,0 +1,68 @@
1
+ import { loadEnv } from 'vite';
2
+ import { findStaleFimoOverride, resolveLocalRuntimeEnv, staleOverrideMessage, } from '../../../runtime/shared/local-runtime-env.js';
3
+ /**
4
+ * Point the app at the Fimo env of the current git branch.
5
+ *
6
+ * One rule, per variable: anything already set — by the process env (sandbox,
7
+ * shell) or the user's own `.env*` files, read through Vite's `loadEnv` — is
8
+ * left alone; derivation fills only what is missing. A value a user wrote by
9
+ * hand is an override, and this plugin must never win over it.
10
+ *
11
+ * Two injection paths, both needed:
12
+ * - `process.env`, so Vite's own `VITE_*` exposure, `loadEnv`, and server-side
13
+ * code (`getFimoPaths`, SSR) all see the value.
14
+ * - `define` for the two keys the browser bundle reads. Fimo's own template
15
+ * `define`s them from `loadEnv` at user-config time — before any plugin can
16
+ * run — which yields `undefined` on a bare checkout; a plugin's `define`
17
+ * merges over the user's, so this is what makes the client see the derived
18
+ * URL. Only for keys nothing else set, so the user's own `define` stays
19
+ * authoritative.
20
+ */
21
+ export default function runtimeEnvPlugin() {
22
+ return {
23
+ name: 'fimo:runtime-env',
24
+ enforce: 'pre',
25
+ config: {
26
+ // `order: 'pre'` on the HOOK, not just `enforce: 'pre'` on the plugin.
27
+ // Vite sorts every hook by its own `order` first and plugin position
28
+ // second, so a plugin-level `enforce` alone does not beat another
29
+ // plugin's `order: 'pre'` hook. SvelteKit's config hook declares exactly
30
+ // that and snapshots the environment through `loadEnv` — without this,
31
+ // it captures the env before this plugin fills it and `$env/dynamic/public`
32
+ // comes back empty. Astro hides the same bug because it reads
33
+ // `import.meta.env`, which `define` patches at transform time.
34
+ order: 'pre',
35
+ handler(config, { command, mode }) {
36
+ // Production builds get their env from the platform. Only a local dev
37
+ // server has a git branch worth deriving from.
38
+ if (command !== 'serve') {
39
+ return;
40
+ }
41
+ const cwd = config.root ?? process.cwd();
42
+ const derived = resolveLocalRuntimeEnv({ cwd });
43
+ if (!derived) {
44
+ return;
45
+ }
46
+ const explicit = { ...loadEnv(mode, config.envDir ?? cwd, ''), ...process.env };
47
+ const stale = findStaleFimoOverride(explicit, derived);
48
+ if (stale) {
49
+ console.warn(staleOverrideMessage(stale));
50
+ }
51
+ // Decide what is missing BEFORE writing to process.env, or the define
52
+ // step below would see the values this loop just set.
53
+ const missing = Object.entries(derived.values).filter(([key]) => !explicit[key]);
54
+ for (const [key, value] of missing) {
55
+ process.env[key] = value;
56
+ }
57
+ // `define` EVERY derived key, not a hand-picked subset. Vite only exposes
58
+ // `envPrefix` matches on `import.meta.env`, so an unprefixed key set on
59
+ // `process.env` is invisible to code that reads `import.meta.env` — which
60
+ // is how Astro's server runtime reads `FIMO_CONTENT_API_URL`. A curated
61
+ // list silently misses whichever framework reads a key that is not on it.
62
+ // Every value here is a public tenant URL or an env name; none is secret.
63
+ const define = Object.fromEntries(missing.map(([key, value]) => [`import.meta.env.${key}`, JSON.stringify(value)]));
64
+ return Object.keys(define).length > 0 ? { define } : undefined;
65
+ },
66
+ },
67
+ };
68
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "bundled": true,
3
3
  "bundler": "esbuild",
4
- "bundledAt": "2026-08-14T12:10:52.606Z",
4
+ "bundledAt": "2026-08-16T19:27:18.832Z",
5
5
  "cliVersion": "0.14.0",
6
6
  "external": [
7
7
  "oxc-parser",