Skip to content

@forinda/kickjs-storage ​

One Storage interface over memory, local disk, and S3-compatible buckets, with signed URLs and no AWS SDK. The main entry runs on Node, Bun, Deno and Cloudflare Workers; diskStorage is in @forinda/kickjs-storage/disk. The File Storage guide covers usage.

Installation ​

pnpm add @forinda/kickjs-storage

@forinda/kickjs (10.1+) is an optional peer — needed only for the settings, adapter and tus entries.

ts
import { s3Storage } from '@forinda/kickjs-storage'

const files = s3Storage({ bucket: 'avatars', region: 'eu-west-1', accessKeyId, secretAccessKey })
await files.put(`avatars/${user.id}.png`, ctx.file!.buffer, { contentType: 'image/png' })
const link = await files.url(`avatars/${user.id}.png`, { expiresIn: 600 })

Exports ​

ExportDescription
Storageput, putIfAbsent, get, getStream, stat, exists, delete, list, url
memoryStorage(options?)Files in a Map, for tests. baseUrl for url()
diskStorage(options)From @forinda/kickjs-storage/disk (Node only). Files under root, written atomically. baseUrl for url()
s3Storage(options)S3, R2, MinIO over fetch with SigV4. url() presigns a GET
checkKey(key)Throws for an empty key, a leading /, empty / . / .. segments, \ or NUL
S3StorageStorage plus uploadUrl(key, { size, contentType, expiresIn }), uploadForm(key, { maxSize, minSize, contentType }), multipart, compose(key, sources, options?) and location
Multipartcreate, partUrl, listParts, complete, abort
UploadFormOptions / UploadFormmaxSize, minSize, contentType (one exact type), expiresIn / { url, fields }
UploadUrlOptionsexpiresIn, size (signed, exact), contentType (signed)
UploadedPart / CompletedPart{ partNumber, etag, size } / { partNumber, etag }
BodyUint8Array | string | AsyncIterable<Uint8Array> (web or Node streams)
FileInfokey, size, lastModified, contentType?
ListOptions / ListPageprefix, delimiter, cursor, limit (1 to 1000, default 1000) / files, prefixes?, cursor?
PutOptionscontentType
UrlOptionsexpiresIn in seconds, default 3600, at most 604800
S3StorageOptionsbucket, region, endpoint, accessKeyId, secretAccessKey, sessionToken, forcePathStyle, fetch, partSize, partConcurrency
DiskStorageOptionsroot, baseUrl
MemoryStorageOptionsbaseUrl

Settings (@forinda/kickjs-storage/settings) ​

Needs @forinda/kickjs 10.1 or later.

ExportDescription
S3SettingsSection S3: S3_BUCKET, S3_REGION, S3_ENDPOINT, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_SESSION_TOKEN, S3_FORCE_PATH_STYLE
s3FromSettings(section?, options?)An S3Storage read from the section on first use; set variables win over options

Adapter (@forinda/kickjs-storage/adapter) ​

Needs @forinda/kickjs 10.1 or later.

ExportDescription
StorageAdapter(options)Binds options.storage to options.token (default STORAGE) and declares the storage's settings section, if it has one. .scoped(name, options) for a second storage. onHealthCheck() lists one key for /health/ready
STORAGEThe default token
StorageAdapterOptionsstorage, token, healthCheck (default true; false reports up without checking)

tus (@forinda/kickjs-storage/tus) ​

Needs @forinda/kickjs 10.1 or later.

ExportDescription
TusAdapter(options)A tus 1.0.0 endpoint at path (creation, creation-with-upload, termination, expiration, checksum, concatenation) on every runtime
createTusHandler(options)The same endpoint as a Node (req, res, next) handler
TusOptionspath, storage, partials, dir, maxSize, expiresIn, onCreate, authorize, onComplete
TusUploadid, key, size, offset, metadata, data, expiresAt, concat?
TusTargetWhat onCreate returns: key, data, contentType (one exact type; default application/octet-stream)
TusCreateRequestheaders, size, metadata, concat?

Released under the MIT License. Built with TypeScript — runs on Express, Fastify, or h3.