Skip to content

New setup#1413

Open
N2D4 wants to merge 8 commits intodevfrom
new-setup
Open

New setup#1413
N2D4 wants to merge 8 commits intodevfrom
new-setup

Conversation

@N2D4
Copy link
Copy Markdown
Contributor

@N2D4 N2D4 commented May 6, 2026

Note

Medium Risk
Touches DB schema and project update paths (new Project.onboardingState JSONB) and changes local-emulator project/bootstrap behavior, so regressions could impact project creation/onboarding flows. Also adds a new Authorization header path used for auth in request-like token stores, which affects authentication integrations.

Overview
Adds a persisted Project.onboardingState (JSONB) with migration + tests, and surfaces it through project read/update flows so the dashboard onboarding wizard can resume progress and clear state on completion.

Extends local emulator bootstrap: empty config files now get a "show-onboarding" sentinel, config parsing supports this value and non-TS filenames, and the local emulator project endpoint now returns onboarding_status/onboarding_outstanding while syncing DB onboarding status based on the sentinel.

Updates dashboard onboarding to validate and persist onboarding_state on each step (and adjust behavior in local emulator mode), and adds/updates E2E tests for both local emulator onboarding behavior and the new getAuthorizationHeader() Bearer format (including request-like/record-style headers).

Reviewed by Cursor Bugbot for commit 3f44cf6. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Project onboarding state tracking with a guided setup wizard and persisted per-project state.
    • New Authorization header APIs and hooks for cross-origin auth (easy to fetch/use Authorization header).
    • Local emulator now surfaces onboarding status/outstanding and can open the emulator onboarding UI.
    • Automated generation and copyable AI setup prompt UI in docs.
  • Documentation

    • Updated auth guides and setup-prompt docs; examples updated to use the new header APIs.
  • Deprecations

    • Legacy auth header helpers marked deprecated in favor of the new Authorization header APIs.
  • Bug Fixes

    • Improved emulator onboarding error handling and UI sync behavior.

Copilot AI review requested due to automatic review settings May 6, 2026 02:12
@mintlify
Copy link
Copy Markdown

mintlify Bot commented May 6, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
stackauth-docs 🔴 Failed May 6, 2026, 2:12 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stack-auth-hosted-components Ready Ready Preview, Comment May 6, 2026 4:16am
stack-backend Ready Ready Preview, Comment May 6, 2026 4:16am
stack-dashboard Ready Ready Preview, Comment May 6, 2026 4:16am
stack-demo Error Error May 6, 2026 4:16am
stack-docs Ready Ready Preview, Comment May 6, 2026 4:16am
stack-preview-backend Ready Ready Preview, Comment May 6, 2026 4:16am
stack-preview-dashboard Ready Ready Preview, Comment May 6, 2026 4:16am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

📝 Walkthrough

Walkthrough

Adds persistent per-project onboarding state with DB migration, local-emulator onboarding flows, dashboard wizard integration and persistence, a new Authorization header token format and APIs, generated setup-prompt artifacts and generator script, CLI/emulator wiring for onboarding UX, and corresponding tests and docs.

Changes

Project Onboarding (DB, Backend, Emulator, Dashboard, Tests)

Layer / File(s) Summary
Database Schema / Migration
apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/migration.sql, apps/backend/prisma/schema.prisma
Adds onboardingState JSONB column to Project; Prisma schema updated with onboardingState Json?.
Migration Tests
apps/backend/prisma/migrations/.../tests/default-and-updates.ts
Adds preMigration/postMigration tests inserting a Project and verifying update/read of onboardingState JSONB.
CRUD & Persistence
apps/backend/src/lib/projects.tsx, packages/stack-shared/src/interface/crud/projects.ts
Reads/writes onboardingState guarded by runtime column-existence checks; exposes onboarding_state in project read shape; adds projectOnboardingStateSchema and onboarding-related schema fields.
Local Emulator Helpers
apps/backend/src/lib/local-emulator.ts, apps/backend/src/lib/local-emulator.test.ts
Adds LOCAL_EMULATOR_SHOW_ONBOARDING_VALUE, readConfigContent/readConfigValueFromFile, isLocalEmulatorOnboardingEnabledInConfig, writeShowOnboardingConfigToFile; tests for show-onboarding behavior and non-.ts filenames.
Local Emulator Endpoint
apps/backend/src/app/api/.../local-emulator/project/route.tsx, apps/e2e/tests/backend/endpoints/api/v1/internal/local-emulator-project.test.ts
Endpoint now computes/synchronizes onboarding status via syncLocalEmulatorOnboardingStatus, returns onboarding_status and onboarding_outstanding; E2E tests added/updated for show-onboarding default, toggles, completion, and PATCHing onboarding_state.
Dashboard Integration
apps/dashboard/src/app/.../content.tsx, apps/dashboard/src/app/.../projects/page-client.tsx
Per-project onboarding state map, loader and PATCH mutator; navigation now driven by onboarding_status for emulator flows.
Onboarding Wizard Component & Tests
apps/dashboard/src/app/.../project-onboarding-wizard.tsx, .../project-onboarding-wizard.test.tsx, .../shared.ts
Introduces ProjectOnboardingState type, guard and helpers; wizard accepts onboardingState, setOnboardingState, clearOnboardingState, consolidates UI selections into persisted onboarding state, builds bulk config updates, and persists/clears state on finalize; tests updated to pass new props.

Authorization Header & Token Store API

Layer / File(s) Summary
Type Surface & RequestLike
packages/template/src/lib/stack-app/common.ts, sdks/spec/src/_utilities.spec.md, sdks/spec/src/types/users/current-user.spec.md, sdks/spec/src/apps/client-app.spec.md
AuthLike gains getAuthorizationHeader() and useAuthorizationHeader(); RequestLike.headers widened to accept { get(...) } or `Record<string,string
Client Impl & Header Utilities
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts, packages/template/src/lib/stack-app/apps/implementations/client-app-impl.oauth-prefetch.test.ts
Adds STACK_AUTHORIZATION_VALUE_PREFIX, helpers to encode/decode stackauth_<base64(...)> Authorization header, header-parsing utilities, token-store creation from Authorization header, and exposes header accessors on top-level and currentSession Auth objects; adds unit test for prefetch behavior.
Examples & Demo
examples/demo/src/app/tokens-demo/page.tsx
Demo updated to display/use getAuthorizationHeader/useAuthorizationHeader and related deprecated/alternate hooks.
Tests (E2E / Integration)
apps/e2e/tests/js/auth-like.test.ts
Adds parseAuthorizationHeaderValue helper and tests verifying Authorization header generation, parsing, and use via request-like tokenStore variants and record-style headers.

Config Authoring, CLI & Emulator UX

Layer / File(s) Summary
Config Typing
packages/stack-shared/src/config-authoring.ts, packages/stack-shared/src/config-authoring.test.ts
StackConfig extended to include sentinel show-onboarding value; StrictStackConfig made conditional to allow non-object sentinel; tests updated to include show-onboarding.
CLI Config Handling
packages/stack-cli/src/commands/config-file.ts
Introduces SHOW_ONBOARDING_STACK_CONFIG_VALUE, parseConfigOverride treating "show-onboarding" as a valid override (mapped to {}) and updates error messaging.
Emulator CLI & UX
packages/stack-cli/src/commands/emulator.ts
EmulatorCredentials extended with onboarding_status and onboarding_outstanding; adds EMULATOR_DASHBOARD_PORT resolution, localEmulatorDashboardBaseUrl(), and maybeOpenOnboardingPage() to optionally open onboarding dashboard when outstanding; start/run workflows updated to call onboarding helper and print compact credentials.
E2E Coverage
apps/e2e/tests/backend/endpoints/api/v1/internal/local-emulator-project.test.ts
Tests cover show-onboarding default generation, toggling onboarding via config file changes, completion behavior, and independent PATCH of onboarding_state without mutating env config.

Setup Prompt Generation & Docs

Layer / File(s) Summary
Prompt Constants & Generator Logic
packages/stack-shared/src/ai/prompts.ts, scripts/generate-setup-prompt-docs.ts
Adds prompt fragments and getSdkSetupPrompt(mainType) generator; new script composes per-tool metadata and writes generated artifacts: home-prompt-island.jsx (exports generatedSetupPromptText, setupToolIds, setupTabMetadata, GeneratedSetupPromptText) and docs-mintlify/guides/getting-started/setup.mdx.
Docs & UI Integration
docs-mintlify/index.mdx, docs-mintlify/snippets/home-prompt-island.jsx, docs-mintlify/sdk/types/user.mdx, docs/content/docs/sdk/types/user.mdx, docs/src/components/mdx/sdk-components.tsx
Replaces prior HomePromptIsland with generated agent-first setup UI and copy-to-clipboard action; docs updated to document getAuthorizationHeader()/useAuthorizationHeader() and mark legacy headers deprecated; MDX components and anchors updated.
Build Scripts
package.json
Adds generate-setup-prompt-docs script and watchers (generate-setup-prompt-docs:watch), integrates generation into codegen and dev/watch scripts.
Knowledge Base Changes
.claude/CLAUDE-KNOWLEDGE.md, claude/CLAUDE-KNOWLEDGE.md, AGENTS.md
Adds nine Q&A entries about test targeting, new Authorization header format and parsing shapes, emulator dashboard URL and onboarding behavior, ParseError handling for non-.ts configs, /api/v1/setup-prompt guidance, and Mintlify snippet guidance; path update for CLAUDE file recorded.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant Dashboard as Dashboard UI
    participant API as Backend API
    participant DB as Database
    participant LocalEmulator as Local Emulator

    User->>Dashboard: Start new project / open onboarding
    Dashboard->>API: POST /projects (create)
    API->>DB: Insert project (onboarding_state = null)
    DB-->>API: Project created
    API-->>Dashboard: Project + onboarding_state

    Dashboard->>User: Render wizard with onboardingState
    User->>Dashboard: Configure apps, auth, theme, payments
    Dashboard->>API: PATCH /projects/current onboarding_state
    API->>DB: Update Project.onboardingState (jsonb)
    DB-->>API: Updated
    API-->>Dashboard: Confirm update

    Dashboard->>API: Finalize -> apply branch config updates
    API->>DB: Persist environment config and onboarding_status = "completed"
    DB-->>API: Done
    API-->>Dashboard: Onboarding completed
Loading
sequenceDiagram
    participant Client as Client App
    participant Server as Server
    participant TokenStore as Token Store

    Client->>Client: call getAuthorizationHeader()
    Client->>TokenStore: getAuthJson() -> {accessToken, refreshToken}
    TokenStore-->>Client: tokens
    Client->>Client: base64Encode({accessToken,refreshToken})
    Client->>Client: prefix with "stackauth_" and "Bearer "
    Client->>Server: HTTP request with Authorization: Bearer stackauth_<base64>
    Server->>Server: parse Authorization header -> decode payload
    Server->>TokenStore: create request-like tokenStore from decoded tokens
    Server-->>Client: authenticated response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A Quick Rabbit Note on Onboarding

I hop through DB rows and config trees,
I tuck auth headers into tiny keys,
The wizard hums while prompts take flight,
New projects bloom from morning to night—
A carrot, a click, and the setup's done. 🎉

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch new-setup

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ff6a375. Configure here.

Comment thread apps/backend/src/lib/projects.tsx
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 6, 2026

Greptile Summary

This PR introduces a new setup/onboarding flow for the Stack Auth local emulator, including a show-onboarding sentinel config value, per-project onboarding_state persistence (new nullable JSONB column), a new Authorization: Bearer stackauth_<base64> header format for token forwarding, and a revamped multi-step onboarding wizard that defers all config application to the final step.

  • Local emulator onboarding: adds writeShowOnboardingConfigToFile, isLocalEmulatorOnboardingEnabledInConfig, syncLocalEmulatorOnboardingStatus, and the onboarding_status/onboarding_outstanding fields on the POST response; the CLI and dashboard route users to the wizard when onboarding is outstanding.
  • Onboarding state persistence: wizard now calls persistOnboardingState at each step transition so progress survives page reloads; finalizeOnboarding applies all branch/environment config changes in one shot at the end.
  • getAuthorizationHeader API: new Bearer stackauth_<base64(authJson)> header format is added to the client app, with request-like tokenStore parsing (both Headers and record-style) and accompanying e2e tests.

Confidence Score: 3/5

The onboarding wizard and local-emulator credential flow are safe in non-emulator environments, but every persistOnboardingState PATCH call from the wizard will produce a 500 in local emulator mode, making the core new feature unusable.

overrideEnvironmentConfigOverride is called unconditionally with an empty configOverrideOverride when only onboarding_state is patched; setEnvironmentConfigOverride throws for all local emulator projects regardless of whether the override object is empty. The CLAUDE-KNOWLEDGE note added in this PR documents the fix but the guard is not present in the code. Migration, schema additions, auth header implementation, and wizard UI restructuring are all correct.

apps/backend/src/lib/projects.tsx — the unconditional overrideEnvironmentConfigOverride call at line 317 needs a guard checking Object.keys(configOverrideOverride).length > 0 before this is usable in local emulator mode

Important Files Changed

Filename Overview
apps/backend/src/lib/projects.tsx Adds onboarding_state column read/write and extends column-existence checks; unconditional call to overrideEnvironmentConfigOverride with an empty object breaks local-emulator PATCH for onboarding_state-only updates
apps/backend/src/app/api/latest/internal/local-emulator/project/route.tsx Adds syncLocalEmulatorOnboardingStatus logic to read/write onboarding status and expose onboarding_status + onboarding_outstanding in POST response; guards onboardingState column writes when the column may not yet exist
apps/backend/src/lib/local-emulator.ts Introduces show-onboarding config sentinel value, writeShowOnboardingConfigToFile, isLocalEmulatorOnboardingEnabledInConfig, and fixes non-.ts extension evaluation via evalFilename fallback
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts Adds ProjectOnboardingState type, isProjectOnboardingState guard, normalizeProjectOnboardingState, and createProjectOnboardingState helpers
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx Defers all config application to finalizeOnboarding and persists onboarding state incrementally at each step; adds local-emulator-specific UI branch
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsx Tracks per-project onboarding state; adds setSelectedProjectOnboardingState helper; conditions local-emulator selector on selectedProjectId == null
apps/e2e/tests/backend/endpoints/api/v1/internal/local-emulator-project.test.ts Adds tests for show-onboarding sentinel toggling and onboarding_state PATCH; the state-only PATCH test would fail due to the missing guard in projects.tsx
apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/migration.sql Adds nullable JSONB onboardingState column to Project table; safe for existing rows
apps/e2e/tests/js/auth-like.test.ts Adds comprehensive tests for getAuthorizationHeader (Bearer stackauth_ format), record-style and Headers-style tokenStore
packages/stack-shared/src/interface/crud/projects.ts Adds projectOnboardingStateSchema and onboarding_state nullable-optional field to admin read/write schemas

Sequence Diagram

sequenceDiagram
    participant CLI as stack-cli emulator run
    participant BE as Backend /internal/local-emulator/project
    participant DB as Database
    participant DASH as Dashboard /new-project

    CLI->>BE: POST (absolute_file_path)
    BE->>BE: readConfigContent(file)
    alt config === show-onboarding
        BE->>DB: syncLocalEmulatorOnboardingStatus(showOnboarding=true)
        DB-->>BE: onboardingStatus = config_choice
    else config is object
        BE->>DB: syncLocalEmulatorOnboardingStatus(showOnboarding=false)
        DB-->>BE: onboardingStatus = completed
    end
    BE-->>CLI: project_id, onboarding_status, onboarding_outstanding

    alt onboarding_outstanding === true
        CLI->>DASH: redirect /new-project?project_id=...
        DASH->>DASH: ProjectOnboardingWizard (multi-step)
        loop Each step
            DASH->>BE: PATCH /internal/projects/current onboarding_state
            BE->>DB: UPDATE Project SET onboardingState
        end
        DASH->>BE: finalizeOnboarding updateConfig branch + env
        DASH->>BE: PATCH onboarding_status completed onboarding_state null
    else
        CLI->>DASH: open existing project dashboard
    end
Loading

Comments Outside Diff (1)

  1. apps/backend/src/lib/projects.tsx, line 317-321 (link)

    P1 Missing guard causes 500 in local emulator on onboarding-state-only PATCH

    overrideEnvironmentConfigOverride is called unconditionally even when configOverrideOverride is an empty {}. In local emulator mode, setEnvironmentConfigOverride (called internally) checks isLocalEmulatorProject and unconditionally throws LOCAL_EMULATOR_ENV_CONFIG_BLOCKED_MESSAGE — it has no short-circuit for an empty override object.

    This means that PATCH /api/v1/internal/projects/current with only onboarding_state (no config fields) will always fail with a 500 in local emulator mode, because filterUndefined({...options.data.config}) yields {} and the guard is never hit. The new e2e test "updates onboarding_state on local emulator projects without mutating env config" (which expects status: 200) will fail because of this. The CLAUDE-KNOWLEDGE note added in this PR also explicitly identifies the fix: skip overrideEnvironmentConfigOverride unless configOverrideOverride has at least one key.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/backend/src/lib/projects.tsx
    Line: 317-321
    
    Comment:
    **Missing guard causes 500 in local emulator on onboarding-state-only PATCH**
    
    `overrideEnvironmentConfigOverride` is called unconditionally even when `configOverrideOverride` is an empty `{}`. In local emulator mode, `setEnvironmentConfigOverride` (called internally) checks `isLocalEmulatorProject` and unconditionally throws `LOCAL_EMULATOR_ENV_CONFIG_BLOCKED_MESSAGE` — it has no short-circuit for an empty override object.
    
    This means that `PATCH /api/v1/internal/projects/current` with only `onboarding_state` (no `config` fields) will always fail with a 500 in local emulator mode, because `filterUndefined({...options.data.config})` yields `{}` and the guard is never hit. The new e2e test `"updates onboarding_state on local emulator projects without mutating env config"` (which expects `status: 200`) will fail because of this. The CLAUDE-KNOWLEDGE note added in this PR also explicitly identifies the fix: skip `overrideEnvironmentConfigOverride` unless `configOverrideOverride` has at least one key.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/backend/src/lib/projects.tsx:317-321
**Missing guard causes 500 in local emulator on onboarding-state-only PATCH**

`overrideEnvironmentConfigOverride` is called unconditionally even when `configOverrideOverride` is an empty `{}`. In local emulator mode, `setEnvironmentConfigOverride` (called internally) checks `isLocalEmulatorProject` and unconditionally throws `LOCAL_EMULATOR_ENV_CONFIG_BLOCKED_MESSAGE` — it has no short-circuit for an empty override object.

This means that `PATCH /api/v1/internal/projects/current` with only `onboarding_state` (no `config` fields) will always fail with a 500 in local emulator mode, because `filterUndefined({...options.data.config})` yields `{}` and the guard is never hit. The new e2e test `"updates onboarding_state on local emulator projects without mutating env config"` (which expects `status: 200`) will fail because of this. The CLAUDE-KNOWLEDGE note added in this PR also explicitly identifies the fix: skip `overrideEnvironmentConfigOverride` unless `configOverrideOverride` has at least one key.

Reviews (1): Last reviewed commit: "Setup builder" | Re-trigger Greptile

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new “setup prompt” doc generation flow for Mintlify, adds a recommended token-forwarding mechanism via an Authorization: Bearer stackauth_<base64(...)> header (deprecating legacy x-stack-auth headers), and extends local-emulator onboarding to persist/restore onboarding progress via a new Project.onboardingState field.

Changes:

  • Add getAuthorizationHeader() / useAuthorizationHeader() APIs and update request-like tokenStore parsing to prefer Authorization with stackauth_ payload, falling back to legacy x-stack-auth and then cookies.
  • Add local-emulator onboarding UX improvements (auto-open onboarding when pending) and persist onboarding progress to Project.onboardingState (DB + schemas + dashboard wizard).
  • Add an auto-generated Mintlify “setup prompt” UI and a generator script wired into codegen/dev workflows.

Reviewed changes

Copilot reviewed 36 out of 47 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
sdks/spec/src/types/users/current-user.spec.md Spec: document getAuthorizationHeader() and deprecate getAuthHeaders().
sdks/spec/src/apps/client-app.spec.md Spec: document app-level getAuthorizationHeader(options?) and deprecate getAuthHeaders(options?).
sdks/spec/src/_utilities.spec.md Spec: describe preferred Authorization header format and legacy x-stack-auth fallback.
scripts/generate-setup-prompt-docs.ts New generator writing Mintlify setup prompt snippet + setup guide MDX.
packages/template/src/lib/stack-app/common.ts Extend RequestLike headers shape and add getAuthorizationHeader() to AuthLike; deprecate getAuthHeaders().
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts Implement Authorization header generation/parsing; prefer Authorization header in request-like tokenStore; remove constructor prefetch call.
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.oauth-prefetch.test.ts Regression test ensuring no prefetch on construction.
packages/stack-shared/src/interface/crud/projects.ts Add onboarding_state schema for admin read/update.
packages/stack-shared/src/config-authoring.ts Allow StackConfig sentinel "show-onboarding" for local emulator onboarding.
packages/stack-shared/src/config-authoring.test.ts Type-level + runtime assertions for "show-onboarding" StackConfig.
packages/stack-shared/src/ai/prompts.ts New canonical setup prompt content source used by generator/docs.
packages/stack-cli/src/commands/emulator.ts Open onboarding page when emulator reports onboarding is pending; add dashboard port/env handling.
packages/stack-cli/src/commands/config-file.ts Accept config sentinel "show-onboarding" and treat as empty override.
package.json Wire generator into codegen and dev watchers; add cli helper script.
examples/demo/src/app/tokens-demo/page.tsx Demo: display new authorization header helpers; mark legacy headers as deprecated.
docs/src/components/mdx/sdk-components.tsx Update docs link to getAuthorizationHeader() section.
docs/content/docs/sdk/types/user.mdx Docs: add getAuthorizationHeader() and mark getAuthHeaders() as deprecated.
docs-mintlify/snippets/home-prompt-island.jsx Replace hand-written snippet with generated setup prompt exports.
docs-mintlify/sdk/types/user.mdx Mintlify docs: add authorization header methods + deprecation text for legacy headers.
docs-mintlify/index.mdx Update homepage to use generated setup prompt snippet/exports.
docs-mintlify/images/setup-tools/tanstack.svg Add TanStack logo for setup tool cards.
docs-mintlify/images/setup-tools/supabase.svg Add Supabase logo for setup tool cards.
docs-mintlify/images/setup-tools/react.svg Add React logo for setup tool cards.
docs-mintlify/images/setup-tools/nodejs.svg Add Node.js logo for setup tool cards.
docs-mintlify/images/setup-tools/nextjs.svg Add Next.js logo for setup tool cards.
docs-mintlify/images/setup-tools/mcp.svg Add MCP logo for setup tool cards.
docs-mintlify/images/setup-tools/javascript.svg Add JavaScript logo for setup tool cards.
docs-mintlify/images/setup-tools/convex.svg Add Convex logo for setup tool cards.
docs-mintlify/images/setup-tools/cli.svg Add CLI (bash) logo for setup tool cards.
docs-mintlify/images/setup-tools/bun.svg Add Bun logo for setup tool cards.
claude/CLAUDE-KNOWLEDGE.md Add internal notes about setup prompt generation and Mintlify constraints.
apps/e2e/tests/js/auth-like.test.ts E2E: verify Authorization header round-trip + request-like parsing (Headers + record-style).
apps/e2e/tests/backend/endpoints/api/v1/internal/local-emulator-project.test.ts E2E: validate onboarding status/outstanding + show-onboarding config behavior + onboarding_state patch.
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/projects/page-client.tsx Route emulator-created projects to onboarding when not completed.
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts Define/validate/normalize ProjectOnboardingState.
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx Persist onboarding state; local-emulator behavior tweaks; centralize config updates at finalize.
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx Update wizard test wiring for new env + onboarding state props.
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsx Fetch/store onboarding_state; PATCH onboarding_state; pass into wizard.
apps/backend/src/lib/projects.tsx Read/return onboarding_state; write onboardingState JSONB when supported.
apps/backend/src/lib/local-emulator.ts Add "show-onboarding" sentinel support; write sentinel config; non-TS filename eval workaround.
apps/backend/src/lib/local-emulator.test.ts Tests for sentinel parsing/writing and non-TS evaluation behavior.
apps/backend/src/app/api/latest/internal/local-emulator/project/route.tsx Return onboarding status/outstanding; seed empty files with show-onboarding; sync DB onboarding status.
apps/backend/prisma/schema.prisma Add onboardingState Json? to Project model.
apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/tests/default-and-updates.ts Migration test: default null + JSONB update round-trip.
apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/migration.sql Migration: add Project.onboardingState JSONB column.
.claude/CLAUDE-KNOWLEDGE.md Add repo-wide notes on auth header format, RequestLike header shapes, emulator ports, and onboarding_state pitfalls.
Comments suppressed due to low confidence (1)

packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts:613

  • After removing the constructor call to _prefetchCrossDomainHandoffParamsIfNeeded(), that method no longer has any call sites (it’s only referenced by _getCrossDomainHandoffParamsForUrlsGetter, which itself isn’t used). This makes the noAutomaticPrefetch option/documentation misleading and leaves dead prefetch code paths. Either reintroduce prefetch behind !noAutomaticPrefetch (if still desired) or remove/update the unused helpers and option docs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/stack-shared/src/ai/prompts.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/src/components/mdx/sdk-components.tsx (1)

133-133: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Debug position metadata leaks into production via title tooltip

The title attribute includes (pos: ${topPosition}px, height: ${height}px) which appears as a browser tooltip when users hover over any clickable code line. The position values are implementation details that serve no user-facing purpose.

🛠 Proposed fix
-                  title={`Line ${area.lineNumber + 1}: ${area.anchor} (pos: ${topPosition}px, height: ${height}px)`}
+                  title={`Go to ${area.anchor}`}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/src/components/mdx/sdk-components.tsx` at line 133, The title tooltip
currently includes internal layout metadata (pos/height) and should not be
exposed; update the title string construction (where title={`Line
${area.lineNumber + 1}: ${area.anchor} (pos: ${topPosition}px, height:
${height}px)`} is created) to omit topPosition and height—e.g. use only `Line
${area.lineNumber + 1}: ${area.anchor}` or, if you need the metadata for
debugging, include it conditionally behind a dev-only flag (check NODE_ENV) so
only area.lineNumber and area.anchor are used in production tooltips.
packages/stack-cli/src/commands/emulator.ts (1)

86-99: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Silent defaulting masks backend contract breakage.

If a backend mismatch returns onboarding_status as a non-string or onboarding_outstanding as a non-boolean, the current code silently coerces them to "completed" / derived-false. That is exactly the failure mode the coding guidelines warn about ("NEVER just silently use fallback values… either update the types or throw an error"), and in this case it would skip opening the onboarding URL when the backend actually wanted to show onboarding — a real user-impacting regression that's hard to spot.

Either keep the fallback only for missing fields (with a deliberate justification comment) or throwErr(...) when the type is unexpectedly wrong. The runtime check on line 93 is correctly strict for the credential fields — apply the same rigor here.

🛡️ Suggested tightening
-  const onboardingStatus = typeof data.onboarding_status === "string" ? data.onboarding_status : "completed";
-  const onboardingOutstanding = typeof data.onboarding_outstanding === "boolean"
-    ? data.onboarding_outstanding
-    : onboardingStatus !== "completed";
+  if (data.onboarding_status !== undefined && typeof data.onboarding_status !== "string") {
+    throw new CliError("Local emulator project endpoint returned a non-string onboarding_status.");
+  }
+  if (data.onboarding_outstanding !== undefined && typeof data.onboarding_outstanding !== "boolean") {
+    throw new CliError("Local emulator project endpoint returned a non-boolean onboarding_outstanding.");
+  }
+  // Defaults retained for older backends that don't return onboarding fields yet.
+  const onboardingStatus = data.onboarding_status ?? "completed";
+  const onboardingOutstanding = data.onboarding_outstanding ?? (onboardingStatus !== "completed");

As per coding guidelines: "NEVER just silently use fallback values when you don't know how to fix type errors. If there is a state that should never happen, either update the types or throw an error."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stack-cli/src/commands/emulator.ts` around lines 86 - 99, The code
currently silently coerces bad types for
onboarding_status/onboarding_outstanding; change the runtime checks so they
either accept a missing field (undefined) and apply a deliberate default, but
throw a CliError when the field is present with the wrong type. Concretely,
replace the onboardingStatus/onboardingOutstanding assignments so they do: if
(data.onboarding_status === undefined) set default "completed"; else if (typeof
data.onboarding_status !== "string") throw new CliError("Invalid
onboarding_status from emulator"); similarly for data.onboarding_outstanding: if
undefined use derived boolean, else if typeof !== "boolean" throw new
CliError("Invalid onboarding_outstanding from emulator"). Use the existing data,
onboardingStatus and onboardingOutstanding symbols and follow the same
strictness used for the credential checks.
🧹 Nitpick comments (11)
packages/stack-cli/src/commands/config-file.ts (1)

10-10: ⚡ Quick win

Reuse the exported sentinel from stack-shared instead of redefining it.

showOnboardingStackConfigValue is exported from packages/stack-shared/src/config-authoring.ts specifically to be the single source of truth for this literal. Defining a duplicate copy here risks silent drift—a typo or future rename in either place would compile fine but break the contract on one side.

♻️ Proposed fix
+import { showOnboardingStackConfigValue } from "@stackframe/stack-shared/dist/config-authoring";
 import { detectImportPackageFromDir, renderConfigFileContent } from "@stackframe/stack-shared/dist/config-rendering";
-
-const SHOW_ONBOARDING_STACK_CONFIG_VALUE = "show-onboarding";
 function parseConfigOverride(value: unknown): EnvironmentConfigOverrideOverride | null {
-  if (value === SHOW_ONBOARDING_STACK_CONFIG_VALUE) {
+  if (value === showOnboardingStackConfigValue) {
     return {};
   }
   return isConfigOverride(value) ? value : null;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stack-cli/src/commands/config-file.ts` at line 10, Replace the local
sentinel constant SHOW_ONBOARDING_STACK_CONFIG_VALUE with the canonical exported
value showOnboardingStackConfigValue from the stack-shared module: remove the
duplicate const declaration in config-file.ts, add an import for
showOnboardingStackConfigValue from the shared package, and update any
references (uses of SHOW_ONBOARDING_STACK_CONFIG_VALUE) to use
showOnboardingStackConfigValue so the project uses the single source of truth
exported by config-authoring.ts.
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts (1)

10-11: ⚡ Quick win

Type definitions duplicate backend schema constants (downstream of projects.ts)

OnboardingConfigChoice and OnboardingPaymentsCountry manually re-state the allowed values from onboardingConfigChoiceValues / onboardingPaymentsCountryValues in packages/stack-shared/.../projects.ts. The fix is on the shared-package side (export those const arrays); once exported, these types can be derived: type OnboardingConfigChoice = typeof onboardingConfigChoiceValues[number].

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts
around lines 10 - 11, The types OnboardingConfigChoice and
OnboardingPaymentsCountry duplicate allowed-value lists; instead export the
const arrays onboardingConfigChoiceValues and onboardingPaymentsCountryValues
from the shared projects.ts and derive the types from them (e.g., type
OnboardingConfigChoice = typeof onboardingConfigChoiceValues[number]); update
the file to import those const arrays and replace the manual string-union type
declarations with derived types, and remove the duplicated literal definitions.
packages/stack-shared/src/interface/crud/projects.ts (1)

35-45: ⚡ Quick win

Unexported constants and schema cause silent type divergence in the dashboard

onboardingConfigChoiceValues, onboardingSignInMethodValues, onboardingPaymentsCountryValues, and projectOnboardingStateSchema are all unexported. As a result, apps/dashboard/.../shared.ts manually re-declares equivalent types (OnboardingConfigChoice, OnboardingPaymentsCountry, SignInMethod, ProjectOnboardingState) and duplicates the validation logic in isProjectOnboardingState(). If any allowed value is added or removed here (e.g., a new payments country), shared.ts silently diverges.

Exporting the value arrays lets the dashboard import them and derive its union types rather than hard-coding them:

♻️ Proposed fix
-const onboardingConfigChoiceValues = ["create-new", "link-existing"] as const;
-const onboardingSignInMethodValues = ["credential", "magicLink", "passkey", "google", "github", "microsoft"] as const;
-const onboardingPaymentsCountryValues = ["US", "OTHER"] as const;
-
-const projectOnboardingStateSchema = yupObject({
+export const onboardingConfigChoiceValues = ["create-new", "link-existing"] as const;
+export const onboardingSignInMethodValues = ["credential", "magicLink", "passkey", "google", "github", "microsoft"] as const;
+export const onboardingPaymentsCountryValues = ["US", "OTHER"] as const;
+
+export const projectOnboardingStateSchema = yupObject({

Then in apps/dashboard/.../shared.ts, replace the manual type declarations:

-export type OnboardingConfigChoice = "create-new" | "link-existing";
-export type OnboardingPaymentsCountry = "US" | "OTHER";
+import { onboardingConfigChoiceValues, onboardingPaymentsCountryValues } from "@stackframe/stack-shared/dist/interface/crud/projects";
+export type OnboardingConfigChoice = typeof onboardingConfigChoiceValues[number];
+export type OnboardingPaymentsCountry = typeof onboardingPaymentsCountryValues[number];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stack-shared/src/interface/crud/projects.ts` around lines 35 - 45,
Export the unexported constants and schema so other packages can derive types
instead of duplicating values: export onboardingConfigChoiceValues,
onboardingSignInMethodValues, onboardingPaymentsCountryValues, and
projectOnboardingStateSchema from this module; then consumers (e.g.,
apps/dashboard/.../shared.ts) should import those symbols and derive union types
like OnboardingConfigChoice = typeof onboardingConfigChoiceValues[number] and
SignInMethod = typeof onboardingSignInMethodValues[number], and use the imported
projectOnboardingStateSchema in isProjectOnboardingState rather than
re-declaring validation logic.
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.oauth-prefetch.test.ts (1)

6-11: ⚡ Quick win

Harden the test against silent passes if the method is renamed.

If _prefetchCrossDomainHandoffParamsIfNeeded is ever renamed or moved off the prototype, originalPrefetch becomes undefined, the override is never invoked, and prefetchCalls stays at 0 — so the test passes without actually exercising the no-prefetch guard. A quick existence check up-front prevents that.

♻️ Suggested change
   const prefetchMethodName = "_prefetchCrossDomainHandoffParamsIfNeeded";
   const originalPrefetch = Reflect.get(StackClientApp.prototype, prefetchMethodName);
+  expect(typeof originalPrefetch).toBe("function");
   let prefetchCalls = 0;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/template/src/lib/stack-app/apps/implementations/client-app-impl.oauth-prefetch.test.ts`
around lines 6 - 11, The test currently assumes the method name
"_prefetchCrossDomainHandoffParamsIfNeeded" exists on StackClientApp.prototype;
add an explicit assertion/check that Reflect.get(StackClientApp.prototype,
prefetchMethodName) is defined before overriding to avoid silent passes if it
was renamed or moved, and ensure you still restore the original
(originalPrefetch) after the test; reference prefetchMethodName,
originalPrefetch, StackClientApp.prototype and prefetchCalls when implementing
the existence check and cleanup.
apps/backend/src/lib/local-emulator.ts (2)

109-143: ⚡ Quick win

Duplicate host-mount/mkdir scaffolding between writeConfigToFile and writeShowOnboardingConfigToFile.

Lines 110–121 and 128–139 are byte-identical except for the eventual content written. Extracting a small helper (e.g., prepareEmulatorWriteDir(filePath) that returns { resolvedPath, dir } after handling host mount/mkdir) keeps the two write paths in sync if the filesystem semantics ever change again.

♻️ Sketch
async function prepareEmulatorWriteDir(filePath: string): Promise<{ resolvedPath: string; dir: string }> {
  const resolvedPath = resolveEmulatorPath(filePath);
  const dir = path.dirname(resolvedPath);
  const hostMountRoot = getEnvVariable(LOCAL_EMULATOR_HOST_MOUNT_ROOT_ENV, "");
  if (hostMountRoot) {
    try {
      await fs.access(dir);
    } catch {
      throw new Error(`Local emulator host mount root ${hostMountRoot} is configured but the parent directory for ${filePath} is not available at ${dir}. Ensure the host filesystem is mounted correctly.`);
    }
  } else {
    await fs.mkdir(dir, { recursive: true });
  }
  return { resolvedPath, dir };
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/src/lib/local-emulator.ts` around lines 109 - 143, There is
duplicated host-mount/mkdir scaffolding in writeConfigToFile and
writeShowOnboardingConfigToFile; extract that logic into a helper (e.g.,
prepareEmulatorWriteDir(filePath): Promise<{ resolvedPath: string; dir: string
}>) which calls resolveEmulatorPath and handles
LOCAL_EMULATOR_HOST_MOUNT_ROOT_ENV, fs.access and fs.mkdir, throws the same
error message on missing host mount, and returns { resolvedPath, dir }; then
replace the duplicated blocks in writeConfigToFile and
writeShowOnboardingConfigToFile to call prepareEmulatorWriteDir and proceed to
detectImportPackageFromDir and write the file content.

67-75: ⚡ Quick win

Use e: unknown with narrowing instead of e: any.

Per coding guidelines, any should be avoided unless commented; here unknown plus a typed narrow is straightforward.

♻️ Suggested fix
-  try {
-    return await fs.readFile(resolvedPath, "utf-8");
-  } catch (e: any) {
-    if (e?.code === "ENOENT") {
-      return "";
-    }
-    throw e;
-  }
+  try {
+    return await fs.readFile(resolvedPath, "utf-8");
+  } catch (e: unknown) {
+    if ((e as NodeJS.ErrnoException | undefined)?.code === "ENOENT") {
+      return "";
+    }
+    throw e;
+  }

As per coding guidelines: "Try to avoid the any type. Whenever you need to use any, leave a comment explaining why you're using it".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/src/lib/local-emulator.ts` around lines 67 - 75, Change the
catch parameter from "e: any" to "e: unknown" and narrow it before checking the
error code: implement a small type guard (e.g. isErrnoException(e: unknown): e
is NodeJS.ErrnoException) or check typeof e === 'object' && e !== null && 'code'
in e, then test (e as NodeJS.ErrnoException).code === 'ENOENT'; update the catch
in the function that reads fs.readFile (uses resolvedPath and fs.readFile) to
use this narrowing and only throw e after narrowing.
apps/e2e/tests/backend/endpoints/api/v1/internal/local-emulator-project.test.ts (1)

221-260: 💤 Low value

Consider asserting onboarding_outstanding flips after the PATCH.

The selected_config_choice: "create-new" field suggests an in-progress onboarding step has been recorded, but the test only asserts the echoed onboarding_state. Adding follow-up GET on /api/v1/internal/projects/current (or another POST to the local-emulator endpoint) to check whether onboarding_status/onboarding_outstanding move appropriately would lock in the contract between PATCH and the local-emulator endpoint that downstream code (e.g., maybeOpenOnboardingPage in packages/stack-cli/src/commands/emulator.ts) relies on.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/e2e/tests/backend/endpoints/api/v1/internal/local-emulator-project.test.ts`
around lines 221 - 260, The test updates onboarding_state but doesn't assert
that onboarding_outstanding/onboarding_status changed; after the PATCH to
"/api/v1/internal/projects/current" (inside the it.runIf block), add a follow-up
fetch to the same project current endpoint (or re-call
LOCAL_EMULATOR_PROJECT_ENDPOINT) to retrieve the project and assert that the
onboarding_outstanding (and/or onboarding_status) value flipped as expected;
locate the calls to niceBackendFetch and the constant
LOCAL_EMULATOR_PROJECT_ENDPOINT in this test to insert the GET and assertions so
the contract between the PATCH and local-emulator behavior is validated.
packages/stack-cli/src/commands/emulator.ts (1)

117-132: 💤 Low value

Catch-all hides real cross-platform issues.

openUrlInBrowser swallows every error from execFileSync, so missing xdg-open on Linux, mis-set DISPLAY, or cmd quoting issues all collapse into a single false. That's acceptable best-effort behavior, but per coding guidelines try-catch-all should at least be explained. Consider narrowing or adding a // best-effort: … comment plus, if cheap, logging the underlying error at debug level so users on broken environments have a breadcrumb.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stack-cli/src/commands/emulator.ts` around lines 117 - 132, The
try-catch in openUrlInBrowser currently swallows all errors from execFileSync
across platforms; update the function to (1) narrow or annotate the catch by
adding a brief "// best-effort: open native browser; swallow errors but keep
breadcrumb" comment above the try-catch, and (2) where a logger is available (or
attach debug logging), log the caught error at debug/trace level inside the
catch so missing xdg-open, DISPLAY issues, or cmd quoting problems are recorded;
reference the function openUrlInBrowser and the execFileSync calls for placement
and ensure the function still returns boolean false on failure.
scripts/generate-setup-prompt-docs.ts (1)

297-345: ⚡ Quick win

Duplicated generated exports between home-prompt-island.jsx and setup.mdx.

generatedSetupPromptText, setupToolIds, setupTabMetadata, unifiedAiPromptTabTitle, and copyGeneratedSetupPrompt are emitted into both docs-mintlify/snippets/home-prompt-island.jsx (lines 282–285) and docs-mintlify/guides/getting-started/setup.mdx (lines 308–320). index.mdx already imports from /snippets/home-prompt-island.jsx; the setup MDX could import the same module instead of re-embedding the (~10KB) prompt text and the helper. This keeps a single source of truth and avoids two copies of the same prompt drifting in the docs bundle.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/generate-setup-prompt-docs.ts` around lines 297 - 345, The generated
setup.mdx duplicates exported symbols and helper code that already live in
docs-mintlify/snippets/home-prompt-island.jsx (generatedSetupPromptText,
setupToolIds, setupTabMetadata, unifiedAiPromptTabTitle,
copyGeneratedSetupPrompt); remove those duplicated export blocks from the
template produced in scripts/generate-setup-prompt-docs.ts and instead emit an
import line in setup.mdx that imports those symbols from
/snippets/home-prompt-island.jsx, leaving only setup-specific helpers (e.g.,
getSelectedSetupToolIdsFromUrl, writeSelectedSetupToolIdsToUrl) in the generated
file; update the template in writeFileSyncIfChanged to stop
JSON.stringify-embedding those symbols and to reference the imported names so
the docs use the single source of truth.
apps/backend/src/lib/projects.tsx (1)

113-130: ⚡ Quick win

Mark this schema-compat probe for next-release cleanup.

These information_schema.columns checks are clearly a temporary migration bridge. Please leave a // TODO next-release here so this path gets removed once every environment has the new columns.

Based on learnings: "Adopt the convention // TODO next-release in this codebase for temporary backward-compat shims that only need to survive one release."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/src/lib/projects.tsx` around lines 113 - 130, Add a one-line
TODO comment marked "// TODO next-release" immediately above the temporary
schema-compat probe where onboardingColumnExistsRows is computed (the
information_schema.columns queries) so the migration bridge is clearly flagged
for removal; update the code near the usages of onboardingStatusColumnExists and
onboardingStateColumnExists to keep the comment visible and referential to that
probe.
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx (1)

280-332: 💤 Low value

Optional: dedupe the OAuth provider build logic.

buildBranchConfigUpdate (local-only branch) and buildEnvironmentOAuthConfigUpdate repeat the same three-provider boilerplate. A small helper would reduce drift risk if a fourth provider (or another flag) is added later.

♻️ Sketch
const OAUTH_PROVIDER_IDS = ["google", "github", "microsoft"] as const;

const oauthProviderEntry = (id: typeof OAUTH_PROVIDER_IDS[number], opts: { isShared: boolean }) =>
  signInMethods.has(id)
    ? {
        type: id,
        ...(opts.isShared ? { isShared: true } : {}),
        allowSignIn: true,
        allowConnectedAccounts: true,
      }
    : null;

Then both builders iterate OAUTH_PROVIDER_IDS and call this helper with the appropriate isShared flag.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx
around lines 280 - 332, The code duplicates OAuth provider objects in
buildBranchConfigUpdate and buildEnvironmentOAuthConfigUpdate; extract a small
helper (e.g., OAUTH_PROVIDER_IDS and oauthProviderEntry) that, given a provider
id and an options object { isShared: boolean }, returns the provider object or
null, then have both buildBranchConfigUpdate and
buildEnvironmentOAuthConfigUpdate iterate OAUTH_PROVIDER_IDS to assign
"auth.oauth.providers.<id>" using oauthProviderEntry(id, { isShared: false })
for the local/emulator branch and oauthProviderEntry(id, { isShared: true }) for
the environment builder; update the builders to use this helper (and adjust
their dependency arrays if they reference any new outer variables).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/backend/src/app/api/latest/internal/local-emulator/project/route.tsx`:
- Around line 309-313: The current code calls writeShowOnboardingConfigToFile as
soon as the file is empty, mutating user config before the request completes;
change the flow so you do not modify the user's file until the entire request
finishes successfully (after owner/team readiness, project creation, onboarding
sync, and credential provisioning). Concretely, remove the immediate call to
writeShowOnboardingConfigToFile in the route handler where
resolvedFilePath/absoluteFilePath are checked, and instead invoke
writeShowOnboardingConfigToFile (or perform an atomic temp-file write+rename)
only after the final success path in this route (the route handler/exported
function) completes without errors. Ensure the same unique symbols
(writeShowOnboardingConfigToFile, resolvedFilePath, absoluteFilePath, and the
route handler) are used when relocating the write so the intent is clear.

In `@apps/backend/src/lib/local-emulator.ts`:
- Around line 77-94: Wrap the call to jiti.evalModule inside
readConfigValueFromFile in a try/catch so any syntax/runtime errors from
evaluating the user's stack.config.ts are converted into a StatusError with
BadRequest; specifically catch errors around jiti.evalModule(content, {
filename: evalFilename }) in readConfigValueFromFile and rethrow new
StatusError(StatusError.BadRequest, `Error evaluating config: ${err.message}`)
(preserve the original error message), then continue with the existing config
validation logic (references: function readConfigValueFromFile, variable jiti,
call jiti.evalModule, constant LOCAL_EMULATOR_SHOW_ONBOARDING_VALUE, and
isValidConfig).

In
`@apps/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/projects/page-client.tsx:
- Around line 175-180: Replace the current fallback behavior that sets
onboardingStatus to "completed" with the same strict validation used by the
sibling /internal/projects path: read onboardingStatus from responseBody (using
the existing "onboarding_status" key check), and if it's missing or not valid
per isProjectOnboardingStatus, throw an Error (similar message to the other
branch) instead of defaulting; update the logic around the onboardingStatus
variable and the isProjectOnboardingStatus check to perform a throw on
invalid/missing values (use the existing function names onboardingStatus,
responseBody, and isProjectOnboardingStatus to locate and modify the code).

In `@apps/e2e/tests/js/auth-like.test.ts`:
- Around line 272-293: The test uses non-null assertions (authorizationHeader!)
after toBeDefined()/not.toBeNull(); replace them with explicit null-guard
checks: after calling clientApp.getAuthorizationHeader() assert/throw if
authorizationHeader is null/undefined with a clear message, then proceed to call
parseAuthorizationHeaderValue(authorizationHeader), clientApp.getAuthJson(),
construct requestLike and call serverApp.getUser({ tokenStore: requestLike });
update expectations to use the guarded variable (authorizationHeader) rather
than the `!` operator to satisfy the defensive coding guideline.

In `@docs-mintlify/index.mdx`:
- Around line 18-25: The copyGeneratedSetupPrompt handler currently awaits
navigator.clipboard.writeText without error handling and silently swallows
rejections; update the copyGeneratedSetupPrompt function to wrap the clipboard
write in try/catch (or call the project's runAsynchronouslyWithAlert helper) and
set explicit UI states: set a loading state on the button while copying, on
success set text to "Copied" as now, on failure set the button to an error state
(e.g., "Copy failed") and optionally trigger an alert/notification; ensure you
still restore the original "Copy prompt" label after a timeout and reference the
existing generatedSetupPromptText, event.currentTarget/button text updates, and
the copyGeneratedSetupPrompt function when making the change.

In `@docs-mintlify/sdk/types/user.mdx`:
- Around line 672-691: Update the docs for getAuthorizationHeader and
useAuthorizationHeader to stop pointing readers to the deprecated getAuthJson():
replace the sentence "If you are not using HTTP, use getAuthJson() instead."
with guidance to use the non-deprecated token APIs (e.g., call getAccessToken()
and getRefreshToken() as appropriate) or remove the non-HTTP guidance entirely;
ensure both CurrentUserSection entries for getAuthorizationHeader and
useAuthorizationHeader reference getAccessToken/getRefreshToken (or omit the
line) and do not mention getAuthJson().

In `@docs-mintlify/snippets/home-prompt-island.jsx`:
- Around line 8-14: The GeneratedSetupPromptText component renders a readOnly
<textarea> without an accessible label; update the generator in
scripts/generate-setup-prompt-docs.ts (around the block that outputs
GeneratedSetupPromptText / generatedSetupPromptText) to include an accessible
label for the textarea—either add a visible <label> tied to the textarea id or
add a clear aria-label/aria-labelledby attribute—so the produced
GeneratedSetupPromptText markup includes the label/id or aria attribute and
provides descriptive context for screen readers.

In `@docs/content/docs/sdk/types/user.mdx`:
- Around line 35-37: Add a new documented section for the React hook
useAuthorizationHeader to match the TOC anchor
`#currentuseruseauthorizationheader`: create a heading and prose that documents
the hook signature useAuthorizationHeader(): string | null, describe what it
returns and when it returns null, include the "NEXT_LINE_PLATFORM react-like"
platform note and a short example showing usage in a React component (parity
with existing getAuthorizationHeader/getAuthHeaders sections), and ensure the
anchor text matches the TOC so the link is not dead.

In `@packages/stack-shared/src/ai/prompts.ts`:
- Around line 279-347: The non-Next React branch is mixing Next-specific
examples (layout.tsx, "@/stack/*" imports, and stackServerApp) which makes the
snippets unusable for plain React; update the template conditionals (the blocks
controlled by isMaybeReact/isMaybeNextjs and isDefinitelyNextjs) so that when
not Next you only show a generic App.tsx example that imports
StackProvider/StackTheme from packageName and uses stackClientApp (not
stackServerApp) with plain relative imports (no "@/stack/*" aliases), and ensure
the Suspense example for non-Next also targets src/App.tsx using stackClientApp
so the copy-paste snippet is framework-agnostic.
- Around line 366-380: The example currently calls await
stackClientApp.getAuthorizationHeader() directly into the headers, but
getAuthorizationHeader() returns string | null; change the example in the Step
titled "Update callers with header & get user" to first await and store the
result (e.g., const auth = await stackClientApp.getAuthorizationHeader()) and
only add the Authorization header when that stored value is non-null (e.g., if
(auth) set headers.Authorization = auth); update the explanatory text to note
that the header is only included for signed-in users.

In `@scripts/generate-setup-prompt-docs.ts`:
- Around line 65-72: The tanstack-query tool card is selectable but has no tabs
so setupTabMetadata (which filters via setupTabs derived from non-empty tabs)
omits it, causing the empty-state message when it's the only selection; either
prevent rendering it unless its parent feature is selected or add a minimal tab.
Fix by updating the tools metadata or rendering logic: either add a minimal tab
entry to the "tanstack-query" object (e.g., a small "Tanstack Query" tab in
tabs) so setupTabs includes it, or change renderToolCards to only show the
"tanstack-query" card when the related feature (e.g., "tanstack-start") is
selected or when extraFeatures includes an active feature; reference
setupTabMetadata, setupTabs, renderToolCards, and the "tanstack-query" and
"tanstack-start" feature names when making the change.
- Around line 313-320: The copyGeneratedSetupPrompt function currently awaits
navigator.clipboard.writeText(generatedSetupPromptText) without handling
rejections; wrap that await in a try/catch inside copyGeneratedSetupPrompt
(using the event/currentTarget button you already read) so on success you set
button.textContent = "Copied" and on failure set a clear failure state (e.g.,
"Copy failed" or "Permission denied") and log the error (console.error or
processLogger) so errors aren’t swallowed; ensure the existing window.setTimeout
still resets the button text back to "Copy prompt" in both success and failure
branches.

---

Outside diff comments:
In `@docs/src/components/mdx/sdk-components.tsx`:
- Line 133: The title tooltip currently includes internal layout metadata
(pos/height) and should not be exposed; update the title string construction
(where title={`Line ${area.lineNumber + 1}: ${area.anchor} (pos:
${topPosition}px, height: ${height}px)`} is created) to omit topPosition and
height—e.g. use only `Line ${area.lineNumber + 1}: ${area.anchor}` or, if you
need the metadata for debugging, include it conditionally behind a dev-only flag
(check NODE_ENV) so only area.lineNumber and area.anchor are used in production
tooltips.

In `@packages/stack-cli/src/commands/emulator.ts`:
- Around line 86-99: The code currently silently coerces bad types for
onboarding_status/onboarding_outstanding; change the runtime checks so they
either accept a missing field (undefined) and apply a deliberate default, but
throw a CliError when the field is present with the wrong type. Concretely,
replace the onboardingStatus/onboardingOutstanding assignments so they do: if
(data.onboarding_status === undefined) set default "completed"; else if (typeof
data.onboarding_status !== "string") throw new CliError("Invalid
onboarding_status from emulator"); similarly for data.onboarding_outstanding: if
undefined use derived boolean, else if typeof !== "boolean" throw new
CliError("Invalid onboarding_outstanding from emulator"). Use the existing data,
onboardingStatus and onboardingOutstanding symbols and follow the same
strictness used for the credential checks.

---

Nitpick comments:
In `@apps/backend/src/lib/local-emulator.ts`:
- Around line 109-143: There is duplicated host-mount/mkdir scaffolding in
writeConfigToFile and writeShowOnboardingConfigToFile; extract that logic into a
helper (e.g., prepareEmulatorWriteDir(filePath): Promise<{ resolvedPath: string;
dir: string }>) which calls resolveEmulatorPath and handles
LOCAL_EMULATOR_HOST_MOUNT_ROOT_ENV, fs.access and fs.mkdir, throws the same
error message on missing host mount, and returns { resolvedPath, dir }; then
replace the duplicated blocks in writeConfigToFile and
writeShowOnboardingConfigToFile to call prepareEmulatorWriteDir and proceed to
detectImportPackageFromDir and write the file content.
- Around line 67-75: Change the catch parameter from "e: any" to "e: unknown"
and narrow it before checking the error code: implement a small type guard (e.g.
isErrnoException(e: unknown): e is NodeJS.ErrnoException) or check typeof e ===
'object' && e !== null && 'code' in e, then test (e as
NodeJS.ErrnoException).code === 'ENOENT'; update the catch in the function that
reads fs.readFile (uses resolvedPath and fs.readFile) to use this narrowing and
only throw e after narrowing.

In `@apps/backend/src/lib/projects.tsx`:
- Around line 113-130: Add a one-line TODO comment marked "// TODO next-release"
immediately above the temporary schema-compat probe where
onboardingColumnExistsRows is computed (the information_schema.columns queries)
so the migration bridge is clearly flagged for removal; update the code near the
usages of onboardingStatusColumnExists and onboardingStateColumnExists to keep
the comment visible and referential to that probe.

In
`@apps/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx:
- Around line 280-332: The code duplicates OAuth provider objects in
buildBranchConfigUpdate and buildEnvironmentOAuthConfigUpdate; extract a small
helper (e.g., OAUTH_PROVIDER_IDS and oauthProviderEntry) that, given a provider
id and an options object { isShared: boolean }, returns the provider object or
null, then have both buildBranchConfigUpdate and
buildEnvironmentOAuthConfigUpdate iterate OAUTH_PROVIDER_IDS to assign
"auth.oauth.providers.<id>" using oauthProviderEntry(id, { isShared: false })
for the local/emulator branch and oauthProviderEntry(id, { isShared: true }) for
the environment builder; update the builders to use this helper (and adjust
their dependency arrays if they reference any new outer variables).

In
`@apps/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts:
- Around line 10-11: The types OnboardingConfigChoice and
OnboardingPaymentsCountry duplicate allowed-value lists; instead export the
const arrays onboardingConfigChoiceValues and onboardingPaymentsCountryValues
from the shared projects.ts and derive the types from them (e.g., type
OnboardingConfigChoice = typeof onboardingConfigChoiceValues[number]); update
the file to import those const arrays and replace the manual string-union type
declarations with derived types, and remove the duplicated literal definitions.

In
`@apps/e2e/tests/backend/endpoints/api/v1/internal/local-emulator-project.test.ts`:
- Around line 221-260: The test updates onboarding_state but doesn't assert that
onboarding_outstanding/onboarding_status changed; after the PATCH to
"/api/v1/internal/projects/current" (inside the it.runIf block), add a follow-up
fetch to the same project current endpoint (or re-call
LOCAL_EMULATOR_PROJECT_ENDPOINT) to retrieve the project and assert that the
onboarding_outstanding (and/or onboarding_status) value flipped as expected;
locate the calls to niceBackendFetch and the constant
LOCAL_EMULATOR_PROJECT_ENDPOINT in this test to insert the GET and assertions so
the contract between the PATCH and local-emulator behavior is validated.

In `@packages/stack-cli/src/commands/config-file.ts`:
- Line 10: Replace the local sentinel constant
SHOW_ONBOARDING_STACK_CONFIG_VALUE with the canonical exported value
showOnboardingStackConfigValue from the stack-shared module: remove the
duplicate const declaration in config-file.ts, add an import for
showOnboardingStackConfigValue from the shared package, and update any
references (uses of SHOW_ONBOARDING_STACK_CONFIG_VALUE) to use
showOnboardingStackConfigValue so the project uses the single source of truth
exported by config-authoring.ts.

In `@packages/stack-cli/src/commands/emulator.ts`:
- Around line 117-132: The try-catch in openUrlInBrowser currently swallows all
errors from execFileSync across platforms; update the function to (1) narrow or
annotate the catch by adding a brief "// best-effort: open native browser;
swallow errors but keep breadcrumb" comment above the try-catch, and (2) where a
logger is available (or attach debug logging), log the caught error at
debug/trace level inside the catch so missing xdg-open, DISPLAY issues, or cmd
quoting problems are recorded; reference the function openUrlInBrowser and the
execFileSync calls for placement and ensure the function still returns boolean
false on failure.

In `@packages/stack-shared/src/interface/crud/projects.ts`:
- Around line 35-45: Export the unexported constants and schema so other
packages can derive types instead of duplicating values: export
onboardingConfigChoiceValues, onboardingSignInMethodValues,
onboardingPaymentsCountryValues, and projectOnboardingStateSchema from this
module; then consumers (e.g., apps/dashboard/.../shared.ts) should import those
symbols and derive union types like OnboardingConfigChoice = typeof
onboardingConfigChoiceValues[number] and SignInMethod = typeof
onboardingSignInMethodValues[number], and use the imported
projectOnboardingStateSchema in isProjectOnboardingState rather than
re-declaring validation logic.

In
`@packages/template/src/lib/stack-app/apps/implementations/client-app-impl.oauth-prefetch.test.ts`:
- Around line 6-11: The test currently assumes the method name
"_prefetchCrossDomainHandoffParamsIfNeeded" exists on StackClientApp.prototype;
add an explicit assertion/check that Reflect.get(StackClientApp.prototype,
prefetchMethodName) is defined before overriding to avoid silent passes if it
was renamed or moved, and ensure you still restore the original
(originalPrefetch) after the test; reference prefetchMethodName,
originalPrefetch, StackClientApp.prototype and prefetchCalls when implementing
the existence check and cleanup.

In `@scripts/generate-setup-prompt-docs.ts`:
- Around line 297-345: The generated setup.mdx duplicates exported symbols and
helper code that already live in docs-mintlify/snippets/home-prompt-island.jsx
(generatedSetupPromptText, setupToolIds, setupTabMetadata,
unifiedAiPromptTabTitle, copyGeneratedSetupPrompt); remove those duplicated
export blocks from the template produced in
scripts/generate-setup-prompt-docs.ts and instead emit an import line in
setup.mdx that imports those symbols from /snippets/home-prompt-island.jsx,
leaving only setup-specific helpers (e.g., getSelectedSetupToolIdsFromUrl,
writeSelectedSetupToolIdsToUrl) in the generated file; update the template in
writeFileSyncIfChanged to stop JSON.stringify-embedding those symbols and to
reference the imported names so the docs use the single source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f13a8ed7-2eb7-4f4e-8010-b6c0b479da92

📥 Commits

Reviewing files that changed from the base of the PR and between b0812c8 and ff6a375.

⛔ Files ignored due to path filters (10)
  • docs-mintlify/images/setup-tools/bun.svg is excluded by !**/*.svg
  • docs-mintlify/images/setup-tools/cli.svg is excluded by !**/*.svg
  • docs-mintlify/images/setup-tools/convex.svg is excluded by !**/*.svg
  • docs-mintlify/images/setup-tools/javascript.svg is excluded by !**/*.svg
  • docs-mintlify/images/setup-tools/mcp.svg is excluded by !**/*.svg
  • docs-mintlify/images/setup-tools/nextjs.svg is excluded by !**/*.svg
  • docs-mintlify/images/setup-tools/nodejs.svg is excluded by !**/*.svg
  • docs-mintlify/images/setup-tools/react.svg is excluded by !**/*.svg
  • docs-mintlify/images/setup-tools/supabase.svg is excluded by !**/*.svg
  • docs-mintlify/images/setup-tools/tanstack.svg is excluded by !**/*.svg
📒 Files selected for processing (37)
  • .claude/CLAUDE-KNOWLEDGE.md
  • apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/migration.sql
  • apps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/tests/default-and-updates.ts
  • apps/backend/prisma/schema.prisma
  • apps/backend/src/app/api/latest/internal/local-emulator/project/route.tsx
  • apps/backend/src/lib/local-emulator.test.ts
  • apps/backend/src/lib/local-emulator.ts
  • apps/backend/src/lib/projects.tsx
  • apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsx
  • apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx
  • apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx
  • apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts
  • apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/projects/page-client.tsx
  • apps/e2e/tests/backend/endpoints/api/v1/internal/local-emulator-project.test.ts
  • apps/e2e/tests/js/auth-like.test.ts
  • claude/CLAUDE-KNOWLEDGE.md
  • docs-mintlify/guides/getting-started/setup.mdx
  • docs-mintlify/index.mdx
  • docs-mintlify/sdk/types/user.mdx
  • docs-mintlify/snippets/home-prompt-island.jsx
  • docs/content/docs/sdk/types/user.mdx
  • docs/src/components/mdx/sdk-components.tsx
  • examples/demo/src/app/tokens-demo/page.tsx
  • package.json
  • packages/stack-cli/src/commands/config-file.ts
  • packages/stack-cli/src/commands/emulator.ts
  • packages/stack-shared/src/ai/prompts.ts
  • packages/stack-shared/src/config-authoring.test.ts
  • packages/stack-shared/src/config-authoring.ts
  • packages/stack-shared/src/interface/crud/projects.ts
  • packages/template/src/lib/stack-app/apps/implementations/client-app-impl.oauth-prefetch.test.ts
  • packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts
  • packages/template/src/lib/stack-app/common.ts
  • scripts/generate-setup-prompt-docs.ts
  • sdks/spec/src/_utilities.spec.md
  • sdks/spec/src/apps/client-app.spec.md
  • sdks/spec/src/types/users/current-user.spec.md

Comment thread apps/backend/src/lib/local-emulator.ts
Comment thread apps/e2e/tests/js/auth-like.test.ts
Comment thread docs-mintlify/index.mdx
Comment thread docs/content/docs/sdk/types/user.mdx
Comment thread packages/stack-shared/src/ai/prompts.ts
Comment thread packages/stack-shared/src/ai/prompts.ts
Comment thread scripts/generate-setup-prompt-docs.ts
Comment thread scripts/generate-setup-prompt-docs.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
packages/stack-shared/src/ai/prompts.ts (2)

328-348: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Non-Next React Suspense snippet still uses Next-specific path and stackServerApp.

The !isDefinitelyNextjs block writes to src/app/layout.tsx and imports stackServerApp from @/stack/server, but plain React / TanStack Start projects don't have an App Router layout.tsx and shouldn't be embedding a server app in client-side providers. The earlier non-Next block at L283-300 already uses src/App.tsx with stackClientApp — please align the Suspense example with that.

♻️ Suggested change
           ${!isDefinitelyNextjs ? deindent`
             The easiest way to do this is to just wrap your entire app in a \`Suspense\` component:

-            \`\`\`tsx src/app/layout.tsx
+            \`\`\`tsx src/App.tsx
             import { Suspense } from "react";
             import { StackProvider, StackTheme } from "${packageName}";
-            import { stackServerApp } from "@/stack/server";
+            import { stackClientApp } from "./stack/client";

-            export default function RootLayout({ children }: { children: React.ReactNode }) {
+            export default function App() {
               return (
                 <Suspense fallback={<div>Loading...</div>}>
-                  <StackProvider app={stackServerApp}>
+                  <StackProvider app={stackClientApp}>
                     <StackTheme>
-                      {children}
+                      {/* your app content */}
                     </StackTheme>
                   </StackProvider>
                 </Suspense>
               );
             }
             \`\`\`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stack-shared/src/ai/prompts.ts` around lines 328 - 348, The non-Next
React Suspense example incorrectly targets src/app/layout.tsx and imports
stackServerApp; update the snippet to match the earlier client example by
showing a client-side App (e.g., src/App.tsx) wrapped in React's Suspense and
using stackClientApp with the StackProvider and StackTheme (symbols: Suspense,
StackProvider, StackTheme, stackClientApp, src/App.tsx) so it no longer
references Next-specific layout.tsx or stackServerApp.

366-411: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard the nullable Authorization header in the example.

If getAuthorizationHeader() can return null for signed-out users (which is the conventional shape used by token-store helpers), this snippet teaches callers to send Authorization: null, which either fails type-checking or sends a literal "null" value that the backend should reject. Please show the conditional pattern so copy-paste users land on a correct call.

🛡️ Suggested change
-          \`\`\`ts
-          // NOTE: This is your frontend's code
-          const response = await fetch("/my-backend-endpoint", {
-            headers: {
-              "Authorization": await stackClientApp.getAuthorizationHeader(),
-            },
-          });
-          // ...
-          \`\`\`
+          \`\`\`ts
+          // NOTE: This is your frontend's code
+          const authorizationHeader = await stackClientApp.getAuthorizationHeader();
+          const response = await fetch("/my-backend-endpoint", {
+            headers: {
+              ...(authorizationHeader != null ? { Authorization: authorizationHeader } : {}),
+            },
+          });
+          // ...
+          \`\`\`
#!/bin/bash
# Confirm the return type of getAuthorizationHeader so we know whether the snippet needs a null guard.
ast-grep --pattern 'getAuthorizationHeader($$$): $_ {
  $$$
}'
rg -nP -C2 'getAuthorizationHeader\s*\(' --type=ts
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/stack-shared/src/ai/prompts.ts` around lines 366 - 411, The example
sends Authorization directly from stackClientApp.getAuthorizationHeader() which
may be null for signed-out users; update the frontend snippet to await
getAuthorizationHeader(), check for a non-null value, and only set the
Authorization header when truthy (e.g., const auth = await
stackClientApp.getAuthorizationHeader(); if (auth) set header) so you don’t send
"null" or break types, and leave the backend usage of stackServerApp.getUser({
tokenStore: request }) and the alternate getAuthJson() example unchanged except
noting tokenStore can be the conditional auth object.
🧹 Nitpick comments (1)
apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx (1)

366-371: 💤 Low value

Order clearOnboardingState before flipping status to completed.

If clearOnboardingState ever fails (network blip, transient 5xx), the project will already be marked onboarding_status: "completed" but still hold a stale onboarding_state blob server-side. That isn't actively harmful for completed projects, but it's a small consistency wart that's easy to avoid by ordering the calls so the cleanup happens before the terminal state transition (or fold them into a single PATCH).

Optionally: combine the two patches into one setSelectedProjectOnboardingState-style call that PATCHes { onboarding_status: "completed", onboarding_state: null } together — atomic from the client's perspective.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx
around lines 366 - 371, The current sequence calls
setProjectOnboardingStatus("completed") before clearOnboardingState, risking a
completed project with stale onboarding_state if clearOnboardingState fails;
change the order so clearOnboardingState() is awaited before
setProjectOnboardingStatus("completed") and then call finishProjectOnboarding(),
or better yet replace the two separate updates with a single atomic patch
utility (e.g. a setSelectedProjectOnboardingState-style call) that updates {
onboarding_status: "completed", onboarding_state: null } in one request to avoid
the inconsistency; adjust the code paths that call clearOnboardingState,
setProjectOnboardingStatus, and finishProjectOnboarding accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/stack-cli/src/commands/emulator.ts`:
- Around line 110-123: The onboarding fields are being silently defaulted;
instead validate them like the credentials and fail loudly: check that
data.onboarding_status is a string and data.onboarding_outstanding is a boolean
(or both present as expected) and if not throw a CliError with a clear message;
update the creation of onboardingStatus and onboardingOutstanding
(variables/keys onboarding_status, onboarding_outstanding) to only use the
values from data when their types are valid and otherwise raise the same kind of
CliError used for project_id/publishable_client_key/secret_server_key.

In `@packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts`:
- Around line 113-119: The catch block around decoding/parsing the auth header
(where parsed is set from decodedAuthJson using decodeBase64, TextDecoder, and
JSON.parse) must not include the full authorizationHeaderValue in the thrown
Error; replace the raw header with a sanitized value (e.g. only the scheme or
the "stackauth_" prefix) or a constant like "<redacted-authorization>" in the
Error message while still attaching the original exception via the cause; update
the same pattern used for the x-stack-auth handling (the other occurrence noted)
so both throw/log sanitized header values only.

---

Duplicate comments:
In `@packages/stack-shared/src/ai/prompts.ts`:
- Around line 328-348: The non-Next React Suspense example incorrectly targets
src/app/layout.tsx and imports stackServerApp; update the snippet to match the
earlier client example by showing a client-side App (e.g., src/App.tsx) wrapped
in React's Suspense and using stackClientApp with the StackProvider and
StackTheme (symbols: Suspense, StackProvider, StackTheme, stackClientApp,
src/App.tsx) so it no longer references Next-specific layout.tsx or
stackServerApp.
- Around line 366-411: The example sends Authorization directly from
stackClientApp.getAuthorizationHeader() which may be null for signed-out users;
update the frontend snippet to await getAuthorizationHeader(), check for a
non-null value, and only set the Authorization header when truthy (e.g., const
auth = await stackClientApp.getAuthorizationHeader(); if (auth) set header) so
you don’t send "null" or break types, and leave the backend usage of
stackServerApp.getUser({ tokenStore: request }) and the alternate getAuthJson()
example unchanged except noting tokenStore can be the conditional auth object.

---

Nitpick comments:
In
`@apps/dashboard/src/app/`(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx:
- Around line 366-371: The current sequence calls
setProjectOnboardingStatus("completed") before clearOnboardingState, risking a
completed project with stale onboarding_state if clearOnboardingState fails;
change the order so clearOnboardingState() is awaited before
setProjectOnboardingStatus("completed") and then call finishProjectOnboarding(),
or better yet replace the two separate updates with a single atomic patch
utility (e.g. a setSelectedProjectOnboardingState-style call) that updates {
onboarding_status: "completed", onboarding_state: null } in one request to avoid
the inconsistency; adjust the code paths that call clearOnboardingState,
setProjectOnboardingStatus, and finishProjectOnboarding accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d16c72df-49e4-42cb-bdd6-9d99a1154db1

📥 Commits

Reviewing files that changed from the base of the PR and between ff6a375 and 3f44cf6.

📒 Files selected for processing (10)
  • .claude/CLAUDE-KNOWLEDGE.md
  • AGENTS.md
  • apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsx
  • apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx
  • apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/projects/page-client.tsx
  • claude/CLAUDE-KNOWLEDGE.md
  • packages/stack-cli/src/commands/emulator.ts
  • packages/stack-shared/src/ai/prompts.ts
  • packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts
  • sdks/spec/src/apps/client-app.spec.md
💤 Files with no reviewable changes (1)
  • claude/CLAUDE-KNOWLEDGE.md

Comment thread packages/stack-cli/src/commands/emulator.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants