DEV Community

Cover image for Getting Started with Lioran S3 in TypeScript
Swaraj Puppalwar
Swaraj Puppalwar

Posted on

Getting Started with Lioran S3 in TypeScript

Getting Started with Lioran S3 in TypeScript

This tutorial walks through the shortest practical path from a clean Node.js project to uploading and reading objects with Lioran S3 / Lioran Bastion.

Lioran S3 V1 Pre-Alpha launched on October 1, 2026. It is developed by Lioran Developer Solutions (LDS) under Lioran Group, led by Founder & CTO Swaraj Puppalwar.

This is pre-alpha infrastructure. Pin versions and test carefully.

Requirements

Use:

  • Node.js 18 or newer
  • TypeScript 5 or newer
  • a running Lioran S3 instance
  • valid user credentials or an access key

Create a project:

mkdir liorans3-demo
cd liorans3-demo

npm init -y
npm install @liorans3/driver@prealpha
npm install -D typescript tsx @types/node
Enter fullscreen mode Exit fullscreen mode

Initialize TypeScript:

npx tsc --init
Enter fullscreen mode Exit fullscreen mode

Store the connection URI

Create .env:

LIORAN_S3_URI=bastion://admin:YOUR_PASSWORD@127.0.0.1:27118
Enter fullscreen mode Exit fullscreen mode

Do not commit credentials.

Connect

Create src/index.ts:

import { BastionClient } from "@liorans3/driver";

const client = new BastionClient(
  process.env.LIORAN_S3_URI ??
    "bastion://admin:YOUR_PASSWORD@127.0.0.1:27118"
);

const health = await client.health();

console.log({
  name: health.name,
  version: health.version,
});
Enter fullscreen mode Exit fullscreen mode

Run it:

npx tsx src/index.ts
Enter fullscreen mode Exit fullscreen mode

URI behavior

The driver accepts Bastion URIs:

bastion://username:password@hostname[:port][/default_bucket]
Enter fullscreen mode Exit fullscreen mode

For local/private addresses, the driver normally resolves to HTTP and the native Bastion port.

For public domains, it can resolve to HTTPS.

You may also use structured configuration:

const client = new BastionClient({
  username: "admin",
  password: process.env.LIORAN_PASSWORD!,
  host: "storage.example.com",
  isTls: true,
});
Enter fullscreen mode Exit fullscreen mode

Or access-key authentication:

const client = new BastionClient({
  accessKey: process.env.LIORAN_ACCESS_KEY!,
  secretKey: process.env.LIORAN_SECRET_KEY!,
  host: "storage.example.com",
  isTls: true,
});
Enter fullscreen mode Exit fullscreen mode

Create a bucket

await client.buckets.create("demo", {
  quotaBytes: 10 * 1024 * 1024 * 1024,
});
Enter fullscreen mode Exit fullscreen mode

Get a bucket-scoped handle:

const bucket = client.bucket("demo");
Enter fullscreen mode Exit fullscreen mode

Upload text

await bucket.put(
  "notes/hello.txt",
  "Hello from Lioran S3",
  {
    contentType: "text/plain",
  }
);
Enter fullscreen mode Exit fullscreen mode

Upload JSON

const payload = {
  service: "liorans3",
  stage: "pre-alpha",
  launched: "2026-10-01",
};

await bucket.put(
  "config/app.json",
  JSON.stringify(payload),
  {
    contentType: "application/json",
  }
);
Enter fullscreen mode Exit fullscreen mode

Upload a file as a stream

This is the preferred pattern for large files because the object does not need to be loaded completely into memory.

import fs from "node:fs";

const input = fs.createReadStream("./sample.zip");

const result = await bucket.put(
  "archives/sample.zip",
  input,
  {
    contentType: "application/zip",
  }
);

console.log({
  key: result.key,
  size: result.size_bytes,
  sha256: result.sha256,
});
Enter fullscreen mode Exit fullscreen mode

Download an object

const object = await bucket.get("notes/hello.txt");

console.log(await object.text());
Enter fullscreen mode Exit fullscreen mode

Write directly to disk:

const archive = await bucket.get("archives/sample.zip");

await archive.writeToFile("./downloads/sample.zip");
Enter fullscreen mode Exit fullscreen mode

Read JSON:

type AppConfig = {
  service: string;
  stage: string;
  launched: string;
};

const object = await bucket.get("config/app.json");
const config = await object.json<AppConfig>();

console.log(config.stage);
Enter fullscreen mode Exit fullscreen mode

Inspect metadata without downloading

const metadata = await bucket.head("archives/sample.zip");

console.log({
  contentType: metadata.contentType,
  contentLength: metadata.contentLength,
  etag: metadata.etag,
  sha256: metadata.sha256,
});
Enter fullscreen mode Exit fullscreen mode

Delete an object

await bucket.delete("notes/hello.txt");
Enter fullscreen mode Exit fullscreen mode

List objects

Fetch one page:

const page = await bucket.listPage({
  prefix: "archives/",
  limit: 100,
});

console.log(page.objects);
console.log(page.has_more);
console.log(page.next_cursor);
Enter fullscreen mode Exit fullscreen mode

Or let the driver paginate:

const objects = await bucket.list({
  prefix: "archives/",
});

console.log(objects);
Enter fullscreen mode Exit fullscreen mode

Error handling

The driver exposes structured error classes.

import {
  BastionAuthError,
  BastionError,
  ConnectionError,
  NotFoundError,
  QuotaExceededError,
} from "@liorans3/driver";

try {
  await bucket.get("does-not-exist.txt");
} catch (error) {
  if (error instanceof NotFoundError) {
    console.error("Object not found");
  } else if (error instanceof QuotaExceededError) {
    console.error("Bucket quota exceeded");
  } else if (error instanceof BastionAuthError) {
    console.error("Authentication failed");
  } else if (error instanceof ConnectionError) {
    console.error(error.safeUri);
  } else if (error instanceof BastionError) {
    console.error(error.code, error.statusCode, error.message);
  } else {
    throw error;
  }
}
Enter fullscreen mode Exit fullscreen mode

Recommended project structure

src/
├── storage/
│   ├── client.ts
│   ├── uploads.ts
│   └── downloads.ts
└── index.ts
Enter fullscreen mode Exit fullscreen mode

client.ts:

import { BastionClient } from "@liorans3/driver";

export const storage = new BastionClient(
  process.env.LIORAN_S3_URI!
);
Enter fullscreen mode Exit fullscreen mode

That keeps connection construction in one place and prevents credentials from spreading through your codebase.

Next

The next article covers bucket administration, object CRUD, pagination, range reads, and server-side image transformations in more detail.

Documentation: https://docs.liorans3.sbs

Top comments (0)