N3 is a v1 S3-shaped blob storage platform. It exposes a custom REST API under
/api/v1, a dashboard backed by Better Auth sessions, a local filesystem storage
adapter, and a typed SDK package.
The repo now ships two API surfaces:
- Internal dashboard APIs:
apps/webunder/api/dashboard/*(session auth). - External public APIs:
apps/apiHono gateway under/api/v1/*(API-key auth).
- Node.js 18 or newer
- pnpm 9
- PostgreSQL-compatible database
- Install dependencies.
pnpm install- Create
.envfrom the example and fill in real values.
cp .env.example .env- Apply the database schema.
pnpm --filter @repo/database db:migrate:dev- Start the web app.
pnpm --filter web dev- Start the public API gateway.
pnpm --filter api devThe dashboard runs at http://localhost:3000.
The public API gateway runs at http://localhost:8787.
POSTGRES_URL is required for Prisma and Better Auth persistence.
BETTER_AUTH_SECRET must be a strong secret for non-throwaway local work and all
deployments.
BETTER_AUTH_URL should match the externally visible web URL, for example
http://localhost:3000 locally.
N3_STORAGE_ROOT optionally overrides the local blob storage directory.
N3_MAX_OBJECT_SIZE_BYTES optionally sets the v1 object upload limit. The
default is 10 MiB.
PUBLIC_API_UPSTREAM optionally sets where the Hono public API forwards versioned
requests. Default: http://127.0.0.1:3000.
Dashboard endpoints use Better Auth browser sessions under /api/dashboard.
Machine API endpoints under /api/v1 require product API keys using:
x-n3-access-key-id: n3_live_...
x-n3-secret-access-key: n3s_...
Dashboard cookies are not sufficient for /api/v1 object or bucket APIs.
apps/api does not expose /api/dashboard/*.
After signing up in the dashboard, create an API key and use the one-time secret
with the SDK or curl.
curl -X POST http://localhost:8787/api/v1/buckets \
-H "content-type: application/json" \
-H "x-n3-access-key-id: $N3_ACCESS_KEY_ID" \
-H "x-n3-secret-access-key: $N3_SECRET_ACCESS_KEY" \
--data '{"name":"photos"}'
curl -X PUT http://localhost:8787/api/v1/buckets/photos/objects/hello.txt \
-H "content-type: text/plain" \
-H "x-n3-access-key-id: $N3_ACCESS_KEY_ID" \
-H "x-n3-secret-access-key: $N3_SECRET_ACCESS_KEY" \
--data 'hello storage'
curl http://localhost:8787/api/v1/buckets/photos/objects/hello.txt \
-H "x-n3-access-key-id: $N3_ACCESS_KEY_ID" \
-H "x-n3-secret-access-key: $N3_SECRET_ACCESS_KEY"Before claiming a change is ready, run:
pnpm lint
pnpm check-types
pnpm test
pnpm build