mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
### Context One script grants free plan to any team which is a customer of the internal project who doesnt have it already. We also want to migrate our users (internal) to the latest version of their products. Needed because some subs on dev right now dont have a plan. And internal isnt using latest version of its own growth plan. ### Describing the Paths we want to Account for 1. Users on production who currently don't have a plan should get free plans, since this script is run with every migrate 2. Users on production should get the latest version of each plan of ours. So a forced migration to latest version of internal project plans 3. No other project's products/product lines should be affected. They will continue to have product versioning 4. 2 should apply to test mode subscriptions as well, on top of stripe subscriptions. All of them should be refreshed 5. Internal project itself should get latest version of its own growth plan 6. If the bulldozer write fails, we should be able to recover on next migration (this should already be handled by init bulldozer script, because it checks if prisma db and bulldozer db are out of sync) 7. if the regenerate or backfill fail, we should be able to recover just by rerunning the script 8. Product version table should not balloon. No table should really balloon ### What I've tested on local 1. Put in 1000 db subscription rows, made them all stale and then ran the regen script. It took about 6 minutes to update all of them, and it was idempotent so rerunning it again did nothing. 2. With proper stripe keys I switched off of test mode on the internal app, granted a product to a new team and updated the product's item list. At this point I checked and the new team had the outdated version of the product. Then I ran the regen script and the new team was moved to latest product version. 3. Tried the above with the internal team's growth plan too and it worked as well. 4. Backfill actually grants free plan ### Deployment strategy in prod Run the backfill and the regen scripts once each after your migrations on the prod db. `pnpm db:backfill-internal-free-plans` will make sure every team has a free plan at least if they dont have an existing plan (and it is idempotent). After that, run `pnpm db:regen-internal-subscriptions-to-latest` which will migrate every user to the latest version of their plan (i.e latest snapshot). This should also be idempotent. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Automated backfill to grant internal free plans to qualifying billing teams. * Regeneration tool to refresh internal subscription snapshots to the latest product versions. * **Chores** * Added CLI commands and package scripts to run backfill and regen jobs. * Database init now runs payment initialization before backfill/regen. * **Tests** * Integration and unit tests added/updated to validate backfill, regeneration, and free-plan idempotency. [](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1421) <!-- end of auto-generated comment: release notes by coderabbit.ai -->
143 lines
11 KiB
JSON
143 lines
11 KiB
JSON
{
|
|
"name": "@stackframe/monorepo",
|
|
"version": "0.0.0",
|
|
"private": true,
|
|
"repository": "https://github.com/hexclave/stack-auth",
|
|
"scripts": {
|
|
"pre-no-codegen": "pnpm exec only-allow pnpm",
|
|
"pre-preinstall": "pnpx only-allow@1.2.2 pnpm && node -e \"if(process.env.STACK_SKIP_TEMPLATE_GENERATION !== 'true') require('child_process').execSync('pnpm exec tsx ./scripts/generate-sdks.ts', {stdio: 'inherit'})\"",
|
|
"pre": "pnpm pre-preinstall",
|
|
"preinstall": "pnpm pre-preinstall",
|
|
"postinstall": "node ./scripts/postinstall-patch-next-async-debug-info.mjs",
|
|
"typecheck": "pnpm pre && turbo typecheck --",
|
|
"build:dev": "pnpm pre && NODE_ENV=development pnpm run build",
|
|
"build": "pnpm pre && turbo build",
|
|
"cli": "pnpm pre && pnpm run --filter=@stackframe/stack-cli build && node packages/stack-cli/dist/index.js",
|
|
"build:backend": "pnpm pre && turbo run build --filter=@stackframe/backend...",
|
|
"build:dashboard": "pnpm pre && turbo run build --filter=@stackframe/dashboard...",
|
|
"build:demo": "pnpm pre && turbo run build --filter=demo-app...",
|
|
"build:docs": "pnpm run build:packages && pnpm run codegen && pnpm run build:backend && pnpm run --filter=@stackframe/stack-docs generate-openapi-docs && turbo run build --filter=@stackframe/stack-docs",
|
|
"build:packages": "pnpm pre && turbo run build --filter=./packages/*",
|
|
"clean": "pnpm pre-no-codegen && turbo run clean && rimraf --glob **/.next && rimraf --glob **/.turbo && rimraf .turbo && rimraf --glob **/node_modules && rimraf node_modules",
|
|
"uff-cutie": "pnpm clean && pnpm i && (pnpm build || true) && pnpm codegen",
|
|
"fml": "pnpm uff-cutie && pnpm restart-deps",
|
|
"codegen": "pnpm pre && turbo run codegen && pnpm run generate-sdks && pnpm run generate-setup-prompt-docs",
|
|
"codegen:backend": "pnpm pre && turbo run codegen --filter=@stackframe/backend...",
|
|
"deps-compose": "docker compose -p stack-dependencies-${NEXT_PUBLIC_STACK_PORT_PREFIX:-81} -f docker/dependencies/docker.compose.yaml",
|
|
"emulator:generate-env": "node ./docker/local-emulator/generate-env-development.mjs",
|
|
"emulator:check-env": "node ./docker/local-emulator/generate-env-development.mjs --check",
|
|
"emulator:start": "pnpm run emulator:generate-env && docker/local-emulator/qemu/run-emulator.sh start",
|
|
"emulator:stop": "docker/local-emulator/qemu/run-emulator.sh stop",
|
|
"emulator:reset": "docker/local-emulator/qemu/run-emulator.sh reset",
|
|
"emulator:status": "docker/local-emulator/qemu/run-emulator.sh status",
|
|
"emulator:build": "docker/local-emulator/qemu/build-image.sh",
|
|
"emulator:bench": "docker/local-emulator/qemu/run-emulator.sh bench",
|
|
"stop-deps": "POSTGRES_DELAY_MS=0 pnpm run deps-compose kill && POSTGRES_DELAY_MS=0 pnpm run deps-compose down -v",
|
|
"wait-until-postgres-is-ready:pg_isready": "until pg_isready -h localhost -p ${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}28 && pg_isready -h localhost -p ${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}34; do sleep 1; done",
|
|
"wait-until-postgres-is-ready": "command -v pg_isready >/dev/null 2>&1 && pnpm run wait-until-postgres-is-ready:pg_isready || sleep 10 # not everyone has pg_isready installed, so we fallback to sleeping",
|
|
"wait-until-clickhouse-is-ready": "pnpm exec wait-on http://localhost:${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}36/ping",
|
|
"start-deps:no-delay": "pnpm pre && pnpm run deps-compose up --detach --build && pnpm run wait-until-postgres-is-ready && pnpm run wait-until-clickhouse-is-ready && pnpm run db:init && echo \"\\nDependencies started in the background as Docker containers. 'pnpm run stop-deps' to stop them\"",
|
|
"start-deps": "POSTGRES_DELAY_MS=${POSTGRES_DELAY_MS:-0} pnpm run start-deps:no-delay",
|
|
"restart-deps": "pnpm pre && pnpm run stop-deps && pnpm run start-deps",
|
|
"restart-deps:no-delay": "pnpm pre && pnpm run stop-deps && pnpm run start-deps:no-delay",
|
|
"restart-deps:with-tests": "pnpm run restart-deps && pnpm test run auto-migrations/migration-tests",
|
|
"psql": "pnpm pre && pnpm run --filter=@stackframe/backend psql",
|
|
"clickhouse": "pnpm pre && pnpm run --filter=@stackframe/backend clickhouse",
|
|
"explain-query": "pnpm pre && echo 'Paste your query (end with Ctrl-D):' && query=$(cat) && echo 'Connecting to Postgres...' && printf \"EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON)\n$query\" | pnpm run --silent psql -qAt | sed -n '/\\[/,$p' > explained-query.untracked.json && echo 'Explained query saved to explained-query.untracked.json. To analyze it, open it in the query analyzer at https://tatiyants.com/pev/#/plans/new'",
|
|
"db:migration-gen": "pnpm pre && pnpm run --filter=@stackframe/backend db:migration-gen",
|
|
"db:reset": "pnpm pre && pnpm run --filter=@stackframe/backend db:reset",
|
|
"db:seed": "pnpm pre && pnpm run --filter=@stackframe/backend db:seed",
|
|
"db:init": "pnpm pre && pnpm run --filter=@stackframe/backend db:init",
|
|
"db:migrate": "pnpm pre && pnpm run --filter=@stackframe/backend db:migrate",
|
|
"db:backfill-internal-free-plans": "pnpm pre && pnpm run --filter=@stackframe/backend db:backfill-internal-free-plans",
|
|
"db:regen-internal-subscriptions-to-latest": "pnpm pre && pnpm run --filter=@stackframe/backend db:regen-internal-subscriptions-to-latest",
|
|
"fern": "pnpm pre && pnpm run --filter=@stackframe/docs fern",
|
|
"dev:full": "pnpm pre && concurrently -k \"pnpm run generate-sdks:watch\" \"pnpm run generate-setup-prompt-docs:watch\" \"turbo run dev --concurrency 99999\"",
|
|
"dev": "pnpm pre && concurrently -k \"pnpm run generate-sdks:watch\" \"pnpm run generate-openapi-docs:watch\" \"pnpm run generate-setup-prompt-docs:watch\" \"turbo run dev --concurrency 99999 --filter=./apps/* --filter=@stackframe/docs-mintlify --filter=@stackframe/stack-docs --filter=./packages/* --filter=./examples/demo --filter=./examples/tanstack-start-demo \"",
|
|
"dev:tui": "pnpm pre && (trap 'kill 0' EXIT; pnpm run generate-sdks:watch & pnpm run generate-openapi-docs:watch & pnpm run generate-setup-prompt-docs:watch & turbo run dev --ui tui --concurrency 99999 --filter=./apps/* --filter=@stackframe/stack-docs --filter=./packages/* --filter=./examples/demo --filter=./examples/tanstack-start-demo)",
|
|
"dev:inspect": "pnpm pre && STACK_BACKEND_DEV_EXTRA_ARGS=\"--inspect\" pnpm run dev",
|
|
"dev:profile": "pnpm pre && STACK_BACKEND_DEV_EXTRA_ARGS=\"--experimental-cpu-prof\" pnpm run dev",
|
|
"dev:basic": "pnpm pre && concurrently -k \"pnpm run generate-sdks:watch\" \"turbo run dev --concurrency 99999 --filter=@stackframe/backend --filter=@stackframe/mcp --filter=@stackframe/dashboard --filter=@stackframe/mock-oauth-server\"",
|
|
"dev:docs": "pnpm pre && concurrently -k \"pnpm run generate-openapi-docs:watch\" \"pnpm run generate-setup-prompt-docs:watch\" \"turbo run dev --concurrency 99999 --filter=@stackframe/stack-docs\"",
|
|
"dev:named": "pnpm pre && concurrently -k \"pnpm run dev\" \"node -e \\\"process.title='node (stack-named-dev-server)'; process.stdin.resume();\\\"\"",
|
|
"kill-dev:named": "(pgrep -f 'stack-named-dev-server' | xargs -r -n1 pkill -P); echo 'Killed named dev server (if found). Sleeping to give some time for it to shut down...' && sleep 10",
|
|
"kms": "PREFIX=${NEXT_PUBLIC_STACK_PORT_PREFIX:-81}; for p in 00 01 02 03 04 06 14 42; do pids=$(lsof -i :$PREFIX$p 2>/dev/null | grep LISTEN | awk '$1 != \"OrbStack\" {print $2}' | sort -u); [ -n \"$pids\" ] && echo $pids | xargs kill -9 2>/dev/null; done; echo Done.",
|
|
"start": "pnpm pre && turbo run start --concurrency 99999",
|
|
"start:backend": "pnpm pre && turbo run start --concurrency 99999 --filter=@stackframe/backend",
|
|
"start:mcp": "pnpm pre && turbo run start --concurrency 99999 --filter=@stackframe/mcp",
|
|
"start:dashboard": "pnpm pre && turbo run start --concurrency 99999 --filter=@stackframe/dashboard",
|
|
"start:mock-oauth-server": "pnpm pre && turbo run start --concurrency 99999 --filter=@stackframe/mock-oauth-server",
|
|
"lint": "pnpm pre && turbo run lint --continue -- --max-warnings=0",
|
|
"release": "pnpm pre && release",
|
|
"dotenv": "dotenv",
|
|
"peek": "pnpm pre && pnpm release --peek",
|
|
"changeset": "pnpm pre && changeset",
|
|
"test": "pnpm pre && vitest",
|
|
"test:e2e": "pnpm pre && vitest e2e/tests",
|
|
"test:unit": "pnpm pre && vitest src",
|
|
"verify-data-integrity": "pnpm pre && pnpm -C apps/backend run verify-data-integrity",
|
|
"generate-keys": "pnpm pre && turbo run generate-keys",
|
|
"generate-sdks": "pnpm exec tsx ./scripts/generate-sdks.ts",
|
|
"generate-setup-prompt-docs": "pnpm exec tsx ./scripts/generate-setup-prompt-docs.ts",
|
|
"generate-sdks:watch": "chokidar --silent -c 'pnpm run generate-sdks' './packages/template' --ignore './packages/template/package.json' --ignore '**/node_modules/**' --ignore '**/dist/**' --ignore '**/.turbo/**' --throttle 2000",
|
|
"generate-openapi-docs:watch": "pnpm exec tsx ./scripts/wait-for-dev-package-imports.ts && pnpm run --filter=@stackframe/backend codegen-docs && chokidar --silent -c 'pnpm run --filter=@stackframe/backend codegen-docs' './apps/backend/src/app/api/latest/**/route.{js,jsx,ts,tsx}' './apps/backend/src/lib/openapi.ts' './packages/stack-shared/src/interface/webhooks.ts' --throttle 2000",
|
|
"generate-setup-prompt-docs:watch": "pnpm run generate-setup-prompt-docs && chokidar --silent -c 'pnpm run generate-setup-prompt-docs' './packages/stack-shared/src/ai/prompts.ts' './scripts/generate-setup-prompt-docs.ts' --throttle 2000"
|
|
},
|
|
"devDependencies": {
|
|
"@changesets/cli": "^2.27.9",
|
|
"@testing-library/react": "^15.0.7",
|
|
"@types/node": "20.17.6",
|
|
"@types/supertest": "^6.0.2",
|
|
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
"@typescript-eslint/parser": "^8.56.1",
|
|
"@vitejs/plugin-react": "^4.3.3",
|
|
"chokidar-cli": "^3.0.0",
|
|
"codebuff": "^1.0.261",
|
|
"concurrently": "^8.2.2",
|
|
"dotenv-cli": "^7.3.0",
|
|
"esbuild": "^0.24.0",
|
|
"eslint": "^8.57.0",
|
|
"eslint-config-next": "^14.2.17",
|
|
"eslint-plugin-import": "^2.31.0",
|
|
"eslint-plugin-node": "^11.1.0",
|
|
"eslint-plugin-promise": "^6.6.0",
|
|
"eslint-plugin-react": "^7.37.2",
|
|
"jsdom": "^24.1.3",
|
|
"only-allow": "^1.2.1",
|
|
"rimraf": "^5.0.10",
|
|
"tsdown": "^0.20.3",
|
|
"turbo": "^2.8.15",
|
|
"typescript": "5.9.3",
|
|
"vite-tsconfig-paths": "^4.3.2",
|
|
"vitest": "^1.6.0",
|
|
"wait-on": "^8.0.1"
|
|
},
|
|
"pnpm": {
|
|
"overrides": {
|
|
"@types/react": "^18.2.0",
|
|
"@types/react-dom": "^18.2.0"
|
|
},
|
|
"packageExtensions": {
|
|
"@mintlify/link-rot": {
|
|
"dependencies": {
|
|
"react": "*",
|
|
"react-dom": "*"
|
|
}
|
|
}
|
|
},
|
|
"patchedDependencies": {
|
|
"openid-client@5.6.4": "patches/openid-client@5.6.4.patch"
|
|
}
|
|
},
|
|
"engines": {
|
|
"npm": ">=10.0.0",
|
|
"node": ">=20.0.0"
|
|
},
|
|
"packageManager": "pnpm@10.23.0",
|
|
"dependencies": {
|
|
"commander": "^13.1.0",
|
|
"tsx": "^4.19.3",
|
|
"yaml": "^2.4.5"
|
|
}
|
|
}
|