perspectapi-ts-sdk 1.4.0 → 1.5.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 +45 -0
- package/dist/index.d.mts +140 -1
- package/dist/index.d.ts +140 -1
- package/dist/index.js +137 -0
- package/dist/index.mjs +130 -0
- package/package.json +1 -1
- package/src/index.ts +16 -0
- package/src/utils/image-transform.ts +296 -0
package/README.md
CHANGED
|
@@ -84,6 +84,51 @@ const checkout = await createCheckoutSession({
|
|
|
84
84
|
> 📚 See [docs/loaders.md](docs/loaders.md) for full walkthroughs, including fallback data, custom logging, and Stripe price resolution.
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
## Image Transformations
|
|
88
|
+
|
|
89
|
+
The SDK includes utilities for transforming images using Cloudflare's Image Resizing service:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { transformMediaItem, buildImageUrl } from 'perspectapi-ts-sdk';
|
|
93
|
+
|
|
94
|
+
// Get a product with media
|
|
95
|
+
const product = await client.products.getProduct('mysite', 123);
|
|
96
|
+
const media = product.data.media?.[0];
|
|
97
|
+
|
|
98
|
+
if (media) {
|
|
99
|
+
// Generate all responsive sizes automatically
|
|
100
|
+
const urls = transformMediaItem('https://api.perspect.co', media);
|
|
101
|
+
|
|
102
|
+
console.log(urls.thumbnail); // 150x150 cover crop
|
|
103
|
+
console.log(urls.small); // 400px wide
|
|
104
|
+
console.log(urls.medium); // 800px wide
|
|
105
|
+
console.log(urls.large); // 1200px wide
|
|
106
|
+
console.log(urls.original); // Original with auto format
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Or build custom transformations
|
|
110
|
+
const customUrl = buildImageUrl(
|
|
111
|
+
'https://api.perspect.co',
|
|
112
|
+
'media/mysite/photo.jpg',
|
|
113
|
+
{
|
|
114
|
+
width: 400,
|
|
115
|
+
height: 300,
|
|
116
|
+
fit: 'cover',
|
|
117
|
+
format: 'webp',
|
|
118
|
+
quality: 85
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Features:**
|
|
124
|
+
- ✅ On-the-fly image resizing (no pre-generated thumbnails)
|
|
125
|
+
- ✅ Automatic format optimization (WebP/AVIF)
|
|
126
|
+
- ✅ Responsive image support with srcset
|
|
127
|
+
- ✅ CDN caching at the edge
|
|
128
|
+
- ✅ Bandwidth savings
|
|
129
|
+
|
|
130
|
+
> 📚 See [docs/image-transforms.md](docs/image-transforms.md) for complete documentation, examples, and best practices.
|
|
131
|
+
|
|
87
132
|
## High-Level Data Loaders
|
|
88
133
|
|
|
89
134
|
The SDK now ships with convenience loaders that wrap the lower-level REST clients. They help you:
|
package/dist/index.d.mts
CHANGED
|
@@ -1925,6 +1925,145 @@ declare class PerspectApiClient {
|
|
|
1925
1925
|
*/
|
|
1926
1926
|
declare function createPerspectApiClient(config: PerspectApiConfig): PerspectApiClient;
|
|
1927
1927
|
|
|
1928
|
+
/**
|
|
1929
|
+
* Cloudflare Image Resizing Integration
|
|
1930
|
+
* Transforms images on-the-fly using Cloudflare's Image Resizing service
|
|
1931
|
+
* https://developers.cloudflare.com/images/transform-images/transform-via-url/
|
|
1932
|
+
*/
|
|
1933
|
+
interface ImageTransformOptions {
|
|
1934
|
+
width?: number;
|
|
1935
|
+
height?: number;
|
|
1936
|
+
fit?: 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
|
|
1937
|
+
gravity?: 'auto' | 'left' | 'right' | 'top' | 'bottom' | 'center';
|
|
1938
|
+
quality?: number;
|
|
1939
|
+
format?: 'auto' | 'avif' | 'webp' | 'json' | 'jpeg' | 'png';
|
|
1940
|
+
sharpen?: number;
|
|
1941
|
+
blur?: number;
|
|
1942
|
+
rotate?: 0 | 90 | 180 | 270;
|
|
1943
|
+
dpr?: number;
|
|
1944
|
+
metadata?: 'keep' | 'copyright' | 'none';
|
|
1945
|
+
background?: string;
|
|
1946
|
+
trim?: {
|
|
1947
|
+
top?: number;
|
|
1948
|
+
right?: number;
|
|
1949
|
+
bottom?: number;
|
|
1950
|
+
left?: number;
|
|
1951
|
+
};
|
|
1952
|
+
}
|
|
1953
|
+
interface ResponsiveImageSizes {
|
|
1954
|
+
thumbnail: ImageTransformOptions;
|
|
1955
|
+
small: ImageTransformOptions;
|
|
1956
|
+
medium: ImageTransformOptions;
|
|
1957
|
+
large: ImageTransformOptions;
|
|
1958
|
+
original: ImageTransformOptions;
|
|
1959
|
+
}
|
|
1960
|
+
/**
|
|
1961
|
+
* Default responsive image sizes
|
|
1962
|
+
*/
|
|
1963
|
+
declare const DEFAULT_IMAGE_SIZES: ResponsiveImageSizes;
|
|
1964
|
+
/**
|
|
1965
|
+
* Build Cloudflare Image Resizing URL
|
|
1966
|
+
*
|
|
1967
|
+
* @param baseUrl - The base URL of your API (e.g., "https://api.perspect.co")
|
|
1968
|
+
* @param mediaPath - The path to the media file (e.g., "media/site/image.jpg")
|
|
1969
|
+
* @param options - Transform options
|
|
1970
|
+
* @returns Cloudflare Image Resizing URL
|
|
1971
|
+
*
|
|
1972
|
+
* @example
|
|
1973
|
+
* ```typescript
|
|
1974
|
+
* const url = buildImageUrl(
|
|
1975
|
+
* 'https://api.perspect.co',
|
|
1976
|
+
* 'media/mysite/photo.jpg',
|
|
1977
|
+
* { width: 400, format: 'webp', quality: 85 }
|
|
1978
|
+
* );
|
|
1979
|
+
* // Returns: '/cdn-cgi/image/width=400,format=webp,quality=85/https://api.perspect.co/media/mysite/photo.jpg'
|
|
1980
|
+
* ```
|
|
1981
|
+
*/
|
|
1982
|
+
declare function buildImageUrl(baseUrl: string, mediaPath: string, options?: ImageTransformOptions): string;
|
|
1983
|
+
/**
|
|
1984
|
+
* Generate responsive image URLs for different sizes
|
|
1985
|
+
*
|
|
1986
|
+
* @example
|
|
1987
|
+
* ```typescript
|
|
1988
|
+
* const urls = generateResponsiveUrls(
|
|
1989
|
+
* 'https://api.perspect.co',
|
|
1990
|
+
* 'media/mysite/photo.jpg'
|
|
1991
|
+
* );
|
|
1992
|
+
* // Returns: { thumbnail: '...', small: '...', medium: '...', large: '...', original: '...' }
|
|
1993
|
+
* ```
|
|
1994
|
+
*/
|
|
1995
|
+
declare function generateResponsiveUrls(baseUrl: string, mediaPath: string, sizes?: ResponsiveImageSizes): Record<keyof ResponsiveImageSizes, string>;
|
|
1996
|
+
/**
|
|
1997
|
+
* Generate srcset for responsive images
|
|
1998
|
+
*
|
|
1999
|
+
* @example
|
|
2000
|
+
* ```typescript
|
|
2001
|
+
* const srcset = generateSrcSet(
|
|
2002
|
+
* 'https://api.perspect.co',
|
|
2003
|
+
* 'media/mysite/photo.jpg',
|
|
2004
|
+
* [400, 800, 1200]
|
|
2005
|
+
* );
|
|
2006
|
+
* // Returns: "...?width=400 400w, ...?width=800 800w, ...?width=1200 1200w"
|
|
2007
|
+
* ```
|
|
2008
|
+
*/
|
|
2009
|
+
declare function generateSrcSet(baseUrl: string, mediaPath: string, widths?: number[]): string;
|
|
2010
|
+
/**
|
|
2011
|
+
* Generate sizes attribute for responsive images
|
|
2012
|
+
*
|
|
2013
|
+
* @example
|
|
2014
|
+
* ```typescript
|
|
2015
|
+
* const sizes = generateSizesAttribute();
|
|
2016
|
+
* // Returns: "(max-width: 640px) 100vw, (max-width: 768px) 80vw, ..."
|
|
2017
|
+
* ```
|
|
2018
|
+
*/
|
|
2019
|
+
declare function generateSizesAttribute(breakpoints?: Array<{
|
|
2020
|
+
maxWidth: string;
|
|
2021
|
+
size: string;
|
|
2022
|
+
}>): string;
|
|
2023
|
+
/**
|
|
2024
|
+
* Helper to generate complete responsive image HTML
|
|
2025
|
+
*
|
|
2026
|
+
* @example
|
|
2027
|
+
* ```typescript
|
|
2028
|
+
* const html = generateResponsiveImageHtml(
|
|
2029
|
+
* 'https://api.perspect.co',
|
|
2030
|
+
* 'media/mysite/photo.jpg',
|
|
2031
|
+
* 'My photo',
|
|
2032
|
+
* { className: 'rounded-lg', loading: 'lazy' }
|
|
2033
|
+
* );
|
|
2034
|
+
* ```
|
|
2035
|
+
*/
|
|
2036
|
+
declare function generateResponsiveImageHtml(baseUrl: string, mediaPath: string, alt: string, options?: {
|
|
2037
|
+
className?: string;
|
|
2038
|
+
loading?: 'lazy' | 'eager';
|
|
2039
|
+
decoding?: 'async' | 'sync' | 'auto';
|
|
2040
|
+
sizes?: string;
|
|
2041
|
+
widths?: number[];
|
|
2042
|
+
}): string;
|
|
2043
|
+
/**
|
|
2044
|
+
* Transform a MediaItem into responsive URLs
|
|
2045
|
+
* Convenience function for working with MediaItem objects from the API
|
|
2046
|
+
*
|
|
2047
|
+
* @example
|
|
2048
|
+
* ```typescript
|
|
2049
|
+
* import { transformMediaItem } from 'perspectapi-ts-sdk';
|
|
2050
|
+
*
|
|
2051
|
+
* const product = await client.products.getProduct('mysite', 123);
|
|
2052
|
+
* const media = product.data.media?.[0];
|
|
2053
|
+
*
|
|
2054
|
+
* if (media) {
|
|
2055
|
+
* const urls = transformMediaItem('https://api.perspect.co', media);
|
|
2056
|
+
* console.log(urls.thumbnail); // Cloudflare-transformed thumbnail URL
|
|
2057
|
+
* }
|
|
2058
|
+
* ```
|
|
2059
|
+
*/
|
|
2060
|
+
declare function transformMediaItem(baseUrl: string, media: {
|
|
2061
|
+
link: string;
|
|
2062
|
+
} | {
|
|
2063
|
+
r2_key: string;
|
|
2064
|
+
site_name: string;
|
|
2065
|
+
}, sizes?: ResponsiveImageSizes): Record<keyof ResponsiveImageSizes, string>;
|
|
2066
|
+
|
|
1928
2067
|
/**
|
|
1929
2068
|
* High-level data loading helpers that wrap the PerspectAPI SDK clients.
|
|
1930
2069
|
* These helpers provide convenient product and content loading utilities with
|
|
@@ -2057,4 +2196,4 @@ declare function createCheckoutSession(options: CheckoutSessionOptions): Promise
|
|
|
2057
2196
|
error: string;
|
|
2058
2197
|
}>;
|
|
2059
2198
|
|
|
2060
|
-
export { type ApiError, type ApiKey, ApiKeysClient, type ApiResponse, AuthClient, type AuthResponse, BaseClient, type BlogPost, CategoriesClient, type Category, CheckoutClient, type CheckoutMetadata, type CheckoutMetadataValue, type CheckoutSession, type CheckoutSessionOptions, ContactClient, type ContactStatusResponse, type ContactSubmission, type ContactSubmitResponse, type Content, ContentClient, type ContentQueryParams, type ContentStatus, type ContentType, type CreateApiKeyRequest, type CreateCategoryRequest, type CreateCheckoutSessionRequest, type CreateContactRequest, type CreateContentRequest, type CreateNewsletterSubscriptionRequest, type CreateOrganizationRequest, type CreatePaymentGatewayRequest, type CreateProductRequest, type CreateSiteRequest, type CreateWebhookRequest, HttpClient, type HttpMethod, type LoadContentBySlugOptions, type LoadContentOptions, type LoadProductBySlugOptions, type LoadProductsOptions, type LoaderLogger, type LoaderOptions, type MediaItem, NewsletterClient, type NewsletterConfirmResponse, type NewsletterList, type NewsletterPreferences, type NewsletterStatusResponse, type NewsletterSubscribeResponse, type NewsletterSubscription, type NewsletterUnsubscribeRequest, type NewsletterUnsubscribeResponse, type Organization, OrganizationsClient, type PaginatedResponse, type PaginationParams, type PaymentGateway, PerspectApiClient, type PerspectApiConfig, type Product, type ProductQueryParams, ProductsClient, type RequestOptions, type SignInRequest, type SignUpRequest, type Site, SitesClient, type UpdateApiKeyRequest, type UpdateContentRequest, type User, type Webhook, WebhooksClient, createApiError, createCheckoutSession, createPerspectApiClient, PerspectApiClient as default, loadAllContent, loadContentBySlug, loadPages, loadPosts, loadProductBySlug, loadProducts, transformContent, transformProduct };
|
|
2199
|
+
export { type ApiError, type ApiKey, ApiKeysClient, type ApiResponse, AuthClient, type AuthResponse, BaseClient, type BlogPost, CategoriesClient, type Category, CheckoutClient, type CheckoutMetadata, type CheckoutMetadataValue, type CheckoutSession, type CheckoutSessionOptions, ContactClient, type ContactStatusResponse, type ContactSubmission, type ContactSubmitResponse, type Content, ContentClient, type ContentQueryParams, type ContentStatus, type ContentType, type CreateApiKeyRequest, type CreateCategoryRequest, type CreateCheckoutSessionRequest, type CreateContactRequest, type CreateContentRequest, type CreateNewsletterSubscriptionRequest, type CreateOrganizationRequest, type CreatePaymentGatewayRequest, type CreateProductRequest, type CreateSiteRequest, type CreateWebhookRequest, DEFAULT_IMAGE_SIZES, HttpClient, type HttpMethod, type ImageTransformOptions, type LoadContentBySlugOptions, type LoadContentOptions, type LoadProductBySlugOptions, type LoadProductsOptions, type LoaderLogger, type LoaderOptions, type MediaItem, NewsletterClient, type NewsletterConfirmResponse, type NewsletterList, type NewsletterPreferences, type NewsletterStatusResponse, type NewsletterSubscribeResponse, type NewsletterSubscription, type NewsletterUnsubscribeRequest, type NewsletterUnsubscribeResponse, type Organization, OrganizationsClient, type PaginatedResponse, type PaginationParams, type PaymentGateway, PerspectApiClient, type PerspectApiConfig, type Product, type ProductQueryParams, ProductsClient, type RequestOptions, type ResponsiveImageSizes, type SignInRequest, type SignUpRequest, type Site, SitesClient, type UpdateApiKeyRequest, type UpdateContentRequest, type User, type Webhook, WebhooksClient, buildImageUrl, createApiError, createCheckoutSession, createPerspectApiClient, PerspectApiClient as default, generateResponsiveImageHtml, generateResponsiveUrls, generateSizesAttribute, generateSrcSet, loadAllContent, loadContentBySlug, loadPages, loadPosts, loadProductBySlug, loadProducts, transformContent, transformMediaItem, transformProduct };
|
package/dist/index.d.ts
CHANGED
|
@@ -1925,6 +1925,145 @@ declare class PerspectApiClient {
|
|
|
1925
1925
|
*/
|
|
1926
1926
|
declare function createPerspectApiClient(config: PerspectApiConfig): PerspectApiClient;
|
|
1927
1927
|
|
|
1928
|
+
/**
|
|
1929
|
+
* Cloudflare Image Resizing Integration
|
|
1930
|
+
* Transforms images on-the-fly using Cloudflare's Image Resizing service
|
|
1931
|
+
* https://developers.cloudflare.com/images/transform-images/transform-via-url/
|
|
1932
|
+
*/
|
|
1933
|
+
interface ImageTransformOptions {
|
|
1934
|
+
width?: number;
|
|
1935
|
+
height?: number;
|
|
1936
|
+
fit?: 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
|
|
1937
|
+
gravity?: 'auto' | 'left' | 'right' | 'top' | 'bottom' | 'center';
|
|
1938
|
+
quality?: number;
|
|
1939
|
+
format?: 'auto' | 'avif' | 'webp' | 'json' | 'jpeg' | 'png';
|
|
1940
|
+
sharpen?: number;
|
|
1941
|
+
blur?: number;
|
|
1942
|
+
rotate?: 0 | 90 | 180 | 270;
|
|
1943
|
+
dpr?: number;
|
|
1944
|
+
metadata?: 'keep' | 'copyright' | 'none';
|
|
1945
|
+
background?: string;
|
|
1946
|
+
trim?: {
|
|
1947
|
+
top?: number;
|
|
1948
|
+
right?: number;
|
|
1949
|
+
bottom?: number;
|
|
1950
|
+
left?: number;
|
|
1951
|
+
};
|
|
1952
|
+
}
|
|
1953
|
+
interface ResponsiveImageSizes {
|
|
1954
|
+
thumbnail: ImageTransformOptions;
|
|
1955
|
+
small: ImageTransformOptions;
|
|
1956
|
+
medium: ImageTransformOptions;
|
|
1957
|
+
large: ImageTransformOptions;
|
|
1958
|
+
original: ImageTransformOptions;
|
|
1959
|
+
}
|
|
1960
|
+
/**
|
|
1961
|
+
* Default responsive image sizes
|
|
1962
|
+
*/
|
|
1963
|
+
declare const DEFAULT_IMAGE_SIZES: ResponsiveImageSizes;
|
|
1964
|
+
/**
|
|
1965
|
+
* Build Cloudflare Image Resizing URL
|
|
1966
|
+
*
|
|
1967
|
+
* @param baseUrl - The base URL of your API (e.g., "https://api.perspect.co")
|
|
1968
|
+
* @param mediaPath - The path to the media file (e.g., "media/site/image.jpg")
|
|
1969
|
+
* @param options - Transform options
|
|
1970
|
+
* @returns Cloudflare Image Resizing URL
|
|
1971
|
+
*
|
|
1972
|
+
* @example
|
|
1973
|
+
* ```typescript
|
|
1974
|
+
* const url = buildImageUrl(
|
|
1975
|
+
* 'https://api.perspect.co',
|
|
1976
|
+
* 'media/mysite/photo.jpg',
|
|
1977
|
+
* { width: 400, format: 'webp', quality: 85 }
|
|
1978
|
+
* );
|
|
1979
|
+
* // Returns: '/cdn-cgi/image/width=400,format=webp,quality=85/https://api.perspect.co/media/mysite/photo.jpg'
|
|
1980
|
+
* ```
|
|
1981
|
+
*/
|
|
1982
|
+
declare function buildImageUrl(baseUrl: string, mediaPath: string, options?: ImageTransformOptions): string;
|
|
1983
|
+
/**
|
|
1984
|
+
* Generate responsive image URLs for different sizes
|
|
1985
|
+
*
|
|
1986
|
+
* @example
|
|
1987
|
+
* ```typescript
|
|
1988
|
+
* const urls = generateResponsiveUrls(
|
|
1989
|
+
* 'https://api.perspect.co',
|
|
1990
|
+
* 'media/mysite/photo.jpg'
|
|
1991
|
+
* );
|
|
1992
|
+
* // Returns: { thumbnail: '...', small: '...', medium: '...', large: '...', original: '...' }
|
|
1993
|
+
* ```
|
|
1994
|
+
*/
|
|
1995
|
+
declare function generateResponsiveUrls(baseUrl: string, mediaPath: string, sizes?: ResponsiveImageSizes): Record<keyof ResponsiveImageSizes, string>;
|
|
1996
|
+
/**
|
|
1997
|
+
* Generate srcset for responsive images
|
|
1998
|
+
*
|
|
1999
|
+
* @example
|
|
2000
|
+
* ```typescript
|
|
2001
|
+
* const srcset = generateSrcSet(
|
|
2002
|
+
* 'https://api.perspect.co',
|
|
2003
|
+
* 'media/mysite/photo.jpg',
|
|
2004
|
+
* [400, 800, 1200]
|
|
2005
|
+
* );
|
|
2006
|
+
* // Returns: "...?width=400 400w, ...?width=800 800w, ...?width=1200 1200w"
|
|
2007
|
+
* ```
|
|
2008
|
+
*/
|
|
2009
|
+
declare function generateSrcSet(baseUrl: string, mediaPath: string, widths?: number[]): string;
|
|
2010
|
+
/**
|
|
2011
|
+
* Generate sizes attribute for responsive images
|
|
2012
|
+
*
|
|
2013
|
+
* @example
|
|
2014
|
+
* ```typescript
|
|
2015
|
+
* const sizes = generateSizesAttribute();
|
|
2016
|
+
* // Returns: "(max-width: 640px) 100vw, (max-width: 768px) 80vw, ..."
|
|
2017
|
+
* ```
|
|
2018
|
+
*/
|
|
2019
|
+
declare function generateSizesAttribute(breakpoints?: Array<{
|
|
2020
|
+
maxWidth: string;
|
|
2021
|
+
size: string;
|
|
2022
|
+
}>): string;
|
|
2023
|
+
/**
|
|
2024
|
+
* Helper to generate complete responsive image HTML
|
|
2025
|
+
*
|
|
2026
|
+
* @example
|
|
2027
|
+
* ```typescript
|
|
2028
|
+
* const html = generateResponsiveImageHtml(
|
|
2029
|
+
* 'https://api.perspect.co',
|
|
2030
|
+
* 'media/mysite/photo.jpg',
|
|
2031
|
+
* 'My photo',
|
|
2032
|
+
* { className: 'rounded-lg', loading: 'lazy' }
|
|
2033
|
+
* );
|
|
2034
|
+
* ```
|
|
2035
|
+
*/
|
|
2036
|
+
declare function generateResponsiveImageHtml(baseUrl: string, mediaPath: string, alt: string, options?: {
|
|
2037
|
+
className?: string;
|
|
2038
|
+
loading?: 'lazy' | 'eager';
|
|
2039
|
+
decoding?: 'async' | 'sync' | 'auto';
|
|
2040
|
+
sizes?: string;
|
|
2041
|
+
widths?: number[];
|
|
2042
|
+
}): string;
|
|
2043
|
+
/**
|
|
2044
|
+
* Transform a MediaItem into responsive URLs
|
|
2045
|
+
* Convenience function for working with MediaItem objects from the API
|
|
2046
|
+
*
|
|
2047
|
+
* @example
|
|
2048
|
+
* ```typescript
|
|
2049
|
+
* import { transformMediaItem } from 'perspectapi-ts-sdk';
|
|
2050
|
+
*
|
|
2051
|
+
* const product = await client.products.getProduct('mysite', 123);
|
|
2052
|
+
* const media = product.data.media?.[0];
|
|
2053
|
+
*
|
|
2054
|
+
* if (media) {
|
|
2055
|
+
* const urls = transformMediaItem('https://api.perspect.co', media);
|
|
2056
|
+
* console.log(urls.thumbnail); // Cloudflare-transformed thumbnail URL
|
|
2057
|
+
* }
|
|
2058
|
+
* ```
|
|
2059
|
+
*/
|
|
2060
|
+
declare function transformMediaItem(baseUrl: string, media: {
|
|
2061
|
+
link: string;
|
|
2062
|
+
} | {
|
|
2063
|
+
r2_key: string;
|
|
2064
|
+
site_name: string;
|
|
2065
|
+
}, sizes?: ResponsiveImageSizes): Record<keyof ResponsiveImageSizes, string>;
|
|
2066
|
+
|
|
1928
2067
|
/**
|
|
1929
2068
|
* High-level data loading helpers that wrap the PerspectAPI SDK clients.
|
|
1930
2069
|
* These helpers provide convenient product and content loading utilities with
|
|
@@ -2057,4 +2196,4 @@ declare function createCheckoutSession(options: CheckoutSessionOptions): Promise
|
|
|
2057
2196
|
error: string;
|
|
2058
2197
|
}>;
|
|
2059
2198
|
|
|
2060
|
-
export { type ApiError, type ApiKey, ApiKeysClient, type ApiResponse, AuthClient, type AuthResponse, BaseClient, type BlogPost, CategoriesClient, type Category, CheckoutClient, type CheckoutMetadata, type CheckoutMetadataValue, type CheckoutSession, type CheckoutSessionOptions, ContactClient, type ContactStatusResponse, type ContactSubmission, type ContactSubmitResponse, type Content, ContentClient, type ContentQueryParams, type ContentStatus, type ContentType, type CreateApiKeyRequest, type CreateCategoryRequest, type CreateCheckoutSessionRequest, type CreateContactRequest, type CreateContentRequest, type CreateNewsletterSubscriptionRequest, type CreateOrganizationRequest, type CreatePaymentGatewayRequest, type CreateProductRequest, type CreateSiteRequest, type CreateWebhookRequest, HttpClient, type HttpMethod, type LoadContentBySlugOptions, type LoadContentOptions, type LoadProductBySlugOptions, type LoadProductsOptions, type LoaderLogger, type LoaderOptions, type MediaItem, NewsletterClient, type NewsletterConfirmResponse, type NewsletterList, type NewsletterPreferences, type NewsletterStatusResponse, type NewsletterSubscribeResponse, type NewsletterSubscription, type NewsletterUnsubscribeRequest, type NewsletterUnsubscribeResponse, type Organization, OrganizationsClient, type PaginatedResponse, type PaginationParams, type PaymentGateway, PerspectApiClient, type PerspectApiConfig, type Product, type ProductQueryParams, ProductsClient, type RequestOptions, type SignInRequest, type SignUpRequest, type Site, SitesClient, type UpdateApiKeyRequest, type UpdateContentRequest, type User, type Webhook, WebhooksClient, createApiError, createCheckoutSession, createPerspectApiClient, PerspectApiClient as default, loadAllContent, loadContentBySlug, loadPages, loadPosts, loadProductBySlug, loadProducts, transformContent, transformProduct };
|
|
2199
|
+
export { type ApiError, type ApiKey, ApiKeysClient, type ApiResponse, AuthClient, type AuthResponse, BaseClient, type BlogPost, CategoriesClient, type Category, CheckoutClient, type CheckoutMetadata, type CheckoutMetadataValue, type CheckoutSession, type CheckoutSessionOptions, ContactClient, type ContactStatusResponse, type ContactSubmission, type ContactSubmitResponse, type Content, ContentClient, type ContentQueryParams, type ContentStatus, type ContentType, type CreateApiKeyRequest, type CreateCategoryRequest, type CreateCheckoutSessionRequest, type CreateContactRequest, type CreateContentRequest, type CreateNewsletterSubscriptionRequest, type CreateOrganizationRequest, type CreatePaymentGatewayRequest, type CreateProductRequest, type CreateSiteRequest, type CreateWebhookRequest, DEFAULT_IMAGE_SIZES, HttpClient, type HttpMethod, type ImageTransformOptions, type LoadContentBySlugOptions, type LoadContentOptions, type LoadProductBySlugOptions, type LoadProductsOptions, type LoaderLogger, type LoaderOptions, type MediaItem, NewsletterClient, type NewsletterConfirmResponse, type NewsletterList, type NewsletterPreferences, type NewsletterStatusResponse, type NewsletterSubscribeResponse, type NewsletterSubscription, type NewsletterUnsubscribeRequest, type NewsletterUnsubscribeResponse, type Organization, OrganizationsClient, type PaginatedResponse, type PaginationParams, type PaymentGateway, PerspectApiClient, type PerspectApiConfig, type Product, type ProductQueryParams, ProductsClient, type RequestOptions, type ResponsiveImageSizes, type SignInRequest, type SignUpRequest, type Site, SitesClient, type UpdateApiKeyRequest, type UpdateContentRequest, type User, type Webhook, WebhooksClient, buildImageUrl, createApiError, createCheckoutSession, createPerspectApiClient, PerspectApiClient as default, generateResponsiveImageHtml, generateResponsiveUrls, generateSizesAttribute, generateSrcSet, loadAllContent, loadContentBySlug, loadPages, loadPosts, loadProductBySlug, loadProducts, transformContent, transformMediaItem, transformProduct };
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,7 @@ __export(index_exports, {
|
|
|
27
27
|
CheckoutClient: () => CheckoutClient,
|
|
28
28
|
ContactClient: () => ContactClient,
|
|
29
29
|
ContentClient: () => ContentClient,
|
|
30
|
+
DEFAULT_IMAGE_SIZES: () => DEFAULT_IMAGE_SIZES,
|
|
30
31
|
HttpClient: () => HttpClient,
|
|
31
32
|
NewsletterClient: () => NewsletterClient,
|
|
32
33
|
OrganizationsClient: () => OrganizationsClient,
|
|
@@ -34,10 +35,15 @@ __export(index_exports, {
|
|
|
34
35
|
ProductsClient: () => ProductsClient,
|
|
35
36
|
SitesClient: () => SitesClient,
|
|
36
37
|
WebhooksClient: () => WebhooksClient,
|
|
38
|
+
buildImageUrl: () => buildImageUrl,
|
|
37
39
|
createApiError: () => createApiError,
|
|
38
40
|
createCheckoutSession: () => createCheckoutSession,
|
|
39
41
|
createPerspectApiClient: () => createPerspectApiClient,
|
|
40
42
|
default: () => perspect_api_client_default,
|
|
43
|
+
generateResponsiveImageHtml: () => generateResponsiveImageHtml,
|
|
44
|
+
generateResponsiveUrls: () => generateResponsiveUrls,
|
|
45
|
+
generateSizesAttribute: () => generateSizesAttribute,
|
|
46
|
+
generateSrcSet: () => generateSrcSet,
|
|
41
47
|
loadAllContent: () => loadAllContent,
|
|
42
48
|
loadContentBySlug: () => loadContentBySlug,
|
|
43
49
|
loadPages: () => loadPages,
|
|
@@ -45,6 +51,7 @@ __export(index_exports, {
|
|
|
45
51
|
loadProductBySlug: () => loadProductBySlug,
|
|
46
52
|
loadProducts: () => loadProducts,
|
|
47
53
|
transformContent: () => transformContent,
|
|
54
|
+
transformMediaItem: () => transformMediaItem,
|
|
48
55
|
transformProduct: () => transformProduct
|
|
49
56
|
});
|
|
50
57
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -1572,6 +1579,129 @@ function createPerspectApiClient(config) {
|
|
|
1572
1579
|
}
|
|
1573
1580
|
var perspect_api_client_default = PerspectApiClient;
|
|
1574
1581
|
|
|
1582
|
+
// src/utils/image-transform.ts
|
|
1583
|
+
var DEFAULT_IMAGE_SIZES = {
|
|
1584
|
+
thumbnail: {
|
|
1585
|
+
width: 150,
|
|
1586
|
+
height: 150,
|
|
1587
|
+
fit: "cover",
|
|
1588
|
+
quality: 85,
|
|
1589
|
+
format: "auto"
|
|
1590
|
+
},
|
|
1591
|
+
small: {
|
|
1592
|
+
width: 400,
|
|
1593
|
+
fit: "scale-down",
|
|
1594
|
+
quality: 85,
|
|
1595
|
+
format: "auto"
|
|
1596
|
+
},
|
|
1597
|
+
medium: {
|
|
1598
|
+
width: 800,
|
|
1599
|
+
fit: "scale-down",
|
|
1600
|
+
quality: 85,
|
|
1601
|
+
format: "auto"
|
|
1602
|
+
},
|
|
1603
|
+
large: {
|
|
1604
|
+
width: 1200,
|
|
1605
|
+
fit: "scale-down",
|
|
1606
|
+
quality: 85,
|
|
1607
|
+
format: "auto"
|
|
1608
|
+
},
|
|
1609
|
+
original: {
|
|
1610
|
+
format: "auto"
|
|
1611
|
+
}
|
|
1612
|
+
};
|
|
1613
|
+
function buildImageUrl(baseUrl, mediaPath, options) {
|
|
1614
|
+
const sourceUrl = `${baseUrl}/${mediaPath.replace(/^\//, "")}`;
|
|
1615
|
+
if (!options || Object.keys(options).length === 0) {
|
|
1616
|
+
return sourceUrl;
|
|
1617
|
+
}
|
|
1618
|
+
const params = [];
|
|
1619
|
+
if (options.width) params.push(`width=${options.width}`);
|
|
1620
|
+
if (options.height) params.push(`height=${options.height}`);
|
|
1621
|
+
if (options.fit) params.push(`fit=${options.fit}`);
|
|
1622
|
+
if (options.gravity) params.push(`gravity=${options.gravity}`);
|
|
1623
|
+
if (options.quality) params.push(`quality=${options.quality}`);
|
|
1624
|
+
if (options.format) params.push(`format=${options.format}`);
|
|
1625
|
+
if (options.sharpen) params.push(`sharpen=${options.sharpen}`);
|
|
1626
|
+
if (options.blur) params.push(`blur=${options.blur}`);
|
|
1627
|
+
if (options.rotate) params.push(`rotate=${options.rotate}`);
|
|
1628
|
+
if (options.dpr) params.push(`dpr=${options.dpr}`);
|
|
1629
|
+
if (options.metadata) params.push(`metadata=${options.metadata}`);
|
|
1630
|
+
if (options.background) params.push(`background=${options.background}`);
|
|
1631
|
+
if (options.trim) {
|
|
1632
|
+
const trimParts = [];
|
|
1633
|
+
if (options.trim.top) trimParts.push(`${options.trim.top}`);
|
|
1634
|
+
if (options.trim.right) trimParts.push(`${options.trim.right}`);
|
|
1635
|
+
if (options.trim.bottom) trimParts.push(`${options.trim.bottom}`);
|
|
1636
|
+
if (options.trim.left) trimParts.push(`${options.trim.left}`);
|
|
1637
|
+
if (trimParts.length > 0) {
|
|
1638
|
+
params.push(`trim=${trimParts.join(";")}`);
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
const queryString = params.join(",");
|
|
1642
|
+
return `/cdn-cgi/image/${queryString}/${sourceUrl}`;
|
|
1643
|
+
}
|
|
1644
|
+
function generateResponsiveUrls(baseUrl, mediaPath, sizes = DEFAULT_IMAGE_SIZES) {
|
|
1645
|
+
return {
|
|
1646
|
+
thumbnail: buildImageUrl(baseUrl, mediaPath, sizes.thumbnail),
|
|
1647
|
+
small: buildImageUrl(baseUrl, mediaPath, sizes.small),
|
|
1648
|
+
medium: buildImageUrl(baseUrl, mediaPath, sizes.medium),
|
|
1649
|
+
large: buildImageUrl(baseUrl, mediaPath, sizes.large),
|
|
1650
|
+
original: buildImageUrl(baseUrl, mediaPath, sizes.original)
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
function generateSrcSet(baseUrl, mediaPath, widths = [400, 800, 1200, 1600]) {
|
|
1654
|
+
return widths.map((width) => {
|
|
1655
|
+
const url = buildImageUrl(baseUrl, mediaPath, {
|
|
1656
|
+
width,
|
|
1657
|
+
fit: "scale-down",
|
|
1658
|
+
quality: 85,
|
|
1659
|
+
format: "auto"
|
|
1660
|
+
});
|
|
1661
|
+
return `${url} ${width}w`;
|
|
1662
|
+
}).join(", ");
|
|
1663
|
+
}
|
|
1664
|
+
function generateSizesAttribute(breakpoints = [
|
|
1665
|
+
{ maxWidth: "640px", size: "100vw" },
|
|
1666
|
+
{ maxWidth: "768px", size: "80vw" },
|
|
1667
|
+
{ maxWidth: "1024px", size: "60vw" },
|
|
1668
|
+
{ maxWidth: "1280px", size: "50vw" }
|
|
1669
|
+
]) {
|
|
1670
|
+
const mediaQueries = breakpoints.map(
|
|
1671
|
+
(bp) => `(max-width: ${bp.maxWidth}) ${bp.size}`
|
|
1672
|
+
);
|
|
1673
|
+
mediaQueries.push("40vw");
|
|
1674
|
+
return mediaQueries.join(", ");
|
|
1675
|
+
}
|
|
1676
|
+
function generateResponsiveImageHtml(baseUrl, mediaPath, alt, options) {
|
|
1677
|
+
const srcset = generateSrcSet(baseUrl, mediaPath, options?.widths);
|
|
1678
|
+
const sizes = options?.sizes || generateSizesAttribute();
|
|
1679
|
+
const src = buildImageUrl(baseUrl, mediaPath, {
|
|
1680
|
+
width: 800,
|
|
1681
|
+
fit: "scale-down",
|
|
1682
|
+
quality: 85,
|
|
1683
|
+
format: "auto"
|
|
1684
|
+
});
|
|
1685
|
+
return `<img
|
|
1686
|
+
src="${src}"
|
|
1687
|
+
srcset="${srcset}"
|
|
1688
|
+
sizes="${sizes}"
|
|
1689
|
+
alt="${alt}"
|
|
1690
|
+
${options?.className ? `class="${options.className}"` : ""}
|
|
1691
|
+
${options?.loading ? `loading="${options.loading}"` : 'loading="lazy"'}
|
|
1692
|
+
${options?.decoding ? `decoding="${options.decoding}"` : 'decoding="async"'}
|
|
1693
|
+
/>`;
|
|
1694
|
+
}
|
|
1695
|
+
function transformMediaItem(baseUrl, media, sizes) {
|
|
1696
|
+
let mediaPath;
|
|
1697
|
+
if ("link" in media) {
|
|
1698
|
+
mediaPath = media.link.replace(/^https?:\/\/[^/]+\//, "");
|
|
1699
|
+
} else {
|
|
1700
|
+
mediaPath = `media/${media.site_name}/${media.r2_key.split("/").pop()}`;
|
|
1701
|
+
}
|
|
1702
|
+
return generateResponsiveUrls(baseUrl, mediaPath, sizes);
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1575
1705
|
// src/loaders.ts
|
|
1576
1706
|
var noopLogger = {};
|
|
1577
1707
|
var log = (logger, level, ...args) => {
|
|
@@ -1968,6 +2098,7 @@ async function createCheckoutSession(options) {
|
|
|
1968
2098
|
CheckoutClient,
|
|
1969
2099
|
ContactClient,
|
|
1970
2100
|
ContentClient,
|
|
2101
|
+
DEFAULT_IMAGE_SIZES,
|
|
1971
2102
|
HttpClient,
|
|
1972
2103
|
NewsletterClient,
|
|
1973
2104
|
OrganizationsClient,
|
|
@@ -1975,9 +2106,14 @@ async function createCheckoutSession(options) {
|
|
|
1975
2106
|
ProductsClient,
|
|
1976
2107
|
SitesClient,
|
|
1977
2108
|
WebhooksClient,
|
|
2109
|
+
buildImageUrl,
|
|
1978
2110
|
createApiError,
|
|
1979
2111
|
createCheckoutSession,
|
|
1980
2112
|
createPerspectApiClient,
|
|
2113
|
+
generateResponsiveImageHtml,
|
|
2114
|
+
generateResponsiveUrls,
|
|
2115
|
+
generateSizesAttribute,
|
|
2116
|
+
generateSrcSet,
|
|
1981
2117
|
loadAllContent,
|
|
1982
2118
|
loadContentBySlug,
|
|
1983
2119
|
loadPages,
|
|
@@ -1985,5 +2121,6 @@ async function createCheckoutSession(options) {
|
|
|
1985
2121
|
loadProductBySlug,
|
|
1986
2122
|
loadProducts,
|
|
1987
2123
|
transformContent,
|
|
2124
|
+
transformMediaItem,
|
|
1988
2125
|
transformProduct
|
|
1989
2126
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1521,6 +1521,129 @@ function createPerspectApiClient(config) {
|
|
|
1521
1521
|
}
|
|
1522
1522
|
var perspect_api_client_default = PerspectApiClient;
|
|
1523
1523
|
|
|
1524
|
+
// src/utils/image-transform.ts
|
|
1525
|
+
var DEFAULT_IMAGE_SIZES = {
|
|
1526
|
+
thumbnail: {
|
|
1527
|
+
width: 150,
|
|
1528
|
+
height: 150,
|
|
1529
|
+
fit: "cover",
|
|
1530
|
+
quality: 85,
|
|
1531
|
+
format: "auto"
|
|
1532
|
+
},
|
|
1533
|
+
small: {
|
|
1534
|
+
width: 400,
|
|
1535
|
+
fit: "scale-down",
|
|
1536
|
+
quality: 85,
|
|
1537
|
+
format: "auto"
|
|
1538
|
+
},
|
|
1539
|
+
medium: {
|
|
1540
|
+
width: 800,
|
|
1541
|
+
fit: "scale-down",
|
|
1542
|
+
quality: 85,
|
|
1543
|
+
format: "auto"
|
|
1544
|
+
},
|
|
1545
|
+
large: {
|
|
1546
|
+
width: 1200,
|
|
1547
|
+
fit: "scale-down",
|
|
1548
|
+
quality: 85,
|
|
1549
|
+
format: "auto"
|
|
1550
|
+
},
|
|
1551
|
+
original: {
|
|
1552
|
+
format: "auto"
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1555
|
+
function buildImageUrl(baseUrl, mediaPath, options) {
|
|
1556
|
+
const sourceUrl = `${baseUrl}/${mediaPath.replace(/^\//, "")}`;
|
|
1557
|
+
if (!options || Object.keys(options).length === 0) {
|
|
1558
|
+
return sourceUrl;
|
|
1559
|
+
}
|
|
1560
|
+
const params = [];
|
|
1561
|
+
if (options.width) params.push(`width=${options.width}`);
|
|
1562
|
+
if (options.height) params.push(`height=${options.height}`);
|
|
1563
|
+
if (options.fit) params.push(`fit=${options.fit}`);
|
|
1564
|
+
if (options.gravity) params.push(`gravity=${options.gravity}`);
|
|
1565
|
+
if (options.quality) params.push(`quality=${options.quality}`);
|
|
1566
|
+
if (options.format) params.push(`format=${options.format}`);
|
|
1567
|
+
if (options.sharpen) params.push(`sharpen=${options.sharpen}`);
|
|
1568
|
+
if (options.blur) params.push(`blur=${options.blur}`);
|
|
1569
|
+
if (options.rotate) params.push(`rotate=${options.rotate}`);
|
|
1570
|
+
if (options.dpr) params.push(`dpr=${options.dpr}`);
|
|
1571
|
+
if (options.metadata) params.push(`metadata=${options.metadata}`);
|
|
1572
|
+
if (options.background) params.push(`background=${options.background}`);
|
|
1573
|
+
if (options.trim) {
|
|
1574
|
+
const trimParts = [];
|
|
1575
|
+
if (options.trim.top) trimParts.push(`${options.trim.top}`);
|
|
1576
|
+
if (options.trim.right) trimParts.push(`${options.trim.right}`);
|
|
1577
|
+
if (options.trim.bottom) trimParts.push(`${options.trim.bottom}`);
|
|
1578
|
+
if (options.trim.left) trimParts.push(`${options.trim.left}`);
|
|
1579
|
+
if (trimParts.length > 0) {
|
|
1580
|
+
params.push(`trim=${trimParts.join(";")}`);
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
const queryString = params.join(",");
|
|
1584
|
+
return `/cdn-cgi/image/${queryString}/${sourceUrl}`;
|
|
1585
|
+
}
|
|
1586
|
+
function generateResponsiveUrls(baseUrl, mediaPath, sizes = DEFAULT_IMAGE_SIZES) {
|
|
1587
|
+
return {
|
|
1588
|
+
thumbnail: buildImageUrl(baseUrl, mediaPath, sizes.thumbnail),
|
|
1589
|
+
small: buildImageUrl(baseUrl, mediaPath, sizes.small),
|
|
1590
|
+
medium: buildImageUrl(baseUrl, mediaPath, sizes.medium),
|
|
1591
|
+
large: buildImageUrl(baseUrl, mediaPath, sizes.large),
|
|
1592
|
+
original: buildImageUrl(baseUrl, mediaPath, sizes.original)
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
function generateSrcSet(baseUrl, mediaPath, widths = [400, 800, 1200, 1600]) {
|
|
1596
|
+
return widths.map((width) => {
|
|
1597
|
+
const url = buildImageUrl(baseUrl, mediaPath, {
|
|
1598
|
+
width,
|
|
1599
|
+
fit: "scale-down",
|
|
1600
|
+
quality: 85,
|
|
1601
|
+
format: "auto"
|
|
1602
|
+
});
|
|
1603
|
+
return `${url} ${width}w`;
|
|
1604
|
+
}).join(", ");
|
|
1605
|
+
}
|
|
1606
|
+
function generateSizesAttribute(breakpoints = [
|
|
1607
|
+
{ maxWidth: "640px", size: "100vw" },
|
|
1608
|
+
{ maxWidth: "768px", size: "80vw" },
|
|
1609
|
+
{ maxWidth: "1024px", size: "60vw" },
|
|
1610
|
+
{ maxWidth: "1280px", size: "50vw" }
|
|
1611
|
+
]) {
|
|
1612
|
+
const mediaQueries = breakpoints.map(
|
|
1613
|
+
(bp) => `(max-width: ${bp.maxWidth}) ${bp.size}`
|
|
1614
|
+
);
|
|
1615
|
+
mediaQueries.push("40vw");
|
|
1616
|
+
return mediaQueries.join(", ");
|
|
1617
|
+
}
|
|
1618
|
+
function generateResponsiveImageHtml(baseUrl, mediaPath, alt, options) {
|
|
1619
|
+
const srcset = generateSrcSet(baseUrl, mediaPath, options?.widths);
|
|
1620
|
+
const sizes = options?.sizes || generateSizesAttribute();
|
|
1621
|
+
const src = buildImageUrl(baseUrl, mediaPath, {
|
|
1622
|
+
width: 800,
|
|
1623
|
+
fit: "scale-down",
|
|
1624
|
+
quality: 85,
|
|
1625
|
+
format: "auto"
|
|
1626
|
+
});
|
|
1627
|
+
return `<img
|
|
1628
|
+
src="${src}"
|
|
1629
|
+
srcset="${srcset}"
|
|
1630
|
+
sizes="${sizes}"
|
|
1631
|
+
alt="${alt}"
|
|
1632
|
+
${options?.className ? `class="${options.className}"` : ""}
|
|
1633
|
+
${options?.loading ? `loading="${options.loading}"` : 'loading="lazy"'}
|
|
1634
|
+
${options?.decoding ? `decoding="${options.decoding}"` : 'decoding="async"'}
|
|
1635
|
+
/>`;
|
|
1636
|
+
}
|
|
1637
|
+
function transformMediaItem(baseUrl, media, sizes) {
|
|
1638
|
+
let mediaPath;
|
|
1639
|
+
if ("link" in media) {
|
|
1640
|
+
mediaPath = media.link.replace(/^https?:\/\/[^/]+\//, "");
|
|
1641
|
+
} else {
|
|
1642
|
+
mediaPath = `media/${media.site_name}/${media.r2_key.split("/").pop()}`;
|
|
1643
|
+
}
|
|
1644
|
+
return generateResponsiveUrls(baseUrl, mediaPath, sizes);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1524
1647
|
// src/loaders.ts
|
|
1525
1648
|
var noopLogger = {};
|
|
1526
1649
|
var log = (logger, level, ...args) => {
|
|
@@ -1916,6 +2039,7 @@ export {
|
|
|
1916
2039
|
CheckoutClient,
|
|
1917
2040
|
ContactClient,
|
|
1918
2041
|
ContentClient,
|
|
2042
|
+
DEFAULT_IMAGE_SIZES,
|
|
1919
2043
|
HttpClient,
|
|
1920
2044
|
NewsletterClient,
|
|
1921
2045
|
OrganizationsClient,
|
|
@@ -1923,10 +2047,15 @@ export {
|
|
|
1923
2047
|
ProductsClient,
|
|
1924
2048
|
SitesClient,
|
|
1925
2049
|
WebhooksClient,
|
|
2050
|
+
buildImageUrl,
|
|
1926
2051
|
createApiError,
|
|
1927
2052
|
createCheckoutSession,
|
|
1928
2053
|
createPerspectApiClient,
|
|
1929
2054
|
perspect_api_client_default as default,
|
|
2055
|
+
generateResponsiveImageHtml,
|
|
2056
|
+
generateResponsiveUrls,
|
|
2057
|
+
generateSizesAttribute,
|
|
2058
|
+
generateSrcSet,
|
|
1930
2059
|
loadAllContent,
|
|
1931
2060
|
loadContentBySlug,
|
|
1932
2061
|
loadPages,
|
|
@@ -1934,5 +2063,6 @@ export {
|
|
|
1934
2063
|
loadProductBySlug,
|
|
1935
2064
|
loadProducts,
|
|
1936
2065
|
transformContent,
|
|
2066
|
+
transformMediaItem,
|
|
1937
2067
|
transformProduct
|
|
1938
2068
|
};
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -26,6 +26,22 @@ export { BaseClient } from './client/base-client';
|
|
|
26
26
|
// Utilities
|
|
27
27
|
export { HttpClient, createApiError } from './utils/http-client';
|
|
28
28
|
|
|
29
|
+
// Image transformation utilities
|
|
30
|
+
export {
|
|
31
|
+
buildImageUrl,
|
|
32
|
+
generateResponsiveUrls,
|
|
33
|
+
generateSrcSet,
|
|
34
|
+
generateSizesAttribute,
|
|
35
|
+
generateResponsiveImageHtml,
|
|
36
|
+
transformMediaItem,
|
|
37
|
+
DEFAULT_IMAGE_SIZES
|
|
38
|
+
} from './utils/image-transform';
|
|
39
|
+
|
|
40
|
+
export type {
|
|
41
|
+
ImageTransformOptions,
|
|
42
|
+
ResponsiveImageSizes
|
|
43
|
+
} from './utils/image-transform';
|
|
44
|
+
|
|
29
45
|
// High-level data loaders
|
|
30
46
|
export {
|
|
31
47
|
loadProducts,
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare Image Resizing Integration
|
|
3
|
+
* Transforms images on-the-fly using Cloudflare's Image Resizing service
|
|
4
|
+
* https://developers.cloudflare.com/images/transform-images/transform-via-url/
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface ImageTransformOptions {
|
|
8
|
+
width?: number;
|
|
9
|
+
height?: number;
|
|
10
|
+
fit?: 'scale-down' | 'contain' | 'cover' | 'crop' | 'pad';
|
|
11
|
+
gravity?: 'auto' | 'left' | 'right' | 'top' | 'bottom' | 'center';
|
|
12
|
+
quality?: number; // 1-100
|
|
13
|
+
format?: 'auto' | 'avif' | 'webp' | 'json' | 'jpeg' | 'png';
|
|
14
|
+
sharpen?: number; // 0-10
|
|
15
|
+
blur?: number; // 0-250
|
|
16
|
+
rotate?: 0 | 90 | 180 | 270;
|
|
17
|
+
dpr?: number; // Device Pixel Ratio: 1, 2, or 3
|
|
18
|
+
metadata?: 'keep' | 'copyright' | 'none';
|
|
19
|
+
background?: string; // hex color for padding
|
|
20
|
+
trim?: {
|
|
21
|
+
top?: number;
|
|
22
|
+
right?: number;
|
|
23
|
+
bottom?: number;
|
|
24
|
+
left?: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ResponsiveImageSizes {
|
|
29
|
+
thumbnail: ImageTransformOptions;
|
|
30
|
+
small: ImageTransformOptions;
|
|
31
|
+
medium: ImageTransformOptions;
|
|
32
|
+
large: ImageTransformOptions;
|
|
33
|
+
original: ImageTransformOptions;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Default responsive image sizes
|
|
38
|
+
*/
|
|
39
|
+
export const DEFAULT_IMAGE_SIZES: ResponsiveImageSizes = {
|
|
40
|
+
thumbnail: {
|
|
41
|
+
width: 150,
|
|
42
|
+
height: 150,
|
|
43
|
+
fit: 'cover',
|
|
44
|
+
quality: 85,
|
|
45
|
+
format: 'auto'
|
|
46
|
+
},
|
|
47
|
+
small: {
|
|
48
|
+
width: 400,
|
|
49
|
+
fit: 'scale-down',
|
|
50
|
+
quality: 85,
|
|
51
|
+
format: 'auto'
|
|
52
|
+
},
|
|
53
|
+
medium: {
|
|
54
|
+
width: 800,
|
|
55
|
+
fit: 'scale-down',
|
|
56
|
+
quality: 85,
|
|
57
|
+
format: 'auto'
|
|
58
|
+
},
|
|
59
|
+
large: {
|
|
60
|
+
width: 1200,
|
|
61
|
+
fit: 'scale-down',
|
|
62
|
+
quality: 85,
|
|
63
|
+
format: 'auto'
|
|
64
|
+
},
|
|
65
|
+
original: {
|
|
66
|
+
format: 'auto'
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Build Cloudflare Image Resizing URL
|
|
72
|
+
*
|
|
73
|
+
* @param baseUrl - The base URL of your API (e.g., "https://api.perspect.co")
|
|
74
|
+
* @param mediaPath - The path to the media file (e.g., "media/site/image.jpg")
|
|
75
|
+
* @param options - Transform options
|
|
76
|
+
* @returns Cloudflare Image Resizing URL
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const url = buildImageUrl(
|
|
81
|
+
* 'https://api.perspect.co',
|
|
82
|
+
* 'media/mysite/photo.jpg',
|
|
83
|
+
* { width: 400, format: 'webp', quality: 85 }
|
|
84
|
+
* );
|
|
85
|
+
* // Returns: '/cdn-cgi/image/width=400,format=webp,quality=85/https://api.perspect.co/media/mysite/photo.jpg'
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function buildImageUrl(
|
|
89
|
+
baseUrl: string,
|
|
90
|
+
mediaPath: string,
|
|
91
|
+
options?: ImageTransformOptions
|
|
92
|
+
): string {
|
|
93
|
+
// Construct the full source URL
|
|
94
|
+
const sourceUrl = `${baseUrl}/${mediaPath.replace(/^\//, '')}`;
|
|
95
|
+
|
|
96
|
+
if (!options || Object.keys(options).length === 0) {
|
|
97
|
+
// Return original image URL
|
|
98
|
+
return sourceUrl;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Build transform options string
|
|
102
|
+
const params: string[] = [];
|
|
103
|
+
|
|
104
|
+
if (options.width) params.push(`width=${options.width}`);
|
|
105
|
+
if (options.height) params.push(`height=${options.height}`);
|
|
106
|
+
if (options.fit) params.push(`fit=${options.fit}`);
|
|
107
|
+
if (options.gravity) params.push(`gravity=${options.gravity}`);
|
|
108
|
+
if (options.quality) params.push(`quality=${options.quality}`);
|
|
109
|
+
if (options.format) params.push(`format=${options.format}`);
|
|
110
|
+
if (options.sharpen) params.push(`sharpen=${options.sharpen}`);
|
|
111
|
+
if (options.blur) params.push(`blur=${options.blur}`);
|
|
112
|
+
if (options.rotate) params.push(`rotate=${options.rotate}`);
|
|
113
|
+
if (options.dpr) params.push(`dpr=${options.dpr}`);
|
|
114
|
+
if (options.metadata) params.push(`metadata=${options.metadata}`);
|
|
115
|
+
if (options.background) params.push(`background=${options.background}`);
|
|
116
|
+
|
|
117
|
+
if (options.trim) {
|
|
118
|
+
const trimParts: string[] = [];
|
|
119
|
+
if (options.trim.top) trimParts.push(`${options.trim.top}`);
|
|
120
|
+
if (options.trim.right) trimParts.push(`${options.trim.right}`);
|
|
121
|
+
if (options.trim.bottom) trimParts.push(`${options.trim.bottom}`);
|
|
122
|
+
if (options.trim.left) trimParts.push(`${options.trim.left}`);
|
|
123
|
+
if (trimParts.length > 0) {
|
|
124
|
+
params.push(`trim=${trimParts.join(';')}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const queryString = params.join(',');
|
|
129
|
+
|
|
130
|
+
// Cloudflare Image Resizing URL format:
|
|
131
|
+
// /cdn-cgi/image/{options}/{source-image-url}
|
|
132
|
+
// Note: This only works on Cloudflare zones with Image Resizing enabled
|
|
133
|
+
return `/cdn-cgi/image/${queryString}/${sourceUrl}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Generate responsive image URLs for different sizes
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* const urls = generateResponsiveUrls(
|
|
142
|
+
* 'https://api.perspect.co',
|
|
143
|
+
* 'media/mysite/photo.jpg'
|
|
144
|
+
* );
|
|
145
|
+
* // Returns: { thumbnail: '...', small: '...', medium: '...', large: '...', original: '...' }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export function generateResponsiveUrls(
|
|
149
|
+
baseUrl: string,
|
|
150
|
+
mediaPath: string,
|
|
151
|
+
sizes: ResponsiveImageSizes = DEFAULT_IMAGE_SIZES
|
|
152
|
+
): Record<keyof ResponsiveImageSizes, string> {
|
|
153
|
+
return {
|
|
154
|
+
thumbnail: buildImageUrl(baseUrl, mediaPath, sizes.thumbnail),
|
|
155
|
+
small: buildImageUrl(baseUrl, mediaPath, sizes.small),
|
|
156
|
+
medium: buildImageUrl(baseUrl, mediaPath, sizes.medium),
|
|
157
|
+
large: buildImageUrl(baseUrl, mediaPath, sizes.large),
|
|
158
|
+
original: buildImageUrl(baseUrl, mediaPath, sizes.original)
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Generate srcset for responsive images
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* const srcset = generateSrcSet(
|
|
168
|
+
* 'https://api.perspect.co',
|
|
169
|
+
* 'media/mysite/photo.jpg',
|
|
170
|
+
* [400, 800, 1200]
|
|
171
|
+
* );
|
|
172
|
+
* // Returns: "...?width=400 400w, ...?width=800 800w, ...?width=1200 1200w"
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export function generateSrcSet(
|
|
176
|
+
baseUrl: string,
|
|
177
|
+
mediaPath: string,
|
|
178
|
+
widths: number[] = [400, 800, 1200, 1600]
|
|
179
|
+
): string {
|
|
180
|
+
return widths
|
|
181
|
+
.map((width) => {
|
|
182
|
+
const url = buildImageUrl(baseUrl, mediaPath, {
|
|
183
|
+
width,
|
|
184
|
+
fit: 'scale-down',
|
|
185
|
+
quality: 85,
|
|
186
|
+
format: 'auto'
|
|
187
|
+
});
|
|
188
|
+
return `${url} ${width}w`;
|
|
189
|
+
})
|
|
190
|
+
.join(', ');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Generate sizes attribute for responsive images
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* const sizes = generateSizesAttribute();
|
|
199
|
+
* // Returns: "(max-width: 640px) 100vw, (max-width: 768px) 80vw, ..."
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
export function generateSizesAttribute(
|
|
203
|
+
breakpoints: Array<{ maxWidth: string; size: string }> = [
|
|
204
|
+
{ maxWidth: '640px', size: '100vw' },
|
|
205
|
+
{ maxWidth: '768px', size: '80vw' },
|
|
206
|
+
{ maxWidth: '1024px', size: '60vw' },
|
|
207
|
+
{ maxWidth: '1280px', size: '50vw' }
|
|
208
|
+
]
|
|
209
|
+
): string {
|
|
210
|
+
const mediaQueries = breakpoints.map(
|
|
211
|
+
(bp) => `(max-width: ${bp.maxWidth}) ${bp.size}`
|
|
212
|
+
);
|
|
213
|
+
mediaQueries.push('40vw'); // default size
|
|
214
|
+
return mediaQueries.join(', ');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Helper to generate complete responsive image HTML
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* const html = generateResponsiveImageHtml(
|
|
223
|
+
* 'https://api.perspect.co',
|
|
224
|
+
* 'media/mysite/photo.jpg',
|
|
225
|
+
* 'My photo',
|
|
226
|
+
* { className: 'rounded-lg', loading: 'lazy' }
|
|
227
|
+
* );
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
export function generateResponsiveImageHtml(
|
|
231
|
+
baseUrl: string,
|
|
232
|
+
mediaPath: string,
|
|
233
|
+
alt: string,
|
|
234
|
+
options?: {
|
|
235
|
+
className?: string;
|
|
236
|
+
loading?: 'lazy' | 'eager';
|
|
237
|
+
decoding?: 'async' | 'sync' | 'auto';
|
|
238
|
+
sizes?: string;
|
|
239
|
+
widths?: number[];
|
|
240
|
+
}
|
|
241
|
+
): string {
|
|
242
|
+
const srcset = generateSrcSet(baseUrl, mediaPath, options?.widths);
|
|
243
|
+
const sizes = options?.sizes || generateSizesAttribute();
|
|
244
|
+
const src = buildImageUrl(baseUrl, mediaPath, {
|
|
245
|
+
width: 800,
|
|
246
|
+
fit: 'scale-down',
|
|
247
|
+
quality: 85,
|
|
248
|
+
format: 'auto'
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
return `<img
|
|
252
|
+
src="${src}"
|
|
253
|
+
srcset="${srcset}"
|
|
254
|
+
sizes="${sizes}"
|
|
255
|
+
alt="${alt}"
|
|
256
|
+
${options?.className ? `class="${options.className}"` : ''}
|
|
257
|
+
${options?.loading ? `loading="${options.loading}"` : 'loading="lazy"'}
|
|
258
|
+
${options?.decoding ? `decoding="${options.decoding}"` : 'decoding="async"'}
|
|
259
|
+
/>`;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Transform a MediaItem into responsive URLs
|
|
264
|
+
* Convenience function for working with MediaItem objects from the API
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```typescript
|
|
268
|
+
* import { transformMediaItem } from 'perspectapi-ts-sdk';
|
|
269
|
+
*
|
|
270
|
+
* const product = await client.products.getProduct('mysite', 123);
|
|
271
|
+
* const media = product.data.media?.[0];
|
|
272
|
+
*
|
|
273
|
+
* if (media) {
|
|
274
|
+
* const urls = transformMediaItem('https://api.perspect.co', media);
|
|
275
|
+
* console.log(urls.thumbnail); // Cloudflare-transformed thumbnail URL
|
|
276
|
+
* }
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
export function transformMediaItem(
|
|
280
|
+
baseUrl: string,
|
|
281
|
+
media: { link: string } | { r2_key: string; site_name: string },
|
|
282
|
+
sizes?: ResponsiveImageSizes
|
|
283
|
+
): Record<keyof ResponsiveImageSizes, string> {
|
|
284
|
+
// Determine the media path
|
|
285
|
+
let mediaPath: string;
|
|
286
|
+
|
|
287
|
+
if ('link' in media) {
|
|
288
|
+
// Extract path from full URL
|
|
289
|
+
mediaPath = media.link.replace(/^https?:\/\/[^/]+\//, '');
|
|
290
|
+
} else {
|
|
291
|
+
// Construct from r2_key
|
|
292
|
+
mediaPath = `media/${media.site_name}/${media.r2_key.split('/').pop()}`;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return generateResponsiveUrls(baseUrl, mediaPath, sizes);
|
|
296
|
+
}
|