perspectapi-ts-sdk 6.5.9 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +46 -1011
  2. package/dist/chunk-MZ22HQBX.mjs +1451 -0
  3. package/dist/index-BL9-AZpq.d.mts +2227 -0
  4. package/dist/index-BL9-AZpq.d.ts +2227 -0
  5. package/dist/index.d.mts +130 -2221
  6. package/dist/index.d.ts +130 -2221
  7. package/dist/index.js +71 -7
  8. package/dist/index.mjs +13 -1364
  9. package/dist/v2/index.d.mts +1 -0
  10. package/dist/v2/index.d.ts +1 -0
  11. package/dist/v2/index.js +1477 -0
  12. package/dist/v2/index.mjs +40 -0
  13. package/docs/README.md +15 -0
  14. package/docs/v1-deprecated/README.md +9 -0
  15. package/docs/v1-deprecated/examples/README.md +324 -0
  16. package/docs/v1-deprecated/examples/basic-usage.ts +258 -0
  17. package/docs/v1-deprecated/examples/cloudflare-worker.ts +274 -0
  18. package/docs/v1-deprecated/examples/content-query-with-slug-prefix.ts +237 -0
  19. package/docs/v1-deprecated/examples/image-transforms.ts +200 -0
  20. package/docs/v1-deprecated/examples/site-user-checkout.ts +186 -0
  21. package/docs/v1-deprecated/examples/slug-prefix-examples.ts +491 -0
  22. package/docs/v1-deprecated/legacy-docs/caching.md +667 -0
  23. package/docs/v1-deprecated/legacy-docs/contact.md +1396 -0
  24. package/docs/v1-deprecated/legacy-docs/csrf-protection.md +664 -0
  25. package/docs/v1-deprecated/legacy-docs/image-transforms.md +523 -0
  26. package/docs/v1-deprecated/legacy-docs/loaders.md +304 -0
  27. package/docs/v1-deprecated/legacy-docs/newsletter.md +811 -0
  28. package/docs/v1-deprecated/legacy-docs/site-users.md +817 -0
  29. package/docs/v1-deprecated/legacy-notes/CHANGELOG-CHECKOUT.md +143 -0
  30. package/docs/v1-deprecated/legacy-notes/CSRF-CHECKOUT.md +271 -0
  31. package/docs/v1-deprecated/legacy-notes/IMAGE_TRANSFORMS_PORT.md +298 -0
  32. package/docs/v1-deprecated/sdk-readme.md +1076 -0
  33. package/examples/README.md +19 -0
  34. package/examples/basic-v2.ts +37 -0
  35. package/llms.txt +25 -0
  36. package/package.json +18 -7
  37. package/src/client/api-keys-client.ts +4 -0
  38. package/src/client/auth-client.ts +4 -0
  39. package/src/client/base-client.ts +7 -0
  40. package/src/client/bundles-client.ts +4 -0
  41. package/src/client/categories-client.ts +4 -0
  42. package/src/client/checkout-client.ts +4 -0
  43. package/src/client/contact-client.ts +4 -0
  44. package/src/client/content-client.ts +4 -0
  45. package/src/client/newsletter-client.ts +4 -0
  46. package/src/client/newsletter-management-client.ts +4 -0
  47. package/src/client/organizations-client.ts +4 -0
  48. package/src/client/products-client.ts +4 -0
  49. package/src/client/site-users-client.ts +10 -1
  50. package/src/client/sites-client.ts +4 -0
  51. package/src/client/webhooks-client.ts +4 -0
  52. package/src/deprecation.ts +2 -1
  53. package/src/index.ts +2 -1
  54. package/src/loaders.ts +59 -0
  55. package/src/perspect-api-client.ts +2 -2
  56. package/src/v2/client/orders-client.ts +89 -6
  57. package/src/v2/types.ts +3 -0
@@ -0,0 +1,523 @@
1
+ # Image Transformations with Cloudflare Image Resizing
2
+
3
+ > Deprecated v1 material. Do not copy these examples into new code. v1 sunsets
4
+ > on 2026-06-01; use `createPerspectApiV2Client` from
5
+ > `perspectapi-ts-sdk/v2` and `/api/v2`.
6
+
7
+ The SDK provides utilities to easily transform images using Cloudflare's Image Resizing service. This allows you to resize, optimize, and transform images on-the-fly without pre-generating thumbnails.
8
+
9
+ ## Overview
10
+
11
+ **Benefits:**
12
+ - ✅ **No pre-generated thumbnails** - Images are resized on demand
13
+ - ✅ **Automatic format optimization** - Serves WebP/AVIF when supported
14
+ - ✅ **Responsive images** - Browser requests the size it needs
15
+ - ✅ **CDN caching** - Transformed images are cached at the edge
16
+ - ✅ **Bandwidth savings** - Only serve the size needed
17
+
18
+ ## Quick Start
19
+
20
+ ```typescript
21
+ import {
22
+ buildImageUrl,
23
+ generateResponsiveUrls,
24
+ transformMediaItem
25
+ } from 'perspectapi-ts-sdk';
26
+
27
+ // Get a product with media
28
+ const product = await client.products.getProduct('mysite', 123);
29
+ const media = product.data.media?.[0];
30
+
31
+ if (media) {
32
+ // Generate all responsive sizes
33
+ const urls = transformMediaItem('https://api.perspect.comm', media);
34
+
35
+ console.log(urls.thumbnail); // 150x150 cover crop
36
+ console.log(urls.small); // 400px wide
37
+ console.log(urls.medium); // 800px wide
38
+ console.log(urls.large); // 1200px wide
39
+ console.log(urls.original); // Original with auto format
40
+ }
41
+ ```
42
+
43
+ ## Core Functions
44
+
45
+ ### `buildImageUrl()`
46
+
47
+ Build a single transformed image URL with custom options.
48
+
49
+ ```typescript
50
+ import { buildImageUrl } from 'perspectapi-ts-sdk';
51
+
52
+ const url = buildImageUrl(
53
+ 'https://api.perspect.comm',
54
+ 'media/mysite/photo.jpg',
55
+ {
56
+ width: 400,
57
+ height: 300,
58
+ fit: 'cover',
59
+ quality: 85,
60
+ format: 'webp'
61
+ }
62
+ );
63
+ ```
64
+
65
+ **Parameters:**
66
+ - `baseUrl` - Your API base URL (e.g., `'https://api.perspect.comm'`)
67
+ - `mediaPath` - Path to the media file (e.g., `'media/mysite/photo.jpg'`)
68
+ - `options` - Transform options (optional)
69
+
70
+ **Transform Options:**
71
+
72
+ | Option | Type | Values | Description |
73
+ |--------|------|--------|-------------|
74
+ | `width` | number | 1-9999 | Target width in pixels |
75
+ | `height` | number | 1-9999 | Target height in pixels |
76
+ | `fit` | string | `scale-down`, `contain`, `cover`, `crop`, `pad` | Resize mode |
77
+ | `gravity` | string | `auto`, `left`, `right`, `top`, `bottom`, `center` | Crop focus point |
78
+ | `quality` | number | 1-100 | JPEG/WebP quality (default: 85) |
79
+ | `format` | string | `auto`, `avif`, `webp`, `jpeg`, `png` | Output format |
80
+ | `dpr` | number | 1, 2, 3 | Device pixel ratio |
81
+ | `sharpen` | number | 0-10 | Sharpening amount |
82
+ | `blur` | number | 0-250 | Blur amount |
83
+ | `rotate` | number | 0, 90, 180, 270 | Rotation degrees |
84
+
85
+ ### `generateResponsiveUrls()`
86
+
87
+ Generate multiple sizes at once for responsive images.
88
+
89
+ ```typescript
90
+ import { generateResponsiveUrls } from 'perspectapi-ts-sdk';
91
+
92
+ const urls = generateResponsiveUrls(
93
+ 'https://api.perspect.comm',
94
+ 'media/mysite/photo.jpg'
95
+ );
96
+
97
+ // Returns:
98
+ // {
99
+ // thumbnail: '...?width=150&height=150&fit=cover',
100
+ // small: '...?width=400',
101
+ // medium: '...?width=800',
102
+ // large: '...?width=1200',
103
+ // original: '...'
104
+ // }
105
+ ```
106
+
107
+ ### `transformMediaItem()`
108
+
109
+ Convenience function for working with `MediaItem` objects from the API.
110
+
111
+ ```typescript
112
+ import { transformMediaItem } from 'perspectapi-ts-sdk';
113
+
114
+ // From a product
115
+ const product = await client.products.getProduct('mysite', 123);
116
+ const media = product.data.media?.[0];
117
+
118
+ if (media) {
119
+ const urls = transformMediaItem('https://api.perspect.comm', media);
120
+ // Use urls.thumbnail, urls.small, etc.
121
+ }
122
+
123
+ // From content
124
+ const content = await client.content.getContent('mysite', { limit: 10 });
125
+ const firstPost = content.data?.[0];
126
+ // Extract media from content and transform similarly
127
+ ```
128
+
129
+ ### `generateSrcSet()`
130
+
131
+ Generate `srcset` attribute for responsive images.
132
+
133
+ ```typescript
134
+ import { generateSrcSet } from 'perspectapi-ts-sdk';
135
+
136
+ const srcset = generateSrcSet(
137
+ 'https://api.perspect.comm',
138
+ 'media/mysite/photo.jpg',
139
+ [400, 800, 1200, 1600]
140
+ );
141
+
142
+ // Returns: "/cdn-cgi/image/width=400.../photo.jpg 400w, /cdn-cgi/image/width=800.../photo.jpg 800w, ..."
143
+ ```
144
+
145
+ Use in HTML:
146
+
147
+ ```html
148
+ <img
149
+ src="/cdn-cgi/image/width=800.../photo.jpg"
150
+ srcset="..."
151
+ sizes="(max-width: 640px) 100vw, (max-width: 1024px) 80vw, 60vw"
152
+ alt="Photo"
153
+ />
154
+ ```
155
+
156
+ ### `generateResponsiveImageHtml()`
157
+
158
+ Generate complete responsive image HTML.
159
+
160
+ ```typescript
161
+ import { generateResponsiveImageHtml } from 'perspectapi-ts-sdk';
162
+
163
+ const html = generateResponsiveImageHtml(
164
+ 'https://api.perspect.comm',
165
+ 'media/mysite/photo.jpg',
166
+ 'My photo',
167
+ {
168
+ className: 'rounded-lg shadow-md',
169
+ loading: 'lazy',
170
+ widths: [400, 800, 1200]
171
+ }
172
+ );
173
+
174
+ // Returns complete <img> tag with srcset, sizes, etc.
175
+ ```
176
+
177
+ ## Common Use Cases
178
+
179
+ ### 1. Product Images (E-commerce)
180
+
181
+ ```typescript
182
+ import { createPerspectApiClient, transformMediaItem } from 'perspectapi-ts-sdk';
183
+
184
+ const client = createPerspectApiClient({
185
+ baseUrl: 'https://api.perspect.comm',
186
+ apiKey: 'your-api-key'
187
+ });
188
+
189
+ // Get products
190
+ const products = await client.products.getProducts('mysite', {
191
+ limit: 20,
192
+ published: true
193
+ });
194
+
195
+ // Transform product images
196
+ const productsWithImages = products.data.map(product => {
197
+ const media = product.media?.[0];
198
+ const imageUrls = media
199
+ ? transformMediaItem('https://api.perspect.comm', media)
200
+ : null;
201
+
202
+ return {
203
+ ...product,
204
+ imageUrls
205
+ };
206
+ });
207
+
208
+ // Use in your UI
209
+ productsWithImages.forEach(product => {
210
+ console.log(`Thumbnail: ${product.imageUrls?.thumbnail}`);
211
+ console.log(`Large: ${product.imageUrls?.large}`);
212
+ });
213
+ ```
214
+
215
+ ### 2. Blog Post Featured Images
216
+
217
+ ```typescript
218
+ import { loadPosts, buildImageUrl } from 'perspectapi-ts-sdk';
219
+
220
+ const posts = await loadPosts({
221
+ client,
222
+ siteName: 'myblog',
223
+ limit: 10
224
+ });
225
+
226
+ posts.forEach(post => {
227
+ if (post.featured_image) {
228
+ const featuredImage = buildImageUrl(
229
+ 'https://api.perspect.comm',
230
+ post.featured_image,
231
+ {
232
+ width: 800,
233
+ fit: 'scale-down',
234
+ format: 'auto',
235
+ quality: 85
236
+ }
237
+ );
238
+ console.log(`Featured image: ${featuredImage}`);
239
+ }
240
+ });
241
+ ```
242
+
243
+ ### 3. Responsive Image Component (React)
244
+
245
+ ```tsx
246
+ import { transformMediaItem, type MediaItem } from 'perspectapi-ts-sdk';
247
+
248
+ interface ResponsiveImageProps {
249
+ media: MediaItem;
250
+ alt: string;
251
+ className?: string;
252
+ }
253
+
254
+ export function ResponsiveImage({ media, alt, className }: ResponsiveImageProps) {
255
+ const urls = transformMediaItem('https://api.perspect.comm', media);
256
+
257
+ return (
258
+ <img
259
+ src={urls.medium}
260
+ srcSet={`
261
+ ${urls.small} 400w,
262
+ ${urls.medium} 800w,
263
+ ${urls.large} 1200w
264
+ `}
265
+ sizes="(max-width: 640px) 100vw, (max-width: 1024px) 80vw, 60vw"
266
+ alt={alt}
267
+ className={className}
268
+ loading="lazy"
269
+ decoding="async"
270
+ />
271
+ );
272
+ }
273
+
274
+ // Usage
275
+ <ResponsiveImage
276
+ media={product.media[0]}
277
+ alt={product.name}
278
+ className="rounded-lg"
279
+ />
280
+ ```
281
+
282
+ ### 4. Custom Sizes
283
+
284
+ ```typescript
285
+ import { generateResponsiveUrls, type ResponsiveImageSizes } from 'perspectapi-ts-sdk';
286
+
287
+ // Define custom sizes for your use case
288
+ const customSizes: ResponsiveImageSizes = {
289
+ thumbnail: {
290
+ width: 100,
291
+ height: 100,
292
+ fit: 'cover',
293
+ quality: 75,
294
+ format: 'auto'
295
+ },
296
+ small: {
297
+ width: 300,
298
+ fit: 'scale-down',
299
+ quality: 85,
300
+ format: 'auto'
301
+ },
302
+ medium: {
303
+ width: 600,
304
+ fit: 'scale-down',
305
+ quality: 85,
306
+ format: 'auto'
307
+ },
308
+ large: {
309
+ width: 1000,
310
+ fit: 'scale-down',
311
+ quality: 85,
312
+ format: 'auto'
313
+ },
314
+ original: {
315
+ format: 'auto'
316
+ }
317
+ };
318
+
319
+ const urls = generateResponsiveUrls(
320
+ 'https://api.perspect.comm',
321
+ 'media/mysite/photo.jpg',
322
+ customSizes
323
+ );
324
+ ```
325
+
326
+ ### 5. High DPR (Retina) Displays
327
+
328
+ ```typescript
329
+ import { buildImageUrl } from 'perspectapi-ts-sdk';
330
+
331
+ // For retina displays
332
+ const retinaUrl = buildImageUrl(
333
+ 'https://api.perspect.comm',
334
+ 'media/mysite/photo.jpg',
335
+ {
336
+ width: 400,
337
+ dpr: 2, // 2x resolution
338
+ format: 'auto',
339
+ quality: 85
340
+ }
341
+ );
342
+ ```
343
+
344
+ ## Framework Examples
345
+
346
+ ### Next.js App Router
347
+
348
+ ```tsx
349
+ // app/products/[slug]/page.tsx
350
+ import { createPerspectApiClient, transformMediaItem } from 'perspectapi-ts-sdk';
351
+ import Image from 'next/image';
352
+
353
+ const client = createPerspectApiClient({
354
+ baseUrl: process.env.NEXT_PUBLIC_API_URL!,
355
+ apiKey: process.env.API_KEY!
356
+ });
357
+
358
+ export default async function ProductPage({ params }: { params: { slug: string } }) {
359
+ const product = await client.products.getProductBySlug('mysite', params.slug);
360
+ const media = product.data.media?.[0];
361
+
362
+ if (!media) return <div>No image</div>;
363
+
364
+ const urls = transformMediaItem(process.env.NEXT_PUBLIC_API_URL!, media);
365
+
366
+ return (
367
+ <div>
368
+ <Image
369
+ src={urls.large}
370
+ alt={product.data.name || ''}
371
+ width={1200}
372
+ height={800}
373
+ className="rounded-lg"
374
+ />
375
+ </div>
376
+ );
377
+ }
378
+ ```
379
+
380
+ ### Remix Loader
381
+
382
+ ```typescript
383
+ // app/routes/products.$slug.tsx
384
+ import { json, type LoaderFunctionArgs } from '@remix-run/node';
385
+ import { useLoaderData } from '@remix-run/react';
386
+ import { createPerspectApiClient, transformMediaItem } from 'perspectapi-ts-sdk';
387
+
388
+ export async function loader({ params }: LoaderFunctionArgs) {
389
+ const client = createPerspectApiClient({
390
+ baseUrl: process.env.API_URL!,
391
+ apiKey: process.env.API_KEY!
392
+ });
393
+
394
+ const product = await client.products.getProductBySlug('mysite', params.slug!);
395
+ const media = product.data.media?.[0];
396
+
397
+ const imageUrls = media
398
+ ? transformMediaItem(process.env.API_URL!, media)
399
+ : null;
400
+
401
+ return json({ product: product.data, imageUrls });
402
+ }
403
+
404
+ export default function ProductPage() {
405
+ const { product, imageUrls } = useLoaderData<typeof loader>();
406
+
407
+ return (
408
+ <div>
409
+ {imageUrls && (
410
+ <img
411
+ src={imageUrls.medium}
412
+ srcSet={`
413
+ ${imageUrls.small} 400w,
414
+ ${imageUrls.medium} 800w,
415
+ ${imageUrls.large} 1200w
416
+ `}
417
+ sizes="(max-width: 640px) 100vw, 800px"
418
+ alt={product.name}
419
+ loading="lazy"
420
+ />
421
+ )}
422
+ </div>
423
+ );
424
+ }
425
+ ```
426
+
427
+ ### Cloudflare Workers
428
+
429
+ ```typescript
430
+ import { createPerspectApiClient, transformMediaItem } from 'perspectapi-ts-sdk';
431
+
432
+ export default {
433
+ async fetch(request: Request, env: Env): Promise<Response> {
434
+ const client = createPerspectApiClient({
435
+ baseUrl: env.API_URL,
436
+ apiKey: env.API_KEY
437
+ });
438
+
439
+ const products = await client.products.getProducts('mysite', {
440
+ limit: 10,
441
+ published: true
442
+ });
443
+
444
+ const productsWithImages = products.data.map(product => {
445
+ const media = product.media?.[0];
446
+ const imageUrls = media
447
+ ? transformMediaItem(env.API_URL, media)
448
+ : null;
449
+
450
+ return {
451
+ id: product.id,
452
+ name: product.name,
453
+ price: product.price,
454
+ thumbnail: imageUrls?.thumbnail,
455
+ image: imageUrls?.medium
456
+ };
457
+ });
458
+
459
+ return Response.json(productsWithImages);
460
+ }
461
+ };
462
+ ```
463
+
464
+ ## Best Practices
465
+
466
+ 1. **Always use `format=auto`** - Let Cloudflare choose the best format (WebP, AVIF, etc.)
467
+ 2. **Set appropriate quality** - 85 is a good default, 75 for thumbnails
468
+ 3. **Use `fit=scale-down`** - Prevents upscaling small images
469
+ 4. **Add `loading=lazy`** - Improves page load performance
470
+ 5. **Use srcset for responsive** - Let browser choose appropriate size
471
+ 6. **Cache aggressively** - Images rarely change, use long cache times
472
+
473
+ ## Performance Benefits
474
+
475
+ ### Storage Savings
476
+ - **Before**: 5 sizes × file size = 5× storage
477
+ - **After**: 1 original file only
478
+
479
+ ### Upload Time
480
+ - **Before**: Generate all sizes on upload
481
+ - **After**: Store original only
482
+
483
+ ### Flexibility
484
+ - **Before**: Fixed sizes, must regenerate to change
485
+ - **After**: Any size on demand
486
+
487
+ ### Caching
488
+ - First request: Cloudflare resizes and caches
489
+ - Subsequent requests: Served from edge cache (1 year TTL)
490
+ - Global CDN: Fast delivery worldwide
491
+
492
+ ## Requirements
493
+
494
+ - Cloudflare Image Resizing must be enabled on your zone
495
+ - Images must be served through Cloudflare
496
+ - Free tier: 100,000 images/month
497
+ - Paid: $5 per 100,000 images after free tier
498
+
499
+ ## Troubleshooting
500
+
501
+ ### Images not transforming?
502
+
503
+ Check that:
504
+ - The URL includes the `/cdn-cgi/image/` prefix
505
+ - The source image is accessible
506
+ - Cloudflare Image Resizing is enabled on your zone
507
+
508
+ ### Images loading slowly?
509
+
510
+ - First request is slower (resize + cache)
511
+ - Subsequent requests are fast (served from cache)
512
+ - Consider preloading critical images
513
+
514
+ ### Wrong format served?
515
+
516
+ - Use `format=auto` to let Cloudflare decide
517
+ - Browser must support the format (check Accept header)
518
+
519
+ ## Resources
520
+
521
+ - [Cloudflare Image Resizing Docs](https://developers.cloudflare.com/images/transform-images/)
522
+ - [Responsive Images Guide](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images)
523
+ - [WebP Format](https://developers.google.com/speed/webp)