stripe-experiment-sync 1.0.8 → 1.0.9-beta.1765909347
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/dist/{chunk-J7BH3XD6.js → chunk-2CYYWBTD.js} +486 -27
- package/dist/{chunk-CKWVW2JK.js → chunk-3W3CERIG.js} +3 -1
- package/dist/{chunk-YH6KRZDQ.js → chunk-DBJCCGXP.js} +28 -10
- package/dist/{chunk-X2OQQCC2.js → chunk-SI3VFP3M.js} +16 -5
- package/dist/cli/index.cjs +534 -45
- package/dist/cli/index.js +9 -8
- package/dist/cli/lib.cjs +529 -41
- package/dist/cli/lib.d.cts +2 -0
- package/dist/cli/lib.d.ts +2 -0
- package/dist/cli/lib.js +4 -4
- package/dist/index.cjs +490 -27
- package/dist/index.d.cts +107 -4
- package/dist/index.d.ts +107 -4
- package/dist/index.js +6 -2
- 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/supabase/index.cjs +18 -5
- package/dist/supabase/index.js +2 -2
- package/package.json +3 -1
package/dist/index.d.cts
CHANGED
|
@@ -6,6 +6,22 @@ type PostgresConfig = {
|
|
|
6
6
|
schema: string;
|
|
7
7
|
poolConfig: PoolConfig;
|
|
8
8
|
};
|
|
9
|
+
type RawJsonUpsertOptions = {
|
|
10
|
+
/**
|
|
11
|
+
* Columns to use as the ON CONFLICT target.
|
|
12
|
+
* Example: ['id'] for standard Stripe objects, or a composite key for Sigma tables.
|
|
13
|
+
*/
|
|
14
|
+
conflictTarget: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Additional typed columns to insert alongside `_raw_data` (for tables that don't have `id` keys).
|
|
17
|
+
* Values are read from `entry[entryKey]` and cast to `pgType` in SQL.
|
|
18
|
+
*/
|
|
19
|
+
extraColumns?: Array<{
|
|
20
|
+
column: string;
|
|
21
|
+
pgType: string;
|
|
22
|
+
entryKey: string;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
9
25
|
declare class PostgresClient {
|
|
10
26
|
private config;
|
|
11
27
|
pool: pg.Pool;
|
|
@@ -17,7 +33,7 @@ declare class PostgresClient {
|
|
|
17
33
|
}>(entries: T[], table: string): Promise<T[]>;
|
|
18
34
|
upsertManyWithTimestampProtection<T extends {
|
|
19
35
|
[Key: string]: any;
|
|
20
|
-
}>(entries: T[], table: string, accountId: string, syncTimestamp?: string): Promise<T[]>;
|
|
36
|
+
}>(entries: T[], table: string, accountId: string, syncTimestamp?: string, upsertOptions?: RawJsonUpsertOptions): Promise<T[]>;
|
|
21
37
|
private cleanseArrayField;
|
|
22
38
|
findMissingEntries(table: string, ids: string[]): Promise<string[]>;
|
|
23
39
|
upsertAccount(accountData: {
|
|
@@ -157,6 +173,10 @@ declare class PostgresClient {
|
|
|
157
173
|
* This considers completed, error, AND running runs to ensure recovery syncs
|
|
158
174
|
* don't re-process data that was already synced before a crash.
|
|
159
175
|
* A 'running' status with a cursor means the process was killed mid-sync.
|
|
176
|
+
*
|
|
177
|
+
* Handles two cursor formats:
|
|
178
|
+
* - Numeric: compared as bigint for correct ordering
|
|
179
|
+
* - Composite cursors: compared as strings with COLLATE "C"
|
|
160
180
|
*/
|
|
161
181
|
getLastCompletedCursor(accountId: string, object: string): Promise<string | null>;
|
|
162
182
|
/**
|
|
@@ -198,6 +218,38 @@ declare class PostgresClient {
|
|
|
198
218
|
close(): Promise<void>;
|
|
199
219
|
}
|
|
200
220
|
|
|
221
|
+
type SigmaCursorColumnType = 'timestamp' | 'string' | 'number';
|
|
222
|
+
type SigmaCursorColumnSpec = {
|
|
223
|
+
column: string;
|
|
224
|
+
type: SigmaCursorColumnType;
|
|
225
|
+
};
|
|
226
|
+
type SigmaCursorSpec = {
|
|
227
|
+
version: 1;
|
|
228
|
+
columns: SigmaCursorColumnSpec[];
|
|
229
|
+
};
|
|
230
|
+
type SigmaIngestionConfig = {
|
|
231
|
+
/**
|
|
232
|
+
* The Sigma table name to query (no quoting, no schema).
|
|
233
|
+
*/
|
|
234
|
+
sigmaTable: string;
|
|
235
|
+
/**
|
|
236
|
+
* Destination Postgres table name (in the `stripe` schema by convention).
|
|
237
|
+
*/
|
|
238
|
+
destinationTable: string;
|
|
239
|
+
/** Limit for each Sigma query page. */
|
|
240
|
+
pageSize: number;
|
|
241
|
+
/**
|
|
242
|
+
* Defines the ordering and cursor semantics. The columns must form a total order (i.e. be unique together) or pagination can be incorrect.
|
|
243
|
+
*/
|
|
244
|
+
cursor: SigmaCursorSpec;
|
|
245
|
+
/** Optional additional WHERE clause appended with AND (must not include leading WHERE). */
|
|
246
|
+
additionalWhere?: string;
|
|
247
|
+
/** Columns to SELECT (defaults to `*`). */
|
|
248
|
+
select?: '*' | string[];
|
|
249
|
+
/** Postgres upsert behavior for this table (conflict target and typed columns). */
|
|
250
|
+
upsert: RawJsonUpsertOptions;
|
|
251
|
+
};
|
|
252
|
+
|
|
201
253
|
/**
|
|
202
254
|
* Simple logger interface compatible with both pino and console
|
|
203
255
|
*/
|
|
@@ -212,6 +264,12 @@ type StripeSyncConfig = {
|
|
|
212
264
|
databaseUrl?: string;
|
|
213
265
|
/** Stripe secret key used to authenticate requests to the Stripe API. Defaults to empty string */
|
|
214
266
|
stripeSecretKey: string;
|
|
267
|
+
/**
|
|
268
|
+
* Enables syncing Stripe Sigma (reporting) tables via the Sigma API.
|
|
269
|
+
*
|
|
270
|
+
* Default: false (opt-in, so workers don't enqueue Sigma jobs unexpectedly).
|
|
271
|
+
*/
|
|
272
|
+
enableSigmaSync?: boolean;
|
|
215
273
|
/** Stripe account ID. If not provided, will be retrieved from Stripe API. Used as fallback option. */
|
|
216
274
|
stripeAccountId?: string;
|
|
217
275
|
/** Stripe webhook signing secret for validating webhook signatures. Required if not using managed webhooks. */
|
|
@@ -236,7 +294,7 @@ type StripeSyncConfig = {
|
|
|
236
294
|
revalidateObjectsViaStripeApi?: Array<RevalidateEntity>;
|
|
237
295
|
/** @deprecated Use `poolConfig` instead. */
|
|
238
296
|
maxPostgresConnections?: number;
|
|
239
|
-
poolConfig
|
|
297
|
+
poolConfig?: PoolConfig;
|
|
240
298
|
logger?: Logger;
|
|
241
299
|
/**
|
|
242
300
|
* Maximum number of retry attempts for 429 rate limit errors.
|
|
@@ -260,7 +318,7 @@ type StripeSyncConfig = {
|
|
|
260
318
|
*/
|
|
261
319
|
retryJitterMs?: number;
|
|
262
320
|
};
|
|
263
|
-
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';
|
|
321
|
+
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' | 'subscription_item_change_events_v2_beta' | 'exchange_rates_from_usd';
|
|
264
322
|
interface Sync {
|
|
265
323
|
synced: number;
|
|
266
324
|
}
|
|
@@ -282,6 +340,8 @@ interface SyncBackfill {
|
|
|
282
340
|
earlyFraudWarnings?: Sync;
|
|
283
341
|
refunds?: Sync;
|
|
284
342
|
checkoutSessions?: Sync;
|
|
343
|
+
subscriptionItemChangeEventsV2Beta?: Sync;
|
|
344
|
+
exchangeRatesFromUsd?: Sync;
|
|
285
345
|
}
|
|
286
346
|
interface SyncParams {
|
|
287
347
|
created?: {
|
|
@@ -334,6 +394,44 @@ interface ProcessNextParams extends SyncParams {
|
|
|
334
394
|
/** Who/what triggered this sync (for observability) */
|
|
335
395
|
triggeredBy?: string;
|
|
336
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* Syncable resource configuration
|
|
399
|
+
*/
|
|
400
|
+
type BaseResourceConfig = {
|
|
401
|
+
/** Backfill order: lower numbers sync first; parents before children for FK dependencies */
|
|
402
|
+
order: number;
|
|
403
|
+
/** Whether this resource supports incremental sync via 'created' filter or cursor */
|
|
404
|
+
supportsCreatedFilter: boolean;
|
|
405
|
+
};
|
|
406
|
+
type StripeListResourceConfig = BaseResourceConfig & {
|
|
407
|
+
/** Function to list items from Stripe API */
|
|
408
|
+
listFn: (params: Stripe.PaginationParams & {
|
|
409
|
+
created?: Stripe.RangeQueryParam;
|
|
410
|
+
}) => Promise<{
|
|
411
|
+
data: unknown[];
|
|
412
|
+
has_more: boolean;
|
|
413
|
+
}>;
|
|
414
|
+
/** Function to upsert items to database */
|
|
415
|
+
upsertFn: (items: unknown[], accountId: string, backfillRelated?: boolean) => Promise<unknown[] | void>;
|
|
416
|
+
/** discriminator */
|
|
417
|
+
sigma?: undefined;
|
|
418
|
+
};
|
|
419
|
+
/**
|
|
420
|
+
* Configuration for Sigma query-backed resources.
|
|
421
|
+
* Uses Stripe Sigma SQL queries with composite cursor pagination.
|
|
422
|
+
*/
|
|
423
|
+
type SigmaResourceConfig = BaseResourceConfig & {
|
|
424
|
+
/** Sigma uses composite cursors, not created filter */
|
|
425
|
+
supportsCreatedFilter: false;
|
|
426
|
+
/** Sigma ingestion configuration (query, cursor spec, upsert options) */
|
|
427
|
+
sigma: SigmaIngestionConfig;
|
|
428
|
+
/** discriminator */
|
|
429
|
+
listFn?: undefined;
|
|
430
|
+
/** discriminator */
|
|
431
|
+
upsertFn?: undefined;
|
|
432
|
+
};
|
|
433
|
+
/** Union of all resource configuration types */
|
|
434
|
+
type ResourceConfig = StripeListResourceConfig | SigmaResourceConfig;
|
|
337
435
|
|
|
338
436
|
/**
|
|
339
437
|
* Identifies a specific sync run.
|
|
@@ -461,6 +559,8 @@ declare class StripeSync {
|
|
|
461
559
|
* Uses the observable sync system for tracking progress.
|
|
462
560
|
*/
|
|
463
561
|
private fetchOnePage;
|
|
562
|
+
private getSigmaFallbackCursorFromDestination;
|
|
563
|
+
private fetchOneSigmaPage;
|
|
464
564
|
/**
|
|
465
565
|
* Process all pages for all (or specified) object types until complete.
|
|
466
566
|
*
|
|
@@ -652,6 +752,9 @@ interface StripeWebhookEvent {
|
|
|
652
752
|
}
|
|
653
753
|
declare function createStripeWebSocketClient(options: StripeWebSocketOptions): Promise<StripeWebSocketClient>;
|
|
654
754
|
|
|
755
|
+
declare function parseCsvObjects(csv: string): Array<Record<string, string | null>>;
|
|
756
|
+
declare function normalizeSigmaTimestampToIso(value: string): string | null;
|
|
757
|
+
|
|
655
758
|
declare const VERSION: string;
|
|
656
759
|
|
|
657
|
-
export { type Logger, PostgresClient, type ProcessNextParams, type ProcessNextResult, type RevalidateEntity, StripeSync, type StripeSyncConfig, type StripeWebSocketClient, type StripeWebSocketOptions, type StripeWebhookEvent, type Sync, type SyncBackfill, type SyncEntitlementsParams, type SyncFeaturesParams, type SyncObject, type SyncParams, VERSION, type WebhookProcessingResult, createStripeWebSocketClient, hashApiKey, runMigrations };
|
|
760
|
+
export { type BaseResourceConfig, type Logger, PostgresClient, type ProcessNextParams, type ProcessNextResult, type ResourceConfig, type RevalidateEntity, type SigmaResourceConfig, type StripeListResourceConfig, StripeSync, type StripeSyncConfig, type StripeWebSocketClient, type StripeWebSocketOptions, type StripeWebhookEvent, type Sync, type SyncBackfill, type SyncEntitlementsParams, type SyncFeaturesParams, type SyncObject, type SyncParams, VERSION, type WebhookProcessingResult, createStripeWebSocketClient, hashApiKey, normalizeSigmaTimestampToIso, parseCsvObjects, runMigrations };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,22 @@ type PostgresConfig = {
|
|
|
6
6
|
schema: string;
|
|
7
7
|
poolConfig: PoolConfig;
|
|
8
8
|
};
|
|
9
|
+
type RawJsonUpsertOptions = {
|
|
10
|
+
/**
|
|
11
|
+
* Columns to use as the ON CONFLICT target.
|
|
12
|
+
* Example: ['id'] for standard Stripe objects, or a composite key for Sigma tables.
|
|
13
|
+
*/
|
|
14
|
+
conflictTarget: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Additional typed columns to insert alongside `_raw_data` (for tables that don't have `id` keys).
|
|
17
|
+
* Values are read from `entry[entryKey]` and cast to `pgType` in SQL.
|
|
18
|
+
*/
|
|
19
|
+
extraColumns?: Array<{
|
|
20
|
+
column: string;
|
|
21
|
+
pgType: string;
|
|
22
|
+
entryKey: string;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
9
25
|
declare class PostgresClient {
|
|
10
26
|
private config;
|
|
11
27
|
pool: pg.Pool;
|
|
@@ -17,7 +33,7 @@ declare class PostgresClient {
|
|
|
17
33
|
}>(entries: T[], table: string): Promise<T[]>;
|
|
18
34
|
upsertManyWithTimestampProtection<T extends {
|
|
19
35
|
[Key: string]: any;
|
|
20
|
-
}>(entries: T[], table: string, accountId: string, syncTimestamp?: string): Promise<T[]>;
|
|
36
|
+
}>(entries: T[], table: string, accountId: string, syncTimestamp?: string, upsertOptions?: RawJsonUpsertOptions): Promise<T[]>;
|
|
21
37
|
private cleanseArrayField;
|
|
22
38
|
findMissingEntries(table: string, ids: string[]): Promise<string[]>;
|
|
23
39
|
upsertAccount(accountData: {
|
|
@@ -157,6 +173,10 @@ declare class PostgresClient {
|
|
|
157
173
|
* This considers completed, error, AND running runs to ensure recovery syncs
|
|
158
174
|
* don't re-process data that was already synced before a crash.
|
|
159
175
|
* A 'running' status with a cursor means the process was killed mid-sync.
|
|
176
|
+
*
|
|
177
|
+
* Handles two cursor formats:
|
|
178
|
+
* - Numeric: compared as bigint for correct ordering
|
|
179
|
+
* - Composite cursors: compared as strings with COLLATE "C"
|
|
160
180
|
*/
|
|
161
181
|
getLastCompletedCursor(accountId: string, object: string): Promise<string | null>;
|
|
162
182
|
/**
|
|
@@ -198,6 +218,38 @@ declare class PostgresClient {
|
|
|
198
218
|
close(): Promise<void>;
|
|
199
219
|
}
|
|
200
220
|
|
|
221
|
+
type SigmaCursorColumnType = 'timestamp' | 'string' | 'number';
|
|
222
|
+
type SigmaCursorColumnSpec = {
|
|
223
|
+
column: string;
|
|
224
|
+
type: SigmaCursorColumnType;
|
|
225
|
+
};
|
|
226
|
+
type SigmaCursorSpec = {
|
|
227
|
+
version: 1;
|
|
228
|
+
columns: SigmaCursorColumnSpec[];
|
|
229
|
+
};
|
|
230
|
+
type SigmaIngestionConfig = {
|
|
231
|
+
/**
|
|
232
|
+
* The Sigma table name to query (no quoting, no schema).
|
|
233
|
+
*/
|
|
234
|
+
sigmaTable: string;
|
|
235
|
+
/**
|
|
236
|
+
* Destination Postgres table name (in the `stripe` schema by convention).
|
|
237
|
+
*/
|
|
238
|
+
destinationTable: string;
|
|
239
|
+
/** Limit for each Sigma query page. */
|
|
240
|
+
pageSize: number;
|
|
241
|
+
/**
|
|
242
|
+
* Defines the ordering and cursor semantics. The columns must form a total order (i.e. be unique together) or pagination can be incorrect.
|
|
243
|
+
*/
|
|
244
|
+
cursor: SigmaCursorSpec;
|
|
245
|
+
/** Optional additional WHERE clause appended with AND (must not include leading WHERE). */
|
|
246
|
+
additionalWhere?: string;
|
|
247
|
+
/** Columns to SELECT (defaults to `*`). */
|
|
248
|
+
select?: '*' | string[];
|
|
249
|
+
/** Postgres upsert behavior for this table (conflict target and typed columns). */
|
|
250
|
+
upsert: RawJsonUpsertOptions;
|
|
251
|
+
};
|
|
252
|
+
|
|
201
253
|
/**
|
|
202
254
|
* Simple logger interface compatible with both pino and console
|
|
203
255
|
*/
|
|
@@ -212,6 +264,12 @@ type StripeSyncConfig = {
|
|
|
212
264
|
databaseUrl?: string;
|
|
213
265
|
/** Stripe secret key used to authenticate requests to the Stripe API. Defaults to empty string */
|
|
214
266
|
stripeSecretKey: string;
|
|
267
|
+
/**
|
|
268
|
+
* Enables syncing Stripe Sigma (reporting) tables via the Sigma API.
|
|
269
|
+
*
|
|
270
|
+
* Default: false (opt-in, so workers don't enqueue Sigma jobs unexpectedly).
|
|
271
|
+
*/
|
|
272
|
+
enableSigmaSync?: boolean;
|
|
215
273
|
/** Stripe account ID. If not provided, will be retrieved from Stripe API. Used as fallback option. */
|
|
216
274
|
stripeAccountId?: string;
|
|
217
275
|
/** Stripe webhook signing secret for validating webhook signatures. Required if not using managed webhooks. */
|
|
@@ -236,7 +294,7 @@ type StripeSyncConfig = {
|
|
|
236
294
|
revalidateObjectsViaStripeApi?: Array<RevalidateEntity>;
|
|
237
295
|
/** @deprecated Use `poolConfig` instead. */
|
|
238
296
|
maxPostgresConnections?: number;
|
|
239
|
-
poolConfig
|
|
297
|
+
poolConfig?: PoolConfig;
|
|
240
298
|
logger?: Logger;
|
|
241
299
|
/**
|
|
242
300
|
* Maximum number of retry attempts for 429 rate limit errors.
|
|
@@ -260,7 +318,7 @@ type StripeSyncConfig = {
|
|
|
260
318
|
*/
|
|
261
319
|
retryJitterMs?: number;
|
|
262
320
|
};
|
|
263
|
-
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';
|
|
321
|
+
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' | 'subscription_item_change_events_v2_beta' | 'exchange_rates_from_usd';
|
|
264
322
|
interface Sync {
|
|
265
323
|
synced: number;
|
|
266
324
|
}
|
|
@@ -282,6 +340,8 @@ interface SyncBackfill {
|
|
|
282
340
|
earlyFraudWarnings?: Sync;
|
|
283
341
|
refunds?: Sync;
|
|
284
342
|
checkoutSessions?: Sync;
|
|
343
|
+
subscriptionItemChangeEventsV2Beta?: Sync;
|
|
344
|
+
exchangeRatesFromUsd?: Sync;
|
|
285
345
|
}
|
|
286
346
|
interface SyncParams {
|
|
287
347
|
created?: {
|
|
@@ -334,6 +394,44 @@ interface ProcessNextParams extends SyncParams {
|
|
|
334
394
|
/** Who/what triggered this sync (for observability) */
|
|
335
395
|
triggeredBy?: string;
|
|
336
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* Syncable resource configuration
|
|
399
|
+
*/
|
|
400
|
+
type BaseResourceConfig = {
|
|
401
|
+
/** Backfill order: lower numbers sync first; parents before children for FK dependencies */
|
|
402
|
+
order: number;
|
|
403
|
+
/** Whether this resource supports incremental sync via 'created' filter or cursor */
|
|
404
|
+
supportsCreatedFilter: boolean;
|
|
405
|
+
};
|
|
406
|
+
type StripeListResourceConfig = BaseResourceConfig & {
|
|
407
|
+
/** Function to list items from Stripe API */
|
|
408
|
+
listFn: (params: Stripe.PaginationParams & {
|
|
409
|
+
created?: Stripe.RangeQueryParam;
|
|
410
|
+
}) => Promise<{
|
|
411
|
+
data: unknown[];
|
|
412
|
+
has_more: boolean;
|
|
413
|
+
}>;
|
|
414
|
+
/** Function to upsert items to database */
|
|
415
|
+
upsertFn: (items: unknown[], accountId: string, backfillRelated?: boolean) => Promise<unknown[] | void>;
|
|
416
|
+
/** discriminator */
|
|
417
|
+
sigma?: undefined;
|
|
418
|
+
};
|
|
419
|
+
/**
|
|
420
|
+
* Configuration for Sigma query-backed resources.
|
|
421
|
+
* Uses Stripe Sigma SQL queries with composite cursor pagination.
|
|
422
|
+
*/
|
|
423
|
+
type SigmaResourceConfig = BaseResourceConfig & {
|
|
424
|
+
/** Sigma uses composite cursors, not created filter */
|
|
425
|
+
supportsCreatedFilter: false;
|
|
426
|
+
/** Sigma ingestion configuration (query, cursor spec, upsert options) */
|
|
427
|
+
sigma: SigmaIngestionConfig;
|
|
428
|
+
/** discriminator */
|
|
429
|
+
listFn?: undefined;
|
|
430
|
+
/** discriminator */
|
|
431
|
+
upsertFn?: undefined;
|
|
432
|
+
};
|
|
433
|
+
/** Union of all resource configuration types */
|
|
434
|
+
type ResourceConfig = StripeListResourceConfig | SigmaResourceConfig;
|
|
337
435
|
|
|
338
436
|
/**
|
|
339
437
|
* Identifies a specific sync run.
|
|
@@ -461,6 +559,8 @@ declare class StripeSync {
|
|
|
461
559
|
* Uses the observable sync system for tracking progress.
|
|
462
560
|
*/
|
|
463
561
|
private fetchOnePage;
|
|
562
|
+
private getSigmaFallbackCursorFromDestination;
|
|
563
|
+
private fetchOneSigmaPage;
|
|
464
564
|
/**
|
|
465
565
|
* Process all pages for all (or specified) object types until complete.
|
|
466
566
|
*
|
|
@@ -652,6 +752,9 @@ interface StripeWebhookEvent {
|
|
|
652
752
|
}
|
|
653
753
|
declare function createStripeWebSocketClient(options: StripeWebSocketOptions): Promise<StripeWebSocketClient>;
|
|
654
754
|
|
|
755
|
+
declare function parseCsvObjects(csv: string): Array<Record<string, string | null>>;
|
|
756
|
+
declare function normalizeSigmaTimestampToIso(value: string): string | null;
|
|
757
|
+
|
|
655
758
|
declare const VERSION: string;
|
|
656
759
|
|
|
657
|
-
export { type Logger, PostgresClient, type ProcessNextParams, type ProcessNextResult, type RevalidateEntity, StripeSync, type StripeSyncConfig, type StripeWebSocketClient, type StripeWebSocketOptions, type StripeWebhookEvent, type Sync, type SyncBackfill, type SyncEntitlementsParams, type SyncFeaturesParams, type SyncObject, type SyncParams, VERSION, type WebhookProcessingResult, createStripeWebSocketClient, hashApiKey, runMigrations };
|
|
760
|
+
export { type BaseResourceConfig, type Logger, PostgresClient, type ProcessNextParams, type ProcessNextResult, type ResourceConfig, type RevalidateEntity, type SigmaResourceConfig, type StripeListResourceConfig, StripeSync, type StripeSyncConfig, type StripeWebSocketClient, type StripeWebSocketOptions, type StripeWebhookEvent, type Sync, type SyncBackfill, type SyncEntitlementsParams, type SyncFeaturesParams, type SyncObject, type SyncParams, VERSION, type WebhookProcessingResult, createStripeWebSocketClient, hashApiKey, normalizeSigmaTimestampToIso, parseCsvObjects, runMigrations };
|
package/dist/index.js
CHANGED
|
@@ -4,14 +4,18 @@ import {
|
|
|
4
4
|
VERSION,
|
|
5
5
|
createStripeWebSocketClient,
|
|
6
6
|
hashApiKey,
|
|
7
|
+
normalizeSigmaTimestampToIso,
|
|
8
|
+
parseCsvObjects,
|
|
7
9
|
runMigrations
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-2CYYWBTD.js";
|
|
11
|
+
import "./chunk-3W3CERIG.js";
|
|
10
12
|
export {
|
|
11
13
|
PostgresClient,
|
|
12
14
|
StripeSync,
|
|
13
15
|
VERSION,
|
|
14
16
|
createStripeWebSocketClient,
|
|
15
17
|
hashApiKey,
|
|
18
|
+
normalizeSigmaTimestampToIso,
|
|
19
|
+
parseCsvObjects,
|
|
16
20
|
runMigrations
|
|
17
21
|
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
-- event_timestamp and event_type are not generated columns because they are not immutable.
|
|
2
|
+
-- Postgres requires generated expressions to be immutable.
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS "stripe"."subscription_item_change_events_v2_beta" (
|
|
5
|
+
"_raw_data" jsonb NOT NULL,
|
|
6
|
+
"_last_synced_at" timestamptz,
|
|
7
|
+
"_updated_at" timestamptz DEFAULT now(),
|
|
8
|
+
"_account_id" text NOT NULL,
|
|
9
|
+
|
|
10
|
+
"event_timestamp" timestamptz NOT NULL,
|
|
11
|
+
"event_type" text NOT NULL,
|
|
12
|
+
"subscription_item_id" text NOT NULL,
|
|
13
|
+
|
|
14
|
+
PRIMARY KEY ("_account_id", "event_timestamp", "event_type", "subscription_item_id")
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
-- Foreign key to stripe.accounts
|
|
18
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
19
|
+
DROP CONSTRAINT IF EXISTS fk_subscription_item_change_events_v2_beta_account;
|
|
20
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
21
|
+
ADD CONSTRAINT fk_subscription_item_change_events_v2_beta_account
|
|
22
|
+
FOREIGN KEY ("_account_id") REFERENCES "stripe"."accounts" (id);
|
|
23
|
+
|
|
24
|
+
-- Maintain _updated_at on UPDATE
|
|
25
|
+
DROP TRIGGER IF EXISTS handle_updated_at ON "stripe"."subscription_item_change_events_v2_beta";
|
|
26
|
+
CREATE TRIGGER handle_updated_at
|
|
27
|
+
BEFORE UPDATE ON "stripe"."subscription_item_change_events_v2_beta"
|
|
28
|
+
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
|
29
|
+
|
|
30
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
31
|
+
ADD COLUMN IF NOT EXISTS "currency" text
|
|
32
|
+
GENERATED ALWAYS AS ((NULLIF(_raw_data->>'currency', ''))::text) STORED;
|
|
33
|
+
|
|
34
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
35
|
+
ADD COLUMN IF NOT EXISTS "mrr_change" bigint
|
|
36
|
+
GENERATED ALWAYS AS ((NULLIF(_raw_data->>'mrr_change', ''))::bigint) STORED;
|
|
37
|
+
|
|
38
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
39
|
+
ADD COLUMN IF NOT EXISTS "quantity_change" bigint
|
|
40
|
+
GENERATED ALWAYS AS ((NULLIF(_raw_data->>'quantity_change', ''))::bigint) STORED;
|
|
41
|
+
|
|
42
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
43
|
+
ADD COLUMN IF NOT EXISTS "subscription_id" text
|
|
44
|
+
GENERATED ALWAYS AS ((NULLIF(_raw_data->>'subscription_id', ''))::text) STORED;
|
|
45
|
+
|
|
46
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
47
|
+
ADD COLUMN IF NOT EXISTS "customer_id" text
|
|
48
|
+
GENERATED ALWAYS AS ((NULLIF(_raw_data->>'customer_id', ''))::text) STORED;
|
|
49
|
+
|
|
50
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
51
|
+
ADD COLUMN IF NOT EXISTS "price_id" text
|
|
52
|
+
GENERATED ALWAYS AS ((NULLIF(_raw_data->>'price_id', ''))::text) STORED;
|
|
53
|
+
|
|
54
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
55
|
+
ADD COLUMN IF NOT EXISTS "product_id" text
|
|
56
|
+
GENERATED ALWAYS AS ((NULLIF(_raw_data->>'product_id', ''))::text) STORED;
|
|
57
|
+
|
|
58
|
+
-- Keep as text to avoid non-immutable timestamp casts in a generated column
|
|
59
|
+
ALTER TABLE "stripe"."subscription_item_change_events_v2_beta"
|
|
60
|
+
ADD COLUMN IF NOT EXISTS "local_event_timestamp" text
|
|
61
|
+
GENERATED ALWAYS AS ((NULLIF(_raw_data->>'local_event_timestamp', ''))::text) STORED;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
|
|
2
|
+
CREATE TABLE IF NOT EXISTS "stripe"."exchange_rates_from_usd" (
|
|
3
|
+
"_raw_data" jsonb NOT NULL,
|
|
4
|
+
"_last_synced_at" timestamptz,
|
|
5
|
+
"_updated_at" timestamptz DEFAULT now(),
|
|
6
|
+
"_account_id" text NOT NULL,
|
|
7
|
+
|
|
8
|
+
"date" date NOT NULL,
|
|
9
|
+
"sell_currency" text NOT NULL,
|
|
10
|
+
|
|
11
|
+
PRIMARY KEY ("_account_id", "date", "sell_currency")
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
-- Foreign key to stripe.accounts
|
|
15
|
+
ALTER TABLE "stripe"."exchange_rates_from_usd"
|
|
16
|
+
DROP CONSTRAINT IF EXISTS fk_exchange_rates_from_usd_account;
|
|
17
|
+
ALTER TABLE "stripe"."exchange_rates_from_usd"
|
|
18
|
+
ADD CONSTRAINT fk_exchange_rates_from_usd_account
|
|
19
|
+
FOREIGN KEY ("_account_id") REFERENCES "stripe"."accounts" (id);
|
|
20
|
+
|
|
21
|
+
-- Maintain _updated_at on UPDATE
|
|
22
|
+
DROP TRIGGER IF EXISTS handle_updated_at ON "stripe"."exchange_rates_from_usd";
|
|
23
|
+
CREATE TRIGGER handle_updated_at
|
|
24
|
+
BEFORE UPDATE ON "stripe"."exchange_rates_from_usd"
|
|
25
|
+
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
|
26
|
+
|
|
27
|
+
ALTER TABLE "stripe"."exchange_rates_from_usd"
|
|
28
|
+
ADD COLUMN IF NOT EXISTS "buy_currency_exchange_rates" text
|
|
29
|
+
GENERATED ALWAYS AS ((NULLIF(_raw_data->>'buy_currency_exchange_rates', ''))::text) STORED;
|
|
30
|
+
|
|
31
|
+
-- Index on date for efficient range queries
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_exchange_rates_from_usd_date
|
|
33
|
+
ON "stripe"."exchange_rates_from_usd" ("date");
|
|
34
|
+
|
|
35
|
+
-- Index on sell_currency for filtering by currency
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_exchange_rates_from_usd_sell_currency
|
|
37
|
+
ON "stripe"."exchange_rates_from_usd" ("sell_currency");
|
|
38
|
+
|
package/dist/supabase/index.cjs
CHANGED
|
@@ -47,14 +47,14 @@ module.exports = __toCommonJS(supabase_exports);
|
|
|
47
47
|
// src/supabase/supabase.ts
|
|
48
48
|
var import_supabase_management_js = require("supabase-management-js");
|
|
49
49
|
|
|
50
|
-
// raw-ts:/
|
|
50
|
+
// raw-ts:/home/runner/work/sync-engine/sync-engine/packages/sync-engine/src/supabase/edge-functions/stripe-setup.ts
|
|
51
51
|
var stripe_setup_default = "import { StripeSync, runMigrations } from 'npm:stripe-experiment-sync'\n\nDeno.serve(async (req) => {\n if (req.method !== 'POST') {\n return new Response('Method not allowed', { status: 405 })\n }\n\n const authHeader = req.headers.get('Authorization')\n if (!authHeader?.startsWith('Bearer ')) {\n return new Response('Unauthorized', { status: 401 })\n }\n\n let stripeSync = null\n try {\n // Get and validate database URL\n const rawDbUrl = Deno.env.get('SUPABASE_DB_URL')\n if (!rawDbUrl) {\n throw new Error('SUPABASE_DB_URL environment variable is not set')\n }\n // Remove sslmode from connection string (not supported by pg in Deno)\n const dbUrl = rawDbUrl.replace(/[?&]sslmode=[^&]*/g, '').replace(/[?&]$/, '')\n\n await runMigrations({ databaseUrl: dbUrl })\n\n stripeSync = new StripeSync({\n poolConfig: { connectionString: dbUrl, max: 2 }, // Need 2 for advisory lock + queries\n stripeSecretKey: Deno.env.get('STRIPE_SECRET_KEY'),\n })\n\n // Release any stale advisory locks from previous timeouts\n await stripeSync.postgresClient.query('SELECT pg_advisory_unlock_all()')\n\n // Construct webhook URL from SUPABASE_URL (available in all Edge Functions)\n const supabaseUrl = Deno.env.get('SUPABASE_URL')\n if (!supabaseUrl) {\n throw new Error('SUPABASE_URL environment variable is not set')\n }\n const webhookUrl = supabaseUrl + '/functions/v1/stripe-webhook'\n\n const webhook = await stripeSync.findOrCreateManagedWebhook(webhookUrl)\n\n await stripeSync.postgresClient.pool.end()\n\n return new Response(\n JSON.stringify({\n success: true,\n message: 'Setup complete',\n webhookId: webhook.id,\n }),\n {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n }\n )\n } catch (error) {\n console.error('Setup error:', error)\n // Cleanup on error\n if (stripeSync) {\n try {\n await stripeSync.postgresClient.query('SELECT pg_advisory_unlock_all()')\n await stripeSync.postgresClient.pool.end()\n } catch (cleanupErr) {\n console.warn('Cleanup failed:', cleanupErr)\n }\n }\n return new Response(JSON.stringify({ success: false, error: error.message }), {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n})\n";
|
|
52
52
|
|
|
53
|
-
// raw-ts:/
|
|
53
|
+
// raw-ts:/home/runner/work/sync-engine/sync-engine/packages/sync-engine/src/supabase/edge-functions/stripe-webhook.ts
|
|
54
54
|
var stripe_webhook_default = "import { StripeSync } from 'npm:stripe-experiment-sync'\n\nDeno.serve(async (req) => {\n if (req.method !== 'POST') {\n return new Response('Method not allowed', { status: 405 })\n }\n\n const sig = req.headers.get('stripe-signature')\n if (!sig) {\n return new Response('Missing stripe-signature header', { status: 400 })\n }\n\n const rawDbUrl = Deno.env.get('SUPABASE_DB_URL')\n if (!rawDbUrl) {\n return new Response(JSON.stringify({ error: 'SUPABASE_DB_URL not set' }), { status: 500 })\n }\n const dbUrl = rawDbUrl.replace(/[?&]sslmode=[^&]*/g, '').replace(/[?&]$/, '')\n\n const stripeSync = new StripeSync({\n poolConfig: { connectionString: dbUrl, max: 1 },\n stripeSecretKey: Deno.env.get('STRIPE_SECRET_KEY')!,\n })\n\n try {\n const rawBody = new Uint8Array(await req.arrayBuffer())\n await stripeSync.processWebhook(rawBody, sig)\n return new Response(JSON.stringify({ received: true }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n } catch (error) {\n console.error('Webhook processing error:', error)\n const isSignatureError =\n error.message?.includes('signature') || error.type === 'StripeSignatureVerificationError'\n const status = isSignatureError ? 400 : 500\n return new Response(JSON.stringify({ error: error.message }), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n } finally {\n await stripeSync.postgresClient.pool.end()\n }\n})\n";
|
|
55
55
|
|
|
56
|
-
// raw-ts:/
|
|
57
|
-
var stripe_worker_default = "/**\n * Stripe Sync Worker\n *\n * Triggered by pg_cron every 10 seconds. Uses pgmq for durable work queue.\n *\n * Flow:\n * 1. Read batch of messages from pgmq (qty=10, vt=60s)\n * 2. If queue empty: enqueue all objects (continuous sync)\n * 3. Process messages in parallel (Promise.all):\n * - processNext(object)\n * - Delete message on success\n * - Re-enqueue if hasMore\n * 4. Return results summary\n *\n * Concurrency:\n * - Multiple workers can run concurrently via overlapping pg_cron triggers.\n * - Each worker processes its batch of messages in parallel (Promise.all).\n * - pgmq visibility timeout prevents duplicate message reads across workers.\n * - processNext() is idempotent (uses internal cursor tracking), so duplicate\n * processing on timeout/crash is safe.\n */\n\nimport { StripeSync } from 'npm:stripe-experiment-sync'\nimport postgres from 'npm:postgres'\n\nconst QUEUE_NAME = 'stripe_sync_work'\nconst VISIBILITY_TIMEOUT = 60 // seconds\nconst BATCH_SIZE = 10\n\nDeno.serve(async (req) => {\n const authHeader = req.headers.get('Authorization')\n if (!authHeader?.startsWith('Bearer ')) {\n return new Response('Unauthorized', { status: 401 })\n }\n\n const rawDbUrl = Deno.env.get('SUPABASE_DB_URL')\n if (!rawDbUrl) {\n return new Response(JSON.stringify({ error: 'SUPABASE_DB_URL not set' }), { status: 500 })\n }\n const dbUrl = rawDbUrl.replace(/[?&]sslmode=[^&]*/g, '').replace(/[?&]$/, '')\n\n let sql\n let stripeSync\n\n try {\n sql = postgres(dbUrl, { max: 1, prepare: false })\n } catch (error) {\n return new Response(\n JSON.stringify({\n error: 'Failed to create postgres connection',\n details: error.message,\n stack: error.stack,\n }),\n { status: 500, headers: { 'Content-Type': 'application/json' } }\n )\n }\n\n try {\n stripeSync = new StripeSync({\n poolConfig: { connectionString: dbUrl, max: 1 },\n stripeSecretKey: Deno.env.get('STRIPE_SECRET_KEY')!,\n })\n } catch (error) {\n await sql.end()\n return new Response(\n JSON.stringify({\n error: 'Failed to create StripeSync',\n details: error.message,\n stack: error.stack,\n }),\n { status: 500, headers: { 'Content-Type': 'application/json' } }\n )\n }\n\n try {\n // Read batch of messages from queue\n const messages = await sql`\n SELECT * FROM pgmq.read(${QUEUE_NAME}::text, ${VISIBILITY_TIMEOUT}::int, ${BATCH_SIZE}::int)\n `\n\n // If queue empty, enqueue all objects for continuous sync\n if (messages.length === 0) {\n // Create sync run to make enqueued work visible (status='pending')\n const { objects } = await stripeSync.joinOrCreateSyncRun('worker')\n const msgs = objects.map((object) => JSON.stringify({ object }))\n\n await sql`\n SELECT pgmq.send_batch(\n ${QUEUE_NAME}::text,\n ${sql.array(msgs)}::jsonb[]\n )\n `\n\n return new Response(JSON.stringify({ enqueued: objects.length, objects }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n\n // Process messages in parallel\n const results = await Promise.all(\n messages.map(async (msg) => {\n const { object } = msg.message as { object: string }\n\n try {\n const result = await stripeSync.processNext(object)\n\n // Delete message on success (cast to bigint to disambiguate overloaded function)\n await sql`SELECT pgmq.delete(${QUEUE_NAME}::text, ${msg.msg_id}::bigint)`\n\n // Re-enqueue if more pages\n if (result.hasMore) {\n await sql`SELECT pgmq.send(${QUEUE_NAME}::text, ${sql.json({ object })}::jsonb)`\n }\n\n return { object, ...result }\n } catch (error) {\n // Log error but continue to next message\n // Message will become visible again after visibility timeout\n console.error(`Error processing ${object}:`, error)\n return {\n object,\n processed: 0,\n hasMore: false,\n error: error.message,\n stack: error.stack,\n }\n }\n })\n )\n\n return new Response(JSON.stringify({ results }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n } catch (error) {\n console.error('Worker error:', error)\n return new Response(JSON.stringify({ error: error.message, stack: error.stack }), {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n })\n } finally {\n if (sql) await sql.end()\n if (stripeSync) await stripeSync.postgresClient.pool.end()\n }\n})\n";
|
|
56
|
+
// raw-ts:/home/runner/work/sync-engine/sync-engine/packages/sync-engine/src/supabase/edge-functions/stripe-worker.ts
|
|
57
|
+
var stripe_worker_default = "/**\n * Stripe Sync Worker\n *\n * Triggered by pg_cron every 10 seconds. Uses pgmq for durable work queue.\n *\n * Flow:\n * 1. Read batch of messages from pgmq (qty=10, vt=60s)\n * 2. If queue empty: enqueue all objects (continuous sync)\n * 3. Process messages in parallel (Promise.all):\n * - processNext(object)\n * - Delete message on success\n * - Re-enqueue if hasMore\n * 4. Return results summary\n *\n * Concurrency:\n * - Multiple workers can run concurrently via overlapping pg_cron triggers.\n * - Each worker processes its batch of messages in parallel (Promise.all).\n * - pgmq visibility timeout prevents duplicate message reads across workers.\n * - processNext() is idempotent (uses internal cursor tracking), so duplicate\n * processing on timeout/crash is safe.\n */\n\nimport { StripeSync } from 'npm:stripe-experiment-sync'\nimport postgres from 'npm:postgres'\n\nconst QUEUE_NAME = 'stripe_sync_work'\nconst VISIBILITY_TIMEOUT = 60 // seconds\nconst BATCH_SIZE = 10\n\nDeno.serve(async (req) => {\n const authHeader = req.headers.get('Authorization')\n if (!authHeader?.startsWith('Bearer ')) {\n return new Response('Unauthorized', { status: 401 })\n }\n\n const rawDbUrl = Deno.env.get('SUPABASE_DB_URL')\n if (!rawDbUrl) {\n return new Response(JSON.stringify({ error: 'SUPABASE_DB_URL not set' }), { status: 500 })\n }\n const dbUrl = rawDbUrl.replace(/[?&]sslmode=[^&]*/g, '').replace(/[?&]$/, '')\n\n let sql\n let stripeSync\n\n try {\n sql = postgres(dbUrl, { max: 1, prepare: false })\n } catch (error) {\n return new Response(\n JSON.stringify({\n error: 'Failed to create postgres connection',\n details: error.message,\n stack: error.stack,\n }),\n { status: 500, headers: { 'Content-Type': 'application/json' } }\n )\n }\n\n try {\n stripeSync = new StripeSync({\n poolConfig: { connectionString: dbUrl, max: 1 },\n stripeSecretKey: Deno.env.get('STRIPE_SECRET_KEY')!,\n enableSigmaSync: (Deno.env.get('ENABLE_SIGMA_SYNC') ?? 'false') === 'true',\n })\n } catch (error) {\n await sql.end()\n return new Response(\n JSON.stringify({\n error: 'Failed to create StripeSync',\n details: error.message,\n stack: error.stack,\n }),\n { status: 500, headers: { 'Content-Type': 'application/json' } }\n )\n }\n\n try {\n // Read batch of messages from queue\n const messages = await sql`\n SELECT * FROM pgmq.read(${QUEUE_NAME}::text, ${VISIBILITY_TIMEOUT}::int, ${BATCH_SIZE}::int)\n `\n\n // If queue empty, enqueue all objects for continuous sync\n if (messages.length === 0) {\n // Create sync run to make enqueued work visible (status='pending')\n const { objects } = await stripeSync.joinOrCreateSyncRun('worker')\n const msgs = objects.map((object) => JSON.stringify({ object }))\n\n await sql`\n SELECT pgmq.send_batch(\n ${QUEUE_NAME}::text,\n ${sql.array(msgs)}::jsonb[]\n )\n `\n\n return new Response(JSON.stringify({ enqueued: objects.length, objects }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n\n // Process messages in parallel\n const results = await Promise.all(\n messages.map(async (msg) => {\n const { object } = msg.message as { object: string }\n\n try {\n const result = await stripeSync.processNext(object)\n\n // Delete message on success (cast to bigint to disambiguate overloaded function)\n await sql`SELECT pgmq.delete(${QUEUE_NAME}::text, ${msg.msg_id}::bigint)`\n\n // Re-enqueue if more pages\n if (result.hasMore) {\n await sql`SELECT pgmq.send(${QUEUE_NAME}::text, ${sql.json({ object })}::jsonb)`\n }\n\n return { object, ...result }\n } catch (error) {\n // Log error but continue to next message\n // Message will become visible again after visibility timeout\n console.error(`Error processing ${object}:`, error)\n return {\n object,\n processed: 0,\n hasMore: false,\n error: error.message,\n stack: error.stack,\n }\n }\n })\n )\n\n return new Response(JSON.stringify({ results }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n } catch (error) {\n console.error('Worker error:', error)\n return new Response(JSON.stringify({ error: error.message, stack: error.stack }), {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n })\n } finally {\n if (sql) await sql.end()\n if (stripeSync) await stripeSync.postgresClient.pool.end()\n }\n})\n";
|
|
58
58
|
|
|
59
59
|
// src/supabase/edge-function-code.ts
|
|
60
60
|
var setupFunctionCode = stripe_setup_default;
|
|
@@ -64,7 +64,7 @@ var workerFunctionCode = stripe_worker_default;
|
|
|
64
64
|
// package.json
|
|
65
65
|
var package_default = {
|
|
66
66
|
name: "stripe-experiment-sync",
|
|
67
|
-
version: "1.0.
|
|
67
|
+
version: "1.0.9-beta.1765909347",
|
|
68
68
|
private: false,
|
|
69
69
|
description: "Stripe Sync Engine to sync Stripe data to Postgres",
|
|
70
70
|
type: "module",
|
|
@@ -104,6 +104,7 @@ var package_default = {
|
|
|
104
104
|
dotenv: "^16.4.7",
|
|
105
105
|
express: "^4.18.2",
|
|
106
106
|
inquirer: "^12.3.0",
|
|
107
|
+
papaparse: "5.4.1",
|
|
107
108
|
pg: "^8.16.3",
|
|
108
109
|
"pg-node-migrations": "0.0.8",
|
|
109
110
|
stripe: "^17.7.0",
|
|
@@ -115,6 +116,7 @@ var package_default = {
|
|
|
115
116
|
"@types/express": "^4.17.21",
|
|
116
117
|
"@types/inquirer": "^9.0.7",
|
|
117
118
|
"@types/node": "^24.10.1",
|
|
119
|
+
"@types/papaparse": "5.3.16",
|
|
118
120
|
"@types/pg": "^8.15.5",
|
|
119
121
|
"@types/ws": "^8.5.13",
|
|
120
122
|
"@types/yesql": "^4.1.4",
|
|
@@ -443,6 +445,17 @@ var SupabaseSetupClient = class {
|
|
|
443
445
|
} catch (err) {
|
|
444
446
|
console.warn("Could not delete vault secret:", err);
|
|
445
447
|
}
|
|
448
|
+
try {
|
|
449
|
+
await this.runSQL(`
|
|
450
|
+
SELECT pg_terminate_backend(pid)
|
|
451
|
+
FROM pg_stat_activity
|
|
452
|
+
WHERE datname = current_database()
|
|
453
|
+
AND pid != pg_backend_pid()
|
|
454
|
+
AND query ILIKE '%stripe.%'
|
|
455
|
+
`);
|
|
456
|
+
} catch (err) {
|
|
457
|
+
console.warn("Could not terminate connections:", err);
|
|
458
|
+
}
|
|
446
459
|
await this.runSQL(`DROP SCHEMA IF EXISTS stripe CASCADE`);
|
|
447
460
|
} catch (error) {
|
|
448
461
|
throw new Error(`Uninstall failed: ${error instanceof Error ? error.message : String(error)}`);
|
package/dist/supabase/index.js
CHANGED
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
uninstall,
|
|
10
10
|
webhookFunctionCode,
|
|
11
11
|
workerFunctionCode
|
|
12
|
-
} from "../chunk-
|
|
13
|
-
import "../chunk-
|
|
12
|
+
} from "../chunk-SI3VFP3M.js";
|
|
13
|
+
import "../chunk-3W3CERIG.js";
|
|
14
14
|
export {
|
|
15
15
|
INSTALLATION_ERROR_SUFFIX,
|
|
16
16
|
INSTALLATION_INSTALLED_SUFFIX,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stripe-experiment-sync",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9-beta.1765909347",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Stripe Sync Engine to sync Stripe data to Postgres",
|
|
6
6
|
"type": "module",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"dotenv": "^16.4.7",
|
|
41
41
|
"express": "^4.18.2",
|
|
42
42
|
"inquirer": "^12.3.0",
|
|
43
|
+
"papaparse": "5.4.1",
|
|
43
44
|
"pg": "^8.16.3",
|
|
44
45
|
"pg-node-migrations": "0.0.8",
|
|
45
46
|
"stripe": "^17.7.0",
|
|
@@ -51,6 +52,7 @@
|
|
|
51
52
|
"@types/express": "^4.17.21",
|
|
52
53
|
"@types/inquirer": "^9.0.7",
|
|
53
54
|
"@types/node": "^24.10.1",
|
|
55
|
+
"@types/papaparse": "5.3.16",
|
|
54
56
|
"@types/pg": "^8.15.5",
|
|
55
57
|
"@types/ws": "^8.5.13",
|
|
56
58
|
"@types/yesql": "^4.1.4",
|