npm installation
Install the published package from npm and run it on Node.js 18+ or another runtime where you inject a compatible fetch.
SDK library
Python, TypeScript, and PHP are live now. Each route documents the same Dilnaka upload lifecycle in the conventions of its own runtime.
Environment-driven setup, direct-to-S3 uploads, and the current Python reference implementation.
Node 18+ uploads, typed file helpers, and fetch injection for tests or custom runtimes.
Composer installation, PHP 8.1+, Guzzle transport, and the same Dilnaka file lifecycle.
Documentation
TypeScript SDK for uploading files through the Dilnaka Upload API. The client resolves configuration from constructor options first, then environment variables, then .env, requests a presigned upload URL from your Dilnaka backend, uploads directly to S3, and finally completes the file record.
Install the published package from npm and run it on Node.js 18+ or another runtime where you inject a compatible fetch.
The SDK reads the local file path, creates a presigned upload with your Dilnaka backend, uploads to S3, and then completes the file record.
The TypeScript client hits the same upload, file lookup, access URL, and delete endpoints as the Python SDK.
Setup
Install the published Dilnaka package from npm. The package name matches the Python SDK package name, so the constructor import stays consistent across languages.
Package: npmjs.com/package/dilnaka
npm install dilnaka
Minimum runtime: Node.js 18+. If you run in a custom environment, pass a compatible fetch implementation in the constructor options.
Configuration
The SDK only needs your API key in .env. It is built specifically for Dilnaka Storage.
DILNAKA_API_KEY=dlk_dev_your_api_key_here
DILNAKA_TIMEOUT=60
DILNAKA_MULTIPART_THRESHOLD=104857600
DILNAKA_UPLOAD_TIMEOUT=300
Optional: set DILNAKA_TIMEOUT (default 60) for the JSON API request timeout in seconds.
Set DILNAKA_MULTIPART_THRESHOLD (default 104857600, i.e. 100 MB) to control when uploads switch to the multipart flow.
Set DILNAKA_UPLOAD_TIMEOUT (default 300) for the per-part transfer timeout in seconds. It is intentionally larger than the API timeout so large chunks over slow links do not time out.
Core flow
Instantiate the client with defaults and upload a local file path with one async method call.
import __PP_ESCAPED_LEFT_BRACE__ Dilnaka __PP_ESCAPED_RIGHT_BRACE__ from "dilnaka";
const client = new Dilnaka();
const uploaded = await client.upload("./test-upload.txt");
console.log(uploaded.id);
console.log(uploaded.key);
console.log(uploaded.status);
Alternate setup
Pass constructor options directly when you want to avoid environment files, change the timeout, or inject a custom fetch implementation for tests or another runtime.
import __PP_ESCAPED_LEFT_BRACE__ Dilnaka __PP_ESCAPED_RIGHT_BRACE__ from "dilnaka";
const client = new Dilnaka(__PP_ESCAPED_LEFT_BRACE__
apiKey: "dlk_dev_your_api_key_here",
timeout: 60,
fetch,
__PP_ESCAPED_RIGHT_BRACE__);
const uploaded = await client.upload("./avatar.png", __PP_ESCAPED_LEFT_BRACE__
folder: "avatars",
metadata: __PP_ESCAPED_LEFT_BRACE__ source: "profile-settings" __PP_ESCAPED_RIGHT_BRACE__,
__PP_ESCAPED_RIGHT_BRACE__);
console.log(uploaded);
Large files
The same upload() call handles files of any size. Small files use a single presigned PUT. Files at or above the multipart threshold (100 MB by default) automatically switch to a resumable S3 multipart upload that streams the file in chunks and retries a failed part instead of discarding the whole transfer.
import __PP_ESCAPED_LEFT_BRACE__ Dilnaka __PP_ESCAPED_RIGHT_BRACE__ from "dilnaka";
const client = new Dilnaka();
// Large files (>= 100 MB) automatically use resumable multipart upload.
const uploaded = await client.upload("./course-bundle.zip");
// Tune per call: force multipart above 25 MB and allow 10 minutes per part.
const large = await client.upload("./course-bundle.zip", __PP_ESCAPED_LEFT_BRACE__
multipartThreshold: 25 * 1024 * 1024,
uploadTimeout: 600,
__PP_ESCAPED_RIGHT_BRACE__);
console.log(uploaded.id, uploaded.status);
The multipart flow streams the file from disk one part at a time, so memory stays flat even for multi-gigabyte uploads. Each part is retried with a fresh presigned URL if it fails, and a transfer that cannot finish is aborted automatically so it never leaves a dangling upload on the bucket.
For direct control, the lower-level methods are also available:
createMultipartUpload(options) starts the upload and returns the part layout.presignMultipartParts(fileId, partNumbers) returns a map of part number to presigned PUT URL.completeMultipartUpload(fileId, parts) finalizes the upload from part ETags.abortMultipartUpload(fileId) cancels an in-progress upload.Read access
Use getFileAccessUrl(fileId, expiresIn?) when your app needs a temporary download or preview URL.
import __PP_ESCAPED_LEFT_BRACE__ Dilnaka __PP_ESCAPED_RIGHT_BRACE__ from "dilnaka";
const client = new Dilnaka();
const access = await client.getFileAccessUrl("file_123", 600);
console.log(access.fileId);
console.log(access.url);
console.log(access.expiresIn);
console.log(access.isTemporary);
If you omit expiresIn, the SDK requests the default access URL returned by your backend. The method rejects values less than or equal to zero.
API surface
const client = new Dilnaka(__PP_ESCAPED_LEFT_BRACE__
apiKey?: string;
timeout?: number;
envFile?: string;
fetch?: typeof fetch;
__PP_ESCAPED_RIGHT_BRACE__);
await client.upload(filePath, options?);
await client.createPresignedUpload(options);
await client.completeUpload(fileId);
await client.createMultipartUpload(options);
await client.presignMultipartParts(fileId, partNumbers);
await client.completeMultipartUpload(fileId, parts);
await client.abortMultipartUpload(fileId);
await client.listFiles();
await client.getFile(fileId);
await client.getFileAccessUrl(fileId, expiresIn?);
await client.deleteFile(fileId);
Primary names
Use the camelCase methods in normal TypeScript and JavaScript code: createPresignedUpload, getFileAccessUrl, and the other typed helpers.
Migration aliases
Python-style aliases are also shipped for migration convenience: list_files(), get_file(), and related helpers.
Backend contract
The TypeScript SDK uses the same Caspian endpoints as the Python SDK.
POST /v1/uploads/presign
POST /v1/uploads/complete
POST /v1/uploads/multipart/create
POST /v1/uploads/multipart/parts
POST /v1/uploads/multipart/complete
POST /v1/uploads/multipart/abort
GET /v1/files
GET /v1/files/__PP_ESCAPED_LEFT_BRACE__file_id__PP_ESCAPED_RIGHT_BRACE__
GET /v1/files/__PP_ESCAPED_LEFT_BRACE__file_id__PP_ESCAPED_RIGHT_BRACE__/access-url?expiresIn=1200
DELETE /v1/files/__PP_ESCAPED_LEFT_BRACE__file_id__PP_ESCAPED_RIGHT_BRACE__
When you pass expiresIn to getFileAccessUrl, the SDK appends it as a query parameter on the access URL endpoint.
API payloads
__PP_ESCAPED_LEFT_BRACE__
"fileId": "clx_file_id",
"fileKey": "uploads/2026/05/clx_file_id-test.txt",
"uploadUrl": "https://s3-presigned-url",
"expiresIn": 300,
"method": "PUT",
"headers": __PP_ESCAPED_LEFT_BRACE__
"Content-Type": "text/plain"
__PP_ESCAPED_RIGHT_BRACE__
__PP_ESCAPED_RIGHT_BRACE__
__PP_ESCAPED_LEFT_BRACE__
"fileId": "clx_file_id",
"status": "uploaded",
"key": "uploads/2026/05/clx_file_id-test.txt",
"originalName": "test.txt",
"contentType": "text/plain",
"size": 94,
"publicUrl": null,
"etag": "\"3b5d5c3712955042212316173ccf37be\""
__PP_ESCAPED_RIGHT_BRACE__
__PP_ESCAPED_LEFT_BRACE__
"fileId": "clx_file_id",
"url": "https://s3-presigned-url",
"expiresIn": 1200,
"isTemporary": true
__PP_ESCAPED_RIGHT_BRACE__
Examples
import __PP_ESCAPED_LEFT_BRACE__ Dilnaka __PP_ESCAPED_RIGHT_BRACE__ from "dilnaka";
const client = new Dilnaka();
const access = await client.getFileAccessUrl(
"maext0cfjsquw2mu9o597fb9",
1200,
);
console.log(access.url);
console.log(access.expiresIn);
import __PP_ESCAPED_LEFT_BRACE__ Dilnaka __PP_ESCAPED_RIGHT_BRACE__ from "dilnaka";
const client = new Dilnaka();
const fileId = "maext0cfjsquw2mu9o597fb9";
const result = await client.deleteFile(fileId);
console.log(result);
import __PP_ESCAPED_LEFT_BRACE__ Dilnaka __PP_ESCAPED_RIGHT_BRACE__ from "dilnaka";
const client = new Dilnaka();
const uploaded = await client.upload("./test-upload.txt", __PP_ESCAPED_LEFT_BRACE__
folder: "uploads",
__PP_ESCAPED_RIGHT_BRACE__);
console.log("Uploaded file:");
console.log(" id: " + uploaded.id);
console.log(" key: " + uploaded.key);
console.log(" status: " + uploaded.status);
console.log(" size: " + uploaded.size);
console.log(" contentType: " + uploaded.contentType);
import __PP_ESCAPED_LEFT_BRACE__ Dilnaka __PP_ESCAPED_RIGHT_BRACE__ from "dilnaka";
const client = new Dilnaka();
// Files >= 100 MB automatically use resumable multipart upload.
const uploaded = await client.upload("./course-bundle.zip", __PP_ESCAPED_LEFT_BRACE__
folder: "courses",
uploadTimeout: 600,
__PP_ESCAPED_RIGHT_BRACE__);
console.log(uploaded.id, uploaded.status, uploaded.size);
import __PP_ESCAPED_LEFT_BRACE__ Dilnaka __PP_ESCAPED_RIGHT_BRACE__ from "dilnaka";
const client = new Dilnaka();
for (const file of await client.listFiles()) __PP_ESCAPED_LEFT_BRACE__
console.log(file.id + " | " + file.status + " | " + file.key);
__PP_ESCAPED_RIGHT_BRACE__
Security
The SDK never receives AWS credentials. It only receives a temporary presigned upload URL from your Dilnaka backend.
Your backend remains responsible for API key validation, scope checking, file validation, S3 key generation, metadata persistence, upload completion verification, and temporary read URL expiration.