stripe-experiment-sync 0.0.4 → 1.0.0
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 +113 -42
- package/dist/adapter-BtXT5w9r.d.cts +51 -0
- package/dist/adapter-BtXT5w9r.d.ts +51 -0
- package/dist/index.cjs +2652 -1731
- package/dist/index.d.cts +496 -126
- package/dist/index.d.ts +496 -126
- package/dist/index.js +2642 -1723
- 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/pg.cjs +87 -0
- package/dist/pg.d.cts +28 -0
- package/dist/pg.d.ts +28 -0
- package/dist/pg.js +50 -0
- package/dist/postgres-js.cjs +90 -0
- package/dist/postgres-js.d.cts +31 -0
- package/dist/postgres-js.d.ts +31 -0
- package/dist/postgres-js.js +53 -0
- package/package.json +41 -13
package/dist/index.d.cts
CHANGED
|
@@ -1,78 +1,220 @@
|
|
|
1
|
-
import { Express } from 'express';
|
|
2
|
-
import pg, { PoolConfig, QueryResult } from 'pg';
|
|
3
|
-
import pino from 'pino';
|
|
4
1
|
import Stripe from 'stripe';
|
|
5
|
-
import {
|
|
2
|
+
import { D as DatabaseAdapter } from './adapter-BtXT5w9r.cjs';
|
|
3
|
+
export { P as PgCompatibleClient } from './adapter-BtXT5w9r.cjs';
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
5
|
+
type PostgresConfig = {
|
|
6
|
+
schema: string;
|
|
7
|
+
adapter: DatabaseAdapter;
|
|
8
|
+
};
|
|
9
|
+
declare class PostgresClient {
|
|
10
|
+
private config;
|
|
11
|
+
private adapter;
|
|
12
|
+
constructor(config: PostgresConfig);
|
|
13
|
+
/**
|
|
14
|
+
* Get the underlying adapter.
|
|
15
|
+
* Useful for accessing adapter-specific features.
|
|
16
|
+
*/
|
|
17
|
+
getAdapter(): DatabaseAdapter;
|
|
18
|
+
/**
|
|
19
|
+
* Close all database connections.
|
|
20
|
+
*/
|
|
21
|
+
end(): Promise<void>;
|
|
22
|
+
delete(table: string, id: string): Promise<boolean>;
|
|
23
|
+
query<T = any>(text: string, params?: any[]): Promise<{
|
|
24
|
+
rows: T[];
|
|
25
|
+
rowCount: number;
|
|
26
|
+
}>;
|
|
27
|
+
upsertMany<T extends {
|
|
28
|
+
[Key: string]: any;
|
|
29
|
+
}>(entries: T[], table: string): Promise<T[]>;
|
|
30
|
+
upsertManyWithTimestampProtection<T extends {
|
|
31
|
+
[Key: string]: any;
|
|
32
|
+
}>(entries: T[], table: string, accountId: string, syncTimestamp?: string): Promise<T[]>;
|
|
33
|
+
private cleanseArrayField;
|
|
34
|
+
findMissingEntries(table: string, ids: string[]): Promise<string[]>;
|
|
35
|
+
upsertAccount(accountData: {
|
|
36
|
+
id: string;
|
|
37
|
+
raw_data: any;
|
|
38
|
+
}, apiKeyHash: string): Promise<void>;
|
|
39
|
+
getAllAccounts(): Promise<any[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Looks up an account ID by API key hash
|
|
42
|
+
* Uses the GIN index on api_key_hashes for fast lookups
|
|
43
|
+
* @param apiKeyHash - SHA-256 hash of the Stripe API key
|
|
44
|
+
* @returns Account ID if found, null otherwise
|
|
45
|
+
*/
|
|
46
|
+
getAccountIdByApiKeyHash(apiKeyHash: string): Promise<string | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Looks up full account data by API key hash
|
|
49
|
+
* @param apiKeyHash - SHA-256 hash of the Stripe API key
|
|
50
|
+
* @returns Account raw data if found, null otherwise
|
|
51
|
+
*/
|
|
52
|
+
getAccountByApiKeyHash(apiKeyHash: string): Promise<any | null>;
|
|
53
|
+
private getAccountIdColumn;
|
|
54
|
+
getAccountRecordCounts(accountId: string): Promise<{
|
|
55
|
+
[tableName: string]: number;
|
|
56
|
+
}>;
|
|
57
|
+
deleteAccountWithCascade(accountId: string, useTransaction: boolean): Promise<{
|
|
58
|
+
[tableName: string]: number;
|
|
59
|
+
}>;
|
|
60
|
+
/**
|
|
61
|
+
* Hash a string to a 32-bit integer for use with PostgreSQL advisory locks.
|
|
62
|
+
* Uses a simple hash algorithm that produces consistent results.
|
|
63
|
+
*/
|
|
64
|
+
private hashToInt32;
|
|
65
|
+
/**
|
|
66
|
+
* Acquire a PostgreSQL advisory lock for the given key.
|
|
67
|
+
* This lock is automatically released when the connection is closed or explicitly released.
|
|
68
|
+
* Advisory locks are session-level and will block until the lock is available.
|
|
69
|
+
*
|
|
70
|
+
* @param key - A string key to lock on (will be hashed to an integer)
|
|
71
|
+
*/
|
|
72
|
+
acquireAdvisoryLock(key: string): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Release a PostgreSQL advisory lock for the given key.
|
|
75
|
+
*
|
|
76
|
+
* @param key - The same string key used to acquire the lock
|
|
77
|
+
*/
|
|
78
|
+
releaseAdvisoryLock(key: string): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Execute a function while holding an advisory lock.
|
|
81
|
+
* The lock is automatically released after the function completes (success or error).
|
|
42
82
|
*
|
|
43
|
-
* @param
|
|
44
|
-
* @
|
|
83
|
+
* @param key - A string key to lock on (will be hashed to an integer)
|
|
84
|
+
* @param fn - The function to execute while holding the lock
|
|
85
|
+
* @returns The result of the function
|
|
86
|
+
*/
|
|
87
|
+
withAdvisoryLock<T>(key: string, fn: () => Promise<T>): Promise<T>;
|
|
88
|
+
/**
|
|
89
|
+
* Cancel stale runs (running but no object updated in 5 minutes).
|
|
90
|
+
* Called before creating a new run to clean up crashed syncs.
|
|
91
|
+
* Only cancels runs that have objects AND none have recent activity.
|
|
92
|
+
* Runs without objects yet (just created) are not considered stale.
|
|
93
|
+
*/
|
|
94
|
+
cancelStaleRuns(accountId: string): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Get or create a sync run for this account.
|
|
97
|
+
* Returns existing run if one is active, otherwise creates new one.
|
|
98
|
+
* Auto-cancels stale runs before checking.
|
|
99
|
+
*
|
|
100
|
+
* @returns RunKey with isNew flag, or null if constraint violation (race condition)
|
|
101
|
+
*/
|
|
102
|
+
getOrCreateSyncRun(accountId: string, triggeredBy?: string): Promise<{
|
|
103
|
+
accountId: string;
|
|
104
|
+
runStartedAt: Date;
|
|
105
|
+
isNew: boolean;
|
|
106
|
+
} | null>;
|
|
107
|
+
/**
|
|
108
|
+
* Get the active sync run for an account (if any).
|
|
45
109
|
*/
|
|
46
|
-
|
|
110
|
+
getActiveSyncRun(accountId: string): Promise<{
|
|
111
|
+
accountId: string;
|
|
112
|
+
runStartedAt: Date;
|
|
113
|
+
} | null>;
|
|
47
114
|
/**
|
|
48
|
-
*
|
|
49
|
-
* 1. Optionally deletes Stripe webhook endpoint from Stripe and database (based on keepWebhooksOnShutdown)
|
|
115
|
+
* Get full sync run details.
|
|
50
116
|
*/
|
|
51
|
-
|
|
117
|
+
getSyncRun(accountId: string, runStartedAt: Date): Promise<{
|
|
118
|
+
accountId: string;
|
|
119
|
+
runStartedAt: Date;
|
|
120
|
+
status: string;
|
|
121
|
+
maxConcurrent: number;
|
|
122
|
+
} | null>;
|
|
52
123
|
/**
|
|
53
|
-
*
|
|
54
|
-
|
|
55
|
-
|
|
124
|
+
* Mark a sync run as complete.
|
|
125
|
+
*/
|
|
126
|
+
completeSyncRun(accountId: string, runStartedAt: Date): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Mark a sync run as failed.
|
|
129
|
+
*/
|
|
130
|
+
failSyncRun(accountId: string, runStartedAt: Date, errorMessage: string): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Create object run entries for a sync run.
|
|
133
|
+
* All objects start as 'pending'.
|
|
134
|
+
*/
|
|
135
|
+
createObjectRuns(accountId: string, runStartedAt: Date, objects: string[]): Promise<void>;
|
|
136
|
+
/**
|
|
137
|
+
* Try to start an object sync (respects max_concurrent).
|
|
138
|
+
* Returns true if claimed, false if already running or at concurrency limit.
|
|
56
139
|
*
|
|
57
|
-
*
|
|
140
|
+
* Note: There's a small race window where concurrent calls could result in
|
|
141
|
+
* max_concurrent + 1 objects running. This is acceptable behavior.
|
|
142
|
+
*/
|
|
143
|
+
tryStartObjectSync(accountId: string, runStartedAt: Date, object: string): Promise<boolean>;
|
|
144
|
+
/**
|
|
145
|
+
* Get object run details.
|
|
58
146
|
*/
|
|
59
|
-
|
|
147
|
+
getObjectRun(accountId: string, runStartedAt: Date, object: string): Promise<{
|
|
148
|
+
object: string;
|
|
149
|
+
status: string;
|
|
150
|
+
processedCount: number;
|
|
151
|
+
cursor: string | null;
|
|
152
|
+
} | null>;
|
|
60
153
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* IMPORTANT: Must be called BEFORE app.use(express.json()) to ensure raw body parsing.
|
|
154
|
+
* Update progress for an object sync.
|
|
155
|
+
* Also touches updated_at for stale detection.
|
|
64
156
|
*/
|
|
65
|
-
|
|
157
|
+
incrementObjectProgress(accountId: string, runStartedAt: Date, object: string, count: number): Promise<void>;
|
|
158
|
+
/**
|
|
159
|
+
* Update the cursor for an object sync.
|
|
160
|
+
* Only updates if the new cursor is higher than the existing one (cursors should never decrease).
|
|
161
|
+
* For numeric cursors (timestamps), uses GREATEST to ensure monotonic increase.
|
|
162
|
+
* For non-numeric cursors, just sets the value directly.
|
|
163
|
+
*/
|
|
164
|
+
updateObjectCursor(accountId: string, runStartedAt: Date, object: string, cursor: string | null): Promise<void>;
|
|
165
|
+
/**
|
|
166
|
+
* Get the highest cursor from previous syncs for an object type.
|
|
167
|
+
* This considers completed, error, AND running runs to ensure recovery syncs
|
|
168
|
+
* don't re-process data that was already synced before a crash.
|
|
169
|
+
* A 'running' status with a cursor means the process was killed mid-sync.
|
|
170
|
+
*/
|
|
171
|
+
getLastCompletedCursor(accountId: string, object: string): Promise<string | null>;
|
|
172
|
+
/**
|
|
173
|
+
* Delete all sync runs and object runs for an account.
|
|
174
|
+
* Useful for testing or resetting sync state.
|
|
175
|
+
*/
|
|
176
|
+
deleteSyncRuns(accountId: string): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Mark an object sync as complete.
|
|
179
|
+
*/
|
|
180
|
+
completeObjectSync(accountId: string, runStartedAt: Date, object: string): Promise<void>;
|
|
181
|
+
/**
|
|
182
|
+
* Mark an object sync as failed.
|
|
183
|
+
*/
|
|
184
|
+
failObjectSync(accountId: string, runStartedAt: Date, object: string, errorMessage: string): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Count running objects in a run.
|
|
187
|
+
*/
|
|
188
|
+
countRunningObjects(accountId: string, runStartedAt: Date): Promise<number>;
|
|
189
|
+
/**
|
|
190
|
+
* Get the next pending object to process.
|
|
191
|
+
* Returns null if no pending objects or at concurrency limit.
|
|
192
|
+
*/
|
|
193
|
+
getNextPendingObject(accountId: string, runStartedAt: Date): Promise<string | null>;
|
|
194
|
+
/**
|
|
195
|
+
* Check if all objects in a run are complete (or error).
|
|
196
|
+
*/
|
|
197
|
+
areAllObjectsComplete(accountId: string, runStartedAt: Date): Promise<boolean>;
|
|
66
198
|
}
|
|
67
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Simple logger interface compatible with both pino and console
|
|
202
|
+
*/
|
|
203
|
+
interface Logger {
|
|
204
|
+
info(message?: unknown, ...optionalParams: unknown[]): void;
|
|
205
|
+
warn(message?: unknown, ...optionalParams: unknown[]): void;
|
|
206
|
+
error(message?: unknown, ...optionalParams: unknown[]): void;
|
|
207
|
+
}
|
|
68
208
|
type RevalidateEntity = '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' | 'entitlements';
|
|
69
209
|
type StripeSyncConfig = {
|
|
70
210
|
/** @deprecated Use `poolConfig` with a connection string instead. */
|
|
71
211
|
databaseUrl?: string;
|
|
72
|
-
/** Database schema name. */
|
|
73
|
-
schema?: string;
|
|
74
212
|
/** Stripe secret key used to authenticate requests to the Stripe API. Defaults to empty string */
|
|
75
213
|
stripeSecretKey: string;
|
|
214
|
+
/** Stripe account ID. If not provided, will be retrieved from Stripe API. Used as fallback option. */
|
|
215
|
+
stripeAccountId?: string;
|
|
216
|
+
/** Stripe webhook signing secret for validating webhook signatures. Required if not using managed webhooks. */
|
|
217
|
+
stripeWebhookSecret?: string;
|
|
76
218
|
/** Stripe API version for the webhooks, defaults to 2020-08-27 */
|
|
77
219
|
stripeApiVersion?: string;
|
|
78
220
|
/**
|
|
@@ -91,10 +233,33 @@ type StripeSyncConfig = {
|
|
|
91
233
|
* Default: false
|
|
92
234
|
*/
|
|
93
235
|
revalidateObjectsViaStripeApi?: Array<RevalidateEntity>;
|
|
94
|
-
/**
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Database adapter for database operations.
|
|
238
|
+
* Use PgAdapter for Node.js or a custom adapter for other environments (e.g., Deno).
|
|
239
|
+
*/
|
|
240
|
+
adapter: DatabaseAdapter;
|
|
241
|
+
logger?: Logger;
|
|
242
|
+
/**
|
|
243
|
+
* Maximum number of retry attempts for 429 rate limit errors.
|
|
244
|
+
* Default: 5
|
|
245
|
+
*/
|
|
246
|
+
maxRetries?: number;
|
|
247
|
+
/**
|
|
248
|
+
* Initial delay in milliseconds before first retry attempt.
|
|
249
|
+
* Delay increases exponentially: 1s, 2s, 4s, 8s, 16s, etc.
|
|
250
|
+
* Default: 1000 (1 second)
|
|
251
|
+
*/
|
|
252
|
+
initialRetryDelayMs?: number;
|
|
253
|
+
/**
|
|
254
|
+
* Maximum delay in milliseconds between retry attempts.
|
|
255
|
+
* Default: 60000 (60 seconds)
|
|
256
|
+
*/
|
|
257
|
+
maxRetryDelayMs?: number;
|
|
258
|
+
/**
|
|
259
|
+
* Random jitter in milliseconds added to retry delays to prevent thundering herd.
|
|
260
|
+
* Default: 500
|
|
261
|
+
*/
|
|
262
|
+
retryJitterMs?: number;
|
|
98
263
|
};
|
|
99
264
|
type SyncObject = 'all' | 'customer' | 'customer_with_entitlements' | 'invoice' | 'price' | 'product' | 'subscription' | 'subscription_schedules' | 'setup_intent' | 'payment_method' | 'dispute' | 'charge' | 'payment_intent' | 'plan' | 'tax_id' | 'credit_note' | 'early_fraud_warning' | 'refund' | 'checkout_sessions';
|
|
100
265
|
interface Sync {
|
|
@@ -119,7 +284,7 @@ interface SyncBackfill {
|
|
|
119
284
|
refunds?: Sync;
|
|
120
285
|
checkoutSessions?: Sync;
|
|
121
286
|
}
|
|
122
|
-
interface
|
|
287
|
+
interface SyncParams {
|
|
123
288
|
created?: {
|
|
124
289
|
/**
|
|
125
290
|
* Minimum value to filter by (exclusive)
|
|
@@ -150,83 +315,288 @@ interface SyncFeaturesParams {
|
|
|
150
315
|
object: 'features';
|
|
151
316
|
pagination?: Pick<Stripe.PaginationParams, 'starting_after' | 'ending_before'>;
|
|
152
317
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Result of processing a single page of items via processNext()
|
|
320
|
+
*/
|
|
321
|
+
interface ProcessNextResult {
|
|
322
|
+
/** Number of items processed in this page */
|
|
323
|
+
processed: number;
|
|
324
|
+
/** Whether there are more items to process */
|
|
325
|
+
hasMore: boolean;
|
|
326
|
+
/** The sync run this processing belongs to */
|
|
327
|
+
runStartedAt: Date;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Parameters for processNext() including optional run context
|
|
331
|
+
*/
|
|
332
|
+
interface ProcessNextParams extends SyncParams {
|
|
333
|
+
/** Join an existing sync run instead of creating a new one */
|
|
334
|
+
runStartedAt?: Date;
|
|
335
|
+
/** Who/what triggered this sync (for observability) */
|
|
336
|
+
triggeredBy?: string;
|
|
156
337
|
}
|
|
157
338
|
|
|
158
|
-
|
|
159
|
-
schema: string;
|
|
160
|
-
poolConfig: PoolConfig;
|
|
161
|
-
};
|
|
162
|
-
declare class PostgresClient {
|
|
339
|
+
declare class StripeSync {
|
|
163
340
|
private config;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
341
|
+
stripe: Stripe;
|
|
342
|
+
postgresClient: PostgresClient;
|
|
343
|
+
constructor(config: StripeSyncConfig);
|
|
344
|
+
/**
|
|
345
|
+
* Get the Stripe account ID. Delegates to getCurrentAccount() for the actual lookup.
|
|
346
|
+
*/
|
|
347
|
+
getAccountId(objectAccountId?: string): Promise<string>;
|
|
348
|
+
/**
|
|
349
|
+
* Upsert Stripe account information to the database
|
|
350
|
+
* @param account - Stripe account object
|
|
351
|
+
* @param apiKeyHash - SHA-256 hash of API key to store for fast lookups
|
|
352
|
+
*/
|
|
353
|
+
private upsertAccount;
|
|
354
|
+
/**
|
|
355
|
+
* Get the current account being synced. Uses database lookup by API key hash,
|
|
356
|
+
* with fallback to Stripe API if not found (first-time setup or new API key).
|
|
357
|
+
* @param objectAccountId - Optional account ID from event data (Connect scenarios)
|
|
358
|
+
*/
|
|
359
|
+
getCurrentAccount(objectAccountId?: string): Promise<Stripe.Account | null>;
|
|
175
360
|
/**
|
|
176
|
-
*
|
|
177
|
-
* eg,
|
|
178
|
-
* insert into customers ("id", "name")
|
|
179
|
-
* values (:id, :name)
|
|
180
|
-
* on conflict (id)
|
|
181
|
-
* do update set (
|
|
182
|
-
* "id" = :id,
|
|
183
|
-
* "name" = :name
|
|
184
|
-
* )
|
|
361
|
+
* Get all accounts that have been synced to the database
|
|
185
362
|
*/
|
|
186
|
-
|
|
363
|
+
getAllSyncedAccounts(): Promise<Stripe.Account[]>;
|
|
187
364
|
/**
|
|
188
|
-
*
|
|
365
|
+
* DANGEROUS: Delete an account and all associated data from the database
|
|
366
|
+
* This operation cannot be undone!
|
|
189
367
|
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
368
|
+
* @param accountId - The Stripe account ID to delete
|
|
369
|
+
* @param options - Options for deletion behavior
|
|
370
|
+
* @param options.dryRun - If true, only count records without deleting (default: false)
|
|
371
|
+
* @param options.useTransaction - If true, use transaction for atomic deletion (default: true)
|
|
372
|
+
* @returns Deletion summary with counts and warnings
|
|
373
|
+
*/
|
|
374
|
+
dangerouslyDeleteSyncedAccountData(accountId: string, options?: {
|
|
375
|
+
dryRun?: boolean;
|
|
376
|
+
useTransaction?: boolean;
|
|
377
|
+
}): Promise<{
|
|
378
|
+
deletedAccountId: string;
|
|
379
|
+
deletedRecordCounts: {
|
|
380
|
+
[tableName: string]: number;
|
|
381
|
+
};
|
|
382
|
+
warnings: string[];
|
|
383
|
+
}>;
|
|
384
|
+
processWebhook(payload: Buffer | string, signature: string | undefined): Promise<void>;
|
|
385
|
+
private readonly eventHandlers;
|
|
386
|
+
private readonly resourceRegistry;
|
|
387
|
+
processEvent(event: Stripe.Event): Promise<void>;
|
|
388
|
+
/**
|
|
389
|
+
* Returns an array of all webhook event types that this sync engine can handle.
|
|
390
|
+
* Useful for configuring webhook endpoints with specific event subscriptions.
|
|
391
|
+
*/
|
|
392
|
+
getSupportedEventTypes(): Stripe.WebhookEndpointCreateParams.EnabledEvent[];
|
|
393
|
+
/**
|
|
394
|
+
* Returns an array of all object types that can be synced via processNext/processUntilDone.
|
|
395
|
+
* Ordered for backfill: parents before children (products before prices, customers before subscriptions).
|
|
396
|
+
* Order is determined by the `order` field in resourceRegistry.
|
|
397
|
+
*/
|
|
398
|
+
getSupportedSyncObjects(): Exclude<SyncObject, 'all' | 'customer_with_entitlements'>[];
|
|
399
|
+
private handleChargeEvent;
|
|
400
|
+
private handleCustomerDeletedEvent;
|
|
401
|
+
private handleCustomerEvent;
|
|
402
|
+
private handleCheckoutSessionEvent;
|
|
403
|
+
private handleSubscriptionEvent;
|
|
404
|
+
private handleTaxIdEvent;
|
|
405
|
+
private handleTaxIdDeletedEvent;
|
|
406
|
+
private handleInvoiceEvent;
|
|
407
|
+
private handleProductEvent;
|
|
408
|
+
private handleProductDeletedEvent;
|
|
409
|
+
private handlePriceEvent;
|
|
410
|
+
private handlePriceDeletedEvent;
|
|
411
|
+
private handlePlanEvent;
|
|
412
|
+
private handlePlanDeletedEvent;
|
|
413
|
+
private handleSetupIntentEvent;
|
|
414
|
+
private handleSubscriptionScheduleEvent;
|
|
415
|
+
private handlePaymentMethodEvent;
|
|
416
|
+
private handleDisputeEvent;
|
|
417
|
+
private handlePaymentIntentEvent;
|
|
418
|
+
private handleCreditNoteEvent;
|
|
419
|
+
private handleEarlyFraudWarningEvent;
|
|
420
|
+
private handleRefundEvent;
|
|
421
|
+
private handleReviewEvent;
|
|
422
|
+
private handleEntitlementSummaryEvent;
|
|
423
|
+
private getSyncTimestamp;
|
|
424
|
+
private shouldRefetchEntity;
|
|
425
|
+
private fetchOrUseWebhookData;
|
|
426
|
+
syncSingleEntity(stripeId: string): Promise<Stripe.Product[] | Stripe.Price[] | (Stripe.Customer | Stripe.DeletedCustomer)[] | Stripe.Subscription[] | Stripe.Invoice[] | Stripe.Charge[] | Stripe.SetupIntent[] | Stripe.PaymentMethod[] | Stripe.PaymentIntent[] | Stripe.TaxId[] | Stripe.CreditNote[] | Stripe.Dispute[] | Stripe.Radar.EarlyFraudWarning[] | Stripe.Refund[] | Stripe.Checkout.Session[] | Stripe.Review[] | Stripe.Entitlements.Feature[] | undefined>;
|
|
427
|
+
/**
|
|
428
|
+
* Process one page of items for the specified object type.
|
|
429
|
+
* Returns the number of items processed and whether there are more pages.
|
|
193
430
|
*
|
|
431
|
+
* This method is designed for queue-based consumption where each page
|
|
432
|
+
* is processed as a separate job. Uses the observable sync system for tracking.
|
|
194
433
|
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* )
|
|
199
|
-
* VALUES (
|
|
200
|
-
* :id, :amount, :created, :last_synced_at
|
|
201
|
-
* )
|
|
202
|
-
* ON CONFLICT (id) DO UPDATE SET
|
|
203
|
-
* "amount" = EXCLUDED."amount",
|
|
204
|
-
* "created" = EXCLUDED."created",
|
|
205
|
-
* last_synced_at = :last_synced_at
|
|
206
|
-
* WHERE "charges"."last_synced_at" IS NULL
|
|
207
|
-
* OR "charges"."last_synced_at" < :last_synced_at;
|
|
208
|
-
*/
|
|
209
|
-
private constructUpsertWithTimestampProtectionSql;
|
|
210
|
-
/**
|
|
211
|
-
* For array object field like invoice.custom_fields
|
|
212
|
-
* ex: [{"name":"Project name","value":"Test Project"}]
|
|
434
|
+
* @param object - The Stripe object type to sync (e.g., 'customer', 'product')
|
|
435
|
+
* @param params - Optional parameters for filtering and run context
|
|
436
|
+
* @returns ProcessNextResult with processed count, hasMore flag, and runStartedAt
|
|
213
437
|
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
438
|
+
* @example
|
|
439
|
+
* ```typescript
|
|
440
|
+
* // Queue worker
|
|
441
|
+
* const { hasMore, runStartedAt } = await stripeSync.processNext('customer')
|
|
442
|
+
* if (hasMore) {
|
|
443
|
+
* await queue.send({ object: 'customer', runStartedAt })
|
|
219
444
|
* }
|
|
445
|
+
* ```
|
|
220
446
|
*/
|
|
221
|
-
|
|
447
|
+
processNext(object: Exclude<SyncObject, 'all' | 'customer_with_entitlements'>, params?: ProcessNextParams): Promise<ProcessNextResult>;
|
|
448
|
+
/**
|
|
449
|
+
* Get the database resource name for a SyncObject type
|
|
450
|
+
*/
|
|
451
|
+
private getResourceName;
|
|
452
|
+
/**
|
|
453
|
+
* Fetch one page of items from Stripe and upsert to database.
|
|
454
|
+
* Uses resourceRegistry for DRY list/upsert operations.
|
|
455
|
+
* Uses the observable sync system for tracking progress.
|
|
456
|
+
*/
|
|
457
|
+
private fetchOnePage;
|
|
458
|
+
/**
|
|
459
|
+
* Process all pages for all (or specified) object types until complete.
|
|
460
|
+
*
|
|
461
|
+
* @param params - Optional parameters for filtering and specifying object types
|
|
462
|
+
* @returns SyncBackfill with counts for each synced resource type
|
|
463
|
+
*/
|
|
464
|
+
/**
|
|
465
|
+
* Process all pages for a single object type until complete.
|
|
466
|
+
* Loops processNext() internally until hasMore is false.
|
|
467
|
+
*
|
|
468
|
+
* @param object - The object type to sync
|
|
469
|
+
* @param runStartedAt - The sync run to use (for sharing across objects)
|
|
470
|
+
* @param params - Optional sync parameters
|
|
471
|
+
* @returns Sync result with count of synced items
|
|
472
|
+
*/
|
|
473
|
+
private processObjectUntilDone;
|
|
474
|
+
processUntilDone(params?: SyncParams): Promise<SyncBackfill>;
|
|
475
|
+
/**
|
|
476
|
+
* Internal implementation of processUntilDone with an existing run.
|
|
477
|
+
*/
|
|
478
|
+
private processUntilDoneWithRun;
|
|
479
|
+
/**
|
|
480
|
+
* Sync payment methods with an existing run (special case - iterates customers)
|
|
481
|
+
*/
|
|
482
|
+
private syncPaymentMethodsWithRun;
|
|
483
|
+
syncProducts(syncParams?: SyncParams): Promise<Sync>;
|
|
484
|
+
syncPrices(syncParams?: SyncParams): Promise<Sync>;
|
|
485
|
+
syncPlans(syncParams?: SyncParams): Promise<Sync>;
|
|
486
|
+
syncCustomers(syncParams?: SyncParams): Promise<Sync>;
|
|
487
|
+
syncSubscriptions(syncParams?: SyncParams): Promise<Sync>;
|
|
488
|
+
syncSubscriptionSchedules(syncParams?: SyncParams): Promise<Sync>;
|
|
489
|
+
syncInvoices(syncParams?: SyncParams): Promise<Sync>;
|
|
490
|
+
syncCharges(syncParams?: SyncParams): Promise<Sync>;
|
|
491
|
+
syncSetupIntents(syncParams?: SyncParams): Promise<Sync>;
|
|
492
|
+
syncPaymentIntents(syncParams?: SyncParams): Promise<Sync>;
|
|
493
|
+
syncTaxIds(syncParams?: SyncParams): Promise<Sync>;
|
|
494
|
+
syncPaymentMethods(syncParams?: SyncParams): Promise<Sync>;
|
|
495
|
+
syncDisputes(syncParams?: SyncParams): Promise<Sync>;
|
|
496
|
+
syncEarlyFraudWarnings(syncParams?: SyncParams): Promise<Sync>;
|
|
497
|
+
syncRefunds(syncParams?: SyncParams): Promise<Sync>;
|
|
498
|
+
syncCreditNotes(syncParams?: SyncParams): Promise<Sync>;
|
|
499
|
+
syncFeatures(syncParams?: SyncFeaturesParams): Promise<Sync>;
|
|
500
|
+
syncEntitlements(customerId: string, syncParams?: SyncEntitlementsParams): Promise<Sync>;
|
|
501
|
+
syncCheckoutSessions(syncParams?: SyncParams): Promise<Sync>;
|
|
502
|
+
/**
|
|
503
|
+
* Helper to wrap a sync operation in the observable sync system.
|
|
504
|
+
* Creates/gets a sync run, sets up the object run, gets cursor, and handles completion.
|
|
505
|
+
*
|
|
506
|
+
* @param resourceName - The resource being synced (e.g., 'products', 'customers')
|
|
507
|
+
* @param triggeredBy - What triggered this sync (for observability)
|
|
508
|
+
* @param fn - The sync function to execute, receives cursor and runStartedAt
|
|
509
|
+
* @returns The result of the sync function
|
|
510
|
+
*/
|
|
511
|
+
private withSyncRun;
|
|
512
|
+
private fetchAndUpsert;
|
|
513
|
+
private upsertCharges;
|
|
514
|
+
private backfillCharges;
|
|
515
|
+
private backfillPaymentIntents;
|
|
516
|
+
private upsertCreditNotes;
|
|
517
|
+
upsertCheckoutSessions(checkoutSessions: Stripe.Checkout.Session[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.Checkout.Session[]>;
|
|
518
|
+
upsertEarlyFraudWarning(earlyFraudWarnings: Stripe.Radar.EarlyFraudWarning[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.Radar.EarlyFraudWarning[]>;
|
|
519
|
+
upsertRefunds(refunds: Stripe.Refund[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.Refund[]>;
|
|
520
|
+
upsertReviews(reviews: Stripe.Review[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.Review[]>;
|
|
521
|
+
upsertCustomers(customers: (Stripe.Customer | Stripe.DeletedCustomer)[], accountId: string, syncTimestamp?: string): Promise<(Stripe.Customer | Stripe.DeletedCustomer)[]>;
|
|
522
|
+
backfillCustomers(customerIds: string[], accountId: string): Promise<void>;
|
|
523
|
+
upsertDisputes(disputes: Stripe.Dispute[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.Dispute[]>;
|
|
524
|
+
upsertInvoices(invoices: Stripe.Invoice[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.Invoice[]>;
|
|
525
|
+
backfillInvoices: (invoiceIds: string[], accountId: string) => Promise<void>;
|
|
526
|
+
backfillPrices: (priceIds: string[], accountId: string) => Promise<void>;
|
|
527
|
+
upsertPlans(plans: Stripe.Plan[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.Plan[]>;
|
|
528
|
+
deletePlan(id: string): Promise<boolean>;
|
|
529
|
+
upsertPrices(prices: Stripe.Price[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.Price[]>;
|
|
530
|
+
deletePrice(id: string): Promise<boolean>;
|
|
531
|
+
upsertProducts(products: Stripe.Product[], accountId: string, syncTimestamp?: string): Promise<Stripe.Product[]>;
|
|
532
|
+
deleteProduct(id: string): Promise<boolean>;
|
|
533
|
+
backfillProducts(productIds: string[], accountId: string): Promise<void>;
|
|
534
|
+
upsertPaymentIntents(paymentIntents: Stripe.PaymentIntent[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.PaymentIntent[]>;
|
|
535
|
+
upsertPaymentMethods(paymentMethods: Stripe.PaymentMethod[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.PaymentMethod[]>;
|
|
536
|
+
upsertSetupIntents(setupIntents: Stripe.SetupIntent[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.SetupIntent[]>;
|
|
537
|
+
upsertTaxIds(taxIds: Stripe.TaxId[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.TaxId[]>;
|
|
538
|
+
deleteTaxId(id: string): Promise<boolean>;
|
|
539
|
+
upsertSubscriptionItems(subscriptionItems: Stripe.SubscriptionItem[], accountId: string, syncTimestamp?: string): Promise<void>;
|
|
540
|
+
fillCheckoutSessionsLineItems(checkoutSessionIds: string[], accountId: string, syncTimestamp?: string): Promise<void>;
|
|
541
|
+
upsertCheckoutSessionLineItems(lineItems: Stripe.LineItem[], checkoutSessionId: string, accountId: string, syncTimestamp?: string): Promise<void>;
|
|
542
|
+
markDeletedSubscriptionItems(subscriptionId: string, currentSubItemIds: string[]): Promise<{
|
|
543
|
+
rowCount: number;
|
|
544
|
+
}>;
|
|
545
|
+
upsertSubscriptionSchedules(subscriptionSchedules: Stripe.SubscriptionSchedule[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.SubscriptionSchedule[]>;
|
|
546
|
+
upsertSubscriptions(subscriptions: Stripe.Subscription[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<Stripe.Subscription[]>;
|
|
547
|
+
deleteRemovedActiveEntitlements(customerId: string, currentActiveEntitlementIds: string[]): Promise<{
|
|
548
|
+
rowCount: number;
|
|
549
|
+
}>;
|
|
550
|
+
upsertFeatures(features: Stripe.Entitlements.Feature[], accountId: string, syncTimestamp?: string): Promise<Stripe.Entitlements.Feature[]>;
|
|
551
|
+
backfillFeatures(featureIds: string[], accountId: string): Promise<void>;
|
|
552
|
+
upsertActiveEntitlements(customerId: string, activeEntitlements: Stripe.Entitlements.ActiveEntitlement[], accountId: string, backfillRelatedEntities?: boolean, syncTimestamp?: string): Promise<{
|
|
553
|
+
id: string;
|
|
554
|
+
object: "entitlements.active_entitlement";
|
|
555
|
+
feature: string;
|
|
556
|
+
customer: string;
|
|
557
|
+
livemode: boolean;
|
|
558
|
+
lookup_key: string;
|
|
559
|
+
}[]>;
|
|
560
|
+
findOrCreateManagedWebhook(url: string, params?: Omit<Stripe.WebhookEndpointCreateParams, 'url'>): Promise<Stripe.WebhookEndpoint>;
|
|
561
|
+
getManagedWebhook(id: string): Promise<Stripe.WebhookEndpoint | null>;
|
|
562
|
+
/**
|
|
563
|
+
* Get a managed webhook by URL and account ID.
|
|
564
|
+
* Used for race condition recovery: when createManagedWebhook hits a unique constraint
|
|
565
|
+
* violation (another instance created the webhook), we need to fetch the existing webhook
|
|
566
|
+
* by URL since we only know the URL, not the ID of the webhook that won the race.
|
|
567
|
+
*/
|
|
568
|
+
getManagedWebhookByUrl(url: string): Promise<Stripe.WebhookEndpoint | null>;
|
|
569
|
+
listManagedWebhooks(): Promise<Array<Stripe.WebhookEndpoint>>;
|
|
570
|
+
updateManagedWebhook(id: string, params: Stripe.WebhookEndpointUpdateParams): Promise<Stripe.WebhookEndpoint>;
|
|
571
|
+
deleteManagedWebhook(id: string): Promise<boolean>;
|
|
572
|
+
upsertManagedWebhooks(webhooks: Array<Stripe.WebhookEndpoint>, accountId: string, syncTimestamp?: string): Promise<Array<Stripe.WebhookEndpoint>>;
|
|
573
|
+
backfillSubscriptions(subscriptionIds: string[], accountId: string): Promise<void>;
|
|
574
|
+
backfillSubscriptionSchedules: (subscriptionIds: string[], accountId: string) => Promise<void>;
|
|
575
|
+
/**
|
|
576
|
+
* Stripe only sends the first 10 entries by default, the option will actively fetch all entries.
|
|
577
|
+
*/
|
|
578
|
+
private expandEntity;
|
|
579
|
+
private fetchMissingEntities;
|
|
222
580
|
}
|
|
223
581
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
582
|
+
/**
|
|
583
|
+
* Hashes a Stripe API key using SHA-256
|
|
584
|
+
* Used to store API key hashes in the database for fast account lookups
|
|
585
|
+
* without storing the actual API key or making Stripe API calls
|
|
586
|
+
*
|
|
587
|
+
* @param apiKey - The Stripe API key (e.g., sk_test_... or sk_live_...)
|
|
588
|
+
* @returns SHA-256 hash of the API key as a hex string
|
|
589
|
+
*/
|
|
590
|
+
declare function hashApiKey(apiKey: string): string;
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Run database migrations using the provided adapter.
|
|
594
|
+
*
|
|
595
|
+
* @param adapter - Database adapter (PgAdapter or PostgresJsAdapter)
|
|
596
|
+
* @param logger - Optional logger for migration progress
|
|
597
|
+
*/
|
|
598
|
+
declare function runMigrations(adapter: DatabaseAdapter, logger?: Logger): Promise<void>;
|
|
599
|
+
|
|
600
|
+
declare const VERSION: string;
|
|
231
601
|
|
|
232
|
-
export {
|
|
602
|
+
export { DatabaseAdapter, type Logger, PostgresClient, type ProcessNextParams, type ProcessNextResult, type RevalidateEntity, StripeSync, type StripeSyncConfig, type Sync, type SyncBackfill, type SyncEntitlementsParams, type SyncFeaturesParams, type SyncObject, type SyncParams, VERSION, hashApiKey, runMigrations };
|