Skip to content

Hono

The Hono adapter integrates Uploadista with Hono framework, enabling edge deployments on Cloudflare Workers, Cloudflare Pages, and other edge runtimes. Perfect for global, low-latency file uploads.

npm install @uploadista/server @uploadista/adapters-hono hono

First, define your flows:

flows.ts
import {
createFlow,
createInputNode,
createOutputNode,
createOptimizeNode,
} from "@uploadista/flow";
export const optimizeFlow = createFlow({
flowId: "optimize-image",
name: "Optimize Image",
nodes: {
input: createInputNode("input"),
optimize: createOptimizeNode("optimize", { format: "webp", quality: 80 }),
output: createOutputNode("output"),
},
edges: [
{ source: "input", target: "optimize" },
{ source: "optimize", target: "output" },
],
});
export const flows = {
"optimize-image": optimizeFlow,
};

Then set up the server:

import { Hono } from "hono";
import { createUploadistaServer } from "@uploadista/server";
import { honoAdapter } from "@uploadista/adapters-hono";
import { s3Store } from "@uploadista/data-store-s3";
import { redisKvStore } from "@uploadista/kv-store-redis";
import { flows } from "./flows";
const app = new Hono();
const uploadistaServer = await createUploadistaServer({
dataStore: s3Store({ /* S3 config */ }),
kvStore: redisKvStore({ /* Redis config */ }),
flows,
adapter: honoAdapter(),
});
app.all("/uploadista/api/*", (c) => uploadistaServer.handler(c));
export default app;
import { Hono } from "hono";
import { cors } from "hono/cors";
import { createUploadistaServer } from "@uploadista/server";
import { honoAdapter } from "@uploadista/adapters-hono";
import { s3Store } from "@uploadista/data-store-s3";
import { cloudflareKvStore } from "@uploadista/kv-store-cloudflare-kv";
import { flows } from "./flows";
const app = new Hono();
app.use(cors({
origin: (origin) => origin, // Configure for your domains
allowMethods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
}));
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const uploadistaServer = await createUploadistaServer({
dataStore: s3Store({
deliveryUrl: env.R2_DELIVERY_URL,
s3ClientConfig: {
bucket: env.R2_BUCKET,
region: "auto",
credentials: {
accessKeyId: env.R2_ACCESS_KEY_ID,
secretAccessKey: env.R2_SECRET_ACCESS_KEY,
},
endpoint: env.R2_ENDPOINT,
},
}),
kvStore: cloudflareKvStore({ kv: env.KV_METADATA }),
flows,
adapter: honoAdapter({
authMiddleware: async (c) => {
const token = c.req.header("Authorization")?.split(" ")[1];
if (!token) return null;
try {
const payload = await verify(token, env.JWT_SECRET);
return {
clientId: payload.sub as string,
permissions: payload.permissions as string[] || [],
};
} catch {
return null;
}
},
}),
});
app.all("/uploadista/api/*", (c) => uploadistaServer.handler(c));
return app.fetch(request, env);
},
};
name = "uploadista-server"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[[r2_buckets]]
binding = "R2_UPLOADS"
bucket_name = "uploads-prod"
[[kv_namespaces]]
binding = "KV_METADATA"
id = "your-kv-namespace-id"
[vars]
ALLOWED_ORIGINS = "https://example.com"
[[routes]]
pattern = "api.example.com/uploadista/*"
zone_name = "example.com"

Hono supports WebSockets across multiple runtimes. WebSocket connections enable real-time progress updates for uploads and flow processing.

import { serve } from "@hono/node-server";
import { createNodeWebSocket } from "@hono/node-ws";
import { Hono } from "hono";
import { flows } from "./flows";
const app = new Hono();
const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });
const uploadistaServer = await createUploadistaServer({
dataStore: s3Store({ /* config */ }),
kvStore: redisKvStore({ /* config */ }),
flows,
adapter: honoAdapter(),
});
// HTTP routes
app.all("/uploadista/api/*", (c) => uploadistaServer.handler(c));
// WebSocket routes for real-time progress
app.get(
"/uploadista/ws/upload/:uploadId",
upgradeWebSocket(uploadistaServer.websocketHandler)
);
app.get(
"/uploadista/ws/flow/:jobId",
upgradeWebSocket(uploadistaServer.websocketHandler)
);
const server = serve({ port: 3000, fetch: app.fetch });
injectWebSocket(server);

Bun has native WebSocket support built-in:

import { Hono } from "hono";
import { createBunWebSocket } from "hono/bun";
import { flows } from "./flows";
const app = new Hono();
const { upgradeWebSocket, websocket } = createBunWebSocket();
const uploadistaServer = await createUploadistaServer({
dataStore: s3Store({ /* config */ }),
kvStore: redisKvStore({ /* config */ }),
flows,
adapter: honoAdapter(),
});
// HTTP routes
app.all("/uploadista/api/*", (c) => uploadistaServer.handler(c));
// WebSocket routes for real-time progress
app.get(
"/uploadista/ws/upload/:uploadId",
upgradeWebSocket(uploadistaServer.websocketHandler)
);
app.get(
"/uploadista/ws/flow/:jobId",
upgradeWebSocket(uploadistaServer.websocketHandler)
);
export default {
port: 3000,
fetch: app.fetch,
websocket,
};
import { Hono } from "hono";
import { upgradeWebSocket } from "hono/deno";
import { flows } from "./flows.ts";
const app = new Hono();
const uploadistaServer = await createUploadistaServer({
dataStore: s3Store({ /* config */ }),
kvStore: redisKvStore({ /* config */ }),
flows,
adapter: honoAdapter(),
});
// HTTP routes
app.all("/uploadista/api/*", (c) => uploadistaServer.handler(c));
// WebSocket routes
app.get(
"/uploadista/ws/upload/:uploadId",
upgradeWebSocket(uploadistaServer.websocketHandler)
);
app.get(
"/uploadista/ws/flow/:jobId",
upgradeWebSocket(uploadistaServer.websocketHandler)
);
Deno.serve(app.fetch);
  • Zero cold starts
  • Global edge distribution
  • Cloudflare R2 storage
  • Cloudflare KV metadata
  • WebSocket progress updates
import { imagePlugin } from "@uploadista/flow-images-sharp";
import { redisEventBroadcaster } from "@uploadista/event-broadcaster-redis";
const uploadistaServer = await createUploadistaServer({
// Required
dataStore: s3Store({ /* config */ }), // File storage backend
kvStore: redisKvStore({ /* config */ }), // Metadata storage
flows, // Flow definitions object
adapter: honoAdapter(), // Framework adapter
// Optional
plugins: [imagePlugin()], // Processing plugins
eventBroadcaster: redisEventBroadcaster({ /* config */ }), // Multi-instance sync
withTracing: true, // OpenTelemetry tracing
baseUrl: "uploadista", // API base path (default)
});
Terminal window
# Deploy to Cloudflare Workers
npx wrangler deploy
# View logs
npx wrangler tail
# Check deployment
curl https://api.example.com/uploadista/api/health