stack/packages/stack-shared/src/config
BilalG1 89554a3eed
payment test mode fixes (#957)
<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md

-->

<!-- RECURSEML_SUMMARY:START -->
## High-level PR Summary
This PR fixes payment test mode behavior by changing the default test
mode setting to `true` and refactoring the test mode bypass UI. The
bypass functionality is moved from a floating card in the purchase page
into the checkout form itself, providing a cleaner and more integrated
experience. Additionally, the database migration configuration is
updated to increase the `maxWait` timeout to handle concurrent migration
attempts more gracefully in high-contention scenarios like CI
environments.

⏱️ Estimated Review Time: 5-15 minutes

<details>
<summary>💡 Review Order Suggestion</summary>

| Order | File Path |
|-------|-----------|
| 1 | `packages/stack-shared/src/config/schema.ts` |
| 2 | `apps/dashboard/src/app/(main)/purchase/[code]/page-client.tsx` |
| 3 | `apps/dashboard/src/components/payments/checkout.tsx` |
| 4 | `apps/backend/src/auto-migrations/index.tsx` |
</details>

<details>
<summary>⚠️ Inconsistent Changes Detected</summary>

| File Path | Warning |
|-----------|---------|
| `apps/backend/src/auto-migrations/index.tsx` | Database migration
timeout configuration changes appear unrelated to payment test mode
fixes, which is the stated purpose of this PR |
</details>

[![Need help? Join our
Discord](https://img.shields.io/badge/Need%20help%3F%20Join%20our%20Discord-5865F2?style=plastic&logo=discord&logoColor=white)](https://discord.gg/n3SsVDAW6U)


[![Analyze latest
changes](564b2cf6ef/?repo_owner=stack-auth&repo_name=stack-auth&pr_number=957)
<!-- RECURSEML_SUMMARY:END -->
<!-- ELLIPSIS_HIDDEN -->


----

> [!IMPORTANT]
> Sets payment test mode to default true, integrates test mode bypass
into checkout form, and updates migration timeout.
> 
>   - **Behavior**:
>     - Default `testMode` set to `true` in `schema.ts`.
> - Integrates test mode bypass into `CheckoutForm` in `checkout.tsx`.
>     - Removes separate bypass panel from `page-client.tsx`.
>   - **Database**:
> - Increases `maxWait` timeout in `index.tsx` to handle concurrent
migration attempts.
>   - **Tests**:
> - Updates tests in `backend-helpers.ts` and `validate-code.test.ts` to
reflect test mode behavior.
> 
> <sup>This description was created by </sup>[<img alt="Ellipsis"
src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=stack-auth%2Fstack-auth&utm_source=github&utm_medium=referral)<sup>
for 6313c0bfed. You can
[customize](https://app.ellipsis.dev/stack-auth/settings/summaries) this
summary. It will automatically update as commits are pushed.</sup>

----


<!-- ELLIPSIS_HIDDEN -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a test-mode checkout path with a “Complete test purchase” action
when test mode is active.
* **Refactor**
* Consolidated test-mode bypass into the checkout component and removed
the separate bypass UI.
* **Bug Fixes**
* Improved reliability of database migrations by extending the
transaction wait window, reducing timeout errors under load.
* **Chores**
  * Payments now default to test mode enabled.
* **Tests**
* Updated tests and payload expectations to reflect test mode defaults
and behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-15 19:14:45 -07:00
..
format.ts Rename offer to product, offer group to product catalog (#914) 2025-10-04 02:28:28 -07:00
README.md Several project config improvements (#811) 2025-07-29 04:13:46 -07:00
schema-fuzzer.test.ts product card fixes, payments test mode (#928) 2025-10-07 18:07:13 +00:00
schema.ts payment test mode fixes (#957) 2025-10-15 19:14:45 -07:00

Some notes on configs

The language in this file is very technical, if you're struggling, put it into ChatGPT and see if it can help you (with the usual hallucination disclaimer).

Generic format vs. Stack Auth

The config format is generally usable and not specific to Stack Auth.

All the logic required for generic usage of the config format are in format/. The other files in this folder are specific to Stack Auth's usage of it.

Terminology

Generic config format:

  • Config: Any config, as described in stack-info
  • Normalized config: A config without null fields and dot notation

Stack Auth: There are four levels, project, branch, environment, organization.

  • Base config: The defaults that come with Stack Auth
  • $Level config override: Overrides that are applied to the base config (in the following order: project -> branch -> environment -> organization)
  • $Level incomplete config: The base config after some overrides have been applied
  • $Level rendered config: An incomplete config with those fields removed that can be overridden by a future override, deeply merged into the defaults and sanitized (using apply{$Level}DefaultsAndSanitize), and then normalized
  • Complete config: The organization rendered config.
  • $Level config override override: An override that overrides the $Level config override. This is most often used eg. in the REST API to let users make changes to the branch-level config, without overwriting the entire branch-level config override. Note that, since config overrides (unlike configs) distinguish between null and a property missing (undefined), it is currently not possible to say "this property in the config override should be unset" (setting a property to null in the override override will simply also set it to null in the override). In the future, we'll have to think about how we handle this, probably with a sentinel value.
  • $Level config: Could refer to any of the above, depending on the context; if it's not clear, specify it.
Examples

Base config:

{
  organizations: {},
  createTeamOnSignUp: false,
  sourceOfTruthConnectionString: null
}

Project config override:

{
  sourceOfTruthConnectionString: 'postgresql://...',
}

Project incomplete config:

// note: `organizations` and `createTeamOnSignUp` may be overridden by branch, environment, or organization configs! They are not final
{
  organizations: {},
  createTeamOnSignUp: false,
  sourceOfTruthConnectionString: 'postgresql://...',
}

Project rendered config:

// since `organizations` and `createTeamOnSignUp` may change later, they are not included in the rendered config
{
  sourceOfTruthConnectionString: 'postgresql://...',
}

Branch config override:

{
  organizations: {
    'my-org': {
      name: 'My Org',
    }
  }
}

Branch incomplete config:

{
  organizations: {
    'my-org': {
      name: 'My Org',
    }
  },
  createTeamOnSignUp: true,
  sourceOfTruthConnectionString: 'postgresql://...',
}

Branch rendered config:

// as above, `organizations` and `createTeamOnSignUp` are not included in the rendered config, as they may change later
{
  sourceOfTruthConnectionString: 'postgresql://...',
}

Environment config override:

// no change from branch config
{}

Environment incomplete config:

// no change from branch config
{
  organizations: {
    'my-org': {
      name: 'My Org',
    }
  },
  createTeamOnSignUp: true,
  sourceOfTruthConnectionString: 'postgresql://...',
}

Environment rendered config:

// organizations can no longer change after this point, so they are included in the rendered config
{
  organizations: {
    'my-org': {
      name: 'My Org',
    }
  },
  createTeamOnSignUp: true,
  sourceOfTruthConnectionString: 'postgresql://...',
}

Organization config override:

{
  createTeamOnSignUp: true,
}

Organization incomplete config = organization rendered config = complete config:

{
  createTeamOnSignUp: true,
  sourceOfTruthConnectionString: 'postgresql://...',
}