Examples
HTML, Next.js, and NestJS upload examples with @oleq-ai/file-manager
Never put OLEQFILES_API_KEY in browser code. The browser posts to your backend; your backend runs the SDK.
| Stack | Client | Server |
|---|---|---|
| HTML | Plain form / fetch | Nest (or any) upload route |
| Next.js | @oleq-ai/file-manager/react hook | App Router Route Handler |
| NestJS | HTML or React | @oleq-ai/file-manager/nest module + controller |
HTML
Post multipart to your API. Point /upload at the NestJS controller below (or an equivalent Express / Next route).
With fetch
Simple path — no upload progress (fetch does not expose it).
<form id="form">
<input type="file" name="file" accept="image/*" required />
<button type="submit">Upload</button>
<p id="status"></p>
</form>
<script>
const form = document.getElementById('form');
const status = document.getElementById('status');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const file = form.file.files[0];
if (!file) return;
const body = new FormData();
body.append('file', file);
status.textContent = 'Uploading…';
try {
const res = await fetch('/upload', { method: 'POST', body });
const data = await res.json();
if (!res.ok) {
status.textContent = data.error || 'Upload failed';
return;
}
status.textContent = 'Done';
console.log(data.id, data.src);
} catch {
status.textContent = 'Upload failed';
}
});
</script>With progress (XMLHttpRequest)
Use XHR when you need a progress bar.
<form id="form">
<input type="file" name="file" accept="image/*" required />
<button type="submit">Upload</button>
<progress id="bar" value="0" max="100" hidden></progress>
<p id="error"></p>
</form>
<script>
const form = document.getElementById('form');
const bar = document.getElementById('bar');
const errorEl = document.getElementById('error');
form.addEventListener('submit', (e) => {
e.preventDefault();
const file = form.file.files[0];
if (!file) return;
const body = new FormData();
body.append('file', file);
bar.hidden = false;
bar.value = 0;
errorEl.textContent = '';
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload');
xhr.upload.onprogress = (ev) => {
if (ev.lengthComputable) {
bar.value = Math.round((ev.loaded / ev.total) * 100);
}
};
xhr.onload = () => {
const data = JSON.parse(xhr.responseText || '{}');
if (xhr.status >= 200 && xhr.status < 300) {
console.log(data.id, data.src);
} else {
errorEl.textContent = data.error || 'Upload failed';
}
};
xhr.onerror = () => {
errorEl.textContent = 'Upload failed';
};
xhr.send(body);
});
</script>Next.js
Client
'use client';
import { useOleqFilesUpload } from '@oleq-ai/file-manager/react';
export function FileUpload() {
const { upload, uploading, progress, error } = useOleqFilesUpload();
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const file = (
e.currentTarget.elements.namedItem('file') as HTMLInputElement
).files?.[0];
if (!file) return;
const result = await upload(file);
if (result) console.log(result.id, result.src);
}
return (
<form onSubmit={onSubmit}>
<input type="file" name="file" accept="image/*" required />
<button type="submit" disabled={uploading}>
{uploading ? 'Uploading…' : 'Upload'}
</button>
{uploading && <progress value={progress} max={100} />}
{error && <p>{error}</p>}
</form>
);
}Optional callback:
const { upload } = useOleqFilesUpload({
endpoint: '/api/upload',
onProgress: (percent) => console.log(`${percent}%`),
});Route Handler
import OleqFiles, { OleqFilesError } from '@oleq-ai/file-manager';
const oleqfiles = new OleqFiles();
export async function POST(req: Request) {
try {
const form = await req.formData();
const file = form.get('file');
if (!(file instanceof File)) {
return Response.json({ error: 'file is required' }, { status: 400 });
}
const result = await oleqfiles.files.upload({
appId: process.env.OLEQFILES_APP_ID!,
name: file.name,
mimeType: file.type || 'application/octet-stream',
data: file,
});
return Response.json({ id: result.id, src: result.src });
} catch (err) {
if (err instanceof OleqFilesError) {
return Response.json({ error: err.message }, { status: err.status });
}
throw err;
}
}Set OLEQFILES_API_KEY and OLEQFILES_APP_ID in server env only.
NestJS
Install the adapter
pnpm add @oleq-ai/file-manager @nestjs/platform-express@oleq-ai/file-manager/nest needs @nestjs/common (already in Nest apps). File uploads use Multer via @nestjs/platform-express.
Register the module
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { OleqFilesModule } from '@oleq-ai/file-manager/nest';
import { UploadController } from './upload.controller';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
OleqFilesModule.forRoot(), // reads OLEQFILES_API_KEY
// or async:
// OleqFilesModule.forRootAsync({
// inject: [ConfigService],
// useFactory: (config: ConfigService) => ({
// apiKey: config.get<string>('OLEQFILES_API_KEY'),
// }),
// }),
],
controllers: [UploadController],
})
export class AppModule {}Upload controller
import {
BadRequestException,
Controller,
HttpException,
Post,
UploadedFile,
UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { OleqFiles, OleqFilesError } from '@oleq-ai/file-manager';
@Controller()
export class UploadController {
constructor(private readonly oleqfiles: OleqFiles) {}
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
async upload(@UploadedFile() file?: Express.Multer.File) {
if (!file) throw new BadRequestException({ error: 'file is required' });
try {
const result = await this.oleqfiles.files.upload({
appId: process.env.OLEQFILES_APP_ID!,
name: file.originalname,
mimeType: file.mimetype || 'application/octet-stream',
data: file.buffer,
});
return { id: result.id, src: result.src };
} catch (err) {
if (err instanceof OleqFilesError) {
throw new HttpException({ error: err.message }, err.status);
}
throw err;
}
}
}Inject OleqFiles anywhere else the same way — list apps, usage, delete, etc.
const { apps } = await this.oleqfiles.apps.list();
const usage = await this.oleqfiles.usage.get();