@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.
- package/README.md +310 -0
- package/dist/chunk-3OQVG44L.js +4196 -0
- package/dist/chunk-CMGFQCD7.js +87 -0
- package/dist/chunk-J6VKHOSX.js +641 -0
- package/dist/chunk-TYAHH7EW.js +406 -0
- package/dist/cli/index.cjs +5371 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +72 -0
- package/dist/cli/lib.cjs +5337 -0
- package/dist/cli/lib.d.cts +73 -0
- package/dist/cli/lib.d.ts +73 -0
- package/dist/cli/lib.js +21 -0
- package/dist/index.cjs +4321 -0
- package/dist/index.d.cts +815 -0
- package/dist/index.d.ts +815 -0
- package/dist/index.js +17 -0
- package/dist/migrations/0000_initial_migration.sql +1 -0
- package/dist/migrations/0001_products.sql +17 -0
- package/dist/migrations/0002_customers.sql +23 -0
- package/dist/migrations/0003_prices.sql +34 -0
- package/dist/migrations/0004_subscriptions.sql +56 -0
- package/dist/migrations/0005_invoices.sql +77 -0
- package/dist/migrations/0006_charges.sql +43 -0
- package/dist/migrations/0007_coupons.sql +19 -0
- package/dist/migrations/0008_disputes.sql +17 -0
- package/dist/migrations/0009_events.sql +12 -0
- package/dist/migrations/0010_payouts.sql +30 -0
- package/dist/migrations/0011_plans.sql +25 -0
- package/dist/migrations/0012_add_updated_at.sql +108 -0
- package/dist/migrations/0013_add_subscription_items.sql +12 -0
- package/dist/migrations/0014_migrate_subscription_items.sql +26 -0
- package/dist/migrations/0015_add_customer_deleted.sql +2 -0
- package/dist/migrations/0016_add_invoice_indexes.sql +2 -0
- package/dist/migrations/0017_drop_charges_unavailable_columns.sql +6 -0
- package/dist/migrations/0018_setup_intents.sql +17 -0
- package/dist/migrations/0019_payment_methods.sql +12 -0
- package/dist/migrations/0020_disputes_payment_intent_created_idx.sql +3 -0
- package/dist/migrations/0021_payment_intent.sql +42 -0
- package/dist/migrations/0022_adjust_plans.sql +5 -0
- package/dist/migrations/0023_invoice_deleted.sql +1 -0
- package/dist/migrations/0024_subscription_schedules.sql +29 -0
- package/dist/migrations/0025_tax_ids.sql +14 -0
- package/dist/migrations/0026_credit_notes.sql +36 -0
- package/dist/migrations/0027_add_marketing_features_to_products.sql +2 -0
- package/dist/migrations/0028_early_fraud_warning.sql +22 -0
- package/dist/migrations/0029_reviews.sql +28 -0
- package/dist/migrations/0030_refunds.sql +29 -0
- package/dist/migrations/0031_add_default_price.sql +2 -0
- package/dist/migrations/0032_update_subscription_items.sql +3 -0
- package/dist/migrations/0033_add_last_synced_at.sql +85 -0
- package/dist/migrations/0034_remove_foreign_keys.sql +13 -0
- package/dist/migrations/0035_checkout_sessions.sql +77 -0
- package/dist/migrations/0036_checkout_session_line_items.sql +24 -0
- package/dist/migrations/0037_add_features.sql +18 -0
- package/dist/migrations/0038_active_entitlement.sql +20 -0
- package/dist/migrations/0039_add_paused_to_subscription_status.sql +1 -0
- package/dist/migrations/0040_managed_webhooks.sql +28 -0
- package/dist/migrations/0041_rename_managed_webhooks.sql +2 -0
- package/dist/migrations/0042_convert_to_jsonb_generated_columns.sql +1821 -0
- package/dist/migrations/0043_add_account_id.sql +49 -0
- package/dist/migrations/0044_make_account_id_required.sql +54 -0
- package/dist/migrations/0045_sync_status.sql +18 -0
- package/dist/migrations/0046_sync_status_per_account.sql +91 -0
- package/dist/migrations/0047_api_key_hashes.sql +12 -0
- package/dist/migrations/0048_rename_reserved_columns.sql +1253 -0
- package/dist/migrations/0049_remove_redundant_underscores_from_metadata_tables.sql +68 -0
- package/dist/migrations/0050_rename_id_to_match_stripe_api.sql +239 -0
- package/dist/migrations/0051_remove_webhook_uuid.sql +7 -0
- package/dist/migrations/0052_webhook_url_uniqueness.sql +7 -0
- package/dist/migrations/0053_sync_observability.sql +104 -0
- package/dist/migrations/0054_drop_sync_status.sql +5 -0
- package/dist/migrations/0055_bigint_money_columns.sql +72 -0
- package/dist/migrations/0056_sync_run_closed_at.sql +53 -0
- package/dist/migrations/0057_rename_sync_tables.sql +57 -0
- package/dist/migrations/0058_improve_sync_runs_status.sql +36 -0
- package/dist/migrations/0059_sigma_subscription_item_change_events_v2_beta.sql +61 -0
- package/dist/migrations/0060_sigma_exchange_rates_from_usd.sql +38 -0
- package/dist/migrations/0061_add_page_cursor.sql +3 -0
- package/dist/migrations/0062_balance_transactions.sql +42 -0
- package/dist/supabase/index.cjs +523 -0
- package/dist/supabase/index.d.cts +121 -0
- package/dist/supabase/index.d.ts +121 -0
- package/dist/supabase/index.js +26 -0
- package/package.json +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Stripe Sync Engine
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
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).
|