Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
72138f2
feat(billing): dual Stripe EE/US account support
cursoragent Sep 8, 2026
4fa7597
fix(billing): resolve lint and typecheck for dual Stripe PR
cursoragent Sep 8, 2026
6ff149c
fix(tests): update stripe-emulator mock for dual billing admin calls
cursoragent Sep 8, 2026
fc4ffce
fix(billing): address CodeRabbit dual Stripe review feedback
cursoragent Sep 8, 2026
7efe3cd
fix(billing): default ee when admin client unavailable in tests
cursoragent Sep 8, 2026
2ef6465
fix(billing): check Stripe configured before constructing client
cursoragent Sep 8, 2026
e66991a
chore(ci): retrigger backend shard 4 after 502 flake
cursoragent Sep 8, 2026
0f42215
fix(billing): rebase on main and address CR/Cubic review items
cursoragent Sep 9, 2026
1acea2e
fix(billing): clear CR/Cubic review items on dual Stripe PR
cursoragent Sep 9, 2026
e19c03e
chore(ci): retrigger plugin serial shard after 502 flake
cursoragent Sep 9, 2026
7726df3
chore(ci): retrigger after 502 flakes on shard 1 and CLI
cursoragent Sep 9, 2026
2f09210
chore(ci): retrigger after duplicate-run shard 3/4 502 flake
cursoragent Sep 9, 2026
d9e6f99
test(billing): restore STRIPE_SECRET_KEY in stripe-redirects afterEach
cursoragent Sep 9, 2026
6c3deca
ci(test): warm /app before backend shards to avoid 502 flakes
cursoragent Sep 9, 2026
6dbbb81
ci(test): retry Supabase start on SIGTERM flakes in plugin job
cursoragent Sep 9, 2026
6730345
ci(test): retry Cloudflare Workers startup on slow CI runners
cursoragent Sep 9, 2026
e1f7ad0
fix(billing,test): cubic P1 guards and stabilize POST /apikey CI
cursoragent Sep 9, 2026
f22fb21
fix(billing): seed US plan ids and relax stripe org unit test coupling
cursoragent Sep 9, 2026
58dcd29
fix(billing): sync dual-stripe types and relax emulator test assertion
cursoragent Sep 9, 2026
06ada0b
fix(billing): skip audit logs for background counter updates regardle…
cursoragent Sep 9, 2026
1bcdaff
fix(billing): address CodeRabbit review on HEAD 06ada0b
cursoragent Sep 10, 2026
09bb211
fix(billing): allow hyphen/underscore in Stripe product id validation
cursoragent Sep 10, 2026
afa8a68
chore(ci): retrigger workflows after shard 6 startup flake
cursoragent Sep 10, 2026
7432f49
fix(billing): account-scoped admin plan joins and checkout error prop…
cursoragent Sep 10, 2026
78d8543
test(billing): mock dual-account plan lookup in stripe redirect tests
cursoragent Sep 10, 2026
ca25cd7
fix(billing): finish admin plan joins and checkout lookup test
cursoragent Sep 10, 2026
5bfa225
fix(billing): address CodeRabbit review on ca25cd748
cursoragent Sep 10, 2026
39ce0b4
fix(billing): allow host.docker.internal for Playwright Stripe emulator
cursoragent Sep 10, 2026
e0c747a
fix(ci): warm edge routes before Capgo CLI integration tests
cursoragent Sep 10, 2026
ff08e9f
fix(billing): address CodeRabbit credit lookup and config review items
cursoragent Sep 10, 2026
2f7bc40
fix(stripe): propagate plan lookup errors instead of Solo fallback
cursoragent Sep 23, 2026
f3ed36b
test(apikeys): warm POST route before tracked warmup key
cursoragent Sep 23, 2026
6171c57
fix(stripe): reject http API base URL for live credentials
cursoragent Sep 23, 2026
1f58c37
merge(main): resolve conflicts and pick up request_actor_email_adress…
cursoragent Sep 23, 2026
f0b675c
fix(ci): restore Playwright Stripe emulator env and published CLI RPC
cursoragent Sep 23, 2026
71c6460
fix(billing): use resolvePlanCreditProductId for credit top-up fallback
cursoragent Sep 23, 2026
f0a1021
fix(billing): resolvePlanCreditProductId in auto top-up Solo fallback
cursoragent Sep 23, 2026
04da928
fix(db): re-stamp dual stripe migration after main merge
cursoragent Sep 23, 2026
47bfaf3
test(updates): retry transient Kong 502 on POST /updates
cursoragent Sep 23, 2026
2b4af89
fix(billing): use resolvePlanCreditProductId in credits Solo fallbacks
cursoragent Sep 23, 2026
fea0899
fix(db): re-stamp dual stripe migration to 20260923105200
cursoragent Sep 23, 2026
89f407e
docs: remove fixed review tip rule (#3428)
WcaleNieWolny Sep 23, 2026
08e4bd0
fix(billing): address CodeRabbit review on HEAD 89f407ea
cursoragent Sep 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/scripts/start-cloudflare-workers-with-retry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash

set -euo pipefail

max_attempts="${CLOUDFLARE_WORKERS_START_MAX_ATTEMPTS:-2}"
worker_port_offset="${CLOUDFLARE_WORKER_PORT_OFFSET:-0}"
log_path="${CLOUDFLARE_WORKERS_LOG_PATH:-${RUNNER_TEMP:-/tmp}/cloudflare-workers.log}"
wait_timeout_ms="${CLOUDFLARE_WORKERS_WAIT_TIMEOUT_MS:-180000}"
worker_pids=()

stop_worker_pid() {
local pid="$1"
if [[ -z "${pid}" ]]; then
return
fi
kill "${pid}" 2>/dev/null || true
pkill -P "${pid}" 2>/dev/null || true
}

stop_all_worker_pids() {
local pid
for pid in "${worker_pids[@]}"; do
stop_worker_pid "${pid}"
done
}

export BACKGROUND_SERVICE_NAME="${BACKGROUND_SERVICE_NAME:-Cloudflare Workers}"
export BACKGROUND_RUN_COMMAND="${BACKGROUND_RUN_COMMAND:-$'chmod +x scripts/start-cloudflare-workers.sh\nexec ./scripts/start-cloudflare-workers.sh'}"
export BACKGROUND_LOG_PATH="${log_path}"
export BACKGROUND_WAIT_TIMEOUT_MS="${wait_timeout_ms}"
export BACKGROUND_TAIL_LINES="${BACKGROUND_TAIL_LINES:-400}"
export BACKGROUND_WAIT_ON="http-get://127.0.0.1:$((8787 + worker_port_offset))/ok
http-get://127.0.0.1:$((8788 + worker_port_offset))/ok
http-get://127.0.0.1:$((8789 + worker_port_offset))/ok"

for attempt in $(seq 1 "${max_attempts}"); do
if bash .github/scripts/start-background-service.sh; then
Comment thread
cursor[bot] marked this conversation as resolved.
exit 0
else
exit_code=$?
if [[ -n "${GITHUB_OUTPUT:-}" ]] && [[ -f "${GITHUB_OUTPUT}" ]]; then
latest_pid="$(grep '^pid=' "${GITHUB_OUTPUT}" | tail -1 | cut -d= -f2- || true)"
if [[ -n "${latest_pid}" ]]; then
worker_pids+=("${latest_pid}")
stop_worker_pid "${latest_pid}"
fi
fi
echo "Cloudflare Workers failed to become ready with exit ${exit_code} (attempt ${attempt}/${max_attempts})" >&2
if [ "${attempt}" -eq "${max_attempts}" ]; then
stop_all_worker_pids
exit "${exit_code}"
fi
sleep_seconds=$((attempt * 10))
echo "Retrying Cloudflare Workers startup in ${sleep_seconds}s..." >&2
sleep "${sleep_seconds}"
fi
done
22 changes: 22 additions & 0 deletions .github/scripts/start-supabase-worktree-with-retry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash

set -euo pipefail

max_attempts="${SUPABASE_START_MAX_ATTEMPTS:-3}"
exclude_services="${SUPABASE_START_EXCLUDE:-imgproxy,studio,mailpit,realtime,postgres-meta,supavisor,logflare,vector}"

for attempt in $(seq 1 "${max_attempts}"); do
bun scripts/supabase-worktree.ts stop --no-backup || true
if bun scripts/supabase-worktree.ts start -x "${exclude_services}"; then
exit 0
else
exit_code=$?
echo "Supabase start failed with exit ${exit_code} (attempt ${attempt}/${max_attempts})" >&2
if [ "${attempt}" -eq "${max_attempts}" ]; then
exit "${exit_code}"
fi
sleep_seconds=$((attempt * 5))
echo "Retrying Supabase start in ${sleep_seconds}s..." >&2
sleep "${sleep_seconds}"
fi
done
81 changes: 48 additions & 33 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ jobs:
warm_get() {
local path="$1"
for attempt in 1 2 3 4 5; do
status=$(curl -s -o /tmp/edge-warm.body -w '%{http_code}' "${base_url}${path}" || true)
status=$(curl --max-time 10 -s -o /tmp/edge-warm.body -w '%{http_code}' "${base_url}${path}" || true)
echo "edge warm GET path=${path} attempt=${attempt} status=${status}"
if [ "${status}" != "502" ] && [ "${status}" != "503" ] && [ "${status}" != "000" ]; then
return 0
Expand All @@ -430,7 +430,7 @@ jobs:
warm_post() {
local path="$1"
for attempt in 1 2 3 4 5; do
status=$(curl -s -o /tmp/edge-warm.body -w '%{http_code}' -X POST "${base_url}${path}" \
status=$(curl --max-time 10 -s -o /tmp/edge-warm.body -w '%{http_code}' -X POST "${base_url}${path}" \
-H 'Content-Type: application/json' \
-H 'apisecret: testsecret' \
-d '{}' || true)
Expand Down Expand Up @@ -742,7 +742,7 @@ jobs:
needs: [changes, lint_typecheck, dead_code]
if: needs.changes.outputs.run_capgo == 'true'
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 7
name: Run Cloudflare Workers tests (shard ${{ matrix.shard }})
permissions:
contents: read
Expand Down Expand Up @@ -813,7 +813,7 @@ jobs:
- name: Install dependencies
run: bun install
- name: Run Supabase Start
run: bun scripts/supabase-worktree.ts start -x imgproxy,studio,mailpit,realtime,postgres-meta,supavisor,logflare,vector
run: bash .github/scripts/start-supabase-worktree-with-retry.sh
- name: Export isolated test endpoints
run: |
{
Expand All @@ -835,20 +835,7 @@ jobs:
bash .github/scripts/start-background-service.sh
- id: start_cloudflare_workers
name: Start Cloudflare Workers for testing
env:
BACKGROUND_SERVICE_NAME: Cloudflare Workers
BACKGROUND_RUN_COMMAND: |
chmod +x scripts/start-cloudflare-workers.sh
exec ./scripts/start-cloudflare-workers.sh
BACKGROUND_LOG_PATH: ${{ runner.temp }}/cloudflare-workers.log
BACKGROUND_WAIT_TIMEOUT_MS: 120000
BACKGROUND_TAIL_LINES: 400
run: |
worker_port_offset="${CLOUDFLARE_WORKER_PORT_OFFSET:-0}"
export BACKGROUND_WAIT_ON="http-get://127.0.0.1:$((8787 + worker_port_offset))/ok
http-get://127.0.0.1:$((8788 + worker_port_offset))/ok
http-get://127.0.0.1:$((8789 + worker_port_offset))/ok"
bash .github/scripts/start-background-service.sh
run: bash .github/scripts/start-cloudflare-workers-with-retry.sh
- name: Run Cloudflare Workers integration tests
env:
VITEST_SHARD: ${{ matrix.shard }}
Expand Down Expand Up @@ -885,7 +872,7 @@ jobs:
needs: [changes, lint_typecheck, dead_code]
if: needs.changes.outputs.run_capgo == 'true'
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 7
name: Run Cloudflare plugin tests (serial)
permissions:
contents: read
Expand Down Expand Up @@ -919,7 +906,7 @@ jobs:
- name: Install dependencies
run: bun install
- name: Run Supabase Start
run: bun scripts/supabase-worktree.ts start -x imgproxy,studio,mailpit,realtime,postgres-meta,supavisor,logflare,vector
run: bash .github/scripts/start-supabase-worktree-with-retry.sh
- name: Export isolated test endpoints
run: |
{
Expand All @@ -941,19 +928,8 @@ jobs:
- id: start_cloudflare_workers
name: Start Cloudflare Workers for testing
env:
BACKGROUND_SERVICE_NAME: Cloudflare Workers
BACKGROUND_RUN_COMMAND: |
chmod +x scripts/start-cloudflare-workers.sh
exec ./scripts/start-cloudflare-workers.sh
BACKGROUND_LOG_PATH: ${{ runner.temp }}/cloudflare-plugin-workers.log
BACKGROUND_WAIT_TIMEOUT_MS: 120000
BACKGROUND_TAIL_LINES: 400
run: |
worker_port_offset="${CLOUDFLARE_WORKER_PORT_OFFSET:-0}"
export BACKGROUND_WAIT_ON="http-get://127.0.0.1:$((8787 + worker_port_offset))/ok
http-get://127.0.0.1:$((8788 + worker_port_offset))/ok
http-get://127.0.0.1:$((8789 + worker_port_offset))/ok"
bash .github/scripts/start-background-service.sh
CLOUDFLARE_WORKERS_LOG_PATH: ${{ runner.temp }}/cloudflare-plugin-workers.log
run: bash .github/scripts/start-cloudflare-workers-with-retry.sh
- name: Warm plugin /updates endpoint
run: |
plugin_url="http://127.0.0.1:$((8788 + CLOUDFLARE_WORKER_PORT_OFFSET))/updates"
Expand Down Expand Up @@ -1503,6 +1479,45 @@ jobs:
run: |
export BACKGROUND_WAIT_ON="${SUPABASE_FUNCTIONS_HEALTH_URL:?Missing isolated Supabase health URL}"
bash .github/scripts/start-background-service.sh
- name: Warm edge functions before CLI integration tests
run: |
# GET /ok alone is not enough — cold first requests under file parallelism 502.
health_url="${SUPABASE_FUNCTIONS_HEALTH_URL#http-get://}"
health_url="${health_url#https-get://}"
base_url="http://${health_url%/ok}"
warm_get() {
local path="$1"
for attempt in 1 2 3 4 5; do
status=$(curl --max-time 10 -s -o /tmp/edge-warm.body -w '%{http_code}' "${base_url}${path}" || true)
echo "edge warm GET path=${path} attempt=${attempt} status=${status}"
if [ "${status}" != "502" ] && [ "${status}" != "503" ] && [ "${status}" != "000" ]; then
return 0
fi
sleep "${attempt}"
done
return 1
}
warm_post() {
local path="$1"
for attempt in 1 2 3 4 5; do
status=$(curl --max-time 10 -s -o /tmp/edge-warm.body -w '%{http_code}' -X POST "${base_url}${path}" \
-H 'Content-Type: application/json' \
-H 'apisecret: testsecret' \
-d '{}' || true)
echo "edge warm POST path=${path} attempt=${attempt} status=${status}"
if [ "${status}" != "502" ] && [ "${status}" != "503" ] && [ "${status}" != "000" ]; then
return 0
fi
sleep "${attempt}"
done
return 1
}
warm_get /ok
warm_post /triggers/cron_email
warm_post /triggers/cron_stat_org
warm_post /triggers/cron_stat_app
warm_post /apikey
warm_post /app
- name: Run Capgo CLI integration tests
run: |
bun run supabase:with-env -- bunx vitest run tests/cli* --exclude=tests/cli-min-version.test.ts --exclude=tests/cli-new-encryption.test.ts
Expand Down
3 changes: 0 additions & 3 deletions BOUNTY.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@

Anyone from the community can review the pull request and leave comments.

Review are rewarded with a tip of $20 when requested on merged pull request.
AI review does not qualify.

## What is a good review?

Check code pattern repetition, and things that can be done better.
Expand Down
25 changes: 16 additions & 9 deletions cli/src/types/supabase.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2267,6 +2267,7 @@ export type Database = {
build_time_unit: number
created_at: string
credit_id: string
credit_id_us: string | null
description: string
id: string
market_desc: string | null
Expand All @@ -2277,15 +2278,19 @@ export type Database = {
price_m_id: string
price_y: number
price_y_id: string
price_y_id_us: string | null
price_m_id_us: string | null
storage: number
stripe_id: string
stripe_id_us: string | null
updated_at: string
}
Insert: {
bandwidth: number
build_time_unit?: number
created_at?: string
credit_id: string
credit_id_us?: string | null
description?: string
id?: string
market_desc?: string | null
Expand All @@ -2296,15 +2301,19 @@ export type Database = {
price_m_id: string
price_y?: number
price_y_id: string
price_y_id_us?: string | null
price_m_id_us?: string | null
storage: number
stripe_id?: string
stripe_id_us?: string | null
updated_at?: string
}
Update: {
bandwidth?: number
build_time_unit?: number
created_at?: string
credit_id?: string
credit_id_us?: string | null
description?: string
id?: string
market_desc?: string | null
Expand All @@ -2315,8 +2324,11 @@ export type Database = {
price_m_id?: string
price_y?: number
price_y_id?: string
price_y_id_us?: string | null
price_m_id_us?: string | null
storage?: number
stripe_id?: string
stripe_id_us?: string | null
updated_at?: string
}
Relationships: []
Expand Down Expand Up @@ -2642,6 +2654,7 @@ export type Database = {
stripe_info: {
Row: {
bandwidth_exceeded: boolean | null
billing_account: string
build_time_exceeded: boolean | null
canceled_at: string | null
churn_reason: string | null
Expand Down Expand Up @@ -2669,6 +2682,7 @@ export type Database = {
}
Insert: {
bandwidth_exceeded?: boolean | null
billing_account?: string
build_time_exceeded?: boolean | null
canceled_at?: string | null
churn_reason?: string | null
Expand Down Expand Up @@ -2696,6 +2710,7 @@ export type Database = {
}
Update: {
bandwidth_exceeded?: boolean | null
billing_account?: string
build_time_exceeded?: boolean | null
canceled_at?: string | null
churn_reason?: string | null
Expand All @@ -2721,15 +2736,7 @@ export type Database = {
updated_at?: string
upgraded_at?: string | null
}
Relationships: [
{
foreignKeyName: "stripe_info_product_id_fkey"
columns: ["product_id"]
isOneToOne: false
referencedRelation: "plans"
referencedColumns: ["stripe_id"]
},
]
Relationships: []
}
trial_extension_events: {
Row: {
Expand Down
2 changes: 2 additions & 0 deletions cloudflare_workers/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ import { app as pluginNotifications } from '../../supabase/functions/_backend/tr
import { app as queue_consumer } from '../../supabase/functions/_backend/triggers/queue_consumer.ts'
import { app as send_email } from './triggers/send_email.ts'
import { app as stripe_event } from '../../supabase/functions/_backend/triggers/stripe_event.ts'
import { app as stripe_event_us } from '../../supabase/functions/_backend/triggers/stripe_event_us.ts'
import { app as webhook_delivery } from '../../supabase/functions/_backend/triggers/webhook_delivery.ts'
import { app as webhook_dispatcher } from '../../supabase/functions/_backend/triggers/webhook_dispatcher.ts'
import { BRES, createAllCatch, createHono } from '../../supabase/functions/_backend/utils/hono.ts'
Expand Down Expand Up @@ -220,6 +221,7 @@ appTriggers.route('/on_version_delete', on_version_delete)
appTriggers.route('/on_manifest_create', on_manifest_create)
appTriggers.route('/on_deploy_history_create', on_deploy_history_create)
appTriggers.route('/stripe_event', stripe_event)
appTriggers.route('/stripe_event_us', stripe_event_us)
appTriggers.route('/on_organization_create', on_organization_create)
appTriggers.route('/cron_stat_app', cron_stat_app)
appTriggers.route('/cron_stat_org', cron_stat_org)
Expand Down
17 changes: 17 additions & 0 deletions read_replicate/schema_replicate.catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -1819,6 +1819,16 @@
"position": 26,
"table": "stripe_info",
"type": "boolean"
},
{
"default": "'ee'::text",
"generated": "",
"identity": "",
"name": "billing_account",
"notNull": true,
"position": 27,
"table": "stripe_info",
"type": "text"
}
],
"constraints": [
Expand Down Expand Up @@ -2067,6 +2077,13 @@
"type": "u",
"valid": true
},
{
"definition": "CHECK (billing_account = ANY (ARRAY['ee'::text, 'us'::text]))",
"name": "stripe_info_billing_account_check",
"table": "stripe_info",
"type": "c",
"valid": true
},
{
"definition": "PRIMARY KEY (customer_id)",
"name": "stripe_info_pkey",
Expand Down
4 changes: 3 additions & 1 deletion read_replicate/schema_replicate.sql
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,9 @@ CREATE TABLE public.stripe_info (
last_stripe_event_at timestamp with time zone,
past_due_at timestamp with time zone,
churn_reason text,
is_above_plan boolean
is_above_plan boolean,
billing_account text DEFAULT 'ee'::text NOT NULL,
CONSTRAINT stripe_info_billing_account_check CHECK ((billing_account = ANY (ARRAY['ee'::text, 'us'::text])))
);

ALTER TABLE ONLY public.stripe_info REPLICA IDENTITY FULL;
Expand Down
Loading
Loading