Skip to content

Commit 2dc9c8c

Browse files
tonyxiaoclaude
andcommitted
Port PR #142: schema visualizer + explorer scripts onto v2
Adds the Stripe schema visualizer (Next.js + PGlite) and explorer build pipeline from github.com/stripe/pull/142. - packages/visualizer: in-browser schema explorer powered by PGlite (WASM Postgres), with committed bootstrap.sql (106 tables, 2020-08-27 Stripe API schema with seed data) so the visualizer works immediately - scripts/explorer-{harness,migrate,seed,export,build}.ts: pipeline to regenerate bootstrap.sql for a new Stripe API version; note that explorer-migrate.ts requires the old monolith (not present in v2) - package.json: adds `visualizer` and `explorer:build` root scripts The accounts→_sync_accounts rename (also in PR #142) is not ported since the old sync_accounts table does not exist in v2's architecture. Run: pnpm visualizer (starts at http://localhost:3000) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Committed-By-Agent: claude
1 parent 536becd commit 2dc9c8c

22 files changed

Lines changed: 10727 additions & 63 deletions

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
"typecheck": "pnpm -r run typecheck",
1313
"lint": "pnpm -r run lint",
1414
"format": "prettier --write .",
15-
"format:check": "prettier --check ."
15+
"format:check": "prettier --check .",
16+
"visualizer": "pnpm --filter @supabase/stripe-sync-visualizer dev",
17+
"explorer:build": "bun run scripts/explorer-build.ts"
1618
},
1719
"dependencies": {
1820
"pino": "^10.0.0"

packages/visualizer/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.vercel
2+
.next
3+
.env*.local
4+
tsconfig.tsbuildinfo

packages/visualizer/README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Stripe Schema Visualizer
2+
3+
This package contains the standalone browser UI for exploring generated Stripe schema data with PGlite.
4+
5+
The visualizer has two parts:
6+
7+
- `pnpm explorer:build` generates static artifacts.
8+
- `packages/visualizer` loads those artifacts into PGlite and lets you run SQL in the browser.
9+
10+
## Generated artifacts
11+
12+
- `packages/visualizer/public/explorer-data/bootstrap.sql`
13+
- `packages/visualizer/public/explorer-data/manifest.json`
14+
15+
These files are generated and should stay out of version control.
16+
17+
## Common commands
18+
19+
```bash
20+
pnpm explorer:build
21+
pnpm visualizer
22+
pnpm visualizer:with-data
23+
```
24+
25+
`pnpm visualizer:with-data` rebuilds the explorer data and then starts the visualizer app.
26+
27+
## How the app loads data
28+
29+
At runtime, the app loads `manifest.json` first and then hydrates PGlite from `bootstrap.sql`.
30+
After hydration, all SQL runs locally in the browser against the generated Stripe schema.
31+
32+
## Direct phase debugging
33+
34+
`pnpm explorer:build` is the normal command, but the underlying phase scripts still exist for debugging:
35+
36+
```bash
37+
pnpm tsx scripts/explorer-harness.ts start
38+
pnpm tsx scripts/explorer-migrate.ts --api-version=2020-08-27
39+
pnpm tsx scripts/explorer-seed.ts --api-version=2020-08-27 --seed=42
40+
pnpm tsx scripts/explorer-export.ts
41+
pnpm tsx scripts/explorer-harness.ts stop
42+
```
43+
44+
## Notes
45+
46+
- SQL bootstrap is preferred for speed and consistency.
47+
- The build pipeline recreates the artifacts from scratch on each run.
48+
- The deploy/install dashboard stays in `packages/dashboard`; this package only contains the schema visualizer UI.

packages/visualizer/next-env.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// <reference types="next" />
2+
/// <reference types="next/image-types/global" />
3+
/// <reference path="./.next/types/routes.d.ts" />
4+
5+
// NOTE: This file should not be edited
6+
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

packages/visualizer/next.config.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { NextConfig } from 'next'
2+
3+
const nextConfig: NextConfig = {
4+
typescript: {
5+
ignoreBuildErrors: false,
6+
},
7+
webpack: (config) => {
8+
config.experiments = {
9+
...config.experiments,
10+
asyncWebAssembly: true,
11+
}
12+
13+
config.module.rules.push({
14+
test: /\.wasm$/,
15+
type: 'asset/resource',
16+
})
17+
18+
return config
19+
},
20+
async headers() {
21+
return [
22+
{
23+
source: '/(.*)',
24+
headers: [
25+
{
26+
key: 'Cross-Origin-Embedder-Policy',
27+
value: 'require-corp',
28+
},
29+
{
30+
key: 'Cross-Origin-Opener-Policy',
31+
value: 'same-origin',
32+
},
33+
],
34+
},
35+
]
36+
},
37+
}
38+
39+
export default nextConfig

packages/visualizer/package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "@supabase/stripe-sync-visualizer",
3+
"version": "0.0.1",
4+
"private": true,
5+
"scripts": {
6+
"dev": "next dev",
7+
"build": "next build",
8+
"start": "next start",
9+
"lint": "next lint"
10+
},
11+
"dependencies": {
12+
"@codemirror/lang-sql": "^6.7.0",
13+
"@codemirror/state": "^6.4.0",
14+
"@codemirror/view": "^6.26.0",
15+
"@electric-sql/pglite": "^0.2.0",
16+
"codemirror": "^6.0.1",
17+
"next": "^15",
18+
"react": "^19",
19+
"react-dom": "^19"
20+
},
21+
"devDependencies": {
22+
"@tailwindcss/postcss": "^4.2.1",
23+
"@types/node": "^22",
24+
"@types/react": "^19",
25+
"@types/react-dom": "^19",
26+
"autoprefixer": "^10.4.27",
27+
"postcss": "^8.5.8",
28+
"tailwindcss": "^4.2.1",
29+
"typescript": "^5"
30+
}
31+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const config = {
2+
plugins: {
3+
'@tailwindcss/postcss': {},
4+
},
5+
}
6+
7+
export default config

packages/visualizer/public/explorer-data/bootstrap.sql

Lines changed: 5075 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
{
2+
"timestamp": "2026-03-25T08:43:23.988Z",
3+
"seed": 42,
4+
"apiVersion": "2020-08-27",
5+
"totalTables": 106,
6+
"coreTables": [
7+
"accounts",
8+
"products",
9+
"prices",
10+
"customers",
11+
"payment_methods",
12+
"setup_intents",
13+
"subscriptions",
14+
"subscription_items",
15+
"invoices",
16+
"payment_intents",
17+
"charges",
18+
"refunds",
19+
"checkout_sessions",
20+
"credit_notes",
21+
"disputes",
22+
"tax_ids"
23+
],
24+
"longTailTables": [
25+
"account_links",
26+
"alipay_accounts",
27+
"apple_pay_domains",
28+
"application_fees",
29+
"balance_transactions",
30+
"balances",
31+
"bank_accounts",
32+
"billing_portal_sessions",
33+
"bitcoin_receivers",
34+
"bitcoin_transactions",
35+
"capabilitys",
36+
"cards",
37+
"checkout_session_line_items",
38+
"country_specs",
39+
"coupons",
40+
"credit_note_line_items",
41+
"customer_balance_transactions",
42+
"deleted_accounts",
43+
"deleted_apple_pay_domains",
44+
"deleted_coupons",
45+
"deleted_customers",
46+
"deleted_discounts",
47+
"deleted_external_accounts",
48+
"deleted_invoiceitems",
49+
"deleted_invoices",
50+
"deleted_payment_sources",
51+
"deleted_persons",
52+
"deleted_plans",
53+
"deleted_products",
54+
"deleted_radar_value_list_items",
55+
"deleted_radar_value_lists",
56+
"deleted_recipients",
57+
"deleted_skus",
58+
"deleted_subscription_items",
59+
"deleted_tax_ids",
60+
"deleted_terminal_locations",
61+
"deleted_terminal_readers",
62+
"deleted_webhook_endpoints",
63+
"discounts",
64+
"early_fraud_warnings",
65+
"ephemeral_keys",
66+
"events",
67+
"exchange_rates",
68+
"external_accounts",
69+
"fee_refunds",
70+
"file_links",
71+
"files",
72+
"invoiceitems",
73+
"issuer_fraud_records",
74+
"issuing_authorizations",
75+
"issuing_cardholders",
76+
"issuing_cards",
77+
"issuing_disputes",
78+
"issuing_settlements",
79+
"issuing_transactions",
80+
"light_account_logouts",
81+
"line_items",
82+
"login_links",
83+
"mandates",
84+
"order_returns",
85+
"orders",
86+
"payment_sources",
87+
"payouts",
88+
"persons",
89+
"plans",
90+
"promotion_codes",
91+
"radar_value_list_items",
92+
"radar_value_lists",
93+
"recipients",
94+
"reporting_report_runs",
95+
"reporting_report_types",
96+
"reviews",
97+
"scheduled_query_runs",
98+
"skus",
99+
"source_mandate_notifications",
100+
"source_transactions",
101+
"sources",
102+
"subscription_schedules",
103+
"tax_rates",
104+
"terminal_connection_tokens",
105+
"terminal_locations",
106+
"terminal_readers",
107+
"three_d_secures",
108+
"tokens",
109+
"topups",
110+
"transfer_reversals",
111+
"transfers",
112+
"usage_record_summarys",
113+
"usage_records",
114+
"webhook_endpoints"
115+
],
116+
"manifest": {
117+
"account_links": 9,
118+
"accounts": 1,
119+
"alipay_accounts": 9,
120+
"apple_pay_domains": 9,
121+
"application_fees": 1,
122+
"balance_transactions": 17,
123+
"balances": 2,
124+
"bank_accounts": 16,
125+
"billing_portal_sessions": 13,
126+
"bitcoin_receivers": 1,
127+
"bitcoin_transactions": 3,
128+
"capabilitys": 2,
129+
"cards": 17,
130+
"charges": 45,
131+
"checkout_session_line_items": 1,
132+
"checkout_sessions": 18,
133+
"country_specs": 16,
134+
"coupons": 15,
135+
"credit_note_line_items": 10,
136+
"credit_notes": 5,
137+
"customer_balance_transactions": 18,
138+
"customers": 25,
139+
"deleted_accounts": 4,
140+
"deleted_apple_pay_domains": 5,
141+
"deleted_coupons": 8,
142+
"deleted_customers": 8,
143+
"deleted_discounts": 3,
144+
"deleted_external_accounts": 5,
145+
"deleted_invoiceitems": 8,
146+
"deleted_invoices": 2,
147+
"deleted_payment_sources": 2,
148+
"deleted_persons": 15,
149+
"deleted_plans": 18,
150+
"deleted_products": 5,
151+
"deleted_radar_value_list_items": 5,
152+
"deleted_radar_value_lists": 9,
153+
"deleted_recipients": 16,
154+
"deleted_skus": 4,
155+
"deleted_subscription_items": 1,
156+
"deleted_tax_ids": 4,
157+
"deleted_terminal_locations": 6,
158+
"deleted_terminal_readers": 20,
159+
"deleted_webhook_endpoints": 1,
160+
"discounts": 13,
161+
"disputes": 3,
162+
"early_fraud_warnings": 15,
163+
"ephemeral_keys": 1,
164+
"events": 10,
165+
"exchange_rates": 1,
166+
"external_accounts": 2,
167+
"fee_refunds": 16,
168+
"file_links": 7,
169+
"files": 3,
170+
"invoiceitems": 19,
171+
"invoices": 35,
172+
"issuer_fraud_records": 18,
173+
"issuing_authorizations": 1,
174+
"issuing_cardholders": 12,
175+
"issuing_cards": 19,
176+
"issuing_disputes": 11,
177+
"issuing_settlements": 2,
178+
"issuing_transactions": 12,
179+
"light_account_logouts": 12,
180+
"line_items": 12,
181+
"login_links": 5,
182+
"mandates": 3,
183+
"order_returns": 3,
184+
"orders": 8,
185+
"payment_intents": 40,
186+
"payment_methods": 30,
187+
"payment_sources": 16,
188+
"payouts": 19,
189+
"persons": 1,
190+
"plans": 7,
191+
"prices": 12,
192+
"products": 8,
193+
"promotion_codes": 4,
194+
"radar_value_list_items": 7,
195+
"radar_value_lists": 18,
196+
"recipients": 4,
197+
"refunds": 10,
198+
"reporting_report_runs": 11,
199+
"reporting_report_types": 8,
200+
"reviews": 7,
201+
"scheduled_query_runs": 11,
202+
"setup_intents": 15,
203+
"skus": 14,
204+
"source_mandate_notifications": 2,
205+
"source_transactions": 2,
206+
"sources": 11,
207+
"subscription_items": 30,
208+
"subscription_schedules": 9,
209+
"subscriptions": 20,
210+
"tax_ids": 12,
211+
"tax_rates": 20,
212+
"terminal_connection_tokens": 6,
213+
"terminal_locations": 8,
214+
"terminal_readers": 16,
215+
"three_d_secures": 16,
216+
"tokens": 18,
217+
"topups": 20,
218+
"transfer_reversals": 3,
219+
"transfers": 7,
220+
"usage_record_summarys": 9,
221+
"usage_records": 4,
222+
"webhook_endpoints": 18
223+
},
224+
"failedTables": [],
225+
"verification": {
226+
"allTablesSeeded": true,
227+
"tablesWithData": 106,
228+
"emptyTables": []
229+
}
230+
}

0 commit comments

Comments
 (0)