fimo 2.3.2 → 2.4.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/assets/skills/fimo-cli/SKILL.md +1 -1
- package/assets/skills/fimo-cli/references/deploy.md +8 -11
- package/assets/skills/fimo-cli/references/init.md +1 -1
- package/assets/skills/fimo-cli/references/integrations/firecrawl.md +1 -1
- package/assets/skills/fimo-cli/references/preview.md +12 -42
- package/assets/skills/fimo-code/references/frameworks/next/app-router.md +7 -21
- package/assets/skills/fimo-code/references/frameworks/next/seo.md +168 -0
- package/assets/skills/fimo-code/references/frameworks/next.md +1 -1
- package/assets/skills/fimo-migration/SKILL.md +29 -33
- package/assets/skills/fimo-migration/references/content.md +1 -1
- package/assets/skills/fimo-migration/references/frameworks/nextjs.md +7 -0
- package/assets/skills/fimo-migration/references/import-contract.md +4 -6
- package/assets/skills/fimo-migration/references/manifest.md +4 -3
- package/assets/skills/fimo-migration/references/questions-and-improvements.md +1 -1
- package/assets/skills/fimo-migration/references/workflow.md +7 -5
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +494 -981
- package/dist/runtime/seo/index.d.ts +1 -0
- package/dist/runtime/seo/resolver.js +10 -0
- package/dist/runtime/seo/server.d.ts +13 -0
- package/dist/runtime/seo/server.js +23 -0
- package/dist/runtime/shared/fimo-config.server.d.ts +2 -0
- package/dist/runtime/shared/fimo-config.server.js +18 -14
- package/package.json +12 -8
- package/release.json +2 -2
- package/templates/astro/package.json +2 -2
- package/templates/nextjs/AGENTS.md +1 -1
- package/templates/nextjs/package.json +3 -3
- package/templates/nextjs/src/app/layout.tsx +5 -3
- package/templates/nextjs/src/app/page.tsx +6 -0
- package/templates/react-router/package.json +4 -4
- package/templates/sveltekit/package.json +2 -2
- package/templates/vite/package.json +4 -4
- package/assets/skills/fimo-migration/scripts/build-canonical-manifest.mjs +0 -595
|
@@ -86,6 +86,16 @@ export function resolveTemplate(template, context) {
|
|
|
86
86
|
}
|
|
87
87
|
function resolveSeoField(routeValue, globalValue, context) {
|
|
88
88
|
if (routeValue) {
|
|
89
|
+
for (const token of routeValue.matchAll(/\{\{([^}]+)\}\}/g)) {
|
|
90
|
+
const raw = getNestedValue(context, token[1].trim());
|
|
91
|
+
const value = raw instanceof String || raw instanceof Number || raw instanceof Boolean ? raw.valueOf() : raw;
|
|
92
|
+
if (value == null ||
|
|
93
|
+
(typeof value === 'string' && value.trim() === '') ||
|
|
94
|
+
!['string', 'number', 'boolean'].includes(typeof value) ||
|
|
95
|
+
(typeof value === 'number' && !Number.isFinite(value))) {
|
|
96
|
+
return globalValue;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
89
99
|
return resolveTemplate(routeValue, context);
|
|
90
100
|
}
|
|
91
101
|
return globalValue;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FimoSEO } from '../shared/fimo-config.types.js';
|
|
2
|
+
export interface GetFimoSeoOptions {
|
|
3
|
+
pathname?: string;
|
|
4
|
+
routeData?: Record<string, unknown>;
|
|
5
|
+
rootDir?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Read global SEO, or resolve an explicit pathname against the project's route
|
|
9
|
+
* catalog. Node only. Missing config/SEO returns undefined; other read and JSON
|
|
10
|
+
* errors propagate. No cache: rendering/revalidation remains application-owned.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getFimoSeo({ pathname, routeData, rootDir }?: GetFimoSeoOptions): FimoSEO | undefined;
|
|
13
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readConfigServer } from '../shared/fimo-config.server.js';
|
|
2
|
+
import { resolveSeoForPath } from './resolver.js';
|
|
3
|
+
/**
|
|
4
|
+
* Read global SEO, or resolve an explicit pathname against the project's route
|
|
5
|
+
* catalog. Node only. Missing config/SEO returns undefined; other read and JSON
|
|
6
|
+
* errors propagate. No cache: rendering/revalidation remains application-owned.
|
|
7
|
+
*/
|
|
8
|
+
export function getFimoSeo({ pathname, routeData, rootDir = process.cwd() } = {}) {
|
|
9
|
+
let config;
|
|
10
|
+
try {
|
|
11
|
+
config = readConfigServer(rootDir);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
if (pathname !== undefined) {
|
|
20
|
+
return resolveSeoForPath(pathname, config, routeData);
|
|
21
|
+
}
|
|
22
|
+
return config.seo && Object.keys(config.seo).length > 0 ? config.seo : undefined;
|
|
23
|
+
}
|
|
@@ -4,6 +4,8 @@ import type { FimoConfig } from './fimo-config.types.js';
|
|
|
4
4
|
* Reads JSON directly to avoid virtual module issues during config loading.
|
|
5
5
|
*/
|
|
6
6
|
export declare function getConfigServer(rootDir: string): FimoConfig;
|
|
7
|
+
/** Read the selected config without swallowing I/O or JSON errors. */
|
|
8
|
+
export declare function readConfigServer(rootDir: string): FimoConfig;
|
|
7
9
|
export declare function getConfigVersion(rootDir: string): number;
|
|
8
10
|
/** Resolve the current config path while keeping legacy projects readable. */
|
|
9
11
|
export declare function resolveFimoConfigPath(rootDir: string): string;
|
|
@@ -13,25 +13,29 @@ const defaultConfig = {
|
|
|
13
13
|
*/
|
|
14
14
|
export function getConfigServer(rootDir) {
|
|
15
15
|
try {
|
|
16
|
-
|
|
17
|
-
const content = readFileSync(configPath, 'utf-8');
|
|
18
|
-
// `fimo validate` owns strict config validation. The public runtime only
|
|
19
|
-
// reads the already-validated values and must stay self-contained: importing
|
|
20
|
-
// the repository-private API contracts package would break installed apps.
|
|
21
|
-
const raw = JSON.parse(content);
|
|
22
|
-
return {
|
|
23
|
-
runtime: raw.runtime,
|
|
24
|
-
hosting: raw.hosting,
|
|
25
|
-
seo: raw.seo,
|
|
26
|
-
i18n: raw.i18n,
|
|
27
|
-
routes: raw.routes,
|
|
28
|
-
version: raw.version,
|
|
29
|
-
};
|
|
16
|
+
return readConfigServer(rootDir);
|
|
30
17
|
}
|
|
31
18
|
catch {
|
|
32
19
|
return defaultConfig;
|
|
33
20
|
}
|
|
34
21
|
}
|
|
22
|
+
/** Read the selected config without swallowing I/O or JSON errors. */
|
|
23
|
+
export function readConfigServer(rootDir) {
|
|
24
|
+
const configPath = resolveFimoConfigPath(rootDir);
|
|
25
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
26
|
+
// `fimo validate` owns strict config validation. The public runtime only
|
|
27
|
+
// reads the already-validated values and must stay self-contained: importing
|
|
28
|
+
// the repository-private API contracts package would break installed apps.
|
|
29
|
+
const raw = JSON.parse(content);
|
|
30
|
+
return {
|
|
31
|
+
runtime: raw.runtime,
|
|
32
|
+
hosting: raw.hosting,
|
|
33
|
+
seo: raw.seo,
|
|
34
|
+
i18n: raw.i18n,
|
|
35
|
+
routes: raw.routes,
|
|
36
|
+
version: raw.version,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
35
39
|
export function getConfigVersion(rootDir) {
|
|
36
40
|
try {
|
|
37
41
|
const configPath = resolveFimoConfigPath(rootDir);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fimo",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0-staging.2",
|
|
4
4
|
"description": "Fimo CLI - create, deploy, and manage Fimo projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro-component"
|
|
@@ -57,6 +57,10 @@
|
|
|
57
57
|
"types": "./dist/runtime/seo/index.d.ts",
|
|
58
58
|
"import": "./dist/runtime/seo/index.js"
|
|
59
59
|
},
|
|
60
|
+
"./seo/server": {
|
|
61
|
+
"types": "./dist/runtime/seo/server.d.ts",
|
|
62
|
+
"import": "./dist/runtime/seo/server.js"
|
|
63
|
+
},
|
|
60
64
|
"./sync": {
|
|
61
65
|
"types": "./dist/scripts/index.d.ts",
|
|
62
66
|
"import": "./dist/scripts/index.js"
|
|
@@ -189,13 +193,13 @@
|
|
|
189
193
|
"devDependencies": {
|
|
190
194
|
"@clack/core": "^1.2.0",
|
|
191
195
|
"@clack/prompts": "^1.2.0",
|
|
192
|
-
"@fimo/agents-bundle": "2.
|
|
193
|
-
"@fimo/api-contracts": "2.
|
|
194
|
-
"@fimo/cli-kit": "2.
|
|
195
|
-
"@fimo/framework-detect": "2.
|
|
196
|
-
"@fimo/routes": "2.
|
|
197
|
-
"@fimo/sdk": "2.
|
|
198
|
-
"@fimo/tsconfig": "2.
|
|
196
|
+
"@fimo/agents-bundle": "2.4.0-staging.2",
|
|
197
|
+
"@fimo/api-contracts": "2.4.0-staging.2",
|
|
198
|
+
"@fimo/cli-kit": "2.4.0-staging.2",
|
|
199
|
+
"@fimo/framework-detect": "2.4.0-staging.2",
|
|
200
|
+
"@fimo/routes": "2.4.0-staging.2",
|
|
201
|
+
"@fimo/sdk": "2.4.0-staging.2",
|
|
202
|
+
"@fimo/tsconfig": "2.4.0-staging.2",
|
|
199
203
|
"@types/node": "22.18.6",
|
|
200
204
|
"agent-install": "^0.0.5",
|
|
201
205
|
"astro": "^7.1.6",
|
package/release.json
CHANGED
|
@@ -40,7 +40,7 @@ The scaffolded homepage is disposable. Replace it on the first real generation.
|
|
|
40
40
|
- Next's `app` tree is the router and stays authoritative: the default shell 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
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
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
|
-
- The application owns
|
|
43
|
+
- The application owns SEO policy. Keep the root's global SEO wiring and the homepage's explicit route wiring. When creating or adding a page, load `fimo skills get fimo-code --ref frameworks/next/seo` and reuse the established route pattern. Resolve the real pathname and content in that route module; add route viewport wiring only for route-specific theme color. Preserve app-owned metadata and file-based images; Next replaces nested metadata objects rather than merging their fields.
|
|
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`.
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@tanstack/react-query": "^5.80.6",
|
|
15
|
-
"fimo": "2.
|
|
16
|
-
"fimo-next": "2.
|
|
17
|
-
"fimo-react": "2.
|
|
15
|
+
"fimo": "2.4.0-staging.2",
|
|
16
|
+
"fimo-next": "2.4.0-staging.2",
|
|
17
|
+
"fimo-react": "2.4.0-staging.2",
|
|
18
18
|
"next": "^16.3.3",
|
|
19
19
|
"react": "^19.2.7",
|
|
20
20
|
"react-dom": "^19.2.7"
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { FimoProvider
|
|
1
|
+
import { FimoProvider } from 'fimo-next';
|
|
2
|
+
import { toNextMetadata, toNextViewport } from 'fimo-next/seo';
|
|
3
|
+
import { getFimoSeo } from 'fimo/seo/server';
|
|
2
4
|
import type { ReactNode } from 'react';
|
|
3
5
|
|
|
4
6
|
import { defaultLocale } from '../locales';
|
|
5
7
|
|
|
6
8
|
import './globals.css';
|
|
7
9
|
|
|
8
|
-
export const generateMetadata = () =>
|
|
9
|
-
export const generateViewport = () =>
|
|
10
|
+
export const generateMetadata = () => toNextMetadata(getFimoSeo());
|
|
11
|
+
export const generateViewport = () => toNextViewport(getFimoSeo());
|
|
10
12
|
|
|
11
13
|
export default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {
|
|
12
14
|
return (
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { toNextMetadata, toNextViewport } from 'fimo-next/seo';
|
|
2
|
+
import { getFimoSeo } from 'fimo/seo/server';
|
|
3
|
+
|
|
4
|
+
export const generateMetadata = () => toNextMetadata(getFimoSeo({ pathname: '/' }));
|
|
5
|
+
export const generateViewport = () => toNextViewport(getFimoSeo({ pathname: '/' }));
|
|
6
|
+
|
|
1
7
|
export default function HomePage() {
|
|
2
8
|
return (
|
|
3
9
|
<div className="starter">
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"cn": "0.2.4",
|
|
22
22
|
"date-fns": "^4.1.0",
|
|
23
23
|
"embla-carousel-react": "^8.6.0",
|
|
24
|
-
"fimo": "2.
|
|
25
|
-
"fimo-react": "2.
|
|
26
|
-
"fimo-react-router": "2.
|
|
27
|
-
"fimo-vite": "2.
|
|
24
|
+
"fimo": "2.4.0-staging.2",
|
|
25
|
+
"fimo-react": "2.4.0-staging.2",
|
|
26
|
+
"fimo-react-router": "2.4.0-staging.2",
|
|
27
|
+
"fimo-vite": "2.4.0-staging.2",
|
|
28
28
|
"input-otp": "^1.4.2",
|
|
29
29
|
"isbot": "^5",
|
|
30
30
|
"lucide-react": "^0.577.0",
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@tanstack/react-query": "^5.80.6",
|
|
14
|
-
"fimo": "2.
|
|
15
|
-
"fimo-react": "2.
|
|
16
|
-
"fimo-react-router": "2.
|
|
17
|
-
"fimo-vite": "2.
|
|
14
|
+
"fimo": "2.4.0-staging.2",
|
|
15
|
+
"fimo-react": "2.4.0-staging.2",
|
|
16
|
+
"fimo-react-router": "2.4.0-staging.2",
|
|
17
|
+
"fimo-vite": "2.4.0-staging.2",
|
|
18
18
|
"react": "^19.2.7",
|
|
19
19
|
"react-dom": "^19.2.7",
|
|
20
20
|
"react-router": "^8.3.0"
|