### Install and Run TanStack Start Project Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/README.md Install dependencies, start the development server, build for production, and deploy to Cloudflare. ```bash pnpm install pnpm dev pnpm build pnpm deploy ``` -------------------------------- ### Start Development Server Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/CLAUDE.md Use this command to start the development server. It runs on port 3000. ```bash pnpm dev ``` -------------------------------- ### Install Dependencies and Build Packages Source: https://github.com/backpine/saas-kit/blob/main/README.md Run this command to install all project dependencies and build necessary packages. ```bash pnpm run setup ``` -------------------------------- ### Start User Application Development Server Source: https://github.com/backpine/saas-kit/blob/main/README.md Use this command to start the development server for the user-facing application. ```bash pnpm run dev:user-application ``` -------------------------------- ### Start Data Service Development Server Source: https://github.com/backpine/saas-kit/blob/main/README.md Use this command to start the development server for the data service backend. ```bash pnpm run dev:data-service ``` -------------------------------- ### Basic Route Handler for GET / Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-hono.md Defines a simple GET route at the root path that returns a plain text 'Hello World' response. ```typescript app.get("/", (c) => { return c.text("Hello World"); }); ``` -------------------------------- ### Complete File Processing Workflow Example Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-workflows.md A comprehensive example demonstrating a file processing workflow. It includes downloading a file, waiting for rate limits, processing the file content, storing results in a database, and sending notifications. ```typescript interface ProcessPayload { userId: string; fileUrl: string; } export class FileProcessWorkflow extends WorkflowEntrypoint< Env, ProcessPayload > { async run( event: WorkflowEvent, step: WorkflowStep, ) { // Download file const file = await step.do("Download file", async () => { const response = await fetch(event.payload.fileUrl); return await response.arrayBuffer(); }); // Wait for rate limit await step.sleep("Rate limit wait", "5 seconds"); // Process file const processed = await step.do("Process file", async () => { // Process file data return Buffer.from(file).toString("utf-8").toUpperCase(); }); // Store result await step.do("Store result", async () => { await env.DB.prepare( "INSERT INTO processed_files (user_id, content) VALUES (?, ?)" ).bind(event.payload.userId, processed).run(); }); // Send notification await step.do("Send notification", async () => { await sendEmail(event.payload.userId, "File processed"); }); } } ``` -------------------------------- ### exampleMiddlewareWithContext Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-middleware.md Example middleware demonstrating context injection pattern. Reference implementation showing how to create custom middleware with context. ```APIDOC ## `exampleMiddlewareWithContext` ### Description Example middleware demonstrating context injection pattern. Reference implementation showing how to create custom middleware with context. ### Purpose Reference implementation showing how to create custom middleware with context. ### Context Provided ```typescript { data: "Some Data From Middleware"; } ``` ``` -------------------------------- ### Setup in wrangler.toml Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-workflows.md Configuration snippet for setting up a workflow in the `wrangler.toml` file, including its name, binding, class name, and script name. ```APIDOC ## Setup in wrangler.toml ```toml [[workflows]] name = "example-workflow" binding = "EXAMPLE_WORKFLOW" class_name = "ExampleWorkflow" script_name = "data-service" ``` ``` -------------------------------- ### GET / Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-hono.md Retrieves a plain text 'Hello World' response. This is the root endpoint of the Hono application. ```APIDOC ## GET / ### Description Returns a plain text response indicating a successful connection. ### Method GET ### Endpoint / ### Response #### Success Response (200 OK) - **Content-Type**: text/plain - **Body**: "Hello World" #### Response Example "Hello World" ``` -------------------------------- ### Adding New Routes (data-service) Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/endpoints.md Examples of how to add new routes to the data-service using Hono, including GET with path parameters and POST with JSON bodies. ```APIDOC ## Adding New Routes (data-service) ### Description Examples of adding new routes using Hono. ### GET with path parameter #### Endpoint `/products/:id` #### Handler Example ```typescript import { app } from "@/hono/app"; app.get("/products/:id", async (c) => { const id = c.req.param("id"); return c.json({ id }); }); ``` ### POST with JSON body #### Endpoint `/products` #### Handler Example ```typescript import { app } from "@/hono/app"; app.post("/products", async (c) => { const body = await c.req.json(); return c.json({ created: true }, { status: 201 }); }); ``` ### Middleware for all routes under /api #### Handler Example ```typescript import { app } from "@/hono/app"; app.use("/api/*", async (c, next) => { c.header("X-Custom-Header", "value"); await next(); }); ``` ``` -------------------------------- ### Create Payment Link Example Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/endpoints.md Example of how to create a payment link using the `createPaymentLink` server function and redirect the user to the checkout URL. Requires authentication and Polar API access. ```typescript const checkout = await createPaymentLink({ data: { productId: "prod_123" } }); window.location.href = checkout.url; ``` -------------------------------- ### Calling Example Server Function Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-functions.md Demonstrates how to invoke the `examplefunction` from a client-side context, passing the required input data. Ensure the `examplefunction` is correctly imported. ```typescript import { examplefunction } from "@/core/functions/example-functions"; const result = await examplefunction({ data: { exampleKey: "value" } }); ``` -------------------------------- ### RootLayout with ThemeProvider Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-theme.md Example of integrating ThemeProvider into the RootLayout component. This setup configures the theme to use system preferences by default and applies class-based theme switching. ```typescript import { ThemeProvider } from "@/components/theme"; export function RootLayout({ children }) { return ( {children} ); } ``` -------------------------------- ### Wrangler Configuration for Cloudflare Deployment Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/README.md Example configuration file for deploying a TanStack Start application to Cloudflare Workers using Wrangler. ```json { "$schema": "node_modules/wrangler/config-schema.json", "name": "tanstack-start-app", "compatibility_date": "2025-09-02", "compatibility_flags": ["nodejs_compat"], "main": "./src/server.ts", // Custom server entry point "vars": { "MY_VAR": "Hello from Cloudflare" } } ``` -------------------------------- ### Example Server Function with Middleware Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-functions.md An example server function that demonstrates the usage of middleware context and input validation. It logs received data and context, expecting a string input. ```typescript const ExampleInputSchema = z.object({ exampleKey: z.string().min(1), }); export const examplefunction = baseFunction .inputValidator((data: ExampleInput) => ExampleInputSchema.parse(data)) .handler(async (ctx) => { console.log("Executing example function"); console.log(`The data passed: ${JSON.stringify(ctx.data)}`); console.log(`The context from middleware: ${JSON.stringify(ctx.context)}`); return "Function executed successfully"; }) ``` -------------------------------- ### Router Setup Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-routing.md Initializes the TanStack Router with route tree, context, and SSR query integration. Wraps the router with a TanStack Query provider. ```typescript import { createRouter } from '@tanstack/react-router' import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query' import * as TanstackQuery from './integrations/tanstack-query/root-provider' import { routeTree } from './routeTree.gen' export const getRouter = () => { const rqContext = TanstackQuery.getContext() const router = createRouter({ routeTree, context: { ...rqContext }, defaultPreload: 'intent', Wrap: (props: { children: React.ReactNode }) => { return ( {props.children} ) }, }) setupRouterSsrQueryIntegration({ router, queryClient: rqContext.queryClient }) return router } ``` -------------------------------- ### GET /error Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-hono.md An example endpoint that returns a 404 Not Found error response. ```APIDOC ## GET /error ### Description An example endpoint designed to demonstrate error handling by returning a 404 Not Found status code. ### Method GET ### Endpoint /error ### Response #### Error Response (404 Not Found) - **Content-Type**: application/json - **Body**: A JSON object containing an error message. #### Response Example ```json { "error": "Not found" } ``` ``` -------------------------------- ### Run Drizzle Migrations Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/authentication.md Apply the generated Drizzle migrations to your database to create the authentication tables. This step is optional but recommended for setup. ```bash pnpm run drizzle:migrate ``` -------------------------------- ### Example Workflow Definition Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-workflows.md Defines an example workflow with steps for getting a random number, sleeping, and logging data. This class extends `WorkflowEntrypoint` and requires `Env` and `ExampleWorkflowParmas` type parameters. ```typescript import { WorkflowEntrypoint, WorkflowEvent, WorkflowStep, } from "cloudflare:workers"; export class ExampleWorkflow extends WorkflowEntrypoint< Env, ExampleWorkflowParmas > { async run( event: Readonly>, step: WorkflowStep, ) { const randomNumber = await step.do("Get random number", async () => { return Math.floor(Math.random() * 10) + 1; }); await step.sleep( "Wait for random number of seconds", `${randomNumber} seconds`, ); await step.do("Log data in payload", async () => { console.log(event.payload); }); } } ``` -------------------------------- ### Custom Cloudflare Workers Server Entry Point Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/README.md Example of a custom server entry point for Cloudflare Workers, integrating with TanStack Start's server handler. ```typescript import handler from "@tanstack/react-start/server-entry"; export default { fetch(request: Request) { return handler.fetch(request, { context: { fromFetch: true, }, }); }, // Add other Cloudflare Workers features: // - Queue consumers: queue(batch, env) { ... } // - Scheduled events: scheduled(event, env) { ... } // - Durable Object handlers // - etc. }; ``` -------------------------------- ### examplefunction Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/endpoints.md An example server function demonstrating request and response structures, along with status codes and middleware usage. ```APIDOC ## `examplefunction(data)` ### Description Example server function for reference. ### Method Not specified (Server Function) ### Endpoint Not specified (Server Function) ### Parameters #### Request Body - **data** (object) - Required - - **exampleKey** (string) - Required - min 1 character ### Request Example ```typescript { "data": { "exampleKey": "test" } } ``` ### Response #### Success Response (200) - **string** - "Function executed successfully" #### Response Example ```typescript "Function executed successfully" ``` ### Error Handling - **400** - Validation error (exampleKey missing or empty) - **500** - Execution error ### Middleware - `exampleMiddlewareWithContext` - Injects example context ``` -------------------------------- ### PostgreSQL (Neon) Server Entry Point Integration Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/database.md Integrates the PostgreSQL database initialization into the TanStack Start server entry point. Ensures the database is set up on each request. ```typescript // src/server.ts - TanStack Start Server Entry import { initDatabase } from "@repo/data-ops/database/setup"; import handler from "@tanstack/react-start/server-entry"; import { env } from "cloudflare:workers"; export default { fetch(request: Request) { // Initialize database on each request const db = initDatabase({ host: env.DATABASE_HOST, username: env.DATABASE_USERNAME, password: env.DATABASE_PASSWORD, }); return handler.fetch(request, { context: { fromFetch: true, }, }); }, }; ``` -------------------------------- ### PostgreSQL Runtime Setup Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/authentication.md Initializes Better Auth with a PostgreSQL database connection. This code should be placed in your server entry point (e.g., src/server.ts) for each serverless invocation. ```typescript // src/server.ts - TanStack Start Server Entry import { setAuth } from "@repo/data-ops/auth/server"; import { initDatabase } from "@repo/data-ops/database/setup"; import handler from "@tanstack/react-start/server-entry"; import { env } from "cloudflare:workers"; export default { fetch(request: Request) { const db = initDatabase({ host: env.DATABASE_HOST, username: env.DATABASE_USERNAME, password: env.DATABASE_PASSWORD, }); setAuth({ secret: env.BETTER_AUTH_SECRET, socialProviders: { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, }, }, adapter: { drizzleDb: db, provider: "pg", }, }); return handler.fetch(request, { context: { fromFetch: true, }, }); }, }; ``` -------------------------------- ### examplefunction(data) Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-functions.md An example server function that demonstrates the usage of middleware context. It logs the received data and context, and returns a success message. ```APIDOC ## `examplefunction(data)` ### Description An example server function that demonstrates the usage of middleware context. It logs the received data and context, and returns a success message. ### Parameters #### Path Parameters - **data** (object) - Required - An object containing input parameters for the function. - **exampleKey** (string) - Required - Example input (min 1 character) ### Returns `string` - "Function executed successfully" ### Example ```typescript import { examplefunction } from "@/core/functions/example-functions"; const result = await examplefunction({ data: { exampleKey: "value" } }); ``` ``` -------------------------------- ### Base Function Setup Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-functions.md Sets up a base server function with protected and Polar middleware. All payment functions extend this base. ```typescript export const baseFunction = createServerFn().middleware([ protectedFunctionMiddleware, polarMiddleware, ]); ``` -------------------------------- ### GET /products Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-hono.md Retrieves a list of products, supporting pagination via query parameters. ```APIDOC ## GET /products ### Description Retrieves a list of products. Supports pagination using the `page` query parameter. ### Method GET ### Endpoint /products ### Parameters #### Query Parameters - **page** (string) - Optional - The page number to retrieve. ### Response #### Success Response (200 OK) - **Content-Type**: application/json - **Body**: A JSON object containing the requested page information. #### Response Example ```json { "page": "1" } ``` ``` -------------------------------- ### Example Server Function Input Schema Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/types.md A Zod schema for validating the input parameters of an example server function, requiring a minimum length for the example key. ```typescript const ExampleInputSchema = z.object({ exampleKey: z.string().min(1), }); ``` -------------------------------- ### PostgreSQL (Neon) Database Setup Function Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/database.md Initializes the Drizzle ORM client for PostgreSQL using Neon. This function should be called once per serverless invocation. ```typescript // packages/data-ops/database/setup.ts import { drizzle } from "drizzle-orm/neon-http"; let db: ReturnType; export function initDatabase(connection: { host: string; username: string; password: string; }) { if (db) { return db; } const connectionString = `postgres://${connection.username}:${connection.password}@${connection.host}`; db = drizzle(connectionString); return db; } export function getDb() { if (!db) { throw new Error("Database not initialized"); } return db; } ``` -------------------------------- ### MySQL Runtime Setup Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/authentication.md Initializes Better Auth with a MySQL database connection. This code should be placed in your server entry point (e.g., src/server.ts) for each serverless invocation. ```typescript // src/server.ts - TanStack Start Server Entry import { setAuth } from "@repo/data-ops/auth/server"; import { initDatabase } from "@repo/data-ops/database/setup"; import handler from "@tanstack/react-start/server-entry"; import { env } from "cloudflare:workers"; export default { fetch(request: Request) { const db = initDatabase({ host: env.DATABASE_HOST, username: env.DATABASE_USERNAME, password: env.DATABASE_PASSWORD, }); setAuth({ secret: env.BETTER_AUTH_SECRET, socialProviders: { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, }, }, adapter: { drizzleDb: db, provider: "mysql", }, }); return handler.fetch(request, { context: { fromFetch: true, }, }); }, }; ``` -------------------------------- ### Button Usage Examples Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-ui-components.md Demonstrates various ways to use the Button component with different variants, sizes, and as a child element for composition. ```typescript // Primary button ``` ```typescript // Large outline button ``` ```typescript // Destructive button ``` ```typescript // Icon button ``` ```typescript // Button as link ``` -------------------------------- ### Hono Route Examples Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-hono.md Provides examples of common Hono route definitions including handling query parameters, POST requests with JSON bodies, path parameters, and basic error responses. ```typescript // GET with query params app.get("/products", (c) => { const page = c.req.query("page") || "1"; return c.json({ page }); }); // POST with body app.post("/products", async (c) => { const body = await c.req.json(); return c.json({ id: "123", ...body }, { status: 201 }); }); // Path parameters app.get("/products/:id", (c) => { const id = c.req.param("id"); return c.json({ id }); }); // Error handling app.get("/error", (c) => { return c.json({ error: "Not found" }, { status: 404 }); }); ``` -------------------------------- ### User Application Build Scripts Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/configuration.md Provides build and development scripts for the user application. Includes commands for starting the dev server, production builds, and previewing. ```bash pnpm run dev # Start dev server on port 3000 pnpm run build # Production build pnpm run serve # Preview production build ``` -------------------------------- ### Example Server Function Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/endpoints.md A reference server function demonstrating input, output, and status codes. Use this as a template for creating new server functions. ```typescript { data: { exampleKey: string; // min 1 character } } ``` ```typescript "Function executed successfully" ``` ```typescript const result = await examplefunction({ data: { exampleKey: "test" } }); console.log(result); ``` -------------------------------- ### MySQL (PlanetScale) Database Setup Function Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/database.md Initializes the Drizzle ORM client for MySQL using PlanetScale serverless driver. This function should be called once per serverless invocation. ```typescript // packages/data-ops/database/setup.ts import { drizzle } from "drizzle-orm/planetscale-serverless"; let db: ReturnType; export function initDatabase(connection: { host: string; username: string; password: string; }) { if (db) { return db } db = drizzle({ connection }); return db; } export function getDb() { if (!db) { throw new Error("Database not initialized"); } return db; } ``` -------------------------------- ### TanStack Router Setup Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/configuration.md Initializes the TanStack Router with route tree, context, and SSR query integration. Ensures proper context provider for React Query. ```typescript const router = createRouter({ routeTree, context: { ...rqContext }, defaultPreload: 'intent', Wrap: (props) => ( {props.children} ), }); setupRouterSsrQueryIntegration({ router, queryClient: rqContext.queryClient }) ``` -------------------------------- ### GET /products/:id Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-hono.md Retrieves a specific product by its ID. ```APIDOC ## GET /products/:id ### Description Retrieves a specific product identified by its unique ID. ### Method GET ### Endpoint /products/:id ### Parameters #### Path Parameters - **id** (string) - Required - The unique identifier of the product. ### Response #### Success Response (200 OK) - **Content-Type**: application/json - **Body**: A JSON object containing the product's ID and associated data. #### Response Example ```json { "id": "product-id-123" } ``` ``` -------------------------------- ### Hono Middleware Example Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-hono.md Illustrates how to implement middleware in Hono to perform actions before and after route handlers are executed, such as logging request details and response status. ```typescript app.use("*", async (c, next) => { console.log(`${c.req.method} ${c.req.path}`); await next(); console.log(`Status: ${c.res.status}`); }); ``` -------------------------------- ### ExampleWorkflow Class Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-workflows.md Defines an example workflow demonstrating step orchestration and state management. It extends `WorkflowEntrypoint` and implements the `run` method to define the workflow's execution logic. ```APIDOC ## `ExampleWorkflow` Example workflow demonstrating step orchestration and state management. ```typescript export class ExampleWorkflow extends WorkflowEntrypoint< Env, ExampleWorkflowParmas > { async run( event: Readonly>, step: WorkflowStep, ) { // Workflow logic here } } ``` ### Type Parameters - `Env` - Cloudflare Worker environment bindings - `ExampleWorkflowParmas` - Type of payload passed to workflow ### Properties | Property | Type | Description | |----------|------|-------------| | event | WorkflowEvent | Workflow trigger event with payload | | step | WorkflowStep | Step execution API | ### Constructor Inherited from `WorkflowEntrypoint`. Called automatically by Cloudflare. ``` -------------------------------- ### Example Middleware with Context Injection Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-middleware.md A reference implementation showing the pattern for creating custom middleware that injects data into the context. Useful for understanding context propagation. ```typescript export const exampleMiddlewareWithContext = createMiddleware({ type: "function", }).server(async ({ next }) => { console.log("Executing exampleMiddlewareWithContext"); return await next({ context: { data: "Some Data From Middleware", }, }); }) ``` -------------------------------- ### pnpm Workspace Dependency Example Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/configuration.md Illustrates how to declare a dependency on a workspace package within a pnpm monorepo. Uses the 'workspace:*' protocol for local linking. ```json { "dependencies": { "@repo/data-ops": "workspace:*" } } ``` -------------------------------- ### Cloudflare D1 Database Setup Function Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/database.md Initializes the Drizzle ORM client for Cloudflare D1. This function should be called once per serverless invocation. ```typescript // packages/data-ops/database/setup.ts import { drizzle } from "drizzle-orm/d1"; let db: ReturnType; export function initDatabase(d1Db: D1Database) { if (db) { return db } db = drizzle(d1Db); return db; } export function getDb() { if (!db) { throw new Error("Database not initialized"); } return db; } ``` -------------------------------- ### Card Component Example Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-ui-components.md Illustrates the usage of the Card component along with its structure components (CardHeader, CardTitle, CardDescription, CardContent, CardFooter) to create a product card layout. ```typescript import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardAction, CardFooter, } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; export function ProductCard() { return ( Premium Plan For growing teams

Includes all features

$29/month

); } ``` -------------------------------- ### Cloudflare D1 Server Entry Point Integration Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/database.md Integrates the Cloudflare D1 database initialization into the TanStack Start server entry point. Ensures the database is set up on each request using the D1 binding. ```typescript // src/server.ts - TanStack Start Server Entry import { initDatabase } from "@repo/data-ops/database/setup"; import handler from "@tanstack/react-start/server-entry"; import { env } from "cloudflare:workers"; export default { fetch(request: Request) { // Initialize database on each request const db = initDatabase(env.DB); // D1 binding return handler.fetch(request, { context: { fromFetch: true, }, }); }, }; ``` -------------------------------- ### Cloudflare D1 Runtime Setup Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/authentication.md Initializes Better Auth with a Cloudflare D1 database binding. This code should be placed in your server entry point (e.g., src/server.ts) for each serverless invocation. ```typescript // src/server.ts - TanStack Start Server Entry import { setAuth } from "@repo/data-ops/auth/server"; import { initDatabase } from "@repo/data-ops/database/setup"; import handler from "@tanstack/react-start/server-entry"; import { env } from "cloudflare:workers"; export default { fetch(request: Request) { const db = initDatabase(env.DB); // D1 binding setAuth({ secret: env.BETTER_AUTH_SECRET, socialProviders: { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, }, }, adapter: { drizzleDb: db, provider: "sqlite", }, }); return handler.fetch(request, { context: { fromFetch: true, }, }); }, }; ``` -------------------------------- ### Root Build Scripts Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/configuration.md Defines essential build scripts for the monorepo root. Includes commands for initial setup, building shared packages, and managing dependencies. ```bash pnpm run setup # Install deps + build data-ops pnpm run build:data-ops # Build shared package ``` -------------------------------- ### Better-Auth Setup Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/configuration.md Configure Better-Auth with a Drizzle ORM adapter for database integration. Ensure your database connection and schema are correctly set up. Supports social providers like Google. ```typescript const auth = createBetterAuth({ database: drizzleAdapter(db, { provider: "mysql", schema: { auth_user, auth_account, auth_session, auth_verification, }, }), secret: process.env.AUTH_SECRET, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }, }, }); ``` -------------------------------- ### TanStack Start API Route for Authentication Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/authentication.md Sets up a catch-all API route for handling authentication requests using Better Auth. This route automatically manages sign-in, sign-out, callbacks, and session management. ```typescript // src/routes/api/auth.$.tsx import { createFileRoute } from "@tanstack/react-router"; import { getAuth } from "@repo/data-ops/auth/server"; export const Route = createFileRoute("/api/auth/$")({ server: { handlers: { GET: ({ request }) => { const auth = getAuth(); return auth.handler(request); }, POST: ({ request }) => { const auth = getAuth(); return auth.handler(request); }, }, }, }); ``` -------------------------------- ### Example Layout with Header and Navigation Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/README.md This snippet shows a root layout component in React using TanStack Router. It includes a header with navigation links and an Outlet for rendering child routes. The TanStackRouterDevtools are optional. ```tsx import { Outlet, createRootRoute } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' import { Link } from "@tanstack/react-router"; export const Route = createRootRoute({ component: () => ( <>
), }) ``` -------------------------------- ### Product Metadata Example Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/polar.md Configure custom metadata for subscription products in Polar to control application features and limits. This JSON structure defines available features and usage limits. ```json { "features": { "analytics": true, "api_access": true, "priority_support": true, "custom_branding": false }, "limits": { "projects": 10, "storage_gb": 100, "api_calls_per_month": 10000 } } ``` -------------------------------- ### Preview Production Build Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/CLAUDE.md Use this command to preview the production build locally. ```bash pnpm serve ``` -------------------------------- ### Checkout Button Component using useCheckout Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-payments.md Example of a React component that uses the `useCheckout` hook to render a checkout button. The button initiates the checkout process when clicked and displays a loading state while the request is pending. ```typescript import { useCheckout } from "@/components/payments/polar/use-checkout"; export function CheckoutButton({ productId }: { productId: string }) { const { redirectToCheckout, isCheckoutPending } = useCheckout(); return ( ); } ``` -------------------------------- ### Example Zod Validation Schema Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/types.md An example Zod schema for validating data, including string length constraints for the name field. ```typescript export const exampleSchema = z.object({ id: z.string(), name: z.string().min(2).max(100), email: z.string(), }); ``` -------------------------------- ### Adding New Server Functions (user-application) Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/endpoints.md Demonstrates how to add new server functions using `createServerFn`, including middleware, input validation with Zod, and handler logic. ```APIDOC ## Adding New Server Functions (user-application) ### Description How to add new server functions with middleware and input validation. ### Function Definition Example ```typescript import { createServerFn } from "@tanstack/react-start"; import { protectedFunctionMiddleware } from "@/core/middleware/auth"; import { z } from "zod"; const InputSchema = z.object({ name: z.string().min(1), }); export const myFunction = createServerFn() .middleware([protectedFunctionMiddleware]) .inputValidator((data) => InputSchema.parse(data)) .handler(async (ctx) => { const { userId, email } = ctx.context; const { name } = ctx.data; return { success: true, userId, name }; }); ``` ### Call from client ```typescript const result = await myFunction({ data: { name: "test" } }); ``` ``` -------------------------------- ### Build for Production Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/CLAUDE.md This command builds the application for production deployment. ```bash pnpm build ``` -------------------------------- ### GET / Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/endpoints.md Returns a simple health check response from the data service. ```APIDOC ## GET / ### Description Returns health check response. ### Method GET ### Endpoint / ### Request Example ```http GET / HTTP/1.1 Host: api.example.com ``` ### Response #### Success Response (200) Content-Type: text/plain Hello World ``` -------------------------------- ### Get Products Function Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-functions.md Retrieves a list of available Polar products. Requires authentication. ```typescript export const getProducts = baseFunction.handler(async (ctx) => { const products = await ctx.context.polar.products.list({ isArchived: false, }); return products.result.items; }) ``` -------------------------------- ### Navigate to User Application Directory Source: https://github.com/backpine/saas-kit/blob/main/README.md Change directory into the user application package to work with it independently. ```bash cd packages/user-application ``` -------------------------------- ### Getting Workflow Status Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-workflows.md Shows how to retrieve the status and result of an existing workflow execution using its unique ID. ```APIDOC ## Getting Workflow Status ```typescript // Get existing workflow handle const handle = c.env.EXAMPLE_WORKFLOW.get(workflowId); // Check status const result = await handle.result(); ``` ``` -------------------------------- ### Use Link Component for Navigation Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/README.md Example of using the Link component from TanStack Router to create SPA navigation links. ```tsx About ``` -------------------------------- ### Create Auth Client Instance Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-auth.md Initializes the better-auth client instance for OAuth-based authentication. This should be done once and imported where needed. ```typescript import { createAuthClient } from "better-auth/react"; export const authClient = createAuthClient(); ``` -------------------------------- ### initDatabase(connection) Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-ops-database.md Initializes a singleton Drizzle ORM database instance with PlanetScale serverless connection. This function sets up the database connection and caches it globally for subsequent use. It requires connection details including host, username, and password. ```APIDOC ## initDatabase(connection) ### Description Initializes a singleton Drizzle ORM database instance with PlanetScale serverless connection. This function sets up the database connection and caches it globally for subsequent use. It requires connection details including host, username, and password. ### Parameters #### Connection Object - **host** (string) - Required - PlanetScale host URL (e.g., "aws.connect.psdb.cloud") - **username** (string) - Required - Database username - **password** (string) - Required - Database password ### Returns `ReturnType` - Drizzle ORM database instance with query builder methods. Returns cached instance on subsequent calls. ### Behavior - First call initializes the database connection and caches it globally - Subsequent calls return the same cached instance without re-initializing - Uses PlanetScale serverless driver for edge-compatible connections ### Example ```typescript import { initDatabase } from "@repo/data-ops/database/setup"; const db = initDatabase({ host: process.env.DATABASE_HOST || "aws.connect.psdb.cloud", username: process.env.DATABASE_USERNAME || "", password: process.env.DATABASE_PASSWORD || "", }); // Use in queries const users = await db.select().from(auth_user); ``` ``` -------------------------------- ### POST /api/data Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-hono.md An example endpoint demonstrating access to Cloudflare Worker environment bindings like D1 database and KV storage. ```APIDOC ## POST /api/data ### Description An example endpoint demonstrating how to access Cloudflare Worker environment bindings such as D1 database and KV storage within a Hono route handler. ### Method POST ### Endpoint /api/data ### Environment Access Access to `c.env.DB` (D1) and `c.env.KV_STORE` (KV) is demonstrated. ### Response #### Success Response (200 OK) - **Content-Type**: application/json - **Body**: A JSON object indicating success. #### Response Example ```json { "message": "Success" } ``` ``` -------------------------------- ### Client-Side Authentication with Better-Auth Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/endpoints.md Demonstrates how to use the authClient for signing in, checking session status, and signing out. Ensure the authClient is imported from '@/lib/auth-client'. ```typescript import { authClient } from "@/lib/auth-client"; // Sign in await authClient.signIn.social({ provider: "google", callbackURL: "/app", }); // Check session const { data: session } = authClient.useSession(); // Sign out await authClient.signOut(); ``` -------------------------------- ### Fetch Health Check Response Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/endpoints.md This TypeScript example shows how to fetch the health check response from the data service and log its text content. ```typescript const response = await fetch('/'); const text = await response.text(); console.log(text); // "Hello World" ``` -------------------------------- ### Add Shadcn/UI Components Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/README.md Commands to add individual Shadcn/UI components to the project. ```bash pnpx shadcn@latest add button pnpx shadcn@latest add card pnpx shadcn@latest add form ``` -------------------------------- ### Conditional Route Protection with Middleware Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-routing.md Protect routes using middleware defined in `beforeLoad`. This example redirects unauthenticated users to the login page. ```typescript import { protectedRequestMiddleware } from "@/core/middleware/auth"; export const Route = createFileRoute("/dashboard")({ beforeLoad: async ({ context }) => { // Middleware context available here const { userId } = context; if (!userId) { throw redirect({ to: "/login" }); } }, component: Dashboard, }); ``` -------------------------------- ### Route Search Parameters Validation Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-routing.md Use `validateSearch` to define and parse search parameters for filtering and pagination. This example uses Zod for validation. ```typescript export const Route = createFileRoute("/products")({ validateSearch: (search: Record) => z.object({ page: z.number().optional(), sort: z.enum(["name", "price"]).optional(), }).parse(search), component: ProductsPage, }); function ProductsPage() { const search = Route.useSearch(); return (
Current page: {search.page || 1} Sort by: {search.sort || "name"}
); } ``` -------------------------------- ### Getting Workflow Status Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-workflows.md Retrieves the status and result of an existing workflow using its ID. This allows for monitoring and checking the outcome of a workflow execution. ```typescript // Get existing workflow handle const handle = c.env.EXAMPLE_WORKFLOW.get(workflowId); // Check status const result = await handle.result(); ``` -------------------------------- ### createBetterAuth(config) Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-ops-auth.md Creates and configures a better-auth instance with specified database and OAuth providers. It sets up the authentication models and supports social OAuth. ```APIDOC ## `createBetterAuth(config)` Creates and configures a better-auth instance with specified database and OAuth providers. ### Parameters - **config** (object) - Required - Configuration object - **config.database** (BetterAuthOptions["database"]) - Required - Database adapter (drizzle adapter) - **config.secret** (BetterAuthOptions["secret"]) - Optional - Secret key for signing tokens - **config.socialProviders** (BetterAuthOptions["socialProviders"]) - Optional - OAuth provider configuration ### Returns `ReturnType` - Configured better-auth instance with auth API methods and utilities. ### Configuration Details The instance is configured with the following hardcoded models: - `user`: model name `auth_user` - `session`: model name `auth_session` - `verification`: model name `auth_verification` - `account`: model name `auth_account` - Email/password authentication is disabled - Supports social OAuth providers ### Example ```typescript import { createBetterAuth } from "@repo/data-ops/auth/setup"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; const auth = createBetterAuth({ database: drizzleAdapter(db, { provider: "mysql", schema: { auth_user, auth_account, auth_session, auth_verification, }, }), secret: process.env.AUTH_SECRET, socialProviders: { google: { enabled: true, }, }, }); ``` ``` -------------------------------- ### Define and Chain Middleware Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-middleware.md Illustrates the basic pattern for defining middleware using `createMiddleware` and chaining server-side logic with `.server()`. ```typescript createMiddleware({ type: "function" | "request" }) .server(async ({ next }) => { ... }) // Perform async setup/validation // Call next({ context: {...} }) to pass context to handler // Handler receives context via ctx.context ``` -------------------------------- ### Adding New Server Functions Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/endpoints.md Shows how to create new server functions using `createServerFn`, including applying middleware like authentication and validating input with Zod. The `ctx.context` provides access to authenticated user details. ```typescript import { createServerFn } from "@tanstack/react-start"; import { protectedFunctionMiddleware } from "@/core/middleware/auth"; import { z } from "zod"; const InputSchema = z.object({ name: z.string().min(1), }); export const myFunction = createServerFn() .middleware([protectedFunctionMiddleware]) .inputValidator((data) => InputSchema.parse(data)) .handler(async (ctx) => { const { userId, email } = ctx.context; const { name } = ctx.data; return { success: true, userId, name }; }); ``` ```typescript const result = await myFunction({ data: { name: "test" } }); ``` -------------------------------- ### POST /products Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/data-service-hono.md Creates a new product with the provided data in the request body. ```APIDOC ## POST /products ### Description Creates a new product. Accepts product data in the request body and returns the created product's ID along with the provided data. ### Method POST ### Endpoint /products ### Parameters #### Request Body - **(object)** - Required - Product data. ### Request Example ```json { "name": "New Product", "price": 100 } ``` ### Response #### Success Response (201 Created) - **Content-Type**: application/json - **Body**: A JSON object containing the ID of the newly created product and its data. #### Response Example ```json { "id": "123", "name": "New Product", "price": 100 } ``` ``` -------------------------------- ### CORS Configuration for Hono Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/configuration.md Example of configuring Cross-Origin Resource Sharing (CORS) middleware for a Hono application. Applied to API routes to manage external access. ```typescript app.use("/api/*", cors()); ``` -------------------------------- ### Deploy User Application to Cloudflare Source: https://github.com/backpine/saas-kit/blob/main/README.md Command to deploy the user application, typically to Cloudflare. ```bash pnpm run deploy:user-application ``` -------------------------------- ### Get Authentication Context Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-middleware.md Retrieves the authentication context, including the user ID and email, by validating the session from the request cookies. Throws an error if the session is invalid. ```typescript async function getAuthContext() { const auth = getAuth(); const req = getRequest(); const session = await auth.api.getSession(req); if (!session) { throw new Error("Unauthorized"); } return { auth: auth, userId: session.user.id, email: session.user.email, }; } ``` -------------------------------- ### Local Development Workflow Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/configuration.md Commands to set up and run the local development environment for both the data service and user application. Specifies access URLs. ```bash # Install dependencies pnpm run setup # Terminal 1: Data Service pnpm run dev:data-service # Terminal 2: User Application pnpm run dev:user-application # Access application # Frontend: http://localhost:3000 # API: http://localhost:8787 ``` -------------------------------- ### MySQL Environment Variables Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/database.md Configure MySQL connection details in the .env file for the data-ops package. Ensure all required credentials are provided. ```bash # packages/data-ops/.env # MySQL Configuration (PlanetScale, etc.) DATABASE_HOST="hostname.com/database-name" DATABASE_USERNAME="username" DATABASE_PASSWORD="password" ``` -------------------------------- ### Add New API Endpoint Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/README.md Example of adding a new POST route to the Hono backend for saving items. Ensure the item is saved and a 201 status is returned. ```typescript app.post("/api/items", async (c) => { const body = await c.req.json(); const item = await saveItem(body); return c.json(item, { status: 201 }); }); ``` -------------------------------- ### Fetch Products and Subscription for Pricing Page Source: https://github.com/backpine/saas-kit/blob/main/_autodocs/api-reference/user-application-payments.md This snippet fetches available products and the user's current subscription using React Query. It's used to populate the pricing grid component. ```typescript import { PricingGrid } from "@/components/payments/polar/pricing-grid"; import { useQuery } from "@tanstack/react-query"; import { getProducts, collectSubscription } from "@/core/functions/payments"; import { useCheckout } from "@/components/payments/polar/use-checkout"; export function PricingPage() { const { data: products } = useQuery({ queryKey: ["products"], queryFn: () => getProducts(), }); const { data: subscription } = useQuery({ queryKey: ["subscription"], queryFn: () => collectSubscription(), }); const { redirectToCheckout, isCheckoutPending } = useCheckout(); return ( ); } ``` -------------------------------- ### Run Tests Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/CLAUDE.md Execute tests using Vitest with this command. ```bash pnpm test ``` -------------------------------- ### PostgreSQL Environment Variables Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/database.md Configure PostgreSQL connection details in the .env file for the data-ops package. Ensure all required credentials are provided. ```bash # packages/data-ops/.env # PostgreSQL Configuration (Supabase, Neon, etc.) DATABASE_HOST="hostname.com/database-name" DATABASE_USERNAME="username" DATABASE_PASSWORD="password" ``` -------------------------------- ### PostgreSQL CLI Configuration for Better Auth Source: https://github.com/backpine/saas-kit/blob/main/apps/user-application/public/docs/authentication.md Configure Better Auth CLI for PostgreSQL using Drizzle ORM. This setup is for CLI use and generates database schemas. ```typescript // packages/data-ops/config/auth.ts import { createBetterAuth } from "../src/auth/setup"; import { initDatabase } from "../src/database/setup"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; export const auth = createBetterAuth({ database: drizzleAdapter( initDatabase({ password: process.env.DATABASE_PASSWORD!, host: process.env.DATABASE_HOST!, username: process.env.DATABASE_USERNAME!, }), { provider: "pg", }, ), }); ```