@samveys/storage

Local and S3 (SigV4) disks and safe uploads

Version
1.0.2Nov 5, 2026
Install
pnpm add @samveys/storage
Import
import { createStorageManager, defineStorageConfig, local, normalizePath, presignUrl, s3, … } from '@samveys/storage'

Function (10)

createStorageManager Function

No documentation comment.

function createStorageManager(config: StorageConfig): StorageManager;

Exported from packages/storage/src/manager.ts

defineStorageConfig Function

Typed helper for `storage({ ... })` config.

function defineStorageConfig<const C extends StorageConfig>(config: C): C;

Exported from packages/storage/src/manager.ts

local Function

A disk backed by a directory. Every path is normalised and must stay inside `root`, symlinks included.

function local(options: LocalDiskOptions): LocalDisk;

Exported from packages/storage/src/local.ts

normalizePath Function

Normalises a disk path to `a/b/c`: `\` is a separator, `.` and empty segments vanish. Refuses NUL bytes, control characters, absolute paths (`/x`, `C:\x`, `//host`), `..` segments and the empty path with SVS_E104. Pure; does no I/O.

function normalizePath(path: string): string;

Exported from packages/storage/src/paths.ts

presignUrl Function

Presigns a URL (query-string authentication, only `host` signed, payload unsigned).

function presignUrl(input: PresignInput): PresignedUrl;

Exported from packages/storage/src/sigv4.ts

s3 Function

An S3-compatible disk (AWS, MinIO, R2, …) that signs requests itself with SigV4. `put` signs the body hash, so a stream is buffered in memory first; keep streamed uploads small or write large files in parts.

function s3(options: S3DiskOptions): Disk;

Exported from packages/storage/src/s3.ts

signRequest Function

Signs a request with the `Authorization` header (SigV4, S3 flavour).

function signRequest(input: SignInput): SignedRequest;

Exported from packages/storage/src/sigv4.ts

sniffType Function

Recognises a file type from its first bytes. Returns `undefined` for anything else.

function sniffType(bytes: Uint8Array): DetectedType | undefined;

Exported from packages/storage/src/upload.ts

storage Function

The `@samveys/storage` plugin: binds `'storage'` (the {@link StorageManager}).

function storage(config: StorageConfig): import("@samveys/core").Plugin<StorageConfig>;

Exported from packages/storage/src/plugin.ts

storeUpload Function

Stores one uploaded file safely (#25). - Reads `multipart/form-data` with `request.formData()`; the HTTP kernel's body limit applies. - Refuses the file when it is larger than `maxBytes`, empty, or not a `File` (SVS_E104). - Decides the type from the first bytes, never from the client's `Content-Type` or file name. - Refuses file names with an executable part (`shell.php.png`) or an extension that does not fit the real type. - Writes to `<directory>/<uuid>.<extension>`: the name is generated here, the client's name is never a path. - Refuses disks whose `visibility` is `public` unless `allowPublicDisk` is set.

function storeUpload(ctx: Pick<HttpContext, 'request' | 'headers'>, field: string, options: UploadOptions): Promise<StoredUpload>;

Exported from packages/storage/src/upload.ts

Interface (9)

Disk Interface

A place files live. Paths are relative keys such as `reports/2026/q1.pdf`; `..`, absolute paths and NUL bytes are refused with SVS_E104 before any I/O happens.

interface Disk {
    /** `private` disks are never served directly; `storeUpload` refuses `public` ones by default. */
    readonly visibility: 'private' | 'public';
    put(path: string, contents: FileContents, options?: PutOptions): Promise<void>;
    /** The whole file. SVS_E105 when it does not exist. */
    get(path: string): Promise<Uint8Array>;
    /** The file as a byte stream. SVS_E105 when it does not exist. */
    stream(path: string): Promise<ReadableStream<Uint8Array>>;
    exists(path: string): Promise<boolean>;
    /** Deletes the file. Deleting a missing file is not an error. */
  …
Show the whole declaration (16 lines)
interface Disk {
    /** `private` disks are never served directly; `storeUpload` refuses `public` ones by default. */
    readonly visibility: 'private' | 'public';
    put(path: string, contents: FileContents, options?: PutOptions): Promise<void>;
    /** The whole file. SVS_E105 when it does not exist. */
    get(path: string): Promise<Uint8Array>;
    /** The file as a byte stream. SVS_E105 when it does not exist. */
    stream(path: string): Promise<ReadableStream<Uint8Array>>;
    exists(path: string): Promise<boolean>;
    /** Deletes the file. Deleting a missing file is not an error. */
    delete(path: string): Promise<void>;
    /** The permanent URL of the file (only reachable when the storage serves it publicly). */
    url(path: string): string;
    /** A URL that stops working after `expiresInSeconds`. */
    temporaryUrl(path: string, expiresInSeconds: number): Promise<string>;
}

Exported from packages/storage/src/contracts.ts

LocalDisk Interface

A local disk can also check the links it signed.

interface LocalDisk extends Disk {
    readonly root: string;
    /** True when `signature` was issued by `temporaryUrl(path)` and `expires` (epoch seconds) is in the future. */
    verifyTemporaryUrl(path: string, expires: number, signature: string): boolean;
}

Exported from packages/storage/src/contracts.ts

LocalDiskOptions Interface

No documentation comment.

interface LocalDiskOptions {
    /** Directory every path is resolved under. Created on first write. */
    readonly root: string;
    /** Prefix returned by `url()`, e.g. `https://cdn.example/files`. Without it `url()` returns the path. */
    readonly baseUrl?: string;
    /** Secret signing `temporaryUrl()` links. Default: random per process. */
    readonly signingKey?: string;
    /** Defaults to `public` when `root` contains a `public` path segment, else `private`. */
    readonly visibility?: 'private' | 'public';
}

Exported from packages/storage/src/contracts.ts

PutOptions Interface

No documentation comment.

interface PutOptions {
    /** Stored as `Content-Type` on S3. Ignored by the local disk. */
    readonly contentType?: string;
}

Exported from packages/storage/src/contracts.ts

S3DiskOptions Interface

No documentation comment.

interface S3DiskOptions {
    /** Defaults to `https://s3.<region>.amazonaws.com`. */
    readonly endpoint?: string;
    readonly bucket: string;
    readonly region: string;
    readonly accessKeyId: string;
    readonly secretAccessKey: string;
    readonly sessionToken?: string;
    /** `endpoint/bucket/key` instead of `bucket.endpoint/key`. Needed for MinIO and most local servers. */
    readonly forcePathStyle?: boolean;
  …
Show the whole declaration (14 lines)
interface S3DiskOptions {
    /** Defaults to `https://s3.<region>.amazonaws.com`. */
    readonly endpoint?: string;
    readonly bucket: string;
    readonly region: string;
    readonly accessKeyId: string;
    readonly secretAccessKey: string;
    readonly sessionToken?: string;
    /** `endpoint/bucket/key` instead of `bucket.endpoint/key`. Needed for MinIO and most local servers. */
    readonly forcePathStyle?: boolean;
    /** `fetch` override (tests, proxies). */
    readonly fetch?: typeof fetch;
    /** Clock override (tests). */
    readonly now?: () => Date;

Exported from packages/storage/src/contracts.ts

StorageConfig Interface

No documentation comment.

interface StorageConfig {
    /** Name of the disk used when none is asked for. */
    readonly default: string;
    readonly disks: Readonly<Record<string, Disk>>;
}

Exported from packages/storage/src/contracts.ts

StorageManager Interface

No documentation comment.

interface StorageManager {
    /** The named disk, or the default one. SVS_E105 is not used here: an unknown name is a programming error. */
    disk(name?: string): Disk;
    readonly names: readonly string[];
}

Exported from packages/storage/src/contracts.ts

StoredUpload Interface

No documentation comment.

interface StoredUpload {
    /** Server-generated path on the disk: `<directory>/<uuid>.<ext>`. */
    readonly path: string;
    readonly size: number;
    /** The sniffed type. */
    readonly mimeType: DetectedType;
    /** The client's file name reduced to a harmless label. Informational only: never used as a path. */
    readonly originalName: string;
}

Exported from packages/storage/src/contracts.ts

UploadOptions Interface

No documentation comment.

interface UploadOptions {
    readonly disk: Disk;
    /** Largest accepted file in bytes. Larger files are refused with SVS_E104. */
    readonly maxBytes: number;
    /** Accepted types, matched against the sniffed type, never against the client's claim. */
    readonly allowedTypes: readonly DetectedType[];
    /** Directory on the disk. Default `uploads`. */
    readonly directory?: string;
    /** Store on a disk whose `visibility` is `public`. Default false: refused. */
    readonly allowPublicDisk?: boolean;
}

Exported from packages/storage/src/contracts.ts

Type (2)

DetectedType Type

File types `storeUpload` can recognise from their first bytes.

type DetectedType = 'image/png' | 'image/jpeg' | 'image/gif' | 'image/webp' | 'application/pdf';

Exported from packages/storage/src/contracts.ts

FileContents Type

What a disk accepts as file contents.

type FileContents = string | Uint8Array | ReadableStream<Uint8Array>;

Exported from packages/storage/src/contracts.ts