fimo 0.8.0 → 0.9.0-experimental.10
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/content-translator/scripts/write-locale-files.ts +66 -0
- package/assets/agents-starter/claude/settings.json +19 -0
- package/assets/content-templates/hooks-template.eta +4 -2
- package/assets/content-templates/types-template.eta +67 -1
- package/assets/skills/fimo/SKILL.md +1 -1
- package/assets/skills/fimo/references/content.md +86 -15
- package/assets/skills/fimo/references/translations.md +75 -0
- package/assets/skills/fimo-cli/SKILL.md +6 -2
- package/assets/skills/fimo-cli/references/content.md +61 -2
- package/assets/skills/fimo-cli/references/integrations/firecrawl.md +20 -4
- package/assets/skills/fimo-cli/references/integrations.md +5 -1
- package/assets/skills/fimo-cli/references/webhooks.md +162 -0
- package/assets/skills/fimo-migration/SKILL.md +24 -2
- package/assets/skills/fimo-migration/references/content.md +24 -0
- package/assets/skills/fimo-migration/references/manifest.md +46 -0
- package/assets/skills/fimo-migration/references/pages.md +234 -0
- package/assets/skills/fimo-migration/references/qa.md +24 -2
- package/assets/skills/fimo-migration/references/workflow.md +12 -1
- package/assets/skills/fimo-migration/references/wrap.md +662 -0
- package/assets/skills/fimo-studio/SKILL.md +5 -3
- package/assets/skills/fimo-studio/references/cms.md +9 -1
- package/assets/skills/fimo-studio/references/visual-editing.md +5 -3
- package/assets/skills/fimo-studio/references/webhooks.md +42 -0
- package/dist/build/vite/plugins/translations.d.ts +2 -8
- package/dist/build/vite/plugins/translations.js +31 -131
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +1337 -189
- package/dist/runtime/app/FimoProviders.d.ts +1 -11
- package/dist/runtime/app/FimoProviders.js +31 -30
- package/dist/runtime/astro/index.d.ts +2 -0
- package/dist/runtime/astro/index.js +3 -0
- package/dist/runtime/astro/server.d.ts +3 -0
- package/dist/runtime/astro/server.js +6 -0
- package/dist/runtime/content/client/internal.js +1 -0
- package/dist/runtime/content/client/types.d.ts +16 -0
- package/dist/runtime/core/BuiltWithBadge.d.ts +2 -0
- package/dist/runtime/core/BuiltWithBadge.js +68 -0
- package/dist/runtime/i18n/FimoLocaleContext.js +1 -0
- package/dist/runtime/next/FimoNextProviders.d.ts +24 -0
- package/dist/runtime/next/FimoNextProviders.js +20 -0
- package/dist/runtime/next/FimoNextScripts.d.ts +10 -0
- package/dist/runtime/next/FimoNextScripts.js +19 -0
- package/dist/runtime/next/index.d.ts +14 -0
- package/dist/runtime/next/index.js +14 -0
- package/dist/runtime/next/server.d.ts +2 -0
- package/dist/runtime/next/server.js +4 -0
- package/dist/runtime/nuxt/composables.d.ts +9 -0
- package/dist/runtime/nuxt/composables.js +57 -0
- package/dist/runtime/nuxt/index.d.ts +3 -0
- package/dist/runtime/nuxt/index.js +6 -0
- package/dist/runtime/nuxt/server.d.ts +3 -0
- package/dist/runtime/nuxt/server.js +6 -0
- package/dist/runtime/primitives/components/RichText.d.ts +5 -1
- package/dist/runtime/primitives/components/RichText.js +2 -2
- package/dist/runtime/primitives/labels-hook.d.ts +33 -0
- package/dist/runtime/primitives/labels-hook.js +41 -0
- package/dist/runtime/primitives/labels-store.d.ts +12 -0
- package/dist/runtime/primitives/labels-store.js +60 -0
- package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +5 -3
- package/dist/runtime/primitives/lib/useFimoLiveValue.js +11 -4
- package/dist/runtime/primitives/translations.d.ts +1 -27
- package/dist/runtime/primitives/translations.js +7 -85
- package/dist/runtime/react/FimoSpaProviders.d.ts +36 -0
- package/dist/runtime/react/FimoSpaProviders.js +122 -0
- package/dist/runtime/react/index.d.ts +35 -0
- package/dist/runtime/react/index.js +40 -0
- package/dist/runtime/react/spa-content-cache.d.ts +38 -0
- package/dist/runtime/react/spa-content-cache.js +64 -0
- package/dist/runtime/remix/FimoRemixProviders.d.ts +16 -0
- package/dist/runtime/remix/FimoRemixProviders.js +12 -0
- package/dist/runtime/remix/FimoRemixScripts.d.ts +10 -0
- package/dist/runtime/remix/FimoRemixScripts.js +19 -0
- package/dist/runtime/remix/index.d.ts +12 -0
- package/dist/runtime/remix/index.js +11 -0
- package/dist/runtime/remix/server.d.ts +2 -0
- package/dist/runtime/remix/server.js +2 -0
- package/dist/runtime/seo/neutral.d.ts +22 -0
- package/dist/runtime/seo/neutral.js +17 -0
- package/dist/runtime/shared/display-routes.d.ts +14 -0
- package/dist/runtime/shared/display-routes.js +25 -0
- package/dist/runtime/shared/fimo-config.server.d.ts +0 -1
- package/dist/runtime/shared/fimo-config.server.js +1 -13
- package/dist/runtime/shared/fimo-config.types.d.ts +2 -0
- package/dist/runtime/shared/i18n-messages.d.ts +29 -0
- package/dist/runtime/shared/i18n-messages.js +79 -0
- package/dist/runtime/shared/labels-fetch.pure.d.ts +17 -0
- package/dist/runtime/shared/labels-fetch.pure.js +71 -0
- package/dist/runtime/shared/labels-fetch.server.d.ts +7 -0
- package/dist/runtime/shared/labels-fetch.server.js +97 -0
- package/dist/runtime/shared/labels-t.pure.d.ts +2 -0
- package/dist/runtime/shared/labels-t.pure.js +10 -0
- package/dist/runtime/strapi/client.d.ts +30 -0
- package/dist/runtime/strapi/client.js +132 -0
- package/dist/runtime/strapi/index.d.ts +5 -0
- package/dist/runtime/strapi/index.js +6 -0
- package/dist/runtime/strapi/reshape.d.ts +50 -0
- package/dist/runtime/strapi/reshape.js +121 -0
- package/dist/runtime/svelte/index.d.ts +3 -0
- package/dist/runtime/svelte/index.js +7 -0
- package/dist/runtime/svelte/server.d.ts +3 -0
- package/dist/runtime/svelte/server.js +6 -0
- package/dist/runtime/vue/index.d.ts +3 -0
- package/dist/runtime/vue/index.js +5 -0
- package/dist/runtime/vue/server.d.ts +3 -0
- package/dist/runtime/vue/server.js +6 -0
- package/dist/runtime/wrapped/FimoFileLink.d.ts +17 -0
- package/dist/runtime/wrapped/FimoFileLink.js +19 -0
- package/dist/runtime/wrapped/FimoMediaImage.d.ts +14 -0
- package/dist/runtime/wrapped/FimoMediaImage.js +20 -0
- package/dist/runtime/wrapped/FimoMediaVideo.d.ts +14 -0
- package/dist/runtime/wrapped/FimoMediaVideo.js +20 -0
- package/dist/runtime/wrapped/FimoRichTextBlock.d.ts +26 -0
- package/dist/runtime/wrapped/FimoRichTextBlock.js +22 -0
- package/dist/runtime/wrapped/FimoText.d.ts +22 -0
- package/dist/runtime/wrapped/FimoText.js +20 -0
- package/dist/runtime/wrapped/WrappedContentContext.d.ts +28 -0
- package/dist/runtime/wrapped/WrappedContentContext.js +30 -0
- package/dist/runtime/wrapped/WrappedProviders.d.ts +33 -0
- package/dist/runtime/wrapped/WrappedProviders.js +101 -0
- package/dist/runtime/wrapped/content-fetch.pure.d.ts +20 -0
- package/dist/runtime/wrapped/content-fetch.pure.js +106 -0
- package/dist/runtime/wrapped/dom.d.ts +4 -0
- package/dist/runtime/wrapped/dom.js +23 -0
- package/dist/runtime/wrapped/server.d.ts +80 -0
- package/dist/runtime/wrapped/server.js +207 -0
- package/dist/scripts/apply-wrap-templates.d.ts +61 -0
- package/dist/scripts/apply-wrap-templates.js +137 -0
- package/dist/scripts/apply-wrap.d.ts +73 -0
- package/dist/scripts/apply-wrap.js +340 -0
- package/dist/scripts/cms/discover.d.ts +2 -0
- package/dist/scripts/cms/discover.js +17 -0
- package/dist/scripts/cms/example-content.d.ts +33 -0
- package/dist/scripts/cms/example-content.js +165 -0
- package/dist/scripts/cms/strapi/detect.d.ts +2 -0
- package/dist/scripts/cms/strapi/detect.js +186 -0
- package/dist/scripts/cms/strapi/index.d.ts +3 -0
- package/dist/scripts/cms/strapi/index.js +25 -0
- package/dist/scripts/cms/strapi/list-source.d.ts +17 -0
- package/dist/scripts/cms/strapi/list-source.js +90 -0
- package/dist/scripts/cms/strapi/schema-map.d.ts +9 -0
- package/dist/scripts/cms/strapi/schema-map.js +289 -0
- package/dist/scripts/cms/strapi/shapes.d.ts +25 -0
- package/dist/scripts/cms/strapi/shapes.js +48 -0
- package/dist/scripts/cms/strapi/touchpoints.d.ts +31 -0
- package/dist/scripts/cms/strapi/touchpoints.js +145 -0
- package/dist/scripts/cms/strapi/wire-client.d.ts +15 -0
- package/dist/scripts/cms/strapi/wire-client.js +107 -0
- package/dist/scripts/cms/strapi/wiring.d.ts +17 -0
- package/dist/scripts/cms/strapi/wiring.js +46 -0
- package/dist/scripts/cms/types.d.ts +145 -0
- package/dist/scripts/cms/types.js +11 -0
- package/dist/scripts/detect-framework.d.ts +39 -0
- package/dist/scripts/detect-framework.js +139 -0
- package/dist/scripts/draft-rows.d.ts +19 -0
- package/dist/scripts/draft-rows.js +178 -0
- package/dist/scripts/draft-schemas.d.ts +27 -0
- package/dist/scripts/draft-schemas.js +247 -0
- package/dist/scripts/extract-translations.js +16 -11
- package/dist/scripts/frameworks/astro/routes.d.ts +3 -0
- package/dist/scripts/frameworks/astro/routes.js +44 -0
- package/dist/scripts/frameworks/astro/template-style.d.ts +7 -0
- package/dist/scripts/frameworks/astro/template-style.js +19 -0
- package/dist/scripts/frameworks/discover.d.ts +83 -0
- package/dist/scripts/frameworks/discover.js +288 -0
- package/dist/scripts/frameworks/discovered-route.d.ts +9 -0
- package/dist/scripts/frameworks/discovered-route.js +17 -0
- package/dist/scripts/frameworks/next/rewire.d.ts +43 -0
- package/dist/scripts/frameworks/next/rewire.js +282 -0
- package/dist/scripts/frameworks/next/routes.d.ts +30 -0
- package/dist/scripts/frameworks/next/routes.js +176 -0
- package/dist/scripts/frameworks/next/wiring.d.ts +33 -0
- package/dist/scripts/frameworks/next/wiring.js +186 -0
- package/dist/scripts/frameworks/nuxt/routes.d.ts +3 -0
- package/dist/scripts/frameworks/nuxt/routes.js +38 -0
- package/dist/scripts/frameworks/nuxt/template-style.d.ts +9 -0
- package/dist/scripts/frameworks/nuxt/template-style.js +27 -0
- package/dist/scripts/frameworks/remix/routes.d.ts +3 -0
- package/dist/scripts/frameworks/remix/routes.js +36 -0
- package/dist/scripts/frameworks/support.d.ts +75 -0
- package/dist/scripts/frameworks/support.js +165 -0
- package/dist/scripts/frameworks/sveltekit/routes.d.ts +3 -0
- package/dist/scripts/frameworks/sveltekit/routes.js +35 -0
- package/dist/scripts/frameworks/sveltekit/template-style.d.ts +9 -0
- package/dist/scripts/frameworks/sveltekit/template-style.js +54 -0
- package/dist/scripts/frameworks/vite/routes.d.ts +20 -0
- package/dist/scripts/frameworks/vite/routes.js +143 -0
- package/dist/scripts/frameworks/vite/wiring.d.ts +22 -0
- package/dist/scripts/frameworks/vite/wiring.js +144 -0
- package/dist/scripts/i18n-namespace.d.ts +27 -0
- package/dist/scripts/i18n-namespace.js +155 -0
- package/dist/scripts/lib/humanize.d.ts +14 -0
- package/dist/scripts/lib/humanize.js +54 -0
- package/dist/scripts/lib/validation-report.d.ts +1 -3
- package/dist/scripts/lib/validation-report.js +3 -9
- package/dist/scripts/render-parity/capture.d.ts +64 -0
- package/dist/scripts/render-parity/capture.js +436 -0
- package/dist/scripts/render-parity/compare.d.ts +59 -0
- package/dist/scripts/render-parity/compare.js +0 -0
- package/dist/scripts/render-parity/normalize-html.d.ts +13 -0
- package/dist/scripts/render-parity/normalize-html.js +223 -0
- package/dist/scripts/render-parity/types.d.ts +41 -0
- package/dist/scripts/render-parity/types.js +1 -0
- package/dist/scripts/routes/bindings.d.ts +93 -0
- package/dist/scripts/routes/bindings.js +117 -0
- package/dist/scripts/routes/label-prefixes.d.ts +49 -0
- package/dist/scripts/routes/label-prefixes.js +136 -0
- package/dist/scripts/routes/module-resolve.d.ts +20 -0
- package/dist/scripts/routes/module-resolve.js +78 -0
- package/dist/scripts/routes/page-structure.d.ts +72 -0
- package/dist/scripts/routes/page-structure.js +234 -0
- package/dist/scripts/scan-wrappable.d.ts +200 -0
- package/dist/scripts/scan-wrappable.js +1355 -0
- package/dist/scripts/validate-route-metadata.js +11 -0
- package/dist/scripts/validate-schemas.js +42 -1
- package/package.json +88 -4
- package/release.json +2 -2
- package/templates/react-router/package.json +1 -1
- package/templates/react-router/translations/en.json +1 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: write-locale-files
|
|
3
|
+
*
|
|
4
|
+
* For locale-keyed JSON files in `src/locales/<locale>.json`, fill in
|
|
5
|
+
* missing keys from the default-locale file using the configured
|
|
6
|
+
* translation provider. Run after translate-entries when projects mix
|
|
7
|
+
* CMS-driven copy with hardcoded i18n strings.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { promises as fs } from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
|
|
13
|
+
interface Catalog {
|
|
14
|
+
[key: string]: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function readCatalog(file: string): Promise<Catalog> {
|
|
18
|
+
try {
|
|
19
|
+
const text = await fs.readFile(file, 'utf8');
|
|
20
|
+
return JSON.parse(text) as Catalog;
|
|
21
|
+
} catch {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function writeCatalog(file: string, catalog: Catalog): Promise<void> {
|
|
27
|
+
await fs.writeFile(file, JSON.stringify(catalog, null, 2) + '\n', 'utf8');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function translate(text: string, _to: string): Promise<string> {
|
|
31
|
+
// Stub — provider-specific call.
|
|
32
|
+
return text;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function main(): Promise<void> {
|
|
36
|
+
const defaultLocale = process.env.FIMO_DEFAULT_LOCALE ?? 'en';
|
|
37
|
+
const targetLocales = (process.env.FIMO_TARGET_LOCALES ?? '').split(',').filter(Boolean);
|
|
38
|
+
const localesDir = process.env.FIMO_LOCALES_DIR ?? 'src/locales';
|
|
39
|
+
|
|
40
|
+
const defaultFile = path.join(localesDir, `${defaultLocale}.json`);
|
|
41
|
+
const defaultCatalog = await readCatalog(defaultFile);
|
|
42
|
+
|
|
43
|
+
for (const target of targetLocales) {
|
|
44
|
+
const targetFile = path.join(localesDir, `${target}.json`);
|
|
45
|
+
const targetCatalog = await readCatalog(targetFile);
|
|
46
|
+
let dirty = false;
|
|
47
|
+
|
|
48
|
+
for (const [key, sourceValue] of Object.entries(defaultCatalog)) {
|
|
49
|
+
if (targetCatalog[key]) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
targetCatalog[key] = await translate(sourceValue, target);
|
|
53
|
+
dirty = true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (dirty) {
|
|
57
|
+
await writeCatalog(targetFile, targetCatalog);
|
|
58
|
+
console.log(`Wrote ${targetFile}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
main().catch((err) => {
|
|
64
|
+
console.error(err);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(fimo:*)",
|
|
5
|
+
"Bash(npx fimo:*)",
|
|
6
|
+
"Bash(pnpm:*)",
|
|
7
|
+
"Bash(pnpm dlx:*)",
|
|
8
|
+
"Bash(npx:*)",
|
|
9
|
+
"Bash(git status)",
|
|
10
|
+
"Bash(git status:*)",
|
|
11
|
+
"Bash(git diff)",
|
|
12
|
+
"Bash(git diff:*)",
|
|
13
|
+
"Bash(git log:*)",
|
|
14
|
+
"Bash(git add:*)",
|
|
15
|
+
"Bash(git restore:*)",
|
|
16
|
+
"Bash(mkdir:*)"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
<% if (model.isSingleton) { -%>
|
|
5
5
|
import { createSingletonClient } from "fimo/ui";
|
|
6
6
|
import type { SingletonContentClient } from "fimo/ui";
|
|
7
|
+
import type { ContentSchema } from "fimo/ui";
|
|
7
8
|
<% } else { -%>
|
|
8
9
|
import { createContentClient } from "fimo/ui";
|
|
9
10
|
import type { CollectionContentClient } from "fimo/ui";
|
|
11
|
+
import type { ContentSchema } from "fimo/ui";
|
|
10
12
|
<% } -%>
|
|
11
13
|
|
|
12
14
|
import schema from "./<%= model.uid %>.json";
|
|
@@ -39,13 +41,13 @@ const client: SingletonContentClient<<%= model.pascal %>, <%= model.pascal %>Inp
|
|
|
39
41
|
<%= model.pascal %>,
|
|
40
42
|
<%= model.pascal %>Input
|
|
41
43
|
>({
|
|
42
|
-
schema,
|
|
44
|
+
schema: schema as unknown as ContentSchema,
|
|
43
45
|
<% } else { -%>
|
|
44
46
|
const client: CollectionContentClient<<%= model.pascal %>, <%= model.pascal %>Input> = createContentClient<
|
|
45
47
|
<%= model.pascal %>,
|
|
46
48
|
<%= model.pascal %>Input
|
|
47
49
|
>({
|
|
48
|
-
schema,
|
|
50
|
+
schema: schema as unknown as ContentSchema,
|
|
49
51
|
<% } -%>
|
|
50
52
|
<% if (model.referenceImports && model.referenceImports.length > 0) { -%>
|
|
51
53
|
references: { <%= model.referenceImports.map((referenceImport) => referenceImport.pascal).join(", ") %> },
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* }
|
|
9
9
|
*/
|
|
10
10
|
%>
|
|
11
|
+
// @ts-nocheck — generated internals are exempt from the app's own tsconfig strictness; exported types still work
|
|
11
12
|
// AUTO-GENERATED ⚠️ – do not edit by hand
|
|
12
13
|
import { type Fields, type FimoBoolean, type FimoMedia, type FimoPolymorphicReference, type FimoReference, type FimoRichText, type FimoRichTextContent, type FimoString, type Populate, type PopulatedResult, type ProjectedWithPopulate, type Query, type Sort, type Where, type WithReferences } from "fimo/ui";
|
|
13
14
|
<%
|
|
@@ -70,7 +71,7 @@ if (model.fields) {
|
|
|
70
71
|
Object.entries(model.fields).forEach(([key, field]) => {
|
|
71
72
|
const type = getInputTypeForField(field);
|
|
72
73
|
-%>
|
|
73
|
-
<%= key %><%= field
|
|
74
|
+
<%= key %><%= isRequiredField(field) ? '' : '?' %>: <%= type %>;
|
|
74
75
|
<%
|
|
75
76
|
});
|
|
76
77
|
}
|
|
@@ -85,6 +86,7 @@ if (model.fields) {
|
|
|
85
86
|
function getTypeForField(field) {
|
|
86
87
|
switch(field.type) {
|
|
87
88
|
case 'string':
|
|
89
|
+
case 'text':
|
|
88
90
|
return 'FimoString';
|
|
89
91
|
case 'richtext':
|
|
90
92
|
return 'FimoRichText';
|
|
@@ -102,6 +104,8 @@ function getTypeForField(field) {
|
|
|
102
104
|
const raw = Array.isArray(field.targets) && field.targets.length > 0 ? 'FimoPolymorphicReference' : 'FimoReference';
|
|
103
105
|
return field.many ? `${raw}[]` : `${raw} | null`;
|
|
104
106
|
}
|
|
107
|
+
case 'blocks':
|
|
108
|
+
return getBlocksType(field, false);
|
|
105
109
|
default:
|
|
106
110
|
return 'any';
|
|
107
111
|
}
|
|
@@ -110,6 +114,7 @@ function getTypeForField(field) {
|
|
|
110
114
|
function getInputTypeForField(field) {
|
|
111
115
|
switch(field.type) {
|
|
112
116
|
case 'string':
|
|
117
|
+
case 'text':
|
|
113
118
|
return 'string';
|
|
114
119
|
case 'richtext':
|
|
115
120
|
return 'FimoRichTextContent';
|
|
@@ -129,10 +134,71 @@ function getInputTypeForField(field) {
|
|
|
129
134
|
const raw = Array.isArray(field.targets) && field.targets.length > 0 ? 'FimoPolymorphicReference' : 'FimoReference';
|
|
130
135
|
return field.many ? `${raw}[]` : `${raw} | null`;
|
|
131
136
|
}
|
|
137
|
+
case 'blocks':
|
|
138
|
+
return getBlocksType(field, true);
|
|
132
139
|
default:
|
|
133
140
|
return 'unknown';
|
|
134
141
|
}
|
|
135
142
|
}
|
|
143
|
+
|
|
144
|
+
function getNestedFieldType(field, input) {
|
|
145
|
+
switch(field.type) {
|
|
146
|
+
case 'string':
|
|
147
|
+
case 'text':
|
|
148
|
+
return 'string';
|
|
149
|
+
case 'richtext':
|
|
150
|
+
return 'FimoRichTextContent';
|
|
151
|
+
case 'number':
|
|
152
|
+
return 'number';
|
|
153
|
+
case 'boolean':
|
|
154
|
+
return 'boolean';
|
|
155
|
+
case 'date':
|
|
156
|
+
return 'string';
|
|
157
|
+
case 'json':
|
|
158
|
+
case 'media':
|
|
159
|
+
return 'Record<string, unknown>';
|
|
160
|
+
case 'reference': {
|
|
161
|
+
const raw = Array.isArray(field.targets) && field.targets.length > 0 ? 'FimoPolymorphicReference' : 'FimoReference';
|
|
162
|
+
return field.many ? `${raw}[]` : `${raw} | null`;
|
|
163
|
+
}
|
|
164
|
+
case 'blocks':
|
|
165
|
+
return getBlocksType(field, input);
|
|
166
|
+
default:
|
|
167
|
+
return 'unknown';
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function getBlockObjectType(fields, input, metadata = {}) {
|
|
172
|
+
const properties = [];
|
|
173
|
+
if (metadata.key) {
|
|
174
|
+
properties.push(`_key${input ? '?' : ''}: string`);
|
|
175
|
+
}
|
|
176
|
+
if (metadata.type) {
|
|
177
|
+
properties.push(`_type: "${metadata.type}"`);
|
|
178
|
+
}
|
|
179
|
+
for (const [key, field] of Object.entries(fields || {})) {
|
|
180
|
+
properties.push(`${key}${isRequiredField(field) ? '' : '?'}: ${getNestedFieldType(field, input)}`);
|
|
181
|
+
}
|
|
182
|
+
return `{ ${properties.join('; ')} }`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function getBlocksType(field, input) {
|
|
186
|
+
const schema = field.schema || {};
|
|
187
|
+
let item;
|
|
188
|
+
if (Array.isArray(schema.oneOf)) {
|
|
189
|
+
item = schema.oneOf
|
|
190
|
+
.map((variant) => getBlockObjectType(variant.fields, input, { key: true, type: variant.uid }))
|
|
191
|
+
.join(' | ') || 'never';
|
|
192
|
+
item = `(${item})`;
|
|
193
|
+
} else {
|
|
194
|
+
item = getBlockObjectType(schema.fields, input, { key: true });
|
|
195
|
+
}
|
|
196
|
+
return `${item}[]`;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function isRequiredField(field) {
|
|
200
|
+
return Boolean(field.required || (field.type === 'blocks' && Number(field.min || 0) > 0));
|
|
201
|
+
}
|
|
136
202
|
-%>
|
|
137
203
|
|
|
138
204
|
export interface <%= model.pascal %>References {
|
|
@@ -14,7 +14,7 @@ You are writing code in a Fimo project — a content + media + forms + analytics
|
|
|
14
14
|
|
|
15
15
|
This skill is version-locked to this project's installed `fimo` package — the shapes here match what your code can actually use.
|
|
16
16
|
|
|
17
|
-
For CLI commands and workflows (creating a project, pushing schemas/forms, deploying, managing labels, etc.), the **`fimo-cli`** skill is the source of truth. Run every CLI command as `npx fimo
|
|
17
|
+
For CLI commands and workflows (creating a project, pushing schemas/forms, deploying, managing labels, etc.), the **`fimo-cli`** skill is the source of truth. Run every CLI command as `npx fimo <command>` when the project declares a `fimo` dependency (it pins the version matching the project's backend); otherwise use `npx fimo@latest`. If `fimo-cli` isn't loaded for your AI tool, register it with `npx fimo skills install --mode=copy`.
|
|
18
18
|
|
|
19
19
|
## Critical: NEVER hardcode user-facing things
|
|
20
20
|
|
|
@@ -13,6 +13,7 @@ This file covers the **package surface**: the JSON shape you write, the generate
|
|
|
13
13
|
"i18n": { "enabled": true },
|
|
14
14
|
"fields": {
|
|
15
15
|
"title": { "type": "string" },
|
|
16
|
+
"summary": { "type": "text" },
|
|
16
17
|
"body": { "type": "richtext" },
|
|
17
18
|
"publishDate": { "type": "string" },
|
|
18
19
|
"featured": { "type": "boolean" },
|
|
@@ -45,19 +46,76 @@ something else (e.g. `handle`, `permalink`).
|
|
|
45
46
|
|
|
46
47
|
## Field types
|
|
47
48
|
|
|
48
|
-
| Type | `data` JSON shape | Use for
|
|
49
|
-
| ----------- | ----------------------------------------------------------------------------- |
|
|
50
|
-
| `string` | `"..."` |
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
54
|
-
| `
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
49
|
+
| Type | `data` JSON shape | Use for |
|
|
50
|
+
| ----------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------- |
|
|
51
|
+
| `string` | `"..."` | One-line text: titles, names, slugs |
|
|
52
|
+
| `text` | `"First line\nSecond line"` | Multiline plain text without formatting |
|
|
53
|
+
| `richtext` | Tiptap JSONContent (see below) | Formatted content with headings, links, lists, or media |
|
|
54
|
+
| `number` | `42` | Counts, quantities |
|
|
55
|
+
| `boolean` | `true` / `false` | Flags |
|
|
56
|
+
| `date` | ISO date string, e.g. `"2026-06-03"` | Publish dates, timestamps |
|
|
57
|
+
| `media` | `{ "source": "local"\|"external", "url": "https://...", "alt": "..." }` | Images, video |
|
|
58
|
+
| `json` | any JSON | Structured metadata |
|
|
59
|
+
| `reference` | `{ "id": "..." }`, `null`, or an array of reference objects when `many: true` | References to another schema |
|
|
60
|
+
| `blocks` | ordered array of objects | Fixed groups, repeated sections, or selectable page blocks |
|
|
58
61
|
|
|
59
62
|
A `date` field currently generates as `any` in the TS client, so for typed access (and the `<Date>` component) prefer a `string` field holding an ISO date — which is what the `publishDate` examples below do.
|
|
60
63
|
|
|
64
|
+
## Blocks
|
|
65
|
+
|
|
66
|
+
`blocks` is the only nested structured-content type and always stores an array. Use `schema.fields` for one homogeneous block shape. Set `max: 1` when the field is a single optional group. Use `schema.oneOf` when editors choose a variant for each item.
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"seo": {
|
|
71
|
+
"type": "blocks",
|
|
72
|
+
"max": 1,
|
|
73
|
+
"schema": {
|
|
74
|
+
"fields": {
|
|
75
|
+
"title": { "type": "string", "required": true },
|
|
76
|
+
"description": { "type": "text" }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"sections": {
|
|
81
|
+
"type": "blocks",
|
|
82
|
+
"min": 1,
|
|
83
|
+
"max": 20,
|
|
84
|
+
"schema": {
|
|
85
|
+
"oneOf": [
|
|
86
|
+
{
|
|
87
|
+
"uid": "hero",
|
|
88
|
+
"label": "Hero",
|
|
89
|
+
"fields": {
|
|
90
|
+
"heading": { "type": "string", "required": true },
|
|
91
|
+
"introduction": { "type": "text" }
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"uid": "quote",
|
|
96
|
+
"label": "Quote",
|
|
97
|
+
"fields": {
|
|
98
|
+
"quote": { "type": "text", "required": true },
|
|
99
|
+
"author": { "type": "reference", "target": "Author" }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- `blocks.schema.fields` repeats one homogeneous shape.
|
|
109
|
+
- `blocks.schema.oneOf` lets the editor choose exactly one variant per item.
|
|
110
|
+
- Blocks always read and write arrays. A field with `max: 1` is `[]` or `[item]`, never a bare object.
|
|
111
|
+
- `min` and `max` constrain the total number of blocks. Use `min: 1` to require at least one block; `required: true` has the same minimum-one behavior.
|
|
112
|
+
- Fimo creates a stable `_key` for each item. A `oneOf` item also carries `_type`, matching the variant `uid`.
|
|
113
|
+
- Nested fields support the same defaults and validators as top-level fields.
|
|
114
|
+
- Blocks inherit the owning entry's locale.
|
|
115
|
+
- Nested references use one fixed `target`. Unpopulated reads return `{ id, documentId }`, like top-level references.
|
|
116
|
+
- Nested population and filtering are not supported yet.
|
|
117
|
+
- `anyOf` is not supported. One block never merges multiple variant schemas.
|
|
118
|
+
|
|
61
119
|
## Reference fields
|
|
62
120
|
|
|
63
121
|
Use `reference` when one content entry references another content entry. Do not store entry IDs in a `json` field as a workaround.
|
|
@@ -102,16 +160,27 @@ Entry payload example:
|
|
|
102
160
|
|
|
103
161
|
After editing schema JSON, run `fimo schemas push {Uid}` and then `fimo validate`. Push regenerates the schema client and applies the schema change to existing content automatically:
|
|
104
162
|
|
|
105
|
-
- Adding fields and changing labels preserve entries.
|
|
106
|
-
-
|
|
163
|
+
- Adding optional fields and changing labels preserve entries.
|
|
164
|
+
- Adding a required field backfills its `default` only in existing objects that need it. The push fails safely if those objects exist and no valid default is provided.
|
|
165
|
+
- Removing a field or block variant removes only those nested values.
|
|
107
166
|
- A one-to-many reference change wraps each existing reference in an array.
|
|
108
|
-
-
|
|
167
|
+
- Changing between `string` and `text` preserves values.
|
|
168
|
+
- Other primitive type changes convert safe values, such as `42` to `"42"`, and reject unsafe values without changing content or schema.
|
|
169
|
+
- Lowering blocks `max` trims items from the end. Raising `min` appends blocks from the field's non-empty `default` array.
|
|
170
|
+
- Changing a reference target clears those connections. Renaming a relation field with the same target preserves them.
|
|
171
|
+
- Preserve top-level or nested renames with repeatable one-time operations: `fimo schemas push Page --rename sections.hero.heading=sections.hero.title`. Renames are command intent, not schema JSON.
|
|
172
|
+
- A many-to-one change or scalar/reference change clears only the changed field.
|
|
109
173
|
- Collection-to-singleton removes that type's entries and cleans references to those documents.
|
|
110
174
|
- Singleton-to-collection preserves the existing entry.
|
|
175
|
+
- Blocks migrations are surgical: unaffected nested fields, block keys, and block order survive every supported change.
|
|
176
|
+
|
|
177
|
+
There are no reset or data-loss flags. A failed migration is atomic: neither schema nor entries change.
|
|
111
178
|
|
|
112
|
-
|
|
179
|
+
Choose by editing intent:
|
|
113
180
|
|
|
114
|
-
|
|
181
|
+
- Use `string` for one-line values such as titles, names, labels, slugs, URLs, and short metadata.
|
|
182
|
+
- Use `text` for plain multiline copy such as summaries, descriptions, bios, excerpts, intros, and details when formatting is unnecessary.
|
|
183
|
+
- Use `richtext` for content that needs formatting or structured blocks, especially article bodies and page content.
|
|
115
184
|
|
|
116
185
|
## Tiptap JSONContent (richtext)
|
|
117
186
|
|
|
@@ -202,6 +271,7 @@ interface BlogPost {
|
|
|
202
271
|
contentType: string;
|
|
203
272
|
};
|
|
204
273
|
title: FimoString;
|
|
274
|
+
summary: FimoString;
|
|
205
275
|
body: FimoRichText;
|
|
206
276
|
coverImage: FimoMedia;
|
|
207
277
|
publishDate: FimoString;
|
|
@@ -391,6 +461,7 @@ The entry objects a hook returns are **not** plain JS values. The generated clie
|
|
|
391
461
|
| Schema field type | Field value you get | Notes |
|
|
392
462
|
| ----------------- | ----------------------------------- | ------------------------------------------------------------------------------------- |
|
|
393
463
|
| `string` | `FimoString` | `extends String` — **not** a primitive `string` |
|
|
464
|
+
| `text` | `FimoString` | Multiline plain text with the same source tracking as `string` |
|
|
394
465
|
| `richtext` | `FimoRichText` | Tiptap JSONContent + source metadata |
|
|
395
466
|
| `boolean` | `FimoBoolean` | class; `.valueOf()` → `boolean` |
|
|
396
467
|
| `media` | `FimoMedia` / `FimoMedia[]` | shape + rendering in `references/assets.md` |
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Translations — package surface
|
|
2
|
+
|
|
3
|
+
> For the CLI workflow (`fimo validate`, when to run validation, what sync does), see **`fimo-cli/references/translations.md`**.
|
|
4
|
+
|
|
5
|
+
This file covers the **package surface**: the `t()` helper, the `useTranslations()` hook, and the code-side rules for wrapping strings.
|
|
6
|
+
|
|
7
|
+
## The rule
|
|
8
|
+
|
|
9
|
+
Every piece of **user-facing static text** in the app (page titles, button labels, nav items, form placeholders, empty-state copy, alt text, meta tags) MUST be wrapped in `t('key', 'Default text')`.
|
|
10
|
+
|
|
11
|
+
Raw string literals in JSX are a bug — they won't show up in the Fimo admin as editable content and won't be translatable. **Hard-coded JSX text (`<h1>Welcome</h1>`) skips the entire i18n + inline-editing pipeline and becomes invisible to the editor.**
|
|
12
|
+
|
|
13
|
+
## Setup (already wired)
|
|
14
|
+
|
|
15
|
+
Translations are wired automatically by the `fimo/vite` build plugin. It exposes a `virtual:translations` module sourced from `<projectRoot>/translations/en.json`, and `useTranslations()` reads from that virtual module — there's no provider to add or remove. The app entry is `src/root.tsx`, which wraps the app in `<FimoProviders>` from `fimo/react-router`; you never import `translations/en.json` in app code. Pages and components only call `useTranslations()`.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { useTranslations, Text } from 'fimo/ui';
|
|
21
|
+
|
|
22
|
+
export function Hero() {
|
|
23
|
+
const { t } = useTranslations();
|
|
24
|
+
return (
|
|
25
|
+
<section>
|
|
26
|
+
<h1>
|
|
27
|
+
<Text value={t('hero.title', 'Welcome to Acme')} />
|
|
28
|
+
</h1>
|
|
29
|
+
<p>
|
|
30
|
+
<Text value={t('hero.subtitle', 'The fastest way to ship your idea.')} />
|
|
31
|
+
</p>
|
|
32
|
+
<input placeholder={String(t('hero.emailPlaceholder', 'you@example.com'))} />
|
|
33
|
+
<img alt={String(t('hero.imageAlt', 'Team collaborating'))} src="..." />
|
|
34
|
+
</section>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- `t(key, default)` returns a `FimoString` (wrapped for source tracking). Render it via `<Text value={...} />` inside JSX.
|
|
40
|
+
- For HTML attributes (`placeholder`, `alt`, `title`, `aria-label`) cast with `String(t(...))` — the attribute can't accept a `FimoString` object directly.
|
|
41
|
+
|
|
42
|
+
## Hard rules (enforced by the pre-build linter)
|
|
43
|
+
|
|
44
|
+
**The first argument to `t()` MUST be a string literal.** Dynamic keys break source tracking and fail the lint step.
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
// ❌ BAD — variable key
|
|
48
|
+
t(item.key, item.label);
|
|
49
|
+
|
|
50
|
+
// ❌ BAD — template with expression
|
|
51
|
+
t(`nav.${page}`, 'Page');
|
|
52
|
+
|
|
53
|
+
// ✅ GOOD — put the t() call where the literal lives
|
|
54
|
+
const items = [{ label: t('nav.home', 'Home') }, { label: t('nav.about', 'About') }];
|
|
55
|
+
items.map((item) => <li>{item.label}</li>);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Key naming
|
|
59
|
+
|
|
60
|
+
- Dot-namespaced, lowercase, kebab or camelCase leaves: `hero.title`, `nav.signIn`, `footer.copyright`, `errors.required`.
|
|
61
|
+
- Namespace by **page/section/component**, not by feature (`contact.form.submitLabel`, not `forms.contactSubmit`).
|
|
62
|
+
- The default (second arg) is the English copy — make it final, not a TODO; it ships to production if no translation exists for the active locale.
|
|
63
|
+
|
|
64
|
+
## What NOT to translate
|
|
65
|
+
|
|
66
|
+
- Dynamic content from entries or forms — that's already stored in the DB (content via schemas, submissions via forms).
|
|
67
|
+
- Content-type field values rendered via `fimo/ui` primitives (`<Text>`, `<RichText>`, …) — those carry their own admin-editing metadata.
|
|
68
|
+
- Purely decorative / non-text (icons, logos).
|
|
69
|
+
- Developer-only strings (`console.log`, error messages thrown for debugging).
|
|
70
|
+
|
|
71
|
+
## Rule of thumb
|
|
72
|
+
|
|
73
|
+
If a human reader sees the text AND the project owner might want to reword it in the admin, it goes through `t()`. When in doubt: wrap it.
|
|
74
|
+
|
|
75
|
+
After adding or changing `t()` calls, run `fimo validate` (or rely on `fimo deploy` doing it). See `fimo-cli/references/translations.md`.
|
|
@@ -4,8 +4,9 @@ description: >-
|
|
|
4
4
|
The `fimo` CLI scaffolds and manages Fimo projects from the command line.
|
|
5
5
|
Load when the user wants to create a new Fimo project, build content
|
|
6
6
|
(schemas, entries, forms, media, labels/locales), deploy a site, manage
|
|
7
|
-
custom domains,
|
|
8
|
-
|
|
7
|
+
custom domains, configure outbound webhooks and event-driven integrations,
|
|
8
|
+
check site traffic/analytics, invite collaborators, inspect AI credits,
|
|
9
|
+
report a failing or slow Fimo API, rejected documented argument,
|
|
9
10
|
undocumented workaround, missing capability that blocks work, forces a
|
|
10
11
|
fragile or heavily manual workaround, or would materially accelerate a
|
|
11
12
|
recurring workflow, or other Fimo platform problem to support, log in or
|
|
@@ -21,6 +22,8 @@ This skill describes **what the CLI does and the workflows it drives**. For the
|
|
|
21
22
|
|
|
22
23
|
Use `fimo <command> --help` for full flag details on any command.
|
|
23
24
|
|
|
25
|
+
> **Webhooks are beta.** Verify a destination with `fimo webhooks test <id> --wait` and inspect its delivery history before depending on it in production.
|
|
26
|
+
|
|
24
27
|
## Running the CLI: always `npx fimo@latest`
|
|
25
28
|
|
|
26
29
|
Run every command as **`npx fimo@latest <command>`**. It always fetches the latest CLI — no install, nothing to keep up to date, and it can't fall behind and get blocked. Do **not** install `fimo` globally.
|
|
@@ -85,6 +88,7 @@ Load the matching reference when the user's request fires its trigger. Recipes t
|
|
|
85
88
|
- "Get the preview URL / open the preview / what's the URL for this env / refresh the preview link / I just want to see the site / the preview URL stopped working" → `references/preview.md`
|
|
86
89
|
- "Schedule a command / cron / nightly publish / recurring checks / `fimo schedules`" → `references/schedules.md`
|
|
87
90
|
- "Set env vars / configure API keys / add project secrets / local `.env.local` / `fimo vars` / `fimo secrets`" → `references/project-vars-and-secrets.md`
|
|
91
|
+
- "React to form submissions / publish changes / agent runs / analytics reports / media activity / send events to Resend, Slack, GitHub, Zapier, or an HTTP endpoint / configure or debug outbound webhooks" → `references/webhooks.md`
|
|
88
92
|
- "Enable provider tools / integrations / API key connection for a provider / agent integration access" → `references/integrations.md`
|
|
89
93
|
- "Firecrawl / scrape a public website / competitor research / agent web research" → `references/integrations.md` **+ load `references/integrations/firecrawl.md`**
|
|
90
94
|
- "Check credits / credit balance / can I keep using AI / billing credits / running low / how many credits are left" → `references/credits.md`
|
|
@@ -20,6 +20,8 @@ Steps 1, 3, and 5 reference the project skill (`fimo`) for shape and React API.
|
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
fimo schemas push [TypeName] # push JSON to API (create or update). Omit TypeName to push all.
|
|
23
|
+
fimo schemas push <TypeName> --rename old.path=new.path
|
|
24
|
+
# preserve a renamed field; repeat --rename for multiple fields.
|
|
23
25
|
# Pushing all sends every schema as ONE atomic batch, so types that
|
|
24
26
|
# reference each other (even cycles) can be added in a single push.
|
|
25
27
|
# Files not present are never deleted — use `schemas delete` for that.
|
|
@@ -32,11 +34,11 @@ The command is `fimo schemas` (plural). There is no singular `fimo schema` alias
|
|
|
32
34
|
|
|
33
35
|
All commands accept `-C, --cwd <dir>` to point at a different project directory.
|
|
34
36
|
|
|
35
|
-
Schema transitions are automatic. Adding fields and changing labels preserve content. Removing a field removes only
|
|
37
|
+
Schema transitions are automatic. Adding optional fields and changing labels preserve content. A new required field backfills its `default` only where existing values need it; the push fails safely when no default can satisfy existing content. Removing a nested field or block variant removes only those values. `string` and `text` preserve values in both directions. Other primitive changes convert safe values and reject unsafe ones without changing the schema or entries. Lowering block `max` trims from the end; raising `min` fills from the blocks `default` templates. A reference target change clears its connections. Use repeatable `--rename old.path=new.path` arguments when a field moved by name so the one-time migration preserves its values; the operation is not stored in schema JSON. Collection-to-singleton removes that type's entries and cleans inbound references; singleton-to-collection preserves its entry. Run `fimo validate` after pushing.
|
|
36
38
|
|
|
37
39
|
## Entries CLI commands
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
Use singular commands for one entry. Bulk create and per-entry bulk update also accept JSON files or stdin.
|
|
40
42
|
|
|
41
43
|
```bash
|
|
42
44
|
fimo entries create <TypeName> --body '<json>'
|
|
@@ -46,6 +48,11 @@ fimo entries list <TypeName> --locale es
|
|
|
46
48
|
fimo entries get <TypeName> <id> [--locale es]
|
|
47
49
|
fimo entries update <TypeName> <id> [--locale es] --body '<json>'
|
|
48
50
|
fimo entries delete <TypeName> <id> [--locale es]
|
|
51
|
+
fimo entries query (--sql '<select>' | --file <path> | --stdin)
|
|
52
|
+
fimo entries bulk-create <TypeName> (--body '<json-array>' | --file <path> | --stdin)
|
|
53
|
+
fimo entries bulk-update <TypeName> (--ids <id1>,<id2> | --where '<json>') --body '<json>'
|
|
54
|
+
fimo entries bulk-update <TypeName> (--file <path> | --stdin)
|
|
55
|
+
fimo entries bulk-delete <TypeName> (--ids <id1>,<id2> | --where '<json>') [--locale es]
|
|
49
56
|
```
|
|
50
57
|
|
|
51
58
|
`--body` is a **required** option on `create` and `update`. Its JSON shape (where `slug` goes, how `media` fields look, Tiptap richtext format) lives in `fimo/references/content.md`. **Always read that first before constructing an entry payload — slug must be inside `data`, media has a specific shape, richtext must be Tiptap JSONContent.**
|
|
@@ -74,6 +81,58 @@ Polymorphic references declare `targets: ["Post", "Product"]` instead of `target
|
|
|
74
81
|
|
|
75
82
|
In generated React code, the equivalent is `populate: ['author', 'contributors'] as const` in the schema hook/query params. Let hooks infer the result when possible; if a named TypeScript shape is needed, use the generated `BlogPostResult<TFields, TPopulate>` type documented in `fimo/references/content.md`. Writes use the separate generated `BlogPostInput` type.
|
|
76
83
|
|
|
84
|
+
### Read-only SQL
|
|
85
|
+
|
|
86
|
+
Use `entries query` when SQL is clearer than list filters, especially for grouping and aggregation. It requires content view access, accepts one `SELECT` statement, can only read the `entries` table, and supports common aggregation, JSON, text, date, and window functions. Queries time out after five seconds and return at most 1,000 rows.
|
|
87
|
+
|
|
88
|
+
**Never use SQL for content writes.** SQL writes are rejected because they would bypass schema validation, locale and reference handling, content-change events, and current or future webhooks. Use `entries create`, `entries update`, `entries delete`, or their bulk variants so every mutation follows the content domain path.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
fimo entries query --sql "SELECT content_type, count(*) AS total FROM entries GROUP BY content_type"
|
|
92
|
+
fimo entries query --sql "SELECT document_id AS id, data->>'title' AS title FROM entries WHERE content_type = 'BlogPost' LIMIT 20"
|
|
93
|
+
fimo entries query --file query.sql
|
|
94
|
+
cat query.sql | fimo entries query --stdin
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
SQL exposes the raw internal representation. `document_id` is the stable ID used by `fimo entries`, content tools, references, and the API. `id` is the internal ID of one exact locale variant. When query results will feed another Fimo command or tool, select `document_id AS id`; use `locale` to select a variant.
|
|
98
|
+
|
|
99
|
+
The available columns are `id`, `document_id`, `content_type`, `locale`, `slug`, `data`, `created_at`, and `updated_at`. Schema fields live inside the JSONB `data` column. If a safe read is blocked because a SQL function is unavailable, tell the user which function is missing and follow `references/support.md` to prepare a support report for approval. Do not bypass the restriction with a write.
|
|
100
|
+
|
|
101
|
+
### Bulk mutations
|
|
102
|
+
|
|
103
|
+
`bulk-create` takes an array of regular create bodies. Inline JSON, a file, and stdin all carry the same array shape:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
fimo entries bulk-create BlogPost --body '[{"data":{"title":"First"}},{"data":{"title":"Second"},"locale":"es"}]'
|
|
107
|
+
fimo entries bulk-create BlogPost --file posts.json
|
|
108
|
+
cat posts.json | fimo entries bulk-create BlogPost --stdin
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`bulk-update` applies the regular update body to explicit IDs or the normal `--where` filter:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
fimo entries bulk-update BlogPost --ids <id1>,<id2> --body '{"data":{"status":"published"}}'
|
|
115
|
+
fimo entries bulk-update BlogPost --where '{"status":"draft"}' --body '{"data":{"status":"published"}}'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
For different changes per entry, `--file` and `--stdin` accept an array of `{ "id", "body" }` records:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
[
|
|
122
|
+
{ "id": "<id1>", "body": { "data": { "status": "published" } } },
|
|
123
|
+
{ "id": "<id2>", "body": { "data": { "featured": true } } }
|
|
124
|
+
]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
fimo entries bulk-update BlogPost --file updates.json
|
|
129
|
+
cat updates.json | fimo entries bulk-update BlogPost --stdin
|
|
130
|
+
fimo entries bulk-delete BlogPost --ids <id1>,<id2>
|
|
131
|
+
fimo entries bulk-delete BlogPost --where '{"archived":true}'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Each bulk request handles at most 1,000 entries. Missing requested IDs do not fail valid work: the CLI prints a warning, and `--json` includes both a top-level `warnings` array and the exact IDs in `data.meta.missing`. Bulk writes use the same validation, locale, reference, and content-change paths as singular entry writes. They apply entries one at a time. Recoverable create and update errors report how many earlier entries were already changed.
|
|
135
|
+
|
|
77
136
|
For reference schema JSON and entry value shape, load `fimo/references/content.md` § Reference fields. The short version:
|
|
78
137
|
|
|
79
138
|
```json
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **Run via `npx fimo@latest <command>`** — always the latest CLI, no install needed.
|
|
4
4
|
|
|
5
|
-
Use Firecrawl when an agent needs to inspect public websites: landing-page research, competitor structure analysis, migration prep, link extraction, and factual page snapshots. Do not use Firecrawl for private URLs, logged-in websites, or content the user has not asked you to fetch.
|
|
5
|
+
Use Firecrawl when an agent needs to research or inspect public websites: direct web answers, landing-page research, competitor structure analysis, migration prep, link extraction, and factual page snapshots. Do not use Firecrawl for private URLs, logged-in websites, or content the user has not asked you to fetch.
|
|
6
6
|
|
|
7
7
|
Current execution support is `search`, `scrape`, `map`, `crawl`, and `monitor.*`.
|
|
8
8
|
|
|
@@ -47,6 +47,20 @@ Search the web:
|
|
|
47
47
|
fimo integrations run firecrawl search --query "Example Domain" --max-results 3
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
Search returns query-relevant excerpts with their source URLs. Narrow results when the request names a site, recency,
|
|
51
|
+
source type, category, or geography:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
fimo integrations run firecrawl search --query "latest React release" --sources web,news --freshness week
|
|
55
|
+
fimo integrations run firecrawl search --query "Firecrawl search API" --include-domains firecrawl.dev --categories research
|
|
56
|
+
fimo integrations run firecrawl search --query "Barcelona developer events" --location "Barcelona, Spain" --country ES
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Search options are `--sources web,news,images`, `--categories github,research,pdf`, `--include-domains`,
|
|
60
|
+
`--exclude-domains`, `--freshness hour|day|week|month|year`, `--location`, `--country`,
|
|
61
|
+
and `--no-highlights`. Do not combine `--include-domains` and `--exclude-domains`. Query-relevant highlights are on by
|
|
62
|
+
default.
|
|
63
|
+
|
|
50
64
|
Default markdown scrape:
|
|
51
65
|
|
|
52
66
|
```bash
|
|
@@ -179,10 +193,12 @@ fimo deploy
|
|
|
179
193
|
If they bring a key, run `fimo integrations connect firecrawl --name <name> --token-stdin`, then
|
|
180
194
|
`fimo integrations enable firecrawl --connection <name>`.
|
|
181
195
|
6. For one-off research, pick the smallest action that answers the question:
|
|
182
|
-
- `search` to
|
|
183
|
-
- `scrape` to read one known page.
|
|
196
|
+
- `search` to get query-relevant excerpts and source URLs.
|
|
197
|
+
- `scrape` to read one known page when the excerpt lacks context or exact wording matters.
|
|
184
198
|
- `map` to collect URLs from one site.
|
|
185
199
|
- `crawl --limit <small>` to read several pages.
|
|
200
|
+
Treat search excerpts as concise evidence for straightforward questions. Scrape the source for full context,
|
|
201
|
+
exact quotations, implementation details, ambiguous claims, or high-stakes verification.
|
|
186
202
|
7. For a project agent, update `integrations`, validate, preview with `fimo agents integrations <agent>`, then deploy.
|
|
187
203
|
8. Keep findings in the agent report or task output; do not write scraped content into source files unless the user asks.
|
|
188
204
|
|
|
@@ -204,7 +220,7 @@ fimo integrations run firecrawl scrape --url https://competitor.example --format
|
|
|
204
220
|
Find likely source pages:
|
|
205
221
|
|
|
206
222
|
```bash
|
|
207
|
-
fimo integrations run firecrawl search --query "acme pricing page" --max-results 5 --json
|
|
223
|
+
fimo integrations run firecrawl search --query "acme pricing page" --max-results 5 --include-domains acme.example --json
|
|
208
224
|
```
|
|
209
225
|
|
|
210
226
|
Collect a simple URL map:
|