@darco2903/cdn-api
v1.7.0
Published
Readme
CDN API
Description
This package provides an API for interacting with Darco2903's CDN service, including functionalities for uploading, managing, and retrieving media assets. It includes both client and server utilities to facilitate the integration of CDN functionalities across multiple applications.
Installation
npm install @darco2903/cdn-apiUsage
Creating a client
import { createClient } from "@darco2903/cdn-api/client";
const SERVER_ORIGIN = "https://cdn.example.com";
const cdnApi = createClient(SERVER_ORIGIN);Services
A service (like auth) stores assets on the CDN for its users. Each service can only store its own asset types:
| Service | Asset types |
| ------- | ----------- |
| auth | avatar |
| share | file |
The list is exported as CDN_SERVICE_ASSET_TYPES, and a token with a type of another service is rejected.
Signing a JWT token
import { CdnAssetTokenData, JWTSign } from "@darco2903/cdn-api/server";
import { Hour } from "@darco2903/secondthought";
const JWT_PRIVATE_KEY = "..."; // Private key here
const tokenData: CdnAssetTokenData = {
user_public_id: "user_public_id",
endpoint: "/test",
service: "auth",
type: "avatar",
};
const expiresIn = new Hour(1); // Token expires in 1 hour. Also accepts a number of seconds (e.g., 3600).
await JWTSign(tokenData, JWT_PRIVATE_KEY, expiresIn).match(
(signedToken) => {
console.log("JWT signing successful:", signedToken);
},
(err) => {
console.error(`JWT signing failed: ${err.message}`);
}
);Verifying a JWT token
import { JWTVerify } from "@darco2903/cdn-api/server";
const JWT_PUBLIC_KEY = "..."; // Public key here
const accessToken = "..."; // JWT token here
await JWTVerify(accessToken, JWT_PUBLIC_KEY).match(
(decodedToken) => {
console.log("JWT verification successful:", decodedToken);
},
(err) => {
console.error(`JWT verification failed: ${err.message}`);
}
);Tokens
| Token | Signed by | Verified with | Used for |
| -------- | --------- | ------------------- | -------------------------------------------------------------- |
| Asset | Service | JWTVerify | Uploading an asset (authorization header) |
| Feedback | CDN | JWTVerifyFeedback | The CDN notifying the service through callback_url |
| Download | Service | JWTVerifyDownload | Downloading an asset (?token= query, CDN_DOWNLOAD_TOKEN_QUERY) |
All of them are signed with JWTSign.
Uploading a large service asset
service.update sends the whole file in one request. For large files, upload it in parts with the asset token in the authorization header of every request:
const headers = { authorization: `Bearer ${assetToken}` };
const init = await cdnApi.service.uploadInit({
headers,
body: { filename: file.name, size: file.size, parts: partCount },
});
// init.body.uploadId
await cdnApi.service.uploadPart({
headers,
params: { upload_id: uploadId, part: "0" },
body: { file: chunk },
});
await cdnApi.service.uploadEnd({
headers,
params: { upload_id: uploadId },
body: undefined,
});Parts are numbered from 0. The endpoint, maximum size and allowed types come from the asset token, not from the request.
Download token
A service can restrict who downloads its assets: it checks the access itself, then redirects to the asset with a short-lived download token.
import { CDN_DOWNLOAD_TOKEN_QUERY, JWTSign, type CdnDownloadTokenData } from "@darco2903/cdn-api/server";
const data: CdnDownloadTokenData = {
scope: "download",
service: "share",
endpoint: "/share/abc/file1",
user_public_id: "abcdefgh", // absent for a public download
filename: "report.pdf", // optional, file name of the download
};
const token = await JWTSign(data, JWT_PRIVATE_KEY, 60);
// redirect to `${CDN_ORIGIN}${data.endpoint}?${CDN_DOWNLOAD_TOKEN_QUERY}=${token}`