fimo 0.21.0-staging.2 → 0.21.0-staging.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-templates/_default/GOAL.md +10 -0
- package/assets/agent-templates/_default/capabilities.yaml +10 -0
- package/assets/content-templates/shared/types.eta +1 -1
- package/assets/skills/fimo-cli/SKILL.md +1 -1
- package/assets/skills/fimo-cli/references/agents.md +85 -32
- package/assets/skills/fimo-cli/references/deploy.md +9 -0
- package/assets/skills/fimo-cli/references/domains.md +4 -4
- package/assets/skills/fimo-cli/references/init.md +4 -0
- package/assets/skills/fimo-cli/references/locales.md +1 -1
- package/assets/skills/fimo-cli/references/mcp.md +1 -1
- package/assets/skills/fimo-cli/references/media.md +18 -1
- package/assets/skills/fimo-code/references/frameworks/next/locales.md +4 -4
- package/assets/skills/fimo-code/references/frameworks/react-router.md +2 -1
- package/assets/skills/fimo-code/references/frameworks/sveltekit.md +3 -5
- package/assets/skills/fimo-code/references/locales.md +2 -2
- package/assets/skills/fimo-studio/references/billing-and-credits.md +6 -4
- package/assets/skills/fimo-studio/references/preview-and-responsive.md +1 -0
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +102 -101
- package/dist/runtime/app/FimoProviders.js +8 -1
- package/dist/runtime/app/FimoScripts.d.ts +0 -1
- package/dist/runtime/app/FimoScripts.js +1 -4
- package/dist/runtime/next/client.d.ts +2 -2
- package/dist/runtime/next/client.js +1 -1
- package/dist/runtime/next/provider.d.ts +0 -5
- package/dist/runtime/next/provider.js +21 -6
- package/dist/runtime/preview/script.d.ts +3 -0
- package/dist/runtime/preview/script.js +14 -0
- package/dist/runtime/react/primitives/contracts.d.ts +7 -1
- package/dist/runtime/sveltekit/preview.d.ts +1 -2
- package/dist/runtime/sveltekit/preview.js +1 -14
- package/dist/scripts/sync-schemas.js +81 -0
- package/package.json +6 -1
- package/templates/astro/AGENTS.md +1 -1
- package/templates/astro/package.json +2 -1
- package/templates/astro/pnpm-workspace.yaml +6 -2
- package/templates/nextjs/.fimo/config.json +1 -2
- package/templates/nextjs/AGENTS.md +5 -15
- package/templates/nextjs/next.config.ts +3 -1
- package/templates/nextjs/package.json +2 -1
- package/templates/nextjs/pnpm-workspace.yaml +6 -2
- package/templates/nextjs/src/app/layout.tsx +16 -0
- package/templates/nextjs/src/locales.ts +3 -6
- package/templates/react-router/AGENTS.md +1 -1
- package/templates/react-router/package.json +3 -2
- package/templates/react-router/pnpm-workspace.yaml +6 -6
- package/templates/react-router/src/vite-env.d.ts +0 -1
- package/templates/sveltekit/AGENTS.md +1 -1
- package/templates/sveltekit/package.json +2 -1
- package/templates/sveltekit/pnpm-workspace.yaml +6 -2
- package/templates/nextjs/src/app/(default)/layout.tsx +0 -10
- package/templates/nextjs/src/app/[locale]/layout.tsx +0 -22
- package/templates/nextjs/src/app/[locale]/page.tsx +0 -1
- package/templates/nextjs/src/components/Document.tsx +0 -26
- package/templates/nextjs/src/components/FimoPreviewBridge.tsx +0 -13
- /package/templates/nextjs/src/app/{(default)/page.tsx → page.tsx} +0 -0
|
@@ -14,6 +14,7 @@ import { getFimoTextDirection, resolveFimoLocale, toHtmlLang } from '../i18n/loc
|
|
|
14
14
|
import { ScreenshotProvider } from '../iframe/ScreenshotProvider.js';
|
|
15
15
|
import { getSafePreviewNavigationPath, isPreviewRuntimeEnabled } from '../preview/bridge.js';
|
|
16
16
|
import { getPreviewLocationChange, getPreviewParentOrigin } from '../preview/location.js';
|
|
17
|
+
import { ensurePreviewScript } from '../preview/script.js';
|
|
17
18
|
import { getActiveRouterRoutes } from '../react-router/active-routes.js';
|
|
18
19
|
import { matchFimoRoute } from '../routes/index.js';
|
|
19
20
|
import { OptionalTracking } from '../t/OptionalTracking.js';
|
|
@@ -170,7 +171,8 @@ export function FimoProviders({ children, locale }) {
|
|
|
170
171
|
const activeLocale = useMemo(() => locale ?? getRouteLocale(location.pathname), [locale, location.pathname]);
|
|
171
172
|
const activeDir = getFimoTextDirection(activeLocale);
|
|
172
173
|
// @ts-ignore - import.meta.env is provided by Vite and React Router.
|
|
173
|
-
const
|
|
174
|
+
const previewScriptUrl = import.meta.env.VITE_PREVIEW_SCRIPT_URL;
|
|
175
|
+
const previewEnabled = isPreviewRuntimeEnabled(previewScriptUrl);
|
|
174
176
|
useEffect(() => {
|
|
175
177
|
if (typeof document === 'undefined') {
|
|
176
178
|
return;
|
|
@@ -178,6 +180,11 @@ export function FimoProviders({ children, locale }) {
|
|
|
178
180
|
document.documentElement.lang = toHtmlLang(activeLocale);
|
|
179
181
|
document.documentElement.dir = activeDir;
|
|
180
182
|
}, [activeDir, activeLocale]);
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
if (previewEnabled) {
|
|
185
|
+
ensurePreviewScript(previewScriptUrl);
|
|
186
|
+
}
|
|
187
|
+
}, [previewEnabled, previewScriptUrl]);
|
|
181
188
|
return (_jsx(ErrorBoundary, { FallbackComponent: AppErrorBoundary, onError: onError, children: _jsx(EnsureQueryClient, { children: _jsx(FimoLocaleProvider, { value: {
|
|
182
189
|
...localeResolution,
|
|
183
190
|
locale: activeLocale,
|
|
@@ -3,7 +3,6 @@ import 'virtual:fimo-overlay-hmr';
|
|
|
3
3
|
* Renders extra <script> tags in <head>:
|
|
4
4
|
* - Dev overlay runtime (window.error / unhandledrejection bridge to parent)
|
|
5
5
|
* - JSON-LD Schema.org Organization + WebSite (when seo.siteName + seo.url set)
|
|
6
|
-
* - Preview script (when VITE_PREVIEW_SCRIPT_URL is set, e.g. iframe preview mode)
|
|
7
6
|
*
|
|
8
7
|
* The overlay runtime is embedded inline via the `virtual:fimo-overlay-runtime`
|
|
9
8
|
* module (resolved by `overlayPlugin` in `fimo/vite`). The previous approach
|
|
@@ -33,7 +33,6 @@ function buildSiteSchemas() {
|
|
|
33
33
|
* Renders extra <script> tags in <head>:
|
|
34
34
|
* - Dev overlay runtime (window.error / unhandledrejection bridge to parent)
|
|
35
35
|
* - JSON-LD Schema.org Organization + WebSite (when seo.siteName + seo.url set)
|
|
36
|
-
* - Preview script (when VITE_PREVIEW_SCRIPT_URL is set, e.g. iframe preview mode)
|
|
37
36
|
*
|
|
38
37
|
* The overlay runtime is embedded inline via the `virtual:fimo-overlay-runtime`
|
|
39
38
|
* module (resolved by `overlayPlugin` in `fimo/vite`). The previous approach
|
|
@@ -41,8 +40,6 @@ function buildSiteSchemas() {
|
|
|
41
40
|
* since framework mode bypasses `index.html` entirely.
|
|
42
41
|
*/
|
|
43
42
|
export function FimoScripts() {
|
|
44
|
-
// @ts-ignore - import.meta.env is a Vite feature
|
|
45
|
-
const previewScriptUrl = import.meta.env.VITE_PREVIEW_SCRIPT_URL;
|
|
46
43
|
const siteSchemas = buildSiteSchemas();
|
|
47
|
-
return (_jsxs(_Fragment, { children: [runtime ? _jsx("script", { type: "module", dangerouslySetInnerHTML: { __html: runtime } }) : null,
|
|
44
|
+
return (_jsxs(_Fragment, { children: [runtime ? _jsx("script", { type: "module", dangerouslySetInnerHTML: { __html: runtime } }) : null, siteSchemas.map((schema, index) => (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(schema) } }, index)))] }));
|
|
48
45
|
}
|
|
@@ -22,7 +22,7 @@ export { Text } from '../react/primitives/editable/Text.js';
|
|
|
22
22
|
export { Video } from '../react/primitives/editable/Video.js';
|
|
23
23
|
export type { BoolOps, DateOps, Field, Fields, FilterFor, FimoPart, FimoPolymorphicReference, FimoReference, FimoRichTextContent, FimoSource, NullOnlyOps, NumberOps, Populate, Populated, PopulatedResult, Projected, ProjectedWithPopulate, Query, ReferenceField, ReferenceMap, ScalarOps, Sort, SortField, StringOps, Where, WithReferences, } from '../content/index.js';
|
|
24
24
|
export type { FimoRichTextComponents, FimoRichTextMarkProps, FimoRichTextNodeProps, } from '../react/primitives/contracts.js';
|
|
25
|
-
export {
|
|
26
|
-
export type {
|
|
25
|
+
export { FimoProvider, useLabels } from './provider.js';
|
|
26
|
+
export type { FimoProviderProps } from './provider.js';
|
|
27
27
|
export type { Labels, LabelsSnapshot } from '../labels/core.js';
|
|
28
28
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -22,4 +22,4 @@ export { RichText } from '../react/primitives/editable/RichText.js';
|
|
|
22
22
|
export { StaticImage } from '../react/primitives/renderers/StaticImage.js';
|
|
23
23
|
export { Text } from '../react/primitives/editable/Text.js';
|
|
24
24
|
export { Video } from '../react/primitives/editable/Video.js';
|
|
25
|
-
export {
|
|
25
|
+
export { FimoProvider, useLabels } from './provider.js';
|
|
@@ -8,11 +8,6 @@ export interface FimoProviderProps {
|
|
|
8
8
|
queryClient?: QueryClient;
|
|
9
9
|
}
|
|
10
10
|
export declare function FimoProvider({ children, labels, locale, queryClient }: FimoProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
-
export interface FimoPreviewBridgeProps {
|
|
12
|
-
readonly navigate: (to: string) => unknown;
|
|
13
|
-
readonly pathname: string;
|
|
14
|
-
}
|
|
15
|
-
export declare function FimoPreviewBridge({ navigate, pathname }: FimoPreviewBridgeProps): ReactNode;
|
|
16
11
|
export declare function useNextContentLocale(requestedLocale: string | undefined, defaultLocale: string): string;
|
|
17
12
|
export declare function useLabels(): Labels;
|
|
18
13
|
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
4
|
-
import {
|
|
4
|
+
import { useRouter as usePagesRouter } from 'next/compat/router.js';
|
|
5
|
+
import { usePathname } from 'next/navigation.js';
|
|
6
|
+
import { createContext, Suspense, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
5
7
|
import { createLabels } from '../labels/core.js';
|
|
8
|
+
import { ensurePreviewScript } from '../preview/script.js';
|
|
6
9
|
import { connectNextPreview } from './preview.js';
|
|
7
10
|
/**
|
|
8
11
|
* Last resort when an application renders `FimoProvider` without a locale and
|
|
@@ -16,13 +19,25 @@ export function FimoProvider({ children, labels, locale, queryClient }) {
|
|
|
16
19
|
const [client] = useState(() => queryClient ?? new QueryClient());
|
|
17
20
|
const activeLocale = locale?.trim() || labels?.locale;
|
|
18
21
|
const value = useMemo(() => ({ labels, locale: activeLocale }), [activeLocale, labels]);
|
|
19
|
-
|
|
22
|
+
const previewScriptUrl = process.env.NEXT_PUBLIC_FIMO_PREVIEW_SCRIPT_URL;
|
|
23
|
+
return (_jsx(FimoNextContext.Provider, { value: value, children: _jsxs(QueryClientProvider, { client: client, children: [previewScriptUrl ? (_jsx(Suspense, { fallback: null, children: _jsx(FimoPreviewRuntime, { previewScriptUrl: previewScriptUrl }) })) : null, children] }) }));
|
|
20
24
|
}
|
|
21
|
-
|
|
25
|
+
function FimoPreviewRuntime({ previewScriptUrl }) {
|
|
22
26
|
const context = useContext(FimoNextContext);
|
|
23
27
|
const locale = context.locale ?? UNRESOLVED_LOCALE;
|
|
24
|
-
const
|
|
25
|
-
|
|
28
|
+
const appPathname = usePathname();
|
|
29
|
+
const pagesRouter = usePagesRouter();
|
|
30
|
+
const pathname = appPathname ?? pagesRouter?.asPath.split(/[?#]/, 1)[0] ?? '/';
|
|
31
|
+
const navigate = useCallback((to) => {
|
|
32
|
+
if (pagesRouter) {
|
|
33
|
+
return pagesRouter.push(to);
|
|
34
|
+
}
|
|
35
|
+
window.history.pushState(null, '', to);
|
|
36
|
+
}, [pagesRouter]);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
ensurePreviewScript(previewScriptUrl);
|
|
39
|
+
return connectNextPreview({ locale, navigate, pathname, previewScriptUrl });
|
|
40
|
+
}, [locale, navigate, pathname, previewScriptUrl]);
|
|
26
41
|
return null;
|
|
27
42
|
}
|
|
28
43
|
export function useNextContentLocale(requestedLocale, defaultLocale) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Load the platform preview script once. Empty configuration keeps preview disabled. */
|
|
2
|
+
export function ensurePreviewScript(src, target = document) {
|
|
3
|
+
if (!src) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
const exists = Array.from(target.scripts).some((script) => script.getAttribute('src') === src);
|
|
7
|
+
if (!exists) {
|
|
8
|
+
const script = target.createElement('script');
|
|
9
|
+
script.src = src;
|
|
10
|
+
script.defer = true;
|
|
11
|
+
target.head.appendChild(script);
|
|
12
|
+
}
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
@@ -66,7 +66,13 @@ export interface RichTextProps extends Omit<ComponentPropsWithoutRef<'div'>, 'ch
|
|
|
66
66
|
value: FimoRichText | null | undefined;
|
|
67
67
|
components?: FimoRichTextComponents;
|
|
68
68
|
}
|
|
69
|
-
export type StaticImageProps = Omit<ComponentPropsWithoutRef<'img'>, 'children'> & {
|
|
69
|
+
export type StaticImageProps = Omit<ComponentPropsWithoutRef<'img'>, 'children' | 'src'> & {
|
|
70
|
+
/**
|
|
71
|
+
* Direct URL to the image. React's own `img` typings widened `src` to accept
|
|
72
|
+
* a Blob; this renderer resolves a URL through the optimizer, so it stays a
|
|
73
|
+
* string. Same reason `BaseVideoProps` omits `src`.
|
|
74
|
+
*/
|
|
75
|
+
src?: string;
|
|
70
76
|
/** Image quality (1-100). Defaults to 85. */
|
|
71
77
|
quality?: number;
|
|
72
78
|
/** Resize fit mode. Also maps to CSS object-fit. Defaults to 'scale-down'. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { ensurePreviewScript } from '../preview/script.js';
|
|
1
2
|
export interface PreviewNavigation {
|
|
2
3
|
/** SvelteKit `goto` — the app router stays in charge of the transition. */
|
|
3
4
|
goto: (to: string) => unknown;
|
|
@@ -6,8 +7,6 @@ export interface PreviewNavigation {
|
|
|
6
7
|
/** Optional app-owned locale resolver, evaluated for every bridge message. */
|
|
7
8
|
locale?: () => string | undefined;
|
|
8
9
|
}
|
|
9
|
-
/** Load the platform preview script once. Empty configuration keeps preview disabled. */
|
|
10
|
-
export declare function ensurePreviewScript(src: string | undefined): boolean;
|
|
11
10
|
/**
|
|
12
11
|
* Report where the app is now, and in which locale. Studio keeps its URL,
|
|
13
12
|
* route selector and content locale in sync from this.
|
|
@@ -1,18 +1,5 @@
|
|
|
1
1
|
import { getDocumentLocale, getPreviewLocationChange, getPreviewParentOrigin } from '../shared/preview-location.js';
|
|
2
|
-
|
|
3
|
-
export function ensurePreviewScript(src) {
|
|
4
|
-
if (!src) {
|
|
5
|
-
return false;
|
|
6
|
-
}
|
|
7
|
-
const exists = Array.from(document.scripts).some((script) => script.getAttribute('src') === src);
|
|
8
|
-
if (!exists) {
|
|
9
|
-
const script = document.createElement('script');
|
|
10
|
-
script.src = src;
|
|
11
|
-
script.defer = true;
|
|
12
|
-
document.head.appendChild(script);
|
|
13
|
-
}
|
|
14
|
-
return true;
|
|
15
|
-
}
|
|
2
|
+
export { ensurePreviewScript } from '../preview/script.js';
|
|
16
3
|
/**
|
|
17
4
|
* Report where the app is now, and in which locale. Studio keeps its URL,
|
|
18
5
|
* route selector and content locale in sync from this.
|
|
@@ -25,6 +25,23 @@ const SCHEMA_DEFINITION_SCHEMA = z.object({
|
|
|
25
25
|
i18n: z.object({ enabled: z.boolean().optional() }).optional(),
|
|
26
26
|
fields: z.record(z.string(), z.unknown()).optional(),
|
|
27
27
|
});
|
|
28
|
+
const RUNTIME_TYPE_IMPORT_ORDER = [
|
|
29
|
+
'Fields',
|
|
30
|
+
'FimoBoolean',
|
|
31
|
+
'FimoMedia',
|
|
32
|
+
'FimoPolymorphicReference',
|
|
33
|
+
'FimoReference',
|
|
34
|
+
'FimoRichText',
|
|
35
|
+
'FimoRichTextContent',
|
|
36
|
+
'FimoString',
|
|
37
|
+
'Populate',
|
|
38
|
+
'PopulatedResult',
|
|
39
|
+
'ProjectedWithPopulate',
|
|
40
|
+
'Query',
|
|
41
|
+
'Sort',
|
|
42
|
+
'Where',
|
|
43
|
+
'WithReferences',
|
|
44
|
+
];
|
|
28
45
|
const CONTENT_TEMPLATE_PATHS = {
|
|
29
46
|
types: { current: 'shared/types.eta', legacy: 'types-template.eta' },
|
|
30
47
|
sharedServer: { current: 'shared/server.eta' },
|
|
@@ -335,6 +352,69 @@ function referenceImportsFor(schema, fields) {
|
|
|
335
352
|
}
|
|
336
353
|
return [...imports.values()].sort((a, b) => a.pascal.localeCompare(b.pascal));
|
|
337
354
|
}
|
|
355
|
+
function collectFieldRuntimeTypeImports(field, imports) {
|
|
356
|
+
if (!field || typeof field !== 'object' || Array.isArray(field)) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const definition = field;
|
|
360
|
+
switch (definition.type) {
|
|
361
|
+
case 'boolean':
|
|
362
|
+
imports.add('FimoBoolean');
|
|
363
|
+
return;
|
|
364
|
+
case 'media':
|
|
365
|
+
imports.add('FimoMedia');
|
|
366
|
+
return;
|
|
367
|
+
case 'reference':
|
|
368
|
+
imports.add(Array.isArray(definition.targets) && definition.targets.length > 0
|
|
369
|
+
? 'FimoPolymorphicReference'
|
|
370
|
+
: 'FimoReference');
|
|
371
|
+
return;
|
|
372
|
+
case 'richtext':
|
|
373
|
+
imports.add('FimoRichText');
|
|
374
|
+
imports.add('FimoRichTextContent');
|
|
375
|
+
return;
|
|
376
|
+
case 'blocks': {
|
|
377
|
+
const schema = definition.schema;
|
|
378
|
+
if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const blockSchema = schema;
|
|
382
|
+
const fieldGroups = Array.isArray(blockSchema.oneOf)
|
|
383
|
+
? blockSchema.oneOf.map((variant) => variant && typeof variant === 'object' && !Array.isArray(variant)
|
|
384
|
+
? variant.fields
|
|
385
|
+
: undefined)
|
|
386
|
+
: [blockSchema.fields];
|
|
387
|
+
for (const fields of fieldGroups) {
|
|
388
|
+
if (!fields || typeof fields !== 'object' || Array.isArray(fields)) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
for (const nestedField of Object.values(fields)) {
|
|
392
|
+
collectFieldRuntimeTypeImports(nestedField, imports);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
default:
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function runtimeTypeImportsFor(fields) {
|
|
402
|
+
const imports = new Set([
|
|
403
|
+
'Fields',
|
|
404
|
+
'FimoString',
|
|
405
|
+
'Populate',
|
|
406
|
+
'PopulatedResult',
|
|
407
|
+
'ProjectedWithPopulate',
|
|
408
|
+
'Query',
|
|
409
|
+
'Sort',
|
|
410
|
+
'Where',
|
|
411
|
+
'WithReferences',
|
|
412
|
+
]);
|
|
413
|
+
for (const field of Object.values(fields)) {
|
|
414
|
+
collectFieldRuntimeTypeImports(field, imports);
|
|
415
|
+
}
|
|
416
|
+
return RUNTIME_TYPE_IMPORT_ORDER.filter((typeImport) => imports.has(typeImport));
|
|
417
|
+
}
|
|
338
418
|
function schemaToModel(schema, localizedByUid) {
|
|
339
419
|
const fields = normalizeFields(schema.fields ?? {});
|
|
340
420
|
return {
|
|
@@ -353,6 +433,7 @@ function schemaToModel(schema, localizedByUid) {
|
|
|
353
433
|
.map(([fieldName]) => fieldName),
|
|
354
434
|
fields,
|
|
355
435
|
referenceImports: referenceImportsFor(schema, fields),
|
|
436
|
+
runtimeTypeImports: runtimeTypeImportsFor(fields),
|
|
356
437
|
};
|
|
357
438
|
}
|
|
358
439
|
export function syncSchemas(options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fimo",
|
|
3
|
-
"version": "0.21.0-staging.
|
|
3
|
+
"version": "0.21.0-staging.3",
|
|
4
4
|
"description": "Fimo CLI - create, deploy, and manage Fimo projects",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fimo": "dist/cli/index.js"
|
|
@@ -168,6 +168,7 @@
|
|
|
168
168
|
"better-auth": "1.6.25",
|
|
169
169
|
"cheerio": "^1.0.0",
|
|
170
170
|
"commander": "^13.1.0",
|
|
171
|
+
"next": "15.5.20",
|
|
171
172
|
"open": "^10.1.2",
|
|
172
173
|
"react": "^19.2.4",
|
|
173
174
|
"react-dom": "^19.2.4",
|
|
@@ -183,6 +184,7 @@
|
|
|
183
184
|
"@sveltejs/kit": "^2.0.0",
|
|
184
185
|
"@tanstack/react-query": "^5.80.6",
|
|
185
186
|
"astro": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
187
|
+
"next": "^15.0.0 || ^16.0.0",
|
|
186
188
|
"react": "^18.2.0 || ^19.0.0",
|
|
187
189
|
"react-dom": "^18.2.0 || ^19.0.0",
|
|
188
190
|
"react-router": "^7.0.0 || ^8.0.0",
|
|
@@ -199,6 +201,9 @@
|
|
|
199
201
|
"astro": {
|
|
200
202
|
"optional": true
|
|
201
203
|
},
|
|
204
|
+
"next": {
|
|
205
|
+
"optional": true
|
|
206
|
+
},
|
|
202
207
|
"react": {
|
|
203
208
|
"optional": true
|
|
204
209
|
},
|
|
@@ -27,7 +27,7 @@ a code-only task, or use `npx fimo@latest` for project-local code generation and
|
|
|
27
27
|
## Project rules
|
|
28
28
|
|
|
29
29
|
- **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
|
|
30
|
-
-
|
|
30
|
+
- Use the selected package manager's committed build-script policy. pnpm projects pin `pnpm@10.26.0` and approve `esbuild` and `fimo` through `pnpm-workspace.yaml#allowBuilds`; Bun projects trust the same packages through `package.json#trustedDependencies`. Run a plain install with the selected manager so local installation matches Preview and production publishing. Review new dependencies before extending the policy; all three paths stop on unreviewed scripts.
|
|
31
31
|
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`. If no language is requested, keep `en` and state that choice. Astro reads this configuration directly, keeps the default locale unprefixed, and prefixes the others.
|
|
32
32
|
- Preserve both the unprefixed default pages and the `[locale]` page tree. Astro has no optional single-segment file route, so the paired native pages keep one-locale URLs clean and allow another locale without changing the route shape. Use `Astro.currentLocale` for Fimo content reads, `getLabels`, and document language.
|
|
33
33
|
- Keep `.fimo/config.json#routes` as Studio metadata aligned with Astro's page files. It does not configure Astro routing.
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# Keep dependency-script decisions explicit across local, Preview, and production installs.
|
|
2
|
+
|
|
3
|
+
strictDepBuilds: true
|
|
4
|
+
allowBuilds:
|
|
5
|
+
esbuild: true
|
|
6
|
+
fimo: true
|
|
3
7
|
|
|
4
8
|
packages: []
|
|
@@ -35,24 +35,14 @@ The scaffolded homepage is disposable. Replace it on the first real generation.
|
|
|
35
35
|
## Project rules
|
|
36
36
|
|
|
37
37
|
- **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
|
|
38
|
-
-
|
|
39
|
-
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`, with every requested locale in `i18n.locales`. If no language is requested, keep `en` and state that choice. That file is the only place to change: `src/locales.ts` reads it, so the served language
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
- Keep `.fimo/config.json#routes` as Studio metadata, not as the Next.js router.
|
|
38
|
+
- Use the selected package manager's committed build-script policy. pnpm projects pin `pnpm@10.26.0` and approve `esbuild` and `fimo` through `pnpm-workspace.yaml#allowBuilds`; Bun projects trust the same packages through `package.json#trustedDependencies`. Run a plain install with the selected manager so local installation matches Preview and production publishing. Review new dependencies before extending the policy; all three paths stop on unreviewed scripts.
|
|
39
|
+
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`, with every requested locale in `i18n.locales`. If no language is requested, keep `en` and state that choice. That file is the only place to change: `src/locales.ts` reads it, so the served language and `<html lang>` follow. It does not create locale URLs; implement a URL strategy only when the product asks for one. Never introduce a default-locale environment variable.
|
|
40
|
+
- Next's `app` tree is the router and stays authoritative: the starter is one ordinary root layout plus `/` as the homepage, and unknown paths get Next's native 404. When a product requires locale URLs, implement the framework-native strategy (`[locale]` segments, middleware, cookies, domains, or an i18n library), pass the resolved locale into Fimo server reads and `FimoProvider`, and load `fimo skills get fimo-code --ref frameworks/next/locales` first. Do not impose locale-prefixed URLs on a default-only project.
|
|
41
|
+
- `FimoProvider` owns the optional Studio preview runtime. Do not add a preview bridge component, read Fimo preview environment variables, or inject Fimo scripts in application code.
|
|
42
|
+
- Keep `.fimo/config.json#routes` as Studio metadata, not as the Next.js router. Describe only URLs the application actually serves; add a `:locale` segment to a route's metadata only after the application implements that locale routing. There, `params.locale.optional: true` means omit the configured default locale from the URL; use `optional: false` only when every locale, including the default, must be prefixed.
|
|
43
43
|
- The application owns routes, locale resolution, links, HTML language/direction, and SEO. Fimo connects to those decisions.
|
|
44
44
|
- Do not add a second deployment platform.
|
|
45
45
|
- Never edit `.fimo/project.json`; it links this directory to the remote project.
|
|
46
46
|
- Keep `.fimo/config.json#runtime` true to the code: framework, `dev`/`build`/`install` commands, output directory. Update it when you rename a package script, move the build output, or change framework; the reference is `fimo skills get fimo-code --ref frameworks/hosting`.
|
|
47
47
|
- Keep secrets in the Fimo dashboard, not in committed environment files.
|
|
48
48
|
- Pass flags to interactive Fimo commands when scripting them.
|
|
49
|
-
|
|
50
|
-
<!-- BEGIN:nextjs-agent-rules -->
|
|
51
|
-
|
|
52
|
-
# This is NOT the Next.js you know
|
|
53
|
-
|
|
54
|
-
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
|
|
55
|
-
|
|
56
|
-
This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
|
|
57
|
-
|
|
58
|
-
<!-- END:nextjs-agent-rules -->
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# Keep dependency-script decisions explicit across local, Preview, and production installs.
|
|
2
|
+
|
|
3
|
+
strictDepBuilds: true
|
|
4
|
+
allowBuilds:
|
|
5
|
+
esbuild: true
|
|
6
|
+
fimo: true
|
|
3
7
|
|
|
4
8
|
packages: []
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FimoProvider } from 'fimo/next/client';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { defaultLocale } from '../locales';
|
|
5
|
+
|
|
6
|
+
import './globals.css';
|
|
7
|
+
|
|
8
|
+
export default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {
|
|
9
|
+
return (
|
|
10
|
+
<html lang={defaultLocale}>
|
|
11
|
+
<body>
|
|
12
|
+
<FimoProvider locale={defaultLocale}>{children}</FimoProvider>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -3,11 +3,8 @@ import fimoConfig from '../.fimo/config.json';
|
|
|
3
3
|
/**
|
|
4
4
|
* Locale policy read from the same file Fimo and Studio read, so the site
|
|
5
5
|
* language cannot drift from the project configuration. Change the locales in
|
|
6
|
-
* `.fimo/config.json#i18n`; nothing here needs editing.
|
|
6
|
+
* `.fimo/config.json#i18n`; nothing here needs editing. Configured locales are
|
|
7
|
+
* content configuration only — URL locale routing is a separate application
|
|
8
|
+
* decision implemented in the `app` tree when the product asks for it.
|
|
7
9
|
*/
|
|
8
10
|
export const defaultLocale: string = fimoConfig.i18n.defaultLocale;
|
|
9
|
-
|
|
10
|
-
/** Only non-default locales carry a URL prefix; the default locale stays at the site root. */
|
|
11
|
-
export const prefixedLocales: ReadonlySet<string> = new Set(
|
|
12
|
-
fimoConfig.i18n.locales.filter((locale) => locale !== defaultLocale)
|
|
13
|
-
);
|
|
@@ -40,7 +40,7 @@ breaks that. Load `fimo-code` for the exact primitives, but the rule is:
|
|
|
40
40
|
## Project rules
|
|
41
41
|
|
|
42
42
|
- **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
|
|
43
|
-
-
|
|
43
|
+
- Use the selected package manager's committed build-script policy. pnpm projects pin `pnpm@10.26.0` and approve `esbuild` and `fimo` through `pnpm-workspace.yaml#allowBuilds`; Bun projects trust the same packages through `package.json#trustedDependencies`. Run a plain install with the selected manager so local installation matches Preview and production publishing. Review new dependencies before extending the policy; all three paths stop on unreviewed scripts.
|
|
44
44
|
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`. If no language is requested, keep `en` and state that choice.
|
|
45
45
|
- Preserve the application-owned `:locale?` route boundary in `src/routes.ts` and pass its route parameter to `FimoProviders` in `LocaleLayout.tsx`. The missing parameter uses the configured default, so a one-locale site stays at `/`. Add locales in `.fimo/config.json` without rebuilding the route tree; use `:locale` without `?` only when every locale must be prefixed.
|
|
46
46
|
- Keep `.fimo/config.json#routes` aligned as Studio metadata, not as the React Router source of truth. Do not add a global locale-routing strategy, a Fimo route helper, or a Fimo-owned route tree.
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"cmdk": "^1.1.1",
|
|
22
22
|
"date-fns": "^4.1.0",
|
|
23
23
|
"embla-carousel-react": "^8.6.0",
|
|
24
|
-
"fimo": "0.21.0-staging.
|
|
24
|
+
"fimo": "0.21.0-staging.3",
|
|
25
25
|
"input-otp": "^1.4.2",
|
|
26
26
|
"isbot": "^5",
|
|
27
27
|
"lucide-react": "^0.577.0",
|
|
@@ -55,5 +55,6 @@
|
|
|
55
55
|
},
|
|
56
56
|
"engines": {
|
|
57
57
|
"node": ">=22.22.0"
|
|
58
|
-
}
|
|
58
|
+
},
|
|
59
|
+
"packageManager": "pnpm@10.26.0"
|
|
59
60
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
# Keep dependency-script decisions explicit across local, Preview, and production installs.
|
|
2
|
+
|
|
3
|
+
strictDepBuilds: true
|
|
4
|
+
allowBuilds:
|
|
5
|
+
esbuild: true
|
|
6
|
+
fimo: true
|
|
7
7
|
|
|
8
8
|
packages: []
|
|
@@ -27,7 +27,7 @@ a code-only task, or use `npx fimo@latest` for project-local code generation and
|
|
|
27
27
|
## Project rules
|
|
28
28
|
|
|
29
29
|
- **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
|
|
30
|
-
-
|
|
30
|
+
- Use the selected package manager's committed build-script policy. pnpm projects pin `pnpm@10.26.0` and approve `esbuild` and `fimo` through `pnpm-workspace.yaml#allowBuilds`; Bun projects trust the same packages through `package.json#trustedDependencies`. Run a plain install with the selected manager so local installation matches Preview and production publishing. Review new dependencies before extending the policy; all three paths stop on unreviewed scripts.
|
|
31
31
|
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`. If no language is requested, keep `en` and state that choice. `src/locales.ts` derives the default and prefixed locale set from that config.
|
|
32
32
|
- Preserve the native `[[locale=locale]]` route boundary. The optional parameter keeps the default locale at `/`; the matcher prevents ordinary top-level routes from being mistaken for locales. The root server layout passes the tracked `event.params` through `resolveLocale`, then sends that locale to `getLabels` and `FimoProvider`. Remove the extra brackets only when every locale must be prefixed.
|
|
33
33
|
- Keep the document language request-aware: `src/hooks.server.ts` renders the initial `<html lang>`, and the root layout updates it after client navigation.
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# Keep dependency-script decisions explicit across local, Preview, and production installs.
|
|
2
|
+
|
|
3
|
+
strictDepBuilds: true
|
|
4
|
+
allowBuilds:
|
|
5
|
+
esbuild: true
|
|
6
|
+
fimo: true
|
|
3
7
|
|
|
4
8
|
packages: []
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
import Document from '../../components/Document';
|
|
4
|
-
import { defaultLocale } from '../../locales';
|
|
5
|
-
|
|
6
|
-
import '../globals.css';
|
|
7
|
-
|
|
8
|
-
export default function DefaultLocaleLayout({ children }: Readonly<{ children: ReactNode }>) {
|
|
9
|
-
return <Document locale={defaultLocale}>{children}</Document>;
|
|
10
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { notFound } from 'next/navigation';
|
|
2
|
-
import type { ReactNode } from 'react';
|
|
3
|
-
|
|
4
|
-
import Document from '../../components/Document';
|
|
5
|
-
import { prefixedLocales } from '../../locales';
|
|
6
|
-
|
|
7
|
-
import '../globals.css';
|
|
8
|
-
|
|
9
|
-
export default async function LocaleLayout({
|
|
10
|
-
children,
|
|
11
|
-
params,
|
|
12
|
-
}: Readonly<{ children: ReactNode; params: Promise<{ locale: string }> }>) {
|
|
13
|
-
const { locale } = await params;
|
|
14
|
-
|
|
15
|
-
// The default locale is served unprefixed by `app/(default)`, so its prefix
|
|
16
|
-
// is not a second URL for the same page.
|
|
17
|
-
if (!prefixedLocales.has(locale)) {
|
|
18
|
-
notFound();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return <Document locale={locale}>{children}</Document>;
|
|
22
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from '../(default)/page';
|