Migrate from better auth to workos for SSO integration - #7
Conversation
📝 WalkthroughWalkthroughThis PR migrates the authentication system from Better Auth to WorkOS AuthKit, updates database connectivity from Vercel Postgres to postgres-js, and refactors environment variables accordingly. The TanStack Start application is updated with new authentication flows, route structures, and middleware integration. Supporting infrastructure includes project governance documentation and OpenAPI tooling updates. Changes
Sequence DiagramsequenceDiagram
participant Client as TanStack Start Client
participant Router as TanStack Router
participant AuthKit as AuthKit Provider
participant Middleware as Request Middleware
participant Server as API Server
participant WorkOS as WorkOS Service
Client->>Router: Navigate / trigger auth action
Router->>AuthKit: getSignInUrl() request
AuthKit->>Server: Server function call
Server->>WorkOS: Request sign-in URL
WorkOS-->>Server: Return OAuth URL
Server-->>AuthKit: Return URL
AuthKit-->>Client: Redirect to WorkOS login
Client->>WorkOS: User authenticates
WorkOS-->>Client: Redirect to /api/auth/callback
Client->>Router: Navigate to /api/auth/callback
Router->>Middleware: authkitMiddleware processes request
Middleware->>Server: handleCallbackRoute()
Server->>WorkOS: Verify & exchange callback
WorkOS-->>Server: Return session/user info
Server->>Middleware: Set secure auth cookie
Middleware-->>Client: Redirect to home
Client->>Server: Subsequent API request
Middleware->>Server: getAuth() retrieves session from cookie
Server-->>Client: Return authenticated response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Important Action Needed: IP Allowlist UpdateIf your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:
Reviews will stop working after February 8, 2026 if the new IP is not added to your allowlist. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tooling/tailwind/theme.css (1)
1-161:⚠️ Potential issue | 🟡 MinorAddress Prettier formatting issues flagged by CI.
The pipeline indicates code style issues found that should be fixed by running Prettier with
--write.Run
pnpm format --writeor the equivalent command to fix formatting before merging.The Biome error about Tailwind-specific syntax is a false positive—
@theme inlineand@variant darkare valid Tailwind CSS v4 directives.
🤖 Fix all issues with AI agents
In @.agent/rules/project-rules.md:
- Line 67: Fix the typo in the rule sentence: replace the misspelled word
"seperate" with "separate" in the line that currently reads 'AI service
shouldn't have a seperate auth flow...' so it becomes 'AI service shouldn't have
a separate auth flow...'; update the .agent/rules/project-rules.md entry
containing that sentence.
In @.github/.copilot-instructions.md:
- Line 6: Update the bullet text "always use pnpm and pnpx for package
management" to correct grammar/capitalization by capitalizing the first word and
ending with a period: replace it with "Always use pnpm and pnpx for package
management." Apply the same capitalization and punctuation fix to the duplicate
occurrence mentioned (line 31).
In `@apps/tanstack-start/src/component/auth-showcase.tsx`:
- Around line 1-41: The component AuthShowcase must await and catch errors from
getSignInUrlFn() and signOut(): wrap the getSignInUrlFn() call inside an async
try/catch in the Sign in button onClick, and handle failures by logging and
showing a user-visible error (e.g., set an error state or display alert/toast);
likewise change the signOut() invocation to an async function that awaits
signOut() inside try/catch and surfaces errors to the user. Update the handlers
in AuthShowcase to use await, try/catch, and a simple UI feedback mechanism
(error state or toast) so both getSignInUrlFn and signOut errors are handled and
reported.
In `@apps/tanstack-start/src/component/NotFound.tsx`:
- Around line 1-6: The NotFound component currently calls console.log("NotFound
triggered for path:", location.pathname) on every render; remove that call or
gate it to only run in development (e.g., wrap it with a check like NODE_ENV ===
'development' or an isDev flag) so location.pathname is not logged in
production; update the NotFound function (which uses useLocation and the
location variable) to either delete the console.log line or conditionally
execute it only when in dev.
In `@package.json`:
- Line 25: The npm script "ai-service:generate" currently calls the
`@hey-api/openapi-ts` CLI without an output path, causing the command to fail;
update the "ai-service:generate" script to add the -o (or --output) flag
followed by the intended output directory (for example "src/generated" or
similar) so the CLI writes generated files to that location; ensure the script
string still uses the same dlx invocation and URL argument and only appends the
-o <output-dir> option.
In `@packages/api/package.json`:
- Line 32: Prettier failed due to formatting in packages/api/package.json after
adding the dependency entry "@types/node": "catalog:"; run the repository
formatter (pnpm run format:fix from the repo root) to fix formatting and commit
the updated package.json, and while doing so verify the dependency value for the
"@types/node" entry is the intended version/resolution (replace the placeholder
"catalog:" with the correct version or spec if needed) so the package.json
remains valid.
🧹 Nitpick comments (4)
docker-compose.yml (1)
23-23: Hardcoded credentials are acceptable for local development but add a cautionary comment.The static analysis tool flagged the plaintext password in
POSTGRES_URL. While hardcoded credentials in docker-compose for local development are common practice, consider adding a comment clarifying this file is for development only to prevent accidental use in production.📝 Suggested documentation
+ # WARNING: Development only - do not use these credentials in production - POSTGRES_URL=postgresql://postgres:password@application_db:5432/app_dbpackages/db/src/client.ts (1)
6-16: Consider lazy initialization for the database client.The current implementation throws at module load time if
POSTGRES_URLis missing and eagerly creates a connection. This means:
- Importing this module in any code path will fail if the env var is absent, even if the database isn't needed for that request.
- The connection is created immediately at import time.
For serverless environments or cases where not all code paths need the database, consider lazy initialization:
♻️ Optional: Lazy initialization pattern
-const connectionString = process.env.POSTGRES_URL; - -if (!connectionString) { - throw new Error("Missing POSTGRES_URL environment variable"); -} - -/** - * Database client using postgres.js - * Works with both local Docker containers and Neon (via standard connection string) - */ -const client = postgres(connectionString); - -export const db = drizzle(client, { +let _db: ReturnType<typeof drizzle> | null = null; + +function getDb() { + if (_db) return _db; + + const connectionString = process.env.POSTGRES_URL; + if (!connectionString) { + throw new Error("Missing POSTGRES_URL environment variable"); + } + + const client = postgres(connectionString); + _db = drizzle(client, { + schema, + casing: "snake_case", + }); + return _db; +} + +/** + * Database client using postgres.js + * Works with both local Docker containers and Neon (via standard connection string) + */ +export const db = new Proxy({} as ReturnType<typeof drizzle>, { + get(_, prop) { + return Reflect.get(getDb(), prop); + }, +});If eager initialization is intentional for this project's architecture (e.g., always needs DB), the current approach is fine—just be aware of the tradeoff.
apps/tanstack-start/src/routes/__root.tsx (1)
15-19: Inline theme script needs CSP/XSS verification.
dangerouslySetInnerHTMLinjects an inline script. If you enforce a strict CSP, this will be blocked unless a nonce/hash is provided. Also ensure the script content stays static (no user input) to avoid XSS risk. Consider adding a CSP nonce or moving the logic to an external script if CSP is enabled.Also applies to: 53-56, 68-68
apps/tanstack-start/src/routeTree.gen.ts (1)
14-104: Ensure WorkOS callback URL matches/api/auth/callback.The generated route tree now exposes
/api/auth/callbackacross route maps and types. Please verify the WorkOS dashboard/environment configuration uses the same callback URL; mismatches will break SSO redirects. Also ensure this generated file is re-built when routes change.
| - 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. No newline at end of file |
There was a problem hiding this comment.
Typo: "seperate" should be "separate".
📝 Proposed fix
-- 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.
+- AI service shouldn't have a separate 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.📝 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.
| - 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. | |
| - AI service shouldn't have a separate 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. |
🤖 Prompt for AI Agents
In @.agent/rules/project-rules.md at line 67, Fix the typo in the rule sentence:
replace the misspelled word "seperate" with "separate" in the line that
currently reads 'AI service shouldn't have a seperate auth flow...' so it
becomes 'AI service shouldn't have a separate auth flow...'; update the
.agent/rules/project-rules.md entry containing that sentence.
| - 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. | ||
| - always use pnpm and pnpx for package management |
There was a problem hiding this comment.
Fix grammar/capitalization in the guidance bullets.
Minor doc polish: capitalize “Always” and make the second sentence a proper sentence.
✍️ Proposed edit
-- always use pnpm and pnpx for package management
+- Always use pnpm and pnpx for package management.
-- All reusable UI components must live in the `packages/ui` package. use them
+- All reusable UI components must live in the `packages/ui` package. Use them.Also applies to: 31-31
🤖 Prompt for AI Agents
In @.github/.copilot-instructions.md at line 6, Update the bullet text "always
use pnpm and pnpx for package management" to correct grammar/capitalization by
capitalizing the first word and ending with a period: replace it with "Always
use pnpm and pnpx for package management." Apply the same capitalization and
punctuation fix to the duplicate occurrence mentioned (line 31).
| import { useAuth } from "@workos/authkit-tanstack-react-start/client"; | ||
| import { getSignInUrl } from "@workos/authkit-tanstack-react-start"; | ||
| import { createServerFn } from "@tanstack/react-start"; | ||
|
|
||
| import { Button } from "@governance/ui/button"; | ||
|
|
||
| import { authClient } from "~/auth/client"; | ||
| const getSignInUrlFn = createServerFn({ method: "GET" }).handler(async () => { | ||
| return await getSignInUrl(); | ||
| }); | ||
|
|
||
| export function AuthShowcase() { | ||
| const { data: session } = authClient.useSession(); | ||
| const navigate = useNavigate(); | ||
| const { user, loading, signOut } = useAuth(); | ||
|
|
||
| if (!session) { | ||
| if (loading) { | ||
| return <div className="text-muted-foreground">Loading...</div>; | ||
| } | ||
|
|
||
| if (!user) { | ||
| return ( | ||
| <Button | ||
| size="lg" | ||
| onClick={async () => { | ||
| const res = await authClient.signIn.social({ | ||
| provider: "discord", | ||
| callbackURL: "/", | ||
| }); | ||
| if (!res.data?.url) { | ||
| throw new Error("No URL returned from signInSocial"); | ||
| } | ||
| await navigate({ href: res.data.url, replace: true }); | ||
| const signInUrl = await getSignInUrlFn(); | ||
| window.location.href = signInUrl; | ||
| }} | ||
| > | ||
| Sign in with Discord | ||
| Sign in with WorkOS | ||
| </Button> | ||
| ); | ||
| } | ||
|
|
||
| return ( | ||
| <div className="flex flex-col items-center justify-center gap-4"> | ||
| <p className="text-center text-2xl"> | ||
| <span>Logged in as {session.user.name}</span> | ||
| <span> | ||
| Logged in as {user.firstName} {user.lastName} | ||
| </span> | ||
| </p> | ||
| <p className="text-muted-foreground">{user.email}</p> | ||
|
|
||
| <Button | ||
| size="lg" | ||
| onClick={async () => { | ||
| await authClient.signOut(); | ||
| await navigate({ href: "/", replace: true }); | ||
| }} | ||
| > | ||
| <Button size="lg" onClick={() => signOut()}> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "auth-showcase.tsx" | head -20Repository: AFAskar/Governance-Agent
Length of output: 121
🏁 Script executed:
git ls-files | grep -E "(auth-showcase|authkit)" | head -30Repository: AFAskar/Governance-Agent
Length of output: 119
🏁 Script executed:
fd "auth-showcase" --type fRepository: AFAskar/Governance-Agent
Length of output: 119
🏁 Script executed:
cat -n ./apps/tanstack-start/src/component/auth-showcase.tsxRepository: AFAskar/Governance-Agent
Length of output: 1569
🏁 Script executed:
rg "@workos/authkit-tanstack-react-start" -t tsx -t ts --context 3 | head -80Repository: AFAskar/Governance-Agent
Length of output: 95
🏁 Script executed:
rg "getSignInUrl|signOut" -t tsx -t ts -A 2 -B 2 | head -100Repository: AFAskar/Governance-Agent
Length of output: 95
🏁 Script executed:
find . -type f -name "package.json" -path "*/tanstack-start/*" -o -name "package.json" -path "*/root" | head -5Repository: AFAskar/Governance-Agent
Length of output: 102
🏁 Script executed:
cat ./apps/tanstack-start/package.jsonRepository: AFAskar/Governance-Agent
Length of output: 2028
🏁 Script executed:
rg "getSignInUrl|signOut" --type-list | grep -i tsxRepository: AFAskar/Governance-Agent
Length of output: 457
🏁 Script executed:
rg "getSignInUrl|signOut" -A 3 -B 2 | head -150Repository: AFAskar/Governance-Agent
Length of output: 2627
🏁 Script executed:
rg "useAuth" --max-count 20 -B 3 -A 5Repository: AFAskar/Governance-Agent
Length of output: 1273
🏁 Script executed:
rg "try.*catch" apps/tanstack-start/src -B 2 -A 4 | head -80Repository: AFAskar/Governance-Agent
Length of output: 50
🏁 Script executed:
rg "getSignInUrlFn" -B 2 -A 5Repository: AFAskar/Governance-Agent
Length of output: 1355
🏁 Script executed:
rg "onClick.*async" apps/tanstack-start/src -B 2 -A 8 | head -100Repository: AFAskar/Governance-Agent
Length of output: 872
🏁 Script executed:
rg "\.catch\|try\s*{" apps/tanstack-start/src -B 3 -A 4Repository: AFAskar/Governance-Agent
Length of output: 163
🏁 Script executed:
find apps/tanstack-start/src -type f -name "*.ts" -o -name "*.tsx" | head -20Repository: AFAskar/Governance-Agent
Length of output: 558
🏁 Script executed:
rg "\.catch|catch\s*\(" apps/tanstack-start/src -B 2 -A 3Repository: AFAskar/Governance-Agent
Length of output: 50
🏁 Script executed:
cat apps/tanstack-start/src/routes/index.tsxRepository: AFAskar/Governance-Agent
Length of output: 6966
🏁 Script executed:
rg "useState" apps/tanstack-start/src --max-count 10 -B 2 -A 2Repository: AFAskar/Governance-Agent
Length of output: 50
🏁 Script executed:
grep -r "use client" apps/tanstack-start/src/component --include="*.tsx"Repository: AFAskar/Governance-Agent
Length of output: 50
🏁 Script executed:
rg "onError|try|catch" packages/auth/src --max-count 20 -B 2 -A 3Repository: AFAskar/Governance-Agent
Length of output: 50
🏁 Script executed:
cat apps/tanstack-start/src/component/auth-showcase.tsx | head -50Repository: AFAskar/Governance-Agent
Length of output: 1247
🏁 Script executed:
web_search
What does `@workos/authkit-tanstack-react-start` getSignInUrl() and signOut() return and can they throw errors?Repository: AFAskar/Governance-Agent
Length of output: 313
🌐 Web query:
@workos/authkit-tanstack-react-start getSignInUrl signOut error handling
💡 Result:
Where errors can happen (and how to handle them)
1) getSignInUrl() (server-side only)
getSignInUrl() is meant to be called in route loaders / server functions / server handlers (not in beforeLoad or directly in client components). The canonical pattern is to generate the URL and throw a TanStack redirect. (github.com)
Error handling pattern (loader):
import { createFileRoute, redirect } from '@tanstack/react-router'
import { getSignInUrl } from '@workos/authkit-tanstack-react-start'
export const Route = createFileRoute('/signin')({
loader: async () => {
try {
const url = await getSignInUrl({ data: { returnPathname: '/dashboard' } })
throw redirect({ href: url })
} catch (err) {
// log + send user somewhere safe
console.error('getSignInUrl failed', err)
throw redirect({ href: '/auth-error' })
}
},
})(Options like returnPathname are supported.) (github.com)
2) signOut() (server-side)
Server-side signOut() ends the session and redirects to WorkOS logout (optionally with a returnTo). (github.com)
Error handling pattern (loader):
import { createFileRoute, redirect } from '@tanstack/react-router'
import { signOut } from '@workos/authkit-tanstack-react-start'
export const Route = createFileRoute('/logout')({
loader: async () => {
try {
await signOut({ data: { returnTo: '/goodbye' } })
} catch (err) {
console.error('signOut failed', err)
throw redirect({ href: '/auth-error' })
}
},
})Note: if your WorkOS Dashboard has neither a Sign-out redirect nor an App homepage URL configured, WorkOS will redirect users to an error page on logout. (github.com)
3) signOut() (client-side via useAuth())
Client-side sign-out is available via the useAuth() hook and returns a promise, so handle it with try/catch (or .catch). (github.com)
import { useAuth } from '@workos/authkit-tanstack-react-start/client'
function SignOutButton() {
const { signOut } = useAuth()
return (
<button
onClick={async () => {
try {
await signOut({ returnTo: '/goodbye' })
} catch (err) {
console.error('Client signOut failed', err)
window.location.href = '/auth-error'
}
}}
>
Sign out
</button>
)
}4) OAuth callback failures (best place for “auth flow” error handling)
If you want centralized handling for login/callback errors, use handleCallbackRoute({ onError }) to return your own Response (JSON, redirect, etc.). (github.com)
import { handleCallbackRoute } from '@workos/authkit-tanstack-react-start'
GET: handleCallbackRoute({
onError: ({ error }) => {
console.error('Auth callback failed:', error)
return new Response('Authentication failed', { status: 500 })
},
})Citations:
- 1: https://github.com/workos/authkit-tanstack-start
- 2: https://github.com/workos/authkit-tanstack-start
- 3: https://github.com/workos/authkit-tanstack-start
- 4: https://github.com/workos/authkit-tanstack-start
- 5: https://github.com/workos/authkit-tanstack-start
- 6: https://github.com/workos/authkit-tanstack-start
Add error handling for signOut() and getSignInUrl() to improve UX.
The signOut() hook method returns a promise that is not being awaited or caught (line 41). Similarly, getSignInUrlFn() can fail without user feedback (line 23). Per the library's documented patterns, both operations should include try/catch with user-visible error messaging.
Suggested fix
import { useAuth } from "@workos/authkit-tanstack-react-start/client";
import { getSignInUrl } from "@workos/authkit-tanstack-react-start";
import { createServerFn } from "@tanstack/react-start";
+import { useState } from "react";
import { Button } from "@governance/ui/button";
const getSignInUrlFn = createServerFn({ method: "GET" }).handler(async () => {
return await getSignInUrl();
});
export function AuthShowcase() {
const { user, loading, signOut } = useAuth();
+ const [error, setError] = useState<string | null>(null);
if (loading) {
return <div className="text-muted-foreground">Loading...</div>;
}
if (!user) {
return (
- <Button
- size="lg"
- onClick={async () => {
- const signInUrl = await getSignInUrlFn();
- window.location.href = signInUrl;
- }}
- >
- Sign in with WorkOS
- </Button>
+ <div className="flex flex-col items-center gap-2">
+ {error && <p className="text-destructive">{error}</p>}
+ <Button
+ size="lg"
+ onClick={async () => {
+ try {
+ setError(null);
+ const signInUrl = await getSignInUrlFn();
+ window.location.href = signInUrl;
+ } catch (err) {
+ console.error(err);
+ setError("Unable to start sign-in. Please try again.");
+ }
+ }}
+ >
+ Sign in with WorkOS
+ </Button>
+ </div>
);
}
return (
<div className="flex flex-col items-center justify-center gap-4">
+ {error && <p className="text-destructive">{error}</p>}
<p className="text-center text-2xl">
<span>
Logged in as {user.firstName} {user.lastName}
</span>
</p>
<p className="text-muted-foreground">{user.email}</p>
- <Button size="lg" onClick={() => signOut()}>
+ <Button
+ size="lg"
+ onClick={async () => {
+ try {
+ setError(null);
+ await signOut();
+ } catch (err) {
+ console.error(err);
+ setError("Unable to sign out. Please try again.");
+ }
+ }}
+ >
Sign out
</Button>
</div>
);
}🤖 Prompt for AI Agents
In `@apps/tanstack-start/src/component/auth-showcase.tsx` around lines 1 - 41, The
component AuthShowcase must await and catch errors from getSignInUrlFn() and
signOut(): wrap the getSignInUrlFn() call inside an async try/catch in the Sign
in button onClick, and handle failures by logging and showing a user-visible
error (e.g., set an error state or display alert/toast); likewise change the
signOut() invocation to an async function that awaits signOut() inside try/catch
and surfaces errors to the user. Update the handlers in AuthShowcase to use
await, try/catch, and a simple UI feedback mechanism (error state or toast) so
both getSignInUrlFn and signOut errors are handled and reported.
| import { Link, useLocation } from "@tanstack/react-router"; | ||
|
|
||
| export function NotFound() { | ||
| const location = useLocation(); | ||
| console.log("NotFound triggered for path:", location.pathname); | ||
|
|
There was a problem hiding this comment.
Remove or gate the render-time console.log.
Logging on every 404 render can spam production logs and expose path data. Consider gating to dev or removing.
🛠️ Suggested fix (gate to dev)
export function NotFound() {
- const location = useLocation();
- console.log("NotFound triggered for path:", location.pathname);
+ const location = useLocation();
+ if (import.meta.env.DEV) {
+ console.log("NotFound triggered for path:", location.pathname);
+ }📝 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.
| import { Link, useLocation } from "@tanstack/react-router"; | |
| export function NotFound() { | |
| const location = useLocation(); | |
| console.log("NotFound triggered for path:", location.pathname); | |
| import { Link, useLocation } from "@tanstack/react-router"; | |
| export function NotFound() { | |
| const location = useLocation(); | |
| if (import.meta.env.DEV) { | |
| console.log("NotFound triggered for path:", location.pathname); | |
| } |
🤖 Prompt for AI Agents
In `@apps/tanstack-start/src/component/NotFound.tsx` around lines 1 - 6, The
NotFound component currently calls console.log("NotFound triggered for path:",
location.pathname) on every render; remove that call or gate it to only run in
development (e.g., wrap it with a check like NODE_ENV === 'development' or an
isDev flag) so location.pathname is not logged in production; update the
NotFound function (which uses useLocation and the location variable) to either
delete the console.log line or conditionally execute it only when in dev.
| "typecheck": "turbo run typecheck", | ||
| "ui-add": "turbo run ui-add" | ||
| "ui-add": "turbo run ui-add", | ||
| "ai-service:generate": "pnpm dlx @hey-api/openapi-ts -i http://localhost:8000/openapi.json" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find and read package.json to confirm the script
cat -n package.jsonRepository: AFAskar/Governance-Agent
Length of output: 1706
🏁 Script executed:
# Check for any openapi-ts or hey-api configuration files
fd -e "config.ts" -e "config.js" -e "config.json" | grep -i "openapi\|hey-api"
fd -i "openapi-ts.config" -o "openapi.config"Repository: AFAskar/Governance-Agent
Length of output: 215
🌐 Web query:
@hey-api/openapi-ts output directory -o flag requirement documentation
💡 Result:
@hey-api/openapi-ts requires you to set an output location (the folder where generated files are written).
- CLI: use the
-oflag to set the output directory (commonly shown with-ifor input), e.g.npx@hey-api/openapi-ts-i … -o src/client. [1] - Config file / programmatic API: you must set
output(either a string path or an object withpath), e.g.output: 'src/client'oroutput: { path: 'src/client', … }. The docs explicitly state: “You must set the output so we know where to generate your files.” [2]
Sources:
[1] Hey API “Get Started” (CLI quick start showing -o) [1]
[2] Hey API “Configuration → Output” (output is required) [2]
🏁 Script executed:
# Search for openapi-ts config files
fd "\.openapi-ts\.config" -type f
fd "openapi-ts\.config" -type f
fd "openapi\.config" -type f
# Also check common config locations
find . -name "*openapi*" -type f 2>/dev/null | head -20Repository: AFAskar/Governance-Agent
Length of output: 580
🏁 Script executed:
# Check if there's a config file in packages/api or similar
find . -path "*/packages/*/openapi*" -o -path "*/packages/api/*config*" 2>/dev/null | head -20Repository: AFAskar/Governance-Agent
Length of output: 128
🏁 Script executed:
# Simpler search for any openapi files
rg "openapi" --type-list | head -5
rg "openapi" -i -l | head -20Repository: AFAskar/Governance-Agent
Length of output: 532
🏁 Script executed:
# Check the README.md for any config info
cat services/ai-service/src/api/models/README.mdRepository: AFAskar/Governance-Agent
Length of output: 372
Add output directory to the ai-service:generate script.
The @hey-api/openapi-ts CLI requires the -o flag to specify where generated files should be written. Without it, the command will fail.
Suggested fix
- "ai-service:generate": "pnpm dlx `@hey-api/openapi-ts` -i http://localhost:8000/openapi.json"
+ "ai-service:generate": "pnpm dlx `@hey-api/openapi-ts` -i http://localhost:8000/openapi.json -o packages/api/src/generated"📝 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.
| "ai-service:generate": "pnpm dlx @hey-api/openapi-ts -i http://localhost:8000/openapi.json" | |
| "ai-service:generate": "pnpm dlx `@hey-api/openapi-ts` -i http://localhost:8000/openapi.json -o packages/api/src/generated" |
🤖 Prompt for AI Agents
In `@package.json` at line 25, The npm script "ai-service:generate" currently
calls the `@hey-api/openapi-ts` CLI without an output path, causing the command to
fail; update the "ai-service:generate" script to add the -o (or --output) flag
followed by the intended output directory (for example "src/generated" or
similar) so the CLI writes generated files to that location; ensure the script
string still uses the same dlx invocation and URL argument and only appends the
-o <output-dir> option.
| "@governance/eslint-config": "workspace:*", | ||
| "@governance/prettier-config": "workspace:*", | ||
| "@governance/tsconfig": "workspace:*", | ||
| "@types/node": "catalog:", |
There was a problem hiding this comment.
Address the Prettier formatting failure.
The CI pipeline reports a Prettier formatting check failure in this package. Run pnpm run format:fix from the root to resolve the formatting issues.
The addition of @types/node is appropriate for Node.js type definitions.
🤖 Prompt for AI Agents
In `@packages/api/package.json` at line 32, Prettier failed due to formatting in
packages/api/package.json after adding the dependency entry "@types/node":
"catalog:"; run the repository formatter (pnpm run format:fix from the repo
root) to fix formatting and commit the updated package.json, and while doing so
verify the dependency value for the "@types/node" entry is the intended
version/resolution (replace the placeholder "catalog:" with the correct version
or spec if needed) so the package.json remains valid.
Summary by CodeRabbit
New Features
Updates
Documentation