@papack/api
v1.1.2
Published
Minimal, opinionated HTTP API core for people who want full control over IO, parsing, streaming, and errors.
Readme
@papack/api
Minimal, opinionated HTTP API core for people who want full control over IO, parsing, streaming, and errors. No magic. No Hooks. No implicit parsing.
Context is explicitly extensible. You can attach schemas, business logic, services, or infrastructure once, and they are available on ctx in every handler, you dont need hooks.
Core Rules
- Transport is dumb. handlers decide everything.
ctx.req.bodyis always string (if present).- Body is read exactly once by the core.
- Parsing is never automatic.
- Streaming stays streaming.
Context
- App context is injected once
- Available in all handlers
- No mutation rules enforced
const api = new Api({ value: "from-context" });Design Intent
- Zero hidden transformations
- Predictable transport semantics
- Streaming stays streaming
- Parsing is a user decision
RPC
POSTonlyreqis the API surface- Return value will be strinifyed with
JSON.stringify
server.rpc("/rpc", (ctx) => {
return {
raw: ctx.req.body,
value: ctx.value,
};
});SSE
GETonly- Real
text/event-stream - Explicit
emit() - Guaranteed
onCleanup()on disconnect
server.sse<{ tick: number }>("/events", (ctx) => {
let i = 0;
const id = setInterval(() => {
ctx.emit("tick", i++);
}, 1000);
ctx.onCleanup(() => {
clearInterval(id);
});
});Blob (raw by design)
- Return
Buffer | Readable - No headers added
- No
Content-Typeguessing - Streams use
Transfer-Encoding: chunked - Full backpressure control
server.blob("/file", () => {
return fs.createReadStream("./big.bin");
});Upload
POSTonly- Request body is binary
ctx.reqis aReadable- Core does not read or buffer
- No
ctx.req.body - No multipart assumptions
server.upload("/upload", async (ctx) => {
for await (const chunk of ctx.req) {
// stream processing
}
return "OK";
});CORS
CORS is handled centrally by the core when enabled at instantiation. If configured, the server:
- sets
Access-Control-Allow-Originto a concrete origin - enables
Access-Control-Allow-Credentialsfor session cookies - responds to
OPTIONSpreflight requests with204
const api = new Api(ctx, {
cors: {
origin: "http://localhost:5173",
},
});Errors
- Explicit
HttpErrors only - Status code + stable
"ERROR_CODE" - No messages
- No leaking
Examples:
"NOT_FOUND"
"METHOD_NOT_ALLOWED"
"BAD_REQUEST"