@paymentsdb/sync-engine 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +310 -0
  2. package/dist/chunk-3OQVG44L.js +4196 -0
  3. package/dist/chunk-CMGFQCD7.js +87 -0
  4. package/dist/chunk-J6VKHOSX.js +641 -0
  5. package/dist/chunk-TYAHH7EW.js +406 -0
  6. package/dist/cli/index.cjs +5371 -0
  7. package/dist/cli/index.d.cts +1 -0
  8. package/dist/cli/index.d.ts +1 -0
  9. package/dist/cli/index.js +72 -0
  10. package/dist/cli/lib.cjs +5337 -0
  11. package/dist/cli/lib.d.cts +73 -0
  12. package/dist/cli/lib.d.ts +73 -0
  13. package/dist/cli/lib.js +21 -0
  14. package/dist/index.cjs +4321 -0
  15. package/dist/index.d.cts +815 -0
  16. package/dist/index.d.ts +815 -0
  17. package/dist/index.js +17 -0
  18. package/dist/migrations/0000_initial_migration.sql +1 -0
  19. package/dist/migrations/0001_products.sql +17 -0
  20. package/dist/migrations/0002_customers.sql +23 -0
  21. package/dist/migrations/0003_prices.sql +34 -0
  22. package/dist/migrations/0004_subscriptions.sql +56 -0
  23. package/dist/migrations/0005_invoices.sql +77 -0
  24. package/dist/migrations/0006_charges.sql +43 -0
  25. package/dist/migrations/0007_coupons.sql +19 -0
  26. package/dist/migrations/0008_disputes.sql +17 -0
  27. package/dist/migrations/0009_events.sql +12 -0
  28. package/dist/migrations/0010_payouts.sql +30 -0
  29. package/dist/migrations/0011_plans.sql +25 -0
  30. package/dist/migrations/0012_add_updated_at.sql +108 -0
  31. package/dist/migrations/0013_add_subscription_items.sql +12 -0
  32. package/dist/migrations/0014_migrate_subscription_items.sql +26 -0
  33. package/dist/migrations/0015_add_customer_deleted.sql +2 -0
  34. package/dist/migrations/0016_add_invoice_indexes.sql +2 -0
  35. package/dist/migrations/0017_drop_charges_unavailable_columns.sql +6 -0
  36. package/dist/migrations/0018_setup_intents.sql +17 -0
  37. package/dist/migrations/0019_payment_methods.sql +12 -0
  38. package/dist/migrations/0020_disputes_payment_intent_created_idx.sql +3 -0
  39. package/dist/migrations/0021_payment_intent.sql +42 -0
  40. package/dist/migrations/0022_adjust_plans.sql +5 -0
  41. package/dist/migrations/0023_invoice_deleted.sql +1 -0
  42. package/dist/migrations/0024_subscription_schedules.sql +29 -0
  43. package/dist/migrations/0025_tax_ids.sql +14 -0
  44. package/dist/migrations/0026_credit_notes.sql +36 -0
  45. package/dist/migrations/0027_add_marketing_features_to_products.sql +2 -0
  46. package/dist/migrations/0028_early_fraud_warning.sql +22 -0
  47. package/dist/migrations/0029_reviews.sql +28 -0
  48. package/dist/migrations/0030_refunds.sql +29 -0
  49. package/dist/migrations/0031_add_default_price.sql +2 -0
  50. package/dist/migrations/0032_update_subscription_items.sql +3 -0
  51. package/dist/migrations/0033_add_last_synced_at.sql +85 -0
  52. package/dist/migrations/0034_remove_foreign_keys.sql +13 -0
  53. package/dist/migrations/0035_checkout_sessions.sql +77 -0
  54. package/dist/migrations/0036_checkout_session_line_items.sql +24 -0
  55. package/dist/migrations/0037_add_features.sql +18 -0
  56. package/dist/migrations/0038_active_entitlement.sql +20 -0
  57. package/dist/migrations/0039_add_paused_to_subscription_status.sql +1 -0
  58. package/dist/migrations/0040_managed_webhooks.sql +28 -0
  59. package/dist/migrations/0041_rename_managed_webhooks.sql +2 -0
  60. package/dist/migrations/0042_convert_to_jsonb_generated_columns.sql +1821 -0
  61. package/dist/migrations/0043_add_account_id.sql +49 -0
  62. package/dist/migrations/0044_make_account_id_required.sql +54 -0
  63. package/dist/migrations/0045_sync_status.sql +18 -0
  64. package/dist/migrations/0046_sync_status_per_account.sql +91 -0
  65. package/dist/migrations/0047_api_key_hashes.sql +12 -0
  66. package/dist/migrations/0048_rename_reserved_columns.sql +1253 -0
  67. package/dist/migrations/0049_remove_redundant_underscores_from_metadata_tables.sql +68 -0
  68. package/dist/migrations/0050_rename_id_to_match_stripe_api.sql +239 -0
  69. package/dist/migrations/0051_remove_webhook_uuid.sql +7 -0
  70. package/dist/migrations/0052_webhook_url_uniqueness.sql +7 -0
  71. package/dist/migrations/0053_sync_observability.sql +104 -0
  72. package/dist/migrations/0054_drop_sync_status.sql +5 -0
  73. package/dist/migrations/0055_bigint_money_columns.sql +72 -0
  74. package/dist/migrations/0056_sync_run_closed_at.sql +53 -0
  75. package/dist/migrations/0057_rename_sync_tables.sql +57 -0
  76. package/dist/migrations/0058_improve_sync_runs_status.sql +36 -0
  77. package/dist/migrations/0059_sigma_subscription_item_change_events_v2_beta.sql +61 -0
  78. package/dist/migrations/0060_sigma_exchange_rates_from_usd.sql +38 -0
  79. package/dist/migrations/0061_add_page_cursor.sql +3 -0
  80. package/dist/migrations/0062_balance_transactions.sql +42 -0
  81. package/dist/supabase/index.cjs +523 -0
  82. package/dist/supabase/index.d.cts +121 -0
  83. package/dist/supabase/index.d.ts +121 -0
  84. package/dist/supabase/index.js +26 -0
  85. package/package.json +83 -0
package/README.md ADDED
@@ -0,0 +1,310 @@
1
+ # Stripe Sync Engine
2
+
3
+ ![GitHub License](https://img.shields.io/github/license/stripe-experiments/sync-engine)
4
+ ![NPM Version](https://img.shields.io/npm/v/stripe-experiment-sync)
5
+
6
+ A TypeScript library to synchronize Stripe data into a PostgreSQL database, designed for use in Node.js backends and serverless environments.
7
+
8
+ ## Features
9
+
10
+ - **Managed Webhooks:** Automatic webhook creation and lifecycle management with built-in processing
11
+ - **Real-time Sync:** Keep your database in sync with Stripe automatically
12
+ - **Backfill Support:** Sync historical data from Stripe to your database
13
+ - **Stripe Sigma:** Support for Stripe Sigma reporting data
14
+ - **Supabase Ready:** Deploy to Supabase Edge Functions with one command
15
+ - **Automatic Retries:** Built-in retry logic for rate limits and transient errors
16
+ - **Observability:** Track sync runs and monitor progress
17
+
18
+ ## Installation
19
+
20
+ ```sh
21
+ npm install stripe-experiment-sync stripe
22
+ # or
23
+ pnpm add stripe-experiment-sync stripe
24
+ # or
25
+ yarn add stripe-experiment-sync stripe
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ```ts
31
+ import { StripeSync } from 'stripe-experiment-sync'
32
+
33
+ const sync = new StripeSync({
34
+ poolConfig: {
35
+ connectionString: 'postgres://user:pass@host:port/db',
36
+ max: 10,
37
+ },
38
+ stripeSecretKey: 'sk_test_...',
39
+ })
40
+
41
+ // Create a managed webhook - no additional processing needed!
42
+ const webhook = await sync.findOrCreateManagedWebhook('https://example.com/stripe-webhooks')
43
+
44
+ // Cleanup when done (closes PostgreSQL connection pool)
45
+ await sync.close()
46
+ ```
47
+
48
+ ## Managed Webhooks
49
+
50
+ The Stripe Sync Engine automatically manages webhook endpoints and their processing. Once created, managed webhooks handle everything automatically - you don't need to manually process events.
51
+
52
+ ### Creating Managed Webhooks
53
+
54
+ ```typescript
55
+ // Create or reuse an existing webhook endpoint
56
+ // This webhook will automatically sync all Stripe events to your database
57
+ const webhook = await sync.findOrCreateManagedWebhook('https://example.com/stripe-webhooks')
58
+
59
+ // Create a webhook for specific events
60
+ const webhook = await sync.createManagedWebhook('https://example.com/stripe-webhooks', {
61
+ enabled_events: ['customer.created', 'customer.updated', 'invoice.paid'],
62
+ })
63
+
64
+ console.log(webhook.id) // we_xxx
65
+ console.log(webhook.secret) // whsec_xxx
66
+ ```
67
+
68
+ **⚠️ Important:** Managed webhooks are tracked in the database and automatically process incoming events. You don't need to call `processWebhook()` for managed webhooks - the library handles this internally.
69
+
70
+ ### Managing Webhooks
71
+
72
+ ```typescript
73
+ // List all managed webhooks
74
+ const webhooks = await sync.listManagedWebhooks()
75
+
76
+ // Get a specific webhook
77
+ const webhook = await sync.getManagedWebhook('we_xxx')
78
+
79
+ // Delete a managed webhook
80
+ await sync.deleteManagedWebhook('we_xxx')
81
+ ```
82
+
83
+ ### How It Works
84
+
85
+ **Automatic Processing:** Managed webhooks are stored in the `stripe._managed_webhooks` table. When Stripe sends events to these webhooks, they are automatically processed and synced to your database.
86
+
87
+ **Race Condition Protection:** PostgreSQL advisory locks prevent race conditions when multiple instances call `findOrCreateManagedWebhook()` concurrently. A unique constraint on `(url, account_id)` provides additional safety.
88
+
89
+ **Automatic Cleanup:** When you call `findOrCreateManagedWebhook()`, it will:
90
+
91
+ 1. Check if a webhook already exists for the URL in the database
92
+ 2. If found, reuse the existing webhook
93
+ 3. If not found, create a new webhook in Stripe and record it
94
+ 4. Clean up any orphaned webhooks from previous installations
95
+
96
+ ## Manual Webhook Processing
97
+
98
+ If you need to process webhooks outside of managed webhooks (e.g., for testing or custom integrations):
99
+
100
+ ```typescript
101
+ // Validate and process a webhook event
102
+ app.post('/stripe-webhooks', async (req, res) => {
103
+ const signature = req.headers['stripe-signature']
104
+ const payload = req.body
105
+
106
+ try {
107
+ await sync.processWebhook(payload, signature)
108
+ res.status(200).send({ received: true })
109
+ } catch (error) {
110
+ res.status(400).send({ error: error.message })
111
+ }
112
+ })
113
+
114
+ // Or process an event directly (no signature validation)
115
+ await sync.processEvent(stripeEvent)
116
+
117
+ // Cleanup when done
118
+ await sync.close()
119
+ ```
120
+
121
+ **Note:** This is only needed for custom webhook endpoints. Managed webhooks handle processing automatically.
122
+
123
+ ## Configuration
124
+
125
+ | Option | Type | Description |
126
+ | ------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
127
+ | `poolConfig` | object | **Required.** PostgreSQL connection pool configuration. Supports `connectionString`, `max`, `keepAlive`. See [Node-Postgres Pool API](https://node-postgres.com/apis/pool). |
128
+ | `stripeSecretKey` | string | **Required.** Stripe secret key |
129
+ | `stripeWebhookSecret` | string | Stripe webhook signing secret (only needed for manual webhook processing) |
130
+ | `stripeApiVersion` | string | Stripe API version (default: `2020-08-27`) |
131
+ | `enableSigma` | boolean | Enable Stripe Sigma reporting data sync. Default: false |
132
+ | `autoExpandLists` | boolean | Fetch all list items from Stripe (not just the default 10) |
133
+ | `backfillRelatedEntities` | boolean | Ensure related entities exist for foreign key integrity |
134
+ | `revalidateObjectsViaStripeApi` | Array | Always fetch latest data from Stripe instead of trusting webhook payload. Possible values: charge, credit_note, customer, dispute, invoice, payment_intent, payment_method, plan, price, product, refund, review, radar.early_fraud_warning, setup_intent, subscription, subscription_schedule, tax_id |
135
+ | `maxRetries` | number | Maximum retry attempts for 429 rate limits. Default: 5 |
136
+ | `initialRetryDelayMs` | number | Initial retry delay in milliseconds. Default: 1000 |
137
+ | `maxRetryDelayMs` | number | Maximum retry delay in milliseconds. Default: 60000 |
138
+ | `logger` | Logger | Logger instance (pino-compatible) |
139
+
140
+ ## Database Schema
141
+
142
+ The library creates and manages a `stripe` schema in PostgreSQL with tables for all supported Stripe objects.
143
+
144
+ > **Important:** The schema name is fixed as `stripe` and cannot be configured.
145
+
146
+ > **Note:** Fields and tables prefixed with `_` are reserved for internal metadata: `_account_id`, `_last_synced_at`, `_updated_at`, `_migrations`, `_managed_webhooks`, `_sync_runs`, `_sync_obj_runs`.
147
+
148
+ ### Running Migrations
149
+
150
+ ```ts
151
+ import { runMigrations } from 'stripe-experiment-sync'
152
+
153
+ await runMigrations({ databaseUrl: 'postgres://...' })
154
+ ```
155
+
156
+ ### Observability
157
+
158
+ Track sync operations with the `sync_runs` view:
159
+
160
+ ```sql
161
+ SELECT
162
+ account_id,
163
+ started_at,
164
+ closed_at,
165
+ status, -- 'running', 'complete', or 'error'
166
+ total_processed, -- Total records synced
167
+ complete_count, -- Completed object types
168
+ error_count, -- Object types with errors
169
+ running_count, -- Currently syncing
170
+ pending_count -- Not yet started
171
+ FROM stripe.sync_runs
172
+ ORDER BY started_at DESC;
173
+ ```
174
+
175
+ ## Syncing Data
176
+
177
+ ### Sync a Single Entity
178
+
179
+ ```ts
180
+ // Automatically detects entity type from ID prefix
181
+ await sync.syncSingleEntity('cus_12345')
182
+ await sync.syncSingleEntity('prod_xyz')
183
+ ```
184
+
185
+ ### Backfill Historical Data
186
+
187
+ ```ts
188
+ // Sync all products created after a date
189
+ await sync.processUntilDone({
190
+ object: 'product',
191
+ created: { gte: 1643872333 }, // Unix timestamp
192
+ })
193
+
194
+ // Sync all customers
195
+ await sync.processUntilDone({ object: 'customer' })
196
+
197
+ // Sync everything
198
+ await sync.processUntilDone({ object: 'all' })
199
+ ```
200
+
201
+ Supported objects: `all`, `charge`, `checkout_sessions`, `credit_note`, `customer`, `customer_with_entitlements`, `dispute`, `early_fraud_warning`, `invoice`, `payment_intent`, `payment_method`, `plan`, `price`, `product`, `refund`, `setup_intent`, `subscription`, `subscription_schedules`, `tax_id`.
202
+
203
+ The sync engine tracks cursors per account and resource, enabling incremental syncing that resumes after interruptions.
204
+
205
+ For paged backfills, the engine keeps a separate per-run pagination cursor (`page_cursor`) while the
206
+ incremental cursor continues to track the highest `created` timestamp.
207
+
208
+ > **Tip:** For large Stripe accounts (>10,000 objects), loop through date ranges day-by-day to avoid timeouts.
209
+
210
+ ## Account Management
211
+
212
+ ### Get Current Account
213
+
214
+ ```ts
215
+ const account = await sync.getCurrentAccount()
216
+ console.log(account.id) // acct_xxx
217
+ ```
218
+
219
+ ### List Synced Accounts
220
+
221
+ ```ts
222
+ const accounts = await sync.getAllSyncedAccounts()
223
+ ```
224
+
225
+ ### Delete Account Data
226
+
227
+ **⚠️ WARNING:** This permanently deletes all synced data for an account.
228
+
229
+ ```ts
230
+ // Preview deletion
231
+ const preview = await sync.dangerouslyDeleteSyncedAccountData('acct_xxx', {
232
+ dryRun: true,
233
+ })
234
+ console.log(preview.deletedRecordCounts)
235
+
236
+ // Actually delete
237
+ const result = await sync.dangerouslyDeleteSyncedAccountData('acct_xxx')
238
+ ```
239
+
240
+ ## Supabase Deployment
241
+
242
+ Deploy to Supabase Edge Functions for serverless operation with automatic webhook processing:
243
+
244
+ ```bash
245
+ # Install
246
+ npx stripe-experiment-sync supabase install \
247
+ --token $SUPABASE_ACCESS_TOKEN \
248
+ --project $SUPABASE_PROJECT_REF \
249
+ --stripe-key $STRIPE_API_KEY
250
+
251
+ # Install specific version
252
+ npx stripe-experiment-sync supabase install \
253
+ --token $SUPABASE_ACCESS_TOKEN \
254
+ --project $SUPABASE_PROJECT_REF \
255
+ --stripe-key $STRIPE_API_KEY \
256
+ --package-version 1.0.15
257
+
258
+ # Uninstall
259
+ npx stripe-experiment-sync supabase uninstall \
260
+ --token $SUPABASE_ACCESS_TOKEN \
261
+ --project $SUPABASE_PROJECT_REF
262
+ ```
263
+
264
+ ### Install Options
265
+
266
+ - `--token <token>` - Supabase access token (or `SUPABASE_ACCESS_TOKEN` env)
267
+ - `--project <ref>` - Supabase project ref (or `SUPABASE_PROJECT_REF` env)
268
+ - `--stripe-key <key>` - Stripe API key (or `STRIPE_API_KEY` env)
269
+ - `--package-version <version>` - npm package version (default: latest)
270
+ - `--worker-interval <seconds>` - Worker interval in seconds (default: 60)
271
+ - `--management-url <url>` - Supabase management API URL with protocol (default: https://api.supabase.com). For local testing: http://localhost:54323
272
+
273
+ The install command will:
274
+
275
+ 1. Deploy Edge Functions: `stripe-setup`, `stripe-webhook`, `stripe-worker`
276
+ 2. Run database migrations to create the `stripe` schema
277
+ 3. Create a managed Stripe webhook pointing to your Supabase project
278
+ 4. Set up a pg_cron job for automatic background syncing
279
+
280
+ ## CLI Commands
281
+
282
+ ```bash
283
+ # Run database migrations
284
+ npx stripe-experiment-sync migrate --database-url $DATABASE_URL
285
+
286
+ # Start local sync with ngrok tunnel
287
+ npx stripe-experiment-sync start \
288
+ --stripe-key $STRIPE_API_KEY \
289
+ --ngrok-token $NGROK_AUTH_TOKEN \
290
+ --database-url $DATABASE_URL
291
+
292
+ # Backfill specific entity type
293
+ npx stripe-experiment-sync backfill customer \
294
+ --stripe-key $STRIPE_API_KEY \
295
+ --database-url $DATABASE_URL
296
+
297
+ # Enable Sigma data syncing
298
+ npx stripe-experiment-sync start \
299
+ --stripe-key $STRIPE_API_KEY \
300
+ --database-url $DATABASE_URL \
301
+ --sigma
302
+ ```
303
+
304
+ ## License
305
+
306
+ See [LICENSE](LICENSE) file.
307
+
308
+ ## Contributing
309
+
310
+ Issues and pull requests are welcome at [https://github.com/stripe-experiments/sync-engine](https://github.com/stripe-experiments/sync-engine).