UNPKG

@athenox/talos

Version:

Talos: a backend you describe instead of write. Declare a schema, write the rules in plain language, map URLs to sentences; a small built-in model turns them into query plans.

39 lines (31 loc) • 1.75 kB
# Files and images A column that holds an uploaded file is declared on its table: ```ts files: { photo: { dir: 'uploads/recipes', url: '/uploads/recipes/', accept: /^image\/(jpeg|png|webp)$/, maxBytes: 12_000_000, message: 'A JPEG, PNG or WebP of 12 MB at most', required: 'A photo is needed', // on creation image: { width: 1600, height: 1600, format: 'webp', quality: 82 }, // processed before it is stored variants: { thumb: { width: 640, height: 480, fit: 'cover', format: 'webp' } }, // more sizes, each in its column record: { width: 'width', height: 'height', size: 'size', type: 'mime', name: 'original_name' }, }, } ``` A multipart request (`FormData`) to a route writing that table carries the file under the column's name; its text fields are values like a JSON body. The file is checked, processed, stored under a random name, and the column set to `url + name`. Replacing it or deleting the row removes the old file; a request that fails its rules leaves nothing behind. Image processing (`sharp`, from your dependencies — `npm install sharp`, or `useImages(sharp)`): at most `width` × `height` (never enlarged, unless `enlarge` or `fit: 'cover'`), re-encoded as `format` at `quality`, rotated upright, and stripped of its metadata — a phone photo carries its GPS position (`keepMetadata: true` to keep it). `transform(buffer, file)` for anything else. Serving them back: ```ts 'GET /uploads/recipes/:name': serveFiles('uploads/recipes', { maxAge: 31536000, guard: (name, event) => {} }), ``` The path stays inside the folder, the type follows the extension, and `nosniff` is set. A route with `download: row => ({ path, name, type })` sends a row's file instead.