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,5 +1,5 @@
1
1
  import React from 'react';
2
- export { getPreviewLocationChange, getPreviewLocationPath } from '../react-router/preview-location.js';
2
+ export { getPreviewLocationChange, getPreviewLocationPath } from '../preview/location.js';
3
3
  export interface ParamInfo {
4
4
  schema: string;
5
5
  queryField: string;
@@ -12,10 +12,11 @@ import { ViteLifecycles } from '../core/ViteLifecycles.js';
12
12
  import { FimoLocaleProvider } from '../i18n/FimoLocaleContext.js';
13
13
  import { getFimoTextDirection, resolveFimoLocale, toHtmlLang } from '../i18n/locale.js';
14
14
  import { ScreenshotProvider } from '../iframe/ScreenshotProvider.js';
15
+ import { getSafePreviewNavigationPath, isPreviewRuntimeEnabled } from '../preview/bridge.js';
16
+ import { getPreviewLocationChange, getPreviewParentOrigin } from '../preview/location.js';
15
17
  import { getActiveRouterRoutes } from '../react-router/active-routes.js';
16
- import { getPreviewLocationChange, getPreviewParentOrigin, } from '../react-router/preview-location.js';
17
18
  import { OptionalTracking } from '../t/OptionalTracking.js';
18
- export { getPreviewLocationChange, getPreviewLocationPath } from '../react-router/preview-location.js';
19
+ export { getPreviewLocationChange, getPreviewLocationPath } from '../preview/location.js';
19
20
  const titleCase = (seg) => seg
20
21
  .replace(/[_-]+/g, ' ')
21
22
  .replace(/([a-z])([A-Z])/g, '$1 $2')
@@ -116,8 +117,11 @@ function PreviewBridge({ readRoutes }) {
116
117
  const payload = event.data?.payload;
117
118
  switch (type) {
118
119
  case 'nav/navigate':
119
- if (payload?.to) {
120
- navigate(payload.to);
120
+ {
121
+ const target = getSafePreviewNavigationPath(payload?.to, window.location.origin);
122
+ if (target) {
123
+ navigate(target);
124
+ }
121
125
  }
122
126
  return;
123
127
  case 'nav/read-routes':
@@ -154,6 +158,8 @@ export function FimoProviders({ children, locale }) {
154
158
  const localeResolution = useMemo(() => resolveFimoLocale({ pathname: location.pathname }, fimoConfig), [location.pathname]);
155
159
  const activeLocale = locale ?? localeResolution.locale;
156
160
  const activeDir = getFimoTextDirection(activeLocale);
161
+ // @ts-ignore - import.meta.env is provided by Vite and React Router.
162
+ const previewEnabled = isPreviewRuntimeEnabled(import.meta.env.VITE_PREVIEW_SCRIPT_URL);
157
163
  useEffect(() => {
158
164
  if (typeof document === 'undefined') {
159
165
  return;
@@ -165,5 +171,5 @@ export function FimoProviders({ children, locale }) {
165
171
  ...localeResolution,
166
172
  locale: activeLocale,
167
173
  dir: activeDir,
168
- }, children: _jsx(DataSourcesProvider, { children: _jsx(ScreenshotProvider, { children: _jsx(ViteLifecycles, { children: _jsxs(RefreshContentProvider, { children: [_jsx(PreviewBridge, { readRoutes: readRoutes }), _jsx(OptionalTracking, { routes: routes }), _jsx(Suspense, { children: children })] }) }) }) }) }) }) }));
174
+ }, children: _jsx(DataSourcesProvider, { children: _jsx(ScreenshotProvider, { children: _jsx(ViteLifecycles, { children: _jsxs(RefreshContentProvider, { children: [previewEnabled ? _jsx(PreviewBridge, { readRoutes: readRoutes }) : null, _jsx(OptionalTracking, { routes: routes }), _jsx(Suspense, { children: children })] }) }) }) }) }) }) }));
169
175
  }
@@ -0,0 +1,6 @@
1
+ export { renderRichTextHtml } from './render-rich-text.js';
2
+ export { resolveImagePresentation, type ImageFit } from '../primitives/lib/image-optimization.js';
3
+ export { connectAstroPreview, type AstroPreviewOptions } from './preview.js';
4
+ type AstroImageStyle = string | Record<string, unknown> | undefined;
5
+ export declare function mergeAstroImageStyle(style: AstroImageStyle, objectFit: string): AstroImageStyle;
6
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1,16 @@
1
+ export { renderRichTextHtml } from './render-rich-text.js';
2
+ export { resolveImagePresentation } from '../primitives/lib/image-optimization.js';
3
+ export { connectAstroPreview } from './preview.js';
4
+ export function mergeAstroImageStyle(style, objectFit) {
5
+ if (typeof style === 'string') {
6
+ if (/(?:^|;)\s*object-fit\s*:/i.test(style)) {
7
+ return style;
8
+ }
9
+ const separator = style.trim() === '' || style.trimEnd().endsWith(';') ? '' : ';';
10
+ return `${style}${separator}object-fit:${objectFit}`;
11
+ }
12
+ if (style && ('objectFit' in style || 'object-fit' in style)) {
13
+ return style;
14
+ }
15
+ return { ...style, objectFit };
16
+ }
@@ -0,0 +1,14 @@
1
+ import type { PreviewRoute } from '../preview/routes.js';
2
+ import type { FimoI18nConfig } from '../shared/fimo-config.types.js';
3
+ export interface AstroPreviewOptions {
4
+ readonly previewScriptUrl: string | undefined;
5
+ readonly routes: PreviewRoute[];
6
+ readonly i18n?: FimoI18nConfig;
7
+ }
8
+ export interface AstroPreviewBrowser {
9
+ readonly window: Window;
10
+ readonly document: Document;
11
+ }
12
+ /** Connect an Astro document to Studio without taking ownership of Astro routing. */
13
+ export declare function connectAstroPreview(options: AstroPreviewOptions, browser?: AstroPreviewBrowser | undefined): () => void;
14
+ //# sourceMappingURL=preview.d.ts.map
@@ -0,0 +1,103 @@
1
+ import { resolveFimoLocale } from '../i18n/locale.js';
2
+ import { getSafePreviewNavigationPath, isPreviewRuntimeEnabled } from '../preview/bridge.js';
3
+ import { getPreviewLocationChange, getPreviewParentOrigin } from '../preview/location.js';
4
+ const ASTRO_PAGE_LOAD_EVENT = 'astro:page-load';
5
+ const ASTRO_AFTER_SWAP_EVENT = 'astro:after-swap';
6
+ const CONNECTION_KEY = '__fimoAstroPreviewDisconnect__';
7
+ /**
8
+ * Internal signal the injected preview bundle listens for on `document`.
9
+ *
10
+ * ClientRouter replaces `<body>` and rewrites the `<html>` attributes in place,
11
+ * so the overlay ends up detached and everything bound to those nodes stale.
12
+ * Translating that here keeps Astro's lifecycle out of the shared bundle, which
13
+ * knows only this event name. Frameworks that keep the document mounted never
14
+ * emit it. Keep in sync with `packages/preview/src/documentChange.ts`.
15
+ */
16
+ const FIMO_DOCUMENT_CHANGE_EVENT = 'fimo:document-change';
17
+ function currentBrowser() {
18
+ return typeof window === 'undefined' || typeof document === 'undefined' ? undefined : { window, document };
19
+ }
20
+ function loadPreviewScript(browserDocument, previewScriptUrl) {
21
+ if (browserDocument.querySelector('script[data-fimo-preview-script]')) {
22
+ return;
23
+ }
24
+ const script = browserDocument.createElement('script');
25
+ script.src = previewScriptUrl;
26
+ script.defer = true;
27
+ script.dataset.fimoPreviewScript = '';
28
+ browserDocument.head.append(script);
29
+ }
30
+ /** Connect an Astro document to Studio without taking ownership of Astro routing. */
31
+ export function connectAstroPreview(options, browser = currentBrowser()) {
32
+ if (!browser) {
33
+ return () => undefined;
34
+ }
35
+ if (!isPreviewRuntimeEnabled(options.previewScriptUrl)) {
36
+ return () => undefined;
37
+ }
38
+ const connectedWindow = browser.window;
39
+ connectedWindow[CONNECTION_KEY]?.();
40
+ loadPreviewScript(browser.document, options.previewScriptUrl);
41
+ const parentOrigin = getPreviewParentOrigin(browser);
42
+ const postToStudio = (message) => browser.window.parent.postMessage(message, parentOrigin ?? '*');
43
+ const sendRoutes = () => {
44
+ postToStudio({ type: 'nav/routes', payload: { routes: options.routes } });
45
+ };
46
+ const sendLocation = () => {
47
+ const location = getPreviewLocationChange(browser.window.location);
48
+ const locale = resolveFimoLocale({ pathname: browser.window.location.pathname }, { i18n: options.i18n });
49
+ postToStudio({
50
+ type: 'nav/locationChange',
51
+ payload: {
52
+ ...(parentOrigin ? location : { path: location.path }),
53
+ routePath: locale.routePath,
54
+ locale: browser.document.documentElement.lang || locale.locale,
55
+ },
56
+ });
57
+ };
58
+ const announceDocumentChange = () => {
59
+ browser.document.dispatchEvent(new Event(FIMO_DOCUMENT_CHANGE_EVENT));
60
+ };
61
+ const handleMessage = (event) => {
62
+ if (event.source !== browser.window.parent || !parentOrigin || event.origin !== parentOrigin) {
63
+ return;
64
+ }
65
+ if (event.data?.type === 'nav/navigate') {
66
+ const target = getSafePreviewNavigationPath(event.data?.payload?.to, browser.window.location.origin);
67
+ if (target) {
68
+ browser.window.location.assign(target);
69
+ }
70
+ return;
71
+ }
72
+ if (event.data?.type === 'content/refresh') {
73
+ if (event.data?.requiresAck && typeof event.data?.messageId === 'string') {
74
+ postToStudio({ type: 'ack', payload: { messageId: event.data.messageId, ok: true } });
75
+ }
76
+ browser.window.setTimeout(() => browser.window.location.reload(), 0);
77
+ return;
78
+ }
79
+ if (event.data?.type === 'nav/read-routes') {
80
+ sendRoutes();
81
+ sendLocation();
82
+ }
83
+ };
84
+ browser.window.addEventListener('message', handleMessage);
85
+ browser.window.addEventListener('popstate', sendLocation);
86
+ browser.window.addEventListener('hashchange', sendLocation);
87
+ browser.document.addEventListener(ASTRO_PAGE_LOAD_EVENT, sendLocation);
88
+ browser.document.addEventListener(ASTRO_AFTER_SWAP_EVENT, announceDocumentChange);
89
+ sendRoutes();
90
+ sendLocation();
91
+ const disconnect = () => {
92
+ browser.window.removeEventListener('message', handleMessage);
93
+ browser.window.removeEventListener('popstate', sendLocation);
94
+ browser.window.removeEventListener('hashchange', sendLocation);
95
+ browser.document.removeEventListener(ASTRO_PAGE_LOAD_EVENT, sendLocation);
96
+ browser.document.removeEventListener(ASTRO_AFTER_SWAP_EVENT, announceDocumentChange);
97
+ if (connectedWindow[CONNECTION_KEY] === disconnect) {
98
+ delete connectedWindow[CONNECTION_KEY];
99
+ }
100
+ };
101
+ connectedWindow[CONNECTION_KEY] = disconnect;
102
+ return disconnect;
103
+ }
@@ -0,0 +1,2 @@
1
+ export { renderRichTextHtml } from '../primitives/lib/render-rich-text.js';
2
+ //# sourceMappingURL=render-rich-text.d.ts.map
@@ -0,0 +1 @@
1
+ export { renderRichTextHtml } from '../primitives/lib/render-rich-text.js';
@@ -0,0 +1,3 @@
1
+ import { type ContentRuntime } from '../content/client/runtime.js';
2
+ export declare const astroServerContentRuntime: ContentRuntime;
3
+ //# sourceMappingURL=server-runtime.d.ts.map
@@ -0,0 +1,20 @@
1
+ import { requireContentApiUrl } from '../content/client/runtime.js';
2
+ export const astroServerContentRuntime = {
3
+ apiBase() {
4
+ return requireContentApiUrl(import.meta.env.FIMO_CONTENT_API_URL, 'FIMO_CONTENT_API_URL');
5
+ },
6
+ defaultLocale() {
7
+ return import.meta.env.FIMO_DEFAULT_LOCALE?.trim() || undefined;
8
+ },
9
+ headers(extra) {
10
+ const headers = { ...extra };
11
+ const env = import.meta.env.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,15 @@
1
+ import type { CollectionContentCore, ContentClientConfig, SingletonContentCore } from '../content/client/core-types.js';
2
+ import { type GetLabelsOptions } from '../labels/fetch.js';
3
+ export declare function createContentClient<T extends {
4
+ id: string;
5
+ }, TInput extends object>(config: ContentClientConfig): CollectionContentCore<T, TInput>;
6
+ export declare function createSingletonClient<T extends {
7
+ id: string;
8
+ }, TInput extends object>(config: ContentClientConfig): SingletonContentCore<T, TInput>;
9
+ export declare function getLabels(options?: GetLabelsOptions): Promise<import("./server.js").Labels>;
10
+ export { fimo } from '../primitives/lib/template.js';
11
+ export type { CollectionContentCore as CollectionContentClient, SingletonContentCore as SingletonContentClient, } from '../content/client/core-types.js';
12
+ export type { GetLabelsOptions } from '../labels/fetch.js';
13
+ export type { Labels, LabelsSnapshot } from '../labels/core.js';
14
+ export * from '../content/index.js';
15
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { createServerContentClient, createServerSingletonClient } from '../content/client/server-content-client.js';
2
+ import { fetchLabels } from '../labels/fetch.js';
3
+ import { astroServerContentRuntime } from './server-runtime.js';
4
+ export function createContentClient(config) {
5
+ return createServerContentClient(config, astroServerContentRuntime);
6
+ }
7
+ export function createSingletonClient(config) {
8
+ return createServerSingletonClient(config, astroServerContentRuntime);
9
+ }
10
+ export function getLabels(options) {
11
+ return fetchLabels(astroServerContentRuntime, options);
12
+ }
13
+ export { fimo } from '../primitives/lib/template.js';
14
+ export * from '../content/index.js';
@@ -1,22 +1,7 @@
1
1
  import type { Fields, Populate, Query } from '../../primitives/lib/query.js';
2
+ import type { CollectionContentCore, ContentClientConfig, ContentReadOptions } from './core-types.js';
2
3
  import type { ContentRuntime } from './runtime.js';
3
- import type { CollectionPage, ContentClientConfig, ContentModuleMeta, ContentReadOptions, ContentResult } from './types.js';
4
- export interface CollectionContentCore<T extends {
5
- id: string;
6
- }, TInput extends object> {
7
- readonly meta: ContentModuleMeta;
8
- wrapWithSource(entry: Record<string, any>): T;
9
- getById<TPopulate extends Populate<T> | undefined = undefined>(id: string, options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate>>;
10
- getBySlug<TPopulate extends Populate<T> | undefined = undefined>(slug: string, options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate> | null>;
11
- getByField<TPopulate extends Populate<T> | undefined = undefined>(fieldName: string, value: string, options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate> | null>;
12
- list<TFields extends Fields<T> | undefined = undefined, TPopulate extends Populate<T> | undefined = undefined>(params?: Query<T, TFields, TPopulate>): Promise<CollectionPage<ContentResult<T, TFields, TPopulate>>>;
13
- get<TFields extends Fields<T> | undefined = undefined, TPopulate extends Populate<T> | undefined = undefined>(params?: Query<T, TFields, TPopulate>): Promise<ContentResult<T, TFields, TPopulate>[]>;
14
- create(payload: TInput): Promise<T>;
15
- update(id: string, payload: Partial<TInput>): Promise<T>;
16
- remove(id: string, options?: {
17
- locale?: string;
18
- }): Promise<void>;
19
- }
4
+ export type { CollectionContentCore } from './core-types.js';
20
5
  export interface CollectionCoreState<T extends {
21
6
  id: string;
22
7
  }, TInput extends object> {
@@ -7,15 +7,19 @@ export function createCollectionContentCore(config, runtime) {
7
7
  throw new Error(`Schema "${info.uid}" is a Single — use createSingletonClient instead.`);
8
8
  }
9
9
  validateReferences(info, references);
10
- const defaultLocale = runtime.defaultLocale();
10
+ const requestDefaultLocale = runtime.defaultLocale();
11
11
  const meta = { uid: info.uid, pascal: info.pascal, localized: info.localized };
12
12
  const self = { wrapWithSource, meta };
13
13
  const resolve = (uid) => uid === info.uid ? self : resolveClientHandle(references[uid]);
14
14
  function wrapWithSource(entry) {
15
- return wrapEntry(info, entry, { alwaysIncludeLocale: true, defaultLocale, resolve });
15
+ return wrapEntry(info, entry, {
16
+ alwaysIncludeLocale: true,
17
+ defaultLocale: requestDefaultLocale ?? 'en',
18
+ resolve,
19
+ });
16
20
  }
17
21
  function readPath(url, options) {
18
- return buildReadPath(url, readCollectionLocale(options, defaultLocale), options.populate, options.localeFallbacks);
22
+ return buildReadPath(url, readCollectionLocale(options, requestDefaultLocale), options.populate, options.localeFallbacks);
19
23
  }
20
24
  async function getById(id, options = {}) {
21
25
  const response = await runtime.fetch(`${runtime.apiBase()}${readPath(`/entries/${info.uid}/${id}`, options)}`, {
@@ -69,7 +73,10 @@ export function createCollectionContentCore(config, runtime) {
69
73
  if (where && Object.keys(where).length > 0) {
70
74
  query.set('where', JSON.stringify(where));
71
75
  }
72
- query.set('locale', readCollectionLocale({ locale: requestedLocale }, defaultLocale));
76
+ const locale = readCollectionLocale({ locale: requestedLocale }, requestDefaultLocale);
77
+ if (locale) {
78
+ query.set('locale', locale);
79
+ }
73
80
  return query.toString();
74
81
  }
75
82
  async function list(params = {}) {
@@ -96,7 +103,7 @@ export function createCollectionContentCore(config, runtime) {
96
103
  }
97
104
  async function create(payload) {
98
105
  const localizedPayload = info.localized
99
- ? withMutationLocale(payload, readCollectionLocale({}, defaultLocale))
106
+ ? withMutationLocale(payload, readCollectionLocale({}, requestDefaultLocale))
100
107
  : payload;
101
108
  const response = await runtime.fetch(`${runtime.apiBase()}/entries/${info.uid}`, {
102
109
  method: 'POST',
@@ -111,7 +118,7 @@ export function createCollectionContentCore(config, runtime) {
111
118
  }
112
119
  async function update(id, payload) {
113
120
  const write = splitWritePayload(payload);
114
- const url = buildReadPath(`/entries/${info.uid}/${id}`, readCollectionLocale({ locale: write.locale }, defaultLocale), undefined);
121
+ const url = buildReadPath(`/entries/${info.uid}/${id}`, readCollectionLocale({ locale: write.locale }, requestDefaultLocale), undefined);
115
122
  const response = await runtime.fetch(`${runtime.apiBase()}${url}`, {
116
123
  method: 'PUT',
117
124
  headers: runtime.headers({ 'Content-Type': 'application/json' }),
@@ -124,7 +131,7 @@ export function createCollectionContentCore(config, runtime) {
124
131
  return wrapWithSource(body.data);
125
132
  }
126
133
  async function remove(id, options = {}) {
127
- const url = buildReadPath(`/entries/${info.uid}/${id}`, readCollectionLocale(options, defaultLocale), undefined);
134
+ const url = buildReadPath(`/entries/${info.uid}/${id}`, readCollectionLocale(options, requestDefaultLocale), undefined);
128
135
  const response = await runtime.fetch(`${runtime.apiBase()}${url}`, {
129
136
  method: 'DELETE',
130
137
  headers: runtime.headers(),
@@ -143,7 +150,7 @@ export function createCollectionContentCore(config, runtime) {
143
150
  };
144
151
  return {
145
152
  client: { meta, wrapWithSource, getById, getBySlug, getByField, list, get, create, update, remove },
146
- defaultLocale,
153
+ defaultLocale: requestDefaultLocale ?? 'en',
147
154
  queryKeys,
148
155
  };
149
156
  }
@@ -0,0 +1,96 @@
1
+ import type { Fields, Populate, PopulatedResult, ProjectedWithPopulate, Query } from '../../primitives/lib/query.js';
2
+ export type ContentResult<T extends {
3
+ id: string;
4
+ }, TFields extends Fields<T> | undefined = undefined, TPopulate extends Populate<T> | undefined = undefined> = ProjectedWithPopulate<PopulatedResult<T, TPopulate> & {
5
+ id: string;
6
+ }, TFields, TPopulate>;
7
+ export interface ContentSchemaField {
8
+ type?: string;
9
+ required?: boolean;
10
+ default?: unknown;
11
+ multiple?: boolean;
12
+ many?: boolean;
13
+ target?: string;
14
+ targets?: readonly string[];
15
+ min?: number;
16
+ max?: number;
17
+ minLength?: number;
18
+ maxLength?: number;
19
+ regex?: string;
20
+ schema?: {
21
+ fields: Readonly<Record<string, ContentSchemaField>>;
22
+ } | {
23
+ oneOf: readonly {
24
+ uid: string;
25
+ label: string;
26
+ description?: string;
27
+ fields: Readonly<Record<string, ContentSchemaField>>;
28
+ }[];
29
+ };
30
+ }
31
+ export interface ContentSchema {
32
+ uid: string;
33
+ name?: string;
34
+ isSingleton?: boolean;
35
+ i18n?: {
36
+ enabled?: boolean;
37
+ };
38
+ fields?: Readonly<Record<string, ContentSchemaField>>;
39
+ }
40
+ export interface ContentModuleMeta {
41
+ readonly uid: string;
42
+ readonly pascal: string;
43
+ readonly localized: boolean;
44
+ }
45
+ export interface ContentClientHandle {
46
+ wrapWithSource: (entry: Record<string, any>) => unknown;
47
+ meta: ContentModuleMeta;
48
+ }
49
+ export type ContentModuleRef = ContentClientHandle | {
50
+ default: ContentClientHandle;
51
+ };
52
+ export interface ContentClientConfig {
53
+ schema: ContentSchema;
54
+ references?: Readonly<Record<string, ContentModuleRef>>;
55
+ }
56
+ export interface ContentReadOptions<TPopulate> {
57
+ locale?: string;
58
+ populate?: TPopulate;
59
+ localeFallbacks?: boolean;
60
+ }
61
+ export interface CollectionPageInfo {
62
+ readonly limit: number;
63
+ readonly offset: number;
64
+ readonly total: number;
65
+ readonly hasMore: boolean;
66
+ readonly nextOffset: number | null;
67
+ }
68
+ export interface CollectionPage<TItem> {
69
+ readonly items: TItem[];
70
+ readonly pageInfo: CollectionPageInfo;
71
+ }
72
+ export interface CollectionContentCore<T extends {
73
+ id: string;
74
+ }, TInput extends object> {
75
+ readonly meta: ContentModuleMeta;
76
+ wrapWithSource(entry: Record<string, any>): T;
77
+ getById<TPopulate extends Populate<T> | undefined = undefined>(id: string, options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate>>;
78
+ getBySlug<TPopulate extends Populate<T> | undefined = undefined>(slug: string, options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate> | null>;
79
+ getByField<TPopulate extends Populate<T> | undefined = undefined>(fieldName: string, value: string, options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate> | null>;
80
+ list<TFields extends Fields<T> | undefined = undefined, TPopulate extends Populate<T> | undefined = undefined>(params?: Query<T, TFields, TPopulate>): Promise<CollectionPage<ContentResult<T, TFields, TPopulate>>>;
81
+ get<TFields extends Fields<T> | undefined = undefined, TPopulate extends Populate<T> | undefined = undefined>(params?: Query<T, TFields, TPopulate>): Promise<ContentResult<T, TFields, TPopulate>[]>;
82
+ create(payload: TInput): Promise<T>;
83
+ update(id: string, payload: Partial<TInput>): Promise<T>;
84
+ remove(id: string, options?: {
85
+ locale?: string;
86
+ }): Promise<void>;
87
+ }
88
+ export interface SingletonContentCore<T extends {
89
+ id: string;
90
+ }, TInput extends object> {
91
+ readonly meta: ContentModuleMeta;
92
+ wrapWithSource(entry: Record<string, any>): T;
93
+ get<TPopulate extends Populate<T> | undefined = undefined>(options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate>>;
94
+ update(payload: Partial<TInput>): Promise<T>;
95
+ }
96
+ //# sourceMappingURL=core-types.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
- import type { ContentClientHandle, ContentModuleRef, ContentSchema, ContentSchemaField } from './types.js';
1
+ import type { ContentClientHandle, ContentModuleRef, ContentSchema, ContentSchemaField } from './core-types.js';
2
2
  export interface InterpretedSchema {
3
3
  uid: string;
4
4
  pascal: string;
@@ -13,7 +13,7 @@ interface LocaleReadOptions {
13
13
  locale?: string;
14
14
  populate?: string | readonly string[];
15
15
  }
16
- export declare function readCollectionLocale(options: LocaleReadOptions, fallbackLocale?: string): string;
16
+ export declare function readCollectionLocale(options: LocaleReadOptions, fallbackLocale?: string): string | undefined;
17
17
  export declare function readSingletonLocale(options: LocaleReadOptions, ownerUsesLocale: boolean, localizedReferenceFields: ReadonlySet<string>, fallbackLocale?: string): string | undefined;
18
18
  export declare function buildReadPath(url: string, locale: string | undefined, populate: string | readonly string[] | undefined, localeFallbacks?: boolean): string;
19
19
  export declare function splitWritePayload(payload: Record<string, unknown>): {
@@ -21,8 +21,8 @@ export declare function splitWritePayload(payload: Record<string, unknown>): {
21
21
  locale?: string;
22
22
  documentId?: string;
23
23
  };
24
- export declare function withMutationLocale<T extends object>(payload: T, activeLocale: string): T & {
25
- locale: string;
24
+ export declare function withMutationLocale<T extends object>(payload: T, activeLocale?: string): T & {
25
+ locale?: string;
26
26
  };
27
27
  type ReferenceResolver = (uid: string) => ContentClientHandle | undefined;
28
28
  /**
@@ -45,10 +45,10 @@ function populateFields(populate) {
45
45
  }
46
46
  return typeof populate === 'string' ? [populate] : [...populate];
47
47
  }
48
- export function readCollectionLocale(options, fallbackLocale = 'en') {
48
+ export function readCollectionLocale(options, fallbackLocale) {
49
49
  return options.locale ?? fallbackLocale;
50
50
  }
51
- export function readSingletonLocale(options, ownerUsesLocale, localizedReferenceFields, fallbackLocale = 'en') {
51
+ export function readSingletonLocale(options, ownerUsesLocale, localizedReferenceFields, fallbackLocale) {
52
52
  const populatesLocalizedTarget = populateFields(options.populate).some((field) => localizedReferenceFields.has(field));
53
53
  return ownerUsesLocale || populatesLocalizedTarget ? (options.locale ?? fallbackLocale) : undefined;
54
54
  }
@@ -80,7 +80,8 @@ export function splitWritePayload(payload) {
80
80
  }
81
81
  export function withMutationLocale(payload, activeLocale) {
82
82
  const locale = payload.locale;
83
- return { ...payload, locale: locale ?? activeLocale };
83
+ const resolvedLocale = locale ?? activeLocale;
84
+ return resolvedLocale ? { ...payload, locale: resolvedLocale } : payload;
84
85
  }
85
86
  function isPopulatedEntry(value) {
86
87
  if (value == null || typeof value !== 'object') {
@@ -1,6 +1,6 @@
1
1
  export interface ContentRuntime {
2
2
  apiBase(): string;
3
- defaultLocale(): string;
3
+ defaultLocale(): string | undefined;
4
4
  headers(extra?: Record<string, string>): Record<string, string>;
5
5
  fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
6
6
  }
@@ -1,9 +1,9 @@
1
+ import type { CollectionContentCore, ContentClientConfig, SingletonContentCore } from './core-types.js';
1
2
  import type { ContentRuntime } from './runtime.js';
2
- import type { CollectionContentClient, ContentClientConfig, SingletonContentClient } from './types.js';
3
3
  export declare function createServerContentClient<T extends {
4
4
  id: string;
5
- }, TInput extends object>(config: ContentClientConfig, runtime: ContentRuntime): CollectionContentClient<T, TInput>;
5
+ }, TInput extends object>(config: ContentClientConfig, runtime: ContentRuntime): CollectionContentCore<T, TInput>;
6
6
  export declare function createServerSingletonClient<T extends {
7
7
  id: string;
8
- }, TInput extends object>(config: ContentClientConfig, runtime: ContentRuntime): SingletonContentClient<T, TInput>;
8
+ }, TInput extends object>(config: ContentClientConfig, runtime: ContentRuntime): SingletonContentCore<T, TInput>;
9
9
  //# sourceMappingURL=server-content-client.d.ts.map
@@ -1,35 +1,8 @@
1
1
  import { createCollectionContentCore } from './collection-core.js';
2
2
  import { createSingletonContentCore } from './singleton-core.js';
3
- function clientHook(name) {
4
- return () => {
5
- throw new Error(`${name} is a Client Component hook. Call it only below a "use client" boundary.`);
6
- };
7
- }
8
3
  export function createServerContentClient(config, runtime) {
9
- const { client } = createCollectionContentCore(config, runtime);
10
- return {
11
- ...client,
12
- useGetById: clientHook('useGetById'),
13
- useGetBySlug: clientHook('useGetBySlug'),
14
- useGetByField: clientHook('useGetByField'),
15
- useGet: clientHook('useGet'),
16
- useList: clientHook('useList'),
17
- useInfiniteList: clientHook('useInfiniteList'),
18
- useSuspenseGetById: clientHook('useSuspenseGetById'),
19
- useSuspenseGetBySlug: clientHook('useSuspenseGetBySlug'),
20
- useSuspenseGetByField: clientHook('useSuspenseGetByField'),
21
- useSuspenseGet: clientHook('useSuspenseGet'),
22
- useCreate: clientHook('useCreate'),
23
- useUpdate: clientHook('useUpdate'),
24
- useRemove: clientHook('useRemove'),
25
- };
4
+ return createCollectionContentCore(config, runtime).client;
26
5
  }
27
6
  export function createServerSingletonClient(config, runtime) {
28
- const { client } = createSingletonContentCore(config, runtime);
29
- return {
30
- ...client,
31
- useGet: clientHook('useGet'),
32
- useSuspenseGet: clientHook('useSuspenseGet'),
33
- useUpdate: clientHook('useUpdate'),
34
- };
7
+ return createSingletonContentCore(config, runtime).client;
35
8
  }
@@ -1,14 +1,7 @@
1
1
  import type { Populate } from '../../primitives/lib/query.js';
2
+ import type { ContentClientConfig, ContentReadOptions, SingletonContentCore } from './core-types.js';
2
3
  import type { ContentRuntime } from './runtime.js';
3
- import type { ContentClientConfig, ContentModuleMeta, ContentReadOptions, ContentResult } from './types.js';
4
- export interface SingletonContentCore<T extends {
5
- id: string;
6
- }, TInput extends object> {
7
- readonly meta: ContentModuleMeta;
8
- wrapWithSource(entry: Record<string, any>): T;
9
- get<TPopulate extends Populate<T> | undefined = undefined>(options?: ContentReadOptions<TPopulate>): Promise<ContentResult<T, undefined, TPopulate>>;
10
- update(payload: Partial<TInput>): Promise<T>;
11
- }
4
+ export type { SingletonContentCore } from './core-types.js';
12
5
  export interface SingletonCoreState<T extends {
13
6
  id: string;
14
7
  }, TInput extends object> {
@@ -6,7 +6,7 @@ export function createSingletonContentCore(config, runtime) {
6
6
  throw new Error(`Schema "${info.uid}" is a collection — use createContentClient instead.`);
7
7
  }
8
8
  validateReferences(info, references);
9
- const defaultLocale = runtime.defaultLocale();
9
+ const requestDefaultLocale = runtime.defaultLocale();
10
10
  const meta = { uid: info.uid, pascal: info.pascal, localized: info.localized };
11
11
  const self = { wrapWithSource, meta };
12
12
  const resolve = (uid) => uid === info.uid ? self : resolveClientHandle(references[uid]);
@@ -31,11 +31,11 @@ export function createSingletonContentCore(config, runtime) {
31
31
  function wrapWithSource(entry) {
32
32
  return wrapEntry(info, entry, {
33
33
  alwaysIncludeLocale: info.localized,
34
- defaultLocale,
34
+ defaultLocale: requestDefaultLocale ?? 'en',
35
35
  resolve,
36
36
  });
37
37
  }
38
- function localize(options, fallbackLocale = defaultLocale) {
38
+ function localize(options, fallbackLocale = requestDefaultLocale) {
39
39
  return readSingletonLocale(options, info.localized, getLocalizedReferenceFields(), fallbackLocale);
40
40
  }
41
41
  function readPath(url, options) {
@@ -69,5 +69,10 @@ export function createSingletonContentCore(config, runtime) {
69
69
  root: [info.pascal],
70
70
  document: (options = {}) => [info.pascal, 'document', options.locale, options.populate],
71
71
  };
72
- return { client: { meta, wrapWithSource, get, update }, defaultLocale, localize, queryKeys };
72
+ return {
73
+ client: { meta, wrapWithSource, get, update },
74
+ defaultLocale: requestDefaultLocale ?? 'en',
75
+ localize,
76
+ queryKeys,
77
+ };
73
78
  }