Conversation
- Local emulator now saves to config at the end - New "show-onboarding" value in stack.config.ts
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds 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. ChangesProject Onboarding (DB, Backend, Emulator, Dashboard, Tests)
Authorization Header & Token Store API
Config Authoring, CLI & Emulator UX
Setup Prompt Generation & Docs
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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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.
Greptile SummaryThis PR introduces a new setup/onboarding flow for the Stack Auth local emulator, including a
Confidence Score: 3/5The 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
Sequence DiagramsequenceDiagram
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
|
There was a problem hiding this comment.
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 preferAuthorizationwithstackauth_payload, falling back to legacyx-stack-authand 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 thenoAutomaticPrefetchoption/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.
There was a problem hiding this comment.
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 winDebug position metadata leaks into production via
titletooltipThe
titleattribute 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 winSilent defaulting masks backend contract breakage.
If a backend mismatch returns
onboarding_statusas a non-string oronboarding_outstandingas 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 winReuse the exported sentinel from
stack-sharedinstead of redefining it.
showOnboardingStackConfigValueis exported frompackages/stack-shared/src/config-authoring.tsspecifically 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 winType definitions duplicate backend schema constants (downstream of
projects.ts)
OnboardingConfigChoiceandOnboardingPaymentsCountrymanually re-state the allowed values fromonboardingConfigChoiceValues/onboardingPaymentsCountryValuesinpackages/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 winUnexported constants and schema cause silent type divergence in the dashboard
onboardingConfigChoiceValues,onboardingSignInMethodValues,onboardingPaymentsCountryValues, andprojectOnboardingStateSchemaare all unexported. As a result,apps/dashboard/.../shared.tsmanually re-declares equivalent types (OnboardingConfigChoice,OnboardingPaymentsCountry,SignInMethod,ProjectOnboardingState) and duplicates the validation logic inisProjectOnboardingState(). If any allowed value is added or removed here (e.g., a new payments country),shared.tssilently 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 winHarden the test against silent passes if the method is renamed.
If
_prefetchCrossDomainHandoffParamsIfNeededis ever renamed or moved off the prototype,originalPrefetchbecomesundefined, the override is never invoked, andprefetchCallsstays at0— 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 winDuplicate host-mount/mkdir scaffolding between
writeConfigToFileandwriteShowOnboardingConfigToFile.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 winUse
e: unknownwith narrowing instead ofe: any.Per coding guidelines,
anyshould be avoided unless commented; hereunknownplus 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
anytype. Whenever you need to useany, 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 valueConsider asserting
onboarding_outstandingflips 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 echoedonboarding_state. Adding follow-up GET on/api/v1/internal/projects/current(or another POST to the local-emulator endpoint) to check whetheronboarding_status/onboarding_outstandingmove appropriately would lock in the contract between PATCH and the local-emulator endpoint that downstream code (e.g.,maybeOpenOnboardingPageinpackages/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 valueCatch-all hides real cross-platform issues.
openUrlInBrowserswallows every error fromexecFileSync, so missingxdg-openon Linux, mis-setDISPLAY, orcmdquoting issues all collapse into a singlefalse. 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 winDuplicated generated exports between
home-prompt-island.jsxandsetup.mdx.
generatedSetupPromptText,setupToolIds,setupTabMetadata,unifiedAiPromptTabTitle, andcopyGeneratedSetupPromptare emitted into bothdocs-mintlify/snippets/home-prompt-island.jsx(lines 282–285) anddocs-mintlify/guides/getting-started/setup.mdx(lines 308–320).index.mdxalready 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 winMark this schema-compat probe for next-release cleanup.
These
information_schema.columnschecks are clearly a temporary migration bridge. Please leave a// TODO next-releasehere 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 valueOptional: dedupe the OAuth provider build logic.
buildBranchConfigUpdate(local-only branch) andbuildEnvironmentOAuthConfigUpdaterepeat 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_IDSand call this helper with the appropriateisSharedflag.🤖 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
⛔ Files ignored due to path filters (10)
docs-mintlify/images/setup-tools/bun.svgis excluded by!**/*.svgdocs-mintlify/images/setup-tools/cli.svgis excluded by!**/*.svgdocs-mintlify/images/setup-tools/convex.svgis excluded by!**/*.svgdocs-mintlify/images/setup-tools/javascript.svgis excluded by!**/*.svgdocs-mintlify/images/setup-tools/mcp.svgis excluded by!**/*.svgdocs-mintlify/images/setup-tools/nextjs.svgis excluded by!**/*.svgdocs-mintlify/images/setup-tools/nodejs.svgis excluded by!**/*.svgdocs-mintlify/images/setup-tools/react.svgis excluded by!**/*.svgdocs-mintlify/images/setup-tools/supabase.svgis excluded by!**/*.svgdocs-mintlify/images/setup-tools/tanstack.svgis excluded by!**/*.svg
📒 Files selected for processing (37)
.claude/CLAUDE-KNOWLEDGE.mdapps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/migration.sqlapps/backend/prisma/migrations/20260420000000_add_project_onboarding_state/tests/default-and-updates.tsapps/backend/prisma/schema.prismaapps/backend/src/app/api/latest/internal/local-emulator/project/route.tsxapps/backend/src/lib/local-emulator.test.tsapps/backend/src/lib/local-emulator.tsapps/backend/src/lib/projects.tsxapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsxapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsxapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsxapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.tsapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/projects/page-client.tsxapps/e2e/tests/backend/endpoints/api/v1/internal/local-emulator-project.test.tsapps/e2e/tests/js/auth-like.test.tsclaude/CLAUDE-KNOWLEDGE.mddocs-mintlify/guides/getting-started/setup.mdxdocs-mintlify/index.mdxdocs-mintlify/sdk/types/user.mdxdocs-mintlify/snippets/home-prompt-island.jsxdocs/content/docs/sdk/types/user.mdxdocs/src/components/mdx/sdk-components.tsxexamples/demo/src/app/tokens-demo/page.tsxpackage.jsonpackages/stack-cli/src/commands/config-file.tspackages/stack-cli/src/commands/emulator.tspackages/stack-shared/src/ai/prompts.tspackages/stack-shared/src/config-authoring.test.tspackages/stack-shared/src/config-authoring.tspackages/stack-shared/src/interface/crud/projects.tspackages/template/src/lib/stack-app/apps/implementations/client-app-impl.oauth-prefetch.test.tspackages/template/src/lib/stack-app/apps/implementations/client-app-impl.tspackages/template/src/lib/stack-app/common.tsscripts/generate-setup-prompt-docs.tssdks/spec/src/_utilities.spec.mdsdks/spec/src/apps/client-app.spec.mdsdks/spec/src/types/users/current-user.spec.md
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
packages/stack-shared/src/ai/prompts.ts (2)
328-348:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winNon-Next React Suspense snippet still uses Next-specific path and
stackServerApp.The
!isDefinitelyNextjsblock writes tosrc/app/layout.tsxand importsstackServerAppfrom@/stack/server, but plain React / TanStack Start projects don't have an App Routerlayout.tsxand shouldn't be embedding a server app in client-side providers. The earlier non-Next block at L283-300 already usessrc/App.tsxwithstackClientApp— 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 winGuard the nullable Authorization header in the example.
If
getAuthorizationHeader()can returnnullfor signed-out users (which is the conventional shape used by token-store helpers), this snippet teaches callers to sendAuthorization: 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 valueOrder
clearOnboardingStatebefore flipping status tocompleted.If
clearOnboardingStateever fails (network blip, transient 5xx), the project will already be markedonboarding_status: "completed"but still hold a staleonboarding_stateblob 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
📒 Files selected for processing (10)
.claude/CLAUDE-KNOWLEDGE.mdAGENTS.mdapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/content.tsxapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsxapps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/projects/page-client.tsxclaude/CLAUDE-KNOWLEDGE.mdpackages/stack-cli/src/commands/emulator.tspackages/stack-shared/src/ai/prompts.tspackages/template/src/lib/stack-app/apps/implementations/client-app-impl.tssdks/spec/src/apps/client-app.spec.md
💤 Files with no reviewable changes (1)
- claude/CLAUDE-KNOWLEDGE.md

Note
Medium Risk
Touches DB schema and project update paths (new
Project.onboardingStateJSONB) 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 returnsonboarding_status/onboarding_outstandingwhile syncing DB onboarding status based on the sentinel.Updates dashboard onboarding to validate and persist
onboarding_stateon each step (and adjust behavior in local emulator mode), and adds/updates E2E tests for both local emulator onboarding behavior and the newgetAuthorizationHeader()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
Documentation
Deprecations
Bug Fixes