Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds a new "Hosted Components" frontend app (Vite + React + TypeScript) with route definitions, client bootstrap, Stack client integration, dev tooling/config, a vitest exclusion, and a small console monkey-patch utility in shared utils. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser as Browser
participant Client as client.tsx
participant Router as TanStack Router
participant Root as __root Route
participant Stack as StackClientApp
Browser->>Client: load & hydrate
Client->>Router: create/getRouter()
Router->>Root: render RootComponent (route match)
Root->>Stack: compute projectId & instantiate StackClientApp
Root->>Stack: wrap app with StackProvider/StackTheme -> Outlet
Router->>Client: render matched page (index / handler)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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 |
Greptile SummaryAdds a new Key changes:
Minor issue:
Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User visits subdomain] --> B{Extract project ID from subdomain}
B --> C{Project ID exists?}
C -->|No| D[Show 'Invalid URL' error]
C -->|Yes| E{Valid UUID format?}
E -->|No| F[Show 'Invalid project ID' error]
E -->|Yes| G[Initialize StackClientApp]
G --> H{User route}
H -->|/handler/*| I[StackHandler component<br/>Sign-in/Sign-up flows]
H -->|/| J{User authenticated?}
J -->|No| K[Redirect to sign-in]
J -->|Yes| L[Show welcome page<br/>with UserButton]
Last reviewed commit: 07b9be1 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
apps/hosted-components/src/routes/__root.tsx (1)
115-117: Render an explicit loading state instead of a blank screen.Line [116] returns an empty fragment while initialization is in progress; use a visible loading UI so state transitions are explicit.
Based on learnings: "When building frontend code, always carefully deal with loading and error states. Be very explicit with these."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/hosted-components/src/routes/__root.tsx` around lines 115 - 117, The early return for projectId (if (projectId === undefined) return <></>;) shows a blank screen; replace it with an explicit loading UI so users see progress. In the if (projectId === undefined) branch in __root.tsx, return a visible loading state (for example a <Loading /> component or a simple accessible element like a div with role="status" and a spinner/text) instead of an empty fragment, ensuring any existing Loading component or CSS spinner is used for consistency with the app.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/hosted-components/package.json`:
- Line 7: The dev script in package.json sets Vite to port 8109 ("dev": "vite
dev --port ${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}09") which conflicts with the
app’s expected 8105; update the dev script to default to 8105 instead (adjust
the NEXT_PUBLIC_STACK_PORT_PREFIX fallback or the appended digits) so the "dev"
npm script, the Vite server, and the local URL guidance in src/routes/__root.tsx
all use port 8105 consistently.
In `@apps/hosted-components/src/routes/__root.tsx`:
- Around line 97-113: Replace the type bypass and non-null assertion: create a
properly typed adapter for redirectMethod that calls the React Router
useNavigate hook (e.g., a small function that captures const navigate =
useNavigate(); and returns a function (to: string) => void) and pass that
adapter to new StackClientApp instead of `useNavigate as any`; and replace the
`stackApp!` usage with a defensive null-coalescing pattern (e.g., `stackApp ??
throwErr('stackApp was unexpectedly null despite validation checks')` or an
explicit guard that throws) so the code is type-safe and fails with an explicit
error if stackApp is null.
---
Nitpick comments:
In `@apps/hosted-components/src/routes/__root.tsx`:
- Around line 115-117: The early return for projectId (if (projectId ===
undefined) return <></>;) shows a blank screen; replace it with an explicit
loading UI so users see progress. In the if (projectId === undefined) branch in
__root.tsx, return a visible loading state (for example a <Loading /> component
or a simple accessible element like a div with role="status" and a spinner/text)
instead of an empty fragment, ensuring any existing Loading component or CSS
spinner is used for consistency with the app.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (12)
apps/dev-launchpad/public/index.htmlapps/hosted-components/.env.developmentapps/hosted-components/.eslintrc.cjsapps/hosted-components/package.jsonapps/hosted-components/src/client.tsxapps/hosted-components/src/routeTree.gen.tsapps/hosted-components/src/router.tsxapps/hosted-components/src/routes/__root.tsxapps/hosted-components/src/routes/handler/$.tsxapps/hosted-components/src/routes/index.tsxapps/hosted-components/tsconfig.jsonapps/hosted-components/vite.config.ts
There was a problem hiding this comment.
can you also create a vercel project for this? domain built-with-stack-auth.com is on cloudflare
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
apps/hosted-components/package.json (1)
7-7:⚠️ Potential issue | 🟠 MajorUse the same default port as the rest of this app.
This still defaults Vite to
8109, whileapps/hosted-components/src/routes/__root.tsxpoints users to<projectId>.localhost:8105. The default dev flow and the in-app guidance will disagree until these match.Proposed fix
- "dev": "vite dev --port ${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}09", + "dev": "vite dev --port ${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}05",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/hosted-components/package.json` at line 7, The dev script in package.json currently defaults Vite to port 8109 via "dev": "vite dev --port ${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}09"; change the default to match the rest of the app (8105) by updating the dev script to use the same fallback prefix so Vite will start on 8105 when NEXT_PUBLIC_STACK_PORT_PREFIX is not set; edit the "dev" script entry (symbol: "dev") and adjust the fallback port expression (symbol: NEXT_PUBLIC_STACK_PORT_PREFIX) so the resolved default is 8105 instead of 8109.
🧹 Nitpick comments (1)
apps/hosted-components/src/routes/__root.tsx (1)
14-24: GuardgetProjectId()against SSR callers.This route module is loaded on the server too, and
getProjectId()is exported. Any future SSR/test caller will crash onwindow. Make the browser-only assumption explicit inside the helper.Suggested change
export function getProjectId(): string | null { + if (typeof window === "undefined") { + return null; + } + // Extract from subdomain: <projectId>.built-with-stack-auth.com // Also works with <projectId>.localhost for local dev const hostname = window.location.hostname;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/hosted-components/src/routes/__root.tsx` around lines 14 - 24, getProjectId() currently assumes a browser environment and directly accesses window, which will crash during SSR/testing; update the function to first guard for non-browser callers by checking typeof window === "undefined" (and/or typeof window.location === "undefined") and returning null in that case, then continue with the existing hostname parsing logic (hostname.split and parts[0]) when running in the browser so server-side imports won't throw.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/hosted-components/package.json`:
- Around line 7-15: The dev script in hosted-components fails because
`@stackframe/react`'s dist files aren't guaranteed to exist; update the task
wiring so hosted-components' dev depends on the package build: add a dependsOn
entry (e.g., dependsOn: ["^build"]) to the hosted-components "dev" task in
turbo.json so the workspace runs the dependent package build first, or
alternatively add a Vite alias in hosted-components' Vite config to resolve
"@stackframe/react" directly to its source (src) to avoid needing dist files
during dev.
In `@apps/hosted-components/src/routes/__root.tsx`:
- Around line 89-93: The initial state for projectId is incorrectly bootstrapped
to the string "internal", causing the app to create a StackClientApp for the
internal project before the real hostname is known; change the initialization so
projectId starts as undefined (or null) instead of "internal", keep the existing
useEffect that calls getProjectId() and setProjectId(), and ensure any code that
constructs/bootstraps StackClientApp (or reads projectId) guards against
undefined and only creates the client after projectId is set to the real value.
In `@apps/hosted-components/src/routes/index.tsx`:
- Around line 6-10: The pendingComponent render lacks accessible status
announcement for screen readers; update the pendingComponent function to include
an accessible status (e.g., role="status" or aria-live="polite") and provide
visible or visually-hidden text such as "Loading, please wait" so assistive tech
is informed during auth loading/redirect; keep the existing spinner for visual
users and add the announcement text inside the same wrapper (or as a
screen-reader-only element) to ensure both visual and non-visual users receive
feedback.
---
Duplicate comments:
In `@apps/hosted-components/package.json`:
- Line 7: The dev script in package.json currently defaults Vite to port 8109
via "dev": "vite dev --port ${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}09"; change the
default to match the rest of the app (8105) by updating the dev script to use
the same fallback prefix so Vite will start on 8105 when
NEXT_PUBLIC_STACK_PORT_PREFIX is not set; edit the "dev" script entry (symbol:
"dev") and adjust the fallback port expression (symbol:
NEXT_PUBLIC_STACK_PORT_PREFIX) so the resolved default is 8105 instead of 8109.
---
Nitpick comments:
In `@apps/hosted-components/src/routes/__root.tsx`:
- Around line 14-24: getProjectId() currently assumes a browser environment and
directly accesses window, which will crash during SSR/testing; update the
function to first guard for non-browser callers by checking typeof window ===
"undefined" (and/or typeof window.location === "undefined") and returning null
in that case, then continue with the existing hostname parsing logic
(hostname.split and parts[0]) when running in the browser so server-side imports
won't throw.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 02535b65-2167-4f30-a751-ce9a02098417
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
apps/hosted-components/.env.developmentapps/hosted-components/package.jsonapps/hosted-components/src/routes/__root.tsxapps/hosted-components/src/routes/index.tsxapps/hosted-components/vite.config.tspackages/stack-shared/src/utils/monkey-patch.tsxpackages/stack-shared/src/utils/react.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/hosted-components/.env.development
- apps/hosted-components/vite.config.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/hosted-components/vite.config.ts (2)
72-75: Validate the port prefix instead of relying on||.
|| "81"treats''as unset, and a malformed prefix still flows intoNumber(...)asNaN. Since this is config input, prefer nullish handling plus an explicit validation error.Suggested diff
+const portPrefix = process.env.NEXT_PUBLIC_STACK_PORT_PREFIX +if (portPrefix !== undefined && !/^\d+$/.test(portPrefix)) { + throw new Error('NEXT_PUBLIC_STACK_PORT_PREFIX must contain only digits') +} + export default defineConfig({ server: { - port: Number((process.env.NEXT_PUBLIC_STACK_PORT_PREFIX || "81") + "09"), + port: Number(`${portPrefix ?? '81'}09`), },As per coding guidelines, "Unless very clearly equivalent from types, prefer explicit null/undefinedness checks over boolean checks" and "Fail early, fail loud. Fail fast with an error instead of silently continuing."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/hosted-components/vite.config.ts` around lines 72 - 75, Replace the fragile port computation in defineConfig's server.port by explicitly reading process.env.NEXT_PUBLIC_STACK_PORT_PREFIX, applying nullish coalescing (not ||), validating that the prefix is non-empty and matches the expected digit pattern (e.g., /^\d+$/), then construct the port (prefix + "09"), parse it to a number and throw a clear Error if the prefix is missing or the resulting Number is NaN/invalid; update the symbol references NEXT_PUBLIC_STACK_PORT_PREFIX and server.port in vite.config.ts so the config fails fast on bad input rather than producing NaN.
42-55: Useperformance.now()for the timeout clock.This loop is measuring elapsed time with wall-clock time, so clock adjustments can skew the timeout.
performance.now()is the safer timer here.Suggested diff
async function waitForFile(filePath: string, timeoutMs = 60_000): Promise<void> { if (fs.existsSync(filePath)) return - const start = Date.now() + const start = performance.now() return new Promise((resolve, reject) => { const interval = setInterval(() => { if (fs.existsSync(filePath)) { clearInterval(interval) resolve() - } else if (Date.now() - start > timeoutMs) { + } else if (performance.now() - start > timeoutMs) { clearInterval(interval) reject(new Error(`Timed out waiting for ${filePath} to exist`)) } }, 500) })As per coding guidelines, "Don't use Date.now() for measuring elapsed (real) time, instead use
performance.now()".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/hosted-components/vite.config.ts` around lines 42 - 55, In waitForFile, replace the Date.now() wall-clock timing with a monotonic timer: set const start = performance.now() and in the interval check use (performance.now() - start > timeoutMs) to detect timeout; if your Node runtime may not expose global performance, import it via const { performance } = require('perf_hooks') or an equivalent ESM import at the top of the file, and ensure timeoutMs remains milliseconds (performance.now() is also in ms).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/hosted-components/src/routes/__root.tsx`:
- Line 95: isValidProjectId uses a loose UUID regex that can accept values
rejected by the StackClientApp constructor; update the validation to the
stricter UUID v1-8 + variant pattern used by StackClientApp so the same IDs are
accepted/rejected. Replace the current regex in isValidProjectId with one that
enforces the version char as [1-8] and the variant nibble as [089ab] (i.e.,
match the same pattern used by StackClientApp), so invalid projectId values
produce the intended FullPageError instead of a constructor exception.
---
Nitpick comments:
In `@apps/hosted-components/vite.config.ts`:
- Around line 72-75: Replace the fragile port computation in defineConfig's
server.port by explicitly reading process.env.NEXT_PUBLIC_STACK_PORT_PREFIX,
applying nullish coalescing (not ||), validating that the prefix is non-empty
and matches the expected digit pattern (e.g., /^\d+$/), then construct the port
(prefix + "09"), parse it to a number and throw a clear Error if the prefix is
missing or the resulting Number is NaN/invalid; update the symbol references
NEXT_PUBLIC_STACK_PORT_PREFIX and server.port in vite.config.ts so the config
fails fast on bad input rather than producing NaN.
- Around line 42-55: In waitForFile, replace the Date.now() wall-clock timing
with a monotonic timer: set const start = performance.now() and in the interval
check use (performance.now() - start > timeoutMs) to detect timeout; if your
Node runtime may not expose global performance, import it via const {
performance } = require('perf_hooks') or an equivalent ESM import at the top of
the file, and ensure timeoutMs remains milliseconds (performance.now() is also
in ms).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f5913baa-8149-4a18-80fe-cb1d7e589522
📒 Files selected for processing (4)
apps/hosted-components/.env.developmentapps/hosted-components/src/routes/__root.tsxapps/hosted-components/src/routes/handler/$.tsxapps/hosted-components/vite.config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/hosted-components/src/routes/handler/$.tsx
<!-- Make sure you've read the CONTRIBUTING.md guidelines: https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a new "Hosted Components" app with its own app shell, routing, auth-aware UI, a handler route, and a welcome page showing the signed-in user. * **Chores** * Added dev tooling and configuration for the new app (build, lint, typecheck, Vite/TS, package manifest) and updated dev env API URL. * **Tests** * Excluded the new app from the test workspace. * **Bug Fixes** * Suppressed noisy console errors for a specific internal sentinel and clarified related error messaging. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Konstantin Wohlwend <n2d4xc@gmail.com>
Summary by CodeRabbit