Skip to content
Back to skills

Trpc Api Limatechnologies Admin Telegram Bot 2

ASecurity

tRPC end-to-end type-safe API patterns. Router setup, procedures, middleware, context, client configuration. Use when building type-safe APIs with tRPC.

  • 666 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 2, 2026
ai-agentstypescriptgoreactnextjsnodeapidatabasesecuritydocumentation

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned September 2, 2026

npx -y skills add majiayu000/claude-skill-registry --skill trpc-api-limatechnologies-admin-telegram-bot-2 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Trpc Api Limatechnologies Admin Telegram Bot 2?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Trpc Api Limatechnologies Admin Telegram Bot 2
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-trpc-api-limatechnologies-admin-telegram-bot-2/badge)](https://www.skillsdirectory.com/skills/majiayu000-trpc-api-limatechnologies-admin-telegram-bot-2)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: trpc-api
description: tRPC end-to-end type-safe API patterns. Router setup, procedures, middleware, context, client configuration. Use when building type-safe APIs with tRPC.
allowed-tools: Read, Write, Edit, Grep, Glob
---

# tRPC API - End-to-End Type Safety

## Purpose

Expert guidance for tRPC v11:

- **Router Setup** - Modular router architecture
- **Procedures** - Queries, mutations, subscriptions
- **Middleware** - Auth, logging, rate limiting
- **Context** - Session, database, utilities
- **Client** - React Query integration

---

## Project Structure

```
server/
├── trpc/
│   ├── index.ts           # Router exports
│   ├── trpc.ts            # tRPC instance
│   ├── context.ts         # Context creation
│   └── routers/
│       ├── user.router.ts
│       ├── post.router.ts
│       └── _app.ts        # Root router
app/
└── api/trpc/[trpc]/route.ts  # Next.js handler
lib/
└── trpc/
    ├── client.ts          # tRPC client
    └── react.tsx          # React Query provider
```

---

## Server Setup

### tRPC Instance

```typescript
// server/trpc/trpc.ts
import { initTRPC, TRPCError } from '@trpc/server';
import superjson from 'superjson';
import { type Context } from './context';

const t = initTRPC.context<Context>().create({
	transformer: superjson,
	errorFormatter({ shape, error }) {
		return {
			...shape,
			data: {
				...shape.data,
				zodError: error.cause instanceof ZodError ? error.cause.flatten() : null,
			},
		};
	},
});

export const router = t.router;
export const publicProcedure = t.procedure;
export const middleware = t.middleware;
```

### Context

```typescript
// server/trpc/context.ts
import { type CreateNextContextOptions } from '@trpc/server/adapters/next';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { db } from '@db';

export async function createContext(opts: CreateNextContextOptions) {
	const session = await getServerSession(authOptions);

	return {
		session,
		user: session?.user ?? null,
		db,
		req: opts.req,
		res: opts.res,
	};
}

export type Context = Awaited<ReturnType<typeof createContext>>;
```

### Auth Middleware

```typescript
// server/trpc/trpc.ts
const isAuthed = middleware(({ ctx, next }) => {
	if (!ctx.user) {
		throw new TRPCError({
			code: 'UNAUTHORIZED',
			message: 'You must be logged in',
		});
	}
	return next({
		ctx: {
			...ctx,
			user: ctx.user, // User is now guaranteed
		},
	});
});

export const protectedProcedure = t.procedure.use(isAuthed);
```

---

## Router Patterns

### Basic Router

```typescript
// server/trpc/routers/user.router.ts
import { z } from 'zod';
import { router, publicProcedure, protectedProcedure } from '../trpc';

export const userRouter = router({
	// Query - fetch data
	getById: publicProcedure
		.input(z.object({ id: z.string().uuid() }))
		.query(async ({ input, ctx }) => {
			const user = await ctx.db.user.findUnique({
				where: { id: input.id },
				select: { id: true, name: true, email: true },
			});

			if (!user) {
				throw new TRPCError({
					code: 'NOT_FOUND',
					message: 'User not found',
				});
			}

			return user;
		}),

	// Mutation - modify data
	updateProfile: protectedProcedure
		.input(
			z.object({
				name: z.string().min(2).max(100),
				bio: z.string().max(500).optional(),
			})
		)
		.mutation(async ({ input, ctx }) => {
			return ctx.db.user.update({
				where: { id: ctx.user.id },
				data: input,
			});
		}),

	// Me - current user
	me: protectedProcedure.query(async ({ ctx }) => {
		return ctx.db.user.findUnique({
			where: { id: ctx.user.id },
		});
	}),
});
```

### Root Router

```typescript
// server/trpc/routers/_app.ts
import { router } from '../trpc';
import { userRouter } from './user.router';
import { postRouter } from './post.router';

export const appRouter = router({
	user: userRouter,
	post: postRouter,
});

export type AppRouter = typeof appRouter;
```

---

## Advanced Patterns

### Pagination

```typescript
const paginationSchema = z.object({
	cursor: z.string().optional(),
	limit: z.number().min(1).max(100).default(20),
});

export const postRouter = router({
	list: publicProcedure.input(paginationSchema).query(async ({ input, ctx }) => {
		const { cursor, limit } = input;

		const posts = await ctx.db.post.findMany({
			take: limit + 1,
			cursor: cursor ? { id: cursor } : undefined,
			orderBy: { createdAt: 'desc' },
		});

		let nextCursor: string | undefined;
		if (posts.length > limit) {
			const nextItem = posts.pop();
			nextCursor = nextItem?.id;
		}

		return {
			items: posts,
			nextCursor,
		};
	}),
});
```

### Optimistic Updates

```typescript
// Client-side with React Query
const utils = trpc.useUtils();

const createPost = trpc.post.create.useMutation({
	onMutate: async (newPost) => {
		// Cancel outgoing refetches
		await utils.post.list.cancel();

		// Snapshot previous value
		const previousPosts = utils.post.list.getData();

		// Optimistically update
		utils.post.list.setData(undefined, (old) => {
			if (!old) return { items: [newPost], nextCursor: undefined };
			return { ...old, items: [newPost, ...old.items] };
		});

		return { previousPosts };
	},

	onError: (err, newPost, context) => {
		// Rollback on error
		utils.post.list.setData(undefined, context?.previousPosts);
	},

	onSettled: () => {
		// Always refetch after error or success
		utils.post.list.invalidate();
	},
});
```

### Batch Requests

```typescript
// tRPC automatically batches by default
// Multiple calls in same tick are batched

const user = trpc.user.me.useQuery();
const posts = trpc.post.list.useQuery();
const notifications = trpc.notification.unread.useQuery();
// These are batched into a single HTTP request
```

---

## Error Handling

### Error Codes

```typescript
throw new TRPCError({
	code: 'NOT_FOUND', // 404
	code: 'BAD_REQUEST', // 400
	code: 'UNAUTHORIZED', // 401
	code: 'FORBIDDEN', // 403
	code: 'CONFLICT', // 409
	code: 'INTERNAL_SERVER_ERROR', // 500
	message: 'Descriptive message',
	cause: originalError,
});
```

### Client Error Handling

```typescript
const mutation = trpc.post.create.useMutation({
	onError: (error) => {
		if (error.data?.code === 'CONFLICT') {
			toast.error('Post with this title already exists');
		} else if (error.data?.zodError) {
			// Validation errors
			const fieldErrors = error.data.zodError.fieldErrors;
			Object.entries(fieldErrors).forEach(([field, errors]) => {
				toast.error(`${field}: ${errors?.join(', ')}`);
			});
		} else {
			toast.error(error.message);
		}
	},
});
```

---

## Client Setup

### React Provider

```typescript
// lib/trpc/react.tsx
'use client';

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { httpBatchLink } from '@trpc/client';
import { createTRPCReact } from '@trpc/react-query';
import { useState } from 'react';
import superjson from 'superjson';
import { type AppRouter } from '@/server/trpc/routers/_app';

export const trpc = createTRPCReact<AppRouter>();

export function TRPCProvider({ children }: { children: React.ReactNode }) {
  const [queryClient] = useState(() => new QueryClient({
    defaultOptions: {
      queries: {
        staleTime: 5 * 1000,
        refetchOnWindowFocus: false,
      },
    },
  }));

  const [trpcClient] = useState(() =>
    trpc.createClient({
      links: [
        httpBatchLink({
          url: '/api/trpc',
          transformer: superjson,
        }),
      ],
    })
  );

  return (
    <trpc.Provider client={trpcClient} queryClient={queryClient}>
      <QueryClientProvider client={queryClient}>
        {children}
      </QueryClientProvider>
    </trpc.Provider>
  );
}
```

### Usage in Components

```typescript
'use client';

import { trpc } from '@/lib/trpc/react';

export function UserProfile() {
  const { data: user, isLoading } = trpc.user.me.useQuery();
  const updateProfile = trpc.user.updateProfile.useMutation();

  if (isLoading) return <Skeleton />;
  if (!user) return null;

  return (
    <form onSubmit={(e) => {
      e.preventDefault();
      updateProfile.mutate({ name: 'New Name' });
    }}>
      <input defaultValue={user.name} />
      <button type="submit" disabled={updateProfile.isPending}>
        Save
      </button>
    </form>
  );
}
```

---

## Next.js Handler

```typescript
// app/api/trpc/[trpc]/route.ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { appRouter } from '@/server/trpc/routers/_app';
import { createContext } from '@/server/trpc/context';

const handler = (req: Request) =>
	fetchRequestHandler({
		endpoint: '/api/trpc',
		req,
		router: appRouter,
		createContext: () => createContext({ req }),
	});

export { handler as GET, handler as POST };
```

---

## Agent Integration

This skill is used by:

- **trpc-expert** subagent
- **api-documenter** for API documentation
- **security-auditor** for route validation
- **test-coverage** for API tests

---

## FORBIDDEN

1. **User ID from input** - ALWAYS use `ctx.user.id`
2. **Procedures without `.input()`** - Validate all inputs
3. **`any` in input schemas** - Use proper Zod types
4. **Sensitive data in responses** - Filter with `.select()`
5. **Public procedures for mutations** - Use `protectedProcedure`

---

## Version

- **v1.0.0** - Initial implementation based on tRPC v11 patterns

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.