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.
- package/README.md +1 -0
- package/assets/astro/components/Boolean.astro +14 -0
- package/assets/astro/components/Date.astro +23 -0
- package/assets/astro/components/Image.astro +79 -0
- package/assets/astro/components/Json.astro +14 -0
- package/assets/astro/components/RichText.astro +17 -0
- package/assets/astro/components/StaticImage.astro +66 -0
- package/assets/astro/components/Text.astro +23 -0
- package/assets/astro/components/Video.astro +47 -0
- package/assets/astro/components/index.d.ts +8 -0
- package/assets/astro/components/index.js +8 -0
- package/assets/content-templates/shared/server.eta +56 -0
- package/assets/content-templates/sveltekit/content.eta +86 -0
- package/assets/skills/fimo/SKILL.md +13 -4
- package/assets/skills/fimo-cli/SKILL.md +28 -28
- package/assets/skills/fimo-cli/references/account.md +0 -2
- package/assets/skills/fimo-cli/references/agent-setup.md +7 -9
- package/assets/skills/fimo-cli/references/agents.md +0 -2
- package/assets/skills/fimo-cli/references/analytics.md +0 -2
- package/assets/skills/fimo-cli/references/assets.md +2 -4
- package/assets/skills/fimo-cli/references/branches.md +14 -15
- package/assets/skills/fimo-cli/references/content.md +9 -11
- package/assets/skills/fimo-cli/references/credits.md +0 -2
- package/assets/skills/fimo-cli/references/deploy.md +6 -7
- package/assets/skills/fimo-cli/references/describe.md +1 -3
- package/assets/skills/fimo-cli/references/domains.md +0 -2
- package/assets/skills/fimo-cli/references/forms.md +5 -7
- package/assets/skills/fimo-cli/references/history.md +0 -2
- package/assets/skills/fimo-cli/references/init.md +34 -26
- package/assets/skills/fimo-cli/references/integrations/firecrawl.md +0 -2
- package/assets/skills/fimo-cli/references/integrations.md +0 -2
- package/assets/skills/fimo-cli/references/invite.md +0 -2
- package/assets/skills/fimo-cli/references/labels.md +5 -7
- package/assets/skills/fimo-cli/references/locales.md +2 -4
- package/assets/skills/fimo-cli/references/mcp.md +2 -4
- package/assets/skills/fimo-cli/references/media.md +0 -2
- package/assets/skills/fimo-cli/references/preview.md +0 -2
- package/assets/skills/fimo-cli/references/project-vars-and-secrets.md +1 -3
- package/assets/skills/fimo-cli/references/projects.md +1 -3
- package/assets/skills/fimo-cli/references/schedules.md +0 -2
- package/assets/skills/fimo-cli/references/support.md +0 -2
- package/assets/skills/fimo-cli/references/webhooks.md +0 -2
- package/assets/skills/fimo-code/SKILL.md +11 -3
- package/assets/skills/fimo-code/references/assets.md +2 -2
- package/assets/skills/fimo-code/references/content/clients.md +5 -1
- package/assets/skills/fimo-code/references/content.md +3 -1
- package/assets/skills/fimo-code/references/frameworks/astro.md +127 -0
- package/assets/skills/fimo-code/references/frameworks/compatibility.md +19 -0
- package/assets/skills/fimo-code/references/frameworks/hosting.md +15 -3
- package/assets/skills/fimo-code/references/frameworks/react-router.md +37 -209
- package/assets/skills/fimo-code/references/frameworks/sveltekit.md +110 -0
- package/assets/skills/fimo-code/references/frameworks/vite-react.md +35 -166
- package/assets/skills/fimo-code/references/labels.md +16 -6
- package/assets/skills/fimo-code/references/locales.md +3 -1
- package/assets/skills/fimo-code/references/ui.md +19 -15
- package/assets/skills/fimo-migration/SKILL.md +99 -146
- package/assets/skills/fimo-migration/references/frameworks/nextjs.md +26 -0
- package/assets/skills/fimo-migration/references/inventory/coordinator.md +40 -0
- package/assets/skills/fimo-migration/references/inventory/locales/next-intl.md +39 -0
- package/assets/skills/fimo-migration/references/inventory/locales.md +41 -0
- package/assets/skills/fimo-migration/references/workflow.md +3 -2
- package/assets/skills/fimo-migration/scripts/inventory/locales/next-intl.mjs +459 -0
- package/assets/skills/fimo-studio/SKILL.md +1 -1
- package/assets/skills/fimo-studio/references/project-creation.md +10 -18
- package/assets/starters/fimo-site/template/.fimo/agents/content-guide/capabilities.yaml +0 -1
- package/assets/starters/fimo-site/template/.fimo/agents/site-review/capabilities.yaml +0 -1
- package/assets/sveltekit/components/Boolean.svelte +19 -0
- package/assets/sveltekit/components/Date.svelte +33 -0
- package/assets/sveltekit/components/FimoProvider.svelte +35 -0
- package/assets/sveltekit/components/Image.svelte +80 -0
- package/assets/sveltekit/components/Json.svelte +18 -0
- package/assets/sveltekit/components/Label.svelte +16 -0
- package/assets/sveltekit/components/Number.svelte +21 -0
- package/assets/sveltekit/components/RichText.svelte +19 -0
- package/assets/sveltekit/components/Text.svelte +30 -0
- package/assets/sveltekit/components/Video.svelte +37 -0
- package/assets/sveltekit/components/index.d.ts +10 -0
- package/assets/sveltekit/components/index.js +10 -0
- package/dist/build/astro/config.d.ts +4 -0
- package/dist/build/astro/config.js +64 -0
- package/dist/build/next/config.js +16 -0
- package/dist/build/sveltekit/config.d.ts +6 -0
- package/dist/build/sveltekit/config.js +8 -0
- package/dist/build/sveltekit/data-id.d.ts +3 -0
- package/dist/build/sveltekit/data-id.js +171 -0
- package/dist/build/sveltekit/vite.d.ts +13 -0
- package/dist/build/sveltekit/vite.js +15 -0
- package/dist/build/vite/index.js +2 -0
- package/dist/build/vite/plugins/data-id.d.ts +9 -0
- package/dist/build/vite/plugins/data-id.js +6 -1
- package/dist/build/vite/plugins/runtime-env.d.ts +21 -0
- package/dist/build/vite/plugins/runtime-env.js +68 -0
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +108 -101
- package/dist/runtime/app/FimoProviders.d.ts +1 -1
- package/dist/runtime/app/FimoProviders.js +11 -5
- package/dist/runtime/astro/internal.d.ts +6 -0
- package/dist/runtime/astro/internal.js +16 -0
- package/dist/runtime/astro/preview.d.ts +14 -0
- package/dist/runtime/astro/preview.js +103 -0
- package/dist/runtime/astro/render-rich-text.d.ts +2 -0
- package/dist/runtime/astro/render-rich-text.js +1 -0
- package/dist/runtime/astro/server-runtime.d.ts +3 -0
- package/dist/runtime/astro/server-runtime.js +20 -0
- package/dist/runtime/astro/server.d.ts +15 -0
- package/dist/runtime/astro/server.js +14 -0
- package/dist/runtime/content/client/collection-core.d.ts +2 -17
- package/dist/runtime/content/client/collection-core.js +15 -8
- package/dist/runtime/content/client/core-types.d.ts +96 -0
- package/dist/runtime/content/client/core-types.js +1 -0
- package/dist/runtime/content/client/internal.d.ts +4 -4
- package/dist/runtime/content/client/internal.js +4 -3
- package/dist/runtime/content/client/runtime.d.ts +1 -1
- package/dist/runtime/content/client/server-content-client.d.ts +3 -3
- package/dist/runtime/content/client/server-content-client.js +2 -29
- package/dist/runtime/content/client/singleton-core.d.ts +2 -9
- package/dist/runtime/content/client/singleton-core.js +9 -4
- package/dist/runtime/content/client/types.d.ts +5 -115
- package/dist/runtime/content/index.d.ts +3 -3
- package/dist/runtime/labels/fetch.js +5 -3
- package/dist/runtime/next/client.d.ts +2 -1
- package/dist/runtime/next/facade.d.ts +1 -1
- package/dist/runtime/next/provider.js +1 -1
- package/dist/runtime/next/server-runtime.js +1 -1
- package/dist/runtime/next/server.d.ts +5 -4
- package/dist/runtime/paths/get-fimo-paths.js +8 -3
- package/dist/runtime/preview/bridge.d.ts +8 -0
- package/dist/runtime/preview/bridge.js +20 -0
- package/dist/runtime/preview/location.d.ts +23 -0
- package/dist/runtime/preview/location.js +93 -0
- package/dist/runtime/preview/routes.d.ts +10 -0
- package/dist/runtime/preview/routes.js +29 -0
- package/dist/runtime/primitives/index.d.ts +4 -1
- package/dist/runtime/primitives/index.js +1 -0
- package/dist/runtime/primitives/lib/image-optimization.d.ts +27 -2
- package/dist/runtime/primitives/lib/image-optimization.js +40 -0
- package/dist/runtime/primitives/lib/index.d.ts +1 -1
- package/dist/runtime/primitives/lib/primitives.d.ts +0 -54
- package/dist/runtime/primitives/lib/primitives.js +6 -0
- package/dist/runtime/primitives/lib/render-rich-text.d.ts +3 -0
- package/dist/runtime/primitives/lib/render-rich-text.js +112 -0
- package/dist/runtime/react/primitives/contracts.d.ts +40 -2
- package/dist/runtime/react/primitives/renderers/ImageRenderer.js +15 -34
- package/dist/runtime/react/primitives/renderers/RichTextRenderer.d.ts +2 -1
- package/dist/runtime/react/primitives/renderers/StaticImage.js +13 -30
- package/dist/runtime/routing/AppRoutesProvider.js +20 -8
- package/dist/runtime/shared/env-identity.d.ts +43 -0
- package/dist/runtime/shared/env-identity.js +88 -0
- package/dist/runtime/shared/local-runtime-env.d.ts +65 -0
- package/dist/runtime/shared/local-runtime-env.js +169 -0
- package/dist/runtime/{react-router → shared}/preview-location.d.ts +7 -13
- package/dist/runtime/{react-router → shared}/preview-location.js +26 -27
- package/dist/runtime/sveltekit/content.d.ts +25 -0
- package/dist/runtime/sveltekit/content.js +33 -0
- package/dist/runtime/sveltekit/context-contract.d.ts +5 -0
- package/dist/runtime/sveltekit/context-contract.js +2 -0
- package/dist/runtime/sveltekit/context.d.ts +8 -0
- package/dist/runtime/sveltekit/context.js +25 -0
- package/dist/runtime/sveltekit/index.d.ts +7 -0
- package/dist/runtime/sveltekit/index.js +4 -0
- package/dist/runtime/sveltekit/internal.d.ts +6 -0
- package/dist/runtime/sveltekit/internal.js +12 -0
- package/dist/runtime/sveltekit/labels.d.ts +16 -0
- package/dist/runtime/sveltekit/labels.js +13 -0
- package/dist/runtime/sveltekit/preview.d.ts +19 -0
- package/dist/runtime/sveltekit/preview.js +77 -0
- package/dist/runtime/sveltekit/runtime.d.ts +8 -0
- package/dist/runtime/sveltekit/runtime.js +17 -0
- package/dist/runtime/templates.d.ts +1 -1
- package/dist/runtime/templates.js +1 -1
- package/dist/runtime/vite/Label.d.ts +13 -0
- package/dist/runtime/vite/Label.js +16 -0
- package/dist/scripts/extract-translations.js +103 -43
- package/dist/scripts/sync-forms.js +1 -1
- package/dist/scripts/sync-schemas.js +83 -16
- package/package.json +57 -2
- package/release.json +2 -2
- package/templates/nextjs/AGENTS.md +10 -5
- package/templates/nextjs/_gitignore +1 -0
- package/templates/react-router/AGENTS.md +4 -3
- package/templates/react-router/package.json +1 -1
- package/templates/sveltekit/.fimo/config.json +15 -0
- package/templates/sveltekit/AGENTS.md +36 -0
- package/templates/sveltekit/CLAUDE.md +5 -0
- package/templates/sveltekit/_gitignore +16 -0
- package/templates/sveltekit/package.json +28 -0
- package/templates/sveltekit/pnpm-workspace.yaml +4 -0
- package/templates/sveltekit/src/app.html +11 -0
- package/templates/sveltekit/src/routes/+layout.server.ts +8 -0
- package/templates/sveltekit/src/routes/+layout.svelte +12 -0
- package/templates/sveltekit/src/routes/+page.svelte +48 -0
- package/templates/sveltekit/svelte.config.js +5 -0
- package/templates/sveltekit/tsconfig.json +14 -0
- package/templates/sveltekit/vite.config.ts +5 -0
- /package/assets/content-templates/{form-template.eta → forms/react.eta} +0 -0
- /package/assets/content-templates/{next-client-template.eta → next/client.eta} +0 -0
- /package/assets/content-templates/{next-server-template.eta → next/server.eta} +0 -0
- /package/assets/content-templates/{hooks-template.eta → react/client.eta} +0 -0
- /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,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,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
|
+
}
|
package/dist/build/vite/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
+
}
|