stripe-experiment-sync 1.0.9-beta.1765909347 → 1.0.10

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/cli/lib.cjs CHANGED
@@ -59,7 +59,6 @@ async function loadConfig(options) {
59
59
  config.stripeApiKey = options.stripeKey || process.env.STRIPE_API_KEY || "";
60
60
  config.ngrokAuthToken = options.ngrokToken || process.env.NGROK_AUTH_TOKEN || "";
61
61
  config.databaseUrl = options.databaseUrl || process.env.DATABASE_URL || "";
62
- config.enableSigmaSync = options.enableSigmaSync ?? (process.env.ENABLE_SIGMA_SYNC !== void 0 ? process.env.ENABLE_SIGMA_SYNC === "true" : void 0);
63
62
  const questions = [];
64
63
  if (!config.stripeApiKey) {
65
64
  questions.push({
@@ -71,8 +70,8 @@ async function loadConfig(options) {
71
70
  if (!input || input.trim() === "") {
72
71
  return "Stripe API key is required";
73
72
  }
74
- if (!input.startsWith("sk_") && !input.startsWith("rk_")) {
75
- return 'Stripe API key should start with "sk_" or "rk_"';
73
+ if (!input.startsWith("sk_")) {
74
+ return 'Stripe API key should start with "sk_"';
76
75
  }
77
76
  return true;
78
77
  }
@@ -95,29 +94,18 @@ async function loadConfig(options) {
95
94
  }
96
95
  });
97
96
  }
98
- if (config.enableSigmaSync === void 0) {
99
- questions.push({
100
- type: "confirm",
101
- name: "enableSigmaSync",
102
- message: "Enable Sigma sync? (Requires Sigma access in Stripe API key)",
103
- default: false
104
- });
105
- }
106
97
  if (questions.length > 0) {
107
- console.log(import_chalk.default.yellow("\nMissing configuration. Please provide:"));
98
+ console.log(import_chalk.default.yellow("\nMissing required configuration. Please provide:"));
108
99
  const answers = await import_inquirer.default.prompt(questions);
109
100
  Object.assign(config, answers);
110
101
  }
111
- if (config.enableSigmaSync === void 0) {
112
- config.enableSigmaSync = false;
113
- }
114
102
  return config;
115
103
  }
116
104
 
117
105
  // package.json
118
106
  var package_default = {
119
107
  name: "stripe-experiment-sync",
120
- version: "1.0.9-beta.1765909347",
108
+ version: "1.0.10",
121
109
  private: false,
122
110
  description: "Stripe Sync Engine to sync Stripe data to Postgres",
123
111
  type: "module",
@@ -157,7 +145,6 @@ var package_default = {
157
145
  dotenv: "^16.4.7",
158
146
  express: "^4.18.2",
159
147
  inquirer: "^12.3.0",
160
- papaparse: "5.4.1",
161
148
  pg: "^8.16.3",
162
149
  "pg-node-migrations": "0.0.8",
163
150
  stripe: "^17.7.0",
@@ -169,7 +156,6 @@ var package_default = {
169
156
  "@types/express": "^4.17.21",
170
157
  "@types/inquirer": "^9.0.7",
171
158
  "@types/node": "^24.10.1",
172
- "@types/papaparse": "5.3.16",
173
159
  "@types/pg": "^8.15.5",
174
160
  "@types/ws": "^8.5.13",
175
161
  "@types/yesql": "^4.1.4",
@@ -199,60 +185,14 @@ var package_default = {
199
185
  };
200
186
 
201
187
  // src/stripeSync.ts
202
- var import_stripe3 = __toESM(require("stripe"), 1);
188
+ var import_stripe2 = __toESM(require("stripe"), 1);
203
189
  var import_yesql2 = require("yesql");
204
190
 
205
191
  // src/database/postgres.ts
206
192
  var import_pg = __toESM(require("pg"), 1);
207
193
  var import_yesql = require("yesql");
208
-
209
- // src/database/QueryUtils.ts
210
- var QueryUtils = class _QueryUtils {
211
- constructor() {
212
- }
213
- static quoteIdent(name) {
214
- return `"${name}"`;
215
- }
216
- static quotedList(names) {
217
- return names.map(_QueryUtils.quoteIdent).join(", ");
218
- }
219
- static buildInsertParts(columns) {
220
- const columnsSql = columns.map((c) => _QueryUtils.quoteIdent(c.column)).join(", ");
221
- const valuesSql = columns.map((c, i) => {
222
- const placeholder = `$${i + 1}`;
223
- return `${placeholder}::${c.pgType}`;
224
- }).join(", ");
225
- const params = columns.map((c) => c.value);
226
- return { columnsSql, valuesSql, params };
227
- }
228
- static buildRawJsonUpsertQuery(schema, table, columns, conflictTarget) {
229
- const { columnsSql, valuesSql, params } = _QueryUtils.buildInsertParts(columns);
230
- const conflictSql = _QueryUtils.quotedList(conflictTarget);
231
- const tsParamIdx = columns.findIndex((c) => c.column === "_last_synced_at") + 1;
232
- if (tsParamIdx <= 0) {
233
- throw new Error("buildRawJsonUpsertQuery requires _last_synced_at column");
234
- }
235
- const sql3 = `
236
- INSERT INTO ${_QueryUtils.quoteIdent(schema)}.${_QueryUtils.quoteIdent(table)} (${columnsSql})
237
- VALUES (${valuesSql})
238
- ON CONFLICT (${conflictSql})
239
- DO UPDATE SET
240
- "_raw_data" = EXCLUDED."_raw_data",
241
- "_last_synced_at" = $${tsParamIdx},
242
- "_account_id" = EXCLUDED."_account_id"
243
- WHERE ${_QueryUtils.quoteIdent(table)}."_last_synced_at" IS NULL
244
- OR ${_QueryUtils.quoteIdent(table)}."_last_synced_at" < $${tsParamIdx}
245
- RETURNING *
246
- `;
247
- return { sql: sql3, params };
248
- }
249
- };
250
-
251
- // src/database/postgres.ts
252
194
  var ORDERED_STRIPE_TABLES = [
253
- "exchange_rates_from_usd",
254
195
  "subscription_items",
255
- "subscription_item_change_events_v2_beta",
256
196
  "subscriptions",
257
197
  "subscription_schedules",
258
198
  "checkout_session_line_items",
@@ -322,7 +262,7 @@ var PostgresClient = class {
322
262
  }
323
263
  return results.flatMap((it) => it.rows);
324
264
  }
325
- async upsertManyWithTimestampProtection(entries, table, accountId, syncTimestamp, upsertOptions) {
265
+ async upsertManyWithTimestampProtection(entries, table, accountId, syncTimestamp) {
326
266
  const timestamp = syncTimestamp || (/* @__PURE__ */ new Date()).toISOString();
327
267
  if (!entries.length) return [];
328
268
  const chunkSize = 5;
@@ -357,33 +297,20 @@ var PostgresClient = class {
357
297
  const prepared = (0, import_yesql.pg)(upsertSql, { useNullForMissing: true })(cleansed);
358
298
  queries.push(this.pool.query(prepared.text, prepared.values));
359
299
  } else {
360
- const conflictTarget = upsertOptions?.conflictTarget ?? ["id"];
361
- const extraColumns = upsertOptions?.extraColumns ?? [];
362
- if (!conflictTarget.length) {
363
- throw new Error(`Invalid upsert config for ${table}: conflictTarget must be non-empty`);
364
- }
365
- const columns = [
366
- { column: "_raw_data", pgType: "jsonb", value: JSON.stringify(entry) },
367
- ...extraColumns.map((c) => ({
368
- column: c.column,
369
- pgType: c.pgType,
370
- value: entry[c.entryKey]
371
- })),
372
- { column: "_last_synced_at", pgType: "timestamptz", value: timestamp },
373
- { column: "_account_id", pgType: "text", value: accountId }
374
- ];
375
- for (const c of columns) {
376
- if (c.value === void 0) {
377
- throw new Error(`Missing required value for ${table}.${c.column}`);
378
- }
379
- }
380
- const { sql: upsertSql, params } = QueryUtils.buildRawJsonUpsertQuery(
381
- this.config.schema,
382
- table,
383
- columns,
384
- conflictTarget
385
- );
386
- queries.push(this.pool.query(upsertSql, params));
300
+ const rawData = JSON.stringify(entry);
301
+ const upsertSql = `
302
+ INSERT INTO "${this.config.schema}"."${table}" ("_raw_data", "_last_synced_at", "_account_id")
303
+ VALUES ($1::jsonb, $2, $3)
304
+ ON CONFLICT (id)
305
+ DO UPDATE SET
306
+ "_raw_data" = EXCLUDED."_raw_data",
307
+ "_last_synced_at" = $2,
308
+ "_account_id" = EXCLUDED."_account_id"
309
+ WHERE "${table}"."_last_synced_at" IS NULL
310
+ OR "${table}"."_last_synced_at" < $2
311
+ RETURNING *
312
+ `;
313
+ queries.push(this.pool.query(upsertSql, [rawData, timestamp, accountId]));
387
314
  }
388
315
  });
389
316
  results.push(...await Promise.all(queries));
@@ -783,12 +710,7 @@ var PostgresClient = class {
783
710
  } else {
784
711
  await this.query(
785
712
  `UPDATE "${this.config.schema}"."_sync_obj_runs"
786
- SET cursor = CASE
787
- WHEN cursor IS NULL THEN $4
788
- WHEN (cursor COLLATE "C") < ($4::text COLLATE "C") THEN $4
789
- ELSE cursor
790
- END,
791
- updated_at = now()
713
+ SET cursor = $4, updated_at = now()
792
714
  WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
793
715
  [accountId, runStartedAt, object, cursor]
794
716
  );
@@ -799,17 +721,10 @@ var PostgresClient = class {
799
721
  * This considers completed, error, AND running runs to ensure recovery syncs
800
722
  * don't re-process data that was already synced before a crash.
801
723
  * A 'running' status with a cursor means the process was killed mid-sync.
802
- *
803
- * Handles two cursor formats:
804
- * - Numeric: compared as bigint for correct ordering
805
- * - Composite cursors: compared as strings with COLLATE "C"
806
724
  */
807
725
  async getLastCompletedCursor(accountId, object) {
808
726
  const result = await this.query(
809
- `SELECT CASE
810
- WHEN BOOL_OR(o.cursor !~ '^\\d+$') THEN MAX(o.cursor COLLATE "C")
811
- ELSE MAX(CASE WHEN o.cursor ~ '^\\d+$' THEN o.cursor::bigint END)::text
812
- END as cursor
727
+ `SELECT MAX(o.cursor::bigint)::text as cursor
813
728
  FROM "${this.config.schema}"."_sync_obj_runs" o
814
729
  WHERE o."_account_id" = $1
815
730
  AND o.object = $2
@@ -1094,269 +1009,6 @@ function hashApiKey(apiKey) {
1094
1009
  return (0, import_crypto.createHash)("sha256").update(apiKey).digest("hex");
1095
1010
  }
1096
1011
 
1097
- // src/sigma/sigmaApi.ts
1098
- var import_papaparse = __toESM(require("papaparse"), 1);
1099
- var import_stripe2 = __toESM(require("stripe"), 1);
1100
- var STRIPE_FILES_BASE = "https://files.stripe.com/v1";
1101
- function sleep2(ms) {
1102
- return new Promise((resolve) => setTimeout(resolve, ms));
1103
- }
1104
- function parseCsvObjects(csv) {
1105
- const input = csv.replace(/^\uFEFF/, "");
1106
- const parsed = import_papaparse.default.parse(input, {
1107
- header: true,
1108
- skipEmptyLines: "greedy"
1109
- });
1110
- if (parsed.errors.length > 0) {
1111
- throw new Error(`Failed to parse Sigma CSV: ${parsed.errors[0]?.message ?? "unknown error"}`);
1112
- }
1113
- return parsed.data.filter((row) => row && Object.keys(row).length > 0).map(
1114
- (row) => Object.fromEntries(
1115
- Object.entries(row).map(([k, v]) => [k, v == null || v === "" ? null : String(v)])
1116
- )
1117
- );
1118
- }
1119
- function normalizeSigmaTimestampToIso(value) {
1120
- const v = value.trim();
1121
- if (!v) return null;
1122
- const hasExplicitTz = /z$|[+-]\d{2}:?\d{2}$/i.test(v);
1123
- const isoish = v.includes("T") ? v : v.replace(" ", "T");
1124
- const candidate = hasExplicitTz ? isoish : `${isoish}Z`;
1125
- const d = new Date(candidate);
1126
- if (Number.isNaN(d.getTime())) return null;
1127
- return d.toISOString();
1128
- }
1129
- async function fetchStripeText(url, apiKey, options) {
1130
- const res = await fetch(url, {
1131
- ...options,
1132
- headers: {
1133
- ...options.headers ?? {},
1134
- Authorization: `Bearer ${apiKey}`
1135
- }
1136
- });
1137
- const text = await res.text();
1138
- if (!res.ok) {
1139
- throw new Error(`Sigma file download error (${res.status}) for ${url}: ${text}`);
1140
- }
1141
- return text;
1142
- }
1143
- async function runSigmaQueryAndDownloadCsv(params) {
1144
- const pollTimeoutMs = params.pollTimeoutMs ?? 5 * 60 * 1e3;
1145
- const pollIntervalMs = params.pollIntervalMs ?? 2e3;
1146
- const stripe = new import_stripe2.default(params.apiKey);
1147
- const created = await stripe.rawRequest("POST", "/v1/sigma/query_runs", {
1148
- sql: params.sql
1149
- });
1150
- const queryRunId = created.id;
1151
- const start = Date.now();
1152
- let current = created;
1153
- while (current.status === "running") {
1154
- if (Date.now() - start > pollTimeoutMs) {
1155
- throw new Error(`Sigma query run timed out after ${pollTimeoutMs}ms: ${queryRunId}`);
1156
- }
1157
- await sleep2(pollIntervalMs);
1158
- current = await stripe.rawRequest(
1159
- "GET",
1160
- `/v1/sigma/query_runs/${queryRunId}`,
1161
- {}
1162
- );
1163
- }
1164
- if (current.status !== "succeeded") {
1165
- throw new Error(
1166
- `Sigma query run did not succeed (status=${current.status}) id=${queryRunId} error=${JSON.stringify(
1167
- current.error
1168
- )}`
1169
- );
1170
- }
1171
- const fileId = current.result?.file;
1172
- if (!fileId) {
1173
- throw new Error(`Sigma query run succeeded but result.file is missing (id=${queryRunId})`);
1174
- }
1175
- const csv = await fetchStripeText(
1176
- `${STRIPE_FILES_BASE}/files/${fileId}/contents`,
1177
- params.apiKey,
1178
- { method: "GET" }
1179
- );
1180
- return { queryRunId, fileId, csv };
1181
- }
1182
-
1183
- // src/sigma/sigmaIngestionConfigs.ts
1184
- var SIGMA_INGESTION_CONFIGS = {
1185
- subscription_item_change_events_v2_beta: {
1186
- sigmaTable: "subscription_item_change_events_v2_beta",
1187
- destinationTable: "subscription_item_change_events_v2_beta",
1188
- pageSize: 1e4,
1189
- cursor: {
1190
- version: 1,
1191
- columns: [
1192
- { column: "event_timestamp", type: "timestamp" },
1193
- { column: "event_type", type: "string" },
1194
- { column: "subscription_item_id", type: "string" }
1195
- ]
1196
- },
1197
- upsert: {
1198
- conflictTarget: ["_account_id", "event_timestamp", "event_type", "subscription_item_id"],
1199
- extraColumns: [
1200
- { column: "event_timestamp", pgType: "timestamptz", entryKey: "event_timestamp" },
1201
- { column: "event_type", pgType: "text", entryKey: "event_type" },
1202
- { column: "subscription_item_id", pgType: "text", entryKey: "subscription_item_id" }
1203
- ]
1204
- }
1205
- },
1206
- exchange_rates_from_usd: {
1207
- sigmaTable: "exchange_rates_from_usd",
1208
- destinationTable: "exchange_rates_from_usd",
1209
- pageSize: 1e4,
1210
- cursor: {
1211
- version: 1,
1212
- columns: [
1213
- { column: "date", type: "string" },
1214
- { column: "sell_currency", type: "string" }
1215
- ]
1216
- },
1217
- upsert: {
1218
- conflictTarget: ["_account_id", "date", "sell_currency"],
1219
- extraColumns: [
1220
- { column: "date", pgType: "date", entryKey: "date" },
1221
- { column: "sell_currency", pgType: "text", entryKey: "sell_currency" }
1222
- ]
1223
- }
1224
- }
1225
- };
1226
-
1227
- // src/sigma/sigmaIngestion.ts
1228
- var SIGMA_CURSOR_DELIM = "";
1229
- function escapeSigmaSqlStringLiteral(value) {
1230
- return value.replace(/'/g, "''");
1231
- }
1232
- function formatSigmaTimestampForSqlLiteral(date) {
1233
- return date.toISOString().replace("T", " ").replace("Z", "");
1234
- }
1235
- function decodeSigmaCursorValues(spec, cursor) {
1236
- const prefix = `v${spec.version}${SIGMA_CURSOR_DELIM}`;
1237
- if (!cursor.startsWith(prefix)) {
1238
- throw new Error(
1239
- `Unrecognized Sigma cursor format (expected prefix ${JSON.stringify(prefix)}): ${cursor}`
1240
- );
1241
- }
1242
- const parts = cursor.split(SIGMA_CURSOR_DELIM);
1243
- const expected = 1 + spec.columns.length;
1244
- if (parts.length !== expected) {
1245
- throw new Error(`Malformed Sigma cursor: expected ${expected} parts, got ${parts.length}`);
1246
- }
1247
- return parts.slice(1);
1248
- }
1249
- function encodeSigmaCursor(spec, values) {
1250
- if (values.length !== spec.columns.length) {
1251
- throw new Error(
1252
- `Cannot encode Sigma cursor: expected ${spec.columns.length} values, got ${values.length}`
1253
- );
1254
- }
1255
- for (const v of values) {
1256
- if (v.includes(SIGMA_CURSOR_DELIM)) {
1257
- throw new Error("Cannot encode Sigma cursor: value contains delimiter character");
1258
- }
1259
- }
1260
- return [`v${spec.version}`, ...values].join(SIGMA_CURSOR_DELIM);
1261
- }
1262
- function sigmaSqlLiteralForCursorValue(spec, rawValue) {
1263
- switch (spec.type) {
1264
- case "timestamp": {
1265
- const d = new Date(rawValue);
1266
- if (Number.isNaN(d.getTime())) {
1267
- throw new Error(`Invalid timestamp cursor value for ${spec.column}: ${rawValue}`);
1268
- }
1269
- return `timestamp '${formatSigmaTimestampForSqlLiteral(d)}'`;
1270
- }
1271
- case "number": {
1272
- if (!/^-?\d+(\.\d+)?$/.test(rawValue)) {
1273
- throw new Error(`Invalid numeric cursor value for ${spec.column}: ${rawValue}`);
1274
- }
1275
- return rawValue;
1276
- }
1277
- case "string":
1278
- return `'${escapeSigmaSqlStringLiteral(rawValue)}'`;
1279
- }
1280
- }
1281
- function buildSigmaCursorWhereClause(spec, cursorValues) {
1282
- if (cursorValues.length !== spec.columns.length) {
1283
- throw new Error(
1284
- `Cannot build Sigma cursor predicate: expected ${spec.columns.length} values, got ${cursorValues.length}`
1285
- );
1286
- }
1287
- const cols = spec.columns.map((c) => c.column);
1288
- const lits = spec.columns.map((c, i) => sigmaSqlLiteralForCursorValue(c, cursorValues[i] ?? ""));
1289
- const ors = [];
1290
- for (let i = 0; i < cols.length; i++) {
1291
- const ands = [];
1292
- for (let j = 0; j < i; j++) {
1293
- ands.push(`${cols[j]} = ${lits[j]}`);
1294
- }
1295
- ands.push(`${cols[i]} > ${lits[i]}`);
1296
- ors.push(`(${ands.join(" AND ")})`);
1297
- }
1298
- return ors.join(" OR ");
1299
- }
1300
- function buildSigmaQuery(config, cursor) {
1301
- const select = config.select === void 0 || config.select === "*" ? "*" : config.select.join(", ");
1302
- const whereParts = [];
1303
- if (config.additionalWhere) {
1304
- whereParts.push(`(${config.additionalWhere})`);
1305
- }
1306
- if (cursor) {
1307
- const values = decodeSigmaCursorValues(config.cursor, cursor);
1308
- const predicate = buildSigmaCursorWhereClause(config.cursor, values);
1309
- whereParts.push(`(${predicate})`);
1310
- }
1311
- const whereClause = whereParts.length > 0 ? `WHERE ${whereParts.join(" AND ")}` : "";
1312
- const orderBy = config.cursor.columns.map((c) => c.column).join(", ");
1313
- return [
1314
- `SELECT ${select} FROM ${config.sigmaTable}`,
1315
- whereClause,
1316
- `ORDER BY ${orderBy} ASC`,
1317
- `LIMIT ${config.pageSize}`
1318
- ].filter(Boolean).join(" ");
1319
- }
1320
- function defaultSigmaRowToEntry(config, row) {
1321
- const out = { ...row };
1322
- for (const col of config.cursor.columns) {
1323
- const raw = row[col.column];
1324
- if (raw == null) {
1325
- throw new Error(`Sigma row missing required cursor column: ${col.column}`);
1326
- }
1327
- if (col.type === "timestamp") {
1328
- const normalized = normalizeSigmaTimestampToIso(raw);
1329
- if (!normalized) {
1330
- throw new Error(`Sigma row has invalid timestamp for ${col.column}: ${raw}`);
1331
- }
1332
- out[col.column] = normalized;
1333
- } else if (col.type === "string") {
1334
- const v = raw.trim();
1335
- if (!v) {
1336
- throw new Error(`Sigma row has empty string for required cursor column: ${col.column}`);
1337
- }
1338
- out[col.column] = v;
1339
- } else {
1340
- const v = raw.trim();
1341
- if (!v) {
1342
- throw new Error(`Sigma row has empty value for required cursor column: ${col.column}`);
1343
- }
1344
- out[col.column] = v;
1345
- }
1346
- }
1347
- return out;
1348
- }
1349
- function sigmaCursorFromEntry(config, entry) {
1350
- const values = config.cursor.columns.map((c) => {
1351
- const raw = entry[c.column];
1352
- if (raw == null) {
1353
- throw new Error(`Cannot build cursor: entry missing ${c.column}`);
1354
- }
1355
- return String(raw);
1356
- });
1357
- return encodeSigmaCursor(config.cursor, values);
1358
- }
1359
-
1360
1012
  // src/stripeSync.ts
1361
1013
  function getUniqueIds(entries, key) {
1362
1014
  const set = new Set(
@@ -1367,7 +1019,7 @@ function getUniqueIds(entries, key) {
1367
1019
  var StripeSync = class {
1368
1020
  constructor(config) {
1369
1021
  this.config = config;
1370
- const baseStripe = new import_stripe3.default(config.stripeSecretKey, {
1022
+ const baseStripe = new import_stripe2.default(config.stripeSecretKey, {
1371
1023
  // https://github.com/stripe/stripe-node#configuration
1372
1024
  // @ts-ignore
1373
1025
  apiVersion: config.stripeApiVersion,
@@ -1768,17 +1420,6 @@ var StripeSync = class {
1768
1420
  listFn: (p) => this.stripe.checkout.sessions.list(p),
1769
1421
  upsertFn: (items, id) => this.upsertCheckoutSessions(items, id),
1770
1422
  supportsCreatedFilter: true
1771
- },
1772
- // Sigma-backed resources
1773
- subscription_item_change_events_v2_beta: {
1774
- order: 18,
1775
- supportsCreatedFilter: false,
1776
- sigma: SIGMA_INGESTION_CONFIGS.subscription_item_change_events_v2_beta
1777
- },
1778
- exchange_rates_from_usd: {
1779
- order: 19,
1780
- supportsCreatedFilter: false,
1781
- sigma: SIGMA_INGESTION_CONFIGS.exchange_rates_from_usd
1782
1423
  }
1783
1424
  };
1784
1425
  async processEvent(event) {
@@ -1811,13 +1452,7 @@ var StripeSync = class {
1811
1452
  * Order is determined by the `order` field in resourceRegistry.
1812
1453
  */
1813
1454
  getSupportedSyncObjects() {
1814
- const all = Object.entries(this.resourceRegistry).sort(([, a], [, b]) => a.order - b.order).map(([key]) => key);
1815
- if (!this.config.enableSigmaSync) {
1816
- return all.filter(
1817
- (o) => o !== "subscription_item_change_events_v2_beta" && o !== "exchange_rates_from_usd"
1818
- );
1819
- }
1820
- return all;
1455
+ return Object.entries(this.resourceRegistry).sort(([, a], [, b]) => a.order - b.order).map(([key]) => key);
1821
1456
  }
1822
1457
  // Event handler methods
1823
1458
  async handleChargeEvent(event, accountId) {
@@ -1896,7 +1531,7 @@ var StripeSync = class {
1896
1531
  );
1897
1532
  await this.upsertProducts([product], accountId, this.getSyncTimestamp(event, refetched));
1898
1533
  } catch (err) {
1899
- if (err instanceof import_stripe3.default.errors.StripeAPIError && err.code === "resource_missing") {
1534
+ if (err instanceof import_stripe2.default.errors.StripeAPIError && err.code === "resource_missing") {
1900
1535
  const product = event.data.object;
1901
1536
  await this.deleteProduct(product.id);
1902
1537
  } else {
@@ -1916,7 +1551,7 @@ var StripeSync = class {
1916
1551
  );
1917
1552
  await this.upsertPrices([price], accountId, false, this.getSyncTimestamp(event, refetched));
1918
1553
  } catch (err) {
1919
- if (err instanceof import_stripe3.default.errors.StripeAPIError && err.code === "resource_missing") {
1554
+ if (err instanceof import_stripe2.default.errors.StripeAPIError && err.code === "resource_missing") {
1920
1555
  const price = event.data.object;
1921
1556
  await this.deletePrice(price.id);
1922
1557
  } else {
@@ -1936,7 +1571,7 @@ var StripeSync = class {
1936
1571
  );
1937
1572
  await this.upsertPlans([plan], accountId, false, this.getSyncTimestamp(event, refetched));
1938
1573
  } catch (err) {
1939
- if (err instanceof import_stripe3.default.errors.StripeAPIError && err.code === "resource_missing") {
1574
+ if (err instanceof import_stripe2.default.errors.StripeAPIError && err.code === "resource_missing") {
1940
1575
  const plan = event.data.object;
1941
1576
  await this.deletePlan(plan.id);
1942
1577
  } else {
@@ -2183,10 +1818,10 @@ var StripeSync = class {
2183
1818
  let cursor = null;
2184
1819
  if (!params?.created) {
2185
1820
  if (objRun?.cursor) {
2186
- cursor = objRun.cursor;
1821
+ cursor = parseInt(objRun.cursor);
2187
1822
  } else {
2188
1823
  const lastCursor = await this.postgresClient.getLastCompletedCursor(accountId, resourceName);
2189
- cursor = lastCursor ?? null;
1824
+ cursor = lastCursor ? parseInt(lastCursor) : null;
2190
1825
  }
2191
1826
  }
2192
1827
  const result = await this.fetchOnePage(
@@ -2241,18 +1876,9 @@ var StripeSync = class {
2241
1876
  throw new Error(`Unsupported object type for processNext: ${object}`);
2242
1877
  }
2243
1878
  try {
2244
- if (config.sigma) {
2245
- return await this.fetchOneSigmaPage(
2246
- accountId,
2247
- resourceName,
2248
- runStartedAt,
2249
- cursor,
2250
- config.sigma
2251
- );
2252
- }
2253
1879
  const listParams = { limit };
2254
1880
  if (config.supportsCreatedFilter) {
2255
- const created = params?.created ?? (cursor && /^\d+$/.test(cursor) ? { gte: Number.parseInt(cursor, 10) } : void 0);
1881
+ const created = params?.created ?? (cursor ? { gte: cursor } : void 0);
2256
1882
  if (created) {
2257
1883
  listParams.created = created;
2258
1884
  }
@@ -2297,97 +1923,6 @@ var StripeSync = class {
2297
1923
  throw error;
2298
1924
  }
2299
1925
  }
2300
- async getSigmaFallbackCursorFromDestination(accountId, sigmaConfig) {
2301
- const cursorCols = sigmaConfig.cursor.columns;
2302
- const selectCols = cursorCols.map((c) => `"${c.column}"`).join(", ");
2303
- const orderBy = cursorCols.map((c) => `"${c.column}" DESC`).join(", ");
2304
- const result = await this.postgresClient.query(
2305
- `SELECT ${selectCols}
2306
- FROM "stripe"."${sigmaConfig.destinationTable}"
2307
- WHERE "_account_id" = $1
2308
- ORDER BY ${orderBy}
2309
- LIMIT 1`,
2310
- [accountId]
2311
- );
2312
- if (result.rows.length === 0) return null;
2313
- const row = result.rows[0];
2314
- const entryForCursor = {};
2315
- for (const c of cursorCols) {
2316
- const v = row[c.column];
2317
- if (v == null) {
2318
- throw new Error(
2319
- `Sigma fallback cursor query returned null for ${sigmaConfig.destinationTable}.${c.column}`
2320
- );
2321
- }
2322
- if (c.type === "timestamp") {
2323
- const d = v instanceof Date ? v : new Date(String(v));
2324
- if (Number.isNaN(d.getTime())) {
2325
- throw new Error(
2326
- `Sigma fallback cursor query returned invalid timestamp for ${sigmaConfig.destinationTable}.${c.column}: ${String(
2327
- v
2328
- )}`
2329
- );
2330
- }
2331
- entryForCursor[c.column] = d.toISOString();
2332
- } else {
2333
- entryForCursor[c.column] = String(v);
2334
- }
2335
- }
2336
- return sigmaCursorFromEntry(sigmaConfig, entryForCursor);
2337
- }
2338
- async fetchOneSigmaPage(accountId, resourceName, runStartedAt, cursor, sigmaConfig) {
2339
- if (!this.config.stripeSecretKey) {
2340
- throw new Error("Sigma sync requested but stripeSecretKey is not configured.");
2341
- }
2342
- if (resourceName !== sigmaConfig.destinationTable) {
2343
- throw new Error(
2344
- `Sigma sync config mismatch: resourceName=${resourceName} destinationTable=${sigmaConfig.destinationTable}`
2345
- );
2346
- }
2347
- const effectiveCursor = cursor ?? await this.getSigmaFallbackCursorFromDestination(accountId, sigmaConfig);
2348
- const sigmaSql = buildSigmaQuery(sigmaConfig, effectiveCursor);
2349
- this.config.logger?.info(
2350
- { object: resourceName, pageSize: sigmaConfig.pageSize, hasCursor: Boolean(effectiveCursor) },
2351
- "Sigma sync: running query"
2352
- );
2353
- const { queryRunId, fileId, csv } = await runSigmaQueryAndDownloadCsv({
2354
- apiKey: this.config.stripeSecretKey,
2355
- sql: sigmaSql,
2356
- logger: this.config.logger
2357
- });
2358
- const rows = parseCsvObjects(csv);
2359
- if (rows.length === 0) {
2360
- await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
2361
- return { processed: 0, hasMore: false, runStartedAt };
2362
- }
2363
- const entries = rows.map(
2364
- (row) => defaultSigmaRowToEntry(sigmaConfig, row)
2365
- );
2366
- this.config.logger?.info(
2367
- { object: resourceName, rows: entries.length, queryRunId, fileId },
2368
- "Sigma sync: upserting rows"
2369
- );
2370
- await this.postgresClient.upsertManyWithTimestampProtection(
2371
- entries,
2372
- resourceName,
2373
- accountId,
2374
- void 0,
2375
- sigmaConfig.upsert
2376
- );
2377
- await this.postgresClient.incrementObjectProgress(
2378
- accountId,
2379
- runStartedAt,
2380
- resourceName,
2381
- entries.length
2382
- );
2383
- const newCursor = sigmaCursorFromEntry(sigmaConfig, entries[entries.length - 1]);
2384
- await this.postgresClient.updateObjectCursor(accountId, runStartedAt, resourceName, newCursor);
2385
- const hasMore = rows.length === sigmaConfig.pageSize;
2386
- if (!hasMore) {
2387
- await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
2388
- }
2389
- return { processed: entries.length, hasMore, runStartedAt };
2390
- }
2391
1926
  /**
2392
1927
  * Process all pages for all (or specified) object types until complete.
2393
1928
  *
@@ -2516,12 +2051,6 @@ var StripeSync = class {
2516
2051
  case "checkout_sessions":
2517
2052
  results.checkoutSessions = result;
2518
2053
  break;
2519
- case "subscription_item_change_events_v2_beta":
2520
- results.subscriptionItemChangeEventsV2Beta = result;
2521
- break;
2522
- case "exchange_rates_from_usd":
2523
- results.exchangeRatesFromUsd = result;
2524
- break;
2525
2054
  }
2526
2055
  }
2527
2056
  }
@@ -4122,7 +3651,7 @@ var stripe_setup_default = "import { StripeSync, runMigrations } from 'npm:strip
4122
3651
  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";
4123
3652
 
4124
3653
  // raw-ts:/home/runner/work/sync-engine/sync-engine/packages/sync-engine/src/supabase/edge-functions/stripe-worker.ts
4125
- 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";
3654
+ var stripe_worker_default = "/**\n * Stripe Sync Worker\n *\n * Triggered by pg_cron at a configurable interval (default: 60 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";
4126
3655
 
4127
3656
  // src/supabase/edge-function-code.ts
4128
3657
  var setupFunctionCode = stripe_setup_default;
@@ -4130,7 +3659,7 @@ var webhookFunctionCode = stripe_webhook_default;
4130
3659
  var workerFunctionCode = stripe_worker_default;
4131
3660
 
4132
3661
  // src/supabase/supabase.ts
4133
- var import_stripe4 = __toESM(require("stripe"), 1);
3662
+ var import_stripe3 = __toESM(require("stripe"), 1);
4134
3663
  var STRIPE_SCHEMA_COMMENT_PREFIX = "stripe-sync";
4135
3664
  var INSTALLATION_STARTED_SUFFIX = "installation:started";
4136
3665
  var INSTALLATION_ERROR_SUFFIX = "installation:error";
@@ -4196,8 +3725,29 @@ var SupabaseSetupClient = class {
4196
3725
  }
4197
3726
  /**
4198
3727
  * Setup pg_cron job to invoke worker function
3728
+ * @param intervalSeconds - How often to run the worker (default: 60 seconds)
4199
3729
  */
4200
- async setupPgCronJob() {
3730
+ async setupPgCronJob(intervalSeconds = 60) {
3731
+ if (!Number.isInteger(intervalSeconds) || intervalSeconds < 1) {
3732
+ throw new Error(`Invalid interval: ${intervalSeconds}. Must be a positive integer.`);
3733
+ }
3734
+ let schedule;
3735
+ if (intervalSeconds < 60) {
3736
+ schedule = `${intervalSeconds} seconds`;
3737
+ } else if (intervalSeconds % 60 === 0) {
3738
+ const minutes = intervalSeconds / 60;
3739
+ if (minutes < 60) {
3740
+ schedule = `*/${minutes} * * * *`;
3741
+ } else {
3742
+ throw new Error(
3743
+ `Invalid interval: ${intervalSeconds}. Intervals >= 3600 seconds (1 hour) are not supported. Use a value between 1-3599 seconds.`
3744
+ );
3745
+ }
3746
+ } else {
3747
+ throw new Error(
3748
+ `Invalid interval: ${intervalSeconds}. Must be either 1-59 seconds or a multiple of 60 (e.g., 60, 120, 180).`
3749
+ );
3750
+ }
4201
3751
  const serviceRoleKey = await this.getServiceRoleKey();
4202
3752
  const escapedServiceRoleKey = serviceRoleKey.replace(/'/g, "''");
4203
3753
  const sql3 = `
@@ -4225,11 +3775,11 @@ var SupabaseSetupClient = class {
4225
3775
  SELECT 1 FROM cron.job WHERE jobname = 'stripe-sync-scheduler'
4226
3776
  );
4227
3777
 
4228
- -- Create job to invoke worker every 10 seconds
3778
+ -- Create job to invoke worker at configured interval
4229
3779
  -- Worker reads from pgmq, enqueues objects if empty, and processes sync work
4230
3780
  SELECT cron.schedule(
4231
3781
  'stripe-sync-worker',
4232
- '10 seconds',
3782
+ '${schedule}',
4233
3783
  $$
4234
3784
  SELECT net.http_post(
4235
3785
  url := 'https://${this.projectRef}.${this.projectBaseUrl}/functions/v1/stripe-worker',
@@ -4390,7 +3940,7 @@ var SupabaseSetupClient = class {
4390
3940
  * Removes all Edge Functions, secrets, database resources, and Stripe webhooks
4391
3941
  */
4392
3942
  async uninstall(stripeSecretKey) {
4393
- const stripe = new import_stripe4.default(stripeSecretKey, { apiVersion: "2025-02-24.acacia" });
3943
+ const stripe = new import_stripe3.default(stripeSecretKey, { apiVersion: "2025-02-24.acacia" });
4394
3944
  try {
4395
3945
  try {
4396
3946
  const webhookResult = await this.runSQL(`
@@ -4457,7 +4007,7 @@ var SupabaseSetupClient = class {
4457
4007
  `from 'npm:stripe-experiment-sync@${version}'`
4458
4008
  );
4459
4009
  }
4460
- async install(stripeKey, packageVersion) {
4010
+ async install(stripeKey, packageVersion, workerIntervalSeconds) {
4461
4011
  const trimmedStripeKey = stripeKey.trim();
4462
4012
  if (!trimmedStripeKey.startsWith("sk_") && !trimmedStripeKey.startsWith("rk_")) {
4463
4013
  throw new Error('Stripe key should start with "sk_" or "rk_"');
@@ -4481,7 +4031,7 @@ var SupabaseSetupClient = class {
4481
4031
  if (!setupResult.success) {
4482
4032
  throw new Error(`Setup failed: ${setupResult.error}`);
4483
4033
  }
4484
- await this.setupPgCronJob();
4034
+ await this.setupPgCronJob(workerIntervalSeconds);
4485
4035
  await this.updateInstallationComment(
4486
4036
  `${STRIPE_SCHEMA_COMMENT_PREFIX} v${package_default.version} ${INSTALLATION_INSTALLED_SUFFIX}`
4487
4037
  );
@@ -4494,14 +4044,20 @@ var SupabaseSetupClient = class {
4494
4044
  }
4495
4045
  };
4496
4046
  async function install(params) {
4497
- const { supabaseAccessToken, supabaseProjectRef, stripeKey, packageVersion } = params;
4047
+ const {
4048
+ supabaseAccessToken,
4049
+ supabaseProjectRef,
4050
+ stripeKey,
4051
+ packageVersion,
4052
+ workerIntervalSeconds
4053
+ } = params;
4498
4054
  const client = new SupabaseSetupClient({
4499
4055
  accessToken: supabaseAccessToken,
4500
4056
  projectRef: supabaseProjectRef,
4501
4057
  projectBaseUrl: params.baseProjectUrl,
4502
4058
  managementApiBaseUrl: params.baseManagementApiUrl
4503
4059
  });
4504
- await client.install(stripeKey, packageVersion);
4060
+ await client.install(stripeKey, packageVersion, workerIntervalSeconds);
4505
4061
  }
4506
4062
  async function uninstall(params) {
4507
4063
  const { supabaseAccessToken, supabaseProjectRef, stripeKey } = params;
@@ -4536,9 +4092,7 @@ var VALID_SYNC_OBJECTS = [
4536
4092
  "credit_note",
4537
4093
  "early_fraud_warning",
4538
4094
  "refund",
4539
- "checkout_sessions",
4540
- "subscription_item_change_events_v2_beta",
4541
- "exchange_rates_from_usd"
4095
+ "checkout_sessions"
4542
4096
  ];
4543
4097
  async function backfillCommand(options, entityName) {
4544
4098
  let stripeSync = null;
@@ -4567,8 +4121,8 @@ async function backfillCommand(options, entityName) {
4567
4121
  if (!input || input.trim() === "") {
4568
4122
  return "Stripe API key is required";
4569
4123
  }
4570
- if (!input.startsWith("sk_") && !input.startsWith("rk_")) {
4571
- return 'Stripe API key should start with "sk_" or "rk_"';
4124
+ if (!input.startsWith("sk_")) {
4125
+ return 'Stripe API key should start with "sk_"';
4572
4126
  }
4573
4127
  return true;
4574
4128
  }
@@ -4625,7 +4179,6 @@ async function backfillCommand(options, entityName) {
4625
4179
  stripeSync = new StripeSync({
4626
4180
  databaseUrl: config.databaseUrl,
4627
4181
  stripeSecretKey: config.stripeApiKey,
4628
- enableSigmaSync: process.env.ENABLE_SIGMA_SYNC === "true",
4629
4182
  stripeApiVersion: process.env.STRIPE_API_VERSION || "2020-08-27",
4630
4183
  autoExpandLists: process.env.AUTO_EXPAND_LISTS === "true",
4631
4184
  backfillRelatedEntities: process.env.BACKFILL_RELATED_ENTITIES !== "false",
@@ -4789,7 +4342,6 @@ Mode: ${modeLabel}`));
4789
4342
  stripeSync = new StripeSync({
4790
4343
  databaseUrl: config.databaseUrl,
4791
4344
  stripeSecretKey: config.stripeApiKey,
4792
- enableSigmaSync: config.enableSigmaSync,
4793
4345
  stripeApiVersion: process.env.STRIPE_API_VERSION || "2020-08-27",
4794
4346
  autoExpandLists: process.env.AUTO_EXPAND_LISTS === "true",
4795
4347
  backfillRelatedEntities: process.env.BACKFILL_RELATED_ENTITIES !== "false",
@@ -4937,8 +4489,7 @@ async function installCommand(options) {
4937
4489
  mask: "*",
4938
4490
  validate: (input) => {
4939
4491
  if (!input.trim()) return "Stripe key is required";
4940
- if (!input.startsWith("sk_") && !input.startsWith("rk_"))
4941
- return 'Stripe key should start with "sk_" or "rk_"';
4492
+ if (!input.startsWith("sk_")) return 'Stripe key should start with "sk_"';
4942
4493
  return true;
4943
4494
  }
4944
4495
  });
@@ -4957,7 +4508,8 @@ async function installCommand(options) {
4957
4508
  supabaseAccessToken: accessToken,
4958
4509
  supabaseProjectRef: projectRef,
4959
4510
  stripeKey,
4960
- packageVersion: options.packageVersion
4511
+ packageVersion: options.packageVersion,
4512
+ workerIntervalSeconds: options.workerInterval
4961
4513
  });
4962
4514
  console.log(import_chalk3.default.cyan("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
4963
4515
  console.log(import_chalk3.default.cyan.bold(" Installation Complete!"));
@@ -5008,8 +4560,7 @@ async function uninstallCommand(options) {
5008
4560
  mask: "*",
5009
4561
  validate: (input) => {
5010
4562
  if (!input.trim()) return "Stripe key is required";
5011
- if (!input.startsWith("sk_") && !input.startsWith("rk_"))
5012
- return 'Stripe key should start with "sk_" or "rk_"';
4563
+ if (!input.startsWith("sk_")) return 'Stripe key should start with "sk_"';
5013
4564
  return true;
5014
4565
  }
5015
4566
  });