Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/.copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
## Architecture & Priorities

- This is a PoC: prioritize developer speed and clarity over abstraction.
- Treat all backends as APIs; do not couple services together.
- The AI service is stateless and must not call application APIs directly.

## Monorepo Structure

- This is a TurboRepo monorepo with pnpm workspaces
- Apps live in `apps/` (currently only tanstack-start)
- Shared packages live in `packages/`
- External services live in `services/`
- Use `turbo.json` for task definitions and caching

## Environment & Configuration

- Use Zod for environment validation in TypeScript packages
- Follow the pattern in `packages/auth/env.ts` for type-safe env vars
- Never commit sensitive values; use `example.env` as a template
- Prefix AI service env vars with `AI_` to avoid conflicts

## Authentication

- Use [WorkOS](https://workos.com/docs/llms.txt) for authentication and organization context.
- Do not invent custom auth flows.
- User identity and org context must be passed explicitly to services.

## Frontend & UI

- All reusable UI components must live in the `packages/ui` package.
- Use Tailwind CSS for styling.
- Prefer shadcn/ui components where applicable.
- Do not create ad-hoc UI components in app folders.

## Forms & State

- Use `@tanstack/react-form` for all forms.
- Use `@tanstack/react-query` for data fetching, caching, and mutations.
- Use `@tanstack/react-router` for routing.

## APIs & Data Fetching

- Use tRPC for type-safe application API calls (user data, metrics, app state).
- Use OpenAPI Generator to generate a typed client for the FastAPI AI service.
- Do not mix tRPC and OpenAPI clients.
- Do not have the AI service call the application API.

## Database & Validation

- Use Drizzle ORM for database access.
- Use Zod for validation.
- Use `drizzle-zod` for deriving Zod schemas from Drizzle models.
- Do not duplicate schema definitions manually.
- Place non-database Zod schemas in the `packages/validators` package.

## AI Service Integration

- The AI service receives all required inputs (user context, metrics, documents).
- The AI service must not fetch user or metrics data on its own.
- Inputs should be explicit, minimal, and versionable.
- AI service shouldn't have a seperate auth flow it should instead use the AI_SERVICE_KEY env var to authenticate requests from the main app which will have that variable sent using a secure header.
21 changes: 21 additions & 0 deletions .github/DISCUSSION_TEMPLATE/ideas.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to file a feature request. Please fill out this form as completely as possible.
- type: textarea
attributes:
label: Describe the feature you'd like to request
description: Please describe the feature as clear and concise as possible. Remember to add context as to why you believe this feature is needed.
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like to see
description: Please describe the solution you would like to see. Adding example usage is a good way to provide context.
validations:
required: true
- type: textarea
attributes:
label: Additional information
description: Add any other information related to the feature here. If your feature request is related to any issues or discussions, link them here.
37 changes: 37 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: 🐞 Bug Report
description: Create a bug report to help us improve
title: "bug: "
labels: ["🐞❔ unconfirmed bug"]
body:
- type: textarea
attributes:
label: Provide environment information
description: |
Run this command in your project root and paste the results in a code block:
```bash
npx envinfo --system --binaries
```
validations:
required: true
- type: textarea
attributes:
label: Describe the bug
description: A clear and concise description of the bug, as well as what you expected to happen when encountering it.
validations:
required: true
- type: input
attributes:
label: Link to reproduction
description: Please provide a link to a reproduction of the bug. Issues without a reproduction repo may be ignored.
validations:
required: true
- type: textarea
attributes:
label: To reproduce
description: Describe how to reproduce your bug. Steps, code snippets, reproduction repos etc.
validations:
required: true
- type: textarea
attributes:
label: Additional information
description: Add any other information related to the bug here, screenshots if applicable.
16 changes: 16 additions & 0 deletions .github/renovate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:base"],
"packageRules": [
{
"matchPackagePatterns": ["^@governance/"],
"enabled": false
}
],
"updateInternalDeps": true,
"rangeStrategy": "bump",
"automerge": true,
"npm": {
"fileMatch": ["(^|/)package\\.json$", "(^|/)package\\.json\\.hbs$"]
}
Comment on lines +1 to +15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Renovate automerge top level configuration applies all updates best practices

💡 Result:

Does top-level automerge apply to all updates?

Yes. Setting "automerge": true at the top level makes every Renovate PR eligible for automerge by default (including majors), unless you override it with more specific config like packageRules. Renovate’s own docs caution that you “usually won’t want to automerge all PRs” and recommend using packageRules to scope automerge to safer update types (e.g. minor/patch/digest). [1]

Best-practice approach (recommended)

  1. Don’t enable global automerge. Keep top-level "automerge": false (or omit it), and enable automerge only for low-risk updates via packageRules. [1]
  2. Start from config:best-practices. Renovate maintainers recommend extending it for upgrade strategy defaults. [2]
  3. Automerge only what you’d merge anyway. Maintainers recommend enabling automerge for updates you wouldn’t review manually, and keeping it off where you want to read changelogs/review (commonly majors). [3]
  4. Prefer stable non-major automerge. Renovate provides a preset pattern that automerges minor/patch only when the current version is semver-stable (not 0.x) to reduce accidental breaking changes. [4]
  5. Require real CI status checks if using platform automerge. Renovate warns that with GitHub branch protection + platform automerge, you should require at least one status check, otherwise GitHub may automerge even with failing tests. [1]

Example config (safe “automerge for most low-risk updates”)

{
  "extends": ["config:best-practices"],

  "automerge": false,
  "automergeType": "pr",

  "packageRules": [
    {
      "description": "Automerge non-major only for semver-stable deps",
      "matchCurrentVersion": "!/^0/",
      "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
      "automerge": true
    },
    {
      "description": "Never automerge majors",
      "matchUpdateTypes": ["major"],
      "automerge": false
    }
  ]
}

If you tell me your platform (GitHub/GitLab/Azure) and whether you want automerge for prod dependencies or only devDependencies, I can tailor the rules more tightly.


🌐 Web query:

Renovate packageRules automerge scope specific packages internal dependencies

💡 Result:

To automerge only your internal dependencies (e.g., npm packages in your org scope like @myco/*, or packages whose sourceUrl points to your GitHub org), use packageRules with matchers such as matchPackageNames (supports glob/regex) and/or matchSourceUrls, then enable automerge (optionally limited to safe update types). (docs.renovatebot.com)

Example: automerge internal scoped npm packages (recommended)

{
  "packageRules": [
    {
      "description": "Automerge internal `@myco/`* deps (non-major only)",
      "matchDatasources": ["npm"],
      "matchPackageNames": ["@myco/**"],
      "matchUpdateTypes": ["patch", "minor", "pin", "digest"],
      "automerge": true,
      "automergeType": "pr"
    }
  ]
}
  • matchPackageNames supports exact names, glob (e.g. @myco/**), and regex patterns. (docs.renovatebot.com)
  • automerge can be combined with matchUpdateTypes to avoid major updates. (docs.renovatebot.com)
  • matchDatasources is a common way to scope rules to npm (or other ecosystems). (docs.renovatebot.com)

Example: automerge “internal” by repo/source URL (works across names)

If your internal packages all originate from (say) GitHub org repos, match on sourceUrl:

{
  "packageRules": [
    {
      "description": "Automerge deps whose source is our GitHub org",
      "matchSourceUrls": ["https://github.com/myco/**"],
      "matchUpdateTypes": ["patch", "minor", "pin", "digest"],
      "automerge": true,
      "automergeType": "pr"
    }
  ]
}

matchSourceUrls can match exact URLs or patterns. (docs.renovatebot.com)

Example: automerge a specific internal package (exact list)

{
  "packageRules": [
    {
      "matchPackageNames": ["@myco/shared-config", "@myco/eslint-config"],
      "automerge": true
    }
  ]
}

matchPackageNames supports exact matching too. (docs.renovatebot.com)

If you tell me your ecosystem (npm/maven/docker/etc.) and what you mean by “internal” (scope, registry host, GitHub org, monorepo workspace), I can tailor the tightest/least-risk rule set.

Citations:


Scope automerge to specific update types instead of globally enabling it.

Global automerge: true applies to all updates by default, including major version bumps and all third-party dependencies. Renovate's documentation recommends disabling global automerge and enabling it selectively only for low-risk updates (e.g., minor, patch, digest) via packageRules.

Instead of the suggested config, disable global automerge and add a packageRules entry with matchUpdateTypes to limit automerge to safe, non-breaking updates:

♻️ Recommended configuration
 {
   "$schema": "https://docs.renovatebot.com/renovate-schema.json",
   "extends": ["config:base"],
   "packageRules": [
     {
       "matchPackagePatterns": ["^@governance/"],
       "enabled": false
     },
+    {
+      "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
+      "automerge": true
+    }
   ],
   "updateInternalDeps": true,
   "rangeStrategy": "bump",
-  "automerge": true,
+  "automerge": false,
   "npm": {
     "fileMatch": ["(^|/)package\\.json$", "(^|/)package\\.json\\.hbs$"]
   }
 }

This prevents accidental automerge of major versions while still automating safe, low-risk updates.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:base"],
"packageRules": [
{
"matchPackagePatterns": ["^@governance/"],
"enabled": false
}
],
"updateInternalDeps": true,
"rangeStrategy": "bump",
"automerge": true,
"npm": {
"fileMatch": ["(^|/)package\\.json$", "(^|/)package\\.json\\.hbs$"]
}
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:base"],
"packageRules": [
{
"matchPackagePatterns": ["^@governance/"],
"enabled": false
},
{
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
"automerge": true
}
],
"updateInternalDeps": true,
"rangeStrategy": "bump",
"automerge": false,
"npm": {
"fileMatch": ["(^|/)package\\.json$", "(^|/)package\\.json\\.hbs$"]
}
}
🤖 Prompt for AI Agents
In @.github/renovate.json around lines 1 - 15, The current Renovate config
enables automerge globally via "automerge": true which can auto-apply high-risk
updates; change this by removing or setting "automerge" to false and add a
packageRules entry that targets safe update types using "matchUpdateTypes"
(e.g., ["minor","patch","digest"]) and sets "automerge": true for those rules;
update the existing "packageRules" array (where "matchPackagePatterns":
["^@governance/"] is defined) to include the new rule(s) scoped to safe update
types so only low-risk updates are auto-merged.

}
57 changes: 57 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: CI

on:
pull_request:
branches: ["*"]
push:
branches: ["main"]
merge_group:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

# You can leverage Vercel Remote Caching with Turbo to speed up your builds
# @link https://turborepo.com/docs/core-concepts/remote-caching#remote-caching-on-vercel-builds
env:
FORCE_COLOR: 3
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Setup
uses: ./tooling/github/setup

- name: Copy env
shell: bash
run: cp .env.example .env

- name: Lint
run: pnpm lint && pnpm lint:ws

format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Setup
uses: ./tooling/github/setup

- name: Format
run: pnpm format

typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Setup
uses: ./tooling/github/setup

- name: Typecheck
run: pnpm typecheck
35 changes: 21 additions & 14 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
node_modules/
.pnp/
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
node_modules
.pnp
.pnp.js

# testing
coverage/
coverage

# next.js
.next/
out/
next-env.d.ts

# nitro
.nitro/
.output/


# production
build/
build

# misc
.DS_Store
Expand All @@ -30,16 +31,22 @@ yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*
# local env files
.env
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
dist/
.cache

# turbo
.turbo

# tanstack
.tanstack

# ========= python =========
# Python-generated files
Expand Down
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22.21.0
8 changes: 8 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"yoavbls.pretty-ts-errors",
"bradlc.vscode-tailwindcss"
]
}
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js",
"type": "node-terminal",
"request": "launch",
"command": "pnpm dev",
"cwd": "${workspaceFolder}/apps/nextjs",
Comment on lines +5 to +9

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check which app folders exist
echo "=== Listing apps directory ==="
ls -la apps/ 2>/dev/null || echo "No 'apps' directory found"

echo -e "\n=== Finding directories in apps ==="
fd -t d -d 2 . apps/ 2>/dev/null || echo "Could not find apps structure"

echo -e "\n=== Checking .vscode/launch.json content ==="
cat .vscode/launch.json 2>/dev/null || echo "Could not find .vscode/launch.json"

Repository: AFAskar/Governance-Agent

Length of output: 863


Update the launch configuration to target the correct app.

The config points to apps/nextjs which no longer exists; only apps/tanstack-start is present. This will cause the debugger to fail. Additionally, sourceMapPathOverrides references ${webRoot}, which is not defined in a node-terminal configuration and will not work as intended.

🔧 Suggested update
     {
-      "name": "Next.js",
+      "name": "TanStack Start",
       "type": "node-terminal",
       "request": "launch",
       "command": "pnpm dev",
-      "cwd": "${workspaceFolder}/apps/nextjs",
+      "cwd": "${workspaceFolder}/apps/tanstack-start",
       "skipFiles": ["<node_internals>/**"],
       "sourceMaps": true,
       "sourceMapPathOverrides": {
-        "/turbopack/[project]/*": "${webRoot}/*" //https://github.com/vercel/next.js/issues/62008
+        "/turbopack/[project]/*": "${workspaceFolder}/apps/tanstack-start/*" //https://github.com/vercel/next.js/issues/62008
       }
     }
🤖 Prompt for AI Agents
In @.vscode/launch.json around lines 5 - 9, Update the Next.js launch
configuration so the working directory and source mapping target the existing
app: change the "cwd" value used in the launch configuration (currently pointing
to "apps/nextjs") to "apps/tanstack-start", and remove or replace any use of
"${webRoot}" in "sourceMapPathOverrides" because "node-terminal" doesn't define
webRoot; instead point sourceMapPathOverrides to a concrete path under the new
cwd (or remove the overrides entirely) so the debugger can resolve source maps
correctly. Ensure you modify the existing configuration entries "cwd", "command"
(if necessary), and "sourceMapPathOverrides" to reference the new app name
("apps/tanstack-start") and valid paths.

"skipFiles": ["<node_internals>/**"],
"sourceMaps": true,
"sourceMapPathOverrides": {
"/turbopack/[project]/*": "${webRoot}/*" //https://github.com/vercel/next.js/issues/62008
}
}
]
}
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"eslint.workingDirectories": [
{
"mode": "auto"
}
]
}
1 change: 1 addition & 0 deletions apps/tanstack-start/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
routeTree.gen.ts
13 changes: 13 additions & 0 deletions apps/tanstack-start/eslint.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineConfig } from "eslint/config";

import { baseConfig, restrictEnvAccess } from "@governance/eslint-config/base";
import { reactConfig } from "@governance/eslint-config/react";

export default defineConfig(
{
ignores: [".nitro/**", ".output/**", ".tanstack/**"],
},
baseConfig,
reactConfig,
restrictEnvAccess,
);
57 changes: 57 additions & 0 deletions apps/tanstack-start/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "@governance/tanstack-start",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"dev": "pnpm with-env vite dev",
"build": "vite build",
"start": "vite start",
"format": "prettier --check . --ignore-path ../../.gitignore --ignore-path .prettierignore",
"lint": "eslint --flag unstable_native_nodejs_ts_config",
"typecheck": "tsc --noEmit",
"with-env": "dotenv -e ../../.env --"
},
"dependencies": {
"@fontsource-variable/geist": "^5.2.8",
"@fontsource-variable/geist-mono": "^5.2.7",
"@governance/api": "workspace:*",
"@governance/auth": "workspace:*",
"@governance/db": "workspace:*",
"@governance/ui": "workspace:*",
"@t3-oss/env-core": "^0.13.8",
"@tanstack/react-form": "catalog:",
"@tanstack/react-query": "catalog:",
"@tanstack/react-router": "^1.135.2",
"@tanstack/react-router-devtools": "^1.135.2",
"@tanstack/react-router-ssr-query": "^1.135.2",
"@tanstack/react-start": "^1.135.2",
"@trpc/client": "catalog:",
"@trpc/server": "catalog:",
"@trpc/tanstack-react-query": "catalog:",
"better-auth": "catalog:",
"nitro": "3.0.1-alpha.1",
"react": "catalog:react19",
"react-dom": "catalog:react19",
"superjson": "2.2.3",
"zod": "catalog:"
},
"devDependencies": {
"@governance/eslint-config": "workspace:*",
"@governance/prettier-config": "workspace:*",
"@governance/tailwind-config": "workspace:*",
"@governance/tsconfig": "workspace:*",
"@tailwindcss/vite": "catalog:",
"@types/node": "catalog:",
"@types/react": "catalog:react19",
"@types/react-dom": "catalog:react19",
"@vitejs/plugin-react": "catalog:",
"eslint": "catalog:",
"prettier": "catalog:",
"tailwindcss": "catalog:",
"typescript": "catalog:",
"vite": "catalog:",
"vite-tsconfig-paths": "^5.1.4"
},
"prettier": "@governance/prettier-config"
}
Binary file added apps/tanstack-start/public/favicon.ico
Binary file not shown.
3 changes: 3 additions & 0 deletions apps/tanstack-start/src/auth/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient();
Comment on lines +1 to +3

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Search for createAuthClient usage in the codebase
rg "createAuthClient" --type ts --type tsx -B 2 -A 2

Repository: AFAskar/Governance-Agent

Length of output: 95


🏁 Script executed:

# Look for better-auth related files and configurations
fd -e "auth" -type f | head -20

Repository: AFAskar/Governance-Agent

Length of output: 238


🏁 Script executed:

# Check for package.json to see better-auth version
cat package.json 2>/dev/null | grep -A 5 "better-auth" || fd "package.json" -x grep -l "better-auth" {}

Repository: AFAskar/Governance-Agent

Length of output: 131


🌐 Web query:

better-auth createAuthClient react configuration baseUrl fetch cookies TanStack Start

💡 Result:

1) Server (TanStack Start) — set baseURL + cookie plugin

// src/lib/auth.ts
import { betterAuth } from "better-auth"
import { tanstackStartCookies } from "better-auth/tanstack-start"

export const auth = betterAuth({
  baseURL: process.env.BETTER_AUTH_URL!, // strongly recommended to set explicitly
  // basePath: "/api/auth", // default
  plugins: [
    // ...other plugins
    tanstackStartCookies(), // must be last
  ],
})
  • Better Auth recommends setting baseURL explicitly (or via BETTER_AUTH_URL) for stability/security. (better-auth.com)
  • TanStack Start requires handling cookies for actions like sign-in/sign-up; tanstackStartCookies() automates that and should be last. (better-auth.com)

Mount the handler:

// src/routes/api/auth/$.ts
import { auth } from "@/lib/auth"
import { createFileRoute } from "@tanstack/react-router"

export const Route = createFileRoute("/api/auth/$")({
  server: {
    handlers: {
      GET: async ({ request }) => auth.handler(request),
      POST: async ({ request }) => auth.handler(request),
    },
  },
})

(better-auth.com)


2) Client (React) — createAuthClient({ baseURL })

// src/lib/auth-client.ts
import { createAuthClient } from "better-auth/react"

export const authClient = createAuthClient({
  baseURL: process.env.PUBLIC_BASE_URL ?? "http://localhost:3000",
  // if you mounted auth somewhere else, include the path (or use basePath)
})

Better Auth’s install docs show passing baseURL (and including the full path if you changed the default /api/auth). (better-auth.com)


3) TanStack Start SSR / server functions — forward cookies manually when calling the client

When you call authClient.* from a TanStack Start server context, forward the incoming request cookies:

import { createServerFn } from "@tanstack/react-start"
import { getRequest } from "@tanstack/react-start/server"
import { authClient } from "@/lib/auth-client"

export const getSessionOnServer = createServerFn({ method: "GET" }).handler(
  async () => {
    const req = getRequest()

    const { data } = await authClient.getSession({
      fetchOptions: {
        headers: {
          cookie: req.headers.get("cookie") ?? "",
        },
      },
    })

    return data
  },
)

(catalins.tech)

(That same write-up also notes missing baseURL can break getSession behavior in TanStack Start.) (catalins.tech)

Citations:


🏁 Script executed:

# Read the actual auth client file
cat apps/tanstack-start/src/auth/client.ts

Repository: AFAskar/Governance-Agent

Length of output: 168


🏁 Script executed:

# Search for how authClient is imported and used
rg "from.*auth/client\|import.*authClient" -B 1 -A 3

Repository: AFAskar/Governance-Agent

Length of output: 50


🏁 Script executed:

# Check for environment variable setup or configuration
rg "PUBLIC_BASE_URL|BETTER_AUTH" --type ts --type js

Repository: AFAskar/Governance-Agent

Length of output: 50


🏁 Script executed:

# Look for any other better-auth files in the project
fd "auth" apps/tanstack-start -type f | grep -E "\.(ts|tsx|js|jsx)$"

Repository: AFAskar/Governance-Agent

Length of output: 238


🏁 Script executed:

# Search for authClient usage without type flags
rg "authClient" --max-count 20

Repository: AFAskar/Governance-Agent

Length of output: 550


🏁 Script executed:

# Check environment files
fd ".env" -o "vite.config" -o "tsconfig"

Repository: AFAskar/Governance-Agent

Length of output: 209


🏁 Script executed:

# Look for better-auth server setup in tanstack-start
fd "auth" apps/tanstack-start/src -o apps/tanstack-start/src/routes

Repository: AFAskar/Governance-Agent

Length of output: 247


🏁 Script executed:

# Look for server-side auth setup in tanstack-start
fd "auth" apps/tanstack-start/src -type f

Repository: AFAskar/Governance-Agent

Length of output: 238


🏁 Script executed:

# Check the auth-showcase usage to understand the issue better
cat apps/tanstack-start/src/component/auth-showcase.tsx | head -50

Repository: AFAskar/Governance-Agent

Length of output: 1231


🏁 Script executed:

# Look for any auth config or .env files
find apps/tanstack-start -name ".env*" -o -name "auth.config*" -type f

Repository: AFAskar/Governance-Agent

Length of output: 50


🏁 Script executed:

# Check if there's a server-side auth handler in routes
find apps/tanstack-start/src/routes -name "*auth*" 2>/dev/null || find apps/tanstack-start -path "*/routes/*" -name "*.ts" 2>/dev/null | head -10

Repository: AFAskar/Governance-Agent

Length of output: 112


🏁 Script executed:

# Look for any vite config or env setup
cat apps/tanstack-start/vite.config.ts 2>/dev/null || cat apps/tanstack-start/vite.config.js 2>/dev/null || echo "No vite config found"

Repository: AFAskar/Governance-Agent

Length of output: 568


🏁 Script executed:

# Check the auth handler route
cat apps/tanstack-start/src/routes/api/auth.$.ts

Repository: AFAskar/Governance-Agent

Length of output: 366


🏁 Script executed:

# Look for better-auth server setup, likely in lib or a separate file
find apps/tanstack-start/src -name "*auth*" -type f | xargs ls -la

Repository: AFAskar/Governance-Agent

Length of output: 262


🏁 Script executed:

# Check for environment variables in package.json or any config
cat apps/tanstack-start/package.json | grep -A 10 '"dependencies"' | head -20

Repository: AFAskar/Governance-Agent

Length of output: 489


🏁 Script executed:

# Check the server-side auth setup
cat apps/tanstack-start/src/auth/server.ts 2>/dev/null || find apps/tanstack-start/src -name "server.ts" -o -name "auth.ts" | head -5

Repository: AFAskar/Governance-Agent

Length of output: 542


🏁 Script executed:

# Look for where better-auth is imported on the server side
find apps/tanstack-start/src -name "*.ts" -o -name "*.tsx" | xargs grep "betterAuth\|from.*better-auth" 2>/dev/null | head -15

Repository: AFAskar/Governance-Agent

Length of output: 260


🏁 Script executed:

# Check the getBaseUrl function that's used on the server
cat apps/tanstack-start/src/lib/url.ts 2>/dev/null || find apps/tanstack-start -name "url.ts" -o -name "url.js"

Repository: AFAskar/Governance-Agent

Length of output: 507


🏁 Script executed:

# Check the env file to understand available environment variables
cat apps/tanstack-start/src/env.ts 2>/dev/null || find apps/tanstack-start -name "env.ts" -o -name "env.js"

Repository: AFAskar/Governance-Agent

Length of output: 1079


🏁 Script executed:

# Check if getBaseUrl is exported or used elsewhere in client context
rg "getBaseUrl" apps/tanstack-start/src

Repository: AFAskar/Governance-Agent

Length of output: 431


🏁 Script executed:

# Look at the auth package setup to understand the pattern better
cat packages/auth/env.ts 2>/dev/null || find packages/auth -name "*.ts" | head -5

Repository: AFAskar/Governance-Agent

Length of output: 542


Add required baseURL configuration to createAuthClient().

The client needs to pass baseURL to initialize properly for TanStack Start. Missing this configuration breaks getSession() behavior according to better-auth documentation.

export const authClient = createAuthClient({
  baseURL: typeof window !== "undefined" 
    ? window.location.origin 
    : "http://localhost:3001",
});

Alternatively, use an environment variable (VITE_PUBLIC_BASE_URL or similar) to match the server-side setup pattern.

🤖 Prompt for AI Agents
In `@apps/tanstack-start/src/auth/client.ts` around lines 1 - 3, The auth client
is missing the required baseURL configuration which breaks getSession(); update
the createAuthClient call (authClient) to pass a baseURL option—use
window.location.origin when running in the browser and a fallback (e.g.,
"http://localhost:3001") or read from an environment variable like
VITE_PUBLIC_BASE_URL so createAuthClient({ baseURL: ... }) is initialized
correctly for both client- and server-side usage.

16 changes: 16 additions & 0 deletions apps/tanstack-start/src/auth/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { reactStartCookies } from "better-auth/react-start";

import { initAuth } from "@governance/auth";

import { env } from "~/env";
import { getBaseUrl } from "~/lib/url";

export const auth = initAuth({
baseUrl: getBaseUrl(),
productionUrl: `https://${env.VERCEL_PROJECT_PRODUCTION_URL ?? "turbo.t3.gg"}`,
secret: env.AUTH_SECRET,
discordClientId: env.AUTH_DISCORD_ID,
discordClientSecret: env.AUTH_DISCORD_SECRET,

Comment on lines +8 to +14

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Align initAuth options with its signature (CI TS2353).

initAuth doesn’t accept discordClientId/discordClientSecret, so this object literal fails type-checking. Either remove these props here or extend initAuth’s options to accept and use them.

🛠️ Suggested fix (remove unsupported props)
 export const auth = initAuth({
   baseUrl: getBaseUrl(),
   productionUrl: `https://${env.VERCEL_PROJECT_PRODUCTION_URL ?? "turbo.t3.gg"}`,
   secret: env.AUTH_SECRET,
-  discordClientId: env.AUTH_DISCORD_ID,
-  discordClientSecret: env.AUTH_DISCORD_SECRET,
 
   extraPlugins: [reactStartCookies()],
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const auth = initAuth({
baseUrl: getBaseUrl(),
productionUrl: `https://${env.VERCEL_PROJECT_PRODUCTION_URL ?? "turbo.t3.gg"}`,
secret: env.AUTH_SECRET,
discordClientId: env.AUTH_DISCORD_ID,
discordClientSecret: env.AUTH_DISCORD_SECRET,
export const auth = initAuth({
baseUrl: getBaseUrl(),
productionUrl: `https://${env.VERCEL_PROJECT_PRODUCTION_URL ?? "turbo.t3.gg"}`,
secret: env.AUTH_SECRET,
extraPlugins: [reactStartCookies()],
});
🧰 Tools
🪛 GitHub Actions: CI

[error] 12-12: TypeScript error TS2353: Object literal may only specify known properties, and 'discordClientId' does not exist in type '{ baseUrl: string; productionUrl: string; secret: string | undefined; extraPlugins?: { id: "react-start-cookies"; hooks: { after: { matcher(ctx: EndpointContext<string, any> & Omit<...> & { ...; }): true; handler: (inputContext: MiddlewareInputContext<...>) => Promise<...>; }[]; }; }[] | undefined; }'. (during 'tsc --noEmit' for @governance/tanstack-start typecheck)

🤖 Prompt for AI Agents
In `@apps/tanstack-start/src/auth/server.ts` around lines 8 - 14, The object
passed to initAuth (assigned to auth) includes unsupported properties
discordClientId and discordClientSecret which causes TS2353; remove these two
properties from the initAuth options object (where auth is initialized and
getBaseUrl/secret/productionUrl are set) or alternatively extend the initAuth
options/type to accept and use discordClientId/discordClientSecret in the
initAuth implementation and types so they compile—prefer removing the two
env.AUTH_DISCORD_* entries from the initAuth call unless you intentionally add
OAuth wiring inside initAuth.

extraPlugins: [reactStartCookies()],
});
Loading
Loading