fimo-react 0.21.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 (94) hide show
  1. package/README.md +21 -0
  2. package/dist/runtime/content/DataSourcesProvider.d.ts +4 -0
  3. package/dist/runtime/content/DataSourcesProvider.js +63 -0
  4. package/dist/runtime/content/RefreshContentProvider.d.ts +19 -0
  5. package/dist/runtime/content/RefreshContentProvider.js +71 -0
  6. package/dist/runtime/content/createContentClient.d.ts +7 -0
  7. package/dist/runtime/content/createContentClient.js +7 -0
  8. package/dist/runtime/content/createSingletonClient.d.ts +5 -0
  9. package/dist/runtime/content/createSingletonClient.js +6 -0
  10. package/dist/runtime/content/fixtures/Author.d.ts +48 -0
  11. package/dist/runtime/content/fixtures/Author.js +22 -0
  12. package/dist/runtime/content/fixtures/Author.types.d.ts +38 -0
  13. package/dist/runtime/content/fixtures/Author.types.js +1 -0
  14. package/dist/runtime/content/fixtures/Post.d.ts +48 -0
  15. package/dist/runtime/content/fixtures/Post.js +37 -0
  16. package/dist/runtime/content/fixtures/Post.types.d.ts +50 -0
  17. package/dist/runtime/content/fixtures/Post.types.js +1 -0
  18. package/dist/runtime/content/fixtures/SiteSettings.d.ts +42 -0
  19. package/dist/runtime/content/fixtures/SiteSettings.js +15 -0
  20. package/dist/runtime/content/fixtures/usage-contract.d.ts +3 -0
  21. package/dist/runtime/content/fixtures/usage-contract.js +57 -0
  22. package/dist/runtime/content/fixtures/virtual-fimo-config.d.ts +3 -0
  23. package/dist/runtime/content/fixtures/virtual-fimo-config.js +3 -0
  24. package/dist/runtime/content/index.d.ts +5 -0
  25. package/dist/runtime/content/index.js +2 -0
  26. package/dist/runtime/content/react-content-client.d.ts +10 -0
  27. package/dist/runtime/content/react-content-client.js +164 -0
  28. package/dist/runtime/content/react-singleton-client.d.ts +7 -0
  29. package/dist/runtime/content/react-singleton-client.js +37 -0
  30. package/dist/runtime/content/retrieve-data-sources.d.ts +29 -0
  31. package/dist/runtime/content/retrieve-data-sources.js +107 -0
  32. package/dist/runtime/content/types.d.ts +42 -0
  33. package/dist/runtime/content/types.js +1 -0
  34. package/dist/runtime/content/useQueryLocale.d.ts +2 -0
  35. package/dist/runtime/content/useQueryLocale.js +5 -0
  36. package/dist/runtime/content/vite-runtime.d.ts +3 -0
  37. package/dist/runtime/content/vite-runtime.js +23 -0
  38. package/dist/runtime/core/AppErrorBoundary.d.ts +10 -0
  39. package/dist/runtime/core/AppErrorBoundary.js +27 -0
  40. package/dist/runtime/core/ViteLifecycles.d.ts +5 -0
  41. package/dist/runtime/core/ViteLifecycles.js +35 -0
  42. package/dist/runtime/i18n-context.d.ts +9 -0
  43. package/dist/runtime/i18n-context.js +17 -0
  44. package/dist/runtime/iframe/ConsoleErrorProvider.d.ts +3 -0
  45. package/dist/runtime/iframe/ConsoleErrorProvider.js +103 -0
  46. package/dist/runtime/iframe/ScreenshotProvider.d.ts +3 -0
  47. package/dist/runtime/iframe/ScreenshotProvider.js +60 -0
  48. package/dist/runtime/index.d.ts +24 -0
  49. package/dist/runtime/index.js +24 -0
  50. package/dist/runtime/internal.d.ts +3 -0
  51. package/dist/runtime/internal.js +6 -0
  52. package/dist/runtime/primitives-server.d.ts +7 -0
  53. package/dist/runtime/primitives-server.js +5 -0
  54. package/dist/runtime/primitives.d.ts +17 -0
  55. package/dist/runtime/primitives.js +18 -0
  56. package/dist/runtime/react/primitives/contracts.d.ts +100 -0
  57. package/dist/runtime/react/primitives/contracts.js +1 -0
  58. package/dist/runtime/react/primitives/editable/Boolean.d.ts +5 -0
  59. package/dist/runtime/react/primitives/editable/Boolean.js +11 -0
  60. package/dist/runtime/react/primitives/editable/Date.d.ts +4 -0
  61. package/dist/runtime/react/primitives/editable/Date.js +12 -0
  62. package/dist/runtime/react/primitives/editable/DateTime.d.ts +4 -0
  63. package/dist/runtime/react/primitives/editable/DateTime.js +13 -0
  64. package/dist/runtime/react/primitives/editable/Image.d.ts +4 -0
  65. package/dist/runtime/react/primitives/editable/Image.js +10 -0
  66. package/dist/runtime/react/primitives/editable/Json.d.ts +5 -0
  67. package/dist/runtime/react/primitives/editable/Json.js +11 -0
  68. package/dist/runtime/react/primitives/editable/RichText.d.ts +4 -0
  69. package/dist/runtime/react/primitives/editable/RichText.js +11 -0
  70. package/dist/runtime/react/primitives/editable/Text.d.ts +20 -0
  71. package/dist/runtime/react/primitives/editable/Text.js +36 -0
  72. package/dist/runtime/react/primitives/editable/Video.d.ts +4 -0
  73. package/dist/runtime/react/primitives/editable/Video.js +10 -0
  74. package/dist/runtime/react/primitives/renderers/DateRenderer.d.ts +17 -0
  75. package/dist/runtime/react/primitives/renderers/DateRenderer.js +17 -0
  76. package/dist/runtime/react/primitives/renderers/ImageRenderer.d.ts +8 -0
  77. package/dist/runtime/react/primitives/renderers/ImageRenderer.js +30 -0
  78. package/dist/runtime/react/primitives/renderers/RichTextRenderer.d.ts +12 -0
  79. package/dist/runtime/react/primitives/renderers/RichTextRenderer.js +135 -0
  80. package/dist/runtime/react/primitives/renderers/StaticImage.d.ts +35 -0
  81. package/dist/runtime/react/primitives/renderers/StaticImage.js +58 -0
  82. package/dist/runtime/react/primitives/renderers/VideoRenderer.d.ts +8 -0
  83. package/dist/runtime/react/primitives/renderers/VideoRenderer.js +10 -0
  84. package/dist/runtime/react/useFimoLiveValue.d.ts +20 -0
  85. package/dist/runtime/react/useFimoLiveValue.js +43 -0
  86. package/dist/runtime/vite/Label.d.ts +13 -0
  87. package/dist/runtime/vite/Label.js +16 -0
  88. package/dist/runtime/vite/__fixtures__/virtual-translations.d.ts +5 -0
  89. package/dist/runtime/vite/__fixtures__/virtual-translations.js +6 -0
  90. package/dist/runtime/vite/primitives/Images.d.ts +4 -0
  91. package/dist/runtime/vite/primitives/Images.js +12 -0
  92. package/dist/runtime/vite/translations.d.ts +28 -0
  93. package/dist/runtime/vite/translations.js +103 -0
  94. package/package.json +72 -0
package/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # fimo-react
2
+
3
+ The React runtime for Fimo projects. Install it alongside `fimo` at the same
4
+ version:
5
+
6
+ ```bash
7
+ npm install fimo fimo-react
8
+ ```
9
+
10
+ `fimo-react` owns the React content clients, `useLabels` / `<Label>`, and the
11
+ source-tracked editable primitives. It has no Vite or React Router peer, so a
12
+ Next.js project can build on it directly; its `fimo-react/primitives/server`
13
+ subpath is the hook-free surface server adapters use.
14
+
15
+ The rest of a React project's Fimo wiring lives next door:
16
+
17
+ - `fimo-vite` — the framework-neutral Vite plugin (config virtual module,
18
+ labels, `data-fimo-id`, dev overlay, sitemap/robots/SEO emitters).
19
+ - `fimo-react-router` — `FimoProviders`, `FimoScripts`, `FimoLink`, route
20
+ `meta` helpers, `fimoRoutes()`, `fimoPreset()`, and the React Router build
21
+ integration.
@@ -0,0 +1,4 @@
1
+ export declare function DataSourcesProvider({ children }: {
2
+ children: React.ReactNode;
3
+ }): import("react/jsx-runtime").JSX.Element;
4
+ //# sourceMappingURL=DataSourcesProvider.d.ts.map
@@ -0,0 +1,63 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useCallback, useEffect } from 'react';
3
+ import { retrieveVisibleDataSources } from './retrieve-data-sources.js';
4
+ const VISIBLE_TRANSLATIONS_SELECTORS = 'h1, h2, h3, nav a, button';
5
+ const MAX_VISIBLE_TRANSLATIONS_ITEMS = 20;
6
+ const MAX_TEXT_LENGTH = 60;
7
+ function isInViewport(el) {
8
+ const rect = el.getBoundingClientRect();
9
+ return (rect.bottom > 0 &&
10
+ rect.top < window.innerHeight &&
11
+ rect.right > 0 &&
12
+ rect.left < window.innerWidth &&
13
+ rect.width > 0 &&
14
+ rect.height > 0);
15
+ }
16
+ function extractVisibleTranslations() {
17
+ const elements = document.querySelectorAll(VISIBLE_TRANSLATIONS_SELECTORS);
18
+ const seen = new Set();
19
+ const items = [];
20
+ for (const el of elements) {
21
+ if (items.length >= MAX_VISIBLE_TRANSLATIONS_ITEMS)
22
+ break;
23
+ if (!isInViewport(el))
24
+ continue;
25
+ const raw = el.textContent?.trim();
26
+ if (!raw)
27
+ continue;
28
+ // Deduplicate (e.g. nav repeated in header + footer)
29
+ const key = `${el.tagName.toLowerCase()}:${raw}`;
30
+ if (seen.has(key))
31
+ continue;
32
+ seen.add(key);
33
+ const text = raw.length > MAX_TEXT_LENGTH ? raw.slice(0, MAX_TEXT_LENGTH) + '…' : raw;
34
+ items.push({ tag: el.tagName.toLowerCase(), text });
35
+ }
36
+ return items;
37
+ }
38
+ export function DataSourcesProvider({ children }) {
39
+ const sendDataSources = useCallback(() => {
40
+ const dataSources = retrieveVisibleDataSources();
41
+ window.parent.postMessage({ type: 'content/send-visible', payload: { dataSources } }, '*');
42
+ }, []);
43
+ const sendVisibleTranslations = useCallback(() => {
44
+ const visibleTranslations = extractVisibleTranslations();
45
+ window.parent.postMessage({ type: 'content/send-visible-translations', payload: { visibleTranslations } }, '*');
46
+ }, []);
47
+ // Handle data requests from parent
48
+ useEffect(() => {
49
+ const handleMessage = (event) => {
50
+ if (event.data?.type === 'content/read-visible') {
51
+ sendDataSources();
52
+ }
53
+ if (event.data?.type === 'content/read-visible-translations') {
54
+ sendVisibleTranslations();
55
+ }
56
+ };
57
+ window.addEventListener('message', handleMessage);
58
+ return () => {
59
+ window.removeEventListener('message', handleMessage);
60
+ };
61
+ }, [sendDataSources, sendVisibleTranslations]);
62
+ return _jsx(_Fragment, { children: children });
63
+ }
@@ -0,0 +1,19 @@
1
+ import type { FC, PropsWithChildren } from 'react';
2
+ interface ContentRefreshPayload {
3
+ changes?: Array<{
4
+ contentType?: string;
5
+ documentId?: string;
6
+ id?: string;
7
+ locale?: string;
8
+ }>;
9
+ contentType?: string;
10
+ documentId?: string;
11
+ id?: string;
12
+ locale?: string;
13
+ }
14
+ export declare function normalizeContentQueryRoot(contentType: string): string;
15
+ export declare function getContentRefreshPayload(data: unknown): ContentRefreshPayload | null;
16
+ export declare function shouldInvalidateContentQuery(queryKey: readonly unknown[], payload: ContentRefreshPayload | null): boolean;
17
+ export declare const RefreshContentProvider: FC<PropsWithChildren>;
18
+ export {};
19
+ //# sourceMappingURL=RefreshContentProvider.d.ts.map
@@ -0,0 +1,71 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useQueryClient } from '@tanstack/react-query';
3
+ import { useEffect } from 'react';
4
+ export function normalizeContentQueryRoot(contentType) {
5
+ return contentType
6
+ .split(/[^a-zA-Z0-9]+/)
7
+ .filter(Boolean)
8
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
9
+ .join('');
10
+ }
11
+ export function getContentRefreshPayload(data) {
12
+ if (!data || typeof data !== 'object') {
13
+ return null;
14
+ }
15
+ const payload = data.payload ?? data;
16
+ if (!payload || typeof payload !== 'object') {
17
+ return null;
18
+ }
19
+ return payload;
20
+ }
21
+ function getContentTypes(payload) {
22
+ if (!payload) {
23
+ return [];
24
+ }
25
+ const contentTypes = new Set();
26
+ if (payload.contentType) {
27
+ contentTypes.add(payload.contentType);
28
+ }
29
+ for (const change of payload.changes ?? []) {
30
+ if (change.contentType) {
31
+ contentTypes.add(change.contentType);
32
+ }
33
+ }
34
+ return [...contentTypes];
35
+ }
36
+ export function shouldInvalidateContentQuery(queryKey, payload) {
37
+ const contentTypes = getContentTypes(payload);
38
+ if (contentTypes.length === 0) {
39
+ return true;
40
+ }
41
+ const queryRoots = new Set(contentTypes.flatMap((contentType) => [contentType, normalizeContentQueryRoot(contentType)]));
42
+ return queryRoots.has(String(queryKey[0]));
43
+ }
44
+ export const RefreshContentProvider = ({ children }) => {
45
+ const queryClient = useQueryClient();
46
+ useEffect(() => {
47
+ const invalidateContent = (payload) => {
48
+ void queryClient.invalidateQueries({
49
+ predicate(query) {
50
+ return shouldInvalidateContentQuery(query.queryKey, payload);
51
+ },
52
+ });
53
+ };
54
+ const onMessage = (e) => {
55
+ if (e.data?.type === 'content/refresh') {
56
+ invalidateContent(getContentRefreshPayload(e.data));
57
+ }
58
+ };
59
+ const hot = import.meta.hot;
60
+ const onContentUpdated = (payload) => {
61
+ invalidateContent(getContentRefreshPayload(payload));
62
+ };
63
+ window.addEventListener('message', onMessage);
64
+ hot?.on('fimo:content-updated', onContentUpdated);
65
+ return () => {
66
+ window.removeEventListener('message', onMessage);
67
+ hot?.off('fimo:content-updated', onContentUpdated);
68
+ };
69
+ }, [queryClient]);
70
+ return _jsx(_Fragment, { children: children });
71
+ };
@@ -0,0 +1,7 @@
1
+ import { SOURCE_TRACKED_QUERY_OPTIONS } from './react-content-client.js';
2
+ import type { ContentClientConfig, CollectionContentClient } from './types.js';
3
+ export { SOURCE_TRACKED_QUERY_OPTIONS };
4
+ export declare function createContentClient<T extends {
5
+ id: string;
6
+ }, TInput extends object>(config: ContentClientConfig): CollectionContentClient<T, TInput>;
7
+ //# sourceMappingURL=createContentClient.d.ts.map
@@ -0,0 +1,7 @@
1
+ import { createReactContentClient, SOURCE_TRACKED_QUERY_OPTIONS } from './react-content-client.js';
2
+ import { useQueryLocale } from './useQueryLocale.js';
3
+ import { viteContentRuntime } from './vite-runtime.js';
4
+ export { SOURCE_TRACKED_QUERY_OPTIONS };
5
+ export function createContentClient(config) {
6
+ return createReactContentClient(config, viteContentRuntime, (requested, fallback) => useQueryLocale(requested, fallback));
7
+ }
@@ -0,0 +1,5 @@
1
+ import type { ContentClientConfig, SingletonContentClient } from './types.js';
2
+ export declare function createSingletonClient<T extends {
3
+ id: string;
4
+ }, TInput extends object>(config: ContentClientConfig): SingletonContentClient<T, TInput>;
5
+ //# sourceMappingURL=createSingletonClient.d.ts.map
@@ -0,0 +1,6 @@
1
+ import { createReactSingletonClient } from './react-singleton-client.js';
2
+ import { useQueryLocale } from './useQueryLocale.js';
3
+ import { viteContentRuntime } from './vite-runtime.js';
4
+ export function createSingletonClient(config) {
5
+ return createReactSingletonClient(config, viteContentRuntime, (requested, fallback) => useQueryLocale(requested, fallback));
6
+ }
@@ -0,0 +1,48 @@
1
+ import type { CollectionContentClient } from '../types.js';
2
+ import type { Author, AuthorFields, AuthorInput, AuthorPopulate, AuthorQuery } from './Author.types.js';
3
+ import * as Post from './Post.js';
4
+ export type { Author, AuthorFields, AuthorFimoMeta, AuthorInput, AuthorPopulate, AuthorQuery, AuthorReferences, AuthorResult, AuthorSort, AuthorWhere, } from './Author.types.js';
5
+ export type { CollectionPage, CollectionPageInfo, InfiniteListResult } from '../types.js';
6
+ export type InfiniteListQuery<TFields extends AuthorFields | undefined = undefined, TPopulate extends AuthorPopulate | undefined = undefined> = Omit<AuthorQuery<TFields, TPopulate>, 'offset'>;
7
+ declare const client: CollectionContentClient<Author, AuthorInput>;
8
+ export declare const getById: <TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(id: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => Promise<import("fimo/content").PopulatedResult<Author, TPopulate> & {
9
+ id: string;
10
+ }>, getBySlug: <TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(slug: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => Promise<(import("fimo/content").PopulatedResult<Author, TPopulate> & {
11
+ id: string;
12
+ }) | null>, getByField: <TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(fieldName: string, value: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => Promise<(import("fimo/content").PopulatedResult<Author, TPopulate> & {
13
+ id: string;
14
+ }) | null>, list: <TFields extends import("fimo/content").Fields<Author> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(params?: import("fimo/content").Query<Author, TFields, TPopulate> | undefined) => Promise<Post.CollectionPage<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Author, TPopulate> & {
15
+ id: string;
16
+ }, TFields, TPopulate>>>, get: <TFields extends import("fimo/content").Fields<Author> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(params?: import("fimo/content").Query<Author, TFields, TPopulate> | undefined) => Promise<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Author, TPopulate> & {
17
+ id: string;
18
+ }, TFields, TPopulate>[]>, create: (payload: AuthorInput) => Promise<Author>, update: (id: string, payload: Partial<AuthorInput>) => Promise<Author>, remove: (id: string, options?: {
19
+ locale?: string;
20
+ }) => Promise<void>, useGetById: <TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(id: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<import("fimo/content").PopulatedResult<Author, TPopulate> & {
21
+ id: string;
22
+ }, Error>, useGetBySlug: <TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(slug: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<(import("fimo/content").PopulatedResult<Author, TPopulate> & {
23
+ id: string;
24
+ }) | null, Error>, useGetByField: <TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(fieldName: string, value: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<(import("fimo/content").PopulatedResult<Author, TPopulate> & {
25
+ id: string;
26
+ }) | null, Error>, useList: <TFields extends import("fimo/content").Fields<Author> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(params?: import("fimo/content").Query<Author, TFields, TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<Post.CollectionPage<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Author, TPopulate> & {
27
+ id: string;
28
+ }, TFields, TPopulate>>, Error>, useInfiniteList: <TFields extends import("fimo/content").Fields<Author> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(params?: Omit<import("fimo/content").Query<Author, TFields, TPopulate>, "offset"> | undefined) => Post.InfiniteListResult<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Author, TPopulate> & {
29
+ id: string;
30
+ }, TFields, TPopulate>>, useGet: <TFields extends import("fimo/content").Fields<Author> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(params?: import("fimo/content").Query<Author, TFields, TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Author, TPopulate> & {
31
+ id: string;
32
+ }, TFields, TPopulate>[], Error>, useSuspenseGetById: <TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(id: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseSuspenseQueryResult<import("fimo/content").PopulatedResult<Author, TPopulate> & {
33
+ id: string;
34
+ }, Error>, useSuspenseGet: <TFields extends import("fimo/content").Fields<Author> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(params?: import("fimo/content").Query<Author, TFields, TPopulate> | undefined) => import("@tanstack/react-query").UseSuspenseQueryResult<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Author, TPopulate> & {
35
+ id: string;
36
+ }, TFields, TPopulate>[], Error>, useSuspenseGetByField: <TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(fieldName: string, value: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseSuspenseQueryResult<(import("fimo/content").PopulatedResult<Author, TPopulate> & {
37
+ id: string;
38
+ }) | null, Error>, useSuspenseGetBySlug: <TPopulate extends import("fimo/content").Populate<Author> | undefined = undefined>(slug: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseSuspenseQueryResult<(import("fimo/content").PopulatedResult<Author, TPopulate> & {
39
+ id: string;
40
+ }) | null, Error>, useCreate: () => import("@tanstack/react-query").UseMutationResult<Author, Error, AuthorInput>, useUpdate: () => import("@tanstack/react-query").UseMutationResult<Author, Error, {
41
+ id: string;
42
+ locale?: string;
43
+ } & Partial<AuthorInput>>, useRemove: () => import("@tanstack/react-query").UseMutationResult<void, Error, string | {
44
+ id: string;
45
+ locale?: string;
46
+ }>;
47
+ export default client;
48
+ //# sourceMappingURL=Author.d.ts.map
@@ -0,0 +1,22 @@
1
+ // Hand-written draft of the future thin generated module — see Post.ts for
2
+ // the provenance banner and the cycle-safety contract this pair exercises.
3
+ import { createContentClient } from '../createContentClient.js';
4
+ import * as Post from './Post.js';
5
+ const schema = {
6
+ uid: 'Author',
7
+ name: 'Author',
8
+ isSingleton: false,
9
+ i18n: { enabled: true },
10
+ fields: {
11
+ name: { type: 'string', required: true },
12
+ bio: { type: 'richtext' },
13
+ avatar: { type: 'media' },
14
+ posts: { type: 'reference', target: 'Post', many: true },
15
+ },
16
+ };
17
+ const client = createContentClient({
18
+ schema,
19
+ references: { Post },
20
+ });
21
+ export const { getById, getBySlug, getByField, list, get, create, update, remove, useGetById, useGetBySlug, useGetByField, useList, useInfiniteList, useGet, useSuspenseGetById, useSuspenseGet, useSuspenseGetByField, useSuspenseGetBySlug, useCreate, useUpdate, useRemove, } = client;
22
+ export default client;
@@ -0,0 +1,38 @@
1
+ import type { Fields, FimoMedia, FimoReference, FimoRichText, FimoRichTextContent, FimoString, Populate, PopulatedResult, ProjectedWithPopulate, Query, Sort, Where, WithReferences } from 'fimo/primitives';
2
+ import type { Post } from './Post.types.js';
3
+ export interface AuthorFimoMeta {
4
+ contentType: string;
5
+ }
6
+ export interface Author extends WithReferences<AuthorReferences> {
7
+ id: string;
8
+ entryId: string;
9
+ documentId: string;
10
+ slug: FimoString;
11
+ locale: string;
12
+ createdAt: string;
13
+ updatedAt: string;
14
+ __fimo: AuthorFimoMeta;
15
+ name: FimoString;
16
+ bio?: FimoRichText | null;
17
+ avatar: FimoMedia;
18
+ posts: FimoReference[];
19
+ }
20
+ export interface AuthorInput {
21
+ slug?: string;
22
+ locale?: string;
23
+ documentId?: string;
24
+ name: string;
25
+ bio?: FimoRichTextContent | null;
26
+ avatar?: Pick<FimoMedia, 'url' | 'alt' | 'name' | 'mime' | 'width' | 'height'>;
27
+ posts?: FimoReference[];
28
+ }
29
+ export interface AuthorReferences {
30
+ posts: Post[];
31
+ }
32
+ export type AuthorPopulate = Populate<Author>;
33
+ export type AuthorWhere = Where<Author>;
34
+ export type AuthorSort = Sort<Author>;
35
+ export type AuthorFields = Fields<Author>;
36
+ export type AuthorQuery<TFields extends AuthorFields | undefined = AuthorFields | undefined, TPopulate extends AuthorPopulate | undefined = AuthorPopulate | undefined> = Query<Author, TFields, TPopulate>;
37
+ export type AuthorResult<TFields extends AuthorFields | undefined = undefined, TPopulate extends AuthorPopulate | undefined = undefined> = ProjectedWithPopulate<PopulatedResult<Author, TPopulate>, TFields, TPopulate>;
38
+ //# sourceMappingURL=Author.types.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
1
+ import type { CollectionContentClient } from '../types.js';
2
+ import * as Author from './Author.js';
3
+ import type { Post, PostFields, PostInput, PostPopulate, PostQuery } from './Post.types.js';
4
+ export type { Post, PostFields, PostFimoMeta, PostInput, PostPopulate, PostQuery, PostReferences, PostResult, PostSort, PostWhere, } from './Post.types.js';
5
+ export type { CollectionPage, CollectionPageInfo, InfiniteListResult } from '../types.js';
6
+ export type InfiniteListQuery<TFields extends PostFields | undefined = undefined, TPopulate extends PostPopulate | undefined = undefined> = Omit<PostQuery<TFields, TPopulate>, 'offset'>;
7
+ declare const client: CollectionContentClient<Post, PostInput>;
8
+ export declare const getById: <TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(id: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => Promise<import("fimo/content").PopulatedResult<Post, TPopulate> & {
9
+ id: string;
10
+ }>, getBySlug: <TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(slug: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => Promise<(import("fimo/content").PopulatedResult<Post, TPopulate> & {
11
+ id: string;
12
+ }) | null>, getByField: <TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(fieldName: string, value: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => Promise<(import("fimo/content").PopulatedResult<Post, TPopulate> & {
13
+ id: string;
14
+ }) | null>, list: <TFields extends import("fimo/content").Fields<Post> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(params?: import("fimo/content").Query<Post, TFields, TPopulate> | undefined) => Promise<Author.CollectionPage<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Post, TPopulate> & {
15
+ id: string;
16
+ }, TFields, TPopulate>>>, get: <TFields extends import("fimo/content").Fields<Post> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(params?: import("fimo/content").Query<Post, TFields, TPopulate> | undefined) => Promise<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Post, TPopulate> & {
17
+ id: string;
18
+ }, TFields, TPopulate>[]>, create: (payload: PostInput) => Promise<Post>, update: (id: string, payload: Partial<PostInput>) => Promise<Post>, remove: (id: string, options?: {
19
+ locale?: string;
20
+ }) => Promise<void>, useGetById: <TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(id: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<import("fimo/content").PopulatedResult<Post, TPopulate> & {
21
+ id: string;
22
+ }, Error>, useGetBySlug: <TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(slug: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<(import("fimo/content").PopulatedResult<Post, TPopulate> & {
23
+ id: string;
24
+ }) | null, Error>, useGetByField: <TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(fieldName: string, value: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<(import("fimo/content").PopulatedResult<Post, TPopulate> & {
25
+ id: string;
26
+ }) | null, Error>, useList: <TFields extends import("fimo/content").Fields<Post> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(params?: import("fimo/content").Query<Post, TFields, TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<Author.CollectionPage<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Post, TPopulate> & {
27
+ id: string;
28
+ }, TFields, TPopulate>>, Error>, useInfiniteList: <TFields extends import("fimo/content").Fields<Post> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(params?: Omit<import("fimo/content").Query<Post, TFields, TPopulate>, "offset"> | undefined) => Author.InfiniteListResult<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Post, TPopulate> & {
29
+ id: string;
30
+ }, TFields, TPopulate>>, useGet: <TFields extends import("fimo/content").Fields<Post> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(params?: import("fimo/content").Query<Post, TFields, TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Post, TPopulate> & {
31
+ id: string;
32
+ }, TFields, TPopulate>[], Error>, useSuspenseGetById: <TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(id: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseSuspenseQueryResult<import("fimo/content").PopulatedResult<Post, TPopulate> & {
33
+ id: string;
34
+ }, Error>, useSuspenseGet: <TFields extends import("fimo/content").Fields<Post> | undefined = undefined, TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(params?: import("fimo/content").Query<Post, TFields, TPopulate> | undefined) => import("@tanstack/react-query").UseSuspenseQueryResult<import("fimo/content").ProjectedWithPopulate<import("fimo/content").PopulatedResult<Post, TPopulate> & {
35
+ id: string;
36
+ }, TFields, TPopulate>[], Error>, useSuspenseGetByField: <TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(fieldName: string, value: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseSuspenseQueryResult<(import("fimo/content").PopulatedResult<Post, TPopulate> & {
37
+ id: string;
38
+ }) | null, Error>, useSuspenseGetBySlug: <TPopulate extends import("fimo/content").Populate<Post> | undefined = undefined>(slug: string, options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseSuspenseQueryResult<(import("fimo/content").PopulatedResult<Post, TPopulate> & {
39
+ id: string;
40
+ }) | null, Error>, useCreate: () => import("@tanstack/react-query").UseMutationResult<Post, Error, PostInput>, useUpdate: () => import("@tanstack/react-query").UseMutationResult<Post, Error, {
41
+ id: string;
42
+ locale?: string;
43
+ } & Partial<PostInput>>, useRemove: () => import("@tanstack/react-query").UseMutationResult<void, Error, string | {
44
+ id: string;
45
+ locale?: string;
46
+ }>;
47
+ export default client;
48
+ //# sourceMappingURL=Post.d.ts.map
@@ -0,0 +1,37 @@
1
+ // Hand-written draft of the future thin generated module. The release-2
2
+ // template stamps this provenance banner on real output:
3
+ //
4
+ // AUTO-GENERATED by `fimo` from src/schemas/Post.json — DO NOT EDIT.
5
+ // To change fields, edit the schema and re-run `fimo validate`.
6
+ // Runtime implementation lives in the fimo-react package.
7
+ //
8
+ // The schema below is inlined here because fixtures live inside the runtime
9
+ // package; generated code imports the real src/schemas/<uid>.json instead.
10
+ // Forms a real ESM cycle with Author.ts — `references` holds namespace
11
+ // imports, and the factory only reads their `default` client at request
12
+ // time, so reciprocal evaluation never touches an uninitialized binding.
13
+ import { createContentClient } from '../createContentClient.js';
14
+ import * as Author from './Author.js';
15
+ const schema = {
16
+ uid: 'Post',
17
+ name: 'Post',
18
+ isSingleton: false,
19
+ i18n: { enabled: true },
20
+ fields: {
21
+ title: { type: 'string', required: true },
22
+ excerpt: { type: 'text' },
23
+ body: { type: 'richtext' },
24
+ cover: { type: 'media' },
25
+ gallery: { type: 'media', multiple: true },
26
+ views: { type: 'number' },
27
+ author: { type: 'reference', target: 'Author' },
28
+ contributors: { type: 'reference', target: 'Author', many: true },
29
+ related: { type: 'reference', target: 'Post', many: true },
30
+ },
31
+ };
32
+ const client = createContentClient({
33
+ schema,
34
+ references: { Author },
35
+ });
36
+ export const { getById, getBySlug, getByField, list, get, create, update, remove, useGetById, useGetBySlug, useGetByField, useList, useInfiniteList, useGet, useSuspenseGetById, useSuspenseGet, useSuspenseGetByField, useSuspenseGetBySlug, useCreate, useUpdate, useRemove, } = client;
37
+ export default client;
@@ -0,0 +1,50 @@
1
+ import type { Fields, FimoMedia, FimoReference, FimoRichText, FimoRichTextContent, FimoString, Populate, PopulatedResult, ProjectedWithPopulate, Query, Sort, Where, WithReferences } from 'fimo/primitives';
2
+ import type { Author } from './Author.types.js';
3
+ export interface PostFimoMeta {
4
+ contentType: string;
5
+ }
6
+ export interface Post extends WithReferences<PostReferences> {
7
+ id: string;
8
+ entryId: string;
9
+ documentId: string;
10
+ slug: FimoString;
11
+ locale: string;
12
+ createdAt: string;
13
+ updatedAt: string;
14
+ __fimo: PostFimoMeta;
15
+ title: FimoString;
16
+ excerpt: FimoString;
17
+ body?: FimoRichText | null;
18
+ cover: FimoMedia;
19
+ gallery: FimoMedia[];
20
+ views: number;
21
+ author: FimoReference | null;
22
+ contributors: FimoReference[];
23
+ related: FimoReference[];
24
+ }
25
+ export interface PostInput {
26
+ slug?: string;
27
+ locale?: string;
28
+ documentId?: string;
29
+ title: string;
30
+ excerpt?: string;
31
+ body?: FimoRichTextContent | null;
32
+ cover?: Pick<FimoMedia, 'url' | 'alt' | 'name' | 'mime' | 'width' | 'height'>;
33
+ gallery?: Pick<FimoMedia, 'url' | 'alt' | 'name' | 'mime' | 'width' | 'height'>[];
34
+ views?: number;
35
+ author?: FimoReference | null;
36
+ contributors?: FimoReference[];
37
+ related?: FimoReference[];
38
+ }
39
+ export interface PostReferences {
40
+ author: Author | null;
41
+ contributors: Author[];
42
+ related: Post[];
43
+ }
44
+ export type PostPopulate = Populate<Post>;
45
+ export type PostWhere = Where<Post>;
46
+ export type PostSort = Sort<Post>;
47
+ export type PostFields = Fields<Post>;
48
+ export type PostQuery<TFields extends PostFields | undefined = PostFields | undefined, TPopulate extends PostPopulate | undefined = PostPopulate | undefined> = Query<Post, TFields, TPopulate>;
49
+ export type PostResult<TFields extends PostFields | undefined = undefined, TPopulate extends PostPopulate | undefined = undefined> = ProjectedWithPopulate<PopulatedResult<Post, TPopulate>, TFields, TPopulate>;
50
+ //# sourceMappingURL=Post.types.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ import type { Fields, FimoReference, FimoString, Populate, PopulatedResult, ProjectedWithPopulate, Query, Sort, Where, WithReferences } from 'fimo/primitives';
2
+ import type { SingletonContentClient } from '../types.js';
3
+ import type { Author } from './Author.types.js';
4
+ export interface SiteSettingsFimoMeta {
5
+ contentType: string;
6
+ }
7
+ export interface SiteSettings extends WithReferences<SiteSettingsReferences> {
8
+ id: string;
9
+ entryId: string;
10
+ documentId: string;
11
+ slug: FimoString;
12
+ locale?: string;
13
+ createdAt: string;
14
+ updatedAt: string;
15
+ __fimo: SiteSettingsFimoMeta;
16
+ siteName: FimoString;
17
+ supportAuthor: FimoReference | null;
18
+ }
19
+ export interface SiteSettingsInput {
20
+ slug?: string;
21
+ siteName: string;
22
+ supportAuthor?: FimoReference | null;
23
+ }
24
+ export interface SiteSettingsReferences {
25
+ supportAuthor: Author | null;
26
+ }
27
+ export type SiteSettingsPopulate = Populate<SiteSettings>;
28
+ export type SiteSettingsWhere = Where<SiteSettings>;
29
+ export type SiteSettingsSort = Sort<SiteSettings>;
30
+ export type SiteSettingsFields = Fields<SiteSettings>;
31
+ export type SiteSettingsQuery<TFields extends SiteSettingsFields | undefined = SiteSettingsFields | undefined, TPopulate extends SiteSettingsPopulate | undefined = SiteSettingsPopulate | undefined> = Query<SiteSettings, TFields, TPopulate>;
32
+ export type SiteSettingsResult<TFields extends SiteSettingsFields | undefined = undefined, TPopulate extends SiteSettingsPopulate | undefined = undefined> = ProjectedWithPopulate<PopulatedResult<SiteSettings, TPopulate>, TFields, TPopulate>;
33
+ declare const client: SingletonContentClient<SiteSettings, SiteSettingsInput>;
34
+ export declare const get: <TPopulate extends Populate<SiteSettings> | undefined = undefined>(options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => Promise<PopulatedResult<SiteSettings, TPopulate> & {
35
+ id: string;
36
+ }>, update: (payload: Partial<SiteSettingsInput>) => Promise<SiteSettings>, useGet: <TPopulate extends Populate<SiteSettings> | undefined = undefined>(options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseQueryResult<PopulatedResult<SiteSettings, TPopulate> & {
37
+ id: string;
38
+ }, Error>, useSuspenseGet: <TPopulate extends Populate<SiteSettings> | undefined = undefined>(options?: import("fimo/content").ContentReadOptions<TPopulate> | undefined) => import("@tanstack/react-query").UseSuspenseQueryResult<PopulatedResult<SiteSettings, TPopulate> & {
39
+ id: string;
40
+ }, Error>, useUpdate: () => import("@tanstack/react-query").UseMutationResult<SiteSettings, Error, Partial<SiteSettingsInput>>;
41
+ export default client;
42
+ //# sourceMappingURL=SiteSettings.d.ts.map
@@ -0,0 +1,15 @@
1
+ import { createSingletonClient } from '../createSingletonClient.js';
2
+ import * as AuthorModule from './Author.js';
3
+ const schema = {
4
+ uid: 'SiteSettings',
5
+ name: 'SiteSettings',
6
+ isSingleton: true,
7
+ i18n: { enabled: false },
8
+ fields: {
9
+ siteName: { type: 'string', required: true },
10
+ supportAuthor: { type: 'reference', target: 'Author' },
11
+ },
12
+ };
13
+ const client = createSingletonClient({ schema, references: { Author: AuthorModule } });
14
+ export const { get, update, useGet, useSuspenseGet, useUpdate } = client;
15
+ export default client;
@@ -0,0 +1,3 @@
1
+ export declare function fetchContract(): Promise<void>;
2
+ export declare function useHookContract(): void;
3
+ //# sourceMappingURL=usage-contract.d.ts.map
@@ -0,0 +1,57 @@
1
+ import Post from './Post.js';
2
+ import SiteSettings from './SiteSettings.js';
3
+ export async function fetchContract() {
4
+ const page = await Post.list({
5
+ fields: ['title', 'author'],
6
+ populate: ['author'],
7
+ limit: 12,
8
+ offset: 24,
9
+ });
10
+ const pagePosts = page.items;
11
+ const firstAuthorName = pagePosts[0]?.author ? String(pagePosts[0].author.name) : '';
12
+ const total = page.pageInfo.total;
13
+ const nextOffset = page.pageInfo.nextOffset;
14
+ const legacyPosts = await Post.get({ limit: 3 });
15
+ const populated = await Post.getBySlug('hello', { populate: ['author', 'contributors'] });
16
+ const contributorNames = populated ? populated.contributors.map((author) => String(author.name)) : [];
17
+ const settings = await SiteSettings.get({
18
+ populate: ['supportAuthor'],
19
+ });
20
+ const supportAuthor = settings.supportAuthor;
21
+ void [pagePosts, firstAuthorName, total, nextOffset, legacyPosts, contributorNames, supportAuthor];
22
+ }
23
+ export function useHookContract() {
24
+ const legacy = Post.useGet({ limit: 3 });
25
+ const page = Post.useList({
26
+ fields: ['title', 'author'],
27
+ populate: ['author'],
28
+ limit: 12,
29
+ });
30
+ const infinite = Post.useInfiniteList({
31
+ fields: ['title', 'author'],
32
+ populate: ['author'],
33
+ limit: 12,
34
+ });
35
+ const legacyPosts = legacy.data ?? [];
36
+ const pagePosts = page.data?.items ?? [];
37
+ const infinitePosts = infinite.items;
38
+ const hasMore = infinite.hasMore;
39
+ const isLoadingMore = infinite.isLoadingMore;
40
+ void infinite.loadMore();
41
+ // @ts-expect-error infinite lists own offset progression
42
+ Post.useInfiniteList({ offset: 12 });
43
+ const create = Post.useCreate();
44
+ create.mutate({ title: 'Hello' });
45
+ // @ts-expect-error create payload must satisfy the generated Input type
46
+ create.mutate({ title: 123 });
47
+ const update = Post.useUpdate();
48
+ update.mutate({ id: 'p1', title: 'Renamed', locale: 'fr' });
49
+ const removeEntry = Post.useRemove();
50
+ removeEntry.mutate('p1');
51
+ removeEntry.mutate({ id: 'p1', locale: 'fr' });
52
+ const settings = SiteSettings.useGet({ populate: ['supportAuthor'] });
53
+ const supportAuthor = settings.data?.supportAuthor;
54
+ // @ts-expect-error singleton clients have no collection reads
55
+ const missingUseList = SiteSettings.useList;
56
+ void [legacyPosts, pagePosts, infinitePosts, hasMore, isLoadingMore, supportAuthor, missingUseList];
57
+ }
@@ -0,0 +1,3 @@
1
+ declare const config: Record<string, unknown>;
2
+ export default config;
3
+ //# sourceMappingURL=virtual-fimo-config.d.ts.map
@@ -0,0 +1,3 @@
1
+ // Static stand-in for the `virtual:fimo-config` Vite module in vitest runs.
2
+ const config = {};
3
+ export default config;
@@ -0,0 +1,5 @@
1
+ export { createReactContentClient, SOURCE_TRACKED_QUERY_OPTIONS } from './react-content-client.js';
2
+ export { createReactSingletonClient } from './react-singleton-client.js';
3
+ export type { UseContentLocale } from './react-content-client.js';
4
+ export type { CollectionContentClient, CollectionPage, CollectionPageInfo, ContentClientConfig, ContentClientHandle, ContentModuleMeta, ContentModuleRef, ContentReadOptions, ContentResult, ContentSchema, ContentSchemaField, InfiniteListResult, SingletonContentClient, } from './types.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ export { createReactContentClient, SOURCE_TRACKED_QUERY_OPTIONS } from './react-content-client.js';
2
+ export { createReactSingletonClient } from './react-singleton-client.js';