fimo 2.6.0 → 2.7.0-staging.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/assets/skills/fimo-cli/SKILL.md +1 -1
  2. package/assets/skills/fimo-cli/references/analytics.md +14 -0
  3. package/assets/skills/fimo-cli/references/content.md +2 -2
  4. package/assets/skills/fimo-cli/references/hosting.md +11 -0
  5. package/assets/skills/fimo-cli/references/locales.md +2 -2
  6. package/assets/skills/fimo-cli/references/pages.md +14 -2
  7. package/assets/skills/fimo-code/references/frameworks/astro.md +2 -0
  8. package/assets/skills/fimo-code/references/frameworks/next.md +12 -9
  9. package/assets/skills/fimo-code/references/ui.md +6 -1
  10. package/assets/skills/fimo-migration/SKILL.md +9 -6
  11. package/assets/skills/fimo-migration/references/frameworks/nextjs.md +24 -27
  12. package/assets/skills/fimo-migration/references/media.md +98 -62
  13. package/assets/skills/fimo-migration/references/qa.md +111 -11
  14. package/assets/skills/fimo-migration/references/workers/content-execution.md +2 -1
  15. package/assets/skills/fimo-migration/references/workers/validator.md +22 -6
  16. package/assets/skills/fimo-migration/references/workers.md +5 -3
  17. package/assets/skills/fimo-migration/scripts/check-rendered-guardrails.mjs +500 -0
  18. package/assets/skills/fimo-studio/references/publish-and-deploy.md +1 -0
  19. package/dist/cli/bundle.json +1 -1
  20. package/dist/cli/index.js +26 -26
  21. package/dist/runtime/paths/get-fimo-paths.d.ts +3 -1
  22. package/dist/runtime/paths/get-fimo-paths.js +59 -5
  23. package/dist/runtime/primitives/lib/primitives.d.ts +20 -1
  24. package/dist/runtime/primitives/lib/primitives.js +24 -1
  25. package/dist/runtime/routes/index.d.ts +19 -3
  26. package/dist/runtime/routes/index.js +27 -2
  27. package/dist/scripts/validate-page-registry.js +14 -3
  28. package/package.json +10 -9
  29. package/release.json +2 -2
  30. package/templates/astro/package.json +2 -2
  31. package/templates/nextjs/package.json +3 -3
  32. package/templates/react-router/package.json +4 -4
  33. package/templates/sveltekit/package.json +2 -2
  34. package/templates/vite/package.json +4 -4
@@ -6,7 +6,9 @@ import type { FimoPath, GetFimoPathsOptions } from './types.js';
6
6
  *
7
7
  * - Static paths in config: emitted as-is.
8
8
  * - Dynamic paths (with `:slug`-style entry params): expanded by fetching
9
- * schema entries from `VITE_API_URL`. One returned entry per expansion.
9
+ * every schema entry from `VITE_API_URL`, page by page. One path per entry.
10
+ * - A route with an external param is never emitted: the application owns
11
+ * those values and lists those URLs itself.
10
12
  * - Locales come from the route contract, not from the project locale list: a
11
13
  * route is emitted once per locale only when its path declares a `:locale`
12
14
  * segment. The default locale is always unprefixed. A route without a
@@ -11,6 +11,9 @@ const isValidationBuild = !!process.env.FIMO_VALIDATION_BUILD;
11
11
  const MAX_FETCH_ATTEMPTS = 3;
12
12
  const RETRYABLE_FETCH_STATUSES = new Set([502, 503, 504]);
13
13
  const RETRY_BASE_DELAY_MS = 250;
14
+ // The content API pages with `limit` (capped at 100) and `offset`; its
15
+ // `meta.hasMore` says whether another page follows.
16
+ const ENTRIES_PAGE_SIZE = 100;
14
17
  function readEnvValue(rootDir, key) {
15
18
  if (process.env[key]) {
16
19
  return process.env[key];
@@ -42,9 +45,6 @@ function resolveApiBaseUrl(rootDir) {
42
45
  async function fetchEntries(baseUrl, schema, rootDir, locale) {
43
46
  const url = new URL(`${baseUrl.replace(/\/$/, '')}/entries/${schema}`);
44
47
  url.searchParams.set('locale', locale);
45
- if (isValidationBuild) {
46
- url.searchParams.set('limit', '1');
47
- }
48
48
  const headers = {};
49
49
  // `FIMO_ENV` is a customer-facing variable name and keeps its spelling; the
50
50
  // header this build emits is canonical. A
@@ -54,11 +54,47 @@ async function fetchEntries(baseUrl, schema, rootDir, locale) {
54
54
  if (branch) {
55
55
  headers['X-Fimo-Branch'] = branch;
56
56
  }
57
+ // A validation build only proves the route expands, so one entry is enough.
58
+ if (isValidationBuild) {
59
+ url.searchParams.set('limit', '1');
60
+ return (await fetchEntriesPage(url, headers, schema)).data;
61
+ }
62
+ // Every entry becomes a URL, so walk the whole collection page by page.
63
+ const entries = [];
64
+ let offset = 0;
65
+ for (;;) {
66
+ const pageUrl = new URL(url);
67
+ pageUrl.searchParams.set('limit', String(ENTRIES_PAGE_SIZE));
68
+ pageUrl.searchParams.set('offset', String(offset));
69
+ const page = await fetchEntriesPage(pageUrl, headers, schema);
70
+ entries.push(...page.data);
71
+ if (!page.meta) {
72
+ // Without pagination metadata a short page is the whole collection; a
73
+ // full one may hide more entries, and a truncated list is a silent bug.
74
+ if (page.data.length >= ENTRIES_PAGE_SIZE) {
75
+ throw new Error(`Entries response for ${schema} returned ${page.data.length} rows without pagination metadata, so every path cannot be enumerated.`);
76
+ }
77
+ return entries;
78
+ }
79
+ if (!page.meta.hasMore) {
80
+ return entries;
81
+ }
82
+ const nextOffset = page.meta.offset + page.meta.limit;
83
+ if (nextOffset <= offset) {
84
+ throw new Error(`Entries pagination for ${schema} did not advance past offset ${offset}.`);
85
+ }
86
+ offset = nextOffset;
87
+ }
88
+ }
89
+ async function fetchEntriesPage(url, headers, schema) {
57
90
  for (let attempt = 1; attempt <= MAX_FETCH_ATTEMPTS; attempt += 1) {
58
91
  const res = await fetch(url, { headers });
59
92
  if (res.ok) {
60
93
  const payload = (await res.json());
61
- return Array.isArray(payload?.data) ? payload.data : [];
94
+ return {
95
+ data: Array.isArray(payload?.data) ? payload.data : [],
96
+ meta: readPageMeta(payload?.meta),
97
+ };
62
98
  }
63
99
  if (!RETRYABLE_FETCH_STATUSES.has(res.status) || attempt === MAX_FETCH_ATTEMPTS) {
64
100
  const attemptDetail = attempt > 1 ? ` after ${attempt} attempts` : '';
@@ -68,6 +104,16 @@ async function fetchEntries(baseUrl, schema, rootDir, locale) {
68
104
  }
69
105
  throw new Error(`Failed to fetch ${schema}`);
70
106
  }
107
+ function readPageMeta(meta) {
108
+ if (!meta || typeof meta !== 'object') {
109
+ return undefined;
110
+ }
111
+ const { limit, offset, hasMore } = meta;
112
+ if (typeof limit !== 'number' || typeof offset !== 'number' || typeof hasMore !== 'boolean') {
113
+ return undefined;
114
+ }
115
+ return { limit, offset, hasMore };
116
+ }
71
117
  // Glob-ish matcher for route keys: '*' matches one segment, '**' matches any.
72
118
  function compilePattern(pattern) {
73
119
  const escaped = pattern
@@ -87,7 +133,9 @@ function matchesAny(routeKey, patterns) {
87
133
  *
88
134
  * - Static paths in config: emitted as-is.
89
135
  * - Dynamic paths (with `:slug`-style entry params): expanded by fetching
90
- * schema entries from `VITE_API_URL`. One returned entry per expansion.
136
+ * every schema entry from `VITE_API_URL`, page by page. One path per entry.
137
+ * - A route with an external param is never emitted: the application owns
138
+ * those values and lists those URLs itself.
91
139
  * - Locales come from the route contract, not from the project locale list: a
92
140
  * route is emitted once per locale only when its path declares a `:locale`
93
141
  * segment. The default locale is always unprefixed. A route without a
@@ -125,6 +173,12 @@ export async function getFimoPaths(opts = {}) {
125
173
  if (contract.unresolvedParams.length > 0) {
126
174
  return false;
127
175
  }
176
+ // Values the application owns cannot be enumerated here. The app lists
177
+ // those URLs itself — React Router `prerender`, Next `generateStaticParams`
178
+ // — and concatenates them with this result.
179
+ if (contract.externalParams.length > 0) {
180
+ return false;
181
+ }
128
182
  if (opts.include && opts.include.length > 0 && !matchesAny(contract.id, opts.include)) {
129
183
  return false;
130
184
  }
@@ -98,7 +98,24 @@ export declare class FimoMedia {
98
98
  get __fimo(): FimoSource;
99
99
  }
100
100
  /**
101
- * FimoBoolean - Boolean with source tracking (for display purposes)
101
+ * FimoBoolean - a boolean with source tracking.
102
+ *
103
+ * Read `.value` before any condition, comparison, attribute, or third-party
104
+ * call, and pass the wrapper itself to `<Boolean>` so Studio keeps the edit
105
+ * target.
106
+ *
107
+ * `if (entry.featured)` is ALWAYS true, including for `false`, because the
108
+ * wrapper is an object. That is a language rule, not a gap to close here:
109
+ * `ToBoolean` on an object never consults `valueOf`, `Symbol.toPrimitive`, a
110
+ * `Boolean` subclass, or a `Proxy`, and TypeScript reports nothing (it
111
+ * special-cases only Promises and functions). Removing the wrapper is the only
112
+ * real fix; do not add a coercion hook that appears to solve it.
113
+ *
114
+ * `toString` and `toJSON` cover the two boundaries that DO give us a hook, so
115
+ * the wrapper stops leaking there: `${flag}` reads `"true"`/`"false"` instead
116
+ * of `"[object Object]"`, and `JSON.stringify` emits `false` instead of
117
+ * `{"value":false}` — a payload that rehydrates as a permanently truthy object.
118
+ * Framework boundaries still use `serializeContent`, which also drops metadata.
102
119
  */
103
120
  export declare class FimoBoolean {
104
121
  readonly value: boolean;
@@ -107,6 +124,8 @@ export declare class FimoBoolean {
107
124
  constructor(value: boolean, source: string, context?: FimoSourceContext);
108
125
  get __fimo(): FimoSource;
109
126
  valueOf(): boolean;
127
+ toString(): string;
128
+ toJSON(): boolean;
110
129
  }
111
130
  /**
112
131
  * Tiptap JSONContent structure for rich text
@@ -180,7 +180,24 @@ export class FimoMedia {
180
180
  }
181
181
  _f = FIMO_SOURCE, _g = FIMO_SOURCE_CONTEXT;
182
182
  /**
183
- * FimoBoolean - Boolean with source tracking (for display purposes)
183
+ * FimoBoolean - a boolean with source tracking.
184
+ *
185
+ * Read `.value` before any condition, comparison, attribute, or third-party
186
+ * call, and pass the wrapper itself to `<Boolean>` so Studio keeps the edit
187
+ * target.
188
+ *
189
+ * `if (entry.featured)` is ALWAYS true, including for `false`, because the
190
+ * wrapper is an object. That is a language rule, not a gap to close here:
191
+ * `ToBoolean` on an object never consults `valueOf`, `Symbol.toPrimitive`, a
192
+ * `Boolean` subclass, or a `Proxy`, and TypeScript reports nothing (it
193
+ * special-cases only Promises and functions). Removing the wrapper is the only
194
+ * real fix; do not add a coercion hook that appears to solve it.
195
+ *
196
+ * `toString` and `toJSON` cover the two boundaries that DO give us a hook, so
197
+ * the wrapper stops leaking there: `${flag}` reads `"true"`/`"false"` instead
198
+ * of `"[object Object]"`, and `JSON.stringify` emits `false` instead of
199
+ * `{"value":false}` — a payload that rehydrates as a permanently truthy object.
200
+ * Framework boundaries still use `serializeContent`, which also drops metadata.
184
201
  */
185
202
  export class FimoBoolean {
186
203
  constructor(value, source, context) {
@@ -212,6 +229,12 @@ export class FimoBoolean {
212
229
  valueOf() {
213
230
  return this.value;
214
231
  }
232
+ toString() {
233
+ return String(this.value);
234
+ }
235
+ toJSON() {
236
+ return this.value;
237
+ }
215
238
  }
216
239
  _h = FIMO_SOURCE, _j = FIMO_SOURCE_CONTEXT;
217
240
  /**
@@ -11,7 +11,12 @@ export interface FimoRouteSeoConfig {
11
11
  siteName?: string;
12
12
  }
13
13
  export interface FimoRouteParamConfig<Query = unknown> {
14
- type?: 'entry' | 'locale';
14
+ /**
15
+ * Omitted means `'entry'`; the reserved name `locale` infers `'locale'`.
16
+ * `'external'` marks a placeholder whose values the application owns: it is
17
+ * matched from URLs but never looked up in the CMS and never enumerated.
18
+ */
19
+ type?: 'entry' | 'locale' | 'external';
15
20
  schema?: string;
16
21
  queryField?: string;
17
22
  displayField?: string;
@@ -67,7 +72,16 @@ export interface FimoLocaleParam {
67
72
  */
68
73
  optional: boolean;
69
74
  }
70
- export type FimoRouteParam = FimoEntryParam | FimoLocaleParam;
75
+ /**
76
+ * A placeholder whose values the application owns: a synced catalogue, a
77
+ * browser-only id, a computed segment. Never read from the CMS, never
78
+ * enumerated by Fimo.
79
+ */
80
+ export interface FimoExternalParam {
81
+ type: 'external';
82
+ name: string;
83
+ }
84
+ export type FimoRouteParam = FimoEntryParam | FimoLocaleParam | FimoExternalParam;
71
85
  export interface FimoRouteIssue {
72
86
  /** The parameter the issue is about, when it is about one. */
73
87
  param?: string;
@@ -85,6 +99,8 @@ export interface FimoRouteContract<RouteConfig extends FimoRouteConfig = FimoRou
85
99
  canonicalPath: string;
86
100
  params: FimoRouteParam[];
87
101
  entryParams: FimoEntryParam[];
102
+ /** Params the application owns. Non-empty means Fimo cannot enumerate this route's URLs. */
103
+ externalParams: FimoExternalParam[];
88
104
  localeParam: FimoLocaleParam | null;
89
105
  /** Placeholders in the path that no usable descriptor resolves. */
90
106
  unresolvedParams: string[];
@@ -120,7 +136,7 @@ export declare function hasLocaleSegment(path: string): boolean;
120
136
  * Normalize one declared route into the contract every consumer reads.
121
137
  *
122
138
  * Parameter types resolve in this order:
123
- * 1. an explicit `type`;
139
+ * 1. an explicit `type` (`entry`, `locale`, or `external`);
124
140
  * 2. the reserved name `locale`, which infers the locale type;
125
141
  * 3. otherwise the entry type, which is what every route written before
126
142
  * locale-aware routing existed relies on.
@@ -85,6 +85,26 @@ function buildLocaleParam(name, descriptor, index, issues) {
85
85
  }
86
86
  return { type: "locale", name, optional: descriptor?.optional !== false };
87
87
  }
88
+ function buildExternalParam(name, descriptor, issues) {
89
+ if (name === FIMO_LOCALE_PARAM) {
90
+ issues.push({
91
+ param: name,
92
+ message: `Param "${name}" is reserved for the locale segment and cannot use \`"type": "external"\`.`,
93
+ fix: `Drop \`"type": "external"\` from \`params.${name}\`, or rename the segment.`
94
+ });
95
+ return null;
96
+ }
97
+ for (const field of ["schema", "queryField", "displayField", "query", "optional"]) {
98
+ if (descriptor[field] !== void 0) {
99
+ issues.push({
100
+ param: name,
101
+ message: `External param "${name}" must not declare "${field}" \u2014 its values are owned by the application, never read from the CMS.`,
102
+ fix: `Remove "${field}" from \`params.${name}\`.`
103
+ });
104
+ }
105
+ }
106
+ return { type: "external", name };
107
+ }
88
108
  function buildEntryParam(name, descriptor, issues) {
89
109
  if (name === FIMO_LOCALE_PARAM) {
90
110
  issues.push({
@@ -153,7 +173,8 @@ function resolveRouteContract(id, route) {
153
173
  }
154
174
  seen.add(name);
155
175
  const descriptor = declared[name];
156
- const resolved = resolveParamType(name, descriptor) === "locale" ? buildLocaleParam(name, descriptor, index, issues) : buildEntryParam(name, descriptor, issues);
176
+ const type = resolveParamType(name, descriptor);
177
+ const resolved = type === "locale" ? buildLocaleParam(name, descriptor, index, issues) : type === "external" && descriptor ? buildExternalParam(name, descriptor, issues) : buildEntryParam(name, descriptor, issues);
157
178
  if (resolved) {
158
179
  params.push(resolved);
159
180
  } else {
@@ -178,6 +199,7 @@ function resolveRouteContract(id, route) {
178
199
  canonicalPath,
179
200
  params,
180
201
  entryParams: params.filter((param) => param.type === "entry"),
202
+ externalParams: params.filter((param) => param.type === "external"),
181
203
  localeParam,
182
204
  unresolvedParams,
183
205
  issues
@@ -217,6 +239,7 @@ function matchContract(urlSegments, contract, vocabulary) {
217
239
  }
218
240
  const params = {};
219
241
  const entryParams = {};
242
+ const entryNames = new Set(contract.entryParams.map((param) => param.name));
220
243
  let localeFromPath = null;
221
244
  let score = 0;
222
245
  let offset = 0;
@@ -244,7 +267,9 @@ function matchContract(urlSegments, contract, vocabulary) {
244
267
  const rawValue = catchAll ? urlSegments.slice(index + offset).join("/") : value;
245
268
  const decoded = safeDecode(rawValue);
246
269
  params[name] = decoded;
247
- entryParams[name] = decoded;
270
+ if (entryNames.has(name)) {
271
+ entryParams[name] = decoded;
272
+ }
248
273
  if (catchAll) {
249
274
  break;
250
275
  }
@@ -1,6 +1,10 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { pageSourceParamExpressions, parsePageParamExpression, } from '@fimo/api-contracts';
3
+ import { isEntryParamBinding, pageSourceParamExpressions, parsePageParamExpression, } from '@fimo/api-contracts';
4
+ /** Only an entry binding names content; the rest declare where values come from. */
5
+ function isEntryBinding(binding) {
6
+ return isEntryParamBinding(binding);
7
+ }
4
8
  function isRecord(value) {
5
9
  return typeof value === 'object' && value !== null && !Array.isArray(value);
6
10
  }
@@ -74,7 +78,14 @@ function validateQuery(query, pointer, schema, params, schemas) {
74
78
  for (const expression of pageSourceParamExpressions(query)) {
75
79
  const parsed = parsePageParamExpression(expression);
76
80
  const binding = parsed ? params[parsed.param] : undefined;
77
- if (!parsed || !binding || typeof binding.schema !== 'string') {
81
+ if (!parsed || !binding) {
82
+ continue;
83
+ }
84
+ if (!isEntryBinding(binding)) {
85
+ errors.push(`${pointer}: ${expression} reads param "${parsed.param}", which is not a Collection entry param.`);
86
+ continue;
87
+ }
88
+ if (typeof binding.schema !== 'string') {
78
89
  continue;
79
90
  }
80
91
  const boundSchema = schemas.get(binding.schema);
@@ -99,7 +110,7 @@ export function validatePageRegistrySchemaReferences(cwd, config, displayPath) {
99
110
  const params = isRecord(rawRoute.params) ? rawRoute.params : {};
100
111
  for (const [param, binding] of Object.entries(params)) {
101
112
  const pointer = `${displayPath}#routes.${routeId}.params.${param}`;
102
- if (typeof binding.schema !== 'string') {
113
+ if (!isEntryBinding(binding) || typeof binding.schema !== 'string') {
103
114
  continue;
104
115
  }
105
116
  const schema = schemas.get(binding.schema);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fimo",
3
- "version": "2.6.0",
3
+ "version": "2.7.0-staging.1",
4
4
  "description": "Fimo CLI - create, deploy, and manage Fimo projects",
5
5
  "keywords": [
6
6
  "astro-component"
@@ -165,7 +165,8 @@
165
165
  "scripts": {
166
166
  "build": "pnpm run clean && tsc -b tsconfig.json && chmod +x dist/cli/index.js",
167
167
  "build:bundle": "node scripts/bundle-cli.mjs && node scripts/bundle-routes.mjs",
168
- "check:types": "tsc -b tsconfig.json && tsc -p tsconfig.test.json",
168
+ "check:types": "tsc -b tsconfig.json && tsc -p tsconfig.test.json && pnpm check:types:guardrails",
169
+ "check:types:guardrails": "tsc -p tsconfig.guardrails.json",
169
170
  "start": "tsx src/cli/index.ts",
170
171
  "install-cli": "pnpm build && node scripts/install-cli.mjs",
171
172
  "publish-cli": "node scripts/publish-tarball.mjs",
@@ -193,13 +194,13 @@
193
194
  "devDependencies": {
194
195
  "@clack/core": "^1.2.0",
195
196
  "@clack/prompts": "^1.2.0",
196
- "@fimo/agents-bundle": "2.6.0",
197
- "@fimo/api-contracts": "2.6.0",
198
- "@fimo/cli-kit": "2.6.0",
199
- "@fimo/framework-detect": "2.6.0",
200
- "@fimo/routes": "2.6.0",
201
- "@fimo/sdk": "2.6.0",
202
- "@fimo/tsconfig": "2.6.0",
197
+ "@fimo/agents-bundle": "2.7.0-staging.1",
198
+ "@fimo/api-contracts": "2.7.0-staging.1",
199
+ "@fimo/cli-kit": "2.7.0-staging.1",
200
+ "@fimo/framework-detect": "2.7.0-staging.1",
201
+ "@fimo/routes": "2.7.0-staging.1",
202
+ "@fimo/sdk": "2.7.0-staging.1",
203
+ "@fimo/tsconfig": "2.7.0-staging.1",
203
204
  "@types/node": "22.18.6",
204
205
  "agent-install": "^0.0.5",
205
206
  "astro": "^7.1.6",
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
  }
@@ -9,8 +9,8 @@
9
9
  "check": "astro sync && astro check"
10
10
  },
11
11
  "dependencies": {
12
- "fimo": "2.6.0",
13
- "fimo-astro": "2.6.0"
12
+ "fimo": "2.7.0-staging.1",
13
+ "fimo-astro": "2.7.0-staging.1"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@astrojs/check": "^0.9.10",
@@ -12,9 +12,9 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@tanstack/react-query": "^5.80.6",
15
- "fimo": "2.6.0",
16
- "fimo-next": "2.6.0",
17
- "fimo-react": "2.6.0",
15
+ "fimo": "2.7.0-staging.1",
16
+ "fimo-next": "2.7.0-staging.1",
17
+ "fimo-react": "2.7.0-staging.1",
18
18
  "next": "^16.3.3",
19
19
  "react": "^19.2.7",
20
20
  "react-dom": "^19.2.7"
@@ -21,10 +21,10 @@
21
21
  "cn": "0.2.4",
22
22
  "date-fns": "^4.1.0",
23
23
  "embla-carousel-react": "^8.6.0",
24
- "fimo": "2.6.0",
25
- "fimo-react": "2.6.0",
26
- "fimo-react-router": "2.6.0",
27
- "fimo-vite": "2.6.0",
24
+ "fimo": "2.7.0-staging.1",
25
+ "fimo-react": "2.7.0-staging.1",
26
+ "fimo-react-router": "2.7.0-staging.1",
27
+ "fimo-vite": "2.7.0-staging.1",
28
28
  "input-otp": "^1.4.2",
29
29
  "isbot": "^5",
30
30
  "lucide-react": "^0.577.0",
@@ -11,8 +11,8 @@
11
11
  "prepare": "svelte-kit sync"
12
12
  },
13
13
  "dependencies": {
14
- "fimo": "2.6.0",
15
- "fimo-sveltekit": "2.6.0"
14
+ "fimo": "2.7.0-staging.1",
15
+ "fimo-sveltekit": "2.7.0-staging.1"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@sveltejs/kit": "^2.70.2",
@@ -11,10 +11,10 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@tanstack/react-query": "^5.80.6",
14
- "fimo": "2.6.0",
15
- "fimo-react": "2.6.0",
16
- "fimo-react-router": "2.6.0",
17
- "fimo-vite": "2.6.0",
14
+ "fimo": "2.7.0-staging.1",
15
+ "fimo-react": "2.7.0-staging.1",
16
+ "fimo-react-router": "2.7.0-staging.1",
17
+ "fimo-vite": "2.7.0-staging.1",
18
18
  "react": "^19.2.7",
19
19
  "react-dom": "^19.2.7",
20
20
  "react-router": "^8.3.0"