ayezee-astro-cms 1.2.2 → 1.4.0

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,10 +1,11 @@
1
1
  # @ayezee/astro-cms
2
2
 
3
- AyeZee CMS integration for Astro with automatic data fetching, form handling, and validation.
3
+ AyeZee CMS integration for Astro with automatic data fetching, form handling, validation, and analytics.
4
4
 
5
5
  ## Features
6
6
 
7
7
  - 🚀 **Automatic Data Fetching** - Fetches CMS data during build time
8
+ - 📊 **Analytics Integration** - Auto-inject Umami analytics from dashboard settings
8
9
  - 📦 **Type-Safe** - Full TypeScript support with proper types
9
10
  - 🔄 **Build-Time Caching** - No runtime API calls needed
10
11
  - ✅ **Form Validation** - Client-side and server-side validation support
@@ -86,6 +87,9 @@ ayezeeCms({
86
87
 
87
88
  // Skip build if fetch fails (defaults to false)
88
89
  skipOnError?: boolean;
90
+
91
+ // Enable automatic Umami analytics injection (defaults to true)
92
+ enableAnalytics?: boolean;
89
93
  });
90
94
  ```
91
95
 
@@ -169,6 +173,28 @@ const info = getCacheInfo();
169
173
  // Returns: { fetchedAt, version, moduleCount }
170
174
  ```
171
175
 
176
+ #### Analytics
177
+
178
+ ```ts
179
+ import {
180
+ getAnalyticsConfig,
181
+ isAnalyticsEnabled,
182
+ getAnalyticsWebsiteId,
183
+ } from '@ayezee/astro-cms';
184
+
185
+ // Get full analytics configuration
186
+ const analytics = getAnalyticsConfig();
187
+ // Returns: { websiteId: string, baseUrl: string } | null
188
+
189
+ // Check if analytics is enabled
190
+ const enabled = isAnalyticsEnabled();
191
+ // Returns: boolean
192
+
193
+ // Get just the website ID
194
+ const websiteId = getAnalyticsWebsiteId();
195
+ // Returns: string | null
196
+ ```
197
+
172
198
  ## TypeScript Support
173
199
 
174
200
  The package exports all necessary types:
@@ -183,6 +209,54 @@ import type {
183
209
  } from '@ayezee/astro-cms';
184
210
  ```
185
211
 
212
+ ## Analytics Integration
213
+
214
+ The integration automatically injects Umami analytics if configured in your AyeZee Dashboard.
215
+
216
+ ### How It Works
217
+
218
+ 1. **Configure in Dashboard**: Set up Umami analytics in your project settings at `/admin/projects/{slug}/settings?tab=analytics`
219
+ 2. **Automatic Injection**: The integration fetches your analytics config and automatically injects the Umami tracking script
220
+ 3. **Zero Configuration**: No need to manually add script tags or manage website IDs
221
+
222
+ ### Analytics Configuration
223
+
224
+ Analytics is enabled by default. The script will only be injected if you've configured Umami in the dashboard.
225
+
226
+ To disable automatic analytics injection:
227
+
228
+ ```js
229
+ // astro.config.mjs
230
+ export default defineConfig({
231
+ integrations: [
232
+ ayezeeCms({
233
+ enableAnalytics: false, // Disable automatic Umami script injection
234
+ }),
235
+ ],
236
+ });
237
+ ```
238
+
239
+ ### Manual Analytics Setup
240
+
241
+ If you need more control over when/where the analytics script loads, you can disable auto-injection and add it manually:
242
+
243
+ ```astro
244
+ ---
245
+ import { getAnalyticsConfig } from '@ayezee/astro-cms';
246
+ import cmsData from '../data/cms-cache.json';
247
+
248
+ const analytics = cmsData.analytics;
249
+ ---
250
+
251
+ {analytics && (
252
+ <script
253
+ defer
254
+ src={`${analytics.baseUrl}/script.js`}
255
+ data-website-id={analytics.websiteId}
256
+ ></script>
257
+ )}
258
+ ```
259
+
186
260
  ## Advanced Usage
187
261
 
188
262
  ### Custom Cache Location
@@ -66,6 +66,10 @@ export interface CachedModule {
66
66
  createdAt: string;
67
67
  updatedAt: string;
68
68
  }
69
+ export interface AnalyticsConfig {
70
+ websiteId: string;
71
+ baseUrl: string;
72
+ }
69
73
  export interface CMSCache {
70
74
  project: {
71
75
  id: string;
@@ -74,6 +78,7 @@ export interface CMSCache {
74
78
  domain?: string;
75
79
  };
76
80
  modules: CachedModule[];
81
+ analytics?: AnalyticsConfig | null;
77
82
  fetchedAt: string;
78
83
  version: string;
79
84
  }
@@ -174,3 +179,15 @@ export declare function getCacheInfo(): {
174
179
  version: string;
175
180
  moduleCount: number;
176
181
  };
182
+ /**
183
+ * Get analytics configuration if enabled
184
+ */
185
+ export declare function getAnalyticsConfig(): AnalyticsConfig | null;
186
+ /**
187
+ * Check if analytics is enabled for this project
188
+ */
189
+ export declare function isAnalyticsEnabled(): boolean;
190
+ /**
191
+ * Get the Umami website ID if analytics is configured
192
+ */
193
+ export declare function getAnalyticsWebsiteId(): string | null;
@@ -187,4 +187,22 @@ export function getCacheInfo() {
187
187
  moduleCount: getCache().modules.length,
188
188
  };
189
189
  }
190
+ /**
191
+ * Get analytics configuration if enabled
192
+ */
193
+ export function getAnalyticsConfig() {
194
+ return getCache().analytics || null;
195
+ }
196
+ /**
197
+ * Check if analytics is enabled for this project
198
+ */
199
+ export function isAnalyticsEnabled() {
200
+ return !!getCache().analytics;
201
+ }
202
+ /**
203
+ * Get the Umami website ID if analytics is configured
204
+ */
205
+ export function getAnalyticsWebsiteId() {
206
+ return getCache().analytics?.websiteId || null;
207
+ }
190
208
  // Types are already exported above, no need to re-export
@@ -45,6 +45,26 @@ export interface AyezeeCmsOptions {
45
45
  * @default false
46
46
  */
47
47
  skipOnError?: boolean;
48
+ /**
49
+ * Enable automatic Umami analytics script injection
50
+ * @default true
51
+ */
52
+ enableAnalytics?: boolean;
53
+ /**
54
+ * Report site version to CMS dashboard for tracking
55
+ * @default true
56
+ */
57
+ reportVersion?: boolean;
58
+ /**
59
+ * Site URL for version reporting (auto-detected if not provided)
60
+ * @default process.env.SITE_URL or process.env.URL
61
+ */
62
+ siteUrl?: string;
63
+ /**
64
+ * Environment name for version reporting
65
+ * @default process.env.NODE_ENV or 'production'
66
+ */
67
+ environment?: string;
48
68
  }
49
69
  /**
50
70
  * AyeZee CMS Astro Integration
@@ -15,6 +15,8 @@
15
15
  */
16
16
  import fs from 'fs';
17
17
  import path from 'path';
18
+ // Package version - automatically updated during build
19
+ const PACKAGE_VERSION = '1.4.0';
18
20
  /**
19
21
  * Load environment variables from .env file
20
22
  */
@@ -48,15 +50,67 @@ function slugify(text) {
48
50
  .replace(/[\s_-]+/g, '-')
49
51
  .replace(/^-+|-+$/g, '');
50
52
  }
53
+ /**
54
+ * Get Astro version from package.json
55
+ */
56
+ function getAstroVersion() {
57
+ try {
58
+ const pkgPath = path.join(process.cwd(), 'node_modules', 'astro', 'package.json');
59
+ if (fs.existsSync(pkgPath)) {
60
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
61
+ return pkg.version;
62
+ }
63
+ }
64
+ catch {
65
+ // Ignore errors
66
+ }
67
+ return undefined;
68
+ }
69
+ /**
70
+ * Report site version to CMS dashboard
71
+ */
72
+ async function reportSiteVersion(baseUrl, apiKey, siteUrl, environment, astroVersion, logger) {
73
+ try {
74
+ const response = await fetch(`${baseUrl}/sites`, {
75
+ method: 'POST',
76
+ headers: {
77
+ 'Content-Type': 'application/json',
78
+ ...(apiKey && { 'Authorization': `Bearer ${apiKey}` }),
79
+ },
80
+ body: JSON.stringify({
81
+ siteUrl,
82
+ environment,
83
+ packageVersion: PACKAGE_VERSION,
84
+ astroVersion,
85
+ metadata: {
86
+ nodeVersion: process.version,
87
+ platform: process.platform,
88
+ buildTime: new Date().toISOString(),
89
+ },
90
+ }),
91
+ });
92
+ if (response.ok) {
93
+ logger.info(`📡 Reported site version to dashboard`);
94
+ }
95
+ else {
96
+ logger.warn(`⚠️ Failed to report site version: ${response.status}`);
97
+ }
98
+ }
99
+ catch (error) {
100
+ // Don't fail the build if version reporting fails
101
+ logger.warn(`⚠️ Could not report site version (non-critical)`);
102
+ }
103
+ }
51
104
  /**
52
105
  * AyeZee CMS Astro Integration
53
106
  */
54
107
  export function ayezeeCms(options = {}) {
108
+ let analyticsConfig = null;
55
109
  return {
56
110
  name: 'ayezee-cms',
57
111
  hooks: {
58
- 'astro:config:setup': async ({ config, logger }) => {
59
- logger.info('🚀 AyeZee CMS: Fetching data...');
112
+ 'astro:config:setup': async ({ config, logger, injectScript }) => {
113
+ logger.info(`🚀 AyeZee CMS v${PACKAGE_VERSION}: Fetching data...`);
60
114
  // Load environment variables from .env
61
115
  loadEnvFile();
62
116
  // Get configuration
@@ -66,21 +120,45 @@ export function ayezeeCms(options = {}) {
66
120
  const outputDir = options.outputDir || 'src/data';
67
121
  const cacheFileName = options.cacheFileName || 'cms-cache.json';
68
122
  const skipOnError = options.skipOnError || false;
69
- // Validate config
123
+ const enableAnalytics = options.enableAnalytics !== false;
124
+ const reportVersion = options.reportVersion !== false;
125
+ const siteUrl = options.siteUrl || process.env.SITE_URL || process.env.URL || process.env.VERCEL_URL;
126
+ const environment = options.environment || process.env.NODE_ENV || 'production';
127
+ // Validate config with helpful error messages
70
128
  if (!cmsDomain || !projectSlug) {
71
- const errorMsg = 'Missing environment variables:';
72
- if (!cmsDomain)
73
- logger.error(` - PUBLIC_CMS_DOMAIN`);
74
- if (!projectSlug)
75
- logger.error(` - PUBLIC_PROJECT_SLUG`);
129
+ logger.error('');
130
+ logger.error('❌ AyeZee CMS Configuration Error');
131
+ logger.error('═══════════════════════════════════════════════════════════');
132
+ logger.error('');
133
+ logger.error('Missing required environment variables:');
134
+ if (!cmsDomain) {
135
+ logger.error(' ✗ PUBLIC_CMS_DOMAIN - The URL of your CMS dashboard');
136
+ logger.error(' Example: PUBLIC_CMS_DOMAIN=https://cms.yourdomain.com');
137
+ }
138
+ if (!projectSlug) {
139
+ logger.error(' ✗ PUBLIC_PROJECT_SLUG - Your project identifier');
140
+ logger.error(' Example: PUBLIC_PROJECT_SLUG=my-project');
141
+ }
142
+ logger.error('');
143
+ logger.error('Add these to your .env file:');
144
+ logger.error('');
145
+ logger.error(' PUBLIC_CMS_DOMAIN=https://your-cms-domain.com');
146
+ logger.error(' PUBLIC_PROJECT_SLUG=your-project-slug');
147
+ logger.error(' PUBLIC_AYEZEE_API_KEY=AZ_your_api_key (optional)');
148
+ logger.error('');
149
+ logger.error('═══════════════════════════════════════════════════════════');
150
+ logger.error('');
76
151
  if (skipOnError) {
77
152
  logger.warn('⚠️ Skipping CMS data fetch due to missing config');
153
+ logger.warn(' Build will continue with cached data (if available)');
78
154
  return;
79
155
  }
80
- throw new Error(`AyeZee CMS integration requires PUBLIC_CMS_DOMAIN and PUBLIC_PROJECT_SLUG`);
156
+ throw new Error(`AyeZee CMS integration requires PUBLIC_CMS_DOMAIN and PUBLIC_PROJECT_SLUG. ` +
157
+ `See the error messages above for details.`);
81
158
  }
82
159
  logger.info(` Domain: ${cmsDomain}`);
83
160
  logger.info(` Project: ${projectSlug}`);
161
+ logger.info(` Environment: ${environment}`);
84
162
  try {
85
163
  // Build API URL
86
164
  let domain = cmsDomain;
@@ -105,6 +183,11 @@ export function ayezeeCms(options = {}) {
105
183
  }
106
184
  const modules = modulesResult.data.modules;
107
185
  logger.info(`✅ Found ${modules.length} modules`);
186
+ // Capture analytics configuration
187
+ if (modulesResult.data.analytics) {
188
+ analyticsConfig = modulesResult.data.analytics;
189
+ logger.info(`📊 Analytics configured: ${analyticsConfig.websiteId}`);
190
+ }
108
191
  // Fetch data for each module
109
192
  const modulesWithData = [];
110
193
  for (const module of modules) {
@@ -147,6 +230,7 @@ export function ayezeeCms(options = {}) {
147
230
  const cacheData = {
148
231
  project: modulesResult.data.project,
149
232
  modules: modulesWithData,
233
+ analytics: analyticsConfig,
150
234
  fetchedAt: new Date().toISOString(),
151
235
  version: '1.0',
152
236
  };
@@ -161,13 +245,63 @@ export function ayezeeCms(options = {}) {
161
245
  fs.writeFileSync(cachePath, JSON.stringify(cacheData, null, 2), 'utf-8');
162
246
  logger.info(`✅ Cached data to: ${path.relative(process.cwd(), cachePath)}`);
163
247
  logger.info(`📅 Fetched at: ${cacheData.fetchedAt}`);
248
+ // Inject Umami analytics script if configured
249
+ if (enableAnalytics && analyticsConfig) {
250
+ logger.info('📊 Injecting Umami analytics script...');
251
+ injectScript('head-inline', `
252
+ (function() {
253
+ var script = document.createElement('script');
254
+ script.defer = true;
255
+ script.src = '${analyticsConfig.baseUrl}/script.js';
256
+ script.setAttribute('data-website-id', '${analyticsConfig.websiteId}');
257
+ document.head.appendChild(script);
258
+ })();
259
+ `);
260
+ logger.info('✅ Umami analytics script injected');
261
+ }
262
+ // Report site version to dashboard (non-blocking)
263
+ if (reportVersion && siteUrl) {
264
+ const astroVersion = getAstroVersion();
265
+ reportSiteVersion(baseUrl, apiKey, siteUrl, environment, astroVersion, logger);
266
+ }
267
+ logger.info('');
268
+ logger.info('🎉 AyeZee CMS data fetched successfully!');
269
+ logger.info('');
164
270
  }
165
271
  catch (error) {
166
272
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
167
- logger.error('❌ Failed to fetch CMS data:');
168
- logger.error(` ${errorMessage}`);
273
+ logger.error('');
274
+ logger.error('❌ Failed to fetch CMS data');
275
+ logger.error('═══════════════════════════════════════════════════════════');
276
+ logger.error('');
277
+ logger.error(`Error: ${errorMessage}`);
278
+ logger.error('');
279
+ // Provide helpful troubleshooting tips
280
+ if (errorMessage.includes('ECONNREFUSED') || errorMessage.includes('fetch failed')) {
281
+ logger.error('Troubleshooting tips:');
282
+ logger.error(' 1. Is the CMS dashboard running?');
283
+ logger.error(` 2. Can you access ${cmsDomain} in your browser?`);
284
+ logger.error(' 3. Check your network connection');
285
+ logger.error(' 4. If using localhost, ensure the dashboard is started');
286
+ }
287
+ else if (errorMessage.includes('401') || errorMessage.includes('403')) {
288
+ logger.error('Troubleshooting tips:');
289
+ logger.error(' 1. Check that PUBLIC_AYEZEE_API_KEY is correct');
290
+ logger.error(' 2. Verify the API key has read permissions');
291
+ logger.error(' 3. Ensure the project slug matches your dashboard project');
292
+ }
293
+ else if (errorMessage.includes('404')) {
294
+ logger.error('Troubleshooting tips:');
295
+ logger.error(' 1. Verify PUBLIC_PROJECT_SLUG is correct');
296
+ logger.error(' 2. Check that the project exists in the dashboard');
297
+ logger.error(` 3. Project slug should match: ${projectSlug}`);
298
+ }
299
+ logger.error('');
300
+ logger.error('═══════════════════════════════════════════════════════════');
301
+ logger.error('');
169
302
  if (skipOnError) {
170
- logger.warn('⚠️ Continuing build without CMS data');
303
+ logger.warn('⚠️ Continuing build with cached data (skipOnError: true)');
304
+ logger.warn(' The site will use previously cached CMS data if available.');
171
305
  return;
172
306
  }
173
307
  throw error;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ayezee-astro-cms",
3
- "version": "1.2.2",
4
- "description": "AyeZee CMS integration for Astro with automatic data fetching, form handling, and validation",
3
+ "version": "1.4.0",
4
+ "description": "AyeZee CMS integration for Astro with automatic data fetching, form handling, validation, and analytics",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -40,7 +40,9 @@
40
40
  "ayezee",
41
41
  "integration",
42
42
  "form",
43
- "validation"
43
+ "validation",
44
+ "analytics",
45
+ "umami"
44
46
  ],
45
47
  "author": "AyeZee Web Designs",
46
48
  "license": "MIT",