fimo 0.8.0-staging.3 → 0.9.0-experimental.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.
Files changed (189) hide show
  1. package/assets/content-templates/hooks-template.eta +4 -2
  2. package/assets/content-templates/types-template.eta +66 -1
  3. package/assets/skills/fimo/SKILL.md +1 -1
  4. package/assets/skills/fimo/references/content.md +86 -15
  5. package/assets/skills/fimo-cli/SKILL.md +6 -2
  6. package/assets/skills/fimo-cli/references/content.md +61 -2
  7. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +20 -4
  8. package/assets/skills/fimo-cli/references/integrations.md +5 -1
  9. package/assets/skills/fimo-cli/references/webhooks.md +162 -0
  10. package/assets/skills/fimo-migration/SKILL.md +22 -2
  11. package/assets/skills/fimo-migration/references/content.md +24 -0
  12. package/assets/skills/fimo-migration/references/manifest.md +35 -0
  13. package/assets/skills/fimo-migration/references/qa.md +24 -2
  14. package/assets/skills/fimo-migration/references/workflow.md +12 -1
  15. package/assets/skills/fimo-migration/references/wrap.md +617 -0
  16. package/assets/skills/fimo-studio/SKILL.md +5 -3
  17. package/assets/skills/fimo-studio/references/cms.md +9 -1
  18. package/assets/skills/fimo-studio/references/visual-editing.md +5 -3
  19. package/assets/skills/fimo-studio/references/webhooks.md +42 -0
  20. package/dist/build/vite/plugins/translations.d.ts +2 -8
  21. package/dist/build/vite/plugins/translations.js +3 -121
  22. package/dist/cli/bundle.json +1 -1
  23. package/dist/cli/index.js +1051 -144
  24. package/dist/runtime/app/FimoProviders.d.ts +1 -11
  25. package/dist/runtime/app/FimoProviders.js +2 -23
  26. package/dist/runtime/astro/index.d.ts +2 -0
  27. package/dist/runtime/astro/index.js +3 -0
  28. package/dist/runtime/astro/server.d.ts +3 -0
  29. package/dist/runtime/astro/server.js +6 -0
  30. package/dist/runtime/content/client/internal.js +1 -0
  31. package/dist/runtime/content/client/types.d.ts +16 -0
  32. package/dist/runtime/i18n/FimoLocaleContext.js +1 -0
  33. package/dist/runtime/next/FimoNextProviders.d.ts +24 -0
  34. package/dist/runtime/next/FimoNextProviders.js +20 -0
  35. package/dist/runtime/next/FimoNextScripts.d.ts +10 -0
  36. package/dist/runtime/next/FimoNextScripts.js +19 -0
  37. package/dist/runtime/next/index.d.ts +14 -0
  38. package/dist/runtime/next/index.js +14 -0
  39. package/dist/runtime/next/server.d.ts +2 -0
  40. package/dist/runtime/next/server.js +4 -0
  41. package/dist/runtime/nuxt/composables.d.ts +9 -0
  42. package/dist/runtime/nuxt/composables.js +57 -0
  43. package/dist/runtime/nuxt/index.d.ts +3 -0
  44. package/dist/runtime/nuxt/index.js +6 -0
  45. package/dist/runtime/nuxt/server.d.ts +3 -0
  46. package/dist/runtime/nuxt/server.js +6 -0
  47. package/dist/runtime/primitives/labels-hook.d.ts +33 -0
  48. package/dist/runtime/primitives/labels-hook.js +41 -0
  49. package/dist/runtime/primitives/labels-store.d.ts +12 -0
  50. package/dist/runtime/primitives/labels-store.js +60 -0
  51. package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +5 -3
  52. package/dist/runtime/primitives/lib/useFimoLiveValue.js +11 -4
  53. package/dist/runtime/primitives/translations.d.ts +1 -27
  54. package/dist/runtime/primitives/translations.js +7 -85
  55. package/dist/runtime/react/FimoSpaProviders.d.ts +36 -0
  56. package/dist/runtime/react/FimoSpaProviders.js +63 -0
  57. package/dist/runtime/react/index.d.ts +33 -0
  58. package/dist/runtime/react/index.js +39 -0
  59. package/dist/runtime/remix/FimoRemixProviders.d.ts +16 -0
  60. package/dist/runtime/remix/FimoRemixProviders.js +12 -0
  61. package/dist/runtime/remix/FimoRemixScripts.d.ts +10 -0
  62. package/dist/runtime/remix/FimoRemixScripts.js +19 -0
  63. package/dist/runtime/remix/index.d.ts +12 -0
  64. package/dist/runtime/remix/index.js +11 -0
  65. package/dist/runtime/remix/server.d.ts +2 -0
  66. package/dist/runtime/remix/server.js +2 -0
  67. package/dist/runtime/shared/display-routes.d.ts +14 -0
  68. package/dist/runtime/shared/display-routes.js +25 -0
  69. package/dist/runtime/shared/fimo-config.server.js +1 -0
  70. package/dist/runtime/shared/fimo-config.types.d.ts +2 -0
  71. package/dist/runtime/shared/i18n-messages.d.ts +29 -0
  72. package/dist/runtime/shared/i18n-messages.js +79 -0
  73. package/dist/runtime/shared/labels-fetch.pure.d.ts +17 -0
  74. package/dist/runtime/shared/labels-fetch.pure.js +71 -0
  75. package/dist/runtime/shared/labels-fetch.server.d.ts +7 -0
  76. package/dist/runtime/shared/labels-fetch.server.js +97 -0
  77. package/dist/runtime/shared/labels-t.pure.d.ts +2 -0
  78. package/dist/runtime/shared/labels-t.pure.js +10 -0
  79. package/dist/runtime/strapi/client.d.ts +30 -0
  80. package/dist/runtime/strapi/client.js +89 -0
  81. package/dist/runtime/strapi/index.d.ts +5 -0
  82. package/dist/runtime/strapi/index.js +6 -0
  83. package/dist/runtime/strapi/reshape.d.ts +46 -0
  84. package/dist/runtime/strapi/reshape.js +114 -0
  85. package/dist/runtime/svelte/index.d.ts +3 -0
  86. package/dist/runtime/svelte/index.js +7 -0
  87. package/dist/runtime/svelte/server.d.ts +3 -0
  88. package/dist/runtime/svelte/server.js +6 -0
  89. package/dist/runtime/vue/index.d.ts +3 -0
  90. package/dist/runtime/vue/index.js +5 -0
  91. package/dist/runtime/vue/server.d.ts +3 -0
  92. package/dist/runtime/vue/server.js +6 -0
  93. package/dist/runtime/wrapped/FimoFileLink.d.ts +17 -0
  94. package/dist/runtime/wrapped/FimoFileLink.js +19 -0
  95. package/dist/runtime/wrapped/FimoMediaImage.d.ts +14 -0
  96. package/dist/runtime/wrapped/FimoMediaImage.js +20 -0
  97. package/dist/runtime/wrapped/FimoMediaVideo.d.ts +14 -0
  98. package/dist/runtime/wrapped/FimoMediaVideo.js +20 -0
  99. package/dist/runtime/wrapped/FimoRichTextBlock.d.ts +23 -0
  100. package/dist/runtime/wrapped/FimoRichTextBlock.js +22 -0
  101. package/dist/runtime/wrapped/FimoText.d.ts +22 -0
  102. package/dist/runtime/wrapped/FimoText.js +20 -0
  103. package/dist/runtime/wrapped/WrappedContentContext.d.ts +28 -0
  104. package/dist/runtime/wrapped/WrappedContentContext.js +30 -0
  105. package/dist/runtime/wrapped/WrappedProviders.d.ts +33 -0
  106. package/dist/runtime/wrapped/WrappedProviders.js +101 -0
  107. package/dist/runtime/wrapped/dom.d.ts +4 -0
  108. package/dist/runtime/wrapped/dom.js +23 -0
  109. package/dist/runtime/wrapped/server.d.ts +77 -0
  110. package/dist/runtime/wrapped/server.js +237 -0
  111. package/dist/scripts/apply-wrap-templates.d.ts +61 -0
  112. package/dist/scripts/apply-wrap-templates.js +132 -0
  113. package/dist/scripts/apply-wrap.d.ts +46 -0
  114. package/dist/scripts/apply-wrap.js +278 -0
  115. package/dist/scripts/cms/discover.d.ts +2 -0
  116. package/dist/scripts/cms/discover.js +17 -0
  117. package/dist/scripts/cms/example-content.d.ts +33 -0
  118. package/dist/scripts/cms/example-content.js +162 -0
  119. package/dist/scripts/cms/strapi/detect.d.ts +2 -0
  120. package/dist/scripts/cms/strapi/detect.js +186 -0
  121. package/dist/scripts/cms/strapi/index.d.ts +3 -0
  122. package/dist/scripts/cms/strapi/index.js +25 -0
  123. package/dist/scripts/cms/strapi/list-source.d.ts +17 -0
  124. package/dist/scripts/cms/strapi/list-source.js +90 -0
  125. package/dist/scripts/cms/strapi/schema-map.d.ts +9 -0
  126. package/dist/scripts/cms/strapi/schema-map.js +277 -0
  127. package/dist/scripts/cms/strapi/shapes.d.ts +23 -0
  128. package/dist/scripts/cms/strapi/shapes.js +38 -0
  129. package/dist/scripts/cms/strapi/touchpoints.d.ts +31 -0
  130. package/dist/scripts/cms/strapi/touchpoints.js +145 -0
  131. package/dist/scripts/cms/strapi/wire-client.d.ts +15 -0
  132. package/dist/scripts/cms/strapi/wire-client.js +107 -0
  133. package/dist/scripts/cms/strapi/wiring.d.ts +17 -0
  134. package/dist/scripts/cms/strapi/wiring.js +46 -0
  135. package/dist/scripts/cms/types.d.ts +145 -0
  136. package/dist/scripts/cms/types.js +11 -0
  137. package/dist/scripts/detect-framework.d.ts +39 -0
  138. package/dist/scripts/detect-framework.js +133 -0
  139. package/dist/scripts/draft-rows.d.ts +19 -0
  140. package/dist/scripts/draft-rows.js +135 -0
  141. package/dist/scripts/draft-schemas.d.ts +27 -0
  142. package/dist/scripts/draft-schemas.js +188 -0
  143. package/dist/scripts/extract-translations.js +16 -11
  144. package/dist/scripts/frameworks/astro/routes.d.ts +3 -0
  145. package/dist/scripts/frameworks/astro/routes.js +55 -0
  146. package/dist/scripts/frameworks/astro/template-style.d.ts +7 -0
  147. package/dist/scripts/frameworks/astro/template-style.js +19 -0
  148. package/dist/scripts/frameworks/discover.d.ts +70 -0
  149. package/dist/scripts/frameworks/discover.js +178 -0
  150. package/dist/scripts/frameworks/next/rewire.d.ts +30 -0
  151. package/dist/scripts/frameworks/next/rewire.js +258 -0
  152. package/dist/scripts/frameworks/next/routes.d.ts +17 -0
  153. package/dist/scripts/frameworks/next/routes.js +134 -0
  154. package/dist/scripts/frameworks/next/wiring.d.ts +33 -0
  155. package/dist/scripts/frameworks/next/wiring.js +186 -0
  156. package/dist/scripts/frameworks/nuxt/routes.d.ts +3 -0
  157. package/dist/scripts/frameworks/nuxt/routes.js +54 -0
  158. package/dist/scripts/frameworks/nuxt/template-style.d.ts +9 -0
  159. package/dist/scripts/frameworks/nuxt/template-style.js +27 -0
  160. package/dist/scripts/frameworks/remix/routes.d.ts +3 -0
  161. package/dist/scripts/frameworks/remix/routes.js +50 -0
  162. package/dist/scripts/frameworks/support.d.ts +75 -0
  163. package/dist/scripts/frameworks/support.js +165 -0
  164. package/dist/scripts/frameworks/sveltekit/routes.d.ts +3 -0
  165. package/dist/scripts/frameworks/sveltekit/routes.js +50 -0
  166. package/dist/scripts/frameworks/sveltekit/template-style.d.ts +9 -0
  167. package/dist/scripts/frameworks/sveltekit/template-style.js +54 -0
  168. package/dist/scripts/frameworks/vite/routes.d.ts +15 -0
  169. package/dist/scripts/frameworks/vite/routes.js +93 -0
  170. package/dist/scripts/frameworks/vite/wiring.d.ts +10 -0
  171. package/dist/scripts/frameworks/vite/wiring.js +99 -0
  172. package/dist/scripts/i18n-namespace.d.ts +27 -0
  173. package/dist/scripts/i18n-namespace.js +155 -0
  174. package/dist/scripts/lib/validation-report.d.ts +1 -0
  175. package/dist/scripts/lib/validation-report.js +3 -0
  176. package/dist/scripts/render-parity/capture.d.ts +56 -0
  177. package/dist/scripts/render-parity/capture.js +366 -0
  178. package/dist/scripts/render-parity/compare.d.ts +59 -0
  179. package/dist/scripts/render-parity/compare.js +0 -0
  180. package/dist/scripts/render-parity/normalize-html.d.ts +13 -0
  181. package/dist/scripts/render-parity/normalize-html.js +223 -0
  182. package/dist/scripts/render-parity/types.d.ts +41 -0
  183. package/dist/scripts/render-parity/types.js +1 -0
  184. package/dist/scripts/scan-wrappable.d.ts +196 -0
  185. package/dist/scripts/scan-wrappable.js +1232 -0
  186. package/dist/scripts/validate-route-metadata.js +11 -0
  187. package/dist/scripts/validate-schemas.js +42 -1
  188. package/package.json +84 -4
  189. package/templates/react-router/package.json +1 -1
@@ -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(", ") %> },
@@ -70,7 +70,7 @@ if (model.fields) {
70
70
  Object.entries(model.fields).forEach(([key, field]) => {
71
71
  const type = getInputTypeForField(field);
72
72
  -%>
73
- <%= key %><%= field.required ? '' : '?' %>: <%= type %>;
73
+ <%= key %><%= isRequiredField(field) ? '' : '?' %>: <%= type %>;
74
74
  <%
75
75
  });
76
76
  }
@@ -85,6 +85,7 @@ if (model.fields) {
85
85
  function getTypeForField(field) {
86
86
  switch(field.type) {
87
87
  case 'string':
88
+ case 'text':
88
89
  return 'FimoString';
89
90
  case 'richtext':
90
91
  return 'FimoRichText';
@@ -102,6 +103,8 @@ function getTypeForField(field) {
102
103
  const raw = Array.isArray(field.targets) && field.targets.length > 0 ? 'FimoPolymorphicReference' : 'FimoReference';
103
104
  return field.many ? `${raw}[]` : `${raw} | null`;
104
105
  }
106
+ case 'blocks':
107
+ return getBlocksType(field, false);
105
108
  default:
106
109
  return 'any';
107
110
  }
@@ -110,6 +113,7 @@ function getTypeForField(field) {
110
113
  function getInputTypeForField(field) {
111
114
  switch(field.type) {
112
115
  case 'string':
116
+ case 'text':
113
117
  return 'string';
114
118
  case 'richtext':
115
119
  return 'FimoRichTextContent';
@@ -129,10 +133,71 @@ function getInputTypeForField(field) {
129
133
  const raw = Array.isArray(field.targets) && field.targets.length > 0 ? 'FimoPolymorphicReference' : 'FimoReference';
130
134
  return field.many ? `${raw}[]` : `${raw} | null`;
131
135
  }
136
+ case 'blocks':
137
+ return getBlocksType(field, true);
132
138
  default:
133
139
  return 'unknown';
134
140
  }
135
141
  }
142
+
143
+ function getNestedFieldType(field, input) {
144
+ switch(field.type) {
145
+ case 'string':
146
+ case 'text':
147
+ return 'string';
148
+ case 'richtext':
149
+ return 'FimoRichTextContent';
150
+ case 'number':
151
+ return 'number';
152
+ case 'boolean':
153
+ return 'boolean';
154
+ case 'date':
155
+ return 'string';
156
+ case 'json':
157
+ case 'media':
158
+ return 'Record<string, unknown>';
159
+ case 'reference': {
160
+ const raw = Array.isArray(field.targets) && field.targets.length > 0 ? 'FimoPolymorphicReference' : 'FimoReference';
161
+ return field.many ? `${raw}[]` : `${raw} | null`;
162
+ }
163
+ case 'blocks':
164
+ return getBlocksType(field, input);
165
+ default:
166
+ return 'unknown';
167
+ }
168
+ }
169
+
170
+ function getBlockObjectType(fields, input, metadata = {}) {
171
+ const properties = [];
172
+ if (metadata.key) {
173
+ properties.push(`_key${input ? '?' : ''}: string`);
174
+ }
175
+ if (metadata.type) {
176
+ properties.push(`_type: "${metadata.type}"`);
177
+ }
178
+ for (const [key, field] of Object.entries(fields || {})) {
179
+ properties.push(`${key}${isRequiredField(field) ? '' : '?'}: ${getNestedFieldType(field, input)}`);
180
+ }
181
+ return `{ ${properties.join('; ')} }`;
182
+ }
183
+
184
+ function getBlocksType(field, input) {
185
+ const schema = field.schema || {};
186
+ let item;
187
+ if (Array.isArray(schema.oneOf)) {
188
+ item = schema.oneOf
189
+ .map((variant) => getBlockObjectType(variant.fields, input, { key: true, type: variant.uid }))
190
+ .join(' | ') || 'never';
191
+ item = `(${item})`;
192
+ } else {
193
+ item = getBlockObjectType(schema.fields, input, { key: true });
194
+ }
195
+ return `${item}[]`;
196
+ }
197
+
198
+ function isRequiredField(field) {
199
+ return Boolean(field.required || (field.type === 'blocks' && Number(field.min || 0) > 0));
200
+ }
136
201
  -%>
137
202
 
138
203
  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@latest <command>` (always the latest, no global install). If `fimo-cli` isn't loaded for your AI tool, register it with `npx fimo@latest skills install --mode=copy`.
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` | `"..."` | Titles, short text |
51
- | `richtext` | Tiptap JSONContent (see below) | Blog body, descriptions, articles |
52
- | `number` | `42` | Counts, quantities |
53
- | `boolean` | `true` / `false` | Flags |
54
- | `date` | ISO date string, e.g. `"2026-06-03"` | Publish dates, timestamps |
55
- | `media` | `{ "source": "local"\|"external", "url": "https://...", "alt": "..." }` | Images, video |
56
- | `json` | any JSON | Structured metadata |
57
- | `reference` | `{ "id": "..." }`, `null`, or an array of reference objects when `many: true` | References to another schema |
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
- - Removing a field removes only that field's values.
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
- - A many-to-one change, reference target change, scalar type change, or scalar/reference change clears only the changed field.
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
- There are no reset or data-loss flags. Do not invent one or promise that incompatible field values survive; the schema change itself selects the behavior above.
179
+ Choose by editing intent:
113
180
 
114
- **Default to `richtext`** for fields named `body`, `content`, `description`, `summary`, `bio`, `intro`, `details`, `excerpt` — only use `string` when the field is explicitly short (e.g. a 160-char meta description).
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` |
@@ -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, check site traffic/analytics, invite collaborators, inspect
8
- AI credits, report a failing or slow Fimo API, rejected documented argument,
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 that field's values. One-to-many reference changes wrap existing references in arrays. Field type changes, scalar/reference changes, reference target changes, and many-to-one changes clear only the changed field. Collection-to-singleton removes that type's entries and cleans inbound references; singleton-to-collection preserves its entry. There are no reset or data-loss flags: changing the schema is the migration request. Run `fimo validate` after pushing to verify the regenerated client and whole project.
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
- Entries are NOT JSON-file-driven. Create/update them via CLI.
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 discover pages.
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:
@@ -67,7 +67,7 @@ Use `connect` for provider accounts, workspaces, OAuth installs, and API-key acc
67
67
  fimo integrations run firecrawl scrape --url https://example.com
68
68
  fimo integrations run firecrawl scrape --url https://example.com --formats markdown,summary,links
69
69
  fimo integrations run firecrawl scrape --url https://example.com --connection client-b
70
- fimo integrations run firecrawl search --query "Example Domain" --max-results 3
70
+ fimo integrations run firecrawl search --query "Example Domain" --max-results 3 --include-domains example.com
71
71
  fimo integrations run firecrawl map --url https://example.com --limit 20
72
72
  fimo integrations run firecrawl crawl --url https://example.com --limit 3 --formats markdown
73
73
  fimo integrations run firecrawl monitor.create --name pricing --url https://example.com/pricing --schedule hourly
@@ -76,6 +76,10 @@ fimo integrations run firecrawl monitor.list
76
76
 
77
77
  Firecrawl execution supports `search`, `scrape`, `map`, `crawl`, and `monitor.*` lifecycle tools. The default scrape/crawl output format is `markdown`; supported formats are `markdown`, `summary`, `links`, `images`, `html`, and `raw-html`.
78
78
 
79
+ Firecrawl search returns query-relevant excerpts by default. Use them for direct, sourced answers and scrape only when
80
+ full context or exact wording is needed. Search can be narrowed with source, category, domain, freshness, location,
81
+ and country options; see the Firecrawl reference for the full command shape.
82
+
79
83
  Use `--connection <alias>` only for one run when a named connection already exists. It does not change the project default
80
84
  integration setup.
81
85