musora-content-services 1.4.2 → 1.4.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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.4.3](https://github.com/railroadmedia/musora-content-services/compare/v1.4.2...v1.4.3) (2025-03-31)
|
|
6
|
+
|
|
5
7
|
### [1.4.2](https://github.com/railroadmedia/musora-content-services/compare/v1.4.1...v1.4.2) (2025-03-28)
|
|
6
8
|
|
|
7
9
|
### [1.4.1](https://github.com/railroadmedia/musora-content-services/compare/v1.4.0...v1.4.1) (2025-03-25)
|
package/package.json
CHANGED
|
File without changes
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds an optimized image URL using both Sanity and Cloudflare Image Resizing services
|
|
3
|
+
*
|
|
4
|
+
* This function takes a Sanity CDN URL and image transformation parameters, then:
|
|
5
|
+
* 1. Adds appropriate transformation parameters to the Sanity URL
|
|
6
|
+
* 2. Wraps the resulting URL with Cloudflare's Image Resizing service
|
|
7
|
+
* 3. Maps compatible parameters between the two services for optimal results
|
|
8
|
+
*
|
|
9
|
+
* @param {string} url - The original image URL, typically from Sanity CDN
|
|
10
|
+
* @param {Object} options - Image transformation options
|
|
11
|
+
* @param {number} [options.width] - Desired image width in pixels
|
|
12
|
+
* @param {number} [options.height] - Desired image height in pixels
|
|
13
|
+
* @param {number} [options.quality] - Image quality (1-100)
|
|
14
|
+
* @param {string} [options.fit] - Resize strategy: 'cover', 'contain', 'scale-down', 'none'
|
|
15
|
+
* @param {string} [options.gravity] - Content positioning: 'auto', 'top', 'bottom', 'left', 'right', etc.
|
|
16
|
+
* @param {string} [options.crop] - Sanity-specific crop mode
|
|
17
|
+
* @param {string} [options.format] - Image format: 'auto', 'webp', 'jpeg', 'png', etc.
|
|
18
|
+
* @param {number} [options.blur] - Blur amount
|
|
19
|
+
* @param {number} [options.sharpen] - Sharpen amount
|
|
20
|
+
* @param {number} [options.saturation] - Saturation adjustment
|
|
21
|
+
* @param {number} [options.brightness] - Brightness adjustment
|
|
22
|
+
* @param {number} [options.contrast] - Contrast adjustment
|
|
23
|
+
* @param {number} [options.gamma] - Gamma adjustment
|
|
24
|
+
* @param {number} [options.rotate] - Rotation angle in degrees
|
|
25
|
+
* @param {number} [options.dpr] - Device pixel ratio for responsive images
|
|
26
|
+
* @param {string} [options.background] - Background color (e.g., '#FFFFFF')
|
|
27
|
+
* @param {number} [options.padding] - Padding to add around the image
|
|
28
|
+
* @param {boolean} [options.anim] - Whether to preserve animation in GIFs
|
|
29
|
+
* @param {string} [options.onerror] - Error handling strategy
|
|
30
|
+
* @param {string} [options.compression] - Compression strategy
|
|
31
|
+
* @param {string} [options.fetchFormat] - Format to request from origin
|
|
32
|
+
* @param {string} [options.sampling] - Chroma subsampling strategy
|
|
33
|
+
* @param {string} [options.metadata] - Metadata to preserve
|
|
34
|
+
*
|
|
35
|
+
* @returns {string} The fully constructed image URL with transformations
|
|
36
|
+
*/
|
|
37
|
+
export function buildImageSRC(url, options = {}) {
|
|
38
|
+
// Process Sanity URL first if applicable
|
|
39
|
+
if (url.includes('cdn.sanity.io')) {
|
|
40
|
+
url = applySanityTransformations(url, options)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Then apply Cloudflare transformations
|
|
44
|
+
return applyCloudflareWrapper(url, options)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Applies Sanity-specific image transformations to a Sanity CDN URL
|
|
49
|
+
*
|
|
50
|
+
* @param {string} url - The Sanity CDN URL
|
|
51
|
+
* @param {Object} options - Image transformation options
|
|
52
|
+
* @returns {string} URL with Sanity transformations applied
|
|
53
|
+
* @private
|
|
54
|
+
*/
|
|
55
|
+
export function applySanityTransformations(url, options) {
|
|
56
|
+
const { width, height, quality } = options
|
|
57
|
+
|
|
58
|
+
const sanityOptions = []
|
|
59
|
+
|
|
60
|
+
// Dimensions
|
|
61
|
+
if (width) sanityOptions.push(`w=${width}`)
|
|
62
|
+
if (height) sanityOptions.push(`h=${height}`)
|
|
63
|
+
if (quality) sanityOptions.push(`q=${quality}`)
|
|
64
|
+
|
|
65
|
+
// Add parameters to Sanity URL
|
|
66
|
+
const sanityQuery = sanityOptions.length > 0 ? `?${sanityOptions.join('&')}` : ''
|
|
67
|
+
return `${url}${sanityQuery}`
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Wraps a URL with Cloudflare's Image Resizing service and applies transformations
|
|
72
|
+
*
|
|
73
|
+
* @param {string} url - The source URL (can be any image URL)
|
|
74
|
+
* @param {Object} options - Image transformation options
|
|
75
|
+
* @returns {string} URL with Cloudflare transformations applied
|
|
76
|
+
* @private
|
|
77
|
+
*/
|
|
78
|
+
export function applyCloudflareWrapper(url, options) {
|
|
79
|
+
const {
|
|
80
|
+
width,
|
|
81
|
+
height,
|
|
82
|
+
quality,
|
|
83
|
+
fit,
|
|
84
|
+
gravity,
|
|
85
|
+
format,
|
|
86
|
+
blur,
|
|
87
|
+
sharpen,
|
|
88
|
+
brightness,
|
|
89
|
+
contrast,
|
|
90
|
+
gamma,
|
|
91
|
+
rotate,
|
|
92
|
+
dpr,
|
|
93
|
+
background,
|
|
94
|
+
padding,
|
|
95
|
+
anim,
|
|
96
|
+
onerror,
|
|
97
|
+
compression,
|
|
98
|
+
fetchFormat,
|
|
99
|
+
sampling,
|
|
100
|
+
metadata,
|
|
101
|
+
} = options
|
|
102
|
+
|
|
103
|
+
const cloudflareOptions = []
|
|
104
|
+
|
|
105
|
+
// Build Cloudflare options - required parameters
|
|
106
|
+
if (width) cloudflareOptions.push(`width=${width}`)
|
|
107
|
+
if (height) cloudflareOptions.push(`height=${height}`)
|
|
108
|
+
if (quality) cloudflareOptions.push(`quality=${quality}`)
|
|
109
|
+
|
|
110
|
+
// Add optional Cloudflare parameters
|
|
111
|
+
if (format) cloudflareOptions.push(`format=${format}`)
|
|
112
|
+
if (fit) cloudflareOptions.push(`fit=${fit}`)
|
|
113
|
+
if (gravity) cloudflareOptions.push(`gravity=${gravity}`)
|
|
114
|
+
|
|
115
|
+
if (sharpen !== null && sharpen !== undefined) cloudflareOptions.push(`sharpen=${sharpen}`)
|
|
116
|
+
if (blur !== null && blur !== undefined) cloudflareOptions.push(`blur=${blur}`)
|
|
117
|
+
if (brightness !== null && brightness !== undefined)
|
|
118
|
+
cloudflareOptions.push(`brightness=${brightness}`)
|
|
119
|
+
if (contrast !== null && contrast !== undefined) cloudflareOptions.push(`contrast=${contrast}`)
|
|
120
|
+
if (gamma !== null && gamma !== undefined) cloudflareOptions.push(`gamma=${gamma}`)
|
|
121
|
+
if (rotate !== null && rotate !== undefined) cloudflareOptions.push(`rotate=${rotate}`)
|
|
122
|
+
if (dpr !== null && dpr !== undefined) cloudflareOptions.push(`dpr=${dpr}`)
|
|
123
|
+
|
|
124
|
+
if (metadata !== null && metadata !== undefined) cloudflareOptions.push(`metadata=${metadata}`)
|
|
125
|
+
if (onerror !== null && onerror !== undefined) cloudflareOptions.push(`onerror=${onerror}`)
|
|
126
|
+
if (anim === false) cloudflareOptions.push('anim=false')
|
|
127
|
+
if (background !== null && background !== undefined)
|
|
128
|
+
cloudflareOptions.push(`background=${background}`)
|
|
129
|
+
if (fetchFormat !== null && fetchFormat !== undefined)
|
|
130
|
+
cloudflareOptions.push(`fetchFormat=${fetchFormat}`)
|
|
131
|
+
if (compression !== null && compression !== undefined)
|
|
132
|
+
cloudflareOptions.push(`compression=${compression}`)
|
|
133
|
+
if (sampling !== null && sampling !== undefined) cloudflareOptions.push(`sampling=${sampling}`)
|
|
134
|
+
if (padding !== null && padding !== undefined) cloudflareOptions.push(`padding=${padding}`)
|
|
135
|
+
|
|
136
|
+
const optionsString = cloudflareOptions.length > 0 ? cloudflareOptions.join(',') : ''
|
|
137
|
+
|
|
138
|
+
return `https://www.musora.com/cdn-cgi/image/${optionsString}/${url}`
|
|
139
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verifies if an image URL follows best practices for optimization
|
|
3
|
+
*
|
|
4
|
+
* This function checks whether:
|
|
5
|
+
* 1. Sanity CDN images include query parameters for optimization
|
|
6
|
+
* 2. Direct S3 images are avoided (should use CDN instead)
|
|
7
|
+
*
|
|
8
|
+
* @param {string} src - The image source URL to verify
|
|
9
|
+
* @returns {void}
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Check a direct Sanity URL
|
|
13
|
+
* verifyImageSRC('https://cdn.sanity.io/images/4032r8py/staging/504c4e3393170f937a579de6f3c75c457b0c9e65-640x360.jpg');
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Check a Sanity URL inside a Cloudflare URL
|
|
17
|
+
* verifyImageSRC('https://www.musora.com/cdn-cgi/image/width=500,quality=95/https://cdn.sanity.io/images/4032r8py/staging/504c4e3393170f937a579de6f3c75c457b0c9e65-640x360.jpg');
|
|
18
|
+
*/
|
|
19
|
+
export function verifyImageSRC(src) {
|
|
20
|
+
// Exit early if the URL is empty
|
|
21
|
+
if (!src) return
|
|
22
|
+
|
|
23
|
+
// Check for S3 direct URLs
|
|
24
|
+
if (isBucketUrl(src)) {
|
|
25
|
+
warnAboutDirectS3Url(src)
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Check for Sanity URLs
|
|
30
|
+
if (src.includes('cdn.sanity.io')) {
|
|
31
|
+
verifySanityUrl(src)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Checks if a URL is a direct link to an S3 bucket
|
|
37
|
+
*
|
|
38
|
+
* @param {string} url - The URL to check
|
|
39
|
+
* @returns {boolean} True if the URL is a direct S3 bucket URL
|
|
40
|
+
* @private
|
|
41
|
+
*/
|
|
42
|
+
export function isBucketUrl(url) {
|
|
43
|
+
// Check for common S3 patterns
|
|
44
|
+
return (
|
|
45
|
+
url.includes('.s3.amazonaws.com') ||
|
|
46
|
+
url.includes('s3.us-') ||
|
|
47
|
+
url.includes('amazonaws.com/') ||
|
|
48
|
+
(url.includes('musora-') && url.includes('.s3.'))
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Issues a warning about using direct S3 URLs instead of a CDN
|
|
54
|
+
*
|
|
55
|
+
* @param {string} url - The S3 URL that triggered the warning
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
function warnAboutDirectS3Url(url) {
|
|
59
|
+
// Only warn in development mode
|
|
60
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
61
|
+
console.warn(`WARNING: Direct S3 bucket URL detected: ${url}
|
|
62
|
+
This is not recommended. Use Cloudfront or another CDN for better performance.`)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Extracts a Sanity URL from a potentially Cloudflare-wrapped URL
|
|
68
|
+
*
|
|
69
|
+
* @param {string} url - The URL to process
|
|
70
|
+
* @returns {string} The extracted Sanity URL
|
|
71
|
+
* @private
|
|
72
|
+
*/
|
|
73
|
+
export function extractSanityUrl(url) {
|
|
74
|
+
// If this is a Cloudflare URL, extract the Sanity portion
|
|
75
|
+
if (url.includes('/cdn-cgi/image/')) {
|
|
76
|
+
// Split the URL to get the portion after /cdn-cgi/image/[parameters]/
|
|
77
|
+
const parts = url.split('/cdn-cgi/image/')
|
|
78
|
+
if (parts.length > 1) {
|
|
79
|
+
// Get everything after the first / that follows the Cloudflare parameters
|
|
80
|
+
const cfParamsAndSanityUrl = parts[1]
|
|
81
|
+
const slashIndex = cfParamsAndSanityUrl.indexOf('/', 0)
|
|
82
|
+
if (slashIndex !== -1) {
|
|
83
|
+
let sanityUrl = cfParamsAndSanityUrl.substring(slashIndex + 1)
|
|
84
|
+
return sanityUrl
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// If not a Cloudflare URL or extraction failed, return the original URL
|
|
90
|
+
return url
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Verifies if a Sanity CDN image URL includes optimization parameters
|
|
95
|
+
*
|
|
96
|
+
* @param {string} src - The Sanity image URL to verify
|
|
97
|
+
* @private
|
|
98
|
+
*/
|
|
99
|
+
function verifySanityUrl(src) {
|
|
100
|
+
// Extract the Sanity URL if it's wrapped in a Cloudflare URL
|
|
101
|
+
const sanityUrl = extractSanityUrl(src)
|
|
102
|
+
|
|
103
|
+
// Check if the Sanity URL has parameters (any query string)
|
|
104
|
+
const hasParameters = sanityUrl.includes('?')
|
|
105
|
+
|
|
106
|
+
// Warn if no parameters are found
|
|
107
|
+
if (!hasParameters) {
|
|
108
|
+
// Only warn in development mode
|
|
109
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
110
|
+
console.warn(`WARNING: Sanity CDN URL without parameters detected: ${src}
|
|
111
|
+
This may cause performance issues. Consider adding image transformations using the buildImageSRC MCS service.`)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { buildImageSRC, applySanityTransformations } = require('../src/services/imageSRCBuilder.js')
|
|
2
|
+
|
|
3
|
+
describe('imageSRCBuilder', function () {
|
|
4
|
+
beforeEach(() => {})
|
|
5
|
+
|
|
6
|
+
test('applySanityTransformations', async () => {
|
|
7
|
+
const url =
|
|
8
|
+
'https://cdn.sanity.io/images/4032r8py/production/83c3b6e7354a46c605804c093f707daa4e3f8f25-8000x4500.png'
|
|
9
|
+
const width = 500
|
|
10
|
+
const height = 100
|
|
11
|
+
const quality = 95
|
|
12
|
+
const resultingURL = applySanityTransformations(url, {
|
|
13
|
+
width: width,
|
|
14
|
+
quality: quality,
|
|
15
|
+
height: height,
|
|
16
|
+
})
|
|
17
|
+
const expected = `${url}?w=${width}&h=${height}&q=${quality}`
|
|
18
|
+
|
|
19
|
+
expect(resultingURL).toStrictEqual(expected)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('buildImageSRC', async () => {
|
|
23
|
+
const url = 'https://d2vyvo0tyx8ig5.cloudfront.net/books/foundations/level-2.jpg'
|
|
24
|
+
const width = 500
|
|
25
|
+
const height = 100
|
|
26
|
+
const quality = 95
|
|
27
|
+
const resultingURL = buildImageSRC(url, {
|
|
28
|
+
width: width,
|
|
29
|
+
quality: quality,
|
|
30
|
+
height: height,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const expected = `https://www.musora.com/cdn-cgi/image/width=${width},height=${height},quality=${quality}/${url}`
|
|
34
|
+
|
|
35
|
+
expect(resultingURL).toStrictEqual(expected)
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Mock console.warn to avoid cluttering test output and to verify warnings
|
|
2
|
+
import { extractSanityUrl, isBucketUrl, verifyImageSRC } from '../src/services/imageSRCVerify.js'
|
|
3
|
+
|
|
4
|
+
const originalConsoleWarn = console.warn
|
|
5
|
+
const originalConsoleError = console.error
|
|
6
|
+
const originalNodeEnv = process.env.NODE_ENV
|
|
7
|
+
|
|
8
|
+
describe('Image URL Verification', () => {
|
|
9
|
+
let consoleWarnMock
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
// Mock console.warn and console.error
|
|
13
|
+
consoleWarnMock = jest.fn()
|
|
14
|
+
console.warn = consoleWarnMock
|
|
15
|
+
console.error = jest.fn()
|
|
16
|
+
|
|
17
|
+
// Set NODE_ENV to development for all tests
|
|
18
|
+
process.env.NODE_ENV = 'development'
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
// Restore the original console methods and NODE_ENV
|
|
23
|
+
console.warn = originalConsoleWarn
|
|
24
|
+
console.error = originalConsoleError
|
|
25
|
+
process.env.NODE_ENV = originalNodeEnv
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('verifyImageSRC', () => {
|
|
29
|
+
test('should not warn for Sanity URL with parameters', () => {
|
|
30
|
+
// Arrange
|
|
31
|
+
const url =
|
|
32
|
+
'https://cdn.sanity.io/images/4032r8py/staging/504c4e3393170f937a579de6f3c75c457b0c9e65-640x360.jpg?w=500&q=95'
|
|
33
|
+
|
|
34
|
+
// Act
|
|
35
|
+
verifyImageSRC(url)
|
|
36
|
+
|
|
37
|
+
// Assert
|
|
38
|
+
expect(consoleWarnMock).not.toHaveBeenCalled()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('should warn for Sanity URL without parameters', () => {
|
|
42
|
+
// Arrange
|
|
43
|
+
const url =
|
|
44
|
+
'https://cdn.sanity.io/images/4032r8py/staging/504c4e3393170f937a579de6f3c75c457b0c9e65-640x360.jpg'
|
|
45
|
+
|
|
46
|
+
// Act
|
|
47
|
+
verifyImageSRC(url)
|
|
48
|
+
|
|
49
|
+
// Assert
|
|
50
|
+
expect(consoleWarnMock).toHaveBeenCalled()
|
|
51
|
+
expect(consoleWarnMock.mock.calls[0][0]).toContain(
|
|
52
|
+
'WARNING: Sanity CDN URL without parameters detected'
|
|
53
|
+
)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('should warn for direct S3 bucket URL', () => {
|
|
57
|
+
// Arrange
|
|
58
|
+
const url = 'https://musora-images.s3.amazonaws.com/drumeo/images/some-image.jpg'
|
|
59
|
+
|
|
60
|
+
// Act
|
|
61
|
+
verifyImageSRC(url)
|
|
62
|
+
|
|
63
|
+
// Assert
|
|
64
|
+
expect(consoleWarnMock).toHaveBeenCalled()
|
|
65
|
+
expect(consoleWarnMock.mock.calls[0][0]).toContain('Direct S3 bucket URL detected')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('should not warn when URL is empty', () => {
|
|
69
|
+
// Arrange
|
|
70
|
+
const url = ''
|
|
71
|
+
|
|
72
|
+
// Act
|
|
73
|
+
verifyImageSRC(url)
|
|
74
|
+
|
|
75
|
+
// Assert
|
|
76
|
+
expect(consoleWarnMock).not.toHaveBeenCalled()
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
describe('Cloudflare wrapped Sanity URLs', () => {
|
|
81
|
+
test('should extract and validate Sanity URL from Cloudflare wrapper', () => {
|
|
82
|
+
// Arrange
|
|
83
|
+
const url =
|
|
84
|
+
'https://www.musora.com/cdn-cgi/image/width=500,quality=95/https://cdn.sanity.io/images/4032r8py/staging/504c4e3393170f937a579de6f3c75c457b0c9e65-640x360.jpg'
|
|
85
|
+
|
|
86
|
+
// Act
|
|
87
|
+
verifyImageSRC(url)
|
|
88
|
+
|
|
89
|
+
// Assert
|
|
90
|
+
expect(consoleWarnMock).toHaveBeenCalled()
|
|
91
|
+
expect(consoleWarnMock.mock.calls[0][0]).toContain(
|
|
92
|
+
'WARNING: Sanity CDN URL without parameters detected'
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
test('should not warn for Cloudflare wrapped Sanity URL with parameters', () => {
|
|
97
|
+
// Arrange
|
|
98
|
+
const url =
|
|
99
|
+
'https://www.musora.com/cdn-cgi/image/width=500,quality=95/https://cdn.sanity.io/images/4032r8py/staging/504c4e3393170f937a579de6f3c75c457b0c9e65-640x360.jpg?w=500&q=95'
|
|
100
|
+
|
|
101
|
+
// Act
|
|
102
|
+
verifyImageSRC(url)
|
|
103
|
+
|
|
104
|
+
// Assert
|
|
105
|
+
expect(consoleWarnMock).not.toHaveBeenCalled()
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
describe('isBucketUrl', () => {
|
|
110
|
+
test('should detect standard S3 URLs', () => {
|
|
111
|
+
// Arrange & Act & Assert
|
|
112
|
+
expect(isBucketUrl('https://my-bucket.s3.amazonaws.com/image.jpg')).toBe(true)
|
|
113
|
+
expect(isBucketUrl('https://s3.us-east-1.amazonaws.com/my-bucket/image.jpg')).toBe(true)
|
|
114
|
+
expect(isBucketUrl('https://musora-images.s3.amazonaws.com/path/to/image.jpg')).toBe(true)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test('should not flag non-S3 URLs', () => {
|
|
118
|
+
// Arrange & Act & Assert
|
|
119
|
+
expect(isBucketUrl('https://cdn.sanity.io/images/123/production/image.jpg')).toBe(false)
|
|
120
|
+
expect(isBucketUrl('https://www.musora.com/image.jpg')).toBe(false)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('extractSanityUrl', () => {
|
|
125
|
+
test('should extract Sanity URL from Cloudflare wrapper', () => {
|
|
126
|
+
// Arrange
|
|
127
|
+
const wrappedUrl =
|
|
128
|
+
'https://www.musora.com/cdn-cgi/image/width=500,quality=95/https://cdn.sanity.io/images/123/production/image.jpg'
|
|
129
|
+
const expectedExtracted = 'https://cdn.sanity.io/images/123/production/image.jpg'
|
|
130
|
+
|
|
131
|
+
// Act
|
|
132
|
+
const result = extractSanityUrl(wrappedUrl)
|
|
133
|
+
|
|
134
|
+
// Assert
|
|
135
|
+
expect(result).toBe(expectedExtracted)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test('should return original URL if not Cloudflare wrapped', () => {
|
|
139
|
+
// Arrange
|
|
140
|
+
const url = 'https://cdn.sanity.io/images/123/production/image.jpg'
|
|
141
|
+
|
|
142
|
+
// Act
|
|
143
|
+
const result = extractSanityUrl(url)
|
|
144
|
+
|
|
145
|
+
// Assert
|
|
146
|
+
expect(result).toBe(url)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
test('should handle malformed Cloudflare URLs gracefully', () => {
|
|
150
|
+
// Arrange
|
|
151
|
+
const malformedUrl = 'https://www.musora.com/cdn-cgi/image/width=500'
|
|
152
|
+
|
|
153
|
+
// Act
|
|
154
|
+
const result = extractSanityUrl(malformedUrl)
|
|
155
|
+
|
|
156
|
+
// Assert
|
|
157
|
+
expect(result).toBe(malformedUrl)
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
})
|