chore: rename STACK_* env vars to HEXCLAVE_* in env templates, with legacy dual-read

Renames every STACK_*-prefixed variable (including NEXT_PUBLIC_STACK_*) to
HEXCLAVE_* across all checked-in .env, .env.development, and .env.example
files, completing the env-var side of the Hexclave rebrand. Legacy STACK_*
names keep working everywhere so existing deployments, .env.local files, and
self-hosted setups don't need immediate migration:

- getEnvVariable already prefers HEXCLAVE_* with STACK_* fallback; fix it to
  treat empty-string values as unset so the empty HEXCLAVE_* placeholders in
  the checked-in templates can't shadow a real value under the legacy name.
- Apply the same empty-as-unset rule (|| instead of ??) to all literal
  process.env dual-reads (dashboard inline env, docs, examples, CLI) and to
  the generated SDK env getter chains via packages/template generate-env.ts.
- Add explicit HEXCLAVE_* || STACK_* dual-reads to direct process.env readers
  fed by the renamed files: prisma seed, e2e tests/helpers, internal-tool
  scripts and app, demo/convex examples.
- docker/server/entrypoint.sh: add a generic two-way HEXCLAVE_/STACK_ env
  mirror (run at startup and again before sentinel replacement), replacing the
  previous URL-trio-only mirror; accept legacy NEXT_PUBLIC_STACK_PORT_PREFIX;
  rotate-secrets.sh falls back to HEXCLAVE_DATABASE_CONNECTION_STRING.
- e2e cross-domain-auth and the internal-feedback-emails in-source test now
  override the canonical HEXCLAVE_* names (the legacy override would be
  shadowed by the renamed env files).
- docs/code-examples snippets renamed outright to the canonical names.
This commit is contained in:
Bilal Godil 2026-06-11 16:23:50 -07:00
parent a092be6dc3
commit 178b5c5a8c
58 changed files with 526 additions and 491 deletions

View File

@ -1,127 +1,127 @@
# Basic
NEXT_PUBLIC_STACK_API_URL=# the base URL of Stack's backend/API. For local development, this is `http://localhost:8102`; for the managed service, this is `https://api.hexclave.com`.
NEXT_PUBLIC_STACK_DASHBOARD_URL=# the URL of Stack's dashboard. For local development, this is `http://localhost:8101`; for the managed service, this is `https://app.hexclave.com`.
NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR=# set to true to enable local emulator-only behaviors (internal local emulator endpoints, read-only environment config overrides, and local emulator auth UX)
STACK_SECRET_SERVER_KEY=# a random, unguessable secret key generated by `pnpm generate-keys`
NEXT_PUBLIC_HEXCLAVE_API_URL=# the base URL of Stack's backend/API. For local development, this is `http://localhost:8102`; for the managed service, this is `https://api.hexclave.com`.
NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL=# the URL of Stack's dashboard. For local development, this is `http://localhost:8101`; for the managed service, this is `https://app.hexclave.com`.
NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR=# set to true to enable local emulator-only behaviors (internal local emulator endpoints, read-only environment config overrides, and local emulator auth UX)
HEXCLAVE_SECRET_SERVER_KEY=# a random, unguessable secret key generated by `pnpm generate-keys`
# seed script settings
STACK_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED=# true to enable user sign up to the dashboard when seeding
STACK_SEED_INTERNAL_PROJECT_OTP_ENABLED=# true to add OTP auth to the dashboard when seeding
STACK_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST=# true to allow running dashboard on the localhost, set this to true only in development
STACK_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS=# list of oauth providers to add to the dashboard when seeding, separated by comma, for example "github,google,facebook"
STACK_SEED_INTERNAL_PROJECT_USER_EMAIL=# default user added to the dashboard
STACK_SEED_INTERNAL_PROJECT_USER_PASSWORD=# default user's password, paired with STACK_SEED_INTERNAL_PROJECT_USER_EMAIL
STACK_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS=# if the default user has access to the internal dashboard project
STACK_SEED_INTERNAL_PROJECT_USER_GITHUB_ID=# add github oauth id to the default user
STACK_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY=# default publishable client key for the internal project
STACK_INTERNAL_PROJECT_SECRET_SERVER_KEY=# default secret server key for the internal project
STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY=# default super secret admin key for the internal project
HEXCLAVE_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED=# true to enable user sign up to the dashboard when seeding
HEXCLAVE_SEED_INTERNAL_PROJECT_OTP_ENABLED=# true to add OTP auth to the dashboard when seeding
HEXCLAVE_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST=# true to allow running dashboard on the localhost, set this to true only in development
HEXCLAVE_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS=# list of oauth providers to add to the dashboard when seeding, separated by comma, for example "github,google,facebook"
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_EMAIL=# default user added to the dashboard
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_PASSWORD=# default user's password, paired with HEXCLAVE_SEED_INTERNAL_PROJECT_USER_EMAIL
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS=# if the default user has access to the internal dashboard project
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_GITHUB_ID=# add github oauth id to the default user
HEXCLAVE_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY=# default publishable client key for the internal project
HEXCLAVE_INTERNAL_PROJECT_SECRET_SERVER_KEY=# default secret server key for the internal project
HEXCLAVE_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY=# default super secret admin key for the internal project
# OAuth mock provider settings
STACK_OAUTH_MOCK_URL=# enter the URL of the mock OAuth provider here. For local development, use `http://localhost:8114`.
HEXCLAVE_OAUTH_MOCK_URL=# enter the URL of the mock OAuth provider here. For local development, use `http://localhost:8114`.
# OAuth shared keys
# Can be set to MOCK to use mock OAuth providers
STACK_GITHUB_CLIENT_ID=# client
STACK_GITHUB_CLIENT_SECRET=# client secret
STACK_GOOGLE_CLIENT_ID=# client id
STACK_GOOGLE_CLIENT_SECRET=# client secret
STACK_MICROSOFT_CLIENT_ID=# client id
STACK_MICROSOFT_CLIENT_SECRET=# client secret
STACK_SPOTIFY_CLIENT_ID=# client id
STACK_SPOTIFY_CLIENT_SECRET=# client secret
HEXCLAVE_GITHUB_CLIENT_ID=# client
HEXCLAVE_GITHUB_CLIENT_SECRET=# client secret
HEXCLAVE_GOOGLE_CLIENT_ID=# client id
HEXCLAVE_GOOGLE_CLIENT_SECRET=# client secret
HEXCLAVE_MICROSOFT_CLIENT_ID=# client id
HEXCLAVE_MICROSOFT_CLIENT_SECRET=# client secret
HEXCLAVE_SPOTIFY_CLIENT_ID=# client id
HEXCLAVE_SPOTIFY_CLIENT_SECRET=# client secret
STACK_ALLOW_SHARED_OAUTH_ACCESS_TOKENS=# allow shared oauth provider to also use connected account access token, this should only be used for development and testing
HEXCLAVE_ALLOW_SHARED_OAUTH_ACCESS_TOKENS=# allow shared oauth provider to also use connected account access token, this should only be used for development and testing
STACK_DISABLE_PLAN_LIMITS=# set to "true" to bypass enforcement of Hexclave's own internal-tenancy plan limits (analytics_events, session_replays, emails_per_month, dashboard_admins seat cap, auth_users soft cap, analytics_timeout_seconds). Default unset/false preserves enforcement. Intended as a temporary cutover safety net while the plan-limits infrastructure rolls out — customer projects' own item APIs are unaffected by this flag.
HEXCLAVE_DISABLE_PLAN_LIMITS=# set to "true" to bypass enforcement of Hexclave's own internal-tenancy plan limits (analytics_events, session_replays, emails_per_month, dashboard_admins seat cap, auth_users soft cap, analytics_timeout_seconds). Default unset/false preserves enforcement. Intended as a temporary cutover safety net while the plan-limits infrastructure rolls out — customer projects' own item APIs are unaffected by this flag.
# Email
# For local development, you can spin up a local SMTP server like inbucket
STACK_EMAIL_HOST=# for local inbucket: 127.0.0.1
STACK_EMAIL_PORT=# for local inbucket: 8129
STACK_EMAIL_USERNAME=# for local inbucket: test
STACK_EMAIL_PASSWORD=# for local inbucket: none
STACK_EMAIL_SENDER=# for local inbucket: noreply@test.com
STACK_EMAILABLE_API_KEY=# Emailable API key for email validation, see https://emailable.com. Use a test key (starting with "test_") for local dev — it does not consume credits. Set to "disable_email_validation" to disable.
HEXCLAVE_EMAIL_HOST=# for local inbucket: 127.0.0.1
HEXCLAVE_EMAIL_PORT=# for local inbucket: 8129
HEXCLAVE_EMAIL_USERNAME=# for local inbucket: test
HEXCLAVE_EMAIL_PASSWORD=# for local inbucket: none
HEXCLAVE_EMAIL_SENDER=# for local inbucket: noreply@test.com
HEXCLAVE_EMAILABLE_API_KEY=# Emailable API key for email validation, see https://emailable.com. Use a test key (starting with "test_") for local dev — it does not consume credits. Set to "disable_email_validation" to disable.
STACK_DEFAULT_EMAIL_CAPACITY_PER_HOUR=# the number of emails a new project can send. Defaults to 200
HEXCLAVE_DEFAULT_EMAIL_CAPACITY_PER_HOUR=# the number of emails a new project can send. Defaults to 200
# Email branching configuration
# If you have multiple deployments of compute accessing the same DB or multiple copies of a DBs connected to compute (as
# you would in preview/branching environments), you may want to either disable the auto-triggered email queue steps
# (those that trigger whenever an email is sent, besides the cron job), or disable email sending as a whole.
STACK_EMAIL_BRANCHING_DISABLE_QUEUE_AUTO_TRIGGER=# set to 'true' to disable the automatic triggering of the email queue step. the cron job must call /email-queue-step to run the queue step. Most useful on production domains where you know the cron job will run on the correct deployment and you don't need the auto-trigger (which may be on the wrong deployment)
STACK_EMAIL_BRANCHING_DISABLE_QUEUE_SENDING=# set to 'true' to throw an error instead of sending emails in the email queue step. Most useful on development branches that have a copy of the production DB, but should not send any emails (as otherwise some emails could be sent twice)
HEXCLAVE_EMAIL_BRANCHING_DISABLE_QUEUE_AUTO_TRIGGER=# set to 'true' to disable the automatic triggering of the email queue step. the cron job must call /email-queue-step to run the queue step. Most useful on production domains where you know the cron job will run on the correct deployment and you don't need the auto-trigger (which may be on the wrong deployment)
HEXCLAVE_EMAIL_BRANCHING_DISABLE_QUEUE_SENDING=# set to 'true' to throw an error instead of sending emails in the email queue step. Most useful on development branches that have a copy of the production DB, but should not send any emails (as otherwise some emails could be sent twice)
# Database
# For local development: `docker run -it --rm -e POSTGRES_PASSWORD=password -p "8128:5432" postgres`
STACK_DATABASE_CONNECTION_STRING=# enter your connection string here. For local development: `postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:8128/stackframe`
HEXCLAVE_DATABASE_CONNECTION_STRING=# enter your connection string here. For local development: `postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:8128/stackframe`
# Webhooks
STACK_SVIX_SERVER_URL=# For prod, leave it empty. For local development, use `http://localhost:8113`
STACK_SVIX_API_KEY=# enter the API key for the Svix webhook service here. Use `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NTUxNDA2MzksImV4cCI6MTk3MDUwMDYzOSwibmJmIjoxNjU1MTQwNjM5LCJpc3MiOiJzdml4LXNlcnZlciIsInN1YiI6Im9yZ18yM3JiOFlkR3FNVDBxSXpwZ0d3ZFhmSGlyTXUifQ.En8w77ZJWbd0qrMlHHupHUB-4cx17RfzFykseg95SUk` for local development
HEXCLAVE_SVIX_SERVER_URL=# For prod, leave it empty. For local development, use `http://localhost:8113`
HEXCLAVE_SVIX_API_KEY=# enter the API key for the Svix webhook service here. Use `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NTUxNDA2MzksImV4cCI6MTk3MDUwMDYzOSwibmJmIjoxNjU1MTQwNjM5LCJpc3MiOiJzdml4LXNlcnZlciIsInN1YiI6Im9yZ18yM3JiOFlkR3FNVDBxSXpwZ0d3ZFhmSGlyTXUifQ.En8w77ZJWbd0qrMlHHupHUB-4cx17RfzFykseg95SUk` for local development
# S3
STACK_S3_PUBLIC_ENDPOINT=# publicly accessible endpoint
STACK_S3_ENDPOINT=# S3 API endpoint URL (e.g., 'https://s3.amazonaws.com' for AWS or custom endpoint for S3-compatible services)
STACK_S3_REGION=
STACK_S3_ACCESS_KEY_ID=
STACK_S3_SECRET_ACCESS_KEY=
STACK_S3_BUCKET=
STACK_S3_PRIVATE_BUCKET=
HEXCLAVE_S3_PUBLIC_ENDPOINT=# publicly accessible endpoint
HEXCLAVE_S3_ENDPOINT=# S3 API endpoint URL (e.g., 'https://s3.amazonaws.com' for AWS or custom endpoint for S3-compatible services)
HEXCLAVE_S3_REGION=
HEXCLAVE_S3_ACCESS_KEY_ID=
HEXCLAVE_S3_SECRET_ACCESS_KEY=
HEXCLAVE_S3_BUCKET=
HEXCLAVE_S3_PRIVATE_BUCKET=
# AWS configuration
STACK_AWS_REGION=
STACK_AWS_KMS_ENDPOINT=
STACK_AWS_ACCESS_KEY_ID=
STACK_AWS_SECRET_ACCESS_KEY=
STACK_AWS_VERCEL_OIDC_ROLE_ARN=
HEXCLAVE_AWS_REGION=
HEXCLAVE_AWS_KMS_ENDPOINT=
HEXCLAVE_AWS_ACCESS_KEY_ID=
HEXCLAVE_AWS_SECRET_ACCESS_KEY=
HEXCLAVE_AWS_VERCEL_OIDC_ROLE_ARN=
# Upstash configuration
STACK_QSTASH_URL=
STACK_QSTASH_TOKEN=
STACK_QSTASH_CURRENT_SIGNING_KEY=
STACK_QSTASH_NEXT_SIGNING_KEY=
HEXCLAVE_QSTASH_URL=
HEXCLAVE_QSTASH_TOKEN=
HEXCLAVE_QSTASH_CURRENT_SIGNING_KEY=
HEXCLAVE_QSTASH_NEXT_SIGNING_KEY=
# Email monitor
STACK_EMAIL_MONITOR_RESEND_EMAIL_API_KEY=# enter the resend poller api key here
STACK_EMAIL_MONITOR_RESEND_EMAIL_DOMAIN=# enter the resend domain that should receive the emails
STACK_EMAIL_MONITOR_PROJECT_ID=# enter the project id for the project that the email monitor will attempt to sign up for
STACK_EMAIL_MONITOR_PUBLISHABLE_CLIENT_KEY=# enter the publishable client key for email monitor to use when attempting a sign up
STACK_EMAIL_MONITOR_VERIFICATION_CALLBACK_URL=# enter a valid verification callback url for the project that the email monitor will attempt to sign up for
STACK_EMAIL_MONITOR_INBUCKET_API_URL=# enter a valid inbucket api url for the email monitor to check emails from in test mode
STACK_EMAIL_MONITOR_USE_INBUCKET=# enter true/false based on whether the email monitor should use inbucket or resend. Note that if this is set to true in prod, the email monitor will throw an error.
STACK_EMAIL_MONITOR_SECRET_TOKEN=# enter the secret token value needed for the request to the email monitor to be accepted
HEXCLAVE_EMAIL_MONITOR_RESEND_EMAIL_API_KEY=# enter the resend poller api key here
HEXCLAVE_EMAIL_MONITOR_RESEND_EMAIL_DOMAIN=# enter the resend domain that should receive the emails
HEXCLAVE_EMAIL_MONITOR_PROJECT_ID=# enter the project id for the project that the email monitor will attempt to sign up for
HEXCLAVE_EMAIL_MONITOR_PUBLISHABLE_CLIENT_KEY=# enter the publishable client key for email monitor to use when attempting a sign up
HEXCLAVE_EMAIL_MONITOR_VERIFICATION_CALLBACK_URL=# enter a valid verification callback url for the project that the email monitor will attempt to sign up for
HEXCLAVE_EMAIL_MONITOR_INBUCKET_API_URL=# enter a valid inbucket api url for the email monitor to check emails from in test mode
HEXCLAVE_EMAIL_MONITOR_USE_INBUCKET=# enter true/false based on whether the email monitor should use inbucket or resend. Note that if this is set to true in prod, the email monitor will throw an error.
HEXCLAVE_EMAIL_MONITOR_SECRET_TOKEN=# enter the secret token value needed for the request to the email monitor to be accepted
# Clickhouse
STACK_CLICKHOUSE_URL=# URL of the Clickhouse instance
STACK_CLICKHOUSE_ADMIN_USER=# username of the admin account
STACK_CLICKHOUSE_ADMIN_PASSWORD=# password of the admin account
STACK_CLICKHOUSE_EXTERNAL_PASSWORD=# a randomly generated secure string. The user account will be created automatically
HEXCLAVE_CLICKHOUSE_URL=# URL of the Clickhouse instance
HEXCLAVE_CLICKHOUSE_ADMIN_USER=# username of the admin account
HEXCLAVE_CLICKHOUSE_ADMIN_PASSWORD=# password of the admin account
HEXCLAVE_CLICKHOUSE_EXTERNAL_PASSWORD=# a randomly generated secure string. The user account will be created automatically
# Misc
STACK_ACCESS_TOKEN_EXPIRATION_TIME=# enter the expiration time for the access token here. Optional, don't specify it for default value
STACK_SETUP_ADMIN_GITHUB_ID=# enter the account ID of the admin user here, and after running the seed script they will be able to access the internal project in the Stack dashboard. Optional, don't specify it for default value
HEXCLAVE_ACCESS_TOKEN_EXPIRATION_TIME=# enter the expiration time for the access token here. Optional, don't specify it for default value
HEXCLAVE_SETUP_ADMIN_GITHUB_ID=# enter the account ID of the admin user here, and after running the seed script they will be able to access the internal project in the Stack dashboard. Optional, don't specify it for default value
OTEL_EXPORTER_OTLP_ENDPOINT=# enter the OpenTelemetry endpoint here. Optional, default is `http://localhost:8131`
STACK_INTEGRATION_CLIENTS_CONFIG=# a list of oidc-provider clients for integrations. If not provided, disables integrations
STACK_FREESTYLE_API_KEY=# enter your freestyle.sh api key
STACK_VERCEL_SANDBOX_PROJECT_ID=# enter the project id for the vercel project that the vercel engine will use
STACK_VERCEL_SANDBOX_TEAM_ID=# enter the team id for the vercel project that the vercel engine will use
STACK_VERCEL_SANDBOX_TOKEN=# enter the token for the vercel project that the vercel engine will use
STACK_OPENAI_API_KEY=# enter your openai api key
STACK_FEATUREBASE_API_KEY=# enter your featurebase api key
STACK_STRIPE_SECRET_KEY=# enter your stripe api key
STACK_STRIPE_WEBHOOK_SECRET=# enter your stripe webhook secret
STACK_TELEGRAM_BOT_TOKEN= # enter you telegram bot token
STACK_TELEGRAM_CHAT_ID=# enter your telegram chat id
HEXCLAVE_INTEGRATION_CLIENTS_CONFIG=# a list of oidc-provider clients for integrations. If not provided, disables integrations
HEXCLAVE_FREESTYLE_API_KEY=# enter your freestyle.sh api key
HEXCLAVE_VERCEL_SANDBOX_PROJECT_ID=# enter the project id for the vercel project that the vercel engine will use
HEXCLAVE_VERCEL_SANDBOX_TEAM_ID=# enter the team id for the vercel project that the vercel engine will use
HEXCLAVE_VERCEL_SANDBOX_TOKEN=# enter the token for the vercel project that the vercel engine will use
HEXCLAVE_OPENAI_API_KEY=# enter your openai api key
HEXCLAVE_FEATUREBASE_API_KEY=# enter your featurebase api key
HEXCLAVE_STRIPE_SECRET_KEY=# enter your stripe api key
HEXCLAVE_STRIPE_WEBHOOK_SECRET=# enter your stripe webhook secret
HEXCLAVE_TELEGRAM_BOT_TOKEN= # enter you telegram bot token
HEXCLAVE_TELEGRAM_CHAT_ID=# enter your telegram chat id
# Docs AI tool bundle
STACK_MINTLIFY_MCP_URL=# override the Mintlify MCP server used by the backend's AI docs tool bundle. Defaults to https://stackauth-e0affa27.mintlify.app/mcp
HEXCLAVE_MINTLIFY_MCP_URL=# override the Mintlify MCP server used by the backend's AI docs tool bundle. Defaults to https://stackauth-e0affa27.mintlify.app/mcp
# MCP review tool (SpacetimeDB)
STACK_SPACETIMEDB_URI=# SpacetimeDB host URI; default empty (logging disabled)
STACK_SPACETIMEDB_DB_NAME=# SpacetimeDB database name
STACK_MCP_LOG_TOKEN=# shared secret gating the log_mcp_call reducer; must match EXPECTED_LOG_TOKEN in apps/internal-tool/spacetimedb/src/index.ts
HEXCLAVE_SPACETIMEDB_URI=# SpacetimeDB host URI; default empty (logging disabled)
HEXCLAVE_SPACETIMEDB_DB_NAME=# SpacetimeDB database name
HEXCLAVE_MCP_LOG_TOKEN=# shared secret gating the log_mcp_call reducer; must match EXPECTED_LOG_TOKEN in apps/internal-tool/spacetimedb/src/index.ts

View File

@ -1,138 +1,138 @@
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_DASHBOARD_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}01
NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX=.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09
NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR=false
STACK_SERVER_SECRET=23-wuNpik0gIW4mruTz25rbIvhuuvZFrLOLtL7J4tyo
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}01
NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX=.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09
NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR=false
HEXCLAVE_SERVER_SECRET=23-wuNpik0gIW4mruTz25rbIvhuuvZFrLOLtL7J4tyo
STACK_CHANGELOG_URL=https://raw.githubusercontent.com/hexclave/hexclave/refs/heads/dev/CHANGELOG.md
HEXCLAVE_CHANGELOG_URL=https://raw.githubusercontent.com/hexclave/hexclave/refs/heads/dev/CHANGELOG.md
STACK_SEED_ENABLE_DUMMY_PROJECT=true
STACK_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED=true
STACK_SEED_INTERNAL_PROJECT_OTP_ENABLED=true
STACK_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST=true
STACK_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS=github,spotify,google,microsoft
STACK_SEED_INTERNAL_PROJECT_USER_GITHUB_ID=admin@example.com
STACK_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS=true
STACK_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_INTERNAL_PROJECT_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY=this-super-secret-admin-key-is-for-local-development-only
HEXCLAVE_SEED_ENABLE_DUMMY_PROJECT=true
HEXCLAVE_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED=true
HEXCLAVE_SEED_INTERNAL_PROJECT_OTP_ENABLED=true
HEXCLAVE_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST=true
HEXCLAVE_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS=github,spotify,google,microsoft
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_GITHUB_ID=admin@example.com
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS=true
HEXCLAVE_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_INTERNAL_PROJECT_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
HEXCLAVE_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY=this-super-secret-admin-key-is-for-local-development-only
STACK_OAUTH_MOCK_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}14
STACK_TURNSTILE_SITEVERIFY_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}14/turnstile/siteverify
HEXCLAVE_OAUTH_MOCK_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}14
HEXCLAVE_TURNSTILE_SITEVERIFY_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}14/turnstile/siteverify
# Cloudflare Turnstile test keys — always-pass widgets, no real challenges
# See https://developers.cloudflare.com/turnstile/troubleshooting/testing/
NEXT_PUBLIC_STACK_BOT_CHALLENGE_SITE_KEY=1x00000000000000000000AA
NEXT_PUBLIC_STACK_BOT_CHALLENGE_INVISIBLE_SITE_KEY=1x00000000000000000000BB
STACK_TURNSTILE_SECRET_KEY=1x0000000000000000000000000000000AA
NEXT_PUBLIC_HEXCLAVE_BOT_CHALLENGE_SITE_KEY=1x00000000000000000000AA
NEXT_PUBLIC_HEXCLAVE_BOT_CHALLENGE_INVISIBLE_SITE_KEY=1x00000000000000000000BB
HEXCLAVE_TURNSTILE_SECRET_KEY=1x0000000000000000000000000000000AA
# Set to true to disable Turnstile entirely in local development.
# This skips invisible/visible bot challenge flow and removes the Turnstile risk penalty.
STACK_DISABLE_BOT_CHALLENGE=false
HEXCLAVE_DISABLE_BOT_CHALLENGE=false
# Default behavior is to block sign-up if the visible challenge cannot be completed.
# Flip this only when you intentionally want local sign-up to continue during Turnstile outages.
STACK_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE=false
HEXCLAVE_ALLOW_SIGN_UP_ON_VISIBLE_BOT_CHALLENGE_FAILURE=false
STACK_GITHUB_CLIENT_ID=MOCK
STACK_GITHUB_CLIENT_SECRET=MOCK
STACK_GOOGLE_CLIENT_ID=MOCK
STACK_GOOGLE_CLIENT_SECRET=MOCK
STACK_MICROSOFT_CLIENT_ID=MOCK
STACK_MICROSOFT_CLIENT_SECRET=MOCK
STACK_SPOTIFY_CLIENT_ID=MOCK
STACK_SPOTIFY_CLIENT_SECRET=MOCK
HEXCLAVE_GITHUB_CLIENT_ID=MOCK
HEXCLAVE_GITHUB_CLIENT_SECRET=MOCK
HEXCLAVE_GOOGLE_CLIENT_ID=MOCK
HEXCLAVE_GOOGLE_CLIENT_SECRET=MOCK
HEXCLAVE_MICROSOFT_CLIENT_ID=MOCK
HEXCLAVE_MICROSOFT_CLIENT_SECRET=MOCK
HEXCLAVE_SPOTIFY_CLIENT_ID=MOCK
HEXCLAVE_SPOTIFY_CLIENT_SECRET=MOCK
STACK_ALLOW_SHARED_OAUTH_ACCESS_TOKENS=true
HEXCLAVE_ALLOW_SHARED_OAUTH_ACCESS_TOKENS=true
# Default to enforcing plan limits in local dev so behavior matches prod.
# Flip to "true" to bypass every Stack-Auth-internal plan-limit enforcement
# site (e.g. session_replays, analytics_events, emails_per_month). See
# apps/backend/src/lib/plan-entitlements.ts:arePlanLimitsEnforced.
STACK_DISABLE_PLAN_LIMITS=false
HEXCLAVE_DISABLE_PLAN_LIMITS=false
STACK_DATABASE_CONNECTION_STRING=postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}28/stackframe
STACK_DATABASE_REPLICA_CONNECTION_STRING=postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}34/stackframe
STACK_DATABASE_REPLICATION_WAIT_STRATEGY=pg-stat-replication
HEXCLAVE_DATABASE_CONNECTION_STRING=postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}28/stackframe
HEXCLAVE_DATABASE_REPLICA_CONNECTION_STRING=postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}34/stackframe
HEXCLAVE_DATABASE_REPLICATION_WAIT_STRATEGY=pg-stat-replication
STACK_EMAIL_HOST=127.0.0.1
STACK_EMAIL_PORT=${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}29
STACK_EMAIL_SECURE=false
STACK_EMAIL_USERNAME="does not matter, ignored by Inbucket"
STACK_EMAIL_PASSWORD="does not matter, ignored by Inbucket"
STACK_EMAIL_SENDER=noreply@example.com
HEXCLAVE_EMAIL_HOST=127.0.0.1
HEXCLAVE_EMAIL_PORT=${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}29
HEXCLAVE_EMAIL_SECURE=false
HEXCLAVE_EMAIL_USERNAME="does not matter, ignored by Inbucket"
HEXCLAVE_EMAIL_PASSWORD="does not matter, ignored by Inbucket"
HEXCLAVE_EMAIL_SENDER=noreply@example.com
STACK_ACCESS_TOKEN_EXPIRATION_TIME=60s
HEXCLAVE_ACCESS_TOKEN_EXPIRATION_TIME=60s
STACK_DEFAULT_EMAIL_CAPACITY_PER_HOUR=100000
HEXCLAVE_DEFAULT_EMAIL_CAPACITY_PER_HOUR=100000
STACK_SVIX_SERVER_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}13
STACK_SVIX_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NTUxNDA2MzksImV4cCI6MTk3MDUwMDYzOSwibmJmIjoxNjU1MTQwNjM5LCJpc3MiOiJzdml4LXNlcnZlciIsInN1YiI6Im9yZ18yM3JiOFlkR3FNVDBxSXpwZ0d3ZFhmSGlyTXUifQ.En8w77ZJWbd0qrMlHHupHUB-4cx17RfzFykseg95SUk
HEXCLAVE_SVIX_SERVER_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}13
HEXCLAVE_SVIX_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NTUxNDA2MzksImV4cCI6MTk3MDUwMDYzOSwibmJmIjoxNjU1MTQwNjM5LCJpc3MiOiJzdml4LXNlcnZlciIsInN1YiI6Im9yZ18yM3JiOFlkR3FNVDBxSXpwZ0d3ZFhmSGlyTXUifQ.En8w77ZJWbd0qrMlHHupHUB-4cx17RfzFykseg95SUk
# Trusted reverse proxy for reading real client IP addresses.
# Set to "vercel", "cloudflare", or leave empty/unset for no proxy trust.
STACK_TRUSTED_PROXY=
HEXCLAVE_TRUSTED_PROXY=
STACK_ARTIFICIAL_DEVELOPMENT_DELAY_MS=500
HEXCLAVE_ARTIFICIAL_DEVELOPMENT_DELAY_MS=500
STACK_ENABLE_HARDCODED_PASSKEY_CHALLENGE_FOR_TESTING=yes
HEXCLAVE_ENABLE_HARDCODED_PASSKEY_CHALLENGE_FOR_TESTING=yes
STACK_INTEGRATION_CLIENTS_CONFIG='[{"client_id": "neon-local", "client_secret": "neon-local-secret", "id_token_signed_response_alg": "ES256", "redirect_uris": ["http://localhost:30000/api/v2/identity/authorize", "http://localhost:30000/api/v2/auth/authorize"]}, {"client_id": "custom-local", "client_secret": "custom-local-secret", "id_token_signed_response_alg": "ES256", "redirect_uris": ["http://localhost:30000/api/v2/identity/authorize", "http://localhost:30000/api/v2/auth/authorize"]}]'
HEXCLAVE_INTEGRATION_CLIENTS_CONFIG='[{"client_id": "neon-local", "client_secret": "neon-local-secret", "id_token_signed_response_alg": "ES256", "redirect_uris": ["http://localhost:30000/api/v2/identity/authorize", "http://localhost:30000/api/v2/auth/authorize"]}, {"client_id": "custom-local", "client_secret": "custom-local-secret", "id_token_signed_response_alg": "ES256", "redirect_uris": ["http://localhost:30000/api/v2/identity/authorize", "http://localhost:30000/api/v2/auth/authorize"]}]'
CRON_SECRET=mock_cron_secret
STACK_FREESTYLE_API_KEY=mock_stack_freestyle_key
STACK_VERCEL_SANDBOX_TOKEN=vercel_sandbox_disabled_for_local_development
STACK_OPENAI_API_KEY=mock_openai_api_key
STACK_STRIPE_SECRET_KEY=sk_test_mockstripekey
STACK_STRIPE_WEBHOOK_SECRET=mock_stripe_webhook_secret
STACK_OPENROUTER_API_KEY=FORWARD_TO_PRODUCTION
STACK_FEEDBACK_MODE=FORWARD_TO_PRODUCTION
STACK_MINTLIFY_MCP_URL=https://stackauth-e0affa27.mintlify.app/mcp
HEXCLAVE_FREESTYLE_API_KEY=mock_stack_freestyle_key
HEXCLAVE_VERCEL_SANDBOX_TOKEN=vercel_sandbox_disabled_for_local_development
HEXCLAVE_OPENAI_API_KEY=mock_openai_api_key
HEXCLAVE_STRIPE_SECRET_KEY=sk_test_mockstripekey
HEXCLAVE_STRIPE_WEBHOOK_SECRET=mock_stripe_webhook_secret
HEXCLAVE_OPENROUTER_API_KEY=FORWARD_TO_PRODUCTION
HEXCLAVE_FEEDBACK_MODE=FORWARD_TO_PRODUCTION
HEXCLAVE_MINTLIFY_MCP_URL=https://stackauth-e0affa27.mintlify.app/mcp
# Email monitor configuration for tests
STACK_EMAIL_MONITOR_VERIFICATION_CALLBACK_URL=http://localhost:8101/handler/email-verification
STACK_EMAIL_MONITOR_PROJECT_ID=internal
STACK_EMAIL_MONITOR_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_EMAIL_MONITOR_RESEND_EMAIL_DOMAIN=stack-generated.example.com
STACK_EMAIL_MONITOR_RESEND_EMAIL_API_KEY=this-is-a-fake-key
STACK_EMAIL_MONITOR_INBUCKET_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}05
STACK_EMAIL_MONITOR_USE_INBUCKET=true
STACK_EMAIL_MONITOR_SECRET_TOKEN=this-secret-token-is-for-local-development-only
HEXCLAVE_EMAIL_MONITOR_VERIFICATION_CALLBACK_URL=http://localhost:8101/handler/email-verification
HEXCLAVE_EMAIL_MONITOR_PROJECT_ID=internal
HEXCLAVE_EMAIL_MONITOR_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_EMAIL_MONITOR_RESEND_EMAIL_DOMAIN=stack-generated.example.com
HEXCLAVE_EMAIL_MONITOR_RESEND_EMAIL_API_KEY=this-is-a-fake-key
HEXCLAVE_EMAIL_MONITOR_INBUCKET_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}05
HEXCLAVE_EMAIL_MONITOR_USE_INBUCKET=true
HEXCLAVE_EMAIL_MONITOR_SECRET_TOKEN=this-secret-token-is-for-local-development-only
STACK_EMAILABLE_API_KEY=
HEXCLAVE_EMAILABLE_API_KEY=
STACK_INTERNAL_FEEDBACK_RECIPIENTS=team@hexclave.com
HEXCLAVE_INTERNAL_FEEDBACK_RECIPIENTS=team@hexclave.com
# S3 Configuration for local development using s3mock
STACK_S3_ENDPOINT=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}21
STACK_S3_REGION=us-east-1
STACK_S3_ACCESS_KEY_ID=s3mockroot
STACK_S3_SECRET_ACCESS_KEY=s3mockroot
STACK_S3_BUCKET=stack-storage
STACK_S3_PRIVATE_BUCKET=stack-storage-private
HEXCLAVE_S3_ENDPOINT=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}21
HEXCLAVE_S3_REGION=us-east-1
HEXCLAVE_S3_ACCESS_KEY_ID=s3mockroot
HEXCLAVE_S3_SECRET_ACCESS_KEY=s3mockroot
HEXCLAVE_S3_BUCKET=stack-storage
HEXCLAVE_S3_PRIVATE_BUCKET=stack-storage-private
# AWS region defaults to LocalStack
STACK_AWS_REGION=us-east-1
STACK_AWS_KMS_ENDPOINT=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}24
STACK_AWS_ACCESS_KEY_ID=test
STACK_AWS_SECRET_ACCESS_KEY=test
HEXCLAVE_AWS_REGION=us-east-1
HEXCLAVE_AWS_KMS_ENDPOINT=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}24
HEXCLAVE_AWS_ACCESS_KEY_ID=test
HEXCLAVE_AWS_SECRET_ACCESS_KEY=test
# Upstash defaults to one of the pre-build test users of the local emulator
STACK_QSTASH_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}25
STACK_QSTASH_TOKEN=eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0=
STACK_QSTASH_CURRENT_SIGNING_KEY=sig_7kYjw48mhY7kAjqNGcy6cr29RJ6r
STACK_QSTASH_NEXT_SIGNING_KEY=sig_5ZB6DVzB1wjE8S6rZ7eenA8Pdnhs
HEXCLAVE_QSTASH_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}25
HEXCLAVE_QSTASH_TOKEN=eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0=
HEXCLAVE_QSTASH_CURRENT_SIGNING_KEY=sig_7kYjw48mhY7kAjqNGcy6cr29RJ6r
HEXCLAVE_QSTASH_NEXT_SIGNING_KEY=sig_5ZB6DVzB1wjE8S6rZ7eenA8Pdnhs
# MCP review tool (SpacetimeDB)
STACK_SPACETIMEDB_URI=ws://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}39
STACK_SPACETIMEDB_DB_NAME=stack-auth-llm
STACK_MCP_LOG_TOKEN=change-me
HEXCLAVE_SPACETIMEDB_URI=ws://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}39
HEXCLAVE_SPACETIMEDB_DB_NAME=stack-auth-llm
HEXCLAVE_MCP_LOG_TOKEN=change-me
# Clickhouse
STACK_CLICKHOUSE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}36
STACK_CLICKHOUSE_ADMIN_USER=stackframe
STACK_CLICKHOUSE_ADMIN_PASSWORD=PASSWORD-PLACEHOLDER--9gKyMxJeMx
STACK_CLICKHOUSE_EXTERNAL_PASSWORD=PASSWORD-PLACEHOLDER--EZeHscBMzE
HEXCLAVE_CLICKHOUSE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}36
HEXCLAVE_CLICKHOUSE_ADMIN_USER=stackframe
HEXCLAVE_CLICKHOUSE_ADMIN_PASSWORD=PASSWORD-PLACEHOLDER--9gKyMxJeMx
HEXCLAVE_CLICKHOUSE_EXTERNAL_PASSWORD=PASSWORD-PLACEHOLDER--EZeHscBMzE
# Managed emails
STACK_RESEND_API_KEY=mock_resend_api_key
STACK_RESEND_WEBHOOK_SECRET=mock_resend_webhook_secret
STACK_DNSIMPLE_API_TOKEN=mock_dnsimple_api_token
STACK_DNSIMPLE_ACCOUNT_ID=mock_dnsimple_account_id
STACK_DNSIMPLE_API_BASE_URL=https://api.dnsimple.com/v2
HEXCLAVE_RESEND_API_KEY=mock_resend_api_key
HEXCLAVE_RESEND_WEBHOOK_SECRET=mock_resend_webhook_secret
HEXCLAVE_DNSIMPLE_API_TOKEN=mock_dnsimple_api_token
HEXCLAVE_DNSIMPLE_ACCOUNT_ID=mock_dnsimple_account_id
HEXCLAVE_DNSIMPLE_API_BASE_URL=https://api.dnsimple.com/v2

View File

@ -56,21 +56,21 @@ function enableSeedLogTimestamps() {
export async function seed() {
enableSeedLogTimestamps();
process.env.STACK_SEED_MODE = 'true';
process.env.HEXCLAVE_SEED_MODE = 'true';
console.log('Seeding database...');
// Optional default admin user
const adminEmail = process.env.STACK_SEED_INTERNAL_PROJECT_USER_EMAIL;
const adminPassword = process.env.STACK_SEED_INTERNAL_PROJECT_USER_PASSWORD;
const adminInternalAccess = process.env.STACK_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS === 'true';
const adminGithubId = process.env.STACK_SEED_INTERNAL_PROJECT_USER_GITHUB_ID;
const adminEmail = (process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_USER_EMAIL || process.env.STACK_SEED_INTERNAL_PROJECT_USER_EMAIL);
const adminPassword = (process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_USER_PASSWORD || process.env.STACK_SEED_INTERNAL_PROJECT_USER_PASSWORD);
const adminInternalAccess = (process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS || process.env.STACK_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS) === 'true';
const adminGithubId = (process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_USER_GITHUB_ID || process.env.STACK_SEED_INTERNAL_PROJECT_USER_GITHUB_ID);
// dashboard settings
const dashboardDomain = process.env.NEXT_PUBLIC_STACK_DASHBOARD_URL;
const oauthProviderIds = process.env.STACK_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS?.split(',') ?? [];
const otpEnabled = process.env.STACK_SEED_INTERNAL_PROJECT_OTP_ENABLED === 'true';
const signUpEnabled = process.env.STACK_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED === 'true';
const allowLocalhost = process.env.STACK_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST === 'true';
const dashboardDomain = (process.env.NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL || process.env.NEXT_PUBLIC_STACK_DASHBOARD_URL);
const oauthProviderIds = (process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS || process.env.STACK_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS)?.split(',') ?? [];
const otpEnabled = (process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_OTP_ENABLED || process.env.STACK_SEED_INTERNAL_PROJECT_OTP_ENABLED) === 'true';
const signUpEnabled = (process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED || process.env.STACK_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED) === 'true';
const allowLocalhost = (process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST || process.env.STACK_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST) === 'true';
const localEmulatorEnabled = isLocalEmulatorEnabled();
@ -366,22 +366,22 @@ export async function seed() {
// seed, email/svix, clickhouse). The emulator CLI authenticates against the
// internal project using the pck stored here, so it must land before the rest
// of the seed even if something later fails.
const isLocalEmulator = process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR === 'true';
const rawPck = process.env.STACK_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY;
const isLocalEmulator = (process.env.NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR || process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR) === 'true';
const rawPck = (process.env.HEXCLAVE_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY || process.env.STACK_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY);
if (isLocalEmulator && !rawPck) {
// Emulator images build before a per-VM pck is available. Runtime boots set
// STACK_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY from the VM-generated
// HEXCLAVE_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY from the VM-generated
// random value and re-run the seed, which upserts the internal key set then.
console.log('Skipping internal API key set (no pck provided; emulator mode).');
} else {
const keySet = {
publishableClientKey: rawPck || throwErr('STACK_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY is not set'),
publishableClientKey: rawPck || throwErr('HEXCLAVE_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY is not set'),
secretServerKey: isLocalEmulator
? (process.env.STACK_INTERNAL_PROJECT_SECRET_SERVER_KEY ?? null)
: (process.env.STACK_INTERNAL_PROJECT_SECRET_SERVER_KEY || throwErr('STACK_INTERNAL_PROJECT_SECRET_SERVER_KEY is not set')),
? ((process.env.HEXCLAVE_INTERNAL_PROJECT_SECRET_SERVER_KEY || process.env.STACK_INTERNAL_PROJECT_SECRET_SERVER_KEY) ?? null)
: ((process.env.HEXCLAVE_INTERNAL_PROJECT_SECRET_SERVER_KEY || process.env.STACK_INTERNAL_PROJECT_SECRET_SERVER_KEY) || throwErr('HEXCLAVE_INTERNAL_PROJECT_SECRET_SERVER_KEY is not set')),
superSecretAdminKey: isLocalEmulator
? (process.env.STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY ?? null)
: (process.env.STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY || throwErr('STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY is not set')),
? ((process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY || process.env.STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY) ?? null)
: ((process.env.HEXCLAVE_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY || process.env.STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY) || throwErr('HEXCLAVE_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY is not set')),
};
await globalPrismaClient.apiKeySet.upsert({
@ -401,7 +401,7 @@ export async function seed() {
console.log('Updated internal API key set');
}
const shouldSeedDummyProject = process.env.STACK_SEED_ENABLE_DUMMY_PROJECT === 'true';
const shouldSeedDummyProject = (process.env.HEXCLAVE_SEED_ENABLE_DUMMY_PROJECT || process.env.STACK_SEED_ENABLE_DUMMY_PROJECT) === 'true';
if (shouldSeedDummyProject) {
await seedDummyProject({
projectId: DUMMY_PROJECT_ID,

View File

@ -125,35 +125,48 @@ export async function sendSupportFeedbackEmail(options: {
}
import.meta.vitest?.test("getInternalFeedbackRecipients()", ({ expect }) => {
// getEnvVariable resolves HEXCLAVE_INTERNAL_FEEDBACK_RECIPIENTS first and
// falls back to the legacy STACK_ name, so clear and restore both.
// eslint-disable-next-line no-restricted-syntax
const previousValue = process.env.STACK_INTERNAL_FEEDBACK_RECIPIENTS;
const previousValue = process.env.HEXCLAVE_INTERNAL_FEEDBACK_RECIPIENTS;
// eslint-disable-next-line no-restricted-syntax
const previousLegacyValue = process.env.STACK_INTERNAL_FEEDBACK_RECIPIENTS;
try {
// eslint-disable-next-line no-restricted-syntax
delete process.env.HEXCLAVE_INTERNAL_FEEDBACK_RECIPIENTS;
// eslint-disable-next-line no-restricted-syntax
delete process.env.STACK_INTERNAL_FEEDBACK_RECIPIENTS;
expect(() => getInternalFeedbackRecipients()).toThrow("Missing environment variable");
// eslint-disable-next-line no-restricted-syntax
process.env.STACK_INTERNAL_FEEDBACK_RECIPIENTS = "TEAM@hexclave.com, team@hexclave.com , another@example.com";
process.env.HEXCLAVE_INTERNAL_FEEDBACK_RECIPIENTS = "TEAM@hexclave.com, team@hexclave.com , another@example.com";
expect(getInternalFeedbackRecipients()).toEqual([
"team@hexclave.com",
"another@example.com",
]);
// eslint-disable-next-line no-restricted-syntax
process.env.STACK_INTERNAL_FEEDBACK_RECIPIENTS = "valid@example.com, ";
process.env.HEXCLAVE_INTERNAL_FEEDBACK_RECIPIENTS = "valid@example.com, ";
expect(() => getInternalFeedbackRecipients()).toThrow("empty recipient");
// eslint-disable-next-line no-restricted-syntax
process.env.STACK_INTERNAL_FEEDBACK_RECIPIENTS = ", ";
process.env.HEXCLAVE_INTERNAL_FEEDBACK_RECIPIENTS = ", ";
expect(() => getInternalFeedbackRecipients()).toThrow("empty recipient");
} finally {
if (previousValue === undefined) {
// eslint-disable-next-line no-restricted-syntax
delete process.env.HEXCLAVE_INTERNAL_FEEDBACK_RECIPIENTS;
} else {
// eslint-disable-next-line no-restricted-syntax
process.env.HEXCLAVE_INTERNAL_FEEDBACK_RECIPIENTS = previousValue;
}
if (previousLegacyValue === undefined) {
// eslint-disable-next-line no-restricted-syntax
delete process.env.STACK_INTERNAL_FEEDBACK_RECIPIENTS;
} else {
// eslint-disable-next-line no-restricted-syntax
process.env.STACK_INTERNAL_FEEDBACK_RECIPIENTS = previousValue;
process.env.STACK_INTERNAL_FEEDBACK_RECIPIENTS = previousLegacyValue;
}
}
});

View File

@ -1,20 +1,20 @@
# Basic
NEXT_PUBLIC_STACK_API_URL=# enter your stack endpoint here, For local development: http://localhost:8102 (no trailing slash)
NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR=# set to true to enable local emulator UI behavior (auto-login + read-only environment config updates)
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=# enter your Stack publishable client key here. For local development, just enter a random string, then run `pnpm db:reset`
STACK_SECRET_SERVER_KEY=# enter your Stack secret client key here. For local development, do the same as above
NEXT_PUBLIC_STACK_DOCS_BASE_URL=# enter the base URL of the docs here
NEXT_PUBLIC_STACK_EXTRA_REQUEST_HEADERS=# a list of extra request headers to add to all Hexclave API requests, as a JSON record
NEXT_PUBLIC_STACK_STRIPE_PUBLISHABLE_KEY=# enter your Stripe publishable key here
NEXT_PUBLIC_HEXCLAVE_API_URL=# enter your stack endpoint here, For local development: http://localhost:8102 (no trailing slash)
NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR=# set to true to enable local emulator UI behavior (auto-login + read-only environment config updates)
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=# enter your Stack publishable client key here. For local development, just enter a random string, then run `pnpm db:reset`
HEXCLAVE_SECRET_SERVER_KEY=# enter your Stack secret client key here. For local development, do the same as above
NEXT_PUBLIC_HEXCLAVE_DOCS_BASE_URL=# enter the base URL of the docs here
NEXT_PUBLIC_HEXCLAVE_EXTRA_REQUEST_HEADERS=# a list of extra request headers to add to all Hexclave API requests, as a JSON record
NEXT_PUBLIC_HEXCLAVE_STRIPE_PUBLISHABLE_KEY=# enter your Stripe publishable key here
# Webhooks
NEXT_PUBLIC_STACK_SVIX_SERVER_URL=# For prod, leave it empty. For local development, use `http://localhost:8113`
NEXT_PUBLIC_HEXCLAVE_SVIX_SERVER_URL=# For prod, leave it empty. For local development, use `http://localhost:8113`
# Misc, optional
NEXT_PUBLIC_STACK_HEAD_TAGS='[{ "tagName": "script", "attributes": {}, "innerHTML": "// insert head tags here" }]'
STACK_DEVELOPMENT_TRANSLATION_LOCALE=# enter the locale to use for the translation provider here, for example: de-DE. Only works during development, not in production. Optional, by default don't translate
NEXT_PUBLIC_STACK_ENABLE_DEVELOPMENT_FEATURES_PROJECT_IDS='["internal"]'
NEXT_PUBLIC_STACK_DEBUGGER_ON_ASSERTION_ERROR=# set to true to open the debugger on assertion errors (set to true in .env.development)
STACK_FEATUREBASE_JWT_SECRET=# used for Featurebase SSO, you probably won't have to set this
STACK_CHANGELOG_URL=# Used for raw github link to root changelog.md file.
NEXT_PUBLIC_HEXCLAVE_HEAD_TAGS='[{ "tagName": "script", "attributes": {}, "innerHTML": "// insert head tags here" }]'
HEXCLAVE_DEVELOPMENT_TRANSLATION_LOCALE=# enter the locale to use for the translation provider here, for example: de-DE. Only works during development, not in production. Optional, by default don't translate
NEXT_PUBLIC_HEXCLAVE_ENABLE_DEVELOPMENT_FEATURES_PROJECT_IDS='["internal"]'
NEXT_PUBLIC_HEXCLAVE_DEBUGGER_ON_ASSERTION_ERROR=# set to true to open the debugger on assertion errors (set to true in .env.development)
HEXCLAVE_FEATUREBASE_JWT_SECRET=# used for Featurebase SSO, you probably won't have to set this
HEXCLAVE_CHANGELOG_URL=# Used for raw github link to root changelog.md file.

View File

@ -1,15 +1,15 @@
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_DOCS_BASE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}26
NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX=.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09
NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR=false
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_DOCS_BASE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}26
NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX=.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09
NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR=false
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_STACK_SVIX_SERVER_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}13
STACK_ARTIFICIAL_DEVELOPMENT_DELAY_MS=50
NEXT_PUBLIC_HEXCLAVE_SVIX_SERVER_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}13
HEXCLAVE_ARTIFICIAL_DEVELOPMENT_DELAY_MS=50
NEXT_PUBLIC_STACK_DEBUGGER_ON_ASSERTION_ERROR=false
NEXT_PUBLIC_HEXCLAVE_DEBUGGER_ON_ASSERTION_ERROR=false
STACK_FEATUREBASE_JWT_SECRET=secret-value
HEXCLAVE_FEATUREBASE_JWT_SECRET=secret-value

View File

@ -12,36 +12,36 @@ export function expandHexclavePortPrefix(value?: string | null) {
// to the legacy NEXT_PUBLIC_*STACK_* literal. Both operands must stay literal
// `process.env.NEXT_PUBLIC_*` references so Next.js can inline them at build time.
const _inlineEnvVars = {
NEXT_PUBLIC_STACK_API_URL: process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL,
NEXT_PUBLIC_STACK_DASHBOARD_URL: process.env.NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL ?? process.env.NEXT_PUBLIC_STACK_DASHBOARD_URL,
NEXT_PUBLIC_STACK_SVIX_SERVER_URL: process.env.NEXT_PUBLIC_HEXCLAVE_SVIX_SERVER_URL ?? process.env.NEXT_PUBLIC_STACK_SVIX_SERVER_URL,
NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR: process.env.NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR ?? process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR,
NEXT_PUBLIC_STACK_IS_REMOTE_DEVELOPMENT_ENVIRONMENT: process.env.NEXT_PUBLIC_HEXCLAVE_IS_REMOTE_DEVELOPMENT_ENVIRONMENT ?? process.env.NEXT_PUBLIC_STACK_IS_REMOTE_DEVELOPMENT_ENVIRONMENT,
NEXT_PUBLIC_STACK_IS_PREVIEW: process.env.NEXT_PUBLIC_HEXCLAVE_IS_PREVIEW ?? process.env.NEXT_PUBLIC_STACK_IS_PREVIEW,
NEXT_PUBLIC_STACK_API_URL: process.env.NEXT_PUBLIC_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL,
NEXT_PUBLIC_STACK_DASHBOARD_URL: process.env.NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL || process.env.NEXT_PUBLIC_STACK_DASHBOARD_URL,
NEXT_PUBLIC_STACK_SVIX_SERVER_URL: process.env.NEXT_PUBLIC_HEXCLAVE_SVIX_SERVER_URL || process.env.NEXT_PUBLIC_STACK_SVIX_SERVER_URL,
NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR: process.env.NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR || process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR,
NEXT_PUBLIC_STACK_IS_REMOTE_DEVELOPMENT_ENVIRONMENT: process.env.NEXT_PUBLIC_HEXCLAVE_IS_REMOTE_DEVELOPMENT_ENVIRONMENT || process.env.NEXT_PUBLIC_STACK_IS_REMOTE_DEVELOPMENT_ENVIRONMENT,
NEXT_PUBLIC_STACK_IS_PREVIEW: process.env.NEXT_PUBLIC_HEXCLAVE_IS_PREVIEW || process.env.NEXT_PUBLIC_STACK_IS_PREVIEW,
NEXT_PUBLIC_HEXCLAVE_LOCAL_DASHBOARD_PORT: process.env.NEXT_PUBLIC_HEXCLAVE_LOCAL_DASHBOARD_PORT,
NEXT_PUBLIC_STACK_PROJECT_ID: process.env.NEXT_PUBLIC_HEXCLAVE_PROJECT_ID ?? process.env.NEXT_PUBLIC_STACK_PROJECT_ID,
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY: process.env.NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY ?? process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY,
NEXT_PUBLIC_STACK_URL: process.env.NEXT_PUBLIC_HEXCLAVE_URL ?? process.env.NEXT_PUBLIC_STACK_URL,
NEXT_PUBLIC_STACK_INBUCKET_WEB_URL: process.env.NEXT_PUBLIC_HEXCLAVE_INBUCKET_WEB_URL ?? process.env.NEXT_PUBLIC_STACK_INBUCKET_WEB_URL,
NEXT_PUBLIC_STACK_ENABLE_DEVELOPMENT_FEATURES_PROJECT_IDS: process.env.NEXT_PUBLIC_HEXCLAVE_ENABLE_DEVELOPMENT_FEATURES_PROJECT_IDS ?? process.env.NEXT_PUBLIC_STACK_ENABLE_DEVELOPMENT_FEATURES_PROJECT_IDS,
NEXT_PUBLIC_STACK_STRIPE_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_HEXCLAVE_STRIPE_PUBLISHABLE_KEY ?? process.env.NEXT_PUBLIC_STACK_STRIPE_PUBLISHABLE_KEY,
NEXT_PUBLIC_STACK_PROJECT_ID: process.env.NEXT_PUBLIC_HEXCLAVE_PROJECT_ID || process.env.NEXT_PUBLIC_STACK_PROJECT_ID,
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY: process.env.NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY || process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY,
NEXT_PUBLIC_STACK_URL: process.env.NEXT_PUBLIC_HEXCLAVE_URL || process.env.NEXT_PUBLIC_STACK_URL,
NEXT_PUBLIC_STACK_INBUCKET_WEB_URL: process.env.NEXT_PUBLIC_HEXCLAVE_INBUCKET_WEB_URL || process.env.NEXT_PUBLIC_STACK_INBUCKET_WEB_URL,
NEXT_PUBLIC_STACK_ENABLE_DEVELOPMENT_FEATURES_PROJECT_IDS: process.env.NEXT_PUBLIC_HEXCLAVE_ENABLE_DEVELOPMENT_FEATURES_PROJECT_IDS || process.env.NEXT_PUBLIC_STACK_ENABLE_DEVELOPMENT_FEATURES_PROJECT_IDS,
NEXT_PUBLIC_STACK_STRIPE_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_HEXCLAVE_STRIPE_PUBLISHABLE_KEY || process.env.NEXT_PUBLIC_STACK_STRIPE_PUBLISHABLE_KEY,
// Hexclave rebrand: port-prefix var renamed outright (no dual-read).
NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX: process.env.NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX,
NEXT_PUBLIC_STACK_DOCS_BASE_URL: process.env.NEXT_PUBLIC_HEXCLAVE_DOCS_BASE_URL ?? process.env.NEXT_PUBLIC_STACK_DOCS_BASE_URL,
NEXT_PUBLIC_STACK_ENABLE_REACT_SCAN_IN_DEVELOPMENT: process.env.NEXT_PUBLIC_HEXCLAVE_ENABLE_REACT_SCAN_IN_DEVELOPMENT ?? process.env.NEXT_PUBLIC_STACK_ENABLE_REACT_SCAN_IN_DEVELOPMENT,
NEXT_PUBLIC_STACK_DOCS_BASE_URL: process.env.NEXT_PUBLIC_HEXCLAVE_DOCS_BASE_URL || process.env.NEXT_PUBLIC_STACK_DOCS_BASE_URL,
NEXT_PUBLIC_STACK_ENABLE_REACT_SCAN_IN_DEVELOPMENT: process.env.NEXT_PUBLIC_HEXCLAVE_ENABLE_REACT_SCAN_IN_DEVELOPMENT || process.env.NEXT_PUBLIC_STACK_ENABLE_REACT_SCAN_IN_DEVELOPMENT,
// TODO: NEXT_PUBLIC_BROWSER_STACK_API_URL should be renamed to NEXT_PUBLIC_STACK_BROWSER_API_URL
NEXT_PUBLIC_BROWSER_STACK_API_URL: process.env.NEXT_PUBLIC_BROWSER_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_BROWSER_STACK_API_URL,
NEXT_PUBLIC_BROWSER_STACK_API_URL: process.env.NEXT_PUBLIC_BROWSER_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_BROWSER_STACK_API_URL,
// TODO: NEXT_PUBLIC_SERVER_STACK_API_URL should be renamed to NEXT_PUBLIC_STACK_SERVER_API_URL
NEXT_PUBLIC_SERVER_STACK_API_URL: process.env.NEXT_PUBLIC_SERVER_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_SERVER_STACK_API_URL,
NEXT_PUBLIC_SERVER_STACK_API_URL: process.env.NEXT_PUBLIC_SERVER_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_SERVER_STACK_API_URL,
// TODO: NEXT_PUBLIC_SENTRY_DSN should be renamed to NEXT_PUBLIC_STACK_SENTRY_DSN
NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN,
// TODO: NEXT_PUBLIC_VERSION_ALERTER_SEVERE_ONLY should be renamed to NEXT_PUBLIC_STACK_VERSION_ALERTER_SEVERE_ONLY
NEXT_PUBLIC_VERSION_ALERTER_SEVERE_ONLY: process.env.NEXT_PUBLIC_VERSION_ALERTER_SEVERE_ONLY,
// TODO: NEXT_PUBLIC_BROWSER_STACK_DASHBOARD_URL should be renamed to NEXT_PUBLIC_STACK_BROWSER_DASHBOARD_URL
NEXT_PUBLIC_BROWSER_STACK_DASHBOARD_URL: process.env.NEXT_PUBLIC_BROWSER_HEXCLAVE_DASHBOARD_URL ?? process.env.NEXT_PUBLIC_BROWSER_STACK_DASHBOARD_URL,
NEXT_PUBLIC_BROWSER_STACK_DASHBOARD_URL: process.env.NEXT_PUBLIC_BROWSER_HEXCLAVE_DASHBOARD_URL || process.env.NEXT_PUBLIC_BROWSER_STACK_DASHBOARD_URL,
// TODO: NEXT_PUBLIC_SERVER_STACK_DASHBOARD_URL should be renamed to NEXT_PUBLIC_STACK_SERVER_DASHBOARD_URL
NEXT_PUBLIC_SERVER_STACK_DASHBOARD_URL: process.env.NEXT_PUBLIC_SERVER_HEXCLAVE_DASHBOARD_URL ?? process.env.NEXT_PUBLIC_SERVER_STACK_DASHBOARD_URL,
NEXT_PUBLIC_SERVER_STACK_DASHBOARD_URL: process.env.NEXT_PUBLIC_SERVER_HEXCLAVE_DASHBOARD_URL || process.env.NEXT_PUBLIC_SERVER_STACK_DASHBOARD_URL,
// TODO: NEXT_PUBLIC_POSTHOG_KEY should be renamed to NEXT_PUBLIC_STACK_POSTHOG_KEY
NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY,
} as const;

View File

@ -1,11 +1,11 @@
STACK_DASHBOARD_BASE_URL=
STACK_BACKEND_BASE_URL=
STACK_MCP_BASE_URL=
STACK_INTERNAL_PROJECT_ID=
STACK_INTERNAL_PROJECT_CLIENT_KEY=
STACK_INTERNAL_PROJECT_SERVER_KEY=
STACK_INTERNAL_PROJECT_ADMIN_KEY=
STACK_TEST_SOURCE_OF_TRUTH=
STACK_DATABASE_CONNECTION_STRING=
HEXCLAVE_DASHBOARD_BASE_URL=
HEXCLAVE_BACKEND_BASE_URL=
HEXCLAVE_MCP_BASE_URL=
HEXCLAVE_INTERNAL_PROJECT_ID=
HEXCLAVE_INTERNAL_PROJECT_CLIENT_KEY=
HEXCLAVE_INTERNAL_PROJECT_SERVER_KEY=
HEXCLAVE_INTERNAL_PROJECT_ADMIN_KEY=
HEXCLAVE_TEST_SOURCE_OF_TRUTH=
HEXCLAVE_DATABASE_CONNECTION_STRING=
STACK_INBUCKET_API_URL=
HEXCLAVE_INBUCKET_API_URL=

View File

@ -1,16 +1,16 @@
STACK_DASHBOARD_BASE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}01
STACK_BACKEND_BASE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
STACK_MCP_BASE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}44
STACK_INTERNAL_PROJECT_ID=internal
STACK_INTERNAL_PROJECT_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_INTERNAL_PROJECT_SERVER_KEY=this-secret-server-key-is-for-local-development-only
STACK_INTERNAL_PROJECT_ADMIN_KEY=this-super-secret-admin-key-is-for-local-development-only
NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX=.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09
STACK_DATABASE_CONNECTION_STRING=postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}28/stackframe
HEXCLAVE_DASHBOARD_BASE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}01
HEXCLAVE_BACKEND_BASE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
HEXCLAVE_MCP_BASE_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}44
HEXCLAVE_INTERNAL_PROJECT_ID=internal
HEXCLAVE_INTERNAL_PROJECT_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_INTERNAL_PROJECT_SERVER_KEY=this-secret-server-key-is-for-local-development-only
HEXCLAVE_INTERNAL_PROJECT_ADMIN_KEY=this-super-secret-admin-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX=.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09
HEXCLAVE_DATABASE_CONNECTION_STRING=postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}28/stackframe
STACK_INBUCKET_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}05
STACK_SVIX_SERVER_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}13
HEXCLAVE_INBUCKET_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}05
HEXCLAVE_SVIX_SERVER_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}13
STACK_EMAIL_MONITOR_SECRET_TOKEN=this-secret-token-is-for-local-development-only
HEXCLAVE_EMAIL_MONITOR_SECRET_TOKEN=this-secret-token-is-for-local-development-only
CRON_SECRET=mock_cron_secret

View File

@ -44,7 +44,7 @@ it("should send email notification to user when revoking an API key through cred
},
});
if (process.env.STACK_TEST_SOURCE_OF_TRUTH === "true") {
if ((process.env.HEXCLAVE_TEST_SOURCE_OF_TRUTH || process.env.STACK_TEST_SOURCE_OF_TRUTH) === "true") {
expect(revokeResponse).toMatchInlineSnapshot(`
NiceResponse {
"status": 404,
@ -180,7 +180,7 @@ it("should send email notification to team members when revoking a team API key
},
});
if (process.env.STACK_TEST_SOURCE_OF_TRUTH === "true") {
if ((process.env.HEXCLAVE_TEST_SOURCE_OF_TRUTH || process.env.STACK_TEST_SOURCE_OF_TRUTH) === "true") {
expect(revokeResponse).toMatchInlineSnapshot(`
NiceResponse {
"status": 404,
@ -353,7 +353,7 @@ it("should handle already revoked API keys gracefully", async ({ expect }: { exp
},
});
if (process.env.STACK_TEST_SOURCE_OF_TRUTH === "true") {
if ((process.env.HEXCLAVE_TEST_SOURCE_OF_TRUTH || process.env.STACK_TEST_SOURCE_OF_TRUTH) === "true") {
expect(revokeResponse).toMatchInlineSnapshot(`
NiceResponse {
"status": 404,

View File

@ -5,7 +5,7 @@ import { describe } from "vitest";
import { it } from "../../../../../helpers";
import { backendContext, niceBackendFetch } from "../../../../backend-helpers";
const isLocalEmulator = process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR === "true";
const isLocalEmulator = (process.env.NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR || process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR) === "true";
const blockedMessage = "cannot be changed in a development environment";
const localEmulatorProjectEndpoint = "/api/v1/internal/local-emulator/project";

View File

@ -168,7 +168,7 @@ describe("with valid credentials", () => {
const { response, batches: mockProjectFailedEmails } = await waitForFailedEmailsDigest(2);
expect(response.status).toBe(200);
if (process.env.STACK_TEST_SOURCE_OF_TRUTH === "true") {
if ((process.env.HEXCLAVE_TEST_SOURCE_OF_TRUTH || process.env.STACK_TEST_SOURCE_OF_TRUTH) === "true") {
expect(mockProjectFailedEmails).toMatchInlineSnapshot(`[]`);
} else {
expect(mockProjectFailedEmails).toMatchInlineSnapshot(`
@ -460,7 +460,7 @@ describe("with valid credentials", () => {
(batch: any) => batch.project_id === projectId
);
if (process.env.STACK_TEST_SOURCE_OF_TRUTH === "true") {
if ((process.env.HEXCLAVE_TEST_SOURCE_OF_TRUTH || process.env.STACK_TEST_SOURCE_OF_TRUTH) === "true") {
expect(currentResponses).toMatchInlineSnapshot(`[]`);
} else {
expect(currentResponses.length).toBe(1);

View File

@ -3,7 +3,7 @@ import { describe } from "vitest";
import { it } from "../../../../../helpers";
import { Auth, backendContext, createMailbox, niceBackendFetch, waitForOutboxEmailWithStatus } from "../../../../backend-helpers";
const isLocalEmulator = process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR === "true";
const isLocalEmulator = (process.env.NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR || process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR) === "true";
const supportConversationsPath = "/api/v1/internal/dogfood/support/conversations";
describe("POST /api/v1/internal/feedback", () => {

View File

@ -7,7 +7,7 @@ import { backendContext, niceBackendFetch } from "../../../../backend-helpers";
const LOCAL_EMULATOR_PROJECT_ENDPOINT = "/api/v1/internal/local-emulator/project";
const LOCAL_EMULATOR_OWNER_TEAM_ID = "5a0c858b-d9e9-49d4-9943-8ce385d86428";
const isLocalEmulator = process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR === "true";
const isLocalEmulator = (process.env.NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR || process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR) === "true";
async function createTempConfigFile(): Promise<string> {
const filePath = `/tmp/${randomUUID()}/stack.config.ts`;

View File

@ -72,7 +72,7 @@ async function createPurchaseCodeForCustomer(options: { customerType: "user" | "
return code as string;
}
const stripeWebhookSecret = process.env.STACK_STRIPE_WEBHOOK_SECRET ?? "mock_stripe_webhook_secret";
const stripeWebhookSecret = (process.env.HEXCLAVE_STRIPE_WEBHOOK_SECRET || process.env.STACK_STRIPE_WEBHOOK_SECRET) ?? "mock_stripe_webhook_secret";
async function sendStripeWebhook(payload: unknown) {
const timestamp = Math.floor(Date.now() / 1000);

View File

@ -7,7 +7,7 @@ import { Result } from "@hexclave/shared/dist/utils/results";
import { describe, beforeAll, afterAll } from "vitest";
import { it, niceFetch, STACK_BACKEND_BASE_URL, STACK_INTERNAL_PROJECT_CLIENT_KEY, STACK_INTERNAL_PROJECT_SERVER_KEY, STACK_INTERNAL_PROJECT_ADMIN_KEY } from "../helpers";
const isLocalEmulator = process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR === "true";
const isLocalEmulator = (process.env.NEXT_PUBLIC_HEXCLAVE_IS_LOCAL_EMULATOR || process.env.NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR) === "true";
const CLI_BIN = path.resolve("packages/cli/dist/index.js");

View File

@ -241,7 +241,7 @@ export class Mailbox {
};
this.waitForMessagesWithSubjectCount = async (subject: string, minCount: number, options?: { noBody?: boolean }) => {
const timeoutMs = Number(process.env.STACK_MAILBOX_WAIT_TIMEOUT_MS ?? 60000);
const timeoutMs = Number((process.env.HEXCLAVE_MAILBOX_WAIT_TIMEOUT_MS || process.env.STACK_MAILBOX_WAIT_TIMEOUT_MS) ?? 60000);
const intervalMs = 500;
const deadline = Date.now() + timeoutMs;
let messages: MailboxMessage[] = [];
@ -324,7 +324,7 @@ export const STACK_MCP_BASE_URL = getEnvVariable("STACK_MCP_BASE_URL");
* fallback port. Always thread this through to SDK constructors instead of
* hardcoding `STACK_BACKEND_BASE_URL`.
*/
export const SDK_BASE_URL: string | undefined = process.env.STACK_TEST_SDK_FALLBACK
export const SDK_BASE_URL: string | undefined = (process.env.HEXCLAVE_TEST_SDK_FALLBACK || process.env.STACK_TEST_SDK_FALLBACK)
? undefined
: STACK_BACKEND_BASE_URL;
export const STACK_INTERNAL_PROJECT_ID = getEnvVariable("STACK_INTERNAL_PROJECT_ID");

View File

@ -31,24 +31,31 @@ function createMockDocument(): Document {
}
const withHostedDomainSuffix = async (callback: () => Promise<void>) => {
const oldHostedHandlerDomainSuffix = process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX;
const oldHostedHandlerUrlTemplate = process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE;
process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX = ".example-stack-hosted.test";
// The SDK resolves NEXT_PUBLIC_HEXCLAVE_* before the legacy NEXT_PUBLIC_STACK_*
// names, so override the canonical name and clear both spellings.
const oldHostedHandlerDomainSuffix = process.env.NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX;
const oldLegacyHostedHandlerDomainSuffix = process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX;
const oldHostedHandlerUrlTemplate = process.env.NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE;
const oldLegacyHostedHandlerUrlTemplate = process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE;
process.env.NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX = ".example-stack-hosted.test";
delete process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX;
delete process.env.NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE;
delete process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE;
try {
await callback();
} finally {
if (oldHostedHandlerDomainSuffix == null) {
delete process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX;
} else {
process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX = oldHostedHandlerDomainSuffix;
}
if (oldHostedHandlerUrlTemplate == null) {
delete process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE;
} else {
process.env.NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE = oldHostedHandlerUrlTemplate;
}
const restore = (name: string, value: string | undefined) => {
if (value == null) {
delete process.env[name];
} else {
process.env[name] = value;
}
};
restore("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX", oldHostedHandlerDomainSuffix);
restore("NEXT_PUBLIC_STACK_HOSTED_HANDLER_DOMAIN_SUFFIX", oldLegacyHostedHandlerDomainSuffix);
restore("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE", oldHostedHandlerUrlTemplate);
restore("NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE", oldLegacyHostedHandlerUrlTemplate);
}
};

View File

@ -1 +1 @@
VITE_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
VITE_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02

View File

@ -1,9 +1,9 @@
# Hexclave
NEXT_PUBLIC_STACK_API_URL=REPLACE_ME
NEXT_PUBLIC_STACK_PROJECT_ID=REPLACE_ME
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=REPLACE_ME
STACK_SECRET_SERVER_KEY=REPLACE_ME
NEXT_PUBLIC_STACK_DASHBOARD_URL=REPLACE_ME
NEXT_PUBLIC_HEXCLAVE_API_URL=REPLACE_ME
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=REPLACE_ME
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=REPLACE_ME
HEXCLAVE_SECRET_SERVER_KEY=REPLACE_ME
NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL=REPLACE_ME
# SpacetimeDB
NEXT_PUBLIC_SPACETIMEDB_HOST=REPLACE_ME
NEXT_PUBLIC_SPACETIMEDB_DB_NAME=REPLACE_ME

View File

@ -1,6 +1,6 @@
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
NEXT_PUBLIC_STACK_DASHBOARD_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}01
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}01
NEXT_PUBLIC_SPACETIMEDB_HOST=ws://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}39
NEXT_PUBLIC_SPACETIMEDB_DB_NAME=stack-auth-llm

View File

@ -8,8 +8,8 @@ const target = process.argv[2]; // "local" or "prod"
/** HTTP API for 'spacetime publish' (matches docker/dependencies/docker.compose.yaml host port ...39). */
function localPublishServerUrl() {
if (process.env.STACK_SPACETIME_PUBLISH_URL) {
return process.env.STACK_SPACETIME_PUBLISH_URL;
if ((process.env.HEXCLAVE_SPACETIME_PUBLISH_URL || process.env.STACK_SPACETIME_PUBLISH_URL)) {
return (process.env.HEXCLAVE_SPACETIME_PUBLISH_URL || process.env.STACK_SPACETIME_PUBLISH_URL);
}
const prefix = process.env.NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX ?? "81";
return `http://127.0.0.1:${prefix}39`;
@ -36,7 +36,7 @@ if (!args) {
process.exit(1);
}
if (target === "prod" && !process.env.STACK_MCP_LOG_TOKEN) {
if (target === "prod" && !(process.env.HEXCLAVE_MCP_LOG_TOKEN || process.env.STACK_MCP_LOG_TOKEN)) {
console.error("Error: STACK_MCP_LOG_TOKEN must be set for prod publish");
process.exit(1);
}

View File

@ -12,7 +12,7 @@ const PLACEHOLDER = "__SPACETIMEDB_LOG_TOKEN__";
const action = process.argv[2];
if (action === "inject") {
const token = process.env.STACK_MCP_LOG_TOKEN || "change-me";
const token = (process.env.HEXCLAVE_MCP_LOG_TOKEN || process.env.STACK_MCP_LOG_TOKEN) || "change-me";
if (existsSync(BACKUP)) {
console.error("Refusing to inject: backup already exists. Run restore first.");
process.exit(1);

View File

@ -26,7 +26,7 @@ export default function App() {
<h1 className="text-lg font-semibold text-gray-900 mb-2">MCP Review Tool</h1>
<p className="text-sm text-gray-500 mb-4">
Sign in to the{" "}
<a href={process.env.NEXT_PUBLIC_STACK_DASHBOARD_URL} className="text-blue-600 underline" target="_blank" rel="noreferrer">
<a href={(process.env.NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL || process.env.NEXT_PUBLIC_STACK_DASHBOARD_URL)} className="text-blue-600 underline" target="_blank" rel="noreferrer">
Hexclave Dashboard
</a>
{" "}first, then reload this page.

View File

@ -1,3 +1,3 @@
NEXT_PUBLIC_STACK_API_URL=
NEXT_PUBLIC_SERVER_STACK_API_URL=
NEXT_PUBLIC_HEXCLAVE_API_URL=
NEXT_PUBLIC_SERVER_HEXCLAVE_API_URL=
NEXT_PUBLIC_POSTHOG_KEY=

View File

@ -1 +1 @@
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02

View File

@ -1,3 +1,3 @@
NEXT_PUBLIC_STACK_API_URL=# the base URL of Stack's backend/API. For local development, this is `http://localhost:8102`; for the managed service, this is `https://api.hexclave.com`.
NEXT_PUBLIC_SERVER_STACK_API_URL=# optional server-side override for the backend/API URL. If unset, falls back to NEXT_PUBLIC_STACK_API_URL.
NEXT_PUBLIC_HEXCLAVE_API_URL=# the base URL of Stack's backend/API. For local development, this is `http://localhost:8102`; for the managed service, this is `https://api.hexclave.com`.
NEXT_PUBLIC_SERVER_HEXCLAVE_API_URL=# optional server-side override for the backend/API URL. If unset, falls back to NEXT_PUBLIC_HEXCLAVE_API_URL.
NEXT_PUBLIC_POSTHOG_KEY=# optional PostHog project key for analytics. Leave blank to use the default public key.

View File

@ -22,6 +22,10 @@ set -euo pipefail
OUTPUT=/run/stack-auth/rotated-secrets.env
WORK_DIR="${STACK_RUNTIME_WORK_DIR:-/app}"
# Hexclave rebrand: the container env may carry the canonical HEXCLAVE_ name
# instead of the legacy STACK_ one this script reads.
STACK_DATABASE_CONNECTION_STRING="${STACK_DATABASE_CONNECTION_STRING:-${HEXCLAVE_DATABASE_CONNECTION_STRING:-}}"
PLACEHOLDER_PCK="00000000000000000000000000000000ffffffffffffffffffffffffffffffff"
log() { printf '[rotate-secrets] %s\n' "$*"; }

View File

@ -1,42 +1,42 @@
NEXT_PUBLIC_STACK_API_URL=# https://your-backend-domain.com
NEXT_PUBLIC_STACK_DASHBOARD_URL=# https://your-dashboard-domain.com, this will be added as a trusted domain by the seed script
NEXT_PUBLIC_HEXCLAVE_API_URL=# https://your-backend-domain.com
NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL=# https://your-dashboard-domain.com, this will be added as a trusted domain by the seed script
STACK_DATABASE_CONNECTION_STRING=# postgres connection string
HEXCLAVE_DATABASE_CONNECTION_STRING=# postgres connection string
STACK_SERVER_SECRET=# a 32 bytes base64url encoded random string, used for JWT encryption. can be generated with `pnpm generate-keys`
HEXCLAVE_SERVER_SECRET=# a 32 bytes base64url encoded random string, used for JWT encryption. can be generated with `pnpm generate-keys`
# seed script settings
STACK_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED=# true to enable user sign up to the dashboard when seeding
STACK_SEED_INTERNAL_PROJECT_OTP_ENABLED=# true to add OTP auth to the dashboard when seeding
STACK_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST=# true to allow running dashboard on the localhost, set this to true only in development
STACK_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS=# list of oauth providers to add to the dashboard when seeding, separated by comma, for example "github,google,facebook"
STACK_SEED_INTERNAL_PROJECT_USER_EMAIL=# default user added to the dashboard
STACK_SEED_INTERNAL_PROJECT_USER_PASSWORD=# default user's password, paired with STACK_SEED_INTERNAL_PROJECT_USER_EMAIL
STACK_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS=# if the default user has access to the internal dashboard project
STACK_SEED_INTERNAL_PROJECT_USER_GITHUB_ID=# add github oauth id to the default user
HEXCLAVE_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED=# true to enable user sign up to the dashboard when seeding
HEXCLAVE_SEED_INTERNAL_PROJECT_OTP_ENABLED=# true to add OTP auth to the dashboard when seeding
HEXCLAVE_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST=# true to allow running dashboard on the localhost, set this to true only in development
HEXCLAVE_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS=# list of oauth providers to add to the dashboard when seeding, separated by comma, for example "github,google,facebook"
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_EMAIL=# default user added to the dashboard
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_PASSWORD=# default user's password, paired with HEXCLAVE_SEED_INTERNAL_PROJECT_USER_EMAIL
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS=# if the default user has access to the internal dashboard project
HEXCLAVE_SEED_INTERNAL_PROJECT_USER_GITHUB_ID=# add github oauth id to the default user
# Set these if you want to use any email functionality
STACK_EMAILABLE_API_KEY=disable_email_validation
STACK_EMAIL_HOST=
STACK_EMAIL_PORT=
STACK_EMAIL_USERNAME=
STACK_EMAIL_PASSWORD=
STACK_EMAIL_SENDER=
HEXCLAVE_EMAILABLE_API_KEY=disable_email_validation
HEXCLAVE_EMAIL_HOST=
HEXCLAVE_EMAIL_PORT=
HEXCLAVE_EMAIL_USERNAME=
HEXCLAVE_EMAIL_PASSWORD=
HEXCLAVE_EMAIL_SENDER=
# Set these if you want to use webhooks
STACK_SVIX_SERVER_URL=# this is only needed if you self-host the Svix service
NEXT_PUBLIC_STACK_SVIX_SERVER_URL=# this is only needed if you are using docker compose and the external and internal urls are different. This is the external url for the Svix service.
STACK_SVIX_API_KEY=
HEXCLAVE_SVIX_SERVER_URL=# this is only needed if you self-host the Svix service
NEXT_PUBLIC_HEXCLAVE_SVIX_SERVER_URL=# this is only needed if you are using docker compose and the external and internal urls are different. This is the external url for the Svix service.
HEXCLAVE_SVIX_API_KEY=
STACK_OPENROUTER_API_KEY=# enter your OpenRouter API key for AI features
HEXCLAVE_OPENROUTER_API_KEY=# enter your OpenRouter API key for AI features
STACK_SKIP_SEED_SCRIPT=# true to skip the seed script
HEXCLAVE_SKIP_SEED_SCRIPT=# true to skip the seed script
STACK_S3_ENDPOINT=
STACK_S3_REGION=
STACK_S3_ACCESS_KEY_ID=
STACK_S3_SECRET_ACCESS_KEY=
STACK_S3_BUCKET=
STACK_S3_PRIVATE_BUCKET=
HEXCLAVE_S3_ENDPOINT=
HEXCLAVE_S3_REGION=
HEXCLAVE_S3_ACCESS_KEY_ID=
HEXCLAVE_S3_SECRET_ACCESS_KEY=
HEXCLAVE_S3_BUCKET=
HEXCLAVE_S3_PRIVATE_BUCKET=
STACK_FREESTYLE_API_KEY=# enter your freestyle.sh api key
HEXCLAVE_FREESTYLE_API_KEY=# enter your freestyle.sh api key

View File

@ -1,20 +1,20 @@
# IMPORTANT: YOU MUST REGENERATE THE STACK_SERVER_SECRET VALUE BELOW
# IMPORTANT: YOU MUST REGENERATE THE HEXCLAVE_SERVER_SECRET VALUE BELOW
NEXT_PUBLIC_STACK_API_URL=http://localhost:8102
NEXT_PUBLIC_STACK_DASHBOARD_URL=http://localhost:8101
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:8102
NEXT_PUBLIC_HEXCLAVE_DASHBOARD_URL=http://localhost:8101
STACK_DATABASE_CONNECTION_STRING=postgres://postgres:password@host.docker.internal:8128/stackframe
HEXCLAVE_DATABASE_CONNECTION_STRING=postgres://postgres:password@host.docker.internal:8128/stackframe
STACK_SERVER_SECRET=23-wuNpik0gIW4mruTz25rbIvhuuvZFrLOLtL7J4tyo
HEXCLAVE_SERVER_SECRET=23-wuNpik0gIW4mruTz25rbIvhuuvZFrLOLtL7J4tyo
STACK_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST=true
STACK_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED=true
HEXCLAVE_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST=true
HEXCLAVE_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED=true
STACK_RUN_MIGRATIONS=true
STACK_RUN_SEED_SCRIPT=true
HEXCLAVE_RUN_MIGRATIONS=true
HEXCLAVE_RUN_SEED_SCRIPT=true
STACK_FREESTYLE_API_KEY=
HEXCLAVE_FREESTYLE_API_KEY=
STACK_CLICKHOUSE_URL=http://host.docker.internal:8133
STACK_CLICKHOUSE_ADMIN_PASSWORD=password
STACK_CLICKHOUSE_EXTERNAL_PASSWORD=password
HEXCLAVE_CLICKHOUSE_URL=http://host.docker.internal:8133
HEXCLAVE_CLICKHOUSE_ADMIN_PASSWORD=password
HEXCLAVE_CLICKHOUSE_EXTERNAL_PASSWORD=password

View File

@ -13,6 +13,28 @@ if [ -f /run/stack-auth/rotated-secrets.env ]; then
set +a
fi
# ============= HEXCLAVE_ ↔ STACK_ ENV ALIASING =============
# Hexclave rebrand: HEXCLAVE_*-prefixed env vars are canonical, but self-host
# operators (and older compose files) may still set the legacy STACK_* names.
# Node-side code dual-reads both, but this shell script and the sentinel
# substitution below look up vars by one exact name — so mirror every
# HEXCLAVE_*/STACK_* var to its unset twin. Called again right before the
# sentinel scan to pick up vars exported by the sections in between.
mirror_hexclave_stack_env() {
local _name _twin
for _name in $(compgen -e); do
case "$_name" in
*HEXCLAVE_*) _twin=${_name/HEXCLAVE_/STACK_} ;;
*STACK_*) _twin=${_name/STACK_/HEXCLAVE_} ;;
*) continue ;;
esac
if [ -z "${!_twin:-}" ] && [ -n "${!_name:-}" ]; then
export "$_twin=${!_name}"
fi
done
}
mirror_hexclave_stack_env
# ============= FORWARD MOCK OAUTH SERVER =============
# Start socat to forward port 32202 for mock-oauth-server if enabled
@ -45,39 +67,15 @@ if [ -n "${STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY:-}" ]; then
export STACK_SUPER_SECRET_ADMIN_KEY=${STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY}
fi
# ============= HEXCLAVE ↔ STACK URL ENV MIRROR =============
# The dashboard bundle inlines BOTH process.env.NEXT_PUBLIC_HEXCLAVE_* and
# process.env.NEXT_PUBLIC_STACK_* references as sentinels (dual-read). At
# runtime the sentinel-replace loop only substitutes a sentinel when the
# corresponding env var is set — but the dashboard's fallback chain
# (`HEXCLAVE_X ?? STACK_X`) treats an unreplaced sentinel as truthy, so it
# would pick the literal sentinel string instead of the real URL whenever
# only one of the two env names is set by the self-host operator.
# Mirror the URL trio HEXCLAVE → STACK and STACK → HEXCLAVE before the
# sentinel-replace runs, so both sentinels resolve to the same real value
# regardless of which name the operator chose.
for _legacy in STACK_API_URL STACK_DASHBOARD_URL STACK_SVIX_SERVER_URL; do
_new=HEXCLAVE_${_legacy#STACK_}
_legacy_full=NEXT_PUBLIC_${_legacy}
_new_full=NEXT_PUBLIC_${_new}
_legacy_val=${!_legacy_full:-}
_new_val=${!_new_full:-}
if [ -n "$_new_val" ] && [ -z "$_legacy_val" ]; then
export "$_legacy_full=$_new_val"
elif [ -n "$_legacy_val" ] && [ -z "$_new_val" ]; then
export "$_new_full=$_legacy_val"
fi
done
export NEXT_PUBLIC_BROWSER_STACK_DASHBOARD_URL=${NEXT_PUBLIC_STACK_DASHBOARD_URL}
# Hexclave rebrand: the port-prefix var was renamed outright to
# NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX. The dashboard bundle's post-build sentinel
# is STACK_ENV_VAR_SENTINEL_NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX, and the sentinel
# substitution loop below derives the env var name from the sentinel — so this
# MUST export NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX or the sentinel never resolves.
# Accept the legacy NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX as input for back-compat with
# Accept the legacy NEXT_PUBLIC_STACK_PORT_PREFIX as input for back-compat with
# existing self-host configs.
export NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX=${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}}
export NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX=${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}}
PORT_PREFIX=${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX}
export NEXT_PUBLIC_SERVER_STACK_DASHBOARD_URL="http://localhost:${PORT_PREFIX}01"
export NEXT_PUBLIC_BROWSER_STACK_API_URL=${NEXT_PUBLIC_STACK_API_URL}
@ -161,6 +159,14 @@ fi
# ============= ENV VARS =============
# Mirror again: the sections above exported more STACK_/HEXCLAVE_ vars (internal
# project keys, NEXT_PUBLIC_STACK_PROJECT_ID, svix fallback). The dashboard
# bundle inlines BOTH process.env.NEXT_PUBLIC_HEXCLAVE_* and
# process.env.NEXT_PUBLIC_STACK_* references as sentinels (dual-read), and the
# fallback chain treats an unreplaced sentinel as truthy — so both spellings
# must resolve to the same real value before the sentinel replacement below.
mirror_hexclave_stack_env
# Create a working directory for our processed files.
# Keep this off /tmp so local-emulator config sharing can bind-mount /tmp
# without pushing the whole runtime copy step onto the host filesystem.

View File

@ -1,6 +1,6 @@
# Basic
NEXT_PUBLIC_STACK_API_URL=# the base URL of Stack's backend/API
NEXT_PUBLIC_STACK_PROJECT_ID=# the project ID to use
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=# publishable client key for the project
STACK_SECRET_SERVER_KEY=# secret server key for the project
STACK_OPENROUTER_API_KEY=# OpenRouter API key for AI-enabled chat
NEXT_PUBLIC_HEXCLAVE_API_URL=# the base URL of Stack's backend/API
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=# the project ID to use
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=# publishable client key for the project
HEXCLAVE_SECRET_SERVER_KEY=# secret server key for the project
HEXCLAVE_OPENROUTER_API_KEY=# OpenRouter API key for AI-enabled chat

View File

@ -1,7 +1,7 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.stack-auth.com.
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
STACK_OPENROUTER_API_KEY=your-open-router-api-key-for-ai-enabled-chat
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
HEXCLAVE_OPENROUTER_API_KEY=your-open-router-api-key-for-ai-enabled-chat

View File

@ -735,9 +735,9 @@ export async function GET(request: Request) {
code: `import { StackServerApp } from "@stackframe/js";
const stackServerApp = new StackServerApp({
projectId: process.env.STACK_PROJECT_ID,
publishableClientKey: process.env.STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.STACK_SECRET_SERVER_KEY,
projectId: process.env.HEXCLAVE_PROJECT_ID,
publishableClientKey: process.env.HEXCLAVE_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.HEXCLAVE_SECRET_SERVER_KEY,
tokenStore: "memory",
});
@ -768,9 +768,9 @@ app.get('/api/protected', async (req, res) => {
code: `import { StackServerApp } from "@stackframe/js";
const stackServerApp = new StackServerApp({
projectId: process.env.STACK_PROJECT_ID,
publishableClientKey: process.env.STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.STACK_SECRET_SERVER_KEY,
projectId: process.env.HEXCLAVE_PROJECT_ID,
publishableClientKey: process.env.HEXCLAVE_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.HEXCLAVE_SECRET_SERVER_KEY,
tokenStore: "memory",
});
@ -929,9 +929,9 @@ export async function POST(request: Request) {
code: `import { StackServerApp } from "@stackframe/js";
const stackServerApp = new StackServerApp({
projectId: process.env.STACK_PROJECT_ID,
publishableClientKey: process.env.STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.STACK_SECRET_SERVER_KEY,
projectId: process.env.HEXCLAVE_PROJECT_ID,
publishableClientKey: process.env.HEXCLAVE_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.HEXCLAVE_SECRET_SERVER_KEY,
tokenStore: "memory",
});
@ -962,9 +962,9 @@ app.post('/api/team-protected', async (req, res) => {
code: `import { StackServerApp } from "@stackframe/js";
const stackServerApp = new StackServerApp({
projectId: process.env.STACK_PROJECT_ID,
publishableClientKey: process.env.STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.STACK_SECRET_SERVER_KEY,
projectId: process.env.HEXCLAVE_PROJECT_ID,
publishableClientKey: process.env.HEXCLAVE_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.HEXCLAVE_SECRET_SERVER_KEY,
tokenStore: "memory",
});

View File

@ -187,9 +187,9 @@ export const stackClientApp = new StackClientApp({
code: `import { StackServerApp } from "@stackframe/js";
export const stackServerApp = new StackServerApp({
projectId: process.env.STACK_PROJECT_ID,
publishableClientKey: process.env.STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.STACK_SECRET_SERVER_KEY,
projectId: process.env.HEXCLAVE_PROJECT_ID,
publishableClientKey: process.env.HEXCLAVE_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.HEXCLAVE_SECRET_SERVER_KEY,
tokenStore: "memory",
});`,
highlightLanguage: 'typescript',
@ -202,8 +202,8 @@ export const stackServerApp = new StackServerApp({
code: `import { StackClientApp } from "@stackframe/js";
export const stackClientApp = new StackClientApp({
projectId: process.env.STACK_PROJECT_ID,
publishableClientKey: process.env.STACK_PUBLISHABLE_CLIENT_KEY,
projectId: process.env.HEXCLAVE_PROJECT_ID,
publishableClientKey: process.env.HEXCLAVE_PUBLISHABLE_CLIENT_KEY,
tokenStore: "cookie",
});`,
highlightLanguage: 'typescript',
@ -216,9 +216,9 @@ export const stackClientApp = new StackClientApp({
code: `import { StackServerApp } from "@stackframe/js";
export const stackServerApp = new StackServerApp({
projectId: process.env.STACK_PROJECT_ID,
publishableClientKey: process.env.STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.STACK_SECRET_SERVER_KEY,
projectId: process.env.HEXCLAVE_PROJECT_ID,
publishableClientKey: process.env.HEXCLAVE_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.HEXCLAVE_SECRET_SERVER_KEY,
tokenStore: "memory",
});`,
highlightLanguage: 'javascript',
@ -231,8 +231,8 @@ export const stackServerApp = new StackServerApp({
code: `import { StackClientApp } from "@stackframe/js";
export const stackClientApp = new StackClientApp({
projectId: process.env.STACK_PROJECT_ID,
publishableClientKey: process.env.STACK_PUBLISHABLE_CLIENT_KEY,
projectId: process.env.HEXCLAVE_PROJECT_ID,
publishableClientKey: process.env.HEXCLAVE_PUBLISHABLE_CLIENT_KEY,
tokenStore: "cookie",
});`,
highlightLanguage: 'javascript',

View File

@ -230,7 +230,7 @@ export function EnhancedAPIPage({ document, operations, description }: EnhancedA
}
// Use local API URL in development, production URL from OpenAPI spec otherwise
const defaultBaseUrl = spec?.servers?.[0]?.url || '';
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL;
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL;
const baseUrl = localApiUrl ? localApiUrl + '/api/v1' : defaultBaseUrl;
let url = baseUrl + path;
@ -439,7 +439,7 @@ function ModernAPIPlayground({
const generateCurlCommand = useCallback(() => {
// Use local API URL in development, production URL otherwise
const defaultBaseUrl = spec.servers?.[0]?.url || '';
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL;
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL;
const baseUrl = localApiUrl
? localApiUrl + '/api/v1'
: defaultBaseUrl;
@ -492,7 +492,7 @@ function ModernAPIPlayground({
const generateJavaScriptCode = useCallback(() => {
// Use local API URL in development, production URL otherwise
const defaultBaseUrl = spec.servers?.[0]?.url || '';
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL;
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL;
const baseUrl = localApiUrl
? localApiUrl + '/api/v1'
: defaultBaseUrl;
@ -554,7 +554,7 @@ function ModernAPIPlayground({
const generatePythonCode = useCallback(() => {
// Use local API URL in development, production URL otherwise
const defaultBaseUrl = spec.servers?.[0]?.url || '';
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL;
const localApiUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL;
const baseUrl = localApiUrl
? localApiUrl + '/api/v1'
: defaultBaseUrl;

View File

@ -351,7 +351,7 @@ export function AIChatDrawer() {
const height = isHomePage && isScrolled ? 'h-[calc(100vh-1.5rem)]' : 'h-[calc(100vh-1.5rem)]';
const [input, setInput] = useState('');
const apiBaseUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL ?? throwErr("NEXT_PUBLIC_HEXCLAVE_API_URL or NEXT_PUBLIC_STACK_API_URL is not set");
const apiBaseUrl = process.env.NEXT_PUBLIC_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL || throwErr("NEXT_PUBLIC_HEXCLAVE_API_URL or NEXT_PUBLIC_STACK_API_URL is not set");
const {
messages,

View File

@ -4,10 +4,10 @@ import "server-only";
// Explicitly configure Stack Auth for docs app
export const stackServerApp = new StackServerApp({
tokenStore: "nextjs-cookie",
projectId: process.env.NEXT_PUBLIC_HEXCLAVE_PROJECT_ID ?? process.env.NEXT_PUBLIC_STACK_PROJECT_ID,
publishableClientKey: process.env.NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY ?? process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.HEXCLAVE_SECRET_SERVER_KEY ?? process.env.STACK_SECRET_SERVER_KEY,
baseUrl: process.env.NEXT_PUBLIC_HEXCLAVE_API_URL ?? process.env.NEXT_PUBLIC_STACK_API_URL,
projectId: process.env.NEXT_PUBLIC_HEXCLAVE_PROJECT_ID || process.env.NEXT_PUBLIC_STACK_PROJECT_ID,
publishableClientKey: process.env.NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY || process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY,
secretServerKey: process.env.HEXCLAVE_SECRET_SERVER_KEY || process.env.STACK_SECRET_SERVER_KEY,
baseUrl: process.env.NEXT_PUBLIC_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL,
analytics: {
replays: {
enabled: true,

View File

@ -1,6 +1,6 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only

View File

@ -1,9 +1,9 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
CONVEX_DEPLOYMENT=anonymous:anonymous-convex-example
NEXT_PUBLIC_CONVEX_URL=http://127.0.0.1:3210

View File

@ -2,7 +2,7 @@ import { getConvexProvidersConfig } from "@hexclave/next/convex-auth.config";
export default {
providers: getConvexProvidersConfig({
projectId: process.env.NEXT_PUBLIC_STACK_PROJECT_ID!,
baseUrl: process.env.NEXT_PUBLIC_STACK_API_URL,
projectId: (process.env.NEXT_PUBLIC_HEXCLAVE_PROJECT_ID || process.env.NEXT_PUBLIC_STACK_PROJECT_ID)!,
baseUrl: (process.env.NEXT_PUBLIC_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL),
}),
}

View File

@ -1,3 +1,3 @@
NEXT_PUBLIC_STACK_API_URL=# enter your stack endpoint here, e.g. http://localhost:8102
NEXT_PUBLIC_STACK_PROJECT_ID=# enter your stack project id here
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=# enter your stack publishable client key here
NEXT_PUBLIC_HEXCLAVE_API_URL=# enter your stack endpoint here, e.g. http://localhost:8102
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=# enter your stack project id here
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=# enter your stack publishable client key here

View File

@ -1,7 +1,7 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_STACK_HOSTED_HANDLER_URL_TEMPLATE=http://{projectId}.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09/{hostedPath}
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE=http://{projectId}.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09/{hostedPath}

View File

@ -2,8 +2,8 @@
/** Minimal `stack login` flow for local demos. Usage: `node cli-sim.mjs` */
const API_URL = process.env.STACK_API_URL || "http://localhost:8102";
const APP_URL = process.env.STACK_APP_URL || "http://localhost:8103";
const API_URL = (process.env.HEXCLAVE_API_URL || process.env.STACK_API_URL) || "http://localhost:8102";
const APP_URL = (process.env.HEXCLAVE_APP_URL || process.env.STACK_APP_URL) || "http://localhost:8103";
const PROJECT_ID = "internal";
const PUBLISHABLE_KEY = "this-publishable-client-key-is-for-local-development-only";

View File

@ -66,8 +66,8 @@ function getDebugInternals(app: ReturnType<typeof useStackApp>): {
}
function getDemoApiUrl(): string {
const baseUrl = process.env.NEXT_PUBLIC_STACK_API_URL
?? process.env.NEXT_PUBLIC_STACK_URL;
const baseUrl = (process.env.NEXT_PUBLIC_HEXCLAVE_API_URL || process.env.NEXT_PUBLIC_STACK_API_URL)
?? (process.env.NEXT_PUBLIC_HEXCLAVE_URL || process.env.NEXT_PUBLIC_STACK_URL);
if (typeof baseUrl !== "string" || baseUrl.length === 0) {
throw new Error("Expected NEXT_PUBLIC_STACK_API_URL to be configured for Turnstile OAuth debug flows");
@ -301,8 +301,8 @@ export default function TurnstileSignupPageClient() {
const signInWithTokens = internals.signInWithTokens;
const apiUrl = getDemoApiUrl();
const oauthClientSecret = app[hexclaveAppInternalsSymbol].toClientJson().publishableClientKey
?? process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY
?? process.env.STACK_PUBLISHABLE_CLIENT_KEY
?? (process.env.NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY || process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY)
?? (process.env.HEXCLAVE_PUBLISHABLE_CLIENT_KEY || process.env.STACK_PUBLISHABLE_CLIENT_KEY)
?? publishableClientKeyNotNecessarySentinel;
useEffect(() => {

View File

@ -1,4 +1,4 @@
NEXT_PUBLIC_STACK_API_URL=# enter your stack endpoint here, e.g. http://localhost:8102
NEXT_PUBLIC_STACK_PROJECT_ID=# enter your stack project id here
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=# enter your stack publishable client key here
STACK_SECRET_SERVER_KEY=# enter your stack secret server key here
NEXT_PUBLIC_HEXCLAVE_API_URL=# enter your stack endpoint here, e.g. http://localhost:8102
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=# enter your stack project id here
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=# enter your stack publishable client key here
HEXCLAVE_SECRET_SERVER_KEY=# enter your stack secret server key here

View File

@ -1,6 +1,6 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only

View File

@ -1,6 +1,6 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only

View File

@ -1,10 +1,10 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
VITE_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
VITE_STACK_PROJECT_ID=internal
VITE_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
VITE_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
VITE_HEXCLAVE_PROJECT_ID=internal
VITE_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only

View File

@ -1,6 +1,6 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
VITE_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
VITE_STACK_PROJECT_ID=internal
VITE_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
VITE_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
VITE_HEXCLAVE_PROJECT_ID=internal
VITE_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only

View File

@ -1,4 +1,4 @@
NEXT_PUBLIC_STACK_API_URL=# enter your stack endpoint here, e.g. http://localhost:8102
NEXT_PUBLIC_STACK_PROJECT_ID=# enter your stack project id here
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=# enter your stack publishable client key here
STACK_SECRET_SERVER_KEY=# enter your stack secret server key here
NEXT_PUBLIC_HEXCLAVE_API_URL=# enter your stack endpoint here, e.g. http://localhost:8102
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=# enter your stack project id here
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=# enter your stack publishable client key here
HEXCLAVE_SECRET_SERVER_KEY=# enter your stack secret server key here

View File

@ -1,6 +1,6 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only

View File

@ -1,6 +1,6 @@
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
VITE_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
VITE_STACK_PROJECT_ID=internal
VITE_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
VITE_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
VITE_HEXCLAVE_PROJECT_ID=internal
VITE_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only

View File

@ -4,7 +4,7 @@ SUPABASE_JWT_SECRET=supabase-jwt-secret
# Contains the credentials for the internal project of Stack's default development environment setup.
# Do not use in a production environment, instead replace it with actual values gathered from https://app.hexclave.com.
NEXT_PUBLIC_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_STACK_PROJECT_ID=internal
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
NEXT_PUBLIC_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=internal
NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
HEXCLAVE_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only

View File

@ -1,3 +1,3 @@
VITE_STACK_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
VITE_STACK_PROJECT_ID=internal
VITE_STACK_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
VITE_HEXCLAVE_API_URL=http://localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}02
VITE_HEXCLAVE_PROJECT_ID=internal
VITE_HEXCLAVE_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only

View File

@ -52,7 +52,7 @@ function resolveRefreshToken(): string {
}
function resolveSecretServerKey(): string | null {
return process.env.HEXCLAVE_SECRET_SERVER_KEY ?? process.env.STACK_SECRET_SERVER_KEY ?? null;
return process.env.HEXCLAVE_SECRET_SERVER_KEY || process.env.STACK_SECRET_SERVER_KEY || null;
}
export function resolveLoginConfig(): LoginConfig {

View File

@ -51,15 +51,17 @@ export function getEnvVariable(name: string, defaultValue?: string | undefined):
}
// Hexclave rebrand: prefer the HEXCLAVE_*-prefixed equivalent, fall back to the STACK_* name.
// Treat the empty string as unset — the checked-in .env templates define empty
// HEXCLAVE_* placeholders, which must not shadow a real value under the legacy name.
const hexclaveName = getHexclaveEnvVarName(name);
let value = (hexclaveName ? process.env[hexclaveName] : undefined) ?? process.env[name];
let value = (hexclaveName ? process.env[hexclaveName] : undefined) || process.env[name];
// check the key under the old name if the new name is not found
if (!value && ENV_VAR_RENAME[name] as any) {
for (const oldName of ENV_VAR_RENAME[name]) {
// Hexclave rebrand: also accept the HEXCLAVE_*-prefixed equivalent of each old alias.
const hexclaveOldName = getHexclaveEnvVarName(oldName);
value = (hexclaveOldName ? process.env[hexclaveOldName] : undefined) ?? process.env[oldName];
value = (hexclaveOldName ? process.env[hexclaveOldName] : undefined) || process.env[oldName];
if (value) break;
}
}

View File

@ -69,11 +69,14 @@ function generateEnvVarsConstSnippet() {
const allVariables = [key, ...(config.deprecatedLegacyNames ?? [])]
.flatMap(k => k.startsWith("HEXCLAVE_") ? [k, k.replace("HEXCLAVE_", "STACK_")] : [k])
.flatMap(k => config.allowPublic ? [k, `NEXT_PUBLIC_${k}`, `VITE_${k}`] : [k]);
// Use || (not ??) between candidates: empty-string env vars (e.g. the empty
// HEXCLAVE_* placeholders in checked-in .env templates) must not shadow a
// real value under a legacy STACK_* name further down the chain.
getters.push(deindent`
get ${key}() {
return ${allVariables.map(variableName => deindent`
((typeof process !== "undefined" ? process.env.${variableName} : undefined) ?? import.meta.env?.${variableName})
`).join("\n ?? ")} ?? undefined;
((typeof process !== "undefined" ? process.env.${variableName} : undefined) || import.meta.env?.${variableName})
`).join("\n || ")} || undefined;
},
`);
}