fimo 2.8.0 → 2.9.0-staging.1
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/references/branches.md +5 -2
- package/assets/skills/fimo-cli/references/hosting.md +22 -22
- package/assets/skills/fimo-code/references/frameworks/next.md +1 -10
- package/assets/skills/fimo-migration/references/frameworks/nextjs.md +1 -22
- package/assets/skills/fimo-migration/references/qa.md +1 -11
- package/assets/skills/fimo-studio/references/ai-chat.md +9 -3
- package/assets/skills/fimo-studio/references/preview-and-responsive.md +1 -0
- package/dist/build/astro/config.js +32 -1
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +78 -74
- package/dist/runtime/preview/frame-headers.d.ts +14 -0
- package/dist/runtime/preview/frame-headers.js +96 -0
- package/dist/runtime/preview/index.d.ts +1 -0
- package/dist/runtime/preview/index.js +1 -0
- package/package.json +8 -8
- package/release.json +2 -2
- package/templates/astro/package.json +3 -3
- package/templates/nextjs/package.json +5 -5
- package/templates/react-router/package.json +5 -5
- package/templates/sveltekit/package.json +3 -3
- package/templates/vite/package.json +5 -5
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface ResponseHeader {
|
|
2
|
+
key: string;
|
|
3
|
+
value: string;
|
|
4
|
+
}
|
|
5
|
+
/** Adapt only framing headers, retaining the response stream, status and cookies. */
|
|
6
|
+
export declare function adaptPreviewFrameResponse(response: Response, studioOrigin?: string): Response;
|
|
7
|
+
/** FIMO-2872: Providers apply matching rules in order, with the last header winning. */
|
|
8
|
+
export declare function adaptPreviewFrameHeaderRules<T extends {
|
|
9
|
+
headers: ResponseHeader[];
|
|
10
|
+
}>(rules: T[], studioOrigin?: string): T[];
|
|
11
|
+
/** FIMO-2872: Only an explicit platform-supplied Studio origin enables adaptation. */
|
|
12
|
+
export declare function adaptPreviewFrameHeaders(headers: ResponseHeader[], studioOrigin?: string, requireAncestors?: boolean): ResponseHeader[];
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=frame-headers.d.ts.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** Adapt only framing headers, retaining the response stream, status and cookies. */
|
|
2
|
+
export function adaptPreviewFrameResponse(response, studioOrigin) {
|
|
3
|
+
const original = [...response.headers].map(([key, value]) => ({ key, value }));
|
|
4
|
+
const adapted = adaptPreviewFrameHeaders(original, studioOrigin);
|
|
5
|
+
if (adapted.length === original.length && adapted.every((header, i) => header === original[i]))
|
|
6
|
+
return response;
|
|
7
|
+
const headers = new Headers(response.headers);
|
|
8
|
+
headers.delete('x-frame-options');
|
|
9
|
+
for (const header of adapted) {
|
|
10
|
+
if (header.key.toLowerCase() === 'content-security-policy')
|
|
11
|
+
headers.set(header.key, header.value);
|
|
12
|
+
}
|
|
13
|
+
return new Response(response.body, { status: response.status, statusText: response.statusText, headers });
|
|
14
|
+
}
|
|
15
|
+
/** FIMO-2872: Providers apply matching rules in order, with the last header winning. */
|
|
16
|
+
export function adaptPreviewFrameHeaderRules(rules, studioOrigin) {
|
|
17
|
+
const hasFrameOptions = rules.some((rule) => rule.headers.some((header) => header.key.toLowerCase() === 'x-frame-options'));
|
|
18
|
+
const defaults = [];
|
|
19
|
+
const adapted = rules.map((rule) => {
|
|
20
|
+
const hasPolicy = rule.headers.some((header) => header.key.toLowerCase() === 'content-security-policy');
|
|
21
|
+
const headers = adaptPreviewFrameHeaders(rule.headers, studioOrigin, hasFrameOptions && hasPolicy);
|
|
22
|
+
if (headers === rule.headers)
|
|
23
|
+
return rule;
|
|
24
|
+
if (!hasPolicy) {
|
|
25
|
+
const policy = headers.find((header) => header.key.toLowerCase() === 'content-security-policy');
|
|
26
|
+
if (policy) {
|
|
27
|
+
// A synthesized framing-only policy must never overwrite an application's
|
|
28
|
+
// resource policy from another matching rule. Keep its original conditions.
|
|
29
|
+
defaults.push({ ...rule, headers: [policy] });
|
|
30
|
+
return { ...rule, headers: headers.filter((header) => header !== policy) };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { ...rule, headers };
|
|
34
|
+
});
|
|
35
|
+
return [...defaults, ...adapted.filter((rule) => rule.headers.length > 0)];
|
|
36
|
+
}
|
|
37
|
+
/** FIMO-2872: Only an explicit platform-supplied Studio origin enables adaptation. */
|
|
38
|
+
export function adaptPreviewFrameHeaders(headers, studioOrigin, requireAncestors = false) {
|
|
39
|
+
if (!studioOrigin)
|
|
40
|
+
return headers;
|
|
41
|
+
let origin;
|
|
42
|
+
try {
|
|
43
|
+
const url = new URL(studioOrigin);
|
|
44
|
+
if (!['http:', 'https:'].includes(url.protocol) ||
|
|
45
|
+
url.username ||
|
|
46
|
+
url.password ||
|
|
47
|
+
url.pathname !== '/' ||
|
|
48
|
+
url.search ||
|
|
49
|
+
url.hash ||
|
|
50
|
+
!/^(?:[a-z\d.-]+|\[[a-f\d:]+\])$/i.test(url.hostname))
|
|
51
|
+
return headers;
|
|
52
|
+
origin = url.origin;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return headers;
|
|
56
|
+
}
|
|
57
|
+
const frameOptions = headers.filter((header) => header.key.toLowerCase() === 'x-frame-options');
|
|
58
|
+
let hasAncestors = false;
|
|
59
|
+
const adapted = headers
|
|
60
|
+
.filter((header) => header.key.toLowerCase() !== 'x-frame-options')
|
|
61
|
+
.map((header) => {
|
|
62
|
+
if (header.key.toLowerCase() !== 'content-security-policy')
|
|
63
|
+
return header;
|
|
64
|
+
// Every enforcing policy applies. Keep non-framing directives verbatim,
|
|
65
|
+
// including nonces, hashes and resource allowlists.
|
|
66
|
+
const value = header.value
|
|
67
|
+
.split(',')
|
|
68
|
+
.map((policy) => policy
|
|
69
|
+
.split(';')
|
|
70
|
+
.map((directive) => {
|
|
71
|
+
const [name, ...sources] = directive.trim().split(/\s+/);
|
|
72
|
+
if (name?.toLowerCase() !== 'frame-ancestors')
|
|
73
|
+
return directive;
|
|
74
|
+
hasAncestors = true;
|
|
75
|
+
if (sources.includes(origin) && !sources.includes("'none'"))
|
|
76
|
+
return directive;
|
|
77
|
+
return `frame-ancestors ${[...new Set([...sources.filter((source) => source !== "'none'"), origin])].join(' ')}`;
|
|
78
|
+
})
|
|
79
|
+
.join(';'))
|
|
80
|
+
.join(',');
|
|
81
|
+
return value === header.value ? header : { ...header, value };
|
|
82
|
+
});
|
|
83
|
+
if ((frameOptions.length || requireAncestors) && !hasAncestors) {
|
|
84
|
+
const self = frameOptions.some((header) => /\bsameorigin\b/i.test(header.value)) ? "'self' " : '';
|
|
85
|
+
const ancestors = `frame-ancestors ${self}${origin}`;
|
|
86
|
+
const policyIndex = adapted.findIndex((header) => header.key.toLowerCase() === 'content-security-policy');
|
|
87
|
+
const policy = adapted[policyIndex];
|
|
88
|
+
// Next stores headers by name; adding a second CSP here would overwrite
|
|
89
|
+
// the application's existing resource restrictions.
|
|
90
|
+
if (policy)
|
|
91
|
+
adapted[policyIndex] = { ...policy, value: `${policy.value}; ${ancestors}` };
|
|
92
|
+
else
|
|
93
|
+
adapted.push({ key: 'Content-Security-Policy', value: ancestors });
|
|
94
|
+
}
|
|
95
|
+
return adapted;
|
|
96
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { getSafePreviewNavigationPath, isPreviewRuntimeEnabled } from './bridge.js';
|
|
2
|
+
export { adaptPreviewFrameHeaderRules, adaptPreviewFrameHeaders, adaptPreviewFrameResponse } from './frame-headers.js';
|
|
2
3
|
export { resolveFimoEditingMetadata, isFimoEditingMetadataEnabled, withoutFimoEditingMetadata, FIMO_EDITING_ATTRIBUTES, } from './editing-metadata.js';
|
|
3
4
|
export { getPreviewLocationChange, getPreviewLocationPath, getPreviewParentOrigin, getDocumentLocale, resolvePreviewParentOrigin, type PreviewBrowserContext, type PreviewLocationChange, type PreviewLocationLike, } from './location.js';
|
|
4
5
|
export { ensurePreviewScript } from './script.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { getSafePreviewNavigationPath, isPreviewRuntimeEnabled } from './bridge.js';
|
|
2
|
+
export { adaptPreviewFrameHeaderRules, adaptPreviewFrameHeaders, adaptPreviewFrameResponse } from './frame-headers.js';
|
|
2
3
|
export { resolveFimoEditingMetadata, isFimoEditingMetadataEnabled, withoutFimoEditingMetadata, FIMO_EDITING_ATTRIBUTES, } from './editing-metadata.js';
|
|
3
4
|
export { getPreviewLocationChange, getPreviewLocationPath, getPreviewParentOrigin, getDocumentLocale, resolvePreviewParentOrigin, } from './location.js';
|
|
4
5
|
export { ensurePreviewScript } from './script.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fimo",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0-staging.1",
|
|
4
4
|
"description": "Fimo CLI - create, deploy, and manage Fimo sites",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro-component"
|
|
@@ -194,13 +194,13 @@
|
|
|
194
194
|
"devDependencies": {
|
|
195
195
|
"@clack/core": "^1.2.0",
|
|
196
196
|
"@clack/prompts": "^1.2.0",
|
|
197
|
-
"@fimo/agents-bundle": "2.
|
|
198
|
-
"@fimo/api-contracts": "2.
|
|
199
|
-
"@fimo/cli-kit": "2.
|
|
200
|
-
"@fimo/framework-detect": "2.
|
|
201
|
-
"@fimo/routes": "2.
|
|
202
|
-
"@fimo/sdk": "2.
|
|
203
|
-
"@fimo/tsconfig": "2.
|
|
197
|
+
"@fimo/agents-bundle": "2.9.0-staging.1",
|
|
198
|
+
"@fimo/api-contracts": "2.9.0-staging.1",
|
|
199
|
+
"@fimo/cli-kit": "2.9.0-staging.1",
|
|
200
|
+
"@fimo/framework-detect": "2.9.0-staging.1",
|
|
201
|
+
"@fimo/routes": "2.9.0-staging.1",
|
|
202
|
+
"@fimo/sdk": "2.9.0-staging.1",
|
|
203
|
+
"@fimo/tsconfig": "2.9.0-staging.1",
|
|
204
204
|
"@types/node": "22.18.6",
|
|
205
205
|
"agent-install": "^0.0.5",
|
|
206
206
|
"astro": "^7.1.6",
|
package/release.json
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"check": "astro sync && astro check"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"fimo": "2.
|
|
13
|
-
"fimo-analytics": "2.
|
|
14
|
-
"fimo-astro": "2.
|
|
12
|
+
"fimo": "2.9.0-staging.1",
|
|
13
|
+
"fimo-analytics": "2.9.0-staging.1",
|
|
14
|
+
"fimo-astro": "2.9.0-staging.1",
|
|
15
15
|
"zod": "^4.4.3"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@tanstack/react-query": "^5.80.6",
|
|
15
|
-
"fimo": "2.
|
|
16
|
-
"fimo-analytics": "2.
|
|
17
|
-
"fimo-next": "2.
|
|
18
|
-
"fimo-react": "2.
|
|
19
|
-
"next": "16.
|
|
15
|
+
"fimo": "2.9.0-staging.1",
|
|
16
|
+
"fimo-analytics": "2.9.0-staging.1",
|
|
17
|
+
"fimo-next": "2.9.0-staging.1",
|
|
18
|
+
"fimo-react": "2.9.0-staging.1",
|
|
19
|
+
"next": "16.4.2",
|
|
20
20
|
"react": "^19.2.7",
|
|
21
21
|
"react-dom": "^19.2.7",
|
|
22
22
|
"zod": "^4.4.3"
|
|
@@ -21,11 +21,11 @@
|
|
|
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-analytics": "2.
|
|
26
|
-
"fimo-react": "2.
|
|
27
|
-
"fimo-react-router": "2.
|
|
28
|
-
"fimo-vite": "2.
|
|
24
|
+
"fimo": "2.9.0-staging.1",
|
|
25
|
+
"fimo-analytics": "2.9.0-staging.1",
|
|
26
|
+
"fimo-react": "2.9.0-staging.1",
|
|
27
|
+
"fimo-react-router": "2.9.0-staging.1",
|
|
28
|
+
"fimo-vite": "2.9.0-staging.1",
|
|
29
29
|
"input-otp": "^1.4.2",
|
|
30
30
|
"isbot": "^5",
|
|
31
31
|
"lucide-react": "^0.577.0",
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"prepare": "svelte-kit sync"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"fimo": "2.
|
|
15
|
-
"fimo-analytics": "2.
|
|
16
|
-
"fimo-sveltekit": "2.
|
|
14
|
+
"fimo": "2.9.0-staging.1",
|
|
15
|
+
"fimo-analytics": "2.9.0-staging.1",
|
|
16
|
+
"fimo-sveltekit": "2.9.0-staging.1",
|
|
17
17
|
"zod": "^4.4.3"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@tanstack/react-query": "^5.80.6",
|
|
14
|
-
"fimo": "2.
|
|
15
|
-
"fimo-analytics": "2.
|
|
16
|
-
"fimo-react": "2.
|
|
17
|
-
"fimo-react-router": "2.
|
|
18
|
-
"fimo-vite": "2.
|
|
14
|
+
"fimo": "2.9.0-staging.1",
|
|
15
|
+
"fimo-analytics": "2.9.0-staging.1",
|
|
16
|
+
"fimo-react": "2.9.0-staging.1",
|
|
17
|
+
"fimo-react-router": "2.9.0-staging.1",
|
|
18
|
+
"fimo-vite": "2.9.0-staging.1",
|
|
19
19
|
"react": "^19.2.7",
|
|
20
20
|
"react-dom": "^19.2.7",
|
|
21
21
|
"react-router": "^8.3.0",
|