Skip to content

Commit c61e694

Browse files
committed
simplify url generation logic to make it a blueprint for all languages
1 parent 6e99777 commit c61e694

File tree

2 files changed

+41
-16
lines changed

2 files changed

+41
-16
lines changed

src/resources/helper.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,11 @@ export class Helper extends APIResource {
4545

4646
const isAbsoluteURL = opts.src.startsWith('http://') || opts.src.startsWith('https://');
4747

48-
var urlObj, isSrcParameterUsedForURL, urlEndpointPattern;
48+
var urlObj, isSrcParameterUsedForURL;
4949

5050
try {
5151
if (!isAbsoluteURL) {
52-
urlEndpointPattern = new URL(opts.urlEndpoint).pathname;
53-
urlObj = new URL(pathJoin([opts.urlEndpoint.replace(urlEndpointPattern, ''), opts.src]));
52+
urlObj = new URL(opts.urlEndpoint);
5453
} else {
5554
urlObj = new URL(opts.src!);
5655
isSrcParameterUsedForURL = true;
@@ -67,30 +66,36 @@ export class Helper extends APIResource {
6766

6867
const addAsQuery = transformationUtils.addAsQueryParameter(opts) || isSrcParameterUsedForURL;
6968

70-
if (transformationString && transformationString.length) {
71-
if (!addAsQuery) {
72-
urlObj.pathname = pathJoin([
73-
TRANSFORMATION_PARAMETER + transformationUtils.getChainTransformDelimiter() + transformationString,
74-
urlObj.pathname,
75-
]);
69+
const TRANSFORMATION_PLACEHOLDER = "PLEASEREPLACEJUSTBEFORESIGN";
70+
71+
if (!isAbsoluteURL) {
72+
// For non-absolute URLs, construct the path: endpoint_path + transformations + src
73+
const endpointPath = new URL(opts.urlEndpoint).pathname;
74+
const pathParts = [endpointPath];
75+
76+
if (transformationString && transformationString.length && !addAsQuery) {
77+
pathParts.push(TRANSFORMATION_PARAMETER + transformationUtils.getChainTransformDelimiter() + TRANSFORMATION_PLACEHOLDER);
7678
}
77-
}
7879

79-
if (urlEndpointPattern) {
80-
urlObj.pathname = pathJoin([urlEndpointPattern, urlObj.pathname]);
81-
} else {
82-
urlObj.pathname = pathJoin([urlObj.pathname]);
80+
pathParts.push(opts.src);
81+
urlObj.pathname = pathJoin(pathParts);
8382
}
8483

8584
// First, build the complete URL with transformations
8685
let finalUrl = urlObj.href;
8786

8887
// Add transformation parameter manually to avoid URL encoding
8988
// URLSearchParams.set() would encode commas and colons in transformation string,
90-
// It would work correctly but not very readable e.g., "w-300,h-400" is better than "w-300%2Ch-400"
89+
// It would work correctly but not very readable e.g., "w-300,h-400" is better than "w-300%2Ch-400". Moreover we ensure transformation string is URL safe by encoding individual components while building it.
9190
if (transformationString && transformationString.length && addAsQuery) {
9291
const separator = urlObj.searchParams.toString() ? '&' : '?';
93-
finalUrl = `${finalUrl}${separator}${TRANSFORMATION_PARAMETER}=${transformationString}`;
92+
finalUrl = `${finalUrl}${separator}${TRANSFORMATION_PARAMETER}=${TRANSFORMATION_PLACEHOLDER}`;
93+
}
94+
95+
// Replace the placeholder with actual transformation string
96+
// We don't put actual transformation string before signing to avoid issues with URL encoding. Though in node it works correctly but other libraries use this code as blueprint and can double encode when using URL object .href equivalent.
97+
if (transformationString && transformationString.length) {
98+
finalUrl = finalUrl.replace(TRANSFORMATION_PLACEHOLDER, transformationString);
9499
}
95100

96101
// Then sign the URL if needed

tests/custom-tests/url-generation/basic.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,26 @@ describe('URL generation', function () {
4646
expect(url).toBe(`https://ik.imagekit.io/test_url_endpoint/test_path.jpg`);
4747
});
4848

49+
it('should generate a valid URL when cname is used', function () {
50+
const url = client.helper.buildSrc({
51+
urlEndpoint: 'https://custom.domain.com',
52+
transformationPosition: 'query',
53+
src: '/test_path.jpg',
54+
});
55+
56+
expect(url).toBe(`https://custom.domain.com/test_path.jpg`);
57+
});
58+
59+
it('should generate a valid URL when cname is used with a url-pattern', function () {
60+
const url = client.helper.buildSrc({
61+
urlEndpoint: 'https://custom.domain.com/url-pattern',
62+
transformationPosition: 'query',
63+
src: '/test_path.jpg',
64+
});
65+
66+
expect(url).toBe(`https://custom.domain.com/url-pattern/test_path.jpg`);
67+
});
68+
4969
it('should generate a valid URL when a src is provided without transformation', function () {
5070
const url = client.helper.buildSrc({
5171
urlEndpoint: 'https://ik.imagekit.io/test_url_endpoint',

0 commit comments

Comments
 (0)