fimo 0.14.0 → 0.15.0-staging.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/README.md +1 -0
  2. package/assets/astro/components/Boolean.astro +14 -0
  3. package/assets/astro/components/Date.astro +23 -0
  4. package/assets/astro/components/Image.astro +79 -0
  5. package/assets/astro/components/Json.astro +14 -0
  6. package/assets/astro/components/RichText.astro +17 -0
  7. package/assets/astro/components/StaticImage.astro +66 -0
  8. package/assets/astro/components/Text.astro +23 -0
  9. package/assets/astro/components/Video.astro +47 -0
  10. package/assets/astro/components/index.d.ts +8 -0
  11. package/assets/astro/components/index.js +8 -0
  12. package/assets/content-templates/shared/server.eta +56 -0
  13. package/assets/content-templates/sveltekit/content.eta +86 -0
  14. package/assets/skills/fimo/SKILL.md +13 -4
  15. package/assets/skills/fimo-cli/SKILL.md +28 -28
  16. package/assets/skills/fimo-cli/references/account.md +0 -2
  17. package/assets/skills/fimo-cli/references/agent-setup.md +7 -9
  18. package/assets/skills/fimo-cli/references/agents.md +0 -2
  19. package/assets/skills/fimo-cli/references/analytics.md +0 -2
  20. package/assets/skills/fimo-cli/references/assets.md +2 -4
  21. package/assets/skills/fimo-cli/references/branches.md +14 -15
  22. package/assets/skills/fimo-cli/references/content.md +9 -11
  23. package/assets/skills/fimo-cli/references/credits.md +0 -2
  24. package/assets/skills/fimo-cli/references/deploy.md +6 -7
  25. package/assets/skills/fimo-cli/references/describe.md +1 -3
  26. package/assets/skills/fimo-cli/references/domains.md +0 -2
  27. package/assets/skills/fimo-cli/references/forms.md +5 -7
  28. package/assets/skills/fimo-cli/references/history.md +0 -2
  29. package/assets/skills/fimo-cli/references/init.md +34 -26
  30. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +0 -2
  31. package/assets/skills/fimo-cli/references/integrations.md +0 -2
  32. package/assets/skills/fimo-cli/references/invite.md +0 -2
  33. package/assets/skills/fimo-cli/references/labels.md +5 -7
  34. package/assets/skills/fimo-cli/references/locales.md +2 -4
  35. package/assets/skills/fimo-cli/references/mcp.md +2 -4
  36. package/assets/skills/fimo-cli/references/media.md +0 -2
  37. package/assets/skills/fimo-cli/references/preview.md +0 -2
  38. package/assets/skills/fimo-cli/references/project-vars-and-secrets.md +1 -3
  39. package/assets/skills/fimo-cli/references/projects.md +1 -3
  40. package/assets/skills/fimo-cli/references/schedules.md +0 -2
  41. package/assets/skills/fimo-cli/references/support.md +0 -2
  42. package/assets/skills/fimo-cli/references/webhooks.md +0 -2
  43. package/assets/skills/fimo-code/SKILL.md +11 -3
  44. package/assets/skills/fimo-code/references/assets.md +2 -2
  45. package/assets/skills/fimo-code/references/content/clients.md +5 -1
  46. package/assets/skills/fimo-code/references/content.md +3 -1
  47. package/assets/skills/fimo-code/references/frameworks/astro.md +127 -0
  48. package/assets/skills/fimo-code/references/frameworks/compatibility.md +19 -0
  49. package/assets/skills/fimo-code/references/frameworks/hosting.md +15 -3
  50. package/assets/skills/fimo-code/references/frameworks/react-router.md +37 -209
  51. package/assets/skills/fimo-code/references/frameworks/sveltekit.md +110 -0
  52. package/assets/skills/fimo-code/references/frameworks/vite-react.md +35 -166
  53. package/assets/skills/fimo-code/references/labels.md +16 -6
  54. package/assets/skills/fimo-code/references/locales.md +3 -1
  55. package/assets/skills/fimo-code/references/ui.md +19 -15
  56. package/assets/skills/fimo-migration/SKILL.md +99 -146
  57. package/assets/skills/fimo-migration/references/frameworks/nextjs.md +26 -0
  58. package/assets/skills/fimo-migration/references/inventory/coordinator.md +40 -0
  59. package/assets/skills/fimo-migration/references/inventory/locales/next-intl.md +39 -0
  60. package/assets/skills/fimo-migration/references/inventory/locales.md +41 -0
  61. package/assets/skills/fimo-migration/references/workflow.md +3 -2
  62. package/assets/skills/fimo-migration/scripts/inventory/locales/next-intl.mjs +459 -0
  63. package/assets/skills/fimo-studio/SKILL.md +1 -1
  64. package/assets/skills/fimo-studio/references/project-creation.md +10 -18
  65. package/assets/starters/fimo-site/template/.fimo/agents/content-guide/capabilities.yaml +0 -1
  66. package/assets/starters/fimo-site/template/.fimo/agents/site-review/capabilities.yaml +0 -1
  67. package/assets/sveltekit/components/Boolean.svelte +19 -0
  68. package/assets/sveltekit/components/Date.svelte +33 -0
  69. package/assets/sveltekit/components/FimoProvider.svelte +35 -0
  70. package/assets/sveltekit/components/Image.svelte +80 -0
  71. package/assets/sveltekit/components/Json.svelte +18 -0
  72. package/assets/sveltekit/components/Label.svelte +16 -0
  73. package/assets/sveltekit/components/Number.svelte +21 -0
  74. package/assets/sveltekit/components/RichText.svelte +19 -0
  75. package/assets/sveltekit/components/Text.svelte +30 -0
  76. package/assets/sveltekit/components/Video.svelte +37 -0
  77. package/assets/sveltekit/components/index.d.ts +10 -0
  78. package/assets/sveltekit/components/index.js +10 -0
  79. package/dist/build/astro/config.d.ts +4 -0
  80. package/dist/build/astro/config.js +64 -0
  81. package/dist/build/next/config.js +16 -0
  82. package/dist/build/sveltekit/config.d.ts +6 -0
  83. package/dist/build/sveltekit/config.js +8 -0
  84. package/dist/build/sveltekit/data-id.d.ts +3 -0
  85. package/dist/build/sveltekit/data-id.js +171 -0
  86. package/dist/build/sveltekit/vite.d.ts +13 -0
  87. package/dist/build/sveltekit/vite.js +15 -0
  88. package/dist/build/vite/index.js +2 -0
  89. package/dist/build/vite/plugins/data-id.d.ts +9 -0
  90. package/dist/build/vite/plugins/data-id.js +6 -1
  91. package/dist/build/vite/plugins/runtime-env.d.ts +21 -0
  92. package/dist/build/vite/plugins/runtime-env.js +68 -0
  93. package/dist/cli/bundle.json +1 -1
  94. package/dist/cli/index.js +108 -101
  95. package/dist/runtime/app/FimoProviders.d.ts +1 -1
  96. package/dist/runtime/app/FimoProviders.js +11 -5
  97. package/dist/runtime/astro/internal.d.ts +6 -0
  98. package/dist/runtime/astro/internal.js +16 -0
  99. package/dist/runtime/astro/preview.d.ts +14 -0
  100. package/dist/runtime/astro/preview.js +103 -0
  101. package/dist/runtime/astro/render-rich-text.d.ts +2 -0
  102. package/dist/runtime/astro/render-rich-text.js +1 -0
  103. package/dist/runtime/astro/server-runtime.d.ts +3 -0
  104. package/dist/runtime/astro/server-runtime.js +20 -0
  105. package/dist/runtime/astro/server.d.ts +15 -0
  106. package/dist/runtime/astro/server.js +14 -0
  107. package/dist/runtime/content/client/collection-core.d.ts +2 -17
  108. package/dist/runtime/content/client/collection-core.js +15 -8
  109. package/dist/runtime/content/client/core-types.d.ts +96 -0
  110. package/dist/runtime/content/client/core-types.js +1 -0
  111. package/dist/runtime/content/client/internal.d.ts +4 -4
  112. package/dist/runtime/content/client/internal.js +4 -3
  113. package/dist/runtime/content/client/runtime.d.ts +1 -1
  114. package/dist/runtime/content/client/server-content-client.d.ts +3 -3
  115. package/dist/runtime/content/client/server-content-client.js +2 -29
  116. package/dist/runtime/content/client/singleton-core.d.ts +2 -9
  117. package/dist/runtime/content/client/singleton-core.js +9 -4
  118. package/dist/runtime/content/client/types.d.ts +5 -115
  119. package/dist/runtime/content/index.d.ts +3 -3
  120. package/dist/runtime/labels/fetch.js +5 -3
  121. package/dist/runtime/next/client.d.ts +2 -1
  122. package/dist/runtime/next/facade.d.ts +1 -1
  123. package/dist/runtime/next/provider.js +1 -1
  124. package/dist/runtime/next/server-runtime.js +1 -1
  125. package/dist/runtime/next/server.d.ts +5 -4
  126. package/dist/runtime/paths/get-fimo-paths.js +8 -3
  127. package/dist/runtime/preview/bridge.d.ts +8 -0
  128. package/dist/runtime/preview/bridge.js +20 -0
  129. package/dist/runtime/preview/location.d.ts +23 -0
  130. package/dist/runtime/preview/location.js +93 -0
  131. package/dist/runtime/preview/routes.d.ts +10 -0
  132. package/dist/runtime/preview/routes.js +29 -0
  133. package/dist/runtime/primitives/index.d.ts +4 -1
  134. package/dist/runtime/primitives/index.js +1 -0
  135. package/dist/runtime/primitives/lib/image-optimization.d.ts +27 -2
  136. package/dist/runtime/primitives/lib/image-optimization.js +40 -0
  137. package/dist/runtime/primitives/lib/index.d.ts +1 -1
  138. package/dist/runtime/primitives/lib/primitives.d.ts +0 -54
  139. package/dist/runtime/primitives/lib/primitives.js +6 -0
  140. package/dist/runtime/primitives/lib/render-rich-text.d.ts +3 -0
  141. package/dist/runtime/primitives/lib/render-rich-text.js +112 -0
  142. package/dist/runtime/react/primitives/contracts.d.ts +40 -2
  143. package/dist/runtime/react/primitives/renderers/ImageRenderer.js +15 -34
  144. package/dist/runtime/react/primitives/renderers/RichTextRenderer.d.ts +2 -1
  145. package/dist/runtime/react/primitives/renderers/StaticImage.js +13 -30
  146. package/dist/runtime/routing/AppRoutesProvider.js +20 -8
  147. package/dist/runtime/shared/env-identity.d.ts +43 -0
  148. package/dist/runtime/shared/env-identity.js +88 -0
  149. package/dist/runtime/shared/local-runtime-env.d.ts +65 -0
  150. package/dist/runtime/shared/local-runtime-env.js +169 -0
  151. package/dist/runtime/{react-router → shared}/preview-location.d.ts +7 -13
  152. package/dist/runtime/{react-router → shared}/preview-location.js +26 -27
  153. package/dist/runtime/sveltekit/content.d.ts +25 -0
  154. package/dist/runtime/sveltekit/content.js +33 -0
  155. package/dist/runtime/sveltekit/context-contract.d.ts +5 -0
  156. package/dist/runtime/sveltekit/context-contract.js +2 -0
  157. package/dist/runtime/sveltekit/context.d.ts +8 -0
  158. package/dist/runtime/sveltekit/context.js +25 -0
  159. package/dist/runtime/sveltekit/index.d.ts +7 -0
  160. package/dist/runtime/sveltekit/index.js +4 -0
  161. package/dist/runtime/sveltekit/internal.d.ts +6 -0
  162. package/dist/runtime/sveltekit/internal.js +12 -0
  163. package/dist/runtime/sveltekit/labels.d.ts +16 -0
  164. package/dist/runtime/sveltekit/labels.js +13 -0
  165. package/dist/runtime/sveltekit/preview.d.ts +19 -0
  166. package/dist/runtime/sveltekit/preview.js +77 -0
  167. package/dist/runtime/sveltekit/runtime.d.ts +8 -0
  168. package/dist/runtime/sveltekit/runtime.js +17 -0
  169. package/dist/runtime/templates.d.ts +1 -1
  170. package/dist/runtime/templates.js +1 -1
  171. package/dist/runtime/vite/Label.d.ts +13 -0
  172. package/dist/runtime/vite/Label.js +16 -0
  173. package/dist/scripts/extract-translations.js +103 -43
  174. package/dist/scripts/sync-forms.js +1 -1
  175. package/dist/scripts/sync-schemas.js +83 -16
  176. package/package.json +57 -2
  177. package/release.json +2 -2
  178. package/templates/nextjs/AGENTS.md +10 -5
  179. package/templates/nextjs/_gitignore +1 -0
  180. package/templates/react-router/AGENTS.md +4 -3
  181. package/templates/react-router/package.json +1 -1
  182. package/templates/sveltekit/.fimo/config.json +15 -0
  183. package/templates/sveltekit/AGENTS.md +36 -0
  184. package/templates/sveltekit/CLAUDE.md +5 -0
  185. package/templates/sveltekit/_gitignore +16 -0
  186. package/templates/sveltekit/package.json +28 -0
  187. package/templates/sveltekit/pnpm-workspace.yaml +4 -0
  188. package/templates/sveltekit/src/app.html +11 -0
  189. package/templates/sveltekit/src/routes/+layout.server.ts +8 -0
  190. package/templates/sveltekit/src/routes/+layout.svelte +12 -0
  191. package/templates/sveltekit/src/routes/+page.svelte +48 -0
  192. package/templates/sveltekit/svelte.config.js +5 -0
  193. package/templates/sveltekit/tsconfig.json +14 -0
  194. package/templates/sveltekit/vite.config.ts +5 -0
  195. /package/assets/content-templates/{form-template.eta → forms/react.eta} +0 -0
  196. /package/assets/content-templates/{next-client-template.eta → next/client.eta} +0 -0
  197. /package/assets/content-templates/{next-server-template.eta → next/server.eta} +0 -0
  198. /package/assets/content-templates/{hooks-template.eta → react/client.eta} +0 -0
  199. /package/assets/content-templates/{types-template.eta → shared/types.eta} +0 -0
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Extract label keys from React components using oxc-parser.
2
+ * Extract label keys from application source.
3
3
  *
4
- * Labels are DB-owned. This scanner reports literal `t("key")` call sites so
5
- * `fimo validate` can verify the tenant DB contains visible values. It never
6
- * writes label values to local files.
4
+ * Labels are DB-owned. This scanner reports literal `t("key")` calls and
5
+ * literal `<Label value="key">` elements so `fimo validate` can verify that
6
+ * the tenant DB contains visible values. It never writes label values.
7
7
  */
8
8
  import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
10
  import { parseSync } from 'oxc-parser';
11
- function findReactFiles(dir, files = []) {
11
+ function findSourceFiles(dir, files = []) {
12
12
  if (!existsSync(dir)) {
13
13
  return files;
14
14
  }
@@ -20,67 +20,127 @@ function findReactFiles(dir, files = []) {
20
20
  if (entry === 'ui' || entry === 'node_modules') {
21
21
  continue;
22
22
  }
23
- findReactFiles(fullPath, files);
23
+ findSourceFiles(fullPath, files);
24
24
  }
25
- else if (/\.(ts|tsx|js|jsx)$/.test(entry)) {
25
+ else if (/\.(ts|tsx|js|jsx|svelte)$/.test(entry)) {
26
26
  files.push(fullPath);
27
27
  }
28
28
  }
29
29
  return files;
30
30
  }
31
- function extractFromFile(filePath) {
32
- const declarations = [];
33
- try {
34
- const code = readFileSync(filePath, 'utf-8');
35
- const result = parseSync(filePath, code);
36
- const ast = result.program;
37
- function visit(node) {
38
- if (!node || typeof node !== 'object') {
39
- return;
31
+ function importedNames(body, source, importedName) {
32
+ const names = new Set();
33
+ for (const statement of body) {
34
+ if (statement.type !== 'ImportDeclaration' || statement.source.value !== source) {
35
+ continue;
36
+ }
37
+ for (const specifier of statement.specifiers) {
38
+ if (specifier.type === 'ImportSpecifier' &&
39
+ specifier.imported.type === 'Identifier' &&
40
+ specifier.imported.name === importedName) {
41
+ names.add(specifier.local.name);
40
42
  }
41
- if (node.type === 'CallExpression') {
42
- const callee = node.callee;
43
- const isTranslationCall = (callee?.type === 'Identifier' && callee.name === 't') ||
44
- (callee?.type === 'MemberExpression' &&
45
- callee.computed === false &&
46
- callee.object?.type === 'Identifier' &&
47
- callee.object.name === 'labels' &&
48
- callee.property?.type === 'Identifier' &&
49
- callee.property.name === 't');
50
- if (isTranslationCall) {
51
- const args = node.arguments || [];
52
- const firstArg = args[0];
53
- if (firstArg?.type === 'Literal' && typeof firstArg.value === 'string') {
54
- const key = firstArg.value;
55
- declarations.push({ key, file: filePath });
56
- }
43
+ }
44
+ }
45
+ return names;
46
+ }
47
+ function extractFromModule(filePath, code, parsePath = filePath) {
48
+ const declarations = [];
49
+ const result = parseSync(parsePath, code);
50
+ const ast = result.program;
51
+ const fimoLabelNames = importedNames(ast.body, 'fimo/ui', 'Label');
52
+ function visit(node) {
53
+ if (!node || typeof node !== 'object') {
54
+ return;
55
+ }
56
+ if (node.type === 'CallExpression') {
57
+ const callee = node.callee;
58
+ const isTranslationCall = (callee?.type === 'Identifier' && callee.name === 't') ||
59
+ (callee?.type === 'MemberExpression' &&
60
+ callee.computed === false &&
61
+ callee.object?.type === 'Identifier' &&
62
+ callee.object.name === 'labels' &&
63
+ callee.property?.type === 'Identifier' &&
64
+ callee.property.name === 't');
65
+ if (isTranslationCall) {
66
+ const args = node.arguments || [];
67
+ const firstArg = args[0];
68
+ if (firstArg?.type === 'Literal' && typeof firstArg.value === 'string') {
69
+ declarations.push({ key: firstArg.value, file: filePath });
57
70
  }
58
71
  }
59
- for (const key of Object.keys(node)) {
60
- const child = node[key];
61
- if (Array.isArray(child)) {
62
- for (const item of child) {
63
- visit(item);
64
- }
72
+ }
73
+ if (node.type === 'JSXOpeningElement' &&
74
+ node.name?.type === 'JSXIdentifier' &&
75
+ fimoLabelNames.has(node.name.name)) {
76
+ for (const attribute of node.attributes ?? []) {
77
+ if (attribute?.type === 'JSXAttribute' &&
78
+ attribute.name?.type === 'JSXIdentifier' &&
79
+ attribute.name.name === 'value' &&
80
+ attribute.value?.type === 'Literal' &&
81
+ typeof attribute.value.value === 'string') {
82
+ declarations.push({ key: attribute.value.value, file: filePath });
65
83
  }
66
- else if (typeof child === 'object' && child !== null) {
67
- visit(child);
84
+ }
85
+ }
86
+ for (const key of Object.keys(node)) {
87
+ const child = node[key];
88
+ if (Array.isArray(child)) {
89
+ for (const item of child) {
90
+ visit(item);
68
91
  }
69
92
  }
93
+ else if (typeof child === 'object' && child !== null) {
94
+ visit(child);
95
+ }
70
96
  }
71
- visit(ast);
97
+ }
98
+ visit(ast);
99
+ return declarations;
100
+ }
101
+ const SVELTE_SCRIPT = /<script\b[^>]*>([\s\S]*?)<\/script>/gi;
102
+ const SVELTE_COMMENT = /<!--[\s\S]*?-->/g;
103
+ const SVELTE_T_CALL_KEY = /(?:\blabels\.t|(?<![\w$.])t)\(\s*(['"])([^'"]*)\1/g;
104
+ function extractFromSvelte(filePath, code) {
105
+ const declarations = [];
106
+ const labelNames = new Set();
107
+ const markup = code
108
+ .replace(SVELTE_SCRIPT, (_script, contents) => {
109
+ const ast = parseSync(`${filePath}.ts`, contents).program;
110
+ for (const name of importedNames(ast.body, 'fimo/sveltekit/components', 'Label')) {
111
+ labelNames.add(name);
112
+ }
113
+ declarations.push(...extractFromModule(filePath, contents, `${filePath}.ts`));
114
+ return '';
115
+ })
116
+ .replace(SVELTE_COMMENT, '');
117
+ for (const name of labelNames) {
118
+ const labelKey = new RegExp(`<${name}\\b[^>]*?\\svalue=(?:"([^"]*)"|'([^']*)')`, 'g');
119
+ for (const match of markup.matchAll(labelKey)) {
120
+ declarations.push({ key: (match[1] ?? match[2]), file: filePath });
121
+ }
122
+ }
123
+ for (const match of markup.matchAll(SVELTE_T_CALL_KEY)) {
124
+ declarations.push({ key: match[2], file: filePath });
125
+ }
126
+ return declarations;
127
+ }
128
+ function extractFromFile(filePath) {
129
+ try {
130
+ const code = readFileSync(filePath, 'utf-8');
131
+ return filePath.endsWith('.svelte') ? extractFromSvelte(filePath, code) : extractFromModule(filePath, code);
72
132
  }
73
133
  catch (error) {
74
134
  console.error(`Failed to parse ${filePath}:`, error);
135
+ return [];
75
136
  }
76
- return declarations;
77
137
  }
78
138
  export function extractLabelKeys(options = {}) {
79
139
  const cwd = options.cwd ?? process.cwd();
80
140
  const srcDir = join(cwd, 'src');
81
141
  const declarations = [];
82
142
  const seen = new Set();
83
- for (const file of findReactFiles(srcDir)) {
143
+ for (const file of findSourceFiles(srcDir)) {
84
144
  for (const declaration of extractFromFile(file)) {
85
145
  if (seen.has(declaration.key)) {
86
146
  continue;
@@ -44,7 +44,7 @@ export function syncForms(options = {}) {
44
44
  }
45
45
  };
46
46
  const formsDir = resolve(cwd, FORMS_REL);
47
- const templatePath = assetPath('content-templates', 'form-template.eta');
47
+ const templatePath = assetPath('content-templates', 'forms', 'react.eta');
48
48
  const templateSource = readFileSync(templatePath, 'utf-8');
49
49
  const eta = new Eta({ views: undefined, useWith: true, varName: 'it', autoEscape: false });
50
50
  const formFiles = getFormFiles(formsDir);
@@ -5,7 +5,7 @@ import { basename, dirname, join, resolve } from 'node:path';
5
5
  * hook files generated from the hooks template.
6
6
  *
7
7
  * - Scans `<cwd>/src/schemas/*.json`.
8
- * - Renders shared types plus either the React facade or split Next server/client facades.
8
+ * - Renders shared types plus the framework's React, Next, Astro, or SvelteKit facade.
9
9
  * - Creates/updates `<Pascal>.types.ts` and `<Pascal>.ts`, plus `<Pascal>.client.ts` for Next; deletes orphans.
10
10
  */
11
11
  import { camelCase, pascalCase } from 'change-case';
@@ -25,6 +25,14 @@ const SCHEMA_DEFINITION_SCHEMA = z.object({
25
25
  i18n: z.object({ enabled: z.boolean().optional() }).optional(),
26
26
  fields: z.record(z.string(), z.unknown()).optional(),
27
27
  });
28
+ const CONTENT_TEMPLATE_PATHS = {
29
+ types: { current: 'shared/types.eta', legacy: 'types-template.eta' },
30
+ sharedServer: { current: 'shared/server.eta' },
31
+ reactClient: { current: 'react/client.eta', legacy: 'hooks-template.eta' },
32
+ nextServer: { current: 'next/server.eta' },
33
+ nextClient: { current: 'next/client.eta' },
34
+ svelteKitContent: { current: 'sveltekit/content.eta' },
35
+ };
28
36
  function getSchemaFiles(schemasDir) {
29
37
  if (!existsSync(schemasDir)) {
30
38
  return [];
@@ -101,58 +109,117 @@ function resolveProjectRuntime(cwd) {
101
109
  packageRoot: dirname(packagePath),
102
110
  version,
103
111
  providesNextRuntime: packageExportsSubpath(packageJson, './next') && packageExportsSubpath(packageJson, './next/client'),
112
+ providesAstroRuntime: packageExportsSubpath(packageJson, './astro'),
113
+ providesSvelteKitRuntime: packageExportsSubpath(packageJson, './sveltekit'),
104
114
  };
105
115
  }
106
116
  function contentRuntimeImportFor(framework) {
107
- return framework === 'nextjs' ? 'fimo/next' : 'fimo/ui';
117
+ if (framework === 'nextjs') {
118
+ return 'fimo/next';
119
+ }
120
+ if (framework === 'astro') {
121
+ return 'fimo/astro';
122
+ }
123
+ // @vercel/frameworks reports SvelteKit as `sveltekit-1`, while Fimo's
124
+ // public runtime profile is `sveltekit`. Both describe the same codegen
125
+ // target; callers may supply either the detector evidence or the profile.
126
+ if (framework === 'sveltekit' || framework === 'sveltekit-1') {
127
+ return 'fimo/sveltekit';
128
+ }
129
+ return 'fimo/ui';
108
130
  }
109
- function templatePath(runtime, fileName) {
131
+ function templatePath(runtime, templateName) {
132
+ const template = CONTENT_TEMPLATE_PATHS[templateName];
110
133
  if (runtime && !isVersionAtLeast(runtime.version, MINIMUM_THIN_CONTENT_CLIENT_RUNTIME_VERSION)) {
111
- return join(runtime.packageRoot, 'assets', 'content-templates', fileName);
134
+ const legacyPath = 'legacy' in template ? template.legacy : template.current;
135
+ return join(runtime.packageRoot, 'assets', 'content-templates', legacyPath);
112
136
  }
113
- return assetPath('content-templates', fileName);
137
+ return assetPath('content-templates', template.current);
114
138
  }
115
139
  function resolveSchemaGenerationTarget(runtimeImport, runtime) {
116
140
  if (runtimeImport === 'fimo/ui') {
117
141
  return 'react';
118
142
  }
119
- if (!runtime.providesNextRuntime) {
143
+ if (runtimeImport === 'fimo/next' && !runtime.providesNextRuntime) {
120
144
  throw new Error(`Cannot generate schema clients because project-local fimo@${runtime.version} does not provide the ` +
121
145
  'fimo/next and fimo/next/client exports required by this Next.js project. ' +
122
146
  `Run \`${CONTENT_CLIENT_RUNTIME_UPGRADE_COMMAND}\` in the project, then run \`npx fimo@latest validate\` again. ` +
123
147
  'No generated files were changed.');
124
148
  }
125
- return 'next';
149
+ if (runtimeImport === 'fimo/astro' && !runtime.providesAstroRuntime) {
150
+ throw new Error(`Cannot generate schema clients because project-local fimo@${runtime.version} does not provide the ` +
151
+ 'fimo/astro export required by this Astro project. ' +
152
+ `Run \`${CONTENT_CLIENT_RUNTIME_UPGRADE_COMMAND}\` in the project, then run \`npx fimo@latest validate\` again. ` +
153
+ 'No generated files were changed.');
154
+ }
155
+ if (runtimeImport === 'fimo/sveltekit' && !runtime.providesSvelteKitRuntime) {
156
+ throw new Error(`Cannot generate schema clients because project-local fimo@${runtime.version} does not provide the ` +
157
+ 'fimo/sveltekit export required by this SvelteKit project. ' +
158
+ `Run \`${CONTENT_CLIENT_RUNTIME_UPGRADE_COMMAND}\` in the project, then run \`npx fimo@latest validate\` again. ` +
159
+ 'No generated files were changed.');
160
+ }
161
+ if (runtimeImport === 'fimo/next') {
162
+ return 'next';
163
+ }
164
+ return runtimeImport === 'fimo/astro' ? 'astro' : 'sveltekit';
126
165
  }
127
166
  function templatesForTarget(target, runtime, runtimeImport) {
128
167
  if (target === 'next') {
129
168
  return [
130
169
  {
131
170
  suffix: '.types.ts',
132
- path: templatePath(runtime, 'types-template.eta'),
171
+ path: templatePath(runtime, 'types'),
133
172
  runtimeImport: 'fimo/next',
134
173
  },
135
174
  {
136
175
  suffix: '.ts',
137
- path: templatePath(runtime, 'next-server-template.eta'),
176
+ path: templatePath(runtime, 'nextServer'),
138
177
  runtimeImport: 'fimo/next',
139
178
  },
140
179
  {
141
180
  suffix: '.client.ts',
142
- path: templatePath(runtime, 'next-client-template.eta'),
181
+ path: templatePath(runtime, 'nextClient'),
143
182
  runtimeImport: 'fimo/next/client',
144
183
  },
145
184
  ];
146
185
  }
186
+ if (target === 'astro') {
187
+ return [
188
+ {
189
+ suffix: '.types.ts',
190
+ path: templatePath(runtime, 'types'),
191
+ runtimeImport: 'fimo/astro',
192
+ },
193
+ {
194
+ suffix: '.ts',
195
+ path: templatePath(runtime, 'sharedServer'),
196
+ runtimeImport: 'fimo/astro',
197
+ },
198
+ ];
199
+ }
200
+ if (target === 'sveltekit') {
201
+ return [
202
+ {
203
+ suffix: '.types.ts',
204
+ path: templatePath(runtime, 'types'),
205
+ runtimeImport: 'fimo/sveltekit',
206
+ },
207
+ {
208
+ suffix: '.ts',
209
+ path: templatePath(runtime, 'svelteKitContent'),
210
+ runtimeImport: 'fimo/sveltekit',
211
+ },
212
+ ];
213
+ }
147
214
  return [
148
215
  {
149
216
  suffix: '.types.ts',
150
- path: templatePath(runtime, 'types-template.eta'),
217
+ path: templatePath(runtime, 'types'),
151
218
  runtimeImport,
152
219
  },
153
220
  {
154
221
  suffix: '.ts',
155
- path: templatePath(runtime, 'hooks-template.eta'),
222
+ path: templatePath(runtime, 'reactClient'),
156
223
  runtimeImport,
157
224
  },
158
225
  ];
@@ -219,7 +286,7 @@ function renderContentRegistry(schemas) {
219
286
  const imports = schemas.map(({ pascal }) => `import * as ${pascal} from "./${pascal}";`).join('\n');
220
287
  const entries = schemas.map(({ pascal, registryKey }) => ` ${registryKey}: ${pascal},`).join('\n');
221
288
  return `${GENERATED_REGISTRY_MARKER}
222
- // Server code imports this registry and passes it to createFimo({ content, locale }).
289
+ // Generated content registry for framework facades and project integrations.
223
290
 
224
291
  ${imports}
225
292
 
@@ -306,10 +373,10 @@ export function syncSchemas(options) {
306
373
  const runtime = schemas.length > 0 || generatedFilesOnDisk.length > 0 ? resolveProjectRuntime(cwd) : null;
307
374
  const runtimeImport = contentRuntimeImportFor(options.framework);
308
375
  const generationTarget = runtime ? resolveSchemaGenerationTarget(runtimeImport, runtime) : null;
309
- const needsNextRegistry = generationTarget === 'next' && schemas.length > 0;
376
+ const needsContentRegistry = (generationTarget === 'next' || generationTarget === 'sveltekit') && schemas.length > 0;
310
377
  const ownsExistingRegistry = existsSync(registryPath) && readFileSync(registryPath, 'utf-8').startsWith(GENERATED_REGISTRY_MARKER);
311
- const shouldGenerateRegistry = needsNextRegistry && (!existsSync(registryPath) || ownsExistingRegistry);
312
- if (needsNextRegistry && !shouldGenerateRegistry) {
378
+ const shouldGenerateRegistry = needsContentRegistry && (!existsSync(registryPath) || ownsExistingRegistry);
379
+ if (needsContentRegistry && !shouldGenerateRegistry) {
313
380
  log(`Kept project-owned schema barrel: ${registryPath}`);
314
381
  }
315
382
  const templates = generationTarget && runtime ? templatesForTarget(generationTarget, runtime, runtimeImport) : [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fimo",
3
- "version": "0.14.0",
3
+ "version": "0.15.0-staging.2",
4
4
  "description": "Fimo CLI - create, deploy, and manage Fimo projects",
5
5
  "bin": {
6
6
  "fimo": "dist/cli/index.js"
@@ -26,6 +26,22 @@
26
26
  "types": "./dist/runtime/content/index.d.ts",
27
27
  "import": "./dist/runtime/content/index.js"
28
28
  },
29
+ "./astro": {
30
+ "types": "./dist/runtime/astro/server.d.ts",
31
+ "import": "./dist/runtime/astro/server.js"
32
+ },
33
+ "./astro/components": {
34
+ "types": "./assets/astro/components/index.d.ts",
35
+ "import": "./assets/astro/components/index.js"
36
+ },
37
+ "./astro/config": {
38
+ "types": "./dist/build/astro/config.d.ts",
39
+ "import": "./dist/build/astro/config.js"
40
+ },
41
+ "./astro/internal": {
42
+ "types": "./dist/runtime/astro/internal.d.ts",
43
+ "import": "./dist/runtime/astro/internal.js"
44
+ },
29
45
  "./next": {
30
46
  "types": "./dist/runtime/next/server.d.ts",
31
47
  "import": "./dist/runtime/next/server.js"
@@ -51,6 +67,27 @@
51
67
  "types": "./dist/runtime/react-router/preset.d.ts",
52
68
  "import": "./dist/runtime/react-router/preset.js"
53
69
  },
70
+ "./sveltekit": {
71
+ "types": "./dist/runtime/sveltekit/index.d.ts",
72
+ "import": "./dist/runtime/sveltekit/index.js"
73
+ },
74
+ "./sveltekit/components": {
75
+ "types": "./assets/sveltekit/components/index.d.ts",
76
+ "svelte": "./assets/sveltekit/components/index.js",
77
+ "import": "./assets/sveltekit/components/index.js"
78
+ },
79
+ "./sveltekit/config": {
80
+ "types": "./dist/build/sveltekit/config.d.ts",
81
+ "import": "./dist/build/sveltekit/config.js"
82
+ },
83
+ "./sveltekit/internal": {
84
+ "types": "./dist/runtime/sveltekit/internal.d.ts",
85
+ "import": "./dist/runtime/sveltekit/internal.js"
86
+ },
87
+ "./sveltekit/vite": {
88
+ "types": "./dist/build/sveltekit/vite.d.ts",
89
+ "import": "./dist/build/sveltekit/vite.js"
90
+ },
54
91
  "./paths": {
55
92
  "types": "./dist/runtime/paths/index.d.ts",
56
93
  "import": "./dist/runtime/paths/index.js"
@@ -84,12 +121,18 @@
84
121
  "publish:dry-run": "npm publish --dry-run",
85
122
  "postinstall": "node scripts/postinstall.mjs",
86
123
  "test": "vitest run",
87
- "test:integration:next": "vitest run --config vitest.integration.config.ts",
124
+ "test:integration:astro": "vitest run --config vitest.integration.config.ts test/integration/astro-runtime.test.ts",
125
+ "test:integration:astro-compat": "vitest run --config vitest.integration.config.ts test/integration/astro-compat.test.ts",
126
+ "test:integration:frameworks": "vitest run --config vitest.integration.config.ts",
127
+ "test:integration:next": "vitest run --config vitest.integration.config.ts test/integration/next-runtime.test.ts",
128
+ "test:integration:sveltekit": "vitest run --config vitest.integration.config.ts test/integration/sveltekit-runtime.test.ts",
88
129
  "test:watch": "vitest",
89
130
  "clean": "rm -rf dist *.tsbuildinfo"
90
131
  },
91
132
  "dependencies": {
133
+ "@astrojs/vercel": "11.0.4",
92
134
  "@rollup/pluginutils": "^5.1.0",
135
+ "@sveltejs/adapter-vercel": "6.3.4",
93
136
  "change-case": "^5.4.4",
94
137
  "eta": "^3.5.0",
95
138
  "oxc-parser": "^0.118.0",
@@ -127,16 +170,25 @@
127
170
  "yaml": "2.8.2"
128
171
  },
129
172
  "peerDependencies": {
173
+ "@sveltejs/kit": "^2.0.0",
130
174
  "@tanstack/react-query": "^5.80.6",
175
+ "astro": "^5.0.0 || ^6.0.0 || ^7.0.0",
131
176
  "react": "^18.2.0 || ^19.0.0",
132
177
  "react-dom": "^18.2.0 || ^19.0.0",
133
178
  "react-router": "^7.0.0 || ^8.0.0",
179
+ "svelte": "^5.0.0",
134
180
  "vite": "^7.0.0 || ^8.0.0"
135
181
  },
136
182
  "peerDependenciesMeta": {
137
183
  "@tanstack/react-query": {
138
184
  "optional": true
139
185
  },
186
+ "@sveltejs/kit": {
187
+ "optional": true
188
+ },
189
+ "astro": {
190
+ "optional": true
191
+ },
140
192
  "react": {
141
193
  "optional": true
142
194
  },
@@ -146,6 +198,9 @@
146
198
  "react-router": {
147
199
  "optional": true
148
200
  },
201
+ "svelte": {
202
+ "optional": true
203
+ },
149
204
  "vite": {
150
205
  "optional": true
151
206
  }
package/release.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "source": "npm",
3
- "apiUrl": "https://api.fimo.ai",
4
- "webUrl": "https://fimo.ai"
3
+ "apiUrl": "https://api.staging.fimo.team",
4
+ "webUrl": "https://staging.fimo.team"
5
5
  }
@@ -4,14 +4,18 @@ This is a Fimo project. Fimo connects content, media, forms, analytics, editing,
4
4
 
5
5
  ## Load the Fimo skills before doing Fimo work
6
6
 
7
- Load only the skill relevant to the task:
7
+ Before writing schema-driven code, running CLI/deploy workflows, or migrating content, load only the
8
+ skill relevant to the task. During onboarding, preserve the exact CLI invocation prefix from the
9
+ initiating prompt for every operational command; otherwise default to `npx fimo@latest`:
8
10
 
9
11
  ```bash
10
- pnpm exec fimo skills get fimo-code # code and framework APIs from this project runtime
11
- npx fimo@latest skills get fimo-cli # operational workflows: push, deploy, labels, domains
12
+ pnpm exec fimo skills get fimo-code # match the lockfile; code + framework APIs come from this project runtime
13
+ npx fimo@latest skills get fimo-cli # default prefix; keep the onboarding prefix when one was supplied
12
14
  ```
13
15
 
14
- Use the command that matches the project lockfile. Add `--ref <doc>` for one reference at a time. For Next.js code, start with `fimo-code --ref frameworks/next`, then load the App Router, Pages Router, or locale reference only when needed.
16
+ Use `npm exec fimo`, `yarn fimo`, or `bunx --no-install fimo` instead of `pnpm exec fimo` when that
17
+ matches the project lockfile. Add `--ref <doc>` for one reference at a time. Do not load `fimo-cli` for
18
+ a code-only task, or use `npx fimo@latest` for project-local code generation and validation.
15
19
 
16
20
  ## Never hardcode editable values
17
21
 
@@ -26,10 +30,11 @@ The scaffolded homepage is disposable. Replace it on the first real generation.
26
30
 
27
31
  1. Start the application with the project package manager (`pnpm dev`, `npm run dev`, `yarn dev`, or `bun dev`).
28
32
  2. Build and verify against the local server.
29
- 3. Offer `fimo deploy` for a hosted preview or `fimo deploy --publish` to go live. Deploy only after the developer confirms.
33
+ 3. When a unit of work is done, **offer** to deploy: `fimo deploy` for a hosted preview / shareable link, or `fimo deploy --publish` to go live. Deploy on the developer's request or confirmation. The one exception: new-project onboarding creates a single first hosted preview automatically unless the developer said not to deploy. Never publish without an explicit request.
30
34
 
31
35
  ## Project rules
32
36
 
37
+ - **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
33
38
  - The application owns routes, locale resolution, links, HTML language/direction, and SEO. Fimo connects to those decisions.
34
39
  - Do not add a second deployment platform.
35
40
  - Never edit `.fimo/project.json`; it links this directory to the remote project.
@@ -7,6 +7,7 @@ node_modules/
7
7
  # Build outputs
8
8
  .next/
9
9
  out/
10
+ .vercel/
10
11
  next-env.d.ts
11
12
  *.tsbuildinfo
12
13
 
@@ -9,11 +9,12 @@ When asked to create or manage an agent in this project, use Fimo's agent workfl
9
9
  ## Load the Fimo skills before doing Fimo work
10
10
 
11
11
  Before writing schema-driven code, running CLI/deploy workflows, or migrating content, load only the
12
- skill relevant to the task:
12
+ skill relevant to the task. During onboarding, preserve the exact CLI invocation prefix from the
13
+ initiating prompt for every operational command; otherwise default to `npx fimo@latest`:
13
14
 
14
15
  ```bash
15
16
  pnpm exec fimo skills get fimo-code # match the lockfile; code + framework APIs come from this project runtime
16
- npx fimo@latest skills get fimo-cli # operational workflows: push, deploy, labels, domains
17
+ npx fimo@latest skills get fimo-cli # default prefix; keep the onboarding prefix when one was supplied
17
18
  ```
18
19
 
19
20
  Use `npm exec fimo`, `yarn fimo`, or `bunx --no-install fimo` instead of `pnpm exec fimo` when that
@@ -34,7 +35,7 @@ breaks that. Load `fimo-code` for the exact primitives, but the rule is:
34
35
 
35
36
  1. Start the dev server with the project's package manager (`pnpm dev`, `npm run dev`, …) — live reload on localhost.
36
37
  2. Make edits; the running server shows them instantly. No deploy needed to see local changes.
37
- 3. When a unit of work is done, **offer** to deploy: `fimo deploy` for a hosted preview / shareable link, or `fimo deploy --publish` to go live. Only after the developer confirms — never deploy on your own.
38
+ 3. When a unit of work is done, **offer** to deploy: `fimo deploy` for a hosted preview / shareable link, or `fimo deploy --publish` to go live. Deploy on the developer's request or confirmation. The one exception: new-project onboarding creates a single first hosted preview automatically unless the developer said not to deploy. Never publish without an explicit request.
38
39
 
39
40
  ## Project rules
40
41
 
@@ -21,7 +21,7 @@
21
21
  "cmdk": "^1.1.1",
22
22
  "date-fns": "^4.1.0",
23
23
  "embla-carousel-react": "^8.6.0",
24
- "fimo": "0.14.0",
24
+ "fimo": "0.15.0-staging.2",
25
25
  "input-otp": "^1.4.2",
26
26
  "isbot": "^5",
27
27
  "lucide-react": "^0.577.0",
@@ -0,0 +1,15 @@
1
+ {
2
+ "runtime": { "framework": "sveltekit" },
3
+ "i18n": {
4
+ "defaultLocale": "en",
5
+ "locales": ["en"]
6
+ },
7
+ "routes": {
8
+ "home": {
9
+ "label": "Home",
10
+ "path": "/"
11
+ }
12
+ },
13
+ "version": "4",
14
+ "source": "cli"
15
+ }
@@ -0,0 +1,36 @@
1
+ # Fimo project
2
+
3
+ This SvelteKit application is connected to Fimo for content, editing, environments, and hosting.
4
+
5
+ ## Load the Fimo skills before doing Fimo work
6
+
7
+ Before writing schema-driven code, running CLI/deploy workflows, or migrating content, load only the
8
+ skill relevant to the task. During onboarding, preserve the exact CLI invocation prefix from the
9
+ initiating prompt for every operational command; otherwise default to `npx fimo@latest`:
10
+
11
+ ```bash
12
+ pnpm exec fimo skills get fimo-code
13
+ pnpm exec fimo skills get fimo-code --ref frameworks/sveltekit
14
+ npx fimo@latest skills get fimo-cli
15
+ ```
16
+
17
+ Use `npm exec fimo`, `yarn fimo`, or `bunx --no-install fimo` instead of `pnpm exec fimo` when that
18
+ matches the project lockfile. Add `--ref <doc>` for one reference at a time. Do not load `fimo-cli` for
19
+ a code-only task, or use `npx fimo@latest` for project-local code generation and validation.
20
+
21
+ ## Development loop
22
+
23
+ 1. Start the application with the project package manager (`pnpm dev`, `npm run dev`, `yarn dev`, or `bun dev`).
24
+ 2. Build and verify against the local server.
25
+ 3. When a unit of work is done, **offer** to deploy: `fimo deploy` for a hosted preview / shareable link, or `fimo deploy --publish` to go live. Deploy on the developer's request or confirmation. The one exception: new-project onboarding creates a single first hosted preview automatically unless the developer said not to deploy. Never publish without an explicit request.
26
+
27
+ ## Project rules
28
+
29
+ - **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
30
+ - The application owns routes, locale resolution, links, HTML language/direction, and SEO. Fimo connects to those decisions.
31
+ - Do not add a second deployment platform.
32
+ - Never edit `.fimo/project.json`; it links this directory to the remote project.
33
+ - Keep secrets in the Fimo dashboard, not committed environment files.
34
+ - Pass flags to interactive Fimo commands when scripting them.
35
+
36
+ The scaffolded homepage is disposable. Replace it when building the requested site.
@@ -0,0 +1,5 @@
1
+ # Fimo project
2
+
3
+ Instructions for this project live in `AGENTS.md`. Read it:
4
+
5
+ @AGENTS.md
@@ -0,0 +1,16 @@
1
+ # System files
2
+ .DS_Store
3
+
4
+ # Dependencies
5
+ node_modules/
6
+
7
+ # Build outputs
8
+ .svelte-kit/
9
+ .vercel/
10
+ build/
11
+ *.tsbuildinfo
12
+
13
+ # Env
14
+ .env
15
+ .env.*
16
+ !.env.example