fragment-headless-sdk 2.1.2 → 2.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/dist/utils/fetch-resource.d.ts +8 -7
- package/dist/utils/fetch-resource.js +71 -8
- package/package.json +1 -1
- package/readme.md +52 -3
- package/CHANGELOG.md +0 -436
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
export declare
|
|
2
|
-
HeroBanners = "hero-banners",
|
|
3
|
-
Announcements = "announcements"
|
|
4
|
-
}
|
|
1
|
+
export declare const ENABLE_REQUEST_DEDUPLICATION = true;
|
|
5
2
|
export type ListParams = {
|
|
6
3
|
status?: "enabled" | "disabled";
|
|
7
4
|
page?: number;
|
|
@@ -9,10 +6,14 @@ export type ListParams = {
|
|
|
9
6
|
search?: string;
|
|
10
7
|
pageFilter?: string;
|
|
11
8
|
};
|
|
9
|
+
export declare enum ResourceType {
|
|
10
|
+
HeroBanners = "hero-banners",
|
|
11
|
+
Announcements = "announcements"
|
|
12
|
+
}
|
|
12
13
|
export type CacheOptions = {
|
|
13
|
-
/** Request cache mode (default: '
|
|
14
|
+
/** Request cache mode (default: 'force-cache' with 60s revalidation) */
|
|
14
15
|
cache?: RequestCache;
|
|
15
|
-
/** Next.js revalidation time in seconds (default:
|
|
16
|
+
/** Next.js revalidation time in seconds (default: 60) */
|
|
16
17
|
revalidate?: number | false;
|
|
17
18
|
/** Next.js cache tags for selective invalidation */
|
|
18
19
|
tags?: string[];
|
|
@@ -23,7 +24,7 @@ type FetchResourceParams = {
|
|
|
23
24
|
type: ResourceType;
|
|
24
25
|
params?: ListParams;
|
|
25
26
|
fetchImpl?: typeof fetch;
|
|
26
|
-
/** Cache configuration (defaults to
|
|
27
|
+
/** Cache configuration (defaults to force-cache with 60s revalidation) */
|
|
27
28
|
cacheOptions?: CacheOptions;
|
|
28
29
|
};
|
|
29
30
|
/** Lists resources with optional filters (parity with client.list) */
|
|
@@ -1,8 +1,30 @@
|
|
|
1
|
+
// Simple anti-spam: prevent identical concurrent requests
|
|
2
|
+
export const ENABLE_REQUEST_DEDUPLICATION = true;
|
|
1
3
|
export var ResourceType;
|
|
2
4
|
(function (ResourceType) {
|
|
3
5
|
ResourceType["HeroBanners"] = "hero-banners";
|
|
4
6
|
ResourceType["Announcements"] = "announcements";
|
|
5
7
|
})(ResourceType || (ResourceType = {}));
|
|
8
|
+
// Simple request deduplication to prevent identical concurrent requests
|
|
9
|
+
const pendingRequests = new Map();
|
|
10
|
+
/**
|
|
11
|
+
* Generates a cache key for request deduplication
|
|
12
|
+
* Normalizes params to include default status for consistent key generation
|
|
13
|
+
*/
|
|
14
|
+
function generateRequestKey(baseUrl, type, params) {
|
|
15
|
+
// Normalize params with defaults (same as performRequest does)
|
|
16
|
+
const normalizedParams = {
|
|
17
|
+
...params,
|
|
18
|
+
status: params.status ?? "enabled", // Include default status
|
|
19
|
+
};
|
|
20
|
+
const sortedParams = Object.keys(normalizedParams)
|
|
21
|
+
.sort()
|
|
22
|
+
.reduce((acc, key) => {
|
|
23
|
+
acc[key] = normalizedParams[key];
|
|
24
|
+
return acc;
|
|
25
|
+
}, {});
|
|
26
|
+
return `${baseUrl}:${type}:${JSON.stringify(sortedParams)}`;
|
|
27
|
+
}
|
|
6
28
|
/**
|
|
7
29
|
* Detects if running in Next.js environment
|
|
8
30
|
*/
|
|
@@ -20,10 +42,10 @@ function getDefaultCacheConfig(type) {
|
|
|
20
42
|
const isNextJS = isNextJSEnvironment();
|
|
21
43
|
const isDev = process?.env?.NODE_ENV === "development";
|
|
22
44
|
if (isNextJS && !isDev) {
|
|
23
|
-
// In Next.js production, default to
|
|
45
|
+
// In Next.js production, default to caching with 60 second revalidation
|
|
24
46
|
return {
|
|
25
|
-
cache: "
|
|
26
|
-
revalidate:
|
|
47
|
+
cache: "force-cache",
|
|
48
|
+
revalidate: 60,
|
|
27
49
|
tags: [`fragment-${type}`],
|
|
28
50
|
};
|
|
29
51
|
}
|
|
@@ -38,6 +60,50 @@ export async function fetchResource({ baseUrl, apiKey, type, params = {}, fetchI
|
|
|
38
60
|
console.warn("❌ Missing EXTERNAL_API_URL or FRAGMENT_API_KEY");
|
|
39
61
|
return [];
|
|
40
62
|
}
|
|
63
|
+
// Generate key for request deduplication
|
|
64
|
+
const requestKey = generateRequestKey(baseUrl, type, params);
|
|
65
|
+
// Request deduplication - check if identical request is already in flight
|
|
66
|
+
if (ENABLE_REQUEST_DEDUPLICATION) {
|
|
67
|
+
const existingRequest = pendingRequests.get(requestKey);
|
|
68
|
+
if (existingRequest) {
|
|
69
|
+
console.log(`🔄 Deduplicating request for ${type}`);
|
|
70
|
+
try {
|
|
71
|
+
return await existingRequest;
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
// If the existing request failed, we'll try again below
|
|
75
|
+
pendingRequests.delete(requestKey);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Create the actual request promise
|
|
80
|
+
const requestPromise = performRequest({
|
|
81
|
+
baseUrl,
|
|
82
|
+
apiKey,
|
|
83
|
+
type,
|
|
84
|
+
params,
|
|
85
|
+
fetchImpl,
|
|
86
|
+
cacheOptions,
|
|
87
|
+
});
|
|
88
|
+
// Store the promise for deduplication
|
|
89
|
+
if (ENABLE_REQUEST_DEDUPLICATION) {
|
|
90
|
+
pendingRequests.set(requestKey, requestPromise);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const result = await requestPromise;
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
// Clean up the pending request
|
|
98
|
+
if (ENABLE_REQUEST_DEDUPLICATION) {
|
|
99
|
+
pendingRequests.delete(requestKey);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Performs the actual HTTP request (separated for cleaner code organization)
|
|
105
|
+
*/
|
|
106
|
+
async function performRequest({ baseUrl, apiKey, type, params = {}, fetchImpl, cacheOptions, }) {
|
|
41
107
|
try {
|
|
42
108
|
const f = fetchImpl ?? fetch;
|
|
43
109
|
const base = baseUrl.replace(/\/+$/, "");
|
|
@@ -47,8 +113,8 @@ export async function fetchResource({ baseUrl, apiKey, type, params = {}, fetchI
|
|
|
47
113
|
const limit = Math.min(100, Math.max(1, params.limit ?? 25));
|
|
48
114
|
url.searchParams.set("pageNum", String(page));
|
|
49
115
|
url.searchParams.set("limit", String(limit));
|
|
50
|
-
if
|
|
51
|
-
|
|
116
|
+
// Default to "enabled" status if not specified
|
|
117
|
+
url.searchParams.set("status", params.status ?? "enabled");
|
|
52
118
|
if (params.pageFilter)
|
|
53
119
|
url.searchParams.set("page", params.pageFilter);
|
|
54
120
|
if (params.search)
|
|
@@ -64,9 +130,6 @@ export async function fetchResource({ baseUrl, apiKey, type, params = {}, fetchI
|
|
|
64
130
|
headers: {
|
|
65
131
|
Authorization: `Bearer ${apiKey}`,
|
|
66
132
|
"Content-Type": "application/json",
|
|
67
|
-
// Add cache-busting headers for better cache control
|
|
68
|
-
"Cache-Control": "no-cache, no-store, must-revalidate",
|
|
69
|
-
Pragma: "no-cache",
|
|
70
133
|
},
|
|
71
134
|
cache: finalCacheOptions.cache,
|
|
72
135
|
};
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
The official SDK for integrating with Fragment-Shopify CMS. Provides React components, TypeScript types, and utilities for rendering published sections in headless Shopify storefronts.
|
|
4
4
|
|
|
5
|
-
## ✨ What's New in v2.1.
|
|
5
|
+
## ✨ What's New in v2.1.3
|
|
6
|
+
|
|
7
|
+
⚡ **Request Deduplication** - Intelligent request deduplication prevents identical concurrent API calls
|
|
8
|
+
🚀 **Enhanced Caching** - Improved caching strategy with 60-second revalidation for better performance
|
|
9
|
+
🔧 **Optimized Fetching** - Consistent parameter handling and smarter cache key generation
|
|
10
|
+
🛡️ **Anti-Spam Protection** - Built-in protection against redundant API requests
|
|
11
|
+
|
|
12
|
+
### Previous Release (v2.1.2)
|
|
6
13
|
|
|
7
14
|
📚 **Enhanced Documentation** - Comprehensive documentation updates highlighting new click tracking features
|
|
8
15
|
📖 **Better Examples** - Improved usage examples and feature descriptions
|
|
@@ -76,6 +83,15 @@ Fragment-Shopify App (CMS) → API Endpoint → fragment-headless-sdk (Consumer)
|
|
|
76
83
|
- 📝 **Type Safety**: Enhanced TypeScript interfaces for all styling options
|
|
77
84
|
- 🔄 **Backward Compatible**: Works seamlessly with existing Hero implementations
|
|
78
85
|
|
|
86
|
+
### Request Deduplication & Performance System (v2.1.3+)
|
|
87
|
+
|
|
88
|
+
- ⚡ **Smart Deduplication**: Prevents identical concurrent API requests automatically
|
|
89
|
+
- 🚀 **Optimized Caching**: 60-second cache revalidation for optimal performance vs freshness
|
|
90
|
+
- 🔧 **Consistent Parameters**: Normalized parameter handling ensures reliable cache keys
|
|
91
|
+
- 🛡️ **Anti-Spam Protection**: Built-in protection against redundant API calls
|
|
92
|
+
- 📊 **Performance Monitoring**: Console logging for deduplication events and debugging
|
|
93
|
+
- 🔄 **Graceful Fallback**: Failed requests retry automatically without affecting user experience
|
|
94
|
+
|
|
79
95
|
### Enhanced Click Tracking System (v2.1.1+)
|
|
80
96
|
|
|
81
97
|
- 🎯 **Separated Concerns**: Button destinations and click tracking handled independently
|
|
@@ -183,11 +199,20 @@ const heroBanners = await fetchResource({
|
|
|
183
199
|
type: ResourceType.HeroBanners,
|
|
184
200
|
});
|
|
185
201
|
|
|
186
|
-
// Fetch announcements
|
|
202
|
+
// Fetch announcements with optional parameters
|
|
187
203
|
const announcements = await fetchResource({
|
|
188
204
|
baseUrl: process.env.EXTERNAL_API_URL,
|
|
189
205
|
apiKey: process.env.FRAGMENT_API_KEY,
|
|
190
206
|
type: ResourceType.Announcements,
|
|
207
|
+
params: {
|
|
208
|
+
status: "enabled", // Only fetch enabled announcements
|
|
209
|
+
limit: 10, // Limit to 10 items
|
|
210
|
+
search: "sale", // Search for announcements containing "sale"
|
|
211
|
+
},
|
|
212
|
+
cacheOptions: {
|
|
213
|
+
revalidate: 30, // Custom 30-second cache revalidation
|
|
214
|
+
tags: ["announcements"], // Custom cache tags
|
|
215
|
+
},
|
|
191
216
|
});
|
|
192
217
|
```
|
|
193
218
|
|
|
@@ -650,13 +675,30 @@ const advancedHeroContent = {
|
|
|
650
675
|
|
|
651
676
|
### `fetchResource<T>(params)`
|
|
652
677
|
|
|
653
|
-
Fetches sections from your Fragment-Shopify app.
|
|
678
|
+
Fetches sections from your Fragment-Shopify app with intelligent request deduplication and caching.
|
|
654
679
|
|
|
655
680
|
**Parameters:**
|
|
656
681
|
|
|
657
682
|
- `baseUrl: string` - URL of your Fragment-Shopify app
|
|
658
683
|
- `apiKey: string` - Fragment API key (format: `keyId:secret`)
|
|
659
684
|
- `type: ResourceType` - Type of resource to fetch
|
|
685
|
+
- `params?: ListParams` - Optional filtering and pagination parameters
|
|
686
|
+
- `fetchImpl?: typeof fetch` - Optional custom fetch implementation
|
|
687
|
+
- `cacheOptions?: CacheOptions` - Optional cache configuration
|
|
688
|
+
|
|
689
|
+
**ListParams Options:**
|
|
690
|
+
|
|
691
|
+
- `status?: "enabled" | "disabled"` - Filter by status (defaults to "enabled")
|
|
692
|
+
- `page?: number` - Page number for pagination (defaults to 1)
|
|
693
|
+
- `limit?: number` - Items per page (defaults to 25, max 100)
|
|
694
|
+
- `search?: string` - Search query for filtering
|
|
695
|
+
- `pageFilter?: string` - Filter by page path (e.g., "/collections/sale")
|
|
696
|
+
|
|
697
|
+
**CacheOptions:**
|
|
698
|
+
|
|
699
|
+
- `cache?: RequestCache` - Request cache mode (defaults to "force-cache")
|
|
700
|
+
- `revalidate?: number | false` - Next.js revalidation time in seconds (defaults to 60)
|
|
701
|
+
- `tags?: string[]` - Next.js cache tags for selective invalidation
|
|
660
702
|
|
|
661
703
|
**ResourceType Options:**
|
|
662
704
|
|
|
@@ -665,6 +707,13 @@ Fetches sections from your Fragment-Shopify app.
|
|
|
665
707
|
|
|
666
708
|
**Returns:** `Promise<T[]>` - Array of fetched resources
|
|
667
709
|
|
|
710
|
+
**Performance Features:**
|
|
711
|
+
|
|
712
|
+
- **Request Deduplication**: Identical concurrent requests are automatically deduplicated
|
|
713
|
+
- **Smart Caching**: 60-second cache revalidation balances performance and freshness
|
|
714
|
+
- **Parameter Normalization**: Consistent cache key generation for reliable deduplication
|
|
715
|
+
- **Error Handling**: Graceful fallbacks with automatic retry on failed requests
|
|
716
|
+
|
|
668
717
|
---
|
|
669
718
|
|
|
670
719
|
## 🧩 Components
|
package/CHANGELOG.md
DELETED
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [2.1.2] - 2025-10-30
|
|
9
|
-
|
|
10
|
-
### 📚 Documentation Updates
|
|
11
|
-
|
|
12
|
-
- **Enhanced README** – Updated documentation to highlight new click tracking features
|
|
13
|
-
- **Feature Highlights** – Added comprehensive documentation for the enhanced click tracking system
|
|
14
|
-
- **Usage Examples** – Improved examples showing the separation of button destinations and tracking
|
|
15
|
-
|
|
16
|
-
## [2.1.1] - 2025-10-30
|
|
17
|
-
|
|
18
|
-
### 🎯 Enhanced Click Tracking System
|
|
19
|
-
|
|
20
|
-
- **Improved Click Tracking Architecture** – Separated button destinations from click tracking for better user experience
|
|
21
|
-
- `buttonHref` now contains the actual destination URL (no redirect)
|
|
22
|
-
- `clickHref` contains the tracking URL for metrics collection
|
|
23
|
-
- Users go directly to intended destinations instead of through redirects
|
|
24
|
-
- **New `fireClickMetric()` Function** – Advanced click tracking without relying on redirects
|
|
25
|
-
- Uses `fetch()` with `no-cors` mode and `keepalive` for reliable tracking
|
|
26
|
-
- Falls back to Image pixel tracking for maximum compatibility
|
|
27
|
-
- Handles server-side rendering gracefully
|
|
28
|
-
- **Removed Automatic New Tab Behavior** – Links no longer force `target="_blank"`
|
|
29
|
-
- Provides more natural user experience
|
|
30
|
-
- Allows developers to control link behavior explicitly
|
|
31
|
-
- Maintains accessibility with proper ARIA labels
|
|
32
|
-
|
|
33
|
-
### 🛠 Technical Improvements
|
|
34
|
-
|
|
35
|
-
- **Enhanced Component Props** – Both Hero and Announcement components now accept separate tracking parameters
|
|
36
|
-
- `buttonHref` for the actual destination
|
|
37
|
-
- `clickHref` for tracking metrics
|
|
38
|
-
- **Better Error Handling** – Click tracking fails gracefully without affecting user experience
|
|
39
|
-
- **Performance Optimized** – Non-blocking click tracking that doesn't delay navigation
|
|
40
|
-
- **Cross-Browser Compatible** – Works across all modern browsers with appropriate fallbacks
|
|
41
|
-
|
|
42
|
-
### 📝 Usage Examples
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
// The SDK automatically handles the separation of concerns
|
|
46
|
-
const heroContent = {
|
|
47
|
-
title: "Shop Now",
|
|
48
|
-
buttonText: "Get Started",
|
|
49
|
-
buttonLink: "https://example.com/products", // Direct destination
|
|
50
|
-
clickUrlBase: "https://tracking.example.com/click", // Tracking base
|
|
51
|
-
// SDK automatically creates:
|
|
52
|
-
// - buttonHref: "https://example.com/products" (direct link)
|
|
53
|
-
// - clickHref: "https://tracking.example.com/click?u=..." (tracking)
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
<Hero content={heroContent} />;
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### ⚡ Performance Benefits
|
|
60
|
-
|
|
61
|
-
- **Faster Navigation** – Users go directly to destinations without redirect delays
|
|
62
|
-
- **Reliable Tracking** – Click metrics are captured even if users navigate away quickly
|
|
63
|
-
- **Better SEO** – Direct links improve search engine crawling and indexing
|
|
64
|
-
- **Enhanced UX** – More predictable link behavior for better user experience
|
|
65
|
-
|
|
66
|
-
### 🔄 Backward Compatibility
|
|
67
|
-
|
|
68
|
-
- **No Breaking Changes** – All existing implementations continue to work
|
|
69
|
-
- **Automatic Upgrade** – New tracking system activates automatically when `clickUrlBase` is present
|
|
70
|
-
- **Legacy Support** – Existing tracking URLs continue to function as before
|
|
71
|
-
|
|
72
|
-
## [2.1.0] - 2025-10-27
|
|
73
|
-
|
|
74
|
-
### 🎨 Enhanced Hero Styling System
|
|
75
|
-
|
|
76
|
-
- **New Hero Resolvers Utility** – Comprehensive utility system for advanced Hero component customization
|
|
77
|
-
- `resolveHeroColors()` – Intelligent color resolution with fallback handling
|
|
78
|
-
- `resolveHeroTypography()` – Typography settings with font family, size, and line height control
|
|
79
|
-
- `resolveContentWidthClass()` – Dynamic content width management
|
|
80
|
-
- `resolvePosition()` – Content positioning (left, center, right alignment)
|
|
81
|
-
- `resolveHeight()` – Flexible height configuration
|
|
82
|
-
- `renderText()` – Unified text rendering with typography and styling support
|
|
83
|
-
|
|
84
|
-
### ✨ Advanced Typography Features
|
|
85
|
-
|
|
86
|
-
- **Font Family Support** – Built-in support for popular font families:
|
|
87
|
-
- Roboto, Open Sans, Lato, Montserrat, Poppins, Inter, Nunito Sans, Source Sans Pro
|
|
88
|
-
- Custom font family support through `FontKey` type system
|
|
89
|
-
- **Responsive Typography** – Granular control over font sizes and line heights
|
|
90
|
-
- Separate title and description typography settings
|
|
91
|
-
- Tailwind CSS class integration for responsive design
|
|
92
|
-
- **Typography Tokens** – New styling tokens for enhanced typography control:
|
|
93
|
-
- `titleFontSize`, `titleLineHeight`, `titleFont`
|
|
94
|
-
- `descriptionFontSize`, `descriptionLineHeight`, `descriptionFont`
|
|
95
|
-
|
|
96
|
-
### 🏗️ Layout & Positioning Enhancements
|
|
97
|
-
|
|
98
|
-
- **Content Positioning** – New positioning system for Hero content alignment
|
|
99
|
-
- Left, center, and right alignment options
|
|
100
|
-
- Responsive positioning with proper text alignment
|
|
101
|
-
- **Content Width Control** – Dynamic content width management
|
|
102
|
-
- Configurable content container widths
|
|
103
|
-
- Responsive design integration
|
|
104
|
-
- **Height Management** – Flexible height configuration system
|
|
105
|
-
- Custom height classes support
|
|
106
|
-
- Default height fallbacks
|
|
107
|
-
|
|
108
|
-
### 🎯 Developer Experience Improvements
|
|
109
|
-
|
|
110
|
-
- **Type Safety** – Enhanced TypeScript interfaces for all new features
|
|
111
|
-
- `HeroResolvedColors` interface for color resolution
|
|
112
|
-
- `HeroTypographySettings` interface for typography configuration
|
|
113
|
-
- `FontKey` type for font family validation
|
|
114
|
-
- **Utility Functions** – New helper functions for common operations
|
|
115
|
-
- `joinClassNames()` – Safe CSS class concatenation
|
|
116
|
-
- `fallbackColor()` – Color value validation with fallbacks
|
|
117
|
-
- **Better Defaults** – Comprehensive default values for all styling options
|
|
118
|
-
- `DEFAULT_COLORS` for color fallbacks
|
|
119
|
-
- `DEFAULT_TYPOGRAPHY` for typography defaults
|
|
120
|
-
- `FONT_FAMILY_MAP` for font family mappings
|
|
121
|
-
|
|
122
|
-
### 🔄 Backward Compatibility
|
|
123
|
-
|
|
124
|
-
- **Seamless Migration** – All existing Hero components continue to work without changes
|
|
125
|
-
- **Progressive Enhancement** – New features are opt-in and don't affect existing implementations
|
|
126
|
-
- **Legacy Support** – Existing styling approaches remain fully supported
|
|
127
|
-
|
|
128
|
-
### 📝 Usage Examples
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
// Enhanced Hero with new typography and positioning
|
|
132
|
-
const heroContent = {
|
|
133
|
-
title: "Welcome to Our Store",
|
|
134
|
-
description: "Discover amazing products",
|
|
135
|
-
buttonText: "Shop Now",
|
|
136
|
-
buttonLink: "/products",
|
|
137
|
-
imageUrl: "https://example.com/hero.jpg",
|
|
138
|
-
|
|
139
|
-
styling: {
|
|
140
|
-
tokens: {
|
|
141
|
-
colors: {
|
|
142
|
-
title: "#ffffff",
|
|
143
|
-
text: "#f0f0f0",
|
|
144
|
-
button: "#007bff",
|
|
145
|
-
buttonText: "#ffffff",
|
|
146
|
-
background: "#1a1a1a",
|
|
147
|
-
},
|
|
148
|
-
typography: {
|
|
149
|
-
titleFont: "montserrat",
|
|
150
|
-
titleFontSize: "text-6xl",
|
|
151
|
-
titleLineHeight: "leading-tight",
|
|
152
|
-
descriptionFont: "inter",
|
|
153
|
-
descriptionFontSize: "text-xl",
|
|
154
|
-
descriptionLineHeight: "leading-relaxed",
|
|
155
|
-
},
|
|
156
|
-
layout: {
|
|
157
|
-
contentWidth: "max-w-4xl",
|
|
158
|
-
position: "center",
|
|
159
|
-
height: "min-h-screen",
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
};
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### 🛠 Technical Improvements
|
|
167
|
-
|
|
168
|
-
- **Performance Optimized** – Efficient color and typography resolution
|
|
169
|
-
- **Memory Efficient** – Optimized utility functions with minimal overhead
|
|
170
|
-
- **Tree Shakeable** – Individual utility functions can be imported separately
|
|
171
|
-
- **CSS-in-JS Ready** – Full compatibility with styled-components and emotion
|
|
172
|
-
|
|
173
|
-
## [1.0.6] - 2025-10-16
|
|
174
|
-
|
|
175
|
-
### 🚀 Next.js Caching Fix
|
|
176
|
-
|
|
177
|
-
- **Fixed Vercel/Next.js Caching Issues** – Resolved aggressive caching that prevented fresh data from appearing in production deployments
|
|
178
|
-
- Added `cache: 'no-store'` by default for all `fetchResource()` calls
|
|
179
|
-
- Added Next.js-specific `revalidate: 0` configuration
|
|
180
|
-
- Added cache-busting headers (`Cache-Control`, `Pragma`) to prevent CDN caching
|
|
181
|
-
- Smart environment detection for Next.js vs other frameworks
|
|
182
|
-
|
|
183
|
-
### ✨ New Cache Management Features
|
|
184
|
-
|
|
185
|
-
- **Cache Configuration Options** – Added optional `cacheOptions` parameter to `fetchResource()`
|
|
186
|
-
- `cache`: Control request cache mode (default: 'no-store' for fresh data)
|
|
187
|
-
- `revalidate`: Next.js revalidation time in seconds (default: 0)
|
|
188
|
-
- `tags`: Next.js cache tags for selective invalidation
|
|
189
|
-
- **Cache Invalidation Utilities** – New helper functions for cache management
|
|
190
|
-
- `revalidateFragmentCache()` – Invalidate all or specific Fragment caches
|
|
191
|
-
- `revalidateResourceType()` – Invalidate cache for specific resource type
|
|
192
|
-
- `revalidateAllFragmentCaches()` – Clear all Fragment-related caches
|
|
193
|
-
- `createCacheTag()` / `createCacheTags()` – Generate cache tags
|
|
194
|
-
|
|
195
|
-
### 🛠 Technical Improvements
|
|
196
|
-
|
|
197
|
-
- **Environment Detection** – Automatic Next.js environment detection for optimal cache settings
|
|
198
|
-
- **Backward Compatibility** – All existing code continues to work without changes
|
|
199
|
-
- **TypeScript Support** – Full type definitions for new cache options
|
|
200
|
-
|
|
201
|
-
### 📝 Usage Examples
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
// Default behavior - always fresh data (recommended)
|
|
205
|
-
const announcements = await fetchResource({
|
|
206
|
-
baseUrl: process.env.FRAGMENT_BASE_URL,
|
|
207
|
-
apiKey: process.env.FRAGMENT_API_KEY,
|
|
208
|
-
type: ResourceType.Announcements,
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
// Optional: Enable caching for performance
|
|
212
|
-
const cachedHeroes = await fetchResource({
|
|
213
|
-
baseUrl: process.env.FRAGMENT_BASE_URL,
|
|
214
|
-
apiKey: process.env.FRAGMENT_API_KEY,
|
|
215
|
-
type: ResourceType.HeroBanners,
|
|
216
|
-
cacheOptions: {
|
|
217
|
-
cache: "default",
|
|
218
|
-
revalidate: 300, // 5 minutes
|
|
219
|
-
},
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
// Cache invalidation (server-side only)
|
|
223
|
-
import { revalidateResourceType } from "fragment-headless-sdk";
|
|
224
|
-
await revalidateResourceType(ResourceType.Announcements);
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### ⚠️ Migration Notes
|
|
228
|
-
|
|
229
|
-
- **No breaking changes** – Existing code works without modification
|
|
230
|
-
- **Fresh data by default** – Your database updates will now appear immediately in production
|
|
231
|
-
- **Opt-in caching** – Use `cacheOptions` if you want to enable caching for performance
|
|
232
|
-
|
|
233
|
-
## [1.0.5] - 2025-09-28
|
|
234
|
-
|
|
235
|
-
### ✨ New Features
|
|
236
|
-
|
|
237
|
-
- **Metrics Tracking** – Added built-in view and click tracking for both **Hero** and **Announcement** sections.
|
|
238
|
-
- Each resource’s `content` object now includes two server-generated fields:
|
|
239
|
-
- `impressionUrl` – 1×1 pixel URL automatically fired when the component enters the viewport.
|
|
240
|
-
- `clickUrlBase` – base redirect URL used to record button clicks before sending the user to the final destination.
|
|
241
|
-
- The SDK’s `<Hero>` and `<Announcement>` components now automatically:
|
|
242
|
-
- trigger a view pixel when visible, and
|
|
243
|
-
- wrap their CTA buttons with a signed click-tracking redirect.
|
|
244
|
-
|
|
245
|
-
### 🛠 Technical Notes
|
|
246
|
-
|
|
247
|
-
- The `makeSignedMetricUrls` helper was refactored to attach `impressionUrl` and `clickUrlBase` **inside the `content` object** for each item returned by the API.
|
|
248
|
-
- New client-side utilities exported from `utils`:
|
|
249
|
-
- `buildClickUrl()` – safely appends the final destination (`&u=...`) to a signed `clickUrlBase`.
|
|
250
|
-
- `fireImpressionWhenVisible()` – fires a pixel only once when an element is at least 30 % visible.
|
|
251
|
-
|
|
252
|
-
### ⚠️ Migration Notes
|
|
253
|
-
|
|
254
|
-
- **No breaking changes.**
|
|
255
|
-
Existing components continue to work; the new tracking is automatic when you upgrade to v1.0.5.
|
|
256
|
-
- If you build custom CTAs outside the provided components, use the new helpers to track clicks and views manually.
|
|
257
|
-
|
|
258
|
-
## [1.0.4] - 2025-09-27
|
|
259
|
-
|
|
260
|
-
- **Types:** `IHero` now includes `views_count: number` and `clicks_count: number`.
|
|
261
|
-
|
|
262
|
-
### 📝 Notes
|
|
263
|
-
|
|
264
|
-
- No breaking changes..
|
|
265
|
-
|
|
266
|
-
## [1.0.3] - 2025-09-21
|
|
267
|
-
|
|
268
|
-
### 🎨 UI/UX Improvements
|
|
269
|
-
|
|
270
|
-
- **Announcement Type Rename** - Changed `AnnouncementType.Announcement` to `AnnouncementType.Static` for better clarity
|
|
271
|
-
- **Countdown Timer Styling** - Removed white background from countdown timer for cleaner appearance
|
|
272
|
-
- **Layout Optimization** - Improved announcement banner layout with:
|
|
273
|
-
- Removed top/bottom padding (`py-3`) for more compact design
|
|
274
|
-
- Added 50px minimum height for consistent banner sizing
|
|
275
|
-
- Enhanced vertical centering of all content elements
|
|
276
|
-
- **Timer Digit Sizing** - Made countdown timer digits smaller and more compact:
|
|
277
|
-
- Reduced digit size from 24×28px to 20×24px
|
|
278
|
-
- Changed font size from `text-xl` to `text-base`
|
|
279
|
-
|
|
280
|
-
### 🔧 Technical Changes
|
|
281
|
-
|
|
282
|
-
- Updated `announcementTypes` array to reflect new "Static" label
|
|
283
|
-
- Improved flexbox layout for better vertical alignment
|
|
284
|
-
- Maintained responsive design across all screen sizes
|
|
285
|
-
|
|
286
|
-
## [1.0.2] - 2025-09-20
|
|
287
|
-
|
|
288
|
-
### 🔄 Breaking Changes
|
|
289
|
-
|
|
290
|
-
- **Component Naming** - Renamed `Banner` component and all related types to `Announcement`
|
|
291
|
-
|
|
292
|
-
- `Banner` → `Announcement`
|
|
293
|
-
- `IBannerContent` → `IAnnouncementContent`
|
|
294
|
-
- `IBanner` → `IAnnouncement`
|
|
295
|
-
- `BannerType` → `AnnouncementType`
|
|
296
|
-
- `BannerStatus` → `AnnouncementStatus`
|
|
297
|
-
- `BannerButton` → `AnnouncementButton`
|
|
298
|
-
- `BannerStyles` → `AnnouncementStyles`
|
|
299
|
-
- `bannerHtml` property → `announcementHtml`
|
|
300
|
-
|
|
301
|
-
- **Resource Type Updates** - Updated resource type enums for consistency
|
|
302
|
-
- `ResourceType.HeroSections` → `ResourceType.HeroBanners`
|
|
303
|
-
- `ResourceType.Banners` → `ResourceType.Announcements`
|
|
304
|
-
|
|
305
|
-
### 🔗 API Endpoint Changes
|
|
306
|
-
|
|
307
|
-
- Updated API endpoints to match new naming:
|
|
308
|
-
- `/api/v1/hero-sections` → `/api/v1/hero-banners`
|
|
309
|
-
- `/api/v1/banners` → `/api/v1/announcements`
|
|
310
|
-
|
|
311
|
-
### 📚 Documentation
|
|
312
|
-
|
|
313
|
-
- Updated all documentation to reflect new component and type names
|
|
314
|
-
- Updated README.md examples with new ResourceType values
|
|
315
|
-
- Updated code examples throughout
|
|
316
|
-
|
|
317
|
-
### 🛠️ Migration Guide
|
|
318
|
-
|
|
319
|
-
To update your existing code:
|
|
320
|
-
|
|
321
|
-
```typescript
|
|
322
|
-
// Before (v1.0.1)
|
|
323
|
-
import {
|
|
324
|
-
Banner,
|
|
325
|
-
BannerType,
|
|
326
|
-
IBannerContent,
|
|
327
|
-
ResourceType,
|
|
328
|
-
} from "fragment-headless-sdk";
|
|
329
|
-
|
|
330
|
-
const banners = await fetchResource({
|
|
331
|
-
type: ResourceType.Banners,
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
<Banner content={bannerContent} type={BannerType.Standard} />;
|
|
335
|
-
|
|
336
|
-
// After (v1.0.2)
|
|
337
|
-
import {
|
|
338
|
-
Announcement,
|
|
339
|
-
AnnouncementType,
|
|
340
|
-
IAnnouncementContent,
|
|
341
|
-
ResourceType,
|
|
342
|
-
} from "fragment-headless-sdk";
|
|
343
|
-
|
|
344
|
-
const announcements = await fetchResource({
|
|
345
|
-
type: ResourceType.Announcements,
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
<Announcement
|
|
349
|
-
content={announcementContent}
|
|
350
|
-
type={AnnouncementType.Announcement}
|
|
351
|
-
/>;
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
## [1.0.1] - 2025-09-07
|
|
355
|
-
|
|
356
|
-
### 🎉 Initial Release
|
|
357
|
-
|
|
358
|
-
The official SDK for integrating with fragment-shopify CMS. Production-ready with full API key authentication support.
|
|
359
|
-
|
|
360
|
-
### Features
|
|
361
|
-
|
|
362
|
-
- **Complete TypeScript Support** - Full type definitions for all components and API responses
|
|
363
|
-
- **React Components** - Pre-built Hero and Announcement components with responsive design
|
|
364
|
-
- **API Integration** - Built-in utilities for fetching sections from fragment-shopify app
|
|
365
|
-
- **Production Ready** - Full API key authentication with v1 endpoints
|
|
366
|
-
- **Tailwind CSS** - Styled components with customizable design system
|
|
367
|
-
|
|
368
|
-
### Components
|
|
369
|
-
|
|
370
|
-
- **Hero Component** - Responsive hero sections with desktop/mobile variants
|
|
371
|
-
- Support for images, videos, and call-to-action buttons
|
|
372
|
-
- Customizable content and styling
|
|
373
|
-
- **Announcement Component** - Flexible announcement bars with multiple display types
|
|
374
|
-
- Standard, marquee, and countdown announcement variants
|
|
375
|
-
- `AnnouncementButton` and `CountdownTimer` sub-components
|
|
376
|
-
|
|
377
|
-
### API Integration
|
|
378
|
-
|
|
379
|
-
- **`fetchResource()` Function** - Simple API for fetching sections
|
|
380
|
-
- **API Key Authentication** - Secure authentication using `keyId:secret` format
|
|
381
|
-
- **v1 Endpoints** - Production endpoints (`/api/v1/announcements`, `/api/v1/hero-banners`)
|
|
382
|
-
- **Error Handling** - Comprehensive error handling and logging
|
|
383
|
-
- **Type Safety** - Full TypeScript support for all API responses
|
|
384
|
-
|
|
385
|
-
### Usage
|
|
386
|
-
|
|
387
|
-
```tsx
|
|
388
|
-
import {
|
|
389
|
-
fetchResource,
|
|
390
|
-
ResourceType,
|
|
391
|
-
Hero,
|
|
392
|
-
Announcement,
|
|
393
|
-
} from "fragment-headless-sdk";
|
|
394
|
-
|
|
395
|
-
// Fetch data
|
|
396
|
-
const heroes = await fetchResource({
|
|
397
|
-
baseUrl: process.env.EXTERNAL_API_URL,
|
|
398
|
-
apiKey: process.env.FRAGMENT_API_KEY,
|
|
399
|
-
type: ResourceType.HeroBanners,
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
// Render components
|
|
403
|
-
<Hero content={heroes[0]?.content} />;
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
### Environment Variables
|
|
407
|
-
|
|
408
|
-
```bash
|
|
409
|
-
EXTERNAL_API_URL=https://your-fragment-app.vercel.app
|
|
410
|
-
FRAGMENT_API_KEY=bh_a1b2c3d4e5f6:your-64-char-secret
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
---
|
|
414
|
-
|
|
415
|
-
## Upcoming Changes
|
|
416
|
-
|
|
417
|
-
### v1.1.0 (Planned)
|
|
418
|
-
|
|
419
|
-
- Enhanced error handling with specific error types
|
|
420
|
-
- Support for additional section types
|
|
421
|
-
- Caching and performance optimizations
|
|
422
|
-
|
|
423
|
-
### v1.2.0 (Planned)
|
|
424
|
-
|
|
425
|
-
- Real-time updates via webhooks
|
|
426
|
-
- Advanced filtering and sorting options
|
|
427
|
-
- Batch operations support
|
|
428
|
-
- TypeScript strict mode compatibility
|
|
429
|
-
|
|
430
|
-
---
|
|
431
|
-
|
|
432
|
-
## Support
|
|
433
|
-
|
|
434
|
-
- **Documentation**: [README.md](./README.md)
|
|
435
|
-
- **NPM Package**: https://www.npmjs.com/package/fragment-shopify-sdk
|
|
436
|
-
- **Issues**: Please report issues in the GitHub repository
|