@nwire/handler — alone
The operation primitive. One typed function declaration that runs on HTTP, on a queue worker, or as an MCP tool — the adopter decides where.
What it does
defineHandler(name, { input, handler })produces a typed operation.- The same definition can be wired via
app.wire(httpBinding, handler),app.wire(queueBinding, handler), orapp.wire(toolBinding, handler). - No transport coupling in your handler body —
ctxis the same shape across all of them.
Install
bash
pnpm add @nwire/handler zodDeclare once
ts
import { defineHandler } from "@nwire/handler"
import { z } from "zod"
export const summarizeText = defineHandler("ai.summarize-text", {
input: z.object({ text: z.string().max(50_000) }),
handler: async (ctx) => ({
summary: await callLLM(ctx.input),
}),
})Wire it on multiple transports
ts
import { createApp } from "@nwire/app"
import { endpoint } from "@nwire/endpoint"
import { post } from "@nwire/wires/http"
import { queue } from "@nwire/wires/queue"
import { tool } from "@nwire/wires/mcp"
import { httpKoa } from "@nwire/koa"
import { queueInMemory } from "@nwire/queue"
import { mcpAdapter } from "@nwire/mcp"
import { z } from "zod"
const app = createApp({ appName: "ai-tools" })
// One handler, three transports — no per-transport code change.
app.wire(post("/summarize", { body: z.object({ text: z.string() }) }), summarizeText)
app.wire(queue("ai.summarize"), summarizeText)
app.wire(tool("summarize-text", { input: z.object({ text: z.string() }) }), summarizeText)
await app.start()
await endpoint("ai-tools", { port: 3000 })
.use(httpKoa({ prefix: "/api" }))
.use(queueInMemory())
.use(mcpAdapter())
.mount(app)
.run()When to use this and not defineAction
defineAction (from @nwire/forge) carries domain metadata (persona, journeyStep, emits) and binds the handler into the forge dispatch pipeline alongside actors, events, projections, and workflows.
defineHandler is the plain operation primitive without forge's domain machinery. Reach for it when:
- You want one operation surface across HTTP + queue + MCP and your code is procedural (no actor, no event emission).
- You're building an LLM tool, an internal admin endpoint, or a wrapper around a third-party API.
If you find yourself wanting events, actors, or projections, climb to defineAction in @nwire/forge.