@cellajs/imado
v0.1.6
Published
File handling with TUS for public and private files using AWS Lambda and S3.
Downloads
329
Maintainers
Readme
Imado (+ TUS + AWS Lambda + S3)
Imado is built as a configure-once solution for file handling with the TUS protocol, for public as well as for private files. It supports images and files such as PDF and DOCX and runs on AWS Lambda. Data - including cache - is stored on your own S3 bucket. Optionally it also supports videos.
This repo is a helper to use Imado and is currently being used by CellaJS. The required AWS lambda repo is currently private.
Contact us here if you are interested in using it or email us at [email protected].
Server
Wrap tus + s3-store and the Imado API to start uploading to your api.
import { ImadoTus } from "imado";
import { env } from "env"; // or wherever you store your env variables
const tus = ImadoTus({
secret: env.TUS_UPLOAD_API_SECRET,
credentials: {
bucket: env.AWS_S3_UPLOAD_BUCKET,
region: env.AWS_S3_UPLOAD_REGION,
accessKeyId: env.AWS_S3_UPLOAD_ACCESS_KEY_ID,
secretAccessKey: env.AWS_S3_UPLOAD_SECRET_ACCESS_KEY,
},
});
tus.listen({
host: "0.0.0.0",
port: Number(env.TUS_PORT ?? "1080"),
});
Signed (private) URLs
Generate signed URLs for your private CDN (if the url does not include the signUrl it will just pass through).
import { ImadoUrl } from "imado";
import { env } from "env";
export const getImadoUrl = new ImadoUrl({
signUrl: env.PRIVATE_CDN_ROOT,
cloudfrontKeyId: env.AWS_CLOUDFRONT_KEY_ID,
cloudfrontPrivateKey: env.AWS_CLOUDFRONT_PRIVATE_KEY,
});
const thumbnailUrl = `${env.PRIVATE_CDN_ROOT}/thumbnail.jpg`;
const signedThumbnailUrl = getImadoUrl.generate(thumbnailUrl, {
width: 100,
format: "avif",
});
What to do on your application
Backend
- Create an endpoint with a JWT including a
public
boolean andsub
in the payload. Recommended would also to define aexpiresIn
(exp). For example:
const jwt = require("jsonwebtoken");
async function getUploadToken(ctx) {
const isPublic = ctx.req.query("public");
const user = ctx.get("user");
const token = jwt.sign(
{ sub: user.id, public: isPublic === "true" },
process.env.TUS_UPLOAD_API_SECRET
);
return ctx.json({
success: true,
data: token,
});
}
Frontend
You would include something like Uppy and uppy/tus.
import Uppy from "@uppy/core";
import Tus from "@uppy/tus";
// Get the JWT from your server
const { token } = await (await fetch("/api/upload/token?public=true")).json();
// Convience method to read out JWT (base64) string
const readJwt = (token: string) => JSON.parse(atob(token.split(".")[1]));
// Read out JWT
const { public: isPublic, sub } = readJwt(token);
const uppy = new Uppy({
meta: {
public: isPublic,
},
})
.use(Tus, {
endpoint: "http://localhost:1080", // endpoint for tus
removeFingerprintOnSuccess: true,
headers: {
authorization: `Bearer ${token}`, // pass the JWT to tus
},
})
.on("complete", (result) => {
if (result.successful) {
const urls = result.successful.map((file) => {
const uploadKey = file.uploadURL.split("/").pop();
return new URL(`https://path_to_your_cdn.com/${sub}/${uploadKey}`);
});
// Do something with the urls!
}
});