fimo 0.11.0 → 0.12.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 (57) hide show
  1. package/README.md +7 -1
  2. package/assets/content-templates/hooks-template.eta +8 -8
  3. package/assets/content-templates/next-client-template.eta +102 -0
  4. package/assets/content-templates/next-server-template.eta +75 -0
  5. package/assets/content-templates/types-template.eta +2 -2
  6. package/assets/skills/fimo-cli/SKILL.md +2 -0
  7. package/assets/skills/fimo-cli/references/deploy.md +22 -1
  8. package/assets/skills/fimo-cli/references/preview.md +4 -3
  9. package/assets/skills/fimo-code/references/setup-plain-vite.md +4 -2
  10. package/assets/skills/fimo-code/references/setup-react-router.md +4 -2
  11. package/dist/cli/bundle.json +1 -1
  12. package/dist/cli/index.js +49 -47
  13. package/dist/runtime/content/client/collection-core.d.ts +37 -0
  14. package/dist/runtime/content/client/collection-core.js +149 -0
  15. package/dist/runtime/content/client/createContentClient.d.ts +3 -16
  16. package/dist/runtime/content/client/createContentClient.js +4 -321
  17. package/dist/runtime/content/client/createSingletonClient.js +3 -108
  18. package/dist/runtime/content/client/internal.d.ts +1 -3
  19. package/dist/runtime/content/client/internal.js +3 -21
  20. package/dist/runtime/content/client/react-content-client.d.ts +10 -0
  21. package/dist/runtime/content/client/react-content-client.js +165 -0
  22. package/dist/runtime/content/client/react-singleton-client.d.ts +7 -0
  23. package/dist/runtime/content/client/react-singleton-client.js +38 -0
  24. package/dist/runtime/content/client/runtime.d.ts +8 -0
  25. package/dist/runtime/content/client/runtime.js +7 -0
  26. package/dist/runtime/content/client/server-content-client.d.ts +9 -0
  27. package/dist/runtime/content/client/server-content-client.js +35 -0
  28. package/dist/runtime/content/client/singleton-core.d.ts +26 -0
  29. package/dist/runtime/content/client/singleton-core.js +73 -0
  30. package/dist/runtime/content/client/useQueryLocale.d.ts +1 -1
  31. package/dist/runtime/content/client/useQueryLocale.js +2 -3
  32. package/dist/runtime/content/client/vite-runtime.d.ts +3 -0
  33. package/dist/runtime/content/client/vite-runtime.js +23 -0
  34. package/dist/runtime/content/index.d.ts +16 -0
  35. package/dist/runtime/content/index.js +10 -0
  36. package/dist/runtime/content/serialization.d.ts +22 -0
  37. package/dist/runtime/content/serialization.js +42 -0
  38. package/dist/runtime/next/Text.d.ts +10 -0
  39. package/dist/runtime/next/Text.js +18 -0
  40. package/dist/runtime/next/client-runtime.d.ts +3 -0
  41. package/dist/runtime/next/client-runtime.js +20 -0
  42. package/dist/runtime/next/client.d.ts +16 -0
  43. package/dist/runtime/next/client.js +15 -0
  44. package/dist/runtime/next/provider.d.ts +10 -0
  45. package/dist/runtime/next/provider.js +12 -0
  46. package/dist/runtime/next/server-runtime.d.ts +3 -0
  47. package/dist/runtime/next/server-runtime.js +20 -0
  48. package/dist/runtime/next/server.d.ts +11 -0
  49. package/dist/runtime/next/server.js +10 -0
  50. package/dist/runtime/primitives/components/Text.d.ts +1 -2
  51. package/dist/runtime/primitives/lib/query.d.ts +1 -1
  52. package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +4 -6
  53. package/dist/runtime/primitives/lib/useFimoLiveValue.js +4 -10
  54. package/dist/scripts/sync-schemas.js +67 -16
  55. package/package.json +14 -1
  56. package/release.json +2 -2
  57. package/templates/react-router/package.json +1 -1
@@ -0,0 +1,16 @@
1
+ import type { CollectionContentClient, ContentClientConfig, SingletonContentClient } from '../content/client/types.js';
2
+ export declare function createContentClient<T extends {
3
+ id: string;
4
+ }, TInput extends object>(config: ContentClientConfig): CollectionContentClient<T, TInput>;
5
+ export declare function createSingletonClient<T extends {
6
+ id: string;
7
+ }, TInput extends object>(config: ContentClientConfig): SingletonContentClient<T, TInput>;
8
+ export type { CollectionContentClient, InfiniteListResult, SingletonContentClient } from '../content/client/types.js';
9
+ export { createContentCore, createSingletonCore } from '../content/index.js';
10
+ export type { CollectionContentCore, CollectionPage, CollectionPageInfo, ContentClientConfig, ContentClientHandle, ContentModuleMeta, ContentModuleRef, ContentReadOptions, ContentResult, ContentRuntime, ContentSchema, ContentSchemaField, SingletonContentCore, } from '../content/index.js';
11
+ export { FIMO_PARTS, FIMO_SOURCE, FimoBoolean, FimoDate, FimoMedia, FimoRichText, FimoString, getFimoParts, getFimoSource, hasFimoSource, isFimoDate, isFimoString, } from '../content/index.js';
12
+ export { Text } from '../primitives/components/Text.js';
13
+ export type { BoolOps, DateOps, Field, Fields, FilterFor, FimoPart, FimoPolymorphicReference, FimoReference, FimoRichTextComponents, FimoRichTextContent, FimoRichTextMarkProps, FimoRichTextNodeProps, FimoSource, NullOnlyOps, NumberOps, Populate, Populated, PopulatedResult, Projected, ProjectedWithPopulate, Query, ReferenceField, ReferenceMap, ScalarOps, Sort, SortField, StringOps, Where, WithReferences, } from '../content/index.js';
14
+ export { FimoNextProvider } from './provider.js';
15
+ export type { FimoNextProviderProps } from './provider.js';
16
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+ import { createReactContentClient } from '../content/client/react-content-client.js';
3
+ import { createReactSingletonClient } from '../content/client/react-singleton-client.js';
4
+ import { nextClientContentRuntime } from './client-runtime.js';
5
+ import { useNextContentLocale } from './provider.js';
6
+ export function createContentClient(config) {
7
+ return createReactContentClient(config, nextClientContentRuntime, useNextContentLocale);
8
+ }
9
+ export function createSingletonClient(config) {
10
+ return createReactSingletonClient(config, nextClientContentRuntime, useNextContentLocale);
11
+ }
12
+ export { createContentCore, createSingletonCore } from '../content/index.js';
13
+ export { FIMO_PARTS, FIMO_SOURCE, FimoBoolean, FimoDate, FimoMedia, FimoRichText, FimoString, getFimoParts, getFimoSource, hasFimoSource, isFimoDate, isFimoString, } from '../content/index.js';
14
+ export { Text } from '../primitives/components/Text.js';
15
+ export { FimoNextProvider } from './provider.js';
@@ -0,0 +1,10 @@
1
+ import { QueryClient } from '@tanstack/react-query';
2
+ import { type ReactNode } from 'react';
3
+ export interface FimoNextProviderProps {
4
+ children: ReactNode;
5
+ locale?: string;
6
+ queryClient?: QueryClient;
7
+ }
8
+ export declare function FimoNextProvider({ children, locale, queryClient }: FimoNextProviderProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function useNextContentLocale(requestedLocale: string | undefined, defaultLocale: string): string;
10
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4
+ import { createContext, useContext, useState } from 'react';
5
+ const FimoNextLocaleContext = createContext(undefined);
6
+ export function FimoNextProvider({ children, locale, queryClient }) {
7
+ const [client] = useState(() => queryClient ?? new QueryClient());
8
+ return (_jsx(FimoNextLocaleContext.Provider, { value: locale, children: _jsx(QueryClientProvider, { client: client, children: children }) }));
9
+ }
10
+ export function useNextContentLocale(requestedLocale, defaultLocale) {
11
+ return requestedLocale ?? useContext(FimoNextLocaleContext) ?? defaultLocale;
12
+ }
@@ -0,0 +1,3 @@
1
+ import { type ContentRuntime } from '../content/client/runtime.js';
2
+ export declare const nextServerContentRuntime: ContentRuntime;
3
+ //# sourceMappingURL=server-runtime.d.ts.map
@@ -0,0 +1,20 @@
1
+ import { requireContentApiUrl } from '../content/client/runtime.js';
2
+ export const nextServerContentRuntime = {
3
+ apiBase() {
4
+ return requireContentApiUrl(process.env.FIMO_API_URL ?? process.env.NEXT_PUBLIC_FIMO_API_URL, 'FIMO_API_URL or NEXT_PUBLIC_FIMO_API_URL');
5
+ },
6
+ defaultLocale() {
7
+ return process.env.FIMO_DEFAULT_LOCALE?.trim() || process.env.NEXT_PUBLIC_FIMO_DEFAULT_LOCALE?.trim() || 'en';
8
+ },
9
+ headers(extra) {
10
+ const headers = { ...extra };
11
+ const env = process.env.FIMO_ENV?.trim() || process.env.NEXT_PUBLIC_FIMO_ENV?.trim();
12
+ if (env) {
13
+ headers['X-Fimo-Env'] = env;
14
+ }
15
+ return headers;
16
+ },
17
+ fetch(input, init) {
18
+ return globalThis.fetch(input, init);
19
+ },
20
+ };
@@ -0,0 +1,11 @@
1
+ import type { CollectionContentClient, ContentClientConfig, SingletonContentClient } from '../content/client/types.js';
2
+ export { Text } from './Text.js';
3
+ export declare function createContentClient<T extends {
4
+ id: string;
5
+ }, TInput extends object>(config: ContentClientConfig): CollectionContentClient<T, TInput>;
6
+ export declare function createSingletonClient<T extends {
7
+ id: string;
8
+ }, TInput extends object>(config: ContentClientConfig): SingletonContentClient<T, TInput>;
9
+ export type { CollectionContentClient, InfiniteListResult, SingletonContentClient } from '../content/client/types.js';
10
+ export * from '../content/index.js';
11
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,10 @@
1
+ import { createServerContentClient, createServerSingletonClient } from '../content/client/server-content-client.js';
2
+ import { nextServerContentRuntime } from './server-runtime.js';
3
+ export { Text } from './Text.js';
4
+ export function createContentClient(config) {
5
+ return createServerContentClient(config, nextServerContentRuntime);
6
+ }
7
+ export function createSingletonClient(config) {
8
+ return createServerSingletonClient(config, nextServerContentRuntime);
9
+ }
10
+ export * from '../content/index.js';
@@ -1,5 +1,5 @@
1
1
  import { type ComponentPropsWithoutRef, type ElementType, type ReactNode } from 'react';
2
- type TextProps<T extends ElementType = 'span'> = {
2
+ export type TextProps<T extends ElementType = 'span'> = {
3
3
  value: unknown;
4
4
  as?: T;
5
5
  children?: (value: string) => ReactNode;
@@ -20,5 +20,4 @@ type TextProps<T extends ElementType = 'span'> = {
20
20
  * <Text value={product.price}>{(p) => `$${Number(p).toLocaleString()}`}</Text>
21
21
  */
22
22
  export declare function Text<T extends ElementType = 'span'>({ value, as, children, ...props }: TextProps<T>): import("react/jsx-runtime").JSX.Element;
23
- export {};
24
23
  //# sourceMappingURL=Text.d.ts.map
@@ -67,7 +67,7 @@ export type Fields<T> = Field<T> | readonly Field<T>[];
67
67
  type SelectedField<TField> = TField extends `__fimo.${string}` ? '__fimo' : TField;
68
68
  type SelectedFields<TFields> = TFields extends readonly (infer K)[] ? SelectedField<K> : SelectedField<TFields>;
69
69
  type ListItem<TValue> = TValue extends readonly (infer K)[] ? K : TValue;
70
- type EntryIdentityField<T> = Extract<'id' | 'entryId' | 'documentId' | 'locale', keyof T>;
70
+ type EntryIdentityField<T> = Extract<'id' | 'entryId' | 'documentId' | 'locale' | '__fimo', keyof T>;
71
71
  export type Projected<T extends {
72
72
  id: string;
73
73
  }, TFields extends Fields<T> | undefined> = [TFields] extends [undefined] ? T : Pick<T, EntryIdentityField<T> | Extract<SelectedFields<TFields>, keyof T>>;
@@ -9,14 +9,12 @@ import { type RefObject } from 'react';
9
9
  * preview knows to dispatch events instead of falling back to raw DOM writes,
10
10
  * and updates internal state when a mutation arrives.
11
11
  *
12
- * In prod (published app): Vite statically inlines `import.meta.env.DEV`, so
13
- * `useFimoLiveValueProd` is the only implementation linked and the listener
14
- * machinery is dead-code-eliminated.
12
+ * The subscription is framework-neutral: Vite and Next.js render the same
13
+ * primitives, and environments that never dispatch `fimo:live-edit` simply
14
+ * keep mirroring the external value.
15
15
  */
16
- declare function useFimoLiveValueDev<T, E extends HTMLElement = HTMLElement>(external: T): {
16
+ export declare function useFimoLiveValue<T, E extends HTMLElement = HTMLElement>(external: T): {
17
17
  value: T;
18
18
  ref: RefObject<E | null>;
19
19
  };
20
- export declare const useFimoLiveValue: typeof useFimoLiveValueDev;
21
- export {};
22
20
  //# sourceMappingURL=useFimoLiveValue.d.ts.map
@@ -1,4 +1,3 @@
1
- /// <reference types="vite/client" />
2
1
  import { useEffect, useRef, useState } from 'react';
3
2
  /**
4
3
  * useFimoLiveValue — mirror a Fimo value into React state so live edits
@@ -10,11 +9,11 @@ import { useEffect, useRef, useState } from 'react';
10
9
  * preview knows to dispatch events instead of falling back to raw DOM writes,
11
10
  * and updates internal state when a mutation arrives.
12
11
  *
13
- * In prod (published app): Vite statically inlines `import.meta.env.DEV`, so
14
- * `useFimoLiveValueProd` is the only implementation linked and the listener
15
- * machinery is dead-code-eliminated.
12
+ * The subscription is framework-neutral: Vite and Next.js render the same
13
+ * primitives, and environments that never dispatch `fimo:live-edit` simply
14
+ * keep mirroring the external value.
16
15
  */
17
- function useFimoLiveValueDev(external) {
16
+ export function useFimoLiveValue(external) {
18
17
  const ref = useRef(null);
19
18
  const [value, setValue] = useState(external);
20
19
  const externalRef = useRef(external);
@@ -42,8 +41,3 @@ function useFimoLiveValueDev(external) {
42
41
  }, []);
43
42
  return { value, ref };
44
43
  }
45
- function useFimoLiveValueProd(external) {
46
- const ref = useRef(null);
47
- return { value: external, ref };
48
- }
49
- export const useFimoLiveValue = (import.meta.env.DEV ? useFimoLiveValueDev : useFimoLiveValueProd);
@@ -5,8 +5,8 @@ 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 `assets/content-templates/types-template.eta` and `hooks-template.eta`.
9
- * - Creates/updates `<cwd>/src/schemas/<Pascal>.types.ts` and `<Pascal>.ts`; deletes orphans.
8
+ * - Renders the shared types plus either the Vite facade or the split Next server/client facades.
9
+ * - Creates/updates `<Pascal>.types.ts` and `<Pascal>.ts`, plus `<Pascal>.client.ts` for Next; deletes orphans.
10
10
  */
11
11
  import { pascalCase } from 'change-case';
12
12
  import { Eta } from 'eta';
@@ -81,6 +81,32 @@ function resolveProjectRuntime(cwd) {
81
81
  }
82
82
  return { packageRoot: dirname(packagePath), version };
83
83
  }
84
+ function resolveContentRuntimeImport(cwd) {
85
+ const packagePath = join(cwd, 'package.json');
86
+ if (!existsSync(packagePath)) {
87
+ return 'fimo/ui';
88
+ }
89
+ let packageJson;
90
+ try {
91
+ packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));
92
+ }
93
+ catch {
94
+ return 'fimo/ui';
95
+ }
96
+ if (!packageJson || typeof packageJson !== 'object' || Array.isArray(packageJson)) {
97
+ return 'fimo/ui';
98
+ }
99
+ const manifest = packageJson;
100
+ const dependencyGroups = ['dependencies', 'devDependencies', 'peerDependencies'];
101
+ const usesNext = dependencyGroups.some((group) => {
102
+ const dependencies = manifest[group];
103
+ return Boolean(dependencies &&
104
+ typeof dependencies === 'object' &&
105
+ !Array.isArray(dependencies) &&
106
+ typeof dependencies.next === 'string');
107
+ });
108
+ return usesNext ? 'fimo/next' : 'fimo/ui';
109
+ }
84
110
  function templatePath(runtime, fileName) {
85
111
  if (runtime && !isVersionAtLeast(runtime.version, MINIMUM_THIN_CONTENT_CLIENT_RUNTIME_VERSION)) {
86
112
  return join(runtime.packageRoot, 'assets', 'content-templates', fileName);
@@ -115,11 +141,11 @@ function loadSchemas(schemaFiles) {
115
141
  }
116
142
  const candidate = parsed;
117
143
  if (typeof candidate.uid !== 'string' || candidate.uid.length === 0) {
118
- errors.push(`${basename(path)} is missing \"uid\". Set it to \"${fileUid}\".`);
144
+ errors.push(`${basename(path)} is missing "uid". Set it to "${fileUid}".`);
119
145
  continue;
120
146
  }
121
147
  if (candidate.uid !== fileUid) {
122
- errors.push(`${basename(path)} declares uid \"${candidate.uid}\". It must match the file name \"${fileUid}\".`);
148
+ errors.push(`${basename(path)} declares uid "${candidate.uid}". It must match the file name "${fileUid}".`);
123
149
  continue;
124
150
  }
125
151
  const validation = SCHEMA_DEFINITION_SCHEMA.safeParse(candidate);
@@ -212,16 +238,41 @@ export function syncSchemas(options = {}) {
212
238
  const schemas = loadSchemas(schemaFiles);
213
239
  const generatedFilesOnDisk = getGeneratedFiles(schemasDir);
214
240
  const runtime = schemas.length > 0 || generatedFilesOnDisk.length > 0 ? resolveProjectRuntime(cwd) : null;
215
- const templates = [
216
- {
217
- suffix: '.types.ts',
218
- path: templatePath(runtime, 'types-template.eta'),
219
- },
220
- {
221
- suffix: '.ts',
222
- path: templatePath(runtime, 'hooks-template.eta'),
223
- },
224
- ].map((template) => ({
241
+ const runtimeImport = resolveContentRuntimeImport(cwd);
242
+ const usesCurrentNextRuntime = runtimeImport === 'fimo/next' &&
243
+ runtime !== null &&
244
+ isVersionAtLeast(runtime.version, MINIMUM_THIN_CONTENT_CLIENT_RUNTIME_VERSION);
245
+ const templates = usesCurrentNextRuntime
246
+ ? [
247
+ {
248
+ suffix: '.types.ts',
249
+ path: templatePath(runtime, 'types-template.eta'),
250
+ runtimeImport: 'fimo/next',
251
+ },
252
+ {
253
+ suffix: '.ts',
254
+ path: templatePath(runtime, 'next-server-template.eta'),
255
+ runtimeImport: 'fimo/next',
256
+ },
257
+ {
258
+ suffix: '.client.ts',
259
+ path: templatePath(runtime, 'next-client-template.eta'),
260
+ runtimeImport: 'fimo/next/client',
261
+ },
262
+ ]
263
+ : [
264
+ {
265
+ suffix: '.types.ts',
266
+ path: templatePath(runtime, 'types-template.eta'),
267
+ runtimeImport,
268
+ },
269
+ {
270
+ suffix: '.ts',
271
+ path: templatePath(runtime, 'hooks-template.eta'),
272
+ runtimeImport,
273
+ },
274
+ ];
275
+ const loadedTemplates = templates.map((template) => ({
225
276
  ...template,
226
277
  source: readFileSync(template.path, 'utf-8'),
227
278
  }));
@@ -234,10 +285,10 @@ export function syncSchemas(options = {}) {
234
285
  let deleted = 0;
235
286
  for (const { pascal, schema } of schemas) {
236
287
  const model = schemaToModel(schema, localizedByUid);
237
- for (const template of templates) {
288
+ for (const template of loadedTemplates) {
238
289
  const tsPath = join(schemasDir, `${pascal}${template.suffix}`);
239
290
  expectedTsFiles.add(tsPath);
240
- generatedFiles.set(tsPath, eta.renderString(template.source, { model }));
291
+ generatedFiles.set(tsPath, eta.renderString(template.source, { model, runtimeImport: template.runtimeImport }));
241
292
  }
242
293
  }
243
294
  for (const [tsPath, content] of generatedFiles) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fimo",
3
- "version": "0.11.0",
3
+ "version": "0.12.0-staging.1",
4
4
  "description": "Fimo CLI - create, deploy, and manage Fimo projects",
5
5
  "bin": {
6
6
  "fimo": "dist/cli/index.js"
@@ -22,6 +22,18 @@
22
22
  "types": "./dist/runtime/index.d.ts",
23
23
  "import": "./dist/runtime/index.js"
24
24
  },
25
+ "./content": {
26
+ "types": "./dist/runtime/content/index.d.ts",
27
+ "import": "./dist/runtime/content/index.js"
28
+ },
29
+ "./next": {
30
+ "types": "./dist/runtime/next/server.d.ts",
31
+ "import": "./dist/runtime/next/server.js"
32
+ },
33
+ "./next/client": {
34
+ "types": "./dist/runtime/next/client.d.ts",
35
+ "import": "./dist/runtime/next/client.js"
36
+ },
25
37
  "./react-router": {
26
38
  "types": "./dist/runtime/react-router/index.d.ts",
27
39
  "import": "./dist/runtime/react-router/index.js"
@@ -63,6 +75,7 @@
63
75
  "publish:dry-run": "npm publish --dry-run",
64
76
  "postinstall": "node scripts/postinstall.mjs",
65
77
  "test": "vitest run",
78
+ "test:integration:next": "vitest run --config vitest.integration.config.ts",
66
79
  "test:watch": "vitest",
67
80
  "clean": "rm -rf dist *.tsbuildinfo"
68
81
  },
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
  }
@@ -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.11.0",
24
+ "fimo": "0.12.0-staging.1",
25
25
  "input-otp": "^1.4.2",
26
26
  "isbot": "^5",
27
27
  "lucide-react": "^0.577.0",