@duffcloudservices/cms-astro 0.1.1 → 0.1.3

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.
package/README.md CHANGED
@@ -1,177 +1,177 @@
1
- # @duffcloudservices/cms-astro
2
-
3
- Astro integration for DCS CMS content and SEO management.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- pnpm add @duffcloudservices/cms-astro
9
- ```
10
-
11
- ## Usage
12
-
13
- ### Configuration
14
-
15
- ```typescript
16
- // astro.config.mjs
17
- import { defineConfig } from 'astro/config'
18
- import dcs from '@duffcloudservices/cms-astro'
19
-
20
- export default defineConfig({
21
- integrations: [dcs()],
22
- })
23
- ```
24
-
25
- ### Using in Components
26
-
27
- ```astro
28
- ---
29
- // src/pages/index.astro
30
- import { t, getPageSeo, getPageContent } from '@duffcloudservices/cms-astro'
31
-
32
- const seo = getPageSeo('home')
33
- const content = getPageContent('home')
34
- ---
35
- <html>
36
- <head>
37
- <title>{seo?.title}</title>
38
- <meta name="description" content={seo?.description} />
39
- {seo?.openGraph?.image && (
40
- <meta property="og:image" content={seo.openGraph.image} />
41
- )}
42
- </head>
43
- <body>
44
- <h1>{t('home', 'hero.title', 'Welcome')}</h1>
45
- <p>{t('home', 'hero.subtitle', 'Build amazing things')}</p>
46
-
47
- <!-- Or use content object directly -->
48
- <p>{content['cta.text']}</p>
49
- </body>
50
- </html>
51
- ```
52
-
53
- ### DCS Configuration Files
54
-
55
- Create `.dcs/content.yaml`:
56
-
57
- ```yaml
58
- version: 1
59
- global:
60
- nav.home: Home
61
- footer.copyright: © 2026 Company
62
- pages:
63
- home:
64
- hero.title: Welcome to Our Site
65
- hero.subtitle: Build something amazing
66
- cta.text: Get Started
67
- ```
68
-
69
- Create `.dcs/seo.yaml`:
70
-
71
- ```yaml
72
- version: 1
73
- global:
74
- siteName: My Site
75
- defaultTitle: My Site
76
- titleTemplate: "%s | My Site"
77
- images:
78
- ogDefault: /images/og-default.jpg
79
- pages:
80
- home:
81
- title: Welcome
82
- description: The homepage of My Site
83
- ```
84
-
85
- ## API
86
-
87
- ### Integration Options
88
-
89
- ```typescript
90
- dcs({
91
- contentPath: '.dcs/content.yaml', // Path to content file
92
- seoPath: '.dcs/seo.yaml', // Path to SEO file
93
- debug: false, // Enable debug logging
94
- })
95
- ```
96
-
97
- ### Runtime Functions
98
-
99
- #### `t(page, key, fallback?)`
100
-
101
- Get text for a specific page and key.
102
-
103
- ```astro
104
- {t('home', 'hero.title', 'Default Title')}
105
- ```
106
-
107
- #### `getContent()`
108
-
109
- Get the full content configuration object.
110
-
111
- #### `getSeo()`
112
-
113
- Get the full SEO configuration object.
114
-
115
- #### `getPageContent(page)`
116
-
117
- Get all content for a page (global merged with page-specific).
118
-
119
- ```astro
120
- ---
121
- const content = getPageContent('home')
122
- ---
123
- {Object.entries(content).map(([key, value]) => (
124
- <p>{key}: {value}</p>
125
- ))}
126
- ```
127
-
128
- #### `getPageSeo(page, overrides?)`
129
-
130
- Get resolved SEO for a page with optional overrides.
131
-
132
- ```astro
133
- ---
134
- const seo = getPageSeo('home', { title: 'Custom Title' })
135
- ---
136
- <title>{seo?.title}</title>
137
- ```
138
-
139
- ## Advanced Usage
140
-
141
- ### Layout Component with SEO
142
-
143
- ```astro
144
- ---
145
- // src/layouts/BaseLayout.astro
146
- import { getPageSeo } from '@duffcloudservices/cms-astro'
147
-
148
- interface Props {
149
- page: string
150
- titleOverride?: string
151
- }
152
-
153
- const { page, titleOverride } = Astro.props
154
- const seo = getPageSeo(page, titleOverride ? { title: titleOverride } : undefined)
155
- ---
156
- <!DOCTYPE html>
157
- <html lang="en">
158
- <head>
159
- <meta charset="UTF-8" />
160
- <meta name="viewport" content="width=device-width" />
161
- <title>{seo?.title ?? 'My Site'}</title>
162
- {seo?.description && (
163
- <meta name="description" content={seo.description} />
164
- )}
165
- {seo?.canonical && (
166
- <link rel="canonical" href={seo.canonical} />
167
- )}
168
- </head>
169
- <body>
170
- <slot />
171
- </body>
172
- </html>
173
- ```
174
-
175
- ## License
176
-
177
- MIT
1
+ # @duffcloudservices/cms-astro
2
+
3
+ Astro integration for DCS CMS content and SEO management.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @duffcloudservices/cms-astro
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Configuration
14
+
15
+ ```typescript
16
+ // astro.config.mjs
17
+ import { defineConfig } from 'astro/config'
18
+ import dcs from '@duffcloudservices/cms-astro'
19
+
20
+ export default defineConfig({
21
+ integrations: [dcs()],
22
+ })
23
+ ```
24
+
25
+ ### Using in Components
26
+
27
+ ```astro
28
+ ---
29
+ // src/pages/index.astro
30
+ import { t, getPageSeo, getPageContent } from '@duffcloudservices/cms-astro'
31
+
32
+ const seo = getPageSeo('home')
33
+ const content = getPageContent('home')
34
+ ---
35
+ <html>
36
+ <head>
37
+ <title>{seo?.title}</title>
38
+ <meta name="description" content={seo?.description} />
39
+ {seo?.openGraph?.image && (
40
+ <meta property="og:image" content={seo.openGraph.image} />
41
+ )}
42
+ </head>
43
+ <body>
44
+ <h1>{t('home', 'hero.title', 'Welcome')}</h1>
45
+ <p>{t('home', 'hero.subtitle', 'Build amazing things')}</p>
46
+
47
+ <!-- Or use content object directly -->
48
+ <p>{content['cta.text']}</p>
49
+ </body>
50
+ </html>
51
+ ```
52
+
53
+ ### DCS Configuration Files
54
+
55
+ Create `.dcs/content.yaml`:
56
+
57
+ ```yaml
58
+ version: 1
59
+ global:
60
+ nav.home: Home
61
+ footer.copyright: © 2026 Company
62
+ pages:
63
+ home:
64
+ hero.title: Welcome to Our Site
65
+ hero.subtitle: Build something amazing
66
+ cta.text: Get Started
67
+ ```
68
+
69
+ Create `.dcs/seo.yaml`:
70
+
71
+ ```yaml
72
+ version: 1
73
+ global:
74
+ siteName: My Site
75
+ defaultTitle: My Site
76
+ titleTemplate: "%s | My Site"
77
+ images:
78
+ ogDefault: /images/og-default.jpg
79
+ pages:
80
+ home:
81
+ title: Welcome
82
+ description: The homepage of My Site
83
+ ```
84
+
85
+ ## API
86
+
87
+ ### Integration Options
88
+
89
+ ```typescript
90
+ dcs({
91
+ contentPath: '.dcs/content.yaml', // Path to content file
92
+ seoPath: '.dcs/seo.yaml', // Path to SEO file
93
+ debug: false, // Enable debug logging
94
+ })
95
+ ```
96
+
97
+ ### Runtime Functions
98
+
99
+ #### `t(page, key, fallback?)`
100
+
101
+ Get text for a specific page and key.
102
+
103
+ ```astro
104
+ {t('home', 'hero.title', 'Default Title')}
105
+ ```
106
+
107
+ #### `getContent()`
108
+
109
+ Get the full content configuration object.
110
+
111
+ #### `getSeo()`
112
+
113
+ Get the full SEO configuration object.
114
+
115
+ #### `getPageContent(page)`
116
+
117
+ Get all content for a page (global merged with page-specific).
118
+
119
+ ```astro
120
+ ---
121
+ const content = getPageContent('home')
122
+ ---
123
+ {Object.entries(content).map(([key, value]) => (
124
+ <p>{key}: {value}</p>
125
+ ))}
126
+ ```
127
+
128
+ #### `getPageSeo(page, overrides?)`
129
+
130
+ Get resolved SEO for a page with optional overrides.
131
+
132
+ ```astro
133
+ ---
134
+ const seo = getPageSeo('home', { title: 'Custom Title' })
135
+ ---
136
+ <title>{seo?.title}</title>
137
+ ```
138
+
139
+ ## Advanced Usage
140
+
141
+ ### Layout Component with SEO
142
+
143
+ ```astro
144
+ ---
145
+ // src/layouts/BaseLayout.astro
146
+ import { getPageSeo } from '@duffcloudservices/cms-astro'
147
+
148
+ interface Props {
149
+ page: string
150
+ titleOverride?: string
151
+ }
152
+
153
+ const { page, titleOverride } = Astro.props
154
+ const seo = getPageSeo(page, titleOverride ? { title: titleOverride } : undefined)
155
+ ---
156
+ <!DOCTYPE html>
157
+ <html lang="en">
158
+ <head>
159
+ <meta charset="UTF-8" />
160
+ <meta name="viewport" content="width=device-width" />
161
+ <title>{seo?.title ?? 'My Site'}</title>
162
+ {seo?.description && (
163
+ <meta name="description" content={seo.description} />
164
+ )}
165
+ {seo?.canonical && (
166
+ <link rel="canonical" href={seo.canonical} />
167
+ )}
168
+ </head>
169
+ <body>
170
+ <slot />
171
+ </body>
172
+ </html>
173
+ ```
174
+
175
+ ## License
176
+
177
+ MIT
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/integration.ts","../src/runtime.ts"],"names":["coreGetPageContent"],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * Astro Integration for DCS CMS\r\n *\r\n * Loads .dcs/content.yaml and .dcs/seo.yaml at build time and injects\r\n * them as global variables for use in Astro components.\r\n */\r\n\r\nimport type { AstroIntegration } from 'astro'\r\nimport { loadContentYaml, loadSeoYaml } from '@duffcloudservices/cms-core'\r\nimport fs from 'node:fs'\r\nimport path from 'node:path'\r\n\r\n/**\r\n * Options for the DCS Astro integration\r\n */\r\nexport interface DcsIntegrationOptions {\r\n /** Path to content.yaml relative to project root (default: '.dcs/content.yaml') */\r\n contentPath?: string\r\n /** Path to seo.yaml relative to project root (default: '.dcs/seo.yaml') */\r\n seoPath?: string\r\n /** Enable debug logging */\r\n debug?: boolean\r\n}\r\n\r\n/**\r\n * Find config file in common locations\r\n */\r\nfunction findConfigFile(filename: string, projectRoot: string): string | undefined {\r\n const possiblePaths = [\r\n path.resolve(projectRoot, filename),\r\n path.resolve(projectRoot, '..', filename),\r\n path.resolve(process.cwd(), filename),\r\n ]\r\n\r\n for (const testPath of possiblePaths) {\r\n if (fs.existsSync(testPath)) {\r\n return testPath\r\n }\r\n }\r\n\r\n return undefined\r\n}\r\n\r\n/**\r\n * DCS Astro integration.\r\n *\r\n * @param options - Integration options\r\n * @returns Astro integration\r\n *\r\n * @example\r\n * ```typescript\r\n * // astro.config.mjs\r\n * import { defineConfig } from 'astro/config'\r\n * import dcs from '@duffcloudservices/cms-astro'\r\n *\r\n * export default defineConfig({\r\n * integrations: [dcs()],\r\n * })\r\n * ```\r\n */\r\nexport default function dcsIntegration(\r\n options: DcsIntegrationOptions = {}\r\n): AstroIntegration {\r\n const {\r\n contentPath = '.dcs/content.yaml',\r\n seoPath = '.dcs/seo.yaml',\r\n debug = false,\r\n } = options\r\n\r\n return {\r\n name: '@duffcloudservices/cms-astro',\r\n hooks: {\r\n 'astro:config:setup': async ({ config, updateConfig, injectScript }) => {\r\n const projectRoot = config.root?.pathname ?? process.cwd()\r\n\r\n // Load content.yaml\r\n let contentJson = 'undefined'\r\n const contentFile = findConfigFile(contentPath, projectRoot)\r\n if (contentFile) {\r\n try {\r\n const content = await loadContentYaml(contentFile)\r\n contentJson = JSON.stringify(content)\r\n if (debug) {\r\n console.log(`[dcs-astro] Loaded content from ${contentFile}`)\r\n }\r\n } catch (err) {\r\n console.warn(`[dcs-astro] Error loading ${contentPath}:`, err)\r\n }\r\n } else if (debug) {\r\n console.log(`[dcs-astro] No content.yaml found at ${contentPath}`)\r\n }\r\n\r\n // Load seo.yaml\r\n let seoJson = 'undefined'\r\n const seoFile = findConfigFile(seoPath, projectRoot)\r\n if (seoFile) {\r\n try {\r\n const seo = await loadSeoYaml(seoFile)\r\n seoJson = JSON.stringify(seo)\r\n if (debug) {\r\n console.log(`[dcs-astro] Loaded SEO config from ${seoFile}`)\r\n }\r\n } catch (err) {\r\n console.warn(`[dcs-astro] Error loading ${seoPath}:`, err)\r\n }\r\n } else if (debug) {\r\n console.log(`[dcs-astro] No seo.yaml found at ${seoPath}`)\r\n }\r\n\r\n // Inject globals via head script\r\n injectScript(\r\n 'head-inline',\r\n `globalThis.__DCS_CONTENT__ = ${contentJson}; globalThis.__DCS_SEO__ = ${seoJson};`\r\n )\r\n\r\n // Also make available to Vite for SSR\r\n updateConfig({\r\n vite: {\r\n define: {\r\n __DCS_CONTENT__: contentJson,\r\n __DCS_SEO__: seoJson,\r\n },\r\n },\r\n })\r\n },\r\n },\r\n }\r\n}\r\n","/**\r\n * Runtime helpers for Astro components\r\n *\r\n * These functions provide access to DCS content and SEO configuration\r\n * that was injected at build time by the Astro integration.\r\n */\r\n\r\nimport {\r\n resolveTextKey,\r\n getPageContent as coreGetPageContent,\r\n resolveSeoForPage,\r\n type ContentConfiguration,\r\n type SeoConfiguration,\r\n type ResolvedSeo,\r\n} from '@duffcloudservices/cms-core'\r\n\r\n// Declare the globals injected by the integration\r\ndeclare const __DCS_CONTENT__: ContentConfiguration | undefined\r\ndeclare const __DCS_SEO__: SeoConfiguration | undefined\r\n\r\n/**\r\n * Get the content configuration.\r\n *\r\n * @returns Content configuration or undefined if not available\r\n */\r\nexport function getContent(): ContentConfiguration | undefined {\r\n try {\r\n if (__DCS_CONTENT__ !== undefined && __DCS_CONTENT__ !== null) {\r\n return __DCS_CONTENT__\r\n }\r\n } catch {\r\n // Not defined\r\n }\r\n return undefined\r\n}\r\n\r\n/**\r\n * Get the SEO configuration.\r\n *\r\n * @returns SEO configuration or undefined if not available\r\n */\r\nexport function getSeo(): SeoConfiguration | undefined {\r\n try {\r\n if (__DCS_SEO__ !== undefined && __DCS_SEO__ !== null) {\r\n return __DCS_SEO__\r\n }\r\n } catch {\r\n // Not defined\r\n }\r\n return undefined\r\n}\r\n\r\n/**\r\n * Get text for a specific page and key.\r\n *\r\n * @param page - Page slug matching entry in content.yaml\r\n * @param key - Text key to retrieve\r\n * @param fallback - Fallback value if key not found\r\n * @returns The resolved text value\r\n *\r\n * @example\r\n * ```astro\r\n * ---\r\n * import { t } from '@duffcloudservices/cms-astro'\r\n * ---\r\n * <h1>{t('home', 'hero.title', 'Welcome')}</h1>\r\n * ```\r\n */\r\nexport function t(page: string, key: string, fallback?: string): string {\r\n const content = getContent()\r\n if (!content) return fallback ?? key\r\n return resolveTextKey(content, page, key) ?? fallback ?? key\r\n}\r\n\r\n/**\r\n * Get all content for a specific page (merged global + page).\r\n *\r\n * @param page - Page slug\r\n * @returns Merged content object\r\n *\r\n * @example\r\n * ```astro\r\n * ---\r\n * import { getPageContent } from '@duffcloudservices/cms-astro'\r\n *\r\n * const content = getPageContent('home')\r\n * ---\r\n * <h1>{content['hero.title']}</h1>\r\n * ```\r\n */\r\nexport function getPageContent(page: string): Record<string, string> {\r\n const content = getContent()\r\n if (!content) return {}\r\n return coreGetPageContent(content, page)\r\n}\r\n\r\n/**\r\n * Get resolved SEO for a specific page.\r\n *\r\n * @param page - Page slug matching entry in seo.yaml\r\n * @param overrides - Optional overrides for title, description, or image\r\n * @returns Resolved SEO object or null if not available\r\n *\r\n * @example\r\n * ```astro\r\n * ---\r\n * import { getPageSeo } from '@duffcloudservices/cms-astro'\r\n *\r\n * const seo = getPageSeo('home')\r\n * ---\r\n * <html>\r\n * <head>\r\n * <title>{seo?.title}</title>\r\n * <meta name=\"description\" content={seo?.description} />\r\n * </head>\r\n * </html>\r\n * ```\r\n */\r\nexport function getPageSeo(\r\n page: string,\r\n overrides?: { title?: string; description?: string; image?: string }\r\n): ResolvedSeo | null {\r\n const seo = getSeo()\r\n if (!seo) return null\r\n\r\n const resolved = resolveSeoForPage(seo, page)\r\n return {\r\n ...resolved,\r\n ...(overrides?.title && { title: overrides.title }),\r\n ...(overrides?.description && { description: overrides.description }),\r\n ...(overrides?.image && { image: overrides.image }),\r\n }\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/integration.ts","../src/runtime.ts"],"names":["coreGetPageContent"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Astro Integration for DCS CMS\n *\n * Loads .dcs/content.yaml and .dcs/seo.yaml at build time and injects\n * them as global variables for use in Astro components.\n */\n\nimport type { AstroIntegration } from 'astro'\nimport { loadContentYaml, loadSeoYaml } from '@duffcloudservices/cms-core'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\n/**\n * Options for the DCS Astro integration\n */\nexport interface DcsIntegrationOptions {\n /** Path to content.yaml relative to project root (default: '.dcs/content.yaml') */\n contentPath?: string\n /** Path to seo.yaml relative to project root (default: '.dcs/seo.yaml') */\n seoPath?: string\n /** Enable debug logging */\n debug?: boolean\n}\n\n/**\n * Find config file in common locations\n */\nfunction findConfigFile(filename: string, projectRoot: string): string | undefined {\n const possiblePaths = [\n path.resolve(projectRoot, filename),\n path.resolve(projectRoot, '..', filename),\n path.resolve(process.cwd(), filename),\n ]\n\n for (const testPath of possiblePaths) {\n if (fs.existsSync(testPath)) {\n return testPath\n }\n }\n\n return undefined\n}\n\n/**\n * DCS Astro integration.\n *\n * @param options - Integration options\n * @returns Astro integration\n *\n * @example\n * ```typescript\n * // astro.config.mjs\n * import { defineConfig } from 'astro/config'\n * import dcs from '@duffcloudservices/cms-astro'\n *\n * export default defineConfig({\n * integrations: [dcs()],\n * })\n * ```\n */\nexport default function dcsIntegration(\n options: DcsIntegrationOptions = {}\n): AstroIntegration {\n const {\n contentPath = '.dcs/content.yaml',\n seoPath = '.dcs/seo.yaml',\n debug = false,\n } = options\n\n return {\n name: '@duffcloudservices/cms-astro',\n hooks: {\n 'astro:config:setup': async ({ config, updateConfig, injectScript }) => {\n const projectRoot = config.root?.pathname ?? process.cwd()\n\n // Load content.yaml\n let contentJson = 'undefined'\n const contentFile = findConfigFile(contentPath, projectRoot)\n if (contentFile) {\n try {\n const content = await loadContentYaml(contentFile)\n contentJson = JSON.stringify(content)\n if (debug) {\n console.log(`[dcs-astro] Loaded content from ${contentFile}`)\n }\n } catch (err) {\n console.warn(`[dcs-astro] Error loading ${contentPath}:`, err)\n }\n } else if (debug) {\n console.log(`[dcs-astro] No content.yaml found at ${contentPath}`)\n }\n\n // Load seo.yaml\n let seoJson = 'undefined'\n const seoFile = findConfigFile(seoPath, projectRoot)\n if (seoFile) {\n try {\n const seo = await loadSeoYaml(seoFile)\n seoJson = JSON.stringify(seo)\n if (debug) {\n console.log(`[dcs-astro] Loaded SEO config from ${seoFile}`)\n }\n } catch (err) {\n console.warn(`[dcs-astro] Error loading ${seoPath}:`, err)\n }\n } else if (debug) {\n console.log(`[dcs-astro] No seo.yaml found at ${seoPath}`)\n }\n\n // Inject globals via head script\n injectScript(\n 'head-inline',\n `globalThis.__DCS_CONTENT__ = ${contentJson}; globalThis.__DCS_SEO__ = ${seoJson};`\n )\n\n // Also make available to Vite for SSR\n updateConfig({\n vite: {\n define: {\n __DCS_CONTENT__: contentJson,\n __DCS_SEO__: seoJson,\n },\n },\n })\n },\n },\n }\n}\n","/**\n * Runtime helpers for Astro components\n *\n * These functions provide access to DCS content and SEO configuration\n * that was injected at build time by the Astro integration.\n */\n\nimport {\n resolveTextKey,\n getPageContent as coreGetPageContent,\n resolveSeoForPage,\n type ContentConfiguration,\n type SeoConfiguration,\n type ResolvedSeo,\n} from '@duffcloudservices/cms-core'\n\n// Declare the globals injected by the integration\ndeclare const __DCS_CONTENT__: ContentConfiguration | undefined\ndeclare const __DCS_SEO__: SeoConfiguration | undefined\n\n/**\n * Get the content configuration.\n *\n * @returns Content configuration or undefined if not available\n */\nexport function getContent(): ContentConfiguration | undefined {\n try {\n if (__DCS_CONTENT__ !== undefined && __DCS_CONTENT__ !== null) {\n return __DCS_CONTENT__\n }\n } catch {\n // Not defined\n }\n return undefined\n}\n\n/**\n * Get the SEO configuration.\n *\n * @returns SEO configuration or undefined if not available\n */\nexport function getSeo(): SeoConfiguration | undefined {\n try {\n if (__DCS_SEO__ !== undefined && __DCS_SEO__ !== null) {\n return __DCS_SEO__\n }\n } catch {\n // Not defined\n }\n return undefined\n}\n\n/**\n * Get text for a specific page and key.\n *\n * @param page - Page slug matching entry in content.yaml\n * @param key - Text key to retrieve\n * @param fallback - Fallback value if key not found\n * @returns The resolved text value\n *\n * @example\n * ```astro\n * ---\n * import { t } from '@duffcloudservices/cms-astro'\n * ---\n * <h1>{t('home', 'hero.title', 'Welcome')}</h1>\n * ```\n */\nexport function t(page: string, key: string, fallback?: string): string {\n const content = getContent()\n if (!content) return fallback ?? key\n return resolveTextKey(content, page, key) ?? fallback ?? key\n}\n\n/**\n * Get all content for a specific page (merged global + page).\n *\n * @param page - Page slug\n * @returns Merged content object\n *\n * @example\n * ```astro\n * ---\n * import { getPageContent } from '@duffcloudservices/cms-astro'\n *\n * const content = getPageContent('home')\n * ---\n * <h1>{content['hero.title']}</h1>\n * ```\n */\nexport function getPageContent(page: string): Record<string, string> {\n const content = getContent()\n if (!content) return {}\n return coreGetPageContent(content, page)\n}\n\n/**\n * Get resolved SEO for a specific page.\n *\n * @param page - Page slug matching entry in seo.yaml\n * @param overrides - Optional overrides for title, description, or image\n * @returns Resolved SEO object or null if not available\n *\n * @example\n * ```astro\n * ---\n * import { getPageSeo } from '@duffcloudservices/cms-astro'\n *\n * const seo = getPageSeo('home')\n * ---\n * <html>\n * <head>\n * <title>{seo?.title}</title>\n * <meta name=\"description\" content={seo?.description} />\n * </head>\n * </html>\n * ```\n */\nexport function getPageSeo(\n page: string,\n overrides?: { title?: string; description?: string; image?: string }\n): ResolvedSeo | null {\n const seo = getSeo()\n if (!seo) return null\n\n const resolved = resolveSeoForPage(seo, page)\n return {\n ...resolved,\n ...(overrides?.title && { title: overrides.title }),\n ...(overrides?.description && { description: overrides.description }),\n ...(overrides?.image && { image: overrides.image }),\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duffcloudservices/cms-astro",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Astro integration for DCS CMS content and SEO management",
5
5
  "type": "module",
6
6
  "exports": {
@@ -18,7 +18,7 @@
18
18
  "astro": "^4.0.0 || ^5.0.0"
19
19
  },
20
20
  "dependencies": {
21
- "@duffcloudservices/cms-core": "0.1.1"
21
+ "@duffcloudservices/cms-core": "0.4.5"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^20.11.0",