From 4c4273a5faa5f17687105634827c33b3a9f7ee01 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 10:37:54 +0000 Subject: [PATCH 01/16] feat: required config setup --- apps/cli/src/helpers/core/create-readme.ts | 3 +++ apps/cli/src/helpers/core/template-manager.ts | 20 ++++++++++++++++++- apps/cli/src/prompts/frontend.ts | 5 +++++ apps/cli/src/types.ts | 1 + apps/cli/src/utils/compatibility.ts | 1 + apps/web/src/lib/constant.ts | 8 ++++++++ 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/apps/cli/src/helpers/core/create-readme.ts b/apps/cli/src/helpers/core/create-readme.ts index fa31d4585..81818b44b 100644 --- a/apps/cli/src/helpers/core/create-readme.ts +++ b/apps/cli/src/helpers/core/create-readme.ts @@ -174,6 +174,7 @@ function generateStackDescription( const hasTanstackStart = frontend.includes("tanstack-start"); const hasSvelte = frontend.includes("svelte"); const hasNuxt = frontend.includes("nuxt"); + const hasAstro = frontend.includes("astro"); const hasSolid = frontend.includes("solid"); const hasFrontendNone = frontend.length === 0 || frontend.includes("none"); @@ -190,6 +191,8 @@ function generateStackDescription( parts.push("SvelteKit"); } else if (hasNuxt) { parts.push("Nuxt"); + } else if (hasAstro) { + parts.push("Astro"); } else if (hasSolid) { parts.push("SolidJS"); } diff --git a/apps/cli/src/helpers/core/template-manager.ts b/apps/cli/src/helpers/core/template-manager.ts index f8c3e2c33..0fe61c9e7 100644 --- a/apps/cli/src/helpers/core/template-manager.ts +++ b/apps/cli/src/helpers/core/template-manager.ts @@ -67,6 +67,7 @@ export async function setupFrontendTemplates( ["tanstack-router", "react-router", "tanstack-start", "next"].includes(f), ); const hasNuxtWeb = context.frontend.includes("nuxt"); + const hasAstroWeb = context.frontend.includes("astro"); const hasSvelteWeb = context.frontend.includes("svelte"); const hasSolidWeb = context.frontend.includes("solid"); const hasNativeWind = context.frontend.includes("native-nativewind"); @@ -74,7 +75,7 @@ export async function setupFrontendTemplates( const _hasNative = hasNativeWind || hasUnistyles; const isConvex = context.backend === "convex"; - if (hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) { + if (hasReactWeb || hasNuxtWeb || hasAstroWeb || hasSvelteWeb || hasSolidWeb) { const webAppDir = path.join(projectDir, "apps/web"); await fs.ensureDir(webAppDir); @@ -140,6 +141,23 @@ export async function setupFrontendTemplates( } else { } } + } else if (hasAstroWeb) { + const astroBaseDir = path.join(PKG_ROOT, "templates/frontend/astro"); + if (await fs.pathExists(astroBaseDir)) { + await processAndCopyFiles("**/*", astroBaseDir, webAppDir, context); + } else { + } + + if (!isConvex && context.api === "orpc") { + const apiWebAstroDir = path.join( + PKG_ROOT, + `templates/api/${context.api}/web/astro`, + ); + if (await fs.pathExists(apiWebAstroDir)) { + await processAndCopyFiles("**/*", apiWebAstroDir, webAppDir, context); + } else { + } + } } else if (hasSvelteWeb) { const svelteBaseDir = path.join(PKG_ROOT, "templates/frontend/svelte"); if (await fs.pathExists(svelteBaseDir)) { diff --git a/apps/cli/src/prompts/frontend.ts b/apps/cli/src/prompts/frontend.ts index f4079c857..91739dd58 100644 --- a/apps/cli/src/prompts/frontend.ts +++ b/apps/cli/src/prompts/frontend.ts @@ -55,6 +55,11 @@ export async function getFrontendChoice( label: "Nuxt", hint: "The Progressive Web Framework for Vue.js", }, + { + value: "astro" as const, + label: "Astro", + hint: "All-in-one web framework for content-driven websites", + }, { value: "svelte" as const, label: "Svelte", diff --git a/apps/cli/src/types.ts b/apps/cli/src/types.ts index a6f7fcfb8..ba9f98369 100644 --- a/apps/cli/src/types.ts +++ b/apps/cli/src/types.ts @@ -27,6 +27,7 @@ export const FrontendSchema = z "tanstack-start", "next", "nuxt", + "astro", "native-nativewind", "native-unistyles", "svelte", diff --git a/apps/cli/src/utils/compatibility.ts b/apps/cli/src/utils/compatibility.ts index 3f488d4c5..0b3f277f2 100644 --- a/apps/cli/src/utils/compatibility.ts +++ b/apps/cli/src/utils/compatibility.ts @@ -6,6 +6,7 @@ export const WEB_FRAMEWORKS: readonly Frontend[] = [ "tanstack-start", "next", "nuxt", + "astro", "svelte", "solid", ] as const; diff --git a/apps/web/src/lib/constant.ts b/apps/web/src/lib/constant.ts index 7fcbcc094..33e81c79c 100644 --- a/apps/web/src/lib/constant.ts +++ b/apps/web/src/lib/constant.ts @@ -80,6 +80,14 @@ export const TECH_OPTIONS: Record< color: "from-green-400 to-green-700", default: false, }, + { + id: "astro", + name: "Astro", + description: "All-in-one web framework for content-driven websites", + icon: `${ICON_BASE_URL}/astro.svg`, + color: "from-indigo-400 to-indigo-700", + default: false, + }, { id: "svelte", name: "Svelte", From 4ea72c1293ea320cd0bfb6bdde38a55139c406eb Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 10:58:15 +0000 Subject: [PATCH 02/16] feat: astro config and baseground --- apps/cli/templates/frontend/astro/_gitignore | 24 ++++++++++++++++++ .../frontend/astro/astro.config.mjs.hbs | 9 +++++++ .../templates/frontend/astro/package.json.hbs | 23 +++++++++++++++++ .../frontend/astro/public/favicon.svg | 9 +++++++ .../frontend/astro/public/robots.txt | 5 ++++ .../frontend/astro/src/styles/global.css | 5 ++++ .../frontend/astro/tsconfig.json.hbs | 25 +++++++++++++++++++ 7 files changed, 100 insertions(+) create mode 100644 apps/cli/templates/frontend/astro/_gitignore create mode 100644 apps/cli/templates/frontend/astro/astro.config.mjs.hbs create mode 100644 apps/cli/templates/frontend/astro/package.json.hbs create mode 100644 apps/cli/templates/frontend/astro/public/favicon.svg create mode 100644 apps/cli/templates/frontend/astro/public/robots.txt create mode 100644 apps/cli/templates/frontend/astro/src/styles/global.css create mode 100644 apps/cli/templates/frontend/astro/tsconfig.json.hbs diff --git a/apps/cli/templates/frontend/astro/_gitignore b/apps/cli/templates/frontend/astro/_gitignore new file mode 100644 index 000000000..a0cee654d --- /dev/null +++ b/apps/cli/templates/frontend/astro/_gitignore @@ -0,0 +1,24 @@ +# build output +dist/ +# generated types +.astro/ + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store + +# jetbrains setting folder +.idea/ \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/astro.config.mjs.hbs b/apps/cli/templates/frontend/astro/astro.config.mjs.hbs new file mode 100644 index 000000000..fa08bd1c1 --- /dev/null +++ b/apps/cli/templates/frontend/astro/astro.config.mjs.hbs @@ -0,0 +1,9 @@ +import { defineConfig } from 'astro/config'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + vite: { + plugins: [tailwindcss()] + }, + output: 'static' +}); \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/package.json.hbs b/apps/cli/templates/frontend/astro/package.json.hbs new file mode 100644 index 000000000..7615293b1 --- /dev/null +++ b/apps/cli/templates/frontend/astro/package.json.hbs @@ -0,0 +1,23 @@ +{ + "name": "web", + "type": "module", + "version": "0.1.0", + "private": true, + "license": "MIT", + "engines": { + "node": ">= 22" + }, + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "astro": "^5.2.4", + "@tailwindcss/vite": "^4.1.15", + "tailwindcss": "^4.1.15", + "typescript": "^5.9.2" + } +} \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/public/favicon.svg b/apps/cli/templates/frontend/astro/public/favicon.svg new file mode 100644 index 000000000..f157bd1c5 --- /dev/null +++ b/apps/cli/templates/frontend/astro/public/favicon.svg @@ -0,0 +1,9 @@ + + + + diff --git a/apps/cli/templates/frontend/astro/public/robots.txt b/apps/cli/templates/frontend/astro/public/robots.txt new file mode 100644 index 000000000..4c954eb9d --- /dev/null +++ b/apps/cli/templates/frontend/astro/public/robots.txt @@ -0,0 +1,5 @@ +# Example: Allow all bots to scan and index your site. +# Full syntax: https://developers.google.com/search/docs/advanced/robots/create-robots-txt + +User-agent: * +Allow: / \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/src/styles/global.css b/apps/cli/templates/frontend/astro/src/styles/global.css new file mode 100644 index 000000000..d0fb0df46 --- /dev/null +++ b/apps/cli/templates/frontend/astro/src/styles/global.css @@ -0,0 +1,5 @@ +@import 'tailwindcss'; + +body { + @apply bg-neutral-950 text-neutral-100; +} \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/tsconfig.json.hbs b/apps/cli/templates/frontend/astro/tsconfig.json.hbs new file mode 100644 index 000000000..f5ca15b25 --- /dev/null +++ b/apps/cli/templates/frontend/astro/tsconfig.json.hbs @@ -0,0 +1,25 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"], + "paths": { + "@components/*": [ + "src/components/*" + ], + "@layouts/*": [ + "src/layouts/*" + ], + "@utils/*": [ + "src/utils/*" + ], + "@styles/*": [ + "src/styles/*" + ], + "@/*": [ + "src/*" + ], + "@assets/*": [ + "src/assets/*" + ] + }, +} \ No newline at end of file From aa00a400ea0c491ed51a452d744b8baaa2b6e8b2 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 10:58:33 +0000 Subject: [PATCH 03/16] feat: add base layout and page --- .../astro/src/layouts/Layout.astro.hbs | 26 ++++++++++++ .../frontend/astro/src/pages/index.astro.hbs | 42 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 apps/cli/templates/frontend/astro/src/layouts/Layout.astro.hbs create mode 100644 apps/cli/templates/frontend/astro/src/pages/index.astro.hbs diff --git a/apps/cli/templates/frontend/astro/src/layouts/Layout.astro.hbs b/apps/cli/templates/frontend/astro/src/layouts/Layout.astro.hbs new file mode 100644 index 000000000..78f53c903 --- /dev/null +++ b/apps/cli/templates/frontend/astro/src/layouts/Layout.astro.hbs @@ -0,0 +1,26 @@ +--- +import '../styles/global.css'; + + +interface Props { + title?: string | undefined; + description?: string | undefined; +} + +const { title, description = "Built with Better-T-Stack"} = Astro.props; + +--- + + + + + + + + + {title} + + + + + \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs b/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs new file mode 100644 index 000000000..a20352e5c --- /dev/null +++ b/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs @@ -0,0 +1,42 @@ +--- +{{#if (eq api "orpc")}} +// TODO: Add oRPC integration for Astro +{{/if}} + +import Layout from '@layouts/Layout.astro'; + +const TITLE_TEXT = ` + ██████╗ ███████╗████████╗████████╗███████╗██████╗ + ██╔══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗ + ██████╔╝█████╗ ██║ ██║ █████╗ ██████╔╝ + ██╔══██╗██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗ + ██████╔╝███████╗ ██║ ██║ ███████╗██║ ██║ + ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ + + ████████╗ ███████╗████████╗ █████╗ ██████╗██╗ ██╗ + ╚══██╔══╝ ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝ + ██║ ███████╗ ██║ ███████║██║ █████╔╝ + ██║ ╚════██║ ██║ ██╔══██║██║ ██╔═██╗ + ██║ ███████║ ██║ ██║ ██║╚██████╗██║ ██╗ + ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ + `; +--- + + +
+
{TITLE_TEXT}
+
+ {{#if (eq api "orpc")}} +
+

API Status

+
+
+ + Ready to connect + +
+
+ {{/if}} +
+
+
\ No newline at end of file From 8f83e3acaecc826864011e776fc5848f8fd39958 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 11:00:03 +0000 Subject: [PATCH 04/16] chore: make static render optional --- apps/cli/templates/frontend/astro/astro.config.mjs.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/cli/templates/frontend/astro/astro.config.mjs.hbs b/apps/cli/templates/frontend/astro/astro.config.mjs.hbs index fa08bd1c1..543a436d2 100644 --- a/apps/cli/templates/frontend/astro/astro.config.mjs.hbs +++ b/apps/cli/templates/frontend/astro/astro.config.mjs.hbs @@ -5,5 +5,5 @@ export default defineConfig({ vite: { plugins: [tailwindcss()] }, - output: 'static' + // output: 'static' }); \ No newline at end of file From 97d7fbfde28ecc91ed1a4ced8acf5fe091e8f88f Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 11:14:23 +0000 Subject: [PATCH 05/16] feat: add oRPC into Astro - 1 --- apps/cli/src/helpers/core/api-setup.ts | 11 +++++++ .../api/orpc/web/astro/src/lib/orpc.ts.hbs | 29 +++++++++++++++++++ .../templates/frontend/astro/package.json.hbs | 15 ++++++++-- .../frontend/astro/src/pages/index.astro.hbs | 26 ++++++++++++++--- 4 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs diff --git a/apps/cli/src/helpers/core/api-setup.ts b/apps/cli/src/helpers/core/api-setup.ts index f685ac39c..c489311db 100644 --- a/apps/cli/src/helpers/core/api-setup.ts +++ b/apps/cli/src/helpers/core/api-setup.ts @@ -25,6 +25,7 @@ function getFrontendType(frontend: Frontend[]): { hasNuxtWeb: boolean; hasSvelteWeb: boolean; hasSolidWeb: boolean; + hasAstroWeb: boolean; hasNative: boolean; } { const reactBasedFrontends = [ @@ -40,6 +41,7 @@ function getFrontendType(frontend: Frontend[]): { hasNuxtWeb: frontend.includes("nuxt"), hasSvelteWeb: frontend.includes("svelte"), hasSolidWeb: frontend.includes("solid"), + hasAstroWeb: frontend.includes("astro"), hasNative: frontend.some((f) => nativeFrontends.includes(f)), }; } @@ -108,6 +110,15 @@ function getApiDependencies( "@tanstack/solid-router-devtools", ], }; + } else if (frontendType.hasAstroWeb && api === "orpc") { + deps.web = { + dependencies: [ + "@orpc/tanstack-query", + "@orpc/client", + "@tanstack/react-query", + ], + devDependencies: ["@tanstack/react-query-devtools"], + }; } if (api === "trpc") { diff --git a/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs new file mode 100644 index 000000000..b3db25cf5 --- /dev/null +++ b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs @@ -0,0 +1,29 @@ +import { createORPCClient } from "@orpc/client"; +import { RPCLink } from "@orpc/client/fetch"; +import { createTanstackQueryUtils } from "@orpc/tanstack-query"; +import { QueryCache, QueryClient } from "@tanstack/react-query"; +import type { AppRouterClient } from "../../../server/src/routers/index"; + +export const queryClient = new QueryClient({ + queryCache: new QueryCache({ + onError: (error) => { + console.error(`Error: ${error.message}`); + }, + }), +}); + +export const link = new RPCLink({ + url: `${import.meta.env.PUBLIC_SERVER_URL}/rpc`, + {{#if (eq auth "better-auth")}} + fetch(url, options) { + return fetch(url, { + ...options, + credentials: "include", + }); + }, + {{/if}} +}); + +export const client: AppRouterClient = createORPCClient(link); + +export const orpc = createTanstackQueryUtils(client); \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/package.json.hbs b/apps/cli/templates/frontend/astro/package.json.hbs index 7615293b1..48a78b664 100644 --- a/apps/cli/templates/frontend/astro/package.json.hbs +++ b/apps/cli/templates/frontend/astro/package.json.hbs @@ -18,6 +18,17 @@ "astro": "^5.2.4", "@tailwindcss/vite": "^4.1.15", "tailwindcss": "^4.1.15", - "typescript": "^5.9.2" - } + "typescript": "^5.9.2", + "zod": "^4.1.5"{{#if (eq api "orpc")}}, + "@orpc/tanstack-query": "^1.9.0", + "@orpc/client": "^1.9.0", + "@tanstack/react-query": "^5.85.5"{{/if}} + }{{#if (eq api "orpc")}}, + "devDependencies": { + "@astrojs/check": "^0.13.0", + "@tanstack/react-query-devtools": "^5.85.5" + }{{else}}, + "devDependencies": { + "@astrojs/check": "^0.13.0" + }{{/if}} } \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs b/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs index a20352e5c..ab28b8422 100644 --- a/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs +++ b/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs @@ -1,9 +1,22 @@ --- +{{#if (eq backend "convex")}} +// TODO: Add Convex integration for Astro +{{else}} {{#if (eq api "orpc")}} -// TODO: Add oRPC integration for Astro +import { client } from '../lib/orpc'; + +// Server-side API call +let healthCheckData; +try { + healthCheckData = await client.healthCheck.query(); +} catch (error) { + console.error('Health check failed:', error); + healthCheckData = null; +} +{{/if}} {{/if}} -import Layout from '@layouts/Layout.astro'; +import Layout from '../layouts/Layout.astro'; const TITLE_TEXT = ` ██████╗ ███████╗████████╗████████╗███████╗██████╗ @@ -30,11 +43,16 @@ const TITLE_TEXT = `

API Status

-
+
- Ready to connect + {healthCheckData ? "Connected" : "Disconnected"}
+ {healthCheckData && ( +
+ Response: {healthCheckData} +
+ )}
{{/if}} From 70c0fef897a6f8244052e72df249a6d37d1a04cf Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 14:02:51 +0000 Subject: [PATCH 06/16] feat(cli): add oRPC into Astro example --- .../astro/src/components/orpc-status.tsx.hbs | 41 +++++++++++++++++++ .../api/orpc/web/astro/src/lib/orpc.ts.hbs | 12 +++++- .../orpc/web/astro/src/shared/query.ts.hbs | 9 ++++ .../frontend/astro/astro.config.mjs.hbs | 14 +++++-- .../templates/frontend/astro/package.json.hbs | 16 ++++---- .../frontend/astro/src/pages/index.astro.hbs | 26 +----------- 6 files changed, 82 insertions(+), 36 deletions(-) create mode 100644 apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs create mode 100644 apps/cli/templates/api/orpc/web/astro/src/shared/query.ts.hbs diff --git a/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs b/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs new file mode 100644 index 000000000..4140efd3e --- /dev/null +++ b/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs @@ -0,0 +1,41 @@ +import { orpc } from '../lib/orpc'; +import { useQuery } from '@tanstack/react-query'; +import { QueryClientProvider } from '@tanstack/react-query'; +import { queryClient } from '../shared/query'; + +function ApiStatus() { + const healthCheck = useQuery(orpc.healthCheck.queryOptions()); + + return ( +
+

API Status

+
+
+ + {healthCheck.isLoading + ? "Checking..." + : healthCheck.data + ? "Connected" + : "Disconnected"} + +
+ {healthCheck.data && ( +
+ Response: {JSON.stringify(healthCheck.data)} +
+ )} +
+ ); +} + +export function OrpcApiStatus() { + return ( + + + + ); +} \ No newline at end of file diff --git a/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs index b3db25cf5..a4d39db4a 100644 --- a/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs +++ b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs @@ -1,4 +1,5 @@ import { createORPCClient } from "@orpc/client"; +import { BatchLinkPlugin } from "@orpc/client/plugins"; import { RPCLink } from "@orpc/client/fetch"; import { createTanstackQueryUtils } from "@orpc/tanstack-query"; import { QueryCache, QueryClient } from "@tanstack/react-query"; @@ -14,13 +15,22 @@ export const queryClient = new QueryClient({ export const link = new RPCLink({ url: `${import.meta.env.PUBLIC_SERVER_URL}/rpc`, + plugins: [ + // for request batching optimization + new BatchLinkPlugin({ + groups: [{ + condition: () => true, + context: {}, + }], + }), + ], {{#if (eq auth "better-auth")}} fetch(url, options) { return fetch(url, { ...options, credentials: "include", }); - }, + } {{/if}} }); diff --git a/apps/cli/templates/api/orpc/web/astro/src/shared/query.ts.hbs b/apps/cli/templates/api/orpc/web/astro/src/shared/query.ts.hbs new file mode 100644 index 000000000..80916465b --- /dev/null +++ b/apps/cli/templates/api/orpc/web/astro/src/shared/query.ts.hbs @@ -0,0 +1,9 @@ +import { QueryClient, QueryCache } from '@tanstack/react-query'; + +export const queryClient = new QueryClient({ + queryCache: new QueryCache({ + onError: (error) => { + console.error(`Error: ${error.message}`); + }, + }), +}); \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/astro.config.mjs.hbs b/apps/cli/templates/frontend/astro/astro.config.mjs.hbs index 543a436d2..fd30411b9 100644 --- a/apps/cli/templates/frontend/astro/astro.config.mjs.hbs +++ b/apps/cli/templates/frontend/astro/astro.config.mjs.hbs @@ -1,9 +1,15 @@ import { defineConfig } from 'astro/config'; import tailwindcss from '@tailwindcss/vite'; +{{#if (eq api "orpc")}} +import react from '@astrojs/react'; +{{/if}} export default defineConfig({ - vite: { - plugins: [tailwindcss()] - }, - // output: 'static' + vite: { + plugins: [tailwindcss()] + }, + {{#if (eq api "orpc")}} + integrations: [react()], + {{/if}} + output: 'static' }); \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/package.json.hbs b/apps/cli/templates/frontend/astro/package.json.hbs index 48a78b664..58b2c30be 100644 --- a/apps/cli/templates/frontend/astro/package.json.hbs +++ b/apps/cli/templates/frontend/astro/package.json.hbs @@ -20,15 +20,17 @@ "tailwindcss": "^4.1.15", "typescript": "^5.9.2", "zod": "^4.1.5"{{#if (eq api "orpc")}}, + "@astrojs/react": "^4.1.3", + "@types/react": "^19.0.18", + "@types/react-dom": "^19.0.18", + "react": "^19.1.0", + "react-dom": "^19.1.0", "@orpc/tanstack-query": "^1.9.0", "@orpc/client": "^1.9.0", "@tanstack/react-query": "^5.85.5"{{/if}} - }{{#if (eq api "orpc")}}, - "devDependencies": { - "@astrojs/check": "^0.13.0", - "@tanstack/react-query-devtools": "^5.85.5" - }{{else}}, + }, "devDependencies": { - "@astrojs/check": "^0.13.0" - }{{/if}} + "@astrojs/check": "^0.13.0"{{#if (eq api "orpc")}}, + "@tanstack/react-query-devtools": "^5.85.5"{{/if}} + } } \ No newline at end of file diff --git a/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs b/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs index ab28b8422..1854353dc 100644 --- a/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs +++ b/apps/cli/templates/frontend/astro/src/pages/index.astro.hbs @@ -3,16 +3,7 @@ // TODO: Add Convex integration for Astro {{else}} {{#if (eq api "orpc")}} -import { client } from '../lib/orpc'; - -// Server-side API call -let healthCheckData; -try { - healthCheckData = await client.healthCheck.query(); -} catch (error) { - console.error('Health check failed:', error); - healthCheckData = null; -} +import { OrpcApiStatus } from '../components/orpc-status'; {{/if}} {{/if}} @@ -40,20 +31,7 @@ const TITLE_TEXT = `
{TITLE_TEXT}
{{#if (eq api "orpc")}} -
-

API Status

-
-
- - {healthCheckData ? "Connected" : "Disconnected"} - -
- {healthCheckData && ( -
- Response: {healthCheckData} -
- )} -
+ {{/if}}
From a164fc8e7da11ca42a40f5bb02f57128b382c183 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 14:28:58 +0000 Subject: [PATCH 07/16] fix(cli): missing Astro in hasWeb() --- apps/cli/src/helpers/core/post-installation.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/cli/src/helpers/core/post-installation.ts b/apps/cli/src/helpers/core/post-installation.ts index 5c6742e26..e11b0def5 100644 --- a/apps/cli/src/helpers/core/post-installation.ts +++ b/apps/cli/src/helpers/core/post-installation.ts @@ -94,6 +94,7 @@ export async function displayPostInstallInstructions( "next", "tanstack-start", "nuxt", + "astro", "svelte", "solid", ].includes(f), From 3ef35b494802f42411b6a809d016e996a41ed0c0 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 14:29:15 +0000 Subject: [PATCH 08/16] test: handle Astro in framework array check --- apps/cli/test/frontend.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/cli/test/frontend.test.ts b/apps/cli/test/frontend.test.ts index d3a352859..11867873e 100644 --- a/apps/cli/test/frontend.test.ts +++ b/apps/cli/test/frontend.test.ts @@ -18,6 +18,7 @@ describe("Frontend Configurations", () => { "native-unistyles", "svelte", "solid", + "astro" ] satisfies ReadonlyArray< | "tanstack-router" | "react-router" @@ -28,6 +29,7 @@ describe("Frontend Configurations", () => { | "native-unistyles" | "svelte" | "solid" + | "astro" >; for (const frontend of singleFrontends) { From 33a756c45ddd70a55821cfbdd247cb1e5edfbb26 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 14:29:27 +0000 Subject: [PATCH 09/16] fix: handle Astro in multiple checks --- apps/cli/src/helpers/core/auth-setup.ts | 1 + apps/cli/src/helpers/core/env-setup.ts | 2 ++ apps/cli/src/helpers/core/payments-setup.ts | 1 + apps/cli/src/utils/compatibility-rules.ts | 2 +- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/cli/src/helpers/core/auth-setup.ts b/apps/cli/src/helpers/core/auth-setup.ts index f6246ce20..f973e9af0 100644 --- a/apps/cli/src/helpers/core/auth-setup.ts +++ b/apps/cli/src/helpers/core/auth-setup.ts @@ -116,6 +116,7 @@ export async function setupAuth(config: ProjectConfig) { "tanstack-start", "next", "nuxt", + "astro", "svelte", "solid", ].includes(f), diff --git a/apps/cli/src/helpers/core/env-setup.ts b/apps/cli/src/helpers/core/env-setup.ts index 02febdc19..0a8d61709 100644 --- a/apps/cli/src/helpers/core/env-setup.ts +++ b/apps/cli/src/helpers/core/env-setup.ts @@ -106,6 +106,7 @@ export async function setupEnvironmentVariables(config: ProjectConfig) { const hasTanStackStart = frontend.includes("tanstack-start"); const hasNextJs = frontend.includes("next"); const hasNuxt = frontend.includes("nuxt"); + const hasAstro = frontend.includes("astro"); const hasSvelte = frontend.includes("svelte"); const hasSolid = frontend.includes("solid"); const hasWebFrontend = @@ -114,6 +115,7 @@ export async function setupEnvironmentVariables(config: ProjectConfig) { hasTanStackStart || hasNextJs || hasNuxt || + hasAstro || hasSolid || hasSvelte; diff --git a/apps/cli/src/helpers/core/payments-setup.ts b/apps/cli/src/helpers/core/payments-setup.ts index 5557b826d..438e0d0a2 100644 --- a/apps/cli/src/helpers/core/payments-setup.ts +++ b/apps/cli/src/helpers/core/payments-setup.ts @@ -34,6 +34,7 @@ export async function setupPayments(config: ProjectConfig) { "tanstack-start", "next", "nuxt", + "astro", "svelte", "solid", ].includes(f), diff --git a/apps/cli/src/utils/compatibility-rules.ts b/apps/cli/src/utils/compatibility-rules.ts index 473f02c2a..9d13ecae4 100644 --- a/apps/cli/src/utils/compatibility-rules.ts +++ b/apps/cli/src/utils/compatibility-rules.ts @@ -33,7 +33,7 @@ export function ensureSingleWebAndNative(frontends: Frontend[]) { const { web, native } = splitFrontends(frontends); if (web.length > 1) { exitWithError( - "Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte, solid", + "Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, astro, svelte, solid", ); } if (native.length > 1) { From 8770375aba24c5ed9922e46745d313eb19eab561 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 16:44:32 +0200 Subject: [PATCH 10/16] fix: get rid of shared query in astro --- .../templates/api/orpc/web/astro/src/shared/query.ts.hbs | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 apps/cli/templates/api/orpc/web/astro/src/shared/query.ts.hbs diff --git a/apps/cli/templates/api/orpc/web/astro/src/shared/query.ts.hbs b/apps/cli/templates/api/orpc/web/astro/src/shared/query.ts.hbs deleted file mode 100644 index 80916465b..000000000 --- a/apps/cli/templates/api/orpc/web/astro/src/shared/query.ts.hbs +++ /dev/null @@ -1,9 +0,0 @@ -import { QueryClient, QueryCache } from '@tanstack/react-query'; - -export const queryClient = new QueryClient({ - queryCache: new QueryCache({ - onError: (error) => { - console.error(`Error: ${error.message}`); - }, - }), -}); \ No newline at end of file From e7a0d18bd296e3d3a7e7ce20adedddda99fddbd3 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 16:47:14 +0200 Subject: [PATCH 11/16] fix: proper packages versions --- apps/cli/templates/frontend/astro/package.json.hbs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/cli/templates/frontend/astro/package.json.hbs b/apps/cli/templates/frontend/astro/package.json.hbs index 58b2c30be..2655cff5e 100644 --- a/apps/cli/templates/frontend/astro/package.json.hbs +++ b/apps/cli/templates/frontend/astro/package.json.hbs @@ -16,8 +16,8 @@ }, "dependencies": { "astro": "^5.2.4", - "@tailwindcss/vite": "^4.1.15", - "tailwindcss": "^4.1.15", + "@tailwindcss/vite": "^4.1.13", + "tailwindcss": "^4.1.13", "typescript": "^5.9.2", "zod": "^4.1.5"{{#if (eq api "orpc")}}, "@astrojs/react": "^4.1.3", @@ -30,7 +30,7 @@ "@tanstack/react-query": "^5.85.5"{{/if}} }, "devDependencies": { - "@astrojs/check": "^0.13.0"{{#if (eq api "orpc")}}, + {{#if (eq api "orpc")}} "@tanstack/react-query-devtools": "^5.85.5"{{/if}} } } \ No newline at end of file From a2b4d03a1bea66250046babe8d1e37f55d982caf Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Sun, 28 Sep 2025 16:52:02 +0200 Subject: [PATCH 12/16] fix: proper React tsconfig --- .../templates/frontend/astro/package.json.hbs | 1 + .../frontend/astro/tsconfig.json.hbs | 33 ++++++++----------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/apps/cli/templates/frontend/astro/package.json.hbs b/apps/cli/templates/frontend/astro/package.json.hbs index 2655cff5e..a4c15effb 100644 --- a/apps/cli/templates/frontend/astro/package.json.hbs +++ b/apps/cli/templates/frontend/astro/package.json.hbs @@ -30,6 +30,7 @@ "@tanstack/react-query": "^5.85.5"{{/if}} }, "devDependencies": { + "@astrojs/check": "^0.9.4", {{#if (eq api "orpc")}} "@tanstack/react-query-devtools": "^5.85.5"{{/if}} } diff --git a/apps/cli/templates/frontend/astro/tsconfig.json.hbs b/apps/cli/templates/frontend/astro/tsconfig.json.hbs index f5ca15b25..ed0b6641b 100644 --- a/apps/cli/templates/frontend/astro/tsconfig.json.hbs +++ b/apps/cli/templates/frontend/astro/tsconfig.json.hbs @@ -2,24 +2,17 @@ "extends": "astro/tsconfigs/strict", "include": [".astro/types.d.ts", "**/*"], "exclude": ["dist"], - "paths": { - "@components/*": [ - "src/components/*" - ], - "@layouts/*": [ - "src/layouts/*" - ], - "@utils/*": [ - "src/utils/*" - ], - "@styles/*": [ - "src/styles/*" - ], - "@/*": [ - "src/*" - ], - "@assets/*": [ - "src/assets/*" - ] - }, + "comilerOptions":{ + {{#if (eq api "orpc")}} + "jsx": "react-jsx", + "jsxImportSource": "react", + {{/if}} + "paths": { + "@components/*": ["./src/components/*"], + "@layouts/*": ["./src/layouts/*"], + "@utils/*": ["./src/utils/*"], + "@styles/*": ["./src/styles/*"], + "@assets/*": ["./src/assets/*"] + } + } } \ No newline at end of file From 06232a77724f6794b31388274f8504eee5f9c1b6 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Mon, 29 Sep 2025 10:01:50 +0200 Subject: [PATCH 13/16] chore: skip better-auth --- apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs index a4d39db4a..3860aaec0 100644 --- a/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs +++ b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs @@ -24,14 +24,6 @@ export const link = new RPCLink({ }], }), ], - {{#if (eq auth "better-auth")}} - fetch(url, options) { - return fetch(url, { - ...options, - credentials: "include", - }); - } - {{/if}} }); export const client: AppRouterClient = createORPCClient(link); From 3ac485176ef345f40fce268aec1619a1abc4c2a8 Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Mon, 29 Sep 2025 10:19:55 +0200 Subject: [PATCH 14/16] fix: proper CORS_ORIGIN for astro --- apps/cli/src/helpers/core/env-setup.ts | 4 ++++ .../orpc/web/astro/src/components/orpc-status.tsx.hbs | 3 +-- .../templates/api/orpc/web/astro/src/lib/orpc.ts.hbs | 10 +++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/cli/src/helpers/core/env-setup.ts b/apps/cli/src/helpers/core/env-setup.ts index 0a8d61709..1d79af848 100644 --- a/apps/cli/src/helpers/core/env-setup.ts +++ b/apps/cli/src/helpers/core/env-setup.ts @@ -283,12 +283,16 @@ export async function setupEnvironmentVariables(config: ProjectConfig) { if (!(await fs.pathExists(serverDir))) { return; } + const envPath = path.join(serverDir, ".env"); let corsOrigin = "http://localhost:3001"; if (hasReactRouter || hasSvelte) { corsOrigin = "http://localhost:5173"; } + if (hasAstro) { + corsOrigin = "http://localhost:4321"; + } let databaseUrl: string | null = null; diff --git a/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs b/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs index 4140efd3e..a419292d3 100644 --- a/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs +++ b/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs @@ -1,7 +1,6 @@ -import { orpc } from '../lib/orpc'; +import { orpc, queryClient } from '../lib/orpc'; import { useQuery } from '@tanstack/react-query'; import { QueryClientProvider } from '@tanstack/react-query'; -import { queryClient } from '../shared/query'; function ApiStatus() { const healthCheck = useQuery(orpc.healthCheck.queryOptions()); diff --git a/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs index 3860aaec0..a0823bf39 100644 --- a/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs +++ b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs @@ -1,4 +1,4 @@ -import { createORPCClient } from "@orpc/client"; +import { createORPCClient, onError } from "@orpc/client"; import { BatchLinkPlugin } from "@orpc/client/plugins"; import { RPCLink } from "@orpc/client/fetch"; import { createTanstackQueryUtils } from "@orpc/tanstack-query"; @@ -14,9 +14,8 @@ export const queryClient = new QueryClient({ }); export const link = new RPCLink({ - url: `${import.meta.env.PUBLIC_SERVER_URL}/rpc`, + url: `${import.meta.env.VITE_SERVER_URL}/rpc`, plugins: [ - // for request batching optimization new BatchLinkPlugin({ groups: [{ condition: () => true, @@ -24,6 +23,11 @@ export const link = new RPCLink({ }], }), ], + interceptors: [ + onError((error) => { + console.error(error) + }) + ], }); export const client: AppRouterClient = createORPCClient(link); From a539ee08d50ac781f89dc4f59f0da03a654d5d6e Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Mon, 29 Sep 2025 10:36:05 +0200 Subject: [PATCH 15/16] chore: monorepo TS setup https://orpc.unnoq.com/docs/best-practices/monorepo-setup#typescript-project-references --- apps/cli/templates/frontend/astro/tsconfig.json.hbs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/cli/templates/frontend/astro/tsconfig.json.hbs b/apps/cli/templates/frontend/astro/tsconfig.json.hbs index ed0b6641b..c811c1b27 100644 --- a/apps/cli/templates/frontend/astro/tsconfig.json.hbs +++ b/apps/cli/templates/frontend/astro/tsconfig.json.hbs @@ -2,6 +2,10 @@ "extends": "astro/tsconfigs/strict", "include": [".astro/types.d.ts", "**/*"], "exclude": ["dist"], + {{#if (eq api "orpc")}} + "references": [ + { "path": "../server" } + ],{{/if}} "comilerOptions":{ {{#if (eq api "orpc")}} "jsx": "react-jsx", From 8ebf95fcb9ab51e82992f6756a610993b44f408a Mon Sep 17 00:00:00 2001 From: Jakub Zomerfeld Date: Tue, 30 Sep 2025 17:47:22 +0200 Subject: [PATCH 16/16] fix: typos in syntax --- .../api/orpc/web/astro/src/components/orpc-status.tsx.hbs | 3 +-- apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs | 2 +- apps/cli/templates/frontend/astro/public/robots.txt | 2 +- apps/cli/templates/frontend/astro/src/layouts/Layout.astro.hbs | 2 +- apps/cli/templates/frontend/astro/tsconfig.json.hbs | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs b/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs index a419292d3..13a7e83a1 100644 --- a/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs +++ b/apps/cli/templates/api/orpc/web/astro/src/components/orpc-status.tsx.hbs @@ -1,6 +1,5 @@ import { orpc, queryClient } from '../lib/orpc'; -import { useQuery } from '@tanstack/react-query'; -import { QueryClientProvider } from '@tanstack/react-query'; +import { useQuery, QueryClientProvider } from '@tanstack/react-query'; function ApiStatus() { const healthCheck = useQuery(orpc.healthCheck.queryOptions()); diff --git a/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs index a0823bf39..8adc4d352 100644 --- a/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs +++ b/apps/cli/templates/api/orpc/web/astro/src/lib/orpc.ts.hbs @@ -25,7 +25,7 @@ export const link = new RPCLink({ ], interceptors: [ onError((error) => { - console.error(error) + console.error(`RPC Error: ${error.message}`, error) }) ], }); diff --git a/apps/cli/templates/frontend/astro/public/robots.txt b/apps/cli/templates/frontend/astro/public/robots.txt index 4c954eb9d..ca2c7ce06 100644 --- a/apps/cli/templates/frontend/astro/public/robots.txt +++ b/apps/cli/templates/frontend/astro/public/robots.txt @@ -2,4 +2,4 @@ # Full syntax: https://developers.google.com/search/docs/advanced/robots/create-robots-txt User-agent: * -Allow: / \ No newline at end of file +Allow: / diff --git a/apps/cli/templates/frontend/astro/src/layouts/Layout.astro.hbs b/apps/cli/templates/frontend/astro/src/layouts/Layout.astro.hbs index 78f53c903..ff6a1231e 100644 --- a/apps/cli/templates/frontend/astro/src/layouts/Layout.astro.hbs +++ b/apps/cli/templates/frontend/astro/src/layouts/Layout.astro.hbs @@ -15,7 +15,7 @@ const { title, description = "Built with Better-T-Stack"} = Astro.props; - + {title} diff --git a/apps/cli/templates/frontend/astro/tsconfig.json.hbs b/apps/cli/templates/frontend/astro/tsconfig.json.hbs index c811c1b27..a6ced2335 100644 --- a/apps/cli/templates/frontend/astro/tsconfig.json.hbs +++ b/apps/cli/templates/frontend/astro/tsconfig.json.hbs @@ -6,7 +6,7 @@ "references": [ { "path": "../server" } ],{{/if}} - "comilerOptions":{ + "compilerOptions":{ {{#if (eq api "orpc")}} "jsx": "react-jsx", "jsxImportSource": "react",