Context
Attach per-request data such as the caller, then read it inside any procedure.
The type argument to tacho<C>() is the context shape. handle() puts req on context. Pass createContext to merge more.
import { const tacho: <C extends Context = {}>() => Builder<C, undefined, unique symbol>tacho } from "tacho";
import { function handle<R extends AnyRouter, C extends Context = {}>(router: R, opts?: HandleOptions<C>): (request: Request) => Promise<Response>handle } from "tacho/transport/fetch";
const const rpc: Builder<{
req: Request;
user?: string;
}, undefined, unique symbol>
rpc = tacho<{
req: Request;
user?: string;
}>(): Builder<{
req: Request;
user?: string;
}, undefined, unique symbol>
tacho<{ req: Requestreq: Request; user?: string | undefineduser?: string }>();
export const const router: {
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}
router = const rpc: <{
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}>(def: {
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}) => {
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}
rpc({
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>
me: const rpc: Builder<{
req: Request;
user?: string;
}, undefined, unique symbol>
rpc.run: <string | undefined>(fn: (opts: {
input: undefined;
ctx: {
req: Request;
user?: string;
};
}) => string | Promise<string | undefined> | undefined) => ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>
run(({ ctx: {
req: Request;
user?: string;
}
ctx }) => ctx: {
req: Request;
user?: string;
}
ctx.user?: string | undefineduser),
});
handle<{
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}, {
user: string | undefined;
}>(router: {
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}, opts?: HandleOptions<{
user: string | undefined;
}> | undefined): (request: Request) => Promise<Response>
handle(const router: {
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}
router, {
createContext?: ((req: Request) => {
user: string | undefined;
} | Promise<{
user: string | undefined;
}>) | undefined
createContext: (req: Requestreq) => ({
user: string | undefineduser: req: Requestreq.Request.headers: HeadersThe **`headers`** read-only property of the Request interface contains the Headers object associated with the request.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/headers)headers.Headers.get(name: string): string | nullThe **`get()`** method of the Headers interface returns a byte string of all the values of a header within a Headers object with a given name. If the requested header doesn't exist in the Headers object, it returns null.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/get)get("x-user") ?? var undefinedundefined,
}),
});
Throw from createContext → JSON-RPC INTERNAL_ERROR.
Set context per call in middleware with next({ ctx }):
import { class RpcErrorRpcError, const tacho: <C extends Context = {}>() => Builder<C, undefined, unique symbol>tacho } from "tacho";
const const rpc: Builder<{
req: Request;
user?: string;
}, undefined, unique symbol>
rpc = tacho<{
req: Request;
user?: string;
}>(): Builder<{
req: Request;
user?: string;
}, undefined, unique symbol>
tacho<{ req: Requestreq: Request; user?: string | undefineduser?: string }>();
const const withUser: Builder<{
req: Request;
user?: string;
}, undefined, unique symbol>
withUser = const rpc: Builder<{
req: Request;
user?: string;
}, undefined, unique symbol>
rpc.function use(mw: Middleware<{
req: Request;
user?: string;
}>): Builder<{
req: Request;
user?: string;
}, undefined, unique symbol>
use(async ({ ctx: {
req: Request;
user?: string;
}
ctx, next: (opts?: {
ctx: Partial<{
req: Request;
user?: string;
}>;
} | undefined) => Promise<unknown>
next }) => {
const const user: string | nulluser = ctx: {
req: Request;
user?: string;
}
ctx.req: Requestreq.Request.headers: HeadersThe **`headers`** read-only property of the Request interface contains the Headers object associated with the request.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/headers)headers.Headers.get(name: string): string | nullThe **`get()`** method of the Headers interface returns a byte string of all the values of a header within a Headers object with a given name. If the requested header doesn't exist in the Headers object, it returns null.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Headers/get)get("x-user");
if (!const user: string | nulluser) {
throw new new RpcError({ code, message, data }: {
code: number;
message: string;
data?: unknown;
}): RpcError
RpcError({ code: numbercode: -32001, message: stringmessage: "unauthorized" });
}
return next: (opts?: {
ctx: Partial<{
req: Request;
user?: string;
}>;
} | undefined) => Promise<unknown>
next({ ctx: Partial<{
req: Request;
user?: string;
}>
ctx: { user?: string | undefineduser } });
});
export const const router: {
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}
router = const rpc: <{
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}>(def: {
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}) => {
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>;
}
rpc({
me: ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>
me: const withUser: Builder<{
req: Request;
user?: string;
}, undefined, unique symbol>
withUser.run: <string | undefined>(fn: (opts: {
input: undefined;
ctx: {
req: Request;
user?: string;
};
}) => string | Promise<string | undefined> | undefined) => ProcedureDef<{
req: Request;
user?: string;
}, undefined, string | undefined>
run(({ ctx: {
req: Request;
user?: string;
}
ctx }) => ctx: {
req: Request;
user?: string;
}
ctx.user?: string | undefineduser),
});