@transloadit/utils 4.5.0 → 4.6.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 +21 -4
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -2
- package/dist/node.d.ts +20 -35
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +11 -32
- package/dist/smartCdn.d.ts +53 -0
- package/dist/smartCdn.d.ts.map +1 -0
- package/dist/smartCdn.js +42 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,8 +10,11 @@ npm install @transloadit/utils
|
|
|
10
10
|
|
|
11
11
|
## Web / Edge usage
|
|
12
12
|
|
|
13
|
+
Everything in the root export runs on WebCrypto, so it works in browsers (secure origins only:
|
|
14
|
+
`https://` or `localhost`), edge runtimes, and Node.
|
|
15
|
+
|
|
13
16
|
```ts
|
|
14
|
-
import { signParams, verifyWebhookSignature } from '@transloadit/utils'
|
|
17
|
+
import { getSignedSmartCdnUrl, signParams, verifyWebhookSignature } from '@transloadit/utils'
|
|
15
18
|
|
|
16
19
|
const signature = await signParams(paramsString, authSecret)
|
|
17
20
|
const verified = await verifyWebhookSignature({
|
|
@@ -19,6 +22,13 @@ const verified = await verifyWebhookSignature({
|
|
|
19
22
|
signatureHeader,
|
|
20
23
|
authSecret,
|
|
21
24
|
})
|
|
25
|
+
const url = await getSignedSmartCdnUrl({
|
|
26
|
+
workspace,
|
|
27
|
+
template,
|
|
28
|
+
input,
|
|
29
|
+
authKey,
|
|
30
|
+
authSecret,
|
|
31
|
+
})
|
|
22
32
|
```
|
|
23
33
|
|
|
24
34
|
## Node usage
|
|
@@ -47,13 +57,20 @@ const imageCandidates = getSignedSmartCdnImageCandidates({
|
|
|
47
57
|
widths: [320, 640, 960],
|
|
48
58
|
workspace,
|
|
49
59
|
})
|
|
60
|
+
|
|
61
|
+
for (const source of imageCandidates.sources) {
|
|
62
|
+
console.log(source.format, source.quality, source.candidates)
|
|
63
|
+
}
|
|
50
64
|
```
|
|
51
65
|
|
|
52
66
|
## API
|
|
53
67
|
|
|
54
|
-
- `signParams(paramsString, authSecret, algorithm?)`: WebCrypto-based HMAC signature for params
|
|
68
|
+
- `signParams(paramsString, authSecret, algorithm?)`: WebCrypto-based HMAC signature for params
|
|
69
|
+
(`sha1`, `sha256`, `sha384`, `sha512`).
|
|
55
70
|
- `verifyWebhookSignature({ rawBody, signatureHeader, authSecret })`: validates webhook signatures.
|
|
71
|
+
- `getSignedSmartCdnUrl(options)`: async, WebCrypto-based Smart CDN URL signer. Byte-identical to
|
|
72
|
+
the Node variant below.
|
|
56
73
|
- `signParamsSync(paramsString, authSecret, algorithm?)`: Node-only sync signature helper.
|
|
57
|
-
- `getSignedSmartCdnUrl(options)`:
|
|
58
|
-
- `getSignedSmartCdnImageCandidates(options)`: deterministic signed AVIF and WebP
|
|
74
|
+
- `getSignedSmartCdnUrl(options)` from `@transloadit/utils/node`: synchronous Smart CDN URL signer.
|
|
75
|
+
- `getSignedSmartCdnImageCandidates(options)`: deterministic structured, signed AVIF and WebP
|
|
59
76
|
candidates plus the original fallback URL.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { SmartCdnUrlOptions } from './smartCdn.ts';
|
|
2
|
+
export type SignatureAlgorithm = 'sha1' | 'sha256' | 'sha384' | 'sha512';
|
|
3
|
+
export type { SmartCdnUrlOptions } from './smartCdn.ts';
|
|
2
4
|
export * from './assemblyInstructionsCompiler.ts';
|
|
3
5
|
export declare const signParams: (paramsString: string, authSecret: string, algorithm?: SignatureAlgorithm) => Promise<string>;
|
|
4
6
|
export type VerifyWebhookSignatureOptions = {
|
|
@@ -7,4 +9,9 @@ export type VerifyWebhookSignatureOptions = {
|
|
|
7
9
|
authSecret: string;
|
|
8
10
|
};
|
|
9
11
|
export declare const verifyWebhookSignature: (options: VerifyWebhookSignatureOptions) => Promise<boolean>;
|
|
12
|
+
/**
|
|
13
|
+
* Signs a Smart CDN URL with WebCrypto, so it works in browsers, edge runtimes and Node alike.
|
|
14
|
+
* Produces the same URL as the synchronous `getSignedSmartCdnUrl` from `@transloadit/utils/node`.
|
|
15
|
+
*/
|
|
16
|
+
export declare const getSignedSmartCdnUrl: (opts: SmartCdnUrlOptions) => Promise<string>;
|
|
10
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAIvD,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAExE,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEvD,cAAc,mCAAmC,CAAA;AAqDjD,eAAO,MAAM,UAAU,GACrB,cAAc,MAAM,EACpB,YAAY,MAAM,EAClB,YAAW,kBAA6B,KACvC,OAAO,CAAC,MAAM,CAOhB,CAAA;AAED,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,eAAO,MAAM,sBAAsB,GACjC,SAAS,6BAA6B,KACrC,OAAO,CAAC,OAAO,CAkBjB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAU,MAAM,kBAAkB,KAAG,OAAO,CAAC,MAAM,CAInF,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import { finishSmartCdnUrl, prepareSmartCdnUrl } from "./smartCdn.js";
|
|
1
2
|
export * from "./assemblyInstructionsCompiler.js";
|
|
2
3
|
const algorithmMap = {
|
|
3
4
|
sha1: 'SHA-1',
|
|
4
5
|
sha256: 'SHA-256',
|
|
5
6
|
sha384: 'SHA-384',
|
|
7
|
+
sha512: 'SHA-512',
|
|
6
8
|
};
|
|
7
|
-
const isSignatureAlgorithm = (value) => value === 'sha1' || value === 'sha256' || value === 'sha384';
|
|
9
|
+
const isSignatureAlgorithm = (value) => value === 'sha1' || value === 'sha256' || value === 'sha384' || value === 'sha512';
|
|
8
10
|
const getSubtle = () => {
|
|
9
11
|
const subtle = globalThis.crypto?.subtle;
|
|
10
12
|
if (!subtle) {
|
|
11
|
-
|
|
13
|
+
// Browsers only expose crypto.subtle on secure origins (https:// or localhost).
|
|
14
|
+
throw new Error('Web Crypto is required to sign Transloadit payloads; browsers only provide crypto.subtle on secure origins (https:// or localhost)');
|
|
12
15
|
}
|
|
13
16
|
return subtle;
|
|
14
17
|
};
|
|
@@ -55,3 +58,12 @@ export const verifyWebhookSignature = async (options) => {
|
|
|
55
58
|
const expected = await hmacHex(normalized, options.authSecret, options.rawBody);
|
|
56
59
|
return safeCompare(expected, signature);
|
|
57
60
|
};
|
|
61
|
+
/**
|
|
62
|
+
* Signs a Smart CDN URL with WebCrypto, so it works in browsers, edge runtimes and Node alike.
|
|
63
|
+
* Produces the same URL as the synchronous `getSignedSmartCdnUrl` from `@transloadit/utils/node`.
|
|
64
|
+
*/
|
|
65
|
+
export const getSignedSmartCdnUrl = async (opts) => {
|
|
66
|
+
const prepared = prepareSmartCdnUrl(opts);
|
|
67
|
+
const signature = await hmacHex('sha256', opts.authSecret, prepared.stringToSign);
|
|
68
|
+
return finishSmartCdnUrl(prepared, signature);
|
|
69
|
+
};
|
package/dist/node.d.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import type { SignatureAlgorithm } from './index.ts';
|
|
2
|
+
import type { SmartCdnUrlOptions } from './smartCdn.ts';
|
|
2
3
|
export type { SignatureAlgorithm } from './index.ts';
|
|
4
|
+
export type { SmartCdnUrlOptions } from './smartCdn.ts';
|
|
3
5
|
export type SignatureAlgorithmInput = SignatureAlgorithm | (string & {});
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
/** Image formats supported by the responsive-image Built-in. */
|
|
7
|
+
export type SmartCdnImageFormat = 'avif' | 'png' | 'webp';
|
|
8
|
+
/** One signed Smart CDN rendition at a specific intrinsic width. */
|
|
9
|
+
export interface SmartCdnImageCandidate {
|
|
10
|
+
url: string;
|
|
11
|
+
width: number;
|
|
12
|
+
}
|
|
13
|
+
/** Ordered candidates for one image format and quality. */
|
|
14
|
+
export interface SmartCdnImageSource {
|
|
15
|
+
candidates: readonly SmartCdnImageCandidate[];
|
|
16
|
+
format: SmartCdnImageFormat;
|
|
17
|
+
quality: number;
|
|
18
|
+
}
|
|
19
|
+
/** Structured data for rendering a responsive image. */
|
|
20
|
+
export interface SmartCdnImageCandidates {
|
|
21
|
+
fallbackUrl: string;
|
|
22
|
+
sources: readonly SmartCdnImageSource[];
|
|
8
23
|
}
|
|
9
24
|
/** Options for deterministic, server-generated Smart CDN image candidates. */
|
|
10
25
|
export interface SmartCdnImageCandidatesOptions {
|
|
@@ -25,38 +40,8 @@ export interface SmartCdnImageCandidatesOptions {
|
|
|
25
40
|
/** Workspace slug. */
|
|
26
41
|
workspace: string;
|
|
27
42
|
}
|
|
28
|
-
export type SmartCdnUrlOptions = {
|
|
29
|
-
/**
|
|
30
|
-
* Workspace slug.
|
|
31
|
-
*/
|
|
32
|
-
workspace: string;
|
|
33
|
-
/**
|
|
34
|
-
* Template slug or template ID.
|
|
35
|
-
*/
|
|
36
|
-
template: string;
|
|
37
|
-
/**
|
|
38
|
-
* Input value that is provided as `${fields.input}` in the template.
|
|
39
|
-
*/
|
|
40
|
-
input: string;
|
|
41
|
-
/**
|
|
42
|
-
* Additional parameters for the URL query string.
|
|
43
|
-
*/
|
|
44
|
-
urlParams?: Record<string, boolean | number | string | (boolean | number | string)[]>;
|
|
45
|
-
/**
|
|
46
|
-
* Expiration timestamp of the signature in milliseconds since UNIX epoch.
|
|
47
|
-
* Defaults to 1 hour from now.
|
|
48
|
-
*/
|
|
49
|
-
expiresAt?: number;
|
|
50
|
-
/**
|
|
51
|
-
* Transloadit auth key used to sign the URL.
|
|
52
|
-
*/
|
|
53
|
-
authKey: string;
|
|
54
|
-
/**
|
|
55
|
-
* Transloadit auth secret used to sign the URL.
|
|
56
|
-
*/
|
|
57
|
-
authSecret: string;
|
|
58
|
-
};
|
|
59
43
|
export declare const signParamsSync: (paramsString: string, authSecret: string, algorithm?: SignatureAlgorithmInput) => string;
|
|
44
|
+
/** Synchronous Smart CDN URL signer (Node). The root export has an async WebCrypto twin. */
|
|
60
45
|
export declare const getSignedSmartCdnUrl: (opts: SmartCdnUrlOptions) => string;
|
|
61
46
|
/**
|
|
62
47
|
* Builds deterministic signed Smart CDN candidates for server-rendered `<picture>` elements.
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAMvD,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACpD,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEvD,MAAM,MAAM,uBAAuB,GAAG,kBAAkB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAExE,gEAAgE;AAChE,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAA;AAEzD,oEAAoE;AACpE,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;CACd;AAED,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC7C,MAAM,EAAE,mBAAmB,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAA;CACxC;AAED,8EAA8E;AAC9E,MAAM,WAAW,8BAA8B;IAC7C,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAA;IACf,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAA;IAClB,uFAAuF;IACvF,SAAS,EAAE,MAAM,CAAA;IACjB,yEAAyE;IACzE,OAAO,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IAChE,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAA;IACb,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oFAAoF;IACpF,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IACzB,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAA;CAClB;AAkED,eAAO,MAAM,cAAc,GACzB,cAAc,MAAM,EACpB,YAAY,MAAM,EAClB,YAAW,uBAAkC,KAC5C,MAKF,CAAA;AAED,4FAA4F;AAC5F,eAAO,MAAM,oBAAoB,GAAI,MAAM,kBAAkB,KAAG,MAM/D,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,8BAA8B,GACnC,uBAAuB,CAsDzB"}
|
package/dist/node.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHmac } from 'node:crypto';
|
|
2
|
+
import { finishSmartCdnUrl, prepareSmartCdnUrl } from "./smartCdn.js";
|
|
2
3
|
const defaultSmartCdnImageFormats = {
|
|
3
4
|
avif: 45,
|
|
4
5
|
webp: 75,
|
|
@@ -57,35 +58,13 @@ export const signParamsSync = (paramsString, authSecret, algorithm = 'sha384') =
|
|
|
57
58
|
.digest('hex');
|
|
58
59
|
return `${algorithm}:${signature}`;
|
|
59
60
|
};
|
|
61
|
+
/** Synchronous Smart CDN URL signer (Node). The root export has an async WebCrypto twin. */
|
|
60
62
|
export const getSignedSmartCdnUrl = (opts) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
throw new TypeError('input is required');
|
|
67
|
-
const workspaceSlug = encodeURIComponent(opts.workspace);
|
|
68
|
-
const templateSlug = encodeURIComponent(opts.template);
|
|
69
|
-
const inputField = encodeURIComponent(opts.input);
|
|
70
|
-
const expiresAt = opts.expiresAt || Date.now() + 60 * 60 * 1000;
|
|
71
|
-
const queryParams = new URLSearchParams();
|
|
72
|
-
for (const [key, value] of Object.entries(opts.urlParams || {})) {
|
|
73
|
-
if (Array.isArray(value)) {
|
|
74
|
-
for (const val of value) {
|
|
75
|
-
queryParams.append(key, `${val}`);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
queryParams.append(key, `${value}`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
queryParams.set('auth_key', opts.authKey);
|
|
83
|
-
queryParams.set('exp', `${expiresAt}`);
|
|
84
|
-
queryParams.sort();
|
|
85
|
-
const stringToSign = `${workspaceSlug}/${templateSlug}/${inputField}?${queryParams}`;
|
|
86
|
-
const signature = createHmac('sha256', opts.authSecret).update(stringToSign).digest('hex');
|
|
87
|
-
queryParams.set('sig', `sha256:${signature}`);
|
|
88
|
-
return `https://${workspaceSlug}.tlcdn.com/${templateSlug}/${inputField}?${queryParams}`;
|
|
63
|
+
const prepared = prepareSmartCdnUrl(opts);
|
|
64
|
+
const signature = createHmac('sha256', opts.authSecret)
|
|
65
|
+
.update(prepared.stringToSign)
|
|
66
|
+
.digest('hex');
|
|
67
|
+
return finishSmartCdnUrl(prepared, signature);
|
|
89
68
|
};
|
|
90
69
|
/**
|
|
91
70
|
* Builds deterministic signed Smart CDN candidates for server-rendered `<picture>` elements.
|
|
@@ -120,7 +99,7 @@ export function getSignedSmartCdnImageCandidates(opts) {
|
|
|
120
99
|
const formats = opts.formats ?? defaultSmartCdnImageFormats;
|
|
121
100
|
validateSmartCdnImageFormats(formats);
|
|
122
101
|
widths.sort((left, right) => left - right);
|
|
123
|
-
const sources =
|
|
102
|
+
const sources = [];
|
|
124
103
|
for (const format of smartCdnImageFormats) {
|
|
125
104
|
const quality = formats[format];
|
|
126
105
|
if (quality == null) {
|
|
@@ -137,9 +116,9 @@ export function getSignedSmartCdnImageCandidates(opts) {
|
|
|
137
116
|
urlParams: { f: format, q: quality, r: 'fit', w: width },
|
|
138
117
|
workspace: opts.workspace,
|
|
139
118
|
});
|
|
140
|
-
candidates.push(
|
|
119
|
+
candidates.push({ url, width });
|
|
141
120
|
}
|
|
142
|
-
sources
|
|
121
|
+
sources.push({ candidates, format, quality });
|
|
143
122
|
}
|
|
144
|
-
return {
|
|
123
|
+
return { fallbackUrl: opts.input, sources };
|
|
145
124
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart CDN URL building shared by the synchronous Node signer (`@transloadit/utils/node`) and the
|
|
3
|
+
* asynchronous WebCrypto signer (`@transloadit/utils`). Only the HMAC differs between the two, so
|
|
4
|
+
* the string-to-sign and the final URL are assembled here and cannot drift apart.
|
|
5
|
+
*/
|
|
6
|
+
export type SmartCdnUrlOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* Workspace slug.
|
|
9
|
+
*/
|
|
10
|
+
workspace: string;
|
|
11
|
+
/**
|
|
12
|
+
* Template slug or template ID.
|
|
13
|
+
*/
|
|
14
|
+
template: string;
|
|
15
|
+
/**
|
|
16
|
+
* Input value that is provided as `${fields.input}` in the template.
|
|
17
|
+
*/
|
|
18
|
+
input: string;
|
|
19
|
+
/**
|
|
20
|
+
* Additional parameters for the URL query string.
|
|
21
|
+
*/
|
|
22
|
+
urlParams?: Record<string, boolean | number | string | (boolean | number | string)[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Expiration timestamp of the signature in milliseconds since UNIX epoch.
|
|
25
|
+
* Defaults to 1 hour from now.
|
|
26
|
+
*/
|
|
27
|
+
expiresAt?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Transloadit auth key used to sign the URL.
|
|
30
|
+
*/
|
|
31
|
+
authKey: string;
|
|
32
|
+
/**
|
|
33
|
+
* Transloadit auth secret used to sign the URL.
|
|
34
|
+
*/
|
|
35
|
+
authSecret: string;
|
|
36
|
+
};
|
|
37
|
+
/** A Smart CDN URL with everything but its signature in place. */
|
|
38
|
+
export interface PreparedSmartCdnUrl {
|
|
39
|
+
/** `workspace/template/input?sortedQuery`, the message the auth secret signs with HMAC-SHA256. */
|
|
40
|
+
stringToSign: string;
|
|
41
|
+
/** URL-encoded path segments and the sorted query (without `sig`). */
|
|
42
|
+
parts: {
|
|
43
|
+
workspaceSlug: string;
|
|
44
|
+
templateSlug: string;
|
|
45
|
+
inputField: string;
|
|
46
|
+
queryParams: URLSearchParams;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Validates the options and assembles the string to sign; the caller supplies the HMAC. */
|
|
50
|
+
export declare const prepareSmartCdnUrl: (opts: SmartCdnUrlOptions) => PreparedSmartCdnUrl;
|
|
51
|
+
/** Appends the `sig` parameter and returns the final `https://{workspace}.tlcdn.com/…` URL. */
|
|
52
|
+
export declare const finishSmartCdnUrl: ({ parts }: PreparedSmartCdnUrl, signatureHex: string) => string;
|
|
53
|
+
//# sourceMappingURL=smartCdn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smartCdn.d.ts","sourceRoot":"","sources":["../src/smartCdn.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,CAAA;IACrF;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,kEAAkE;AAClE,MAAM,WAAW,mBAAmB;IAClC,kGAAkG;IAClG,YAAY,EAAE,MAAM,CAAA;IACpB,sEAAsE;IACtE,KAAK,EAAE;QACL,aAAa,EAAE,MAAM,CAAA;QACrB,YAAY,EAAE,MAAM,CAAA;QACpB,UAAU,EAAE,MAAM,CAAA;QAClB,WAAW,EAAE,eAAe,CAAA;KAC7B,CAAA;CACF;AAED,4FAA4F;AAC5F,eAAO,MAAM,kBAAkB,GAAI,MAAM,kBAAkB,KAAG,mBA6B7D,CAAA;AAED,+FAA+F;AAC/F,eAAO,MAAM,iBAAiB,GAAI,WAAW,mBAAmB,EAAE,cAAc,MAAM,KAAG,MAIxF,CAAA"}
|
package/dist/smartCdn.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart CDN URL building shared by the synchronous Node signer (`@transloadit/utils/node`) and the
|
|
3
|
+
* asynchronous WebCrypto signer (`@transloadit/utils`). Only the HMAC differs between the two, so
|
|
4
|
+
* the string-to-sign and the final URL are assembled here and cannot drift apart.
|
|
5
|
+
*/
|
|
6
|
+
/** Validates the options and assembles the string to sign; the caller supplies the HMAC. */
|
|
7
|
+
export const prepareSmartCdnUrl = (opts) => {
|
|
8
|
+
if (opts.workspace == null || opts.workspace === '')
|
|
9
|
+
throw new TypeError('workspace is required');
|
|
10
|
+
if (opts.template == null || opts.template === '')
|
|
11
|
+
throw new TypeError('template is required');
|
|
12
|
+
if (opts.input == null)
|
|
13
|
+
throw new TypeError('input is required');
|
|
14
|
+
const workspaceSlug = encodeURIComponent(opts.workspace);
|
|
15
|
+
const templateSlug = encodeURIComponent(opts.template);
|
|
16
|
+
const inputField = encodeURIComponent(opts.input);
|
|
17
|
+
const expiresAt = opts.expiresAt || Date.now() + 60 * 60 * 1000;
|
|
18
|
+
const queryParams = new URLSearchParams();
|
|
19
|
+
for (const [key, value] of Object.entries(opts.urlParams || {})) {
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
for (const val of value) {
|
|
22
|
+
queryParams.append(key, `${val}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
queryParams.append(key, `${value}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
queryParams.set('auth_key', opts.authKey);
|
|
30
|
+
queryParams.set('exp', `${expiresAt}`);
|
|
31
|
+
queryParams.sort();
|
|
32
|
+
return {
|
|
33
|
+
stringToSign: `${workspaceSlug}/${templateSlug}/${inputField}?${queryParams}`,
|
|
34
|
+
parts: { workspaceSlug, templateSlug, inputField, queryParams },
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/** Appends the `sig` parameter and returns the final `https://{workspace}.tlcdn.com/…` URL. */
|
|
38
|
+
export const finishSmartCdnUrl = ({ parts }, signatureHex) => {
|
|
39
|
+
const { workspaceSlug, templateSlug, inputField, queryParams } = parts;
|
|
40
|
+
queryParams.set('sig', `sha256:${signatureHex}`);
|
|
41
|
+
return `https://${workspaceSlug}.tlcdn.com/${templateSlug}/${inputField}?${queryParams}`;
|
|
42
|
+
};
|