{"id":30596433,"url":"https://github.com/aldotestino/hono-orpc","last_synced_at":"2026-05-09T05:34:56.503Z","repository":{"id":309977251,"uuid":"1038208468","full_name":"aldotestino/hono-orpc","owner":"aldotestino","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-26T22:43:47.000Z","size":550,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-27T06:14:33.116Z","etag":null,"topics":["bun","hono","orpc","sse","tanstack-query","tanstack-router"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aldotestino.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-14T19:51:51.000Z","updated_at":"2025-08-26T22:43:51.000Z","dependencies_parsed_at":"2025-08-15T00:19:16.380Z","dependency_job_id":null,"html_url":"https://github.com/aldotestino/hono-orpc","commit_stats":null,"previous_names":["aldotestino/hono-orpc"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aldotestino/hono-orpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aldotestino%2Fhono-orpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aldotestino%2Fhono-orpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aldotestino%2Fhono-orpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aldotestino%2Fhono-orpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aldotestino","download_url":"https://codeload.github.com/aldotestino/hono-orpc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aldotestino%2Fhono-orpc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272767558,"owners_count":24989523,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-29T02:00:10.610Z","response_time":87,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","hono","orpc","sse","tanstack-query","tanstack-router"],"created_at":"2025-08-29T21:43:31.774Z","updated_at":"2026-05-09T05:34:56.484Z","avatar_url":"https://github.com/aldotestino.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🚀 Modern TypeScript Full-Stack Chat Application\n\nA showcase of the latest TypeScript ecosystem libraries and best practices for building type-safe full-stack applications.\n\n## ✨ Features\n\nThis application demonstrates modern full-stack development with these key features:\n\n- 🔐 **User Authentication** - Social login (Google) and email/password authentication\n- 💬 **Channel Management** - Create, join, and manage chat channels with role-based permissions\n- 📱 **Real-time Messaging** - Send and receive messages in real-time across channels\n- 🤖 **AI Integration** - Smart AI assistant with tool calling capabilities and multiple model support\n\n## 🏗️ Project Structure\n\nThis project uses a **monorepo architecture** with Bun workspaces, providing several key benefits:\n\n```\nhono-orpc/\n├── apps/\n│   ├── api/          # Hono backend server\n│   └── web/          # React frontend application\n├── packages/\n│   ├── db/           # Drizzle ORM schema and database utilities\n│   └── ai/           # AI tools and model integrations\n└── playgrounds/\n    └── ai/           # AI experimentation playground\n```\n\n### Why Monorepo?\n\n- **Shared Type Safety**: Types flow seamlessly between frontend and backend\n- **Code Reusability**: Shared utilities, schemas, and contracts across apps\n- **Unified Tooling**: Single linting, formatting, and build configuration\n- **Simplified Dependencies**: Manage versions centrally with workspace references\n- **Developer Experience**: Hot reload and type checking across the entire stack\n\n## 🎯 Backend Architecture\n\n### Hono + oRPC: Type-Safe API Development\n\nOur backend leverages **Hono** (ultra-fast web framework) with **oRPC** for end-to-end type safety and automatic OpenAPI documentation generation.\n\n#### Contract Definition\n\n```typescript\n// apps/api/src/modules/chat/channel/channel.contract.ts\nimport { oc } from \"@orpc/contract\";\nimport { z } from \"zod/v4\";\n\nconst channelContract = oc\n  .route({\n    tags: [\"chat\", \"channel\"],\n  })\n  .errors({\n    UNAUTHORIZED: {},\n  });\n\nconst createChannel = channelContract\n  .route({\n    method: \"POST\",\n    description: \"Create a new channel\",\n    path: \"/chat/channel\",\n    successStatus: 201,\n  })\n  .errors({\n    INTERNAL_SERVER_ERROR: {},\n  })\n  .input(\n    z.object({\n      name: z.string().min(1).describe(\"The name of the channel\"),\n      members: z\n        .array(z.string())\n        .min(1)\n        .describe(\"The members of the channel\"),\n    })\n  )\n  .output(channelSchema);\n```\n\n#### Handler Implementation\n\n```typescript\n// apps/api/src/modules/chat/channel/channel.router.ts\nimport { implement } from \"@orpc/server\";\nimport { authMiddleware } from \"../../../middlewares/auth-middleware\";\n\nconst chatRouter = implement(channelContract).$context\u003c{ headers: Headers }\u003e();\n\nconst createChannel = chatRouter.createChannel\n  .use(authMiddleware)\n  .handler(async ({ context, input, errors }) =\u003e {\n    const [ch] = await db\n      .insert(channel)\n      .values({\n        ...input,\n        ownerId: context.user.id,\n      })\n      .returning();\n\n    if (!ch) {\n      throw errors.INTERNAL_SERVER_ERROR({\n        message: \"Failed to create channel\",\n      });\n    }\n\n    // Add members and owner to channel\n    await db.insert(channelParticipant).values([\n      {\n        channelUuid: ch.uuid,\n        userId: context.user.id,\n        role: \"owner\",\n      },\n      ...input.members.map((userId) =\u003e ({\n        channelUuid: ch.uuid,\n        userId,\n      })),\n    ]);\n\n    return ch;\n  });\n```\n\n### Real-Time Message Streaming\n\noRPC provides built-in support for real-time data streaming using Server-Sent Events:\n\n#### Stream Contract Definition\n\n```typescript\n// apps/api/src/modules/chat/message/message.contract.ts\nconst streamChannelMessages = messageContract\n  .route({\n    method: \"GET\",\n    description: \"Stream messages by channel\",\n    path: \"/chat/channel/{uuid}/message/stream\",\n  })\n  .errors({\n    FORBIDDEN: {\n      message: \"You are not a member of this channel\",\n    },\n  })\n  .input(z.object({ uuid: z.uuid().describe(\"The uuid of the channel\") }))\n  .output(eventIterator(\n    messageSchema.extend({ \n      sender: userSchema.nullable() \n    })\n  ));\n```\n\n#### Stream Handler Implementation\n\n```typescript\n// apps/api/src/modules/chat/message/message.router.ts\nimport { EventPublisher } from \"@orpc/server\";\n\nconst publisher = new EventPublisher\u003c\n  Record\u003cstring, Message \u0026 { sender: User | null }\u003e\n\u003e();\n\nconst streamChannelMessages = messageRouter.streamChannelMessages\n  .use(authMiddleware)\n  .use(userInChannelMiddleware)\n  .handler(async function* ({ input, signal }) {\n    // Generator function for streaming data\n    for await (const payload of publisher.subscribe(input.uuid, {\n      signal, // Abort signal for cleanup\n    })) {\n      yield payload; // Stream each message as it arrives\n    }\n  });\n\n// Publishing messages to subscribers\nconst saveAndPublishMessage = async ({ channelUuid, content, sender }) =\u003e {\n  const [msg] = await db\n    .insert(message)\n    .values({ channelUuid, content, senderId: sender.id })\n    .returning();\n\n  // Publish to all subscribers of this channel\n  publisher.publish(channelUuid, {\n    ...msg,\n    sender,\n  });\n\n  return msg;\n};\n```\n\n### Key Benefits of oRPC\n\n- 🔒 **End-to-end Type Safety**: Contracts ensure type consistency between frontend and backend\n- 📖 **Auto-generated OpenAPI**: Documentation generated from Zod schemas and route definitions\n- 🛡️ **Runtime Validation**: Input/output validation with detailed error handling\n- 🔧 **Middleware Support**: Composable middleware for authentication, authorization, and more\n- 🌐 **Real-Time Streaming**: Built-in Server-Sent Events with type-safe event publishers\n\n## 🔐 Authentication with Better-Auth\n\nWe use **Better-Auth** for modern, secure authentication with excellent TypeScript support.\n\n```typescript\n// apps/api/src/lib/auth.ts\nimport { betterAuth } from \"better-auth\";\nimport { drizzleAdapter } from \"better-auth/adapters/drizzle\";\n\nexport const auth = betterAuth({\n  database: drizzleAdapter(db, {\n    provider: \"pg\",\n  }),\n  emailAndPassword: {\n    enabled: true,\n  },\n  socialProviders: {\n    google: {\n      prompt: \"select_account\",\n      clientId: process.env.GOOGLE_CLIENT_ID as string,\n      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,\n    },\n  },\n});\n```\n\n### Why Better-Auth?\n\n- 🔑 **Multiple Auth Methods**: Email/password, OAuth providers, magic links\n- 🏗️ **Framework Agnostic**: Works with any JavaScript framework\n- 🛡️ **Security First**: CSRF protection, secure sessions, and rate limiting\n- 🎨 **Customizable**: Extensible with plugins and custom providers\n- 📚 **TypeScript Native**: Excellent type inference and developer experience\n\n## 🗄️ Database with Drizzle ORM\n\n**Drizzle ORM** provides the best TypeScript experience for database operations with a SQL-like API.\n\n### Table Definition\n\n```typescript\n// packages/db/src/tables/chat.ts\nimport { pgTable, text, uuid, timestamp, json } from \"drizzle-orm/pg-core\";\n\nexport const channel = pgTable(\"channel\", {\n  uuid: uuid().notNull().primaryKey().defaultRandom(),\n  name: text().notNull(),\n  settings: json()\n    .notNull()\n    .default(channelSettingsSchema.parse({ ai: {} }))\n    .$type\u003cChannelSettings\u003e(),\n  ownerId: text()\n    .notNull()\n    .references(() =\u003e user.id, {\n      onDelete: \"cascade\",\n    }),\n  createdAt: timestamp({ mode: \"string\", withTimezone: true })\n    .notNull()\n    .defaultNow(),\n});\n\nexport const message = pgTable(\"message\", {\n  uuid: uuid().notNull().primaryKey().defaultRandom(),\n  senderId: text()\n    .notNull()\n    .references(() =\u003e user.id, {\n      onDelete: \"cascade\",\n    }),\n  content: text().notNull(),\n  channelUuid: uuid()\n    .notNull()\n    .references(() =\u003e channel.uuid, {\n      onDelete: \"cascade\",\n    }),\n  createdAt: timestamp({ mode: \"string\", withTimezone: true })\n    .notNull()\n    .defaultNow(),\n});\n```\n\n## Relation Definition\n```ts\nimport { relations } from \"drizzle-orm\";\nimport { user } from \"./auth\";\nimport { message, channel } from \"./chat\";\n\nexport const messageRelations = relations(message, ({ one }) =\u003e ({\n  sender: one(user, {\n    fields: [message.senderId],\n    references: [user.id],\n  }),\n  channel: one(channel, {\n    fields: [message.channelUuid],\n    references: [channel.uuid],\n  }),\n}));\n```\n\n### Automatic Zod Schema Generation\n\n```typescript\n// packages/db/src/schema/derived.ts\nimport { createSelectSchema } from \"drizzle-zod\";\nimport { channel, message, user } from \"../tables\";\n\n// Automatically generate Zod schemas from Drizzle tables\nexport const channelSchema = createSelectSchema(channel).omit({\n  settings: true,\n});\nexport type Channel = z.infer\u003ctypeof channelSchema\u003e;\n\nexport const messageSchema = createSelectSchema(message);\nexport type Message = z.infer\u003ctypeof messageSchema\u003e;\n\nexport const userSchema = createSelectSchema(user).pick({\n  email: true,\n  name: true,\n  image: true,\n  id: true,\n});\nexport type User = z.infer\u003ctypeof userSchema\u003e;\n```\n\n### Why Drizzle ORM?\n\n- 🏃 **Performance First**: Lightweight with zero runtime overhead\n- 🔍 **SQL-like API**: Familiar syntax for SQL developers\n- 🎯 **Type Safety**: Full TypeScript inference with IntelliSense\n- 🔄 **Schema Generation**: Auto-generate Zod schemas from tables\n- 🛠️ **Developer Tools**: Built-in migration system and database studio\n- 📊 **Query Builder**: Powerful relational queries with joins and subqueries\n\n## 🎨 Frontend Architecture\n\n### Modern React Stack\n\nThe frontend showcases cutting-edge React patterns and tools for 2024:\n\n- **React 19** - Latest React with concurrent features and improved Suspense\n- **TanStack Router** - File-based, type-safe routing with nested layouts and loaders\n- **TanStack Query** - Powerful data fetching, caching, and state synchronization\n- **Tailwind CSS 4** - Utility-first styling with CSS variables and modern features\n- **Shadcn/ui** - High-quality, accessible component library built on Radix\n- **Vite** - Lightning-fast build tool with HMR and optimized bundling\n\n### TanStack Router: Type-Safe File-Based Routing\n\nOur routing system uses TanStack Router's file-based approach with full TypeScript integration:\n\n#### Route Structure\n```\nroutes/\n├── __root.tsx                    # Root layout with outlets\n├── _auth/                        # Auth route group\n│   ├── route.tsx                 # Auth layout with redirect logic\n│   ├── index.tsx                 # Login page\n│   └── sign-up.tsx               # Sign up page\n└── _protected/                   # Protected route group\n    ├── route.tsx                 # Auth guard middleware\n    ├── _bottom-navigation/       # Bottom navigation layout\n    │   ├── route.tsx             # Bottom nav layout component\n    │   ├── chat.tsx              # Chat channels list\n    │   └── profile.tsx           # User profile page\n    └── chat.$uuid/               # Dynamic chat routes\n        ├── index.tsx             # Chat messages view\n        └── details.tsx           # Channel details and settings\n```\n\n#### Route Guards with Authentication\n\nTanStack Router's `beforeLoad` function provides powerful route protection capabilities:\n\n```typescript\n// apps/web/src/routes/_protected/route.tsx\nimport { createFileRoute, Outlet, redirect } from \"@tanstack/react-router\";\n\nexport const Route = createFileRoute(\"/_protected\")({\n  beforeLoad: ({ context: { auth } }) =\u003e {\n    // Redirect to login if user is not authenticated\n    if (!auth.data) {\n      throw redirect({ to: \"/\" });\n    }\n  },\n  component: Outlet,\n});\n```\n\n#### Type-Safe Route Context\n\n```typescript\n// apps/web/src/routes/__root.tsx\ntype MyRouterContext = {\n  queryClient: QueryClient;\n  auth: ReturnType\u003ctypeof authClient.useSession\u003e;\n};\n\nexport const Route = createRootRouteWithContext\u003cMyRouterContext\u003e()({\n  component: RootComponent,\n});\n```\n\n### TanStack Query Integration with oRPC\n\n#### Automatic Query Options Generation\n\noRPC automatically generates TanStack Query-compatible options:\n\n```typescript\n// apps/web/src/lib/orpc-client.ts\nimport contract from \"@hono-orpc/api/contract\";\nimport { createORPCClient } from \"@orpc/client\";\nimport { OpenAPILink } from \"@orpc/openapi-client/fetch\";\nimport { createTanstackQueryUtils } from \"@orpc/tanstack-query\";\n\nconst link = new OpenAPILink(contract, {\n  url: `${window.location.origin}/api/rpc`,\n  eventIteratorKeepAliveEnabled: true,\n  eventIteratorKeepAliveInterval: 5000,\n});\n\nexport const client = createORPCClient(link);\nexport const orpc = createTanstackQueryUtils(client);\n```\n\n#### Route Loaders with Prefetching\n\n```typescript\n// apps/web/src/routes/_protected/chat/$uuid/index.tsx\nexport const Route = createFileRoute(\"/_protected/chat/$uuid/\")({\n  loader: async ({ context: { queryClient }, params }) =\u003e {\n    // Prefetch data during route transition\n    await Promise.all([\n      queryClient.ensureQueryData(\n        orpc.chat.channel.getChannel.queryOptions({\n          input: { uuid: params.uuid },\n        })\n      ),\n      queryClient.ensureQueryData(\n        orpc.chat.message.getChannelMessages.queryOptions({\n          input: { uuid: params.uuid },\n        })\n      ),\n    ]);\n  },\n  component: RouteComponent,\n});\n```\n\n#### Suspense Queries for Instant Loading\n\n```typescript\nfunction RouteComponent() {\n  const { uuid } = Route.useParams();\n\n  // Multiple suspense queries with type safety\n  const [{ data: channel }, { data: messages }] = useSuspenseQueries({\n    queries: [\n      orpc.chat.channel.getChannel.queryOptions({ input: { uuid } }),\n      orpc.chat.message.getChannelMessages.queryOptions({\n        input: { uuid },\n      }),\n    ],\n  });\n\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003e#{channel.name}\u003c/h1\u003e\n      {messages.map((message) =\u003e (\n        \u003cMessageBox key={message.uuid} message={message} /\u003e\n      ))}\n    \u003c/div\u003e\n  );\n}\n```\n\n### Real-Time Streaming with TanStack Query\n\n#### Experimental Streaming Support\n\n```typescript\n// Real-time message streaming\nconst {\n  data: liveMessages,\n  isError: isLiveMessagesError,\n  fetchStatus: liveMessagesFetchStatus,\n} = useQuery({\n  queryKey: orpc.chat.message.streamChannelMessages.queryKey({\n    input: { uuid },\n  }),\n  queryFn: experimental_streamedQuery({\n    streamFn: ({ signal }) =\u003e\n      client.chat.message.streamChannelMessages({ uuid }, { signal }),\n  }),\n});\n```\n\n### Mutations with Query Invalidation\n\n```typescript\n// apps/web/src/components/new-channel.tsx\nconst queryClient = useQueryClient();\n\nconst { mutateAsync: createChannel, isPending } = useMutation(\n  orpc.chat.channel.createChannel.mutationOptions({\n    onSuccess: () =\u003e {\n      // Invalidate channels list to refetch updated data\n      queryClient.invalidateQueries({\n        queryKey: orpc.chat.channel.getChannels.queryKey(),\n      });\n      form.reset();\n      setOpen(false);\n    },\n  })\n);\n\nconst handleSubmit = form.handleSubmit((data) =\u003e createChannel(data));\n```\n\n#### Complex Query Management\n\n```typescript\n// apps/web/src/routes/_protected/chat/$uuid/details.tsx\nfunction cleanupQueries() {\n  return Promise.all([\n    // Remove specific channel queries from cache\n    queryClient.removeQueries({\n      queryKey: orpc.chat.channel.getChannel.queryKey({\n        input: { uuid },\n      }),\n    }),\n    queryClient.removeQueries({\n      queryKey: orpc.chat.message.getChannelMessages.queryKey({\n        input: { uuid },\n      }),\n    }),\n    // Invalidate channels list to reflect changes\n    queryClient.invalidateQueries({\n      queryKey: orpc.chat.channel.getChannels.queryKey(),\n    }),\n  ]);\n}\n\nconst { mutateAsync: leaveChannel } = useMutation(\n  orpc.chat.channel.leaveChannel.mutationOptions({\n    onSuccess: async () =\u003e {\n      await cleanupQueries();\n      navigate({ to: \"/chat\" });\n    },\n  })\n);\n```\n\n### Advanced Query Configuration\n\n```typescript\n// apps/web/src/integrations/tanstack-query/root-provider.tsx\nconst queryClient = new QueryClient({\n  defaultOptions: {\n    queries: {\n      refetchOnWindowFocus: false,\n      staleTime: (query) =\u003e {\n        // Custom stale time based on query type\n        const flatQueryKeys = query.queryKey.flat();\n        if (\n          flatQueryKeys.includes(\"streamChannelMessages\") ||\n          flatQueryKeys.includes(\"getChannelMessages\")\n        ) {\n          return 0; // Always refetch messages\n        }\n        return 300_000; // 5 minutes for other data\n      },\n    },\n  },\n});\n```\n\n### Key Frontend Benefits\n\n🚀 **Performance**\n- Route-based code splitting with automatic lazy loading\n- Intelligent query caching and background refetching\n- Optimistic updates for instant UI feedback\n\n🔒 **Type Safety**\n- End-to-end type safety from API to UI components\n- Compile-time route validation and parameter checking\n- Automatic TypeScript inference for all API calls\n\n📱 **User Experience**\n- Instant navigation with prefetched data\n- Real-time updates via streaming queries\n- Optimistic UI updates for immediate feedback\n\n🛠️ **Developer Experience**\n- File-based routing with automatic code generation\n- Built-in devtools for debugging queries and routes\n- Hot module replacement with state preservation\n\n### Development Tools Integration\n\nThe app includes comprehensive development tools:\n\n```typescript\n// Integrated devtools for development\n{import.meta.env.DEV \u0026\u0026 (\n  \u003cTanStackDevtools\n    config={{ position: \"bottom-left\" }}\n    plugins={[\n      {\n        name: \"Tanstack Router\",\n        render: \u003cTanStackRouterDevtoolsPanel /\u003e,\n      },\n      TanStackQueryDevtools,\n    ]}\n  /\u003e\n)}\n```\n\nThis setup provides real-time inspection of:\n- Route transitions and loader states\n- Query cache and network requests\n- Component tree and state changes\n\n## 🤖 AI Integration\n\n### Vercel AI SDK: Modern AI Application Framework\n\nOur AI implementation leverages **Vercel's AI SDK**, the most comprehensive TypeScript-first framework for building AI applications. The SDK provides:\n\n- 🔗 **Provider Agnostic** - Support for OpenAI, Anthropic, Google, OpenRouter, and 50+ providers\n- 🛠️ **Tool Calling** - Type-safe function calling with automatic schema generation\n- 📡 **Streaming Support** - Real-time token streaming for responsive UIs\n- 🔒 **Type Safety** - Full TypeScript integration with Zod schema validation\n- 🎯 **Framework Integration** - Built-in support for React, Vue, and Node.js\n\n### Multi-Model AI Assistant\n\n```typescript\n// packages/ai/src/index.ts\nimport { createOpenRouter } from \"@openrouter/ai-sdk-provider\";\nimport { generateText, type ModelMessage, stepCountIs } from \"ai\";\nimport tools from \"./tools\";\n\nconst SYSTEM_PROMPT = `\nYou are ChatAI, a human-like participant in a group chat. \nReply like a normal user: brief, helpful, and conversational.\nDo not mention you are an AI unless asked.\n\nStyle and behavior:\n- Match the chat's tone; keep replies under 5 sentences\n- Address people by name when helpful\n- Ask at most one focused clarifying question when needed\n- Use emojis sparingly; avoid sounding like a support bot\n\nTool use:\n- You may call tools when appropriate\n- Always send a final normal text reply summarizing the result\n`;\n\nconst openRouter = createOpenRouter({\n  apiKey: process.env.OPENROUTER_API_KEY,\n});\n\nexport function generateResponse({ messages, model }: GenerateResponseProps) {\n  const modelMessages = messages.map(toModelMessage);\n  \n  const _model = model || \"openai/gpt-oss-120b:free\";\n  const enableTools = [\n    \"openrouter/sonoma-dusk-alpha\",\n    \"openrouter/sonoma-sky-alpha\",\n  ].includes(_model);\n\n  return generateText({\n    model: openRouter(_model),\n    system: SYSTEM_PROMPT,\n    stopWhen: stepCountIs(10),\n    ...(enableTools \u0026\u0026 { tools }), // Conditionally enable tools\n    messages: modelMessages,\n  });\n}\n```\n\n### AI Tool System with Type Safety\n\nThe AI SDK's tool system provides type-safe function calling with automatic schema generation from Zod schemas:\n\n#### Weather API Tool Example\n\n```typescript\n// packages/ai/src/tools/weather.ts\nimport { tool } from \"ai\";\nimport { z } from \"zod/v4\";\n\nexport const getCurrentWeather = tool({\n  description: \"Get current weather information for a city.\",\n  inputSchema: z.object({\n    location: z.string().describe('City name (e.g., \"London\", \"New York, US\")'),\n  }),\n  execute: async ({ location }) =\u003e {\n    const geo = await geocodeLocation(location);\n    const response = await fetch(\n      `${API_BASE_URL}/weather?lat=${geo.lat}\u0026lon=${geo.lon}\u0026appid=${API_KEY}\u0026units=metric`\n    );\n    const data = await response.json();\n\n    return {\n      location: geo.name,\n      temperature: Math.round(data.main.temp),\n      description: data.weather[0].description,\n      humidity: data.main.humidity,\n      windSpeed: Math.round(data.wind.speed * 3.6),\n    };\n  },\n});\n```\n\n### Real-Time AI Integration\n\n#### Message-Triggered AI Responses\n\n```typescript\n// apps/api/src/modules/chat/message/message.router.ts\nconst sendMessageToChannel = messageRouter.sendMessageToChannel\n  .use(authMiddleware)\n  .use(userInChannelMiddleware)\n  .handler(async ({ context, input, errors }) =\u003e {\n    // Save user message\n    const msg = await saveAndPublishMessage({\n      channelUuid: input.uuid,\n      content: input.content,\n      sender: context.user as User,\n    });\n\n    // Trigger AI response when mentioned\n    if (input.content.includes(\"@ai\")) {\n      const ch = await db.query.channel.findFirst({\n        where: eq(channel.uuid, input.uuid),\n      });\n\n      if (ch?.settings.ai.enabled) {\n        const aiResponse = await generateAIResponse(\n          input.uuid, \n          ch.settings.ai\n        );\n\n        await saveAndPublishMessage({\n          channelUuid: input.uuid,\n          content: aiResponse,\n          sender: CHAT_AI_USER,\n        });\n      }\n    }\n\n    return msg;\n  });\n```\n\n#### Context-Aware Response Generation\n\n```typescript\n// apps/api/src/lib/utils.ts\nexport const generateAIResponse = async (\n  channelUuid: string,\n  channelAISettings: ChannelSettings[\"ai\"]\n) =\u003e {\n  // Fetch recent message history for context\n  const lastMessages = await db.query.message.findMany({\n    where: eq(message.channelUuid, channelUuid),\n    orderBy: desc(message.createdAt),\n    limit: channelAISettings.maxMessages, // Configurable context window\n    with: { sender: true },\n  });\n\n  const response = await generateResponse({\n    messages: lastMessages.reverse(),\n    model: channelAISettings.model,\n  });\n\n  // Extract text content from multi-modal response\n  const lastResponse = response.content.at(-1);\n  if (lastResponse?.type !== \"text\") {\n    throw new Error(\"Expected text response\");\n  }\n\n  return lastResponse.text;\n};\n```\n\n### Available AI Models\n\n- **OpenRouter Sonoma Models** - Advanced reasoning with tool calling capabilities\n- **GPT-OSS Models** - Free, fast inference for basic conversational tasks\n- **Custom Model Support** - Easy integration of new providers via AI SDK\n\n### Channel-Specific AI Configuration\n\n```typescript\n// packages/db/src/schema/custom.ts\nexport const channelSettingsSchema = z.object({\n  ai: z.object({\n    enabled: z.boolean().default(false),\n    model: z.enum([\n      \"openrouter/sonoma-dusk-alpha\",\n      \"openrouter/sonoma-sky-alpha\", \n      \"openai/gpt-oss-120b:free\",\n      \"openai/gpt-oss-20b:free\",\n    ]).default(\"openrouter/sonoma-dusk-alpha\"),\n    maxMessages: z.number().default(10), // Context window size\n  }),\n});\n```\n\n### 🚀 What We've Achieved\n\n**End-to-End Type Safety**\n- Zero type gaps from database schema to UI components\n- Compile-time error detection across the entire stack\n- Automatic API contract generation and validation\n\n**Developer Experience Excellence**\n- Sub-second hot reload across frontend and backend\n- Intelligent IntelliSense for all API calls and database queries\n- Built-in debugging tools and comprehensive error messages\n\n**Modern Architecture Patterns**\n- File-based routing with automatic code splitting\n- Real-time streaming with type-safe event handling\n- AI-first development with tool calling capabilities\n\n**Production Readiness**\n- Robust authentication and authorization systems\n- Scalable monorepo architecture for team development\n- Performance optimized with intelligent caching strategies\n\n### 🌟 The TypeScript Ecosystem Advantage\n\nThe combination of these technologies creates a **multiplicative effect** where each tool enhances the others:\n\n- **oRPC** contracts become **TanStack Query** hooks automatically\n- **Drizzle** schemas generate **Zod** validators seamlessly  \n- **Vercel AI SDK** tools integrate with type-safe **API endpoints**\n- **TanStack Router** provides **compile-time route validation**\n\nThis isn't just about individual library quality—it's about how they work together to create something greater than the sum of their parts.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faldotestino%2Fhono-orpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faldotestino%2Fhono-orpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faldotestino%2Fhono-orpc/lists"}