Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

trpc-bun-adapter

Package Overview
Dependencies
Maintainers
0
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

trpc-bun-adapter - npm Package Compare versions

Comparing version 1.1.0 to 1.1.1

dist/createBunHttpHandler.d.ts

48

dist/index.d.ts

@@ -1,45 +0,3 @@

import * as bun from 'bun';
import { Server, ServerWebSocket, WebSocketHandler, ServeOptions } from 'bun';
import { AnyRouter, inferRouterContext } from '@trpc/server';
import { HTTPBaseHandlerOptions, BaseHandlerOptions } from '@trpc/server/http';
import { TRPCClientOutgoingMessage } from '@trpc/server/rpc';
type CreateBunContextOptions = {
req: Request;
};
type BunHttpHandlerOptions<TRouter extends AnyRouter> = HTTPBaseHandlerOptions<TRouter, Request> & {
endpoint?: string;
createContext?: (opts: CreateBunContextOptions) => inferRouterContext<TRouter> | Promise<inferRouterContext<TRouter>>;
};
declare function createBunHttpHandler<TRouter extends AnyRouter>(opts: BunHttpHandlerOptions<TRouter> & {
emitWsUpgrades?: boolean;
}): (request: Request, server: Server) => Response | Promise<Response> | undefined;
type BunWSAdapterOptions<TRouter extends AnyRouter> = BaseHandlerOptions<TRouter, Request> & {
createContext?: (params: {
req: Request;
client: ServerWebSocket<BunWSClientCtx>;
}) => Promise<unknown> | unknown;
};
type BunWSClientCtx = {
req: Request;
handleRequest: (msg: TRPCClientOutgoingMessage) => Promise<void>;
unsubscribe(): void;
};
declare function createBunWSHandler<TRouter extends AnyRouter>(opts: BunWSAdapterOptions<TRouter>): WebSocketHandler<BunWSClientCtx>;
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
declare function createBunServeHandler<TRouter extends AnyRouter>(opts: BunHttpHandlerOptions<TRouter>, serveOptions?: Optional<ServeOptions, "fetch">): {
fetch(req: Request, server: Server): Promise<Response | undefined>;
websocket: bun.WebSocketHandler<BunWSClientCtx>;
error?: ((this: Server, request: bun.Errorlike) => Response | Promise<Response> | Promise<undefined> | undefined) | undefined;
id?: string | null | undefined;
port?: string | number | undefined;
reusePort?: boolean | undefined;
hostname?: string | undefined;
unix?: undefined;
maxRequestBodySize?: number | undefined;
development?: boolean | undefined;
};
export { type BunHttpHandlerOptions, type BunWSAdapterOptions, type BunWSClientCtx, type CreateBunContextOptions, createBunHttpHandler, createBunServeHandler, createBunWSHandler };
export * from "./createBunHttpHandler";
export * from "./createBunWSHandler";
export * from "./createBunServeHandler";

@@ -7,14 +7,20 @@ "use strict";

var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
if ((from && typeof from === "object") || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, {
get: () => from[key],
enumerable:
!(desc = __getOwnPropDesc(from, key)) ||
desc.enumerable,
});
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __toCommonJS = (mod) =>
__copyProps(__defProp({}, "__esModule", { value: true }), mod);

@@ -24,5 +30,5 @@ // src/index.ts

__export(src_exports, {
createBunHttpHandler: () => createBunHttpHandler,
createBunServeHandler: () => createBunServeHandler,
createBunWSHandler: () => createBunWSHandler
createBunHttpHandler: () => createBunHttpHandler,
createBunServeHandler: () => createBunServeHandler,
createBunWSHandler: () => createBunWSHandler,
});

@@ -34,16 +40,20 @@ module.exports = __toCommonJS(src_exports);

function createBunHttpHandler(opts) {
return (request, server) => {
const url = new URL(request.url);
if (opts.endpoint && !url.pathname.startsWith(opts.endpoint)) {
return;
}
if (opts.emitWsUpgrades && server.upgrade(request, { data: { req: request } })) {
return new Response(null, { status: 101 });
}
return (0, import_fetch.fetchRequestHandler)({
endpoint: opts.endpoint ?? "",
...opts,
req: request
});
};
return (request, server) => {
const url = new URL(request.url);
if (opts.endpoint && !url.pathname.startsWith(opts.endpoint)) {
return;
}
if (
opts.emitWsUpgrades &&
server.upgrade(request, { data: { req: request } })
) {
return new Response(null, { status: 101 });
}
return (0, import_fetch.fetchRequestHandler)({
endpoint: opts.endpoint ?? "",
router: opts.router,
req: request,
createContext: opts.createContext,
});
};
}

@@ -56,223 +66,230 @@

function createBunWSHandler(opts) {
const { router, createContext } = opts;
const respond = (client, untransformedJSON) => {
client.send(
JSON.stringify(
(0, import_server.transformTRPCResponse)(
opts.router._def._config,
untransformedJSON
)
)
);
};
return {
async open(client) {
const { req } = client.data;
const clientSubscriptions = /* @__PURE__ */ new Map();
const ctxPromise = createContext?.({ req, client });
let ctx = void 0;
await (async () => {
try {
ctx = await ctxPromise;
} catch (cause) {
const error = (0, import_server.getTRPCErrorFromUnknown)(cause);
opts.onError?.({
error,
path: void 0,
type: "unknown",
ctx,
req,
input: void 0
});
respond(client, {
id: null,
error: (0, import_server.getErrorShape)({
config: router._def._config,
error,
type: "unknown",
path: void 0,
input: void 0,
ctx
})
});
setImmediate(() => client.close());
}
})();
const stopSubscription = (subscription, {
id,
jsonrpc
}) => {
subscription.unsubscribe();
respond(client, {
id,
jsonrpc,
result: {
type: "stopped"
}
});
};
client.data.handleRequest = async (msg) => {
const { id, jsonrpc } = msg;
if (id === null) {
throw new import_server.TRPCError({
code: "BAD_REQUEST",
message: "`id` is required"
});
}
if (msg.method === "subscription.stop") {
const sub = clientSubscriptions.get(id);
if (sub) {
stopSubscription(sub, { id, jsonrpc });
}
clientSubscriptions.delete(id);
return;
}
const { path, input } = msg.params;
const type = msg.method;
try {
await ctxPromise;
const result = await (0, import_server.callProcedure)({
procedures: router._def.procedures,
path,
input,
getRawInput: () => Promise.resolve(input),
ctx,
type
});
if (type === "subscription") {
if (!(0, import_observable.isObservable)(result)) {
throw new import_server.TRPCError({
message: `Subscription ${path} did not return an observable`,
code: "INTERNAL_SERVER_ERROR"
});
}
} else {
respond(client, {
id,
jsonrpc,
result: {
type: "data",
data: result
}
});
return;
}
const observable = result;
const sub = observable.subscribe({
next(data) {
respond(client, {
id,
jsonrpc,
result: {
type: "data",
data
const { router, createContext } = opts;
const respond = (client, untransformedJSON) => {
client.send(
JSON.stringify(
(0, import_server.transformTRPCResponse)(
opts.router._def._config,
untransformedJSON,
),
),
);
};
return {
async open(client) {
const { req } = client.data;
const clientSubscriptions = /* @__PURE__ */ new Map();
const ctxPromise = createContext?.({ req, client });
let ctx = void 0;
await (async () => {
try {
ctx = await ctxPromise;
} catch (cause) {
const error = (0, import_server.getTRPCErrorFromUnknown)(
cause,
);
opts.onError?.({
error,
path: void 0,
type: "unknown",
ctx,
req,
input: void 0,
});
respond(client, {
id: null,
error: (0, import_server.getErrorShape)({
config: router._def._config,
error,
type: "unknown",
path: void 0,
input: void 0,
ctx,
}),
});
setImmediate(() => client.close());
}
});
},
error(err) {
const error = (0, import_server.getTRPCErrorFromUnknown)(err);
opts.onError?.({
error,
path,
type,
ctx,
req,
input
});
respond(client, {
id,
jsonrpc,
error: (0, import_server.getErrorShape)({
config: router._def._config,
error,
type,
path,
input,
ctx
})
});
},
complete() {
respond(client, {
id,
jsonrpc,
result: {
type: "stopped"
})();
const stopSubscription = (subscription, { id, jsonrpc }) => {
subscription.unsubscribe();
respond(client, {
id,
jsonrpc,
result: {
type: "stopped",
},
});
};
client.data.handleRequest = async (msg) => {
const { id, jsonrpc } = msg;
if (id === null) {
throw new import_server.TRPCError({
code: "BAD_REQUEST",
message: "`id` is required",
});
}
});
if (msg.method === "subscription.stop") {
const sub = clientSubscriptions.get(id);
if (sub) {
stopSubscription(sub, { id, jsonrpc });
}
clientSubscriptions.delete(id);
return;
}
const { path, input } = msg.params;
const type = msg.method;
try {
await ctxPromise;
const result = await (0, import_server.callProcedure)({
procedures: router._def.procedures,
path,
input,
getRawInput: () => Promise.resolve(input),
ctx,
type,
});
if (type === "subscription") {
if (!(0, import_observable.isObservable)(result)) {
throw new import_server.TRPCError({
message: `Subscription ${path} did not return an observable`,
code: "INTERNAL_SERVER_ERROR",
});
}
} else {
respond(client, {
id,
jsonrpc,
result: {
type: "data",
data: result,
},
});
return;
}
const observable = result;
const sub = observable.subscribe({
next(data) {
respond(client, {
id,
jsonrpc,
result: {
type: "data",
data,
},
});
},
error(err) {
const error = (0,
import_server.getTRPCErrorFromUnknown)(err);
opts.onError?.({
error,
path,
type,
ctx,
req,
input,
});
respond(client, {
id,
jsonrpc,
error: (0, import_server.getErrorShape)({
config: router._def._config,
error,
type,
path,
input,
ctx,
}),
});
},
complete() {
respond(client, {
id,
jsonrpc,
result: {
type: "stopped",
},
});
},
});
if (client.readyState !== WebSocket.OPEN) {
sub.unsubscribe();
return;
}
if (clientSubscriptions.has(id)) {
stopSubscription(sub, { id, jsonrpc });
throw new import_server.TRPCError({
message: `Duplicate id ${id}`,
code: "BAD_REQUEST",
});
}
clientSubscriptions.set(id, sub);
respond(client, {
id,
jsonrpc,
result: {
type: "started",
},
});
} catch (cause) {
const error = (0, import_server.getTRPCErrorFromUnknown)(
cause,
);
opts.onError?.({ error, path, type, ctx, req, input });
respond(client, {
id,
jsonrpc,
error: (0, import_server.getErrorShape)({
config: router._def._config,
error,
type,
path,
input,
ctx,
}),
});
}
};
client.data.unsubscribe = () => {
for (const sub of clientSubscriptions.values()) {
sub.unsubscribe();
}
clientSubscriptions.clear();
};
},
async close(client) {
client.data.unsubscribe?.();
},
async message(client, message) {
try {
const msgJSON = JSON.parse(message.toString());
const msgs = Array.isArray(msgJSON) ? msgJSON : [msgJSON];
const promises = msgs
.map((raw) =>
(0, import_rpc.parseTRPCMessage)(
raw,
router._def._config.transformer,
),
)
.map(client.data.handleRequest);
await Promise.all(promises);
} catch (cause) {
const error = new import_server.TRPCError({
code: "PARSE_ERROR",
cause,
});
respond(client, {
id: null,
error: (0, import_server.getErrorShape)({
config: router._def._config,
error,
type: "unknown",
path: void 0,
input: void 0,
ctx: void 0,
}),
});
}
});
if (client.readyState !== WebSocket.OPEN) {
sub.unsubscribe();
return;
}
if (clientSubscriptions.has(id)) {
stopSubscription(sub, { id, jsonrpc });
throw new import_server.TRPCError({
message: `Duplicate id ${id}`,
code: "BAD_REQUEST"
});
}
clientSubscriptions.set(id, sub);
respond(client, {
id,
jsonrpc,
result: {
type: "started"
}
});
} catch (cause) {
const error = (0, import_server.getTRPCErrorFromUnknown)(cause);
opts.onError?.({ error, path, type, ctx, req, input });
respond(client, {
id,
jsonrpc,
error: (0, import_server.getErrorShape)({
config: router._def._config,
error,
type,
path,
input,
ctx
})
});
}
};
client.data.unsubscribe = () => {
for (const sub of clientSubscriptions.values()) {
sub.unsubscribe();
}
clientSubscriptions.clear();
};
},
async close(client) {
client.data.unsubscribe?.();
},
async message(client, message) {
try {
const msgJSON = JSON.parse(message.toString());
const msgs = Array.isArray(msgJSON) ? msgJSON : [msgJSON];
const promises = msgs.map(
(raw) => (0, import_rpc.parseTRPCMessage)(raw, router._def._config.transformer)
).map(client.data.handleRequest);
await Promise.all(promises);
} catch (cause) {
const error = new import_server.TRPCError({
code: "PARSE_ERROR",
cause
});
respond(client, {
id: null,
error: (0, import_server.getErrorShape)({
config: router._def._config,
error,
type: "unknown",
path: void 0,
input: void 0,
ctx: void 0
})
});
}
}
};
},
};
}

@@ -282,25 +299,26 @@

function createBunServeHandler(opts, serveOptions) {
const trpcHandler = createBunHttpHandler({
...opts,
emitWsUpgrades: true
});
return {
...serveOptions,
async fetch(req, server) {
const trpcReponse = trpcHandler(req, server);
if (trpcReponse) {
return trpcReponse;
}
return serveOptions?.fetch?.call(server, req, server);
},
websocket: createBunWSHandler(opts)
};
const trpcHandler = createBunHttpHandler({
...opts,
emitWsUpgrades: true,
});
return {
...serveOptions,
async fetch(req, server) {
const trpcReponse = trpcHandler(req, server);
if (trpcReponse) {
return trpcReponse;
}
return serveOptions?.fetch?.call(server, req, server);
},
websocket: createBunWSHandler(opts),
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createBunHttpHandler,
createBunServeHandler,
createBunWSHandler
});
0 &&
(module.exports = {
createBunHttpHandler,
createBunServeHandler,
createBunWSHandler,
});
/* istanbul ignore next -- @preserve */
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map
{
"name": "trpc-bun-adapter",
"version": "1.1.0",
"description": "TRPC adapter for bun js runtime",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"scripts": {
"test": "bun test",
"fmt": "bunx @biomejs/biome format --write .",
"build": "npx tsup src/index.ts --format cjs,esm --dts --clean --sourcemap"
},
"keywords": [
"bun",
"trpc",
"adapter",
"websocket"
],
"repository": {
"url": "git+https://github.com/cah4a/trpc-bun-adapter.git"
},
"bugs": "https://github.com/cah4a/trpc-bun-adapter/issues",
"author": "Sancha <cah4o3@gmail.com>",
"license": "MIT",
"devDependencies": {
"@trpc/server": "next",
"bun-types": "^1.0.20",
"tsup": "^8.0.1",
"typescript": "^5.3.3"
},
"peerDependencies": {
"@trpc/server": "^11.0.0-next-beta.228"
}
"name": "trpc-bun-adapter",
"version": "1.1.1",
"description": "TRPC adapter for bun js runtime",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"src",
"package.json",
"LICENSE.txt",
"README.md",
"tsconfig.json"
],
"scripts": {
"test": "bun test",
"fmt": "bunx @biomejs/biome format --write .",
"build": "npx tsup src/index.ts --format cjs,esm --dts --clean --sourcemap"
},
"keywords": ["bun", "trpc", "adapter", "websocket"],
"repository": {
"url": "git+https://github.com/cah4a/trpc-bun-adapter.git"
},
"bugs": "https://github.com/cah4a/trpc-bun-adapter/issues",
"author": "Sancha <cah4o3@gmail.com>",
"license": "MIT",
"devDependencies": {
"@trpc/server": "next",
"bun-types": "^1.1.17",
"tsup": "^8.0.1",
"typescript": "^5.5.2"
},
"peerDependencies": {
"@trpc/server": "^11.0.0-next-beta.228"
}
}

@@ -45,2 +45,6 @@ # tRPC Bun Adapter

## Example
for a full example, see the [example](./example/) directory.
## API Reference

@@ -84,3 +88,3 @@

fetch(request, server) {
// will be fired if it's not a TRPC request
// will be executed if it's not a TRPC request
return new Response("Hello world");

@@ -93,2 +97,22 @@ },

To add response headers like Cross-origin resource sharing (CORS) use `responseMeta` option:
```ts
Bun.serve(
createBunServeHandler({
router: appRouter,
responseMeta(opts) {
return {
status: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization"
}
};
}
}
)
);
```
### createBunHttpHandler

@@ -95,0 +119,0 @@

import { Server } from "bun";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import type { AnyRouter, inferRouterContext } from "@trpc/server";
import type { HTTPBaseHandlerOptions } from "@trpc/server/http";
import type {
FetchHandlerRequestOptions,
FetchCreateContextFnOptions,
} from "@trpc/server/adapters/fetch";
export type CreateBunContextOptions = { req: Request };
export type CreateBunContextOptions = FetchCreateContextFnOptions;
export type BunHttpHandlerOptions<TRouter extends AnyRouter> =
HTTPBaseHandlerOptions<TRouter, Request> & {
FetchHandlerRequestOptions<TRouter> & {
endpoint?: string;

@@ -34,7 +37,7 @@ createContext?: (

return fetchRequestHandler({
endpoint: opts.endpoint ?? "",
...opts,
req: request,
endpoint: opts.endpoint ?? "",
});
};
}
import type { ServeOptions, Server } from "bun";
import { createBunWSHandler } from "./createBunWSHandler";
import { BunWSAdapterOptions, createBunWSHandler } from "./createBunWSHandler";
import {

@@ -12,3 +12,3 @@ BunHttpHandlerOptions,

export function createBunServeHandler<TRouter extends AnyRouter>(
opts: BunHttpHandlerOptions<TRouter>,
opts: BunHttpHandlerOptions<TRouter> & BunWSAdapterOptions<TRouter>,
serveOptions?: Optional<ServeOptions, "fetch">,

@@ -15,0 +15,0 @@ ) {

@@ -11,3 +11,3 @@ import { ServerWebSocket, WebSocketHandler } from "bun";

callProcedure,
getErrorShape,
getErrorShape,
transformTRPCResponse,

@@ -19,13 +19,22 @@ getTRPCErrorFromUnknown,

import { isObservable, Unsubscribable } from "@trpc/server/observable";
import type { BaseHandlerOptions } from "@trpc/server/http";
import type { BaseHandlerOptions } from "@trpc/server/src/@trpc/server/http";
import type { CreateContextCallback } from "@trpc/server/src/@trpc/server";
import type { MaybePromise } from "@trpc/server/src/unstable-core-do-not-import";
import type { NodeHTTPCreateContextFnOptions } from "@trpc/server/src/adapters/node-http";
export type CreateBunWSSContextFnOptions = Omit<
NodeHTTPCreateContextFnOptions<Request, ServerWebSocket<BunWSClientCtx>>,
"info"
>;
export type BunWSAdapterOptions<TRouter extends AnyRouter> = BaseHandlerOptions<
TRouter,
Request
> & {
createContext?: (params: {
req: Request;
client: ServerWebSocket<BunWSClientCtx>;
}) => Promise<unknown> | unknown;
};
> &
CreateContextCallback<
inferRouterContext<TRouter>,
(
opts: CreateBunWSSContextFnOptions,
) => MaybePromise<inferRouterContext<TRouter>>
>;

@@ -65,3 +74,6 @@ export type BunWSClientCtx = {

const ctxPromise = createContext?.({ req, client });
const ctxPromise = createContext?.({
req,
res: client,
});
let ctx: inferRouterContext<TRouter> | undefined = undefined;

@@ -68,0 +80,0 @@ await (async () => {

{
"compilerOptions": {
"declaration": true,
"baseUrl": "src",
"target": "esnext",
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"emitDecoratorMetadata": true,
"emitDeclarationOnly": true,
"outDir": "dist",
"experimentalDecorators": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"types": ["bun-types"]
},
"include": ["src/index.ts"]
"compilerOptions": {
"declaration": true,
"baseUrl": "src",
"target": "esnext",
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"emitDecoratorMetadata": true,
"emitDeclarationOnly": true,
"outDir": "dist",
"experimentalDecorators": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"types": ["bun-types"]
},
"include": ["src/index.ts"]
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc