stripe-experiment-sync 1.0.7 → 1.0.8-beta.1765872477
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-SX3HLE4H.js → chunk-E2HSDYSR.js} +39 -25
- package/dist/{chunk-7JWRDXNB.js → chunk-E7LIOBPP.js} +195 -23
- package/dist/{chunk-YXQZXR7S.js → chunk-M3MYAMG2.js} +1 -1
- package/dist/{chunk-3P5TZKWU.js → chunk-XDVV7YHP.js} +102 -63
- package/dist/cli/index.cjs +333 -106
- package/dist/cli/index.js +10 -6
- package/dist/cli/lib.cjs +327 -104
- package/dist/cli/lib.d.cts +5 -6
- package/dist/cli/lib.d.ts +5 -6
- package/dist/cli/lib.js +4 -4
- package/dist/index.cjs +196 -23
- package/dist/index.d.cts +53 -1
- package/dist/index.d.ts +53 -1
- package/dist/index.js +4 -2
- package/dist/migrations/0058_improve_sync_runs_status.sql +36 -0
- package/dist/supabase/index.cjs +39 -25
- package/dist/supabase/index.d.cts +6 -1
- package/dist/supabase/index.d.ts +6 -1
- package/dist/supabase/index.js +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
PostgresClient: () => PostgresClient,
|
|
34
34
|
StripeSync: () => StripeSync,
|
|
35
35
|
VERSION: () => VERSION,
|
|
36
|
+
createStripeWebSocketClient: () => createStripeWebSocketClient,
|
|
36
37
|
hashApiKey: () => hashApiKey,
|
|
37
38
|
runMigrations: () => runMigrations
|
|
38
39
|
});
|
|
@@ -45,7 +46,7 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
|
45
46
|
// package.json
|
|
46
47
|
var package_default = {
|
|
47
48
|
name: "stripe-experiment-sync",
|
|
48
|
-
version: "1.0.
|
|
49
|
+
version: "1.0.8-beta.1765872477",
|
|
49
50
|
private: false,
|
|
50
51
|
description: "Stripe Sync Engine to sync Stripe data to Postgres",
|
|
51
52
|
type: "module",
|
|
@@ -1729,19 +1730,8 @@ var StripeSync = class {
|
|
|
1729
1730
|
if (params?.runStartedAt) {
|
|
1730
1731
|
runStartedAt = params.runStartedAt;
|
|
1731
1732
|
} else {
|
|
1732
|
-
const runKey = await this.
|
|
1733
|
-
|
|
1734
|
-
params?.triggeredBy ?? "processNext"
|
|
1735
|
-
);
|
|
1736
|
-
if (!runKey) {
|
|
1737
|
-
const activeRun = await this.postgresClient.getActiveSyncRun(accountId);
|
|
1738
|
-
if (!activeRun) {
|
|
1739
|
-
throw new Error("Failed to get or create sync run");
|
|
1740
|
-
}
|
|
1741
|
-
runStartedAt = activeRun.runStartedAt;
|
|
1742
|
-
} else {
|
|
1743
|
-
runStartedAt = runKey.runStartedAt;
|
|
1744
|
-
}
|
|
1733
|
+
const { runKey } = await this.joinOrCreateSyncRun(params?.triggeredBy ?? "processNext");
|
|
1734
|
+
runStartedAt = runKey.runStartedAt;
|
|
1745
1735
|
}
|
|
1746
1736
|
await this.postgresClient.createObjectRuns(accountId, runStartedAt, [resourceName]);
|
|
1747
1737
|
const objRun = await this.postgresClient.getObjectRun(accountId, runStartedAt, resourceName);
|
|
@@ -1904,18 +1894,39 @@ var StripeSync = class {
|
|
|
1904
1894
|
}
|
|
1905
1895
|
return { synced: totalSynced };
|
|
1906
1896
|
}
|
|
1907
|
-
|
|
1908
|
-
|
|
1897
|
+
/**
|
|
1898
|
+
* Join existing sync run or create a new one.
|
|
1899
|
+
* Returns sync run key and list of supported objects to sync.
|
|
1900
|
+
*
|
|
1901
|
+
* Cooperative behavior: If a sync run already exists, joins it instead of failing.
|
|
1902
|
+
* This is used by workers and background processes that should cooperate.
|
|
1903
|
+
*
|
|
1904
|
+
* @param triggeredBy - What triggered this sync (for observability)
|
|
1905
|
+
* @returns Run key and list of objects to sync
|
|
1906
|
+
*/
|
|
1907
|
+
async joinOrCreateSyncRun(triggeredBy = "worker") {
|
|
1909
1908
|
await this.getCurrentAccount();
|
|
1910
1909
|
const accountId = await this.getAccountId();
|
|
1911
|
-
const
|
|
1912
|
-
if (!
|
|
1910
|
+
const result = await this.postgresClient.getOrCreateSyncRun(accountId, triggeredBy);
|
|
1911
|
+
if (!result) {
|
|
1913
1912
|
const activeRun = await this.postgresClient.getActiveSyncRun(accountId);
|
|
1914
1913
|
if (!activeRun) {
|
|
1915
1914
|
throw new Error("Failed to get or create sync run");
|
|
1916
1915
|
}
|
|
1917
|
-
return
|
|
1916
|
+
return {
|
|
1917
|
+
runKey: { accountId: activeRun.accountId, runStartedAt: activeRun.runStartedAt },
|
|
1918
|
+
objects: this.getSupportedSyncObjects()
|
|
1919
|
+
};
|
|
1918
1920
|
}
|
|
1921
|
+
const { accountId: runAccountId, runStartedAt } = result;
|
|
1922
|
+
return {
|
|
1923
|
+
runKey: { accountId: runAccountId, runStartedAt },
|
|
1924
|
+
objects: this.getSupportedSyncObjects()
|
|
1925
|
+
};
|
|
1926
|
+
}
|
|
1927
|
+
async processUntilDone(params) {
|
|
1928
|
+
const { object } = params ?? { object: "all" };
|
|
1929
|
+
const { runKey } = await this.joinOrCreateSyncRun("processUntilDone");
|
|
1919
1930
|
return this.processUntilDoneWithRun(runKey.runStartedAt, object, params);
|
|
1920
1931
|
}
|
|
1921
1932
|
/**
|
|
@@ -2530,14 +2541,14 @@ var StripeSync = class {
|
|
|
2530
2541
|
throw error;
|
|
2531
2542
|
}
|
|
2532
2543
|
}
|
|
2533
|
-
async fetchAndUpsert(
|
|
2544
|
+
async fetchAndUpsert(fetch2, upsert, accountId, resourceName, runStartedAt) {
|
|
2534
2545
|
const CHECKPOINT_SIZE = 100;
|
|
2535
2546
|
let totalSynced = 0;
|
|
2536
2547
|
let currentBatch = [];
|
|
2537
2548
|
try {
|
|
2538
2549
|
this.config.logger?.info("Fetching items to sync from Stripe");
|
|
2539
2550
|
try {
|
|
2540
|
-
for await (const item of
|
|
2551
|
+
for await (const item of fetch2()) {
|
|
2541
2552
|
currentBatch.push(item);
|
|
2542
2553
|
if (currentBatch.length >= CHECKPOINT_SIZE) {
|
|
2543
2554
|
this.config.logger?.info(`Upserting batch of ${currentBatch.length} items`);
|
|
@@ -3263,11 +3274,11 @@ var StripeSync = class {
|
|
|
3263
3274
|
}
|
|
3264
3275
|
}
|
|
3265
3276
|
}
|
|
3266
|
-
async fetchMissingEntities(ids,
|
|
3277
|
+
async fetchMissingEntities(ids, fetch2) {
|
|
3267
3278
|
if (!ids.length) return [];
|
|
3268
3279
|
const entities = [];
|
|
3269
3280
|
for (const id of ids) {
|
|
3270
|
-
const entity = await
|
|
3281
|
+
const entity = await fetch2(id);
|
|
3271
3282
|
entities.push(entity);
|
|
3272
3283
|
}
|
|
3273
3284
|
return entities;
|
|
@@ -3374,6 +3385,167 @@ async function runMigrations(config) {
|
|
|
3374
3385
|
}
|
|
3375
3386
|
}
|
|
3376
3387
|
|
|
3388
|
+
// src/websocket-client.ts
|
|
3389
|
+
var import_ws = __toESM(require("ws"), 1);
|
|
3390
|
+
var CLI_VERSION = "1.33.0";
|
|
3391
|
+
var PONG_WAIT = 10 * 1e3;
|
|
3392
|
+
var PING_PERIOD = PONG_WAIT * 2 / 10;
|
|
3393
|
+
function getClientUserAgent() {
|
|
3394
|
+
return JSON.stringify({
|
|
3395
|
+
name: "stripe-cli",
|
|
3396
|
+
version: CLI_VERSION,
|
|
3397
|
+
publisher: "stripe",
|
|
3398
|
+
os: process.platform
|
|
3399
|
+
});
|
|
3400
|
+
}
|
|
3401
|
+
async function createCliSession(stripeApiKey) {
|
|
3402
|
+
const params = new URLSearchParams();
|
|
3403
|
+
params.append("device_name", "stripe-sync-engine");
|
|
3404
|
+
params.append("websocket_features[]", "webhooks");
|
|
3405
|
+
const response = await fetch("https://api.stripe.com/v1/stripecli/sessions", {
|
|
3406
|
+
method: "POST",
|
|
3407
|
+
headers: {
|
|
3408
|
+
Authorization: `Bearer ${stripeApiKey}`,
|
|
3409
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
3410
|
+
"User-Agent": `Stripe/v1 stripe-cli/${CLI_VERSION}`,
|
|
3411
|
+
"X-Stripe-Client-User-Agent": getClientUserAgent()
|
|
3412
|
+
},
|
|
3413
|
+
body: params.toString()
|
|
3414
|
+
});
|
|
3415
|
+
if (!response.ok) {
|
|
3416
|
+
const error = await response.text();
|
|
3417
|
+
throw new Error(`Failed to create CLI session: ${error}`);
|
|
3418
|
+
}
|
|
3419
|
+
return await response.json();
|
|
3420
|
+
}
|
|
3421
|
+
async function createStripeWebSocketClient(options) {
|
|
3422
|
+
const { stripeApiKey, onEvent, onReady, onError, onClose } = options;
|
|
3423
|
+
const session = await createCliSession(stripeApiKey);
|
|
3424
|
+
let ws = null;
|
|
3425
|
+
let pingInterval = null;
|
|
3426
|
+
let connected = false;
|
|
3427
|
+
let shouldReconnect = true;
|
|
3428
|
+
function connect() {
|
|
3429
|
+
const wsUrl = `${session.websocket_url}?websocket_feature=${encodeURIComponent(session.websocket_authorized_feature)}`;
|
|
3430
|
+
ws = new import_ws.default(wsUrl, {
|
|
3431
|
+
headers: {
|
|
3432
|
+
"Accept-Encoding": "identity",
|
|
3433
|
+
"User-Agent": `Stripe/v1 stripe-cli/${CLI_VERSION}`,
|
|
3434
|
+
"X-Stripe-Client-User-Agent": getClientUserAgent(),
|
|
3435
|
+
"Websocket-Id": session.websocket_id
|
|
3436
|
+
}
|
|
3437
|
+
});
|
|
3438
|
+
ws.on("pong", () => {
|
|
3439
|
+
});
|
|
3440
|
+
ws.on("open", () => {
|
|
3441
|
+
connected = true;
|
|
3442
|
+
pingInterval = setInterval(() => {
|
|
3443
|
+
if (ws && ws.readyState === import_ws.default.OPEN) {
|
|
3444
|
+
ws.ping();
|
|
3445
|
+
}
|
|
3446
|
+
}, PING_PERIOD);
|
|
3447
|
+
if (onReady) {
|
|
3448
|
+
onReady(session.secret);
|
|
3449
|
+
}
|
|
3450
|
+
});
|
|
3451
|
+
ws.on("message", async (data) => {
|
|
3452
|
+
try {
|
|
3453
|
+
const message = JSON.parse(data.toString());
|
|
3454
|
+
const ack = {
|
|
3455
|
+
type: "event_ack",
|
|
3456
|
+
event_id: message.webhook_id,
|
|
3457
|
+
webhook_conversation_id: message.webhook_conversation_id,
|
|
3458
|
+
webhook_id: message.webhook_id
|
|
3459
|
+
};
|
|
3460
|
+
if (ws && ws.readyState === import_ws.default.OPEN) {
|
|
3461
|
+
ws.send(JSON.stringify(ack));
|
|
3462
|
+
}
|
|
3463
|
+
let response;
|
|
3464
|
+
try {
|
|
3465
|
+
const result = await onEvent(message);
|
|
3466
|
+
response = {
|
|
3467
|
+
type: "webhook_response",
|
|
3468
|
+
webhook_id: message.webhook_id,
|
|
3469
|
+
webhook_conversation_id: message.webhook_conversation_id,
|
|
3470
|
+
forward_url: "stripe-sync-engine",
|
|
3471
|
+
status: result?.status ?? 200,
|
|
3472
|
+
http_headers: {},
|
|
3473
|
+
body: JSON.stringify({
|
|
3474
|
+
event_type: result?.event_type,
|
|
3475
|
+
event_id: result?.event_id,
|
|
3476
|
+
database_url: result?.databaseUrl,
|
|
3477
|
+
error: result?.error
|
|
3478
|
+
}),
|
|
3479
|
+
request_headers: message.http_headers,
|
|
3480
|
+
request_body: message.event_payload,
|
|
3481
|
+
notification_id: message.webhook_id
|
|
3482
|
+
};
|
|
3483
|
+
} catch (err) {
|
|
3484
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
3485
|
+
response = {
|
|
3486
|
+
type: "webhook_response",
|
|
3487
|
+
webhook_id: message.webhook_id,
|
|
3488
|
+
webhook_conversation_id: message.webhook_conversation_id,
|
|
3489
|
+
forward_url: "stripe-sync-engine",
|
|
3490
|
+
status: 500,
|
|
3491
|
+
http_headers: {},
|
|
3492
|
+
body: JSON.stringify({ error: errorMessage }),
|
|
3493
|
+
request_headers: message.http_headers,
|
|
3494
|
+
request_body: message.event_payload,
|
|
3495
|
+
notification_id: message.webhook_id
|
|
3496
|
+
};
|
|
3497
|
+
if (onError) {
|
|
3498
|
+
onError(err instanceof Error ? err : new Error(errorMessage));
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
if (ws && ws.readyState === import_ws.default.OPEN) {
|
|
3502
|
+
ws.send(JSON.stringify(response));
|
|
3503
|
+
}
|
|
3504
|
+
} catch (err) {
|
|
3505
|
+
if (onError) {
|
|
3506
|
+
onError(err instanceof Error ? err : new Error(String(err)));
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
});
|
|
3510
|
+
ws.on("error", (error) => {
|
|
3511
|
+
if (onError) {
|
|
3512
|
+
onError(error);
|
|
3513
|
+
}
|
|
3514
|
+
});
|
|
3515
|
+
ws.on("close", (code, reason) => {
|
|
3516
|
+
connected = false;
|
|
3517
|
+
if (pingInterval) {
|
|
3518
|
+
clearInterval(pingInterval);
|
|
3519
|
+
pingInterval = null;
|
|
3520
|
+
}
|
|
3521
|
+
if (onClose) {
|
|
3522
|
+
onClose(code, reason.toString());
|
|
3523
|
+
}
|
|
3524
|
+
if (shouldReconnect) {
|
|
3525
|
+
const delay = (session.reconnect_delay || 5) * 1e3;
|
|
3526
|
+
setTimeout(() => {
|
|
3527
|
+
connect();
|
|
3528
|
+
}, delay);
|
|
3529
|
+
}
|
|
3530
|
+
});
|
|
3531
|
+
}
|
|
3532
|
+
connect();
|
|
3533
|
+
return {
|
|
3534
|
+
close: () => {
|
|
3535
|
+
shouldReconnect = false;
|
|
3536
|
+
if (pingInterval) {
|
|
3537
|
+
clearInterval(pingInterval);
|
|
3538
|
+
pingInterval = null;
|
|
3539
|
+
}
|
|
3540
|
+
if (ws) {
|
|
3541
|
+
ws.close(1e3, "Connection Done");
|
|
3542
|
+
ws = null;
|
|
3543
|
+
}
|
|
3544
|
+
},
|
|
3545
|
+
isConnected: () => connected
|
|
3546
|
+
};
|
|
3547
|
+
}
|
|
3548
|
+
|
|
3377
3549
|
// src/index.ts
|
|
3378
3550
|
var VERSION = package_default.version;
|
|
3379
3551
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -3381,6 +3553,7 @@ var VERSION = package_default.version;
|
|
|
3381
3553
|
PostgresClient,
|
|
3382
3554
|
StripeSync,
|
|
3383
3555
|
VERSION,
|
|
3556
|
+
createStripeWebSocketClient,
|
|
3384
3557
|
hashApiKey,
|
|
3385
3558
|
runMigrations
|
|
3386
3559
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -335,6 +335,13 @@ interface ProcessNextParams extends SyncParams {
|
|
|
335
335
|
triggeredBy?: string;
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Identifies a specific sync run.
|
|
340
|
+
*/
|
|
341
|
+
type RunKey = {
|
|
342
|
+
accountId: string;
|
|
343
|
+
runStartedAt: Date;
|
|
344
|
+
};
|
|
338
345
|
declare class StripeSync {
|
|
339
346
|
private config;
|
|
340
347
|
stripe: Stripe;
|
|
@@ -470,6 +477,20 @@ declare class StripeSync {
|
|
|
470
477
|
* @returns Sync result with count of synced items
|
|
471
478
|
*/
|
|
472
479
|
private processObjectUntilDone;
|
|
480
|
+
/**
|
|
481
|
+
* Join existing sync run or create a new one.
|
|
482
|
+
* Returns sync run key and list of supported objects to sync.
|
|
483
|
+
*
|
|
484
|
+
* Cooperative behavior: If a sync run already exists, joins it instead of failing.
|
|
485
|
+
* This is used by workers and background processes that should cooperate.
|
|
486
|
+
*
|
|
487
|
+
* @param triggeredBy - What triggered this sync (for observability)
|
|
488
|
+
* @returns Run key and list of objects to sync
|
|
489
|
+
*/
|
|
490
|
+
joinOrCreateSyncRun(triggeredBy?: string): Promise<{
|
|
491
|
+
runKey: RunKey;
|
|
492
|
+
objects: Exclude<SyncObject, 'all' | 'customer_with_entitlements'>[];
|
|
493
|
+
}>;
|
|
473
494
|
processUntilDone(params?: SyncParams): Promise<SyncBackfill>;
|
|
474
495
|
/**
|
|
475
496
|
* Internal implementation of processUntilDone with an existing run.
|
|
@@ -600,6 +621,37 @@ declare function runMigrations(config: MigrationConfig): Promise<void>;
|
|
|
600
621
|
*/
|
|
601
622
|
declare function hashApiKey(apiKey: string): string;
|
|
602
623
|
|
|
624
|
+
interface WebhookProcessingResult {
|
|
625
|
+
status: number;
|
|
626
|
+
databaseUrl: string;
|
|
627
|
+
event_type?: string;
|
|
628
|
+
event_id?: string;
|
|
629
|
+
error?: string;
|
|
630
|
+
}
|
|
631
|
+
interface StripeWebSocketOptions {
|
|
632
|
+
stripeApiKey: string;
|
|
633
|
+
onEvent: (event: StripeWebhookEvent) => Promise<WebhookProcessingResult | void> | WebhookProcessingResult | void;
|
|
634
|
+
onReady?: (secret: string) => void;
|
|
635
|
+
onError?: (error: Error) => void;
|
|
636
|
+
onClose?: (code: number, reason: string) => void;
|
|
637
|
+
}
|
|
638
|
+
interface StripeWebSocketClient {
|
|
639
|
+
close: () => void;
|
|
640
|
+
isConnected: () => boolean;
|
|
641
|
+
}
|
|
642
|
+
interface StripeWebhookEvent {
|
|
643
|
+
type: string;
|
|
644
|
+
webhook_id: string;
|
|
645
|
+
webhook_conversation_id: string;
|
|
646
|
+
event_payload: string;
|
|
647
|
+
http_headers: Record<string, string>;
|
|
648
|
+
endpoint: {
|
|
649
|
+
url: string;
|
|
650
|
+
status: string;
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
declare function createStripeWebSocketClient(options: StripeWebSocketOptions): Promise<StripeWebSocketClient>;
|
|
654
|
+
|
|
603
655
|
declare const VERSION: string;
|
|
604
656
|
|
|
605
|
-
export { 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 };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -335,6 +335,13 @@ interface ProcessNextParams extends SyncParams {
|
|
|
335
335
|
triggeredBy?: string;
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Identifies a specific sync run.
|
|
340
|
+
*/
|
|
341
|
+
type RunKey = {
|
|
342
|
+
accountId: string;
|
|
343
|
+
runStartedAt: Date;
|
|
344
|
+
};
|
|
338
345
|
declare class StripeSync {
|
|
339
346
|
private config;
|
|
340
347
|
stripe: Stripe;
|
|
@@ -470,6 +477,20 @@ declare class StripeSync {
|
|
|
470
477
|
* @returns Sync result with count of synced items
|
|
471
478
|
*/
|
|
472
479
|
private processObjectUntilDone;
|
|
480
|
+
/**
|
|
481
|
+
* Join existing sync run or create a new one.
|
|
482
|
+
* Returns sync run key and list of supported objects to sync.
|
|
483
|
+
*
|
|
484
|
+
* Cooperative behavior: If a sync run already exists, joins it instead of failing.
|
|
485
|
+
* This is used by workers and background processes that should cooperate.
|
|
486
|
+
*
|
|
487
|
+
* @param triggeredBy - What triggered this sync (for observability)
|
|
488
|
+
* @returns Run key and list of objects to sync
|
|
489
|
+
*/
|
|
490
|
+
joinOrCreateSyncRun(triggeredBy?: string): Promise<{
|
|
491
|
+
runKey: RunKey;
|
|
492
|
+
objects: Exclude<SyncObject, 'all' | 'customer_with_entitlements'>[];
|
|
493
|
+
}>;
|
|
473
494
|
processUntilDone(params?: SyncParams): Promise<SyncBackfill>;
|
|
474
495
|
/**
|
|
475
496
|
* Internal implementation of processUntilDone with an existing run.
|
|
@@ -600,6 +621,37 @@ declare function runMigrations(config: MigrationConfig): Promise<void>;
|
|
|
600
621
|
*/
|
|
601
622
|
declare function hashApiKey(apiKey: string): string;
|
|
602
623
|
|
|
624
|
+
interface WebhookProcessingResult {
|
|
625
|
+
status: number;
|
|
626
|
+
databaseUrl: string;
|
|
627
|
+
event_type?: string;
|
|
628
|
+
event_id?: string;
|
|
629
|
+
error?: string;
|
|
630
|
+
}
|
|
631
|
+
interface StripeWebSocketOptions {
|
|
632
|
+
stripeApiKey: string;
|
|
633
|
+
onEvent: (event: StripeWebhookEvent) => Promise<WebhookProcessingResult | void> | WebhookProcessingResult | void;
|
|
634
|
+
onReady?: (secret: string) => void;
|
|
635
|
+
onError?: (error: Error) => void;
|
|
636
|
+
onClose?: (code: number, reason: string) => void;
|
|
637
|
+
}
|
|
638
|
+
interface StripeWebSocketClient {
|
|
639
|
+
close: () => void;
|
|
640
|
+
isConnected: () => boolean;
|
|
641
|
+
}
|
|
642
|
+
interface StripeWebhookEvent {
|
|
643
|
+
type: string;
|
|
644
|
+
webhook_id: string;
|
|
645
|
+
webhook_conversation_id: string;
|
|
646
|
+
event_payload: string;
|
|
647
|
+
http_headers: Record<string, string>;
|
|
648
|
+
endpoint: {
|
|
649
|
+
url: string;
|
|
650
|
+
status: string;
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
declare function createStripeWebSocketClient(options: StripeWebSocketOptions): Promise<StripeWebSocketClient>;
|
|
654
|
+
|
|
603
655
|
declare const VERSION: string;
|
|
604
656
|
|
|
605
|
-
export { 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 };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -2,14 +2,16 @@ import {
|
|
|
2
2
|
PostgresClient,
|
|
3
3
|
StripeSync,
|
|
4
4
|
VERSION,
|
|
5
|
+
createStripeWebSocketClient,
|
|
5
6
|
hashApiKey,
|
|
6
7
|
runMigrations
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-E7LIOBPP.js";
|
|
9
|
+
import "./chunk-M3MYAMG2.js";
|
|
9
10
|
export {
|
|
10
11
|
PostgresClient,
|
|
11
12
|
StripeSync,
|
|
12
13
|
VERSION,
|
|
14
|
+
createStripeWebSocketClient,
|
|
13
15
|
hashApiKey,
|
|
14
16
|
runMigrations
|
|
15
17
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
-- Improve sync_runs view status logic
|
|
2
|
+
-- More granular status based on actual object run states
|
|
3
|
+
|
|
4
|
+
DROP VIEW IF EXISTS "stripe"."sync_runs";
|
|
5
|
+
|
|
6
|
+
CREATE VIEW "stripe"."sync_runs" AS
|
|
7
|
+
SELECT
|
|
8
|
+
r._account_id as account_id,
|
|
9
|
+
r.started_at,
|
|
10
|
+
r.closed_at,
|
|
11
|
+
r.triggered_by,
|
|
12
|
+
r.max_concurrent,
|
|
13
|
+
-- Aggregate metrics from child objects
|
|
14
|
+
COALESCE(SUM(o.processed_count), 0) as total_processed,
|
|
15
|
+
COUNT(o.*) as total_objects,
|
|
16
|
+
COUNT(*) FILTER (WHERE o.status = 'complete') as complete_count,
|
|
17
|
+
COUNT(*) FILTER (WHERE o.status = 'error') as error_count,
|
|
18
|
+
COUNT(*) FILTER (WHERE o.status = 'running') as running_count,
|
|
19
|
+
COUNT(*) FILTER (WHERE o.status = 'pending') as pending_count,
|
|
20
|
+
-- Collect error messages if any
|
|
21
|
+
STRING_AGG(o.error_message, '; ') FILTER (WHERE o.error_message IS NOT NULL) as error_message,
|
|
22
|
+
-- Derive overall status from run state and object states
|
|
23
|
+
CASE
|
|
24
|
+
-- Run still open (closed_at IS NULL)
|
|
25
|
+
WHEN r.closed_at IS NULL AND COUNT(*) FILTER (WHERE o.status = 'running') > 0 THEN 'running'
|
|
26
|
+
WHEN r.closed_at IS NULL AND (COUNT(o.*) = 0 OR COUNT(o.*) = COUNT(*) FILTER (WHERE o.status = 'pending')) THEN 'pending'
|
|
27
|
+
WHEN r.closed_at IS NULL THEN 'running'
|
|
28
|
+
-- Run closed (closed_at IS NOT NULL)
|
|
29
|
+
WHEN COUNT(*) FILTER (WHERE o.status = 'error') > 0 THEN 'error'
|
|
30
|
+
ELSE 'complete'
|
|
31
|
+
END as status
|
|
32
|
+
FROM "stripe"."_sync_runs" r
|
|
33
|
+
LEFT JOIN "stripe"."_sync_obj_runs" o
|
|
34
|
+
ON o._account_id = r._account_id
|
|
35
|
+
AND o.run_started_at = r.started_at
|
|
36
|
+
GROUP BY r._account_id, r.started_at, r.closed_at, r.triggered_by, r.max_concurrent;
|
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:/Users/lfdepombo/src/stripe-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:/Users/lfdepombo/src/stripe-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 const objects = stripeSync.
|
|
56
|
+
// raw-ts:/Users/lfdepombo/src/stripe-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 })\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.8-beta.1765872477",
|
|
68
68
|
private: false,
|
|
69
69
|
description: "Stripe Sync Engine to sync Stripe data to Postgres",
|
|
70
70
|
type: "module",
|
|
@@ -443,45 +443,59 @@ var SupabaseSetupClient = class {
|
|
|
443
443
|
} catch (err) {
|
|
444
444
|
console.warn("Could not delete vault secret:", err);
|
|
445
445
|
}
|
|
446
|
+
try {
|
|
447
|
+
await this.runSQL(`
|
|
448
|
+
SELECT pg_terminate_backend(pid)
|
|
449
|
+
FROM pg_stat_activity
|
|
450
|
+
WHERE datname = current_database()
|
|
451
|
+
AND pid != pg_backend_pid()
|
|
452
|
+
AND query ILIKE '%stripe.%'
|
|
453
|
+
`);
|
|
454
|
+
} catch (err) {
|
|
455
|
+
console.warn("Could not terminate connections:", err);
|
|
456
|
+
}
|
|
446
457
|
await this.runSQL(`DROP SCHEMA IF EXISTS stripe CASCADE`);
|
|
447
458
|
} catch (error) {
|
|
448
459
|
throw new Error(`Uninstall failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
449
460
|
}
|
|
450
461
|
}
|
|
451
|
-
|
|
462
|
+
/**
|
|
463
|
+
* Inject package version into Edge Function code
|
|
464
|
+
*/
|
|
465
|
+
injectPackageVersion(code, version) {
|
|
466
|
+
if (version === "latest") {
|
|
467
|
+
return code;
|
|
468
|
+
}
|
|
469
|
+
return code.replace(
|
|
470
|
+
/from ['"]npm:stripe-experiment-sync['"]/g,
|
|
471
|
+
`from 'npm:stripe-experiment-sync@${version}'`
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
async install(stripeKey, packageVersion) {
|
|
452
475
|
const trimmedStripeKey = stripeKey.trim();
|
|
453
476
|
if (!trimmedStripeKey.startsWith("sk_") && !trimmedStripeKey.startsWith("rk_")) {
|
|
454
477
|
throw new Error('Stripe key should start with "sk_" or "rk_"');
|
|
455
478
|
}
|
|
479
|
+
const version = packageVersion || "latest";
|
|
456
480
|
try {
|
|
457
481
|
await this.validateProject();
|
|
458
482
|
await this.runSQL(`CREATE SCHEMA IF NOT EXISTS stripe`);
|
|
459
483
|
await this.updateInstallationComment(
|
|
460
484
|
`${STRIPE_SCHEMA_COMMENT_PREFIX} v${package_default.version} ${INSTALLATION_STARTED_SUFFIX}`
|
|
461
485
|
);
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
486
|
+
const versionedSetup = this.injectPackageVersion(setupFunctionCode, version);
|
|
487
|
+
const versionedWebhook = this.injectPackageVersion(webhookFunctionCode, version);
|
|
488
|
+
const versionedWorker = this.injectPackageVersion(workerFunctionCode, version);
|
|
489
|
+
await this.deployFunction("stripe-setup", versionedSetup);
|
|
490
|
+
await this.deployFunction("stripe-webhook", versionedWebhook);
|
|
491
|
+
await this.deployFunction("stripe-worker", versionedWorker);
|
|
465
492
|
await this.setSecrets([{ name: "STRIPE_SECRET_KEY", value: trimmedStripeKey }]);
|
|
466
493
|
const serviceRoleKey = await this.getServiceRoleKey();
|
|
467
494
|
const setupResult = await this.invokeFunction("stripe-setup", serviceRoleKey);
|
|
468
495
|
if (!setupResult.success) {
|
|
469
496
|
throw new Error(`Setup failed: ${setupResult.error}`);
|
|
470
497
|
}
|
|
471
|
-
|
|
472
|
-
try {
|
|
473
|
-
await this.setupPgCronJob();
|
|
474
|
-
pgCronEnabled = true;
|
|
475
|
-
} catch {
|
|
476
|
-
console.warn("pg_cron setup failed - falling back to manual worker invocation");
|
|
477
|
-
}
|
|
478
|
-
if (!pgCronEnabled) {
|
|
479
|
-
try {
|
|
480
|
-
await this.invokeFunction("stripe-worker", serviceRoleKey);
|
|
481
|
-
} catch (err) {
|
|
482
|
-
console.warn("Failed to trigger initial worker invocation:", err);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
498
|
+
await this.setupPgCronJob();
|
|
485
499
|
await this.updateInstallationComment(
|
|
486
500
|
`${STRIPE_SCHEMA_COMMENT_PREFIX} v${package_default.version} ${INSTALLATION_INSTALLED_SUFFIX}`
|
|
487
501
|
);
|
|
@@ -494,14 +508,14 @@ var SupabaseSetupClient = class {
|
|
|
494
508
|
}
|
|
495
509
|
};
|
|
496
510
|
async function install(params) {
|
|
497
|
-
const { supabaseAccessToken, supabaseProjectRef, stripeKey } = params;
|
|
511
|
+
const { supabaseAccessToken, supabaseProjectRef, stripeKey, packageVersion } = params;
|
|
498
512
|
const client = new SupabaseSetupClient({
|
|
499
513
|
accessToken: supabaseAccessToken,
|
|
500
514
|
projectRef: supabaseProjectRef,
|
|
501
515
|
projectBaseUrl: params.baseProjectUrl,
|
|
502
516
|
managementApiBaseUrl: params.baseManagementApiUrl
|
|
503
517
|
});
|
|
504
|
-
await client.install(stripeKey);
|
|
518
|
+
await client.install(stripeKey, packageVersion);
|
|
505
519
|
}
|
|
506
520
|
async function uninstall(params) {
|
|
507
521
|
const { supabaseAccessToken, supabaseProjectRef, stripeKey } = params;
|
|
@@ -93,12 +93,17 @@ declare class SupabaseSetupClient {
|
|
|
93
93
|
* Removes all Edge Functions, secrets, database resources, and Stripe webhooks
|
|
94
94
|
*/
|
|
95
95
|
uninstall(stripeSecretKey: string): Promise<void>;
|
|
96
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Inject package version into Edge Function code
|
|
98
|
+
*/
|
|
99
|
+
private injectPackageVersion;
|
|
100
|
+
install(stripeKey: string, packageVersion?: string): Promise<void>;
|
|
97
101
|
}
|
|
98
102
|
declare function install(params: {
|
|
99
103
|
supabaseAccessToken: string;
|
|
100
104
|
supabaseProjectRef: string;
|
|
101
105
|
stripeKey: string;
|
|
106
|
+
packageVersion?: string;
|
|
102
107
|
baseProjectUrl?: string;
|
|
103
108
|
baseManagementApiUrl?: string;
|
|
104
109
|
}): Promise<void>;
|