Type-safe RPC for ComputerCraft that speaks TRPC!
CRPC is a TypeScript RPC framework specifically designed for ComputerCraft that maintains compatibility with tRPC. It enables end-to-end typesafe APIs between ComputerCraft computers and either other computers or external tRPC servers.
Think of it as tRPC's quirky cousin who lives in Minecraft! 🎮
bun add @cc-ts/crpc
import { initCRPC } from "@cc-ts/crpc";
const t = initCRPC.create();
const appRouter = t.router({
greeting: t.procedure.input(z.string()).query((opts) => {
return `Hello ${opts.input}!`;
}),
counter: t.procedure.subscription((opts) => {
return observable<number>((observer) => {
let count = 0;
const timer = setInterval(() => {
observer.next(count++);
}, 1000);
return () => clearInterval(timer);
});
}),
});
export type AppRouter = typeof appRouter;
import { createRednetCRPCServer } from "@cc-ts/crpc/adapter/rednet";
// Open modem
peripheral.find("modem", (name) => {
rednet.open(name);
});
// Create server
createRednetCRPCServer({
router: appRouter,
});
print("CRPC Server running!");
import { createCRPCClient } from "@cc-ts/crpc";
import { RednetCRPCTransport } from "@cc-ts/crpc/client/transports/rednet";
// Open modem
peripheral.find("modem", (name) => {
rednet.open(name);
});
const client = createCRPCClient<AppRouter>({
transport: new RednetCRPCTransport({
recipient: 1, // Computer ID to connect to
}),
});
// Make type-safe calls!
const greeting = await client.greeting.query("CRPC");
print(greeting); // "Hello CRPC!"
// Subscribe to updates
client.counter.subscribe(undefined, {
onData: (count) => {
print(`Count: ${count}`);
},
});
import { createCRPCClient } from "@cc-ts/crpc";
import { WebSocketCRPCTransport } from "@cc-ts/crpc/client/transports/websocket";
const transport = new WebSocketCRPCTransport({
url: "ws://localhost:3000",
reconnect: true,
keepAliveTimeout: 10_000,
maxReconnectAttempts: "infinite",
});
const client = createCRPCClient<AppRouter>({
transport,
});
// Same API as Rednet client!
const greeting = await client.greeting.query("CRPC");
try {
await client.greeting.query("");
} catch (err) {
if (err instanceof CRPCClientError) {
print("Something went wrong:", err.message);
}
}
interface Context {
user?: {
id: string;
name: string;
};
}
const t = initCRPC.context<Context>().create();
const appRouter = t.router({
me: t.procedure.query(({ ctx }) => {
return ctx.user;
}),
});
const authMiddleware = t.middleware(({ next, ctx }) => {
if (!ctx.user) {
throw new CRPCError({
code: "UNAUTHORIZED",
message: "Must be logged in",
});
}
return next();
});
const protectedProcedure = t.procedure.use(authMiddleware);
Contributions are welcome! Feel free to:
git checkout -b feature/amazing-feature
)git commit -m 'Add some amazing feature'
)git push origin feature/amazing-feature
)Made with ❤️ for the ComputerCraft community