@qazuor/qzpay-drizzle 1.7.8 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -130,13 +130,13 @@ function firstOrThrow(results, entityType, id) {
130
130
  }
131
131
  async function updateWithVersionHelper(db, table, id, expectedVersion, updateData, options) {
132
132
  const { entityType, entityId, includeSoftDeleted = false, transform } = options;
133
- const { and: and19, eq: eq18, isNull: isNull13 } = await import('drizzle-orm');
133
+ const { and: and20, eq: eq19, isNull: isNull13 } = await import('drizzle-orm');
134
134
  const { generateVersion: generateVersion2 } = await Promise.resolve().then(() => (init_optimistic_locking(), optimistic_locking_exports));
135
- const conditions = [eq18(table.id, id), eq18(table.version, expectedVersion)];
135
+ const conditions = [eq19(table.id, id), eq19(table.version, expectedVersion)];
136
136
  if (!includeSoftDeleted && "deletedAt" in table) {
137
137
  conditions.push(isNull13(table.deletedAt));
138
138
  }
139
- const whereClause = and19(...conditions);
139
+ const whereClause = and20(...conditions);
140
140
  if (!whereClause) {
141
141
  throw new Error("Failed to build WHERE clause for version update");
142
142
  }
@@ -150,7 +150,7 @@ async function updateWithVersionHelper(db, table, id, expectedVersion, updateDat
150
150
  result = await db.update(table).set(dataWithVersion).where(whereClause).returning();
151
151
  } catch (_error) {
152
152
  try {
153
- const existsQuery = await db.select().from(table).where(includeSoftDeleted ? eq18(table.id, id) : and19(eq18(table.id, id), isNull13(table.deletedAt))).limit(1);
153
+ const existsQuery = await db.select().from(table).where(includeSoftDeleted ? eq19(table.id, id) : and20(eq19(table.id, id), isNull13(table.deletedAt))).limit(1);
154
154
  if (existsQuery.length > 0) {
155
155
  throw new exports.QZPayOptimisticLockError(entityType, entityId);
156
156
  }
@@ -159,7 +159,7 @@ async function updateWithVersionHelper(db, table, id, expectedVersion, updateDat
159
159
  throw new exports.QZPayEntityNotFoundError(entityType, entityId);
160
160
  }
161
161
  if (result.length === 0) {
162
- const existsQuery = await db.select().from(table).where(includeSoftDeleted ? eq18(table.id, id) : and19(eq18(table.id, id), isNull13(table.deletedAt))).limit(1);
162
+ const existsQuery = await db.select().from(table).where(includeSoftDeleted ? eq19(table.id, id) : and20(eq19(table.id, id), isNull13(table.deletedAt))).limit(1);
163
163
  if (existsQuery.length > 0) {
164
164
  throw new exports.QZPayOptimisticLockError(entityType, entityId);
165
165
  }
@@ -1107,6 +1107,48 @@ function mapCorePromoCodeUpdateToDrizzle(update) {
1107
1107
  return result;
1108
1108
  }
1109
1109
 
1110
+ // src/mappers/subscription-polling-job.mapper.ts
1111
+ var POLLING_JOB_DEFAULTS = {
1112
+ initialDelayMs: 3e4,
1113
+ maxAttempts: 60
1114
+ };
1115
+ function mapDrizzlePollingJobToCore(row) {
1116
+ return {
1117
+ id: row.id,
1118
+ subscriptionId: row.subscriptionId,
1119
+ provider: row.provider,
1120
+ providerResourceId: row.providerResourceId,
1121
+ resourceType: row.resourceType,
1122
+ status: row.status,
1123
+ attempts: row.attempts,
1124
+ maxAttempts: row.maxAttempts,
1125
+ nextPollAt: row.nextPollAt,
1126
+ lastPolledAt: row.lastPolledAt ?? null,
1127
+ lastProviderStatus: row.lastProviderStatus ?? null,
1128
+ lastError: row.lastError ?? null,
1129
+ metadata: row.metadata ?? {},
1130
+ createdAt: row.createdAt,
1131
+ updatedAt: row.updatedAt,
1132
+ completedAt: row.completedAt ?? null,
1133
+ version: row.version
1134
+ };
1135
+ }
1136
+ function mapPollingScheduleInputToDrizzleInsert(input) {
1137
+ const initialDelayMs = input.initialDelayMs ?? POLLING_JOB_DEFAULTS.initialDelayMs;
1138
+ const nextPollAt = new Date(Date.now() + initialDelayMs);
1139
+ return {
1140
+ subscriptionId: input.subscriptionId,
1141
+ provider: input.provider,
1142
+ providerResourceId: input.providerResourceId,
1143
+ resourceType: input.resourceType ?? "subscription",
1144
+ status: "pending",
1145
+ attempts: 0,
1146
+ maxAttempts: input.maxAttempts ?? POLLING_JOB_DEFAULTS.maxAttempts,
1147
+ nextPollAt,
1148
+ metadata: input.metadata ?? {}
1149
+ };
1150
+ }
1151
+
1110
1152
  // src/mappers/subscription.mapper.ts
1111
1153
  function mapDrizzleSubscriptionToCore(drizzle3) {
1112
1154
  const providerSubscriptionIds = {};
@@ -1890,6 +1932,93 @@ var billingPrices = pgCore.pgTable(
1890
1932
  );
1891
1933
  var billingPriceInsertSchema = drizzleZod.createInsertSchema(billingPrices);
1892
1934
  var billingPriceSelectSchema = drizzleZod.createSelectSchema(billingPrices);
1935
+ var billingSubscriptionPollingJobs = pgCore.pgTable(
1936
+ "billing_subscription_polling_jobs",
1937
+ {
1938
+ id: pgCore.uuid("id").primaryKey().defaultRandom(),
1939
+ subscriptionId: pgCore.uuid("subscription_id").notNull().references(() => billingSubscriptions.id, { onDelete: "cascade" }),
1940
+ /**
1941
+ * Provider identifier, e.g. `mercadopago`. Future-proofed so
1942
+ * Stripe or other adapters can opt in to polling if needed.
1943
+ */
1944
+ provider: pgCore.varchar("provider", { length: 50 }).notNull(),
1945
+ /**
1946
+ * Provider-side resource id (e.g. MP preapproval id, MP preference
1947
+ * id) that the poller uses to query the provider's REST endpoint.
1948
+ * Interpretation depends on {@link resourceType}.
1949
+ */
1950
+ providerResourceId: pgCore.varchar("provider_resource_id", { length: 255 }).notNull(),
1951
+ /**
1952
+ * Provider-agnostic classification of the polled resource.
1953
+ * - `subscription`: recurring authorization (MP preapproval, Stripe subscription).
1954
+ * - `one_time_payment`: deferred-payment checkout session whose
1955
+ * payment id isn't known yet (MP preference one-time, Stripe
1956
+ * checkout.session in payment mode). The poller's adapter search
1957
+ * call resolves the actual payment when the user completes the flow.
1958
+ *
1959
+ * Default `'subscription'` keeps backward compatibility for pre-existing
1960
+ * rows enqueued before the column was introduced.
1961
+ */
1962
+ resourceType: pgCore.varchar("resource_type", { length: 20 }).notNull().default("subscription"),
1963
+ /**
1964
+ * Job lifecycle status.
1965
+ * - `pending`: cron will pick up when due
1966
+ * - `succeeded`: provider returned a terminal authorized state
1967
+ * - `failed`: provider returned cancelled/rejected
1968
+ * - `timeout`: max_attempts reached without resolution
1969
+ * - `cancelled`: cancelled externally (e.g. user cancelled sub mid-flight)
1970
+ */
1971
+ status: pgCore.varchar("status", { length: 20 }).notNull().default("pending"),
1972
+ attempts: pgCore.integer("attempts").notNull().default(0),
1973
+ maxAttempts: pgCore.integer("max_attempts").notNull().default(60),
1974
+ nextPollAt: pgCore.timestamp("next_poll_at", { withTimezone: true }).notNull().defaultNow(),
1975
+ lastPolledAt: pgCore.timestamp("last_polled_at", { withTimezone: true }),
1976
+ /**
1977
+ * Raw provider status from the last poll (e.g. `pending`,
1978
+ * `authorized`). Useful for diagnostics without joining logs.
1979
+ */
1980
+ lastProviderStatus: pgCore.varchar("last_provider_status", { length: 50 }),
1981
+ /**
1982
+ * Last error message (truncated server-side to avoid bloat).
1983
+ * Set when a poll attempt fails (network, 4xx, 5xx).
1984
+ */
1985
+ lastError: pgCore.text("last_error"),
1986
+ metadata: pgCore.jsonb("metadata").notNull().default({}),
1987
+ createdAt: pgCore.timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
1988
+ updatedAt: pgCore.timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
1989
+ completedAt: pgCore.timestamp("completed_at", { withTimezone: true }),
1990
+ /**
1991
+ * Optimistic lock token. Updated on every state change. Workers
1992
+ * must include this in their UPDATE WHERE clause to detect
1993
+ * concurrent modifications.
1994
+ */
1995
+ version: pgCore.uuid("version").notNull().defaultRandom()
1996
+ },
1997
+ (table) => ({
1998
+ /**
1999
+ * Partial index that supports the cron's "find due pending
2000
+ * jobs" query. Only rows still pending are scanned, so the
2001
+ * per-tick cost is O(k) where k = #pending jobs (NOT a full
2002
+ * table scan that would grow with historical job count).
2003
+ */
2004
+ dueIdx: pgCore.index("idx_polling_jobs_due").on(table.nextPollAt).where(drizzleOrm.sql`status = 'pending'`),
2005
+ /**
2006
+ * Lookup by subscription, e.g. when a webhook arrives and we
2007
+ * need to mark the active polling job as `succeeded`.
2008
+ */
2009
+ subscriptionIdx: pgCore.index("idx_polling_jobs_subscription").on(table.subscriptionId),
2010
+ /**
2011
+ * At most one ACTIVE polling job per subscription. Prevents
2012
+ * duplicate enqueuing if `schedulePolling()` is called twice
2013
+ * concurrently. Historical jobs (succeeded/failed/timeout/
2014
+ * cancelled) are NOT constrained — multiple terminal rows per
2015
+ * subscription are allowed for audit trail.
2016
+ */
2017
+ oneActivePerSubscriptionIdx: pgCore.uniqueIndex("idx_polling_jobs_one_active_per_sub").on(table.subscriptionId).where(drizzleOrm.sql`status = 'pending'`)
2018
+ })
2019
+ );
2020
+ var billingSubscriptionPollingJobInsertSchema = drizzleZod.createInsertSchema(billingSubscriptionPollingJobs);
2021
+ var billingSubscriptionPollingJobSelectSchema = drizzleZod.createSelectSchema(billingSubscriptionPollingJobs);
1893
2022
  var billingUsageRecords = pgCore.pgTable(
1894
2023
  "billing_usage_records",
1895
2024
  {
@@ -1991,7 +2120,14 @@ var billingSubscriptionsRelations = drizzleOrm.relations(billingSubscriptions, (
1991
2120
  payments: many(billingPayments),
1992
2121
  invoices: many(billingInvoices),
1993
2122
  usageRecords: many(billingUsageRecords),
1994
- addons: many(billingSubscriptionAddons)
2123
+ addons: many(billingSubscriptionAddons),
2124
+ pollingJobs: many(billingSubscriptionPollingJobs)
2125
+ }));
2126
+ var billingSubscriptionPollingJobsRelations = drizzleOrm.relations(billingSubscriptionPollingJobs, ({ one }) => ({
2127
+ subscription: one(billingSubscriptions, {
2128
+ fields: [billingSubscriptionPollingJobs.subscriptionId],
2129
+ references: [billingSubscriptions.id]
2130
+ })
1995
2131
  }));
1996
2132
  var billingPaymentsRelations = drizzleOrm.relations(billingPayments, ({ one, many }) => ({
1997
2133
  customer: one(billingCustomers, {
@@ -2188,6 +2324,7 @@ var qzpaySchema = {
2188
2324
  billingPromoCodes,
2189
2325
  billingPromoCodeUsage,
2190
2326
  billingSubscriptions,
2327
+ billingSubscriptionPollingJobs,
2191
2328
  billingUsageRecords,
2192
2329
  billingVendors,
2193
2330
  billingVendorPayouts,
@@ -2212,6 +2349,7 @@ var qzpaySchema = {
2212
2349
  billingPromoCodesRelations,
2213
2350
  billingPromoCodeUsageRelations,
2214
2351
  billingSubscriptionsRelations,
2352
+ billingSubscriptionPollingJobsRelations,
2215
2353
  billingUsageRecordsRelations,
2216
2354
  billingVendorsRelations,
2217
2355
  billingVendorPayoutsRelations
@@ -4700,6 +4838,119 @@ var QZPayPromoCodesRepository = class {
4700
4838
  }
4701
4839
  };
4702
4840
  init_base_repository();
4841
+ var PG_UNIQUE_VIOLATION = "23505";
4842
+ function isUniqueViolation(error) {
4843
+ if (typeof error !== "object" || error === null) {
4844
+ return false;
4845
+ }
4846
+ const direct = error;
4847
+ if (direct.code === PG_UNIQUE_VIOLATION) {
4848
+ return true;
4849
+ }
4850
+ const cause = error.cause;
4851
+ if (cause && typeof cause === "object") {
4852
+ const innerCode = cause.code;
4853
+ if (innerCode === PG_UNIQUE_VIOLATION) {
4854
+ return true;
4855
+ }
4856
+ }
4857
+ return false;
4858
+ }
4859
+ var QZPaySubscriptionPollingJobsRepository = class {
4860
+ constructor(db) {
4861
+ this.db = db;
4862
+ }
4863
+ /**
4864
+ * Insert a new pending polling job.
4865
+ *
4866
+ * Returns `null` if a partial-unique violation is raised — i.e.,
4867
+ * there is already a `pending` job for the same subscription. The
4868
+ * caller can then choose to read the existing job and treat it as
4869
+ * the source of truth.
4870
+ */
4871
+ async create(input) {
4872
+ try {
4873
+ const result = await this.db.insert(billingSubscriptionPollingJobs).values(input).returning();
4874
+ return firstOrNull(result);
4875
+ } catch (error) {
4876
+ if (isUniqueViolation(error)) {
4877
+ return null;
4878
+ }
4879
+ throw error;
4880
+ }
4881
+ }
4882
+ /**
4883
+ * Find a polling job by id.
4884
+ */
4885
+ async findById(id) {
4886
+ const result = await this.db.select().from(billingSubscriptionPollingJobs).where(drizzleOrm.eq(billingSubscriptionPollingJobs.id, id)).limit(1);
4887
+ return firstOrNull(result);
4888
+ }
4889
+ /**
4890
+ * Find the active (`pending`) polling job for a subscription, if any.
4891
+ * Returns the single active job because the partial-unique index
4892
+ * enforces at most one.
4893
+ */
4894
+ async findActiveBySubscriptionId(subscriptionId) {
4895
+ const result = await this.db.select().from(billingSubscriptionPollingJobs).where(
4896
+ drizzleOrm.and(drizzleOrm.eq(billingSubscriptionPollingJobs.subscriptionId, subscriptionId), drizzleOrm.eq(billingSubscriptionPollingJobs.status, "pending"))
4897
+ ).limit(1);
4898
+ return firstOrNull(result);
4899
+ }
4900
+ /**
4901
+ * Fetch up to `limit` pending jobs whose `next_poll_at <= now`,
4902
+ * ordered by `next_poll_at` ascending so most-overdue jobs are
4903
+ * processed first.
4904
+ */
4905
+ async findDuePending(now, limit) {
4906
+ const safeLimit = Math.max(1, Math.min(limit, 200));
4907
+ return this.db.select().from(billingSubscriptionPollingJobs).where(drizzleOrm.and(drizzleOrm.eq(billingSubscriptionPollingJobs.status, "pending"), drizzleOrm.lte(billingSubscriptionPollingJobs.nextPollAt, now))).orderBy(drizzleOrm.asc(billingSubscriptionPollingJobs.nextPollAt)).limit(safeLimit);
4908
+ }
4909
+ /**
4910
+ * Optimistic-locked update.
4911
+ *
4912
+ * The UPDATE only fires when both `id` AND `version` match the row
4913
+ * the caller previously read. On success the row's `version` is
4914
+ * rotated to a fresh uuid (server-side via gen_random_uuid()) and
4915
+ * `updated_at` is bumped. Returns `null` when another worker has
4916
+ * already moved the row (the version no longer matches).
4917
+ */
4918
+ async tryLockedUpdate(params) {
4919
+ const updates = {
4920
+ updatedAt: /* @__PURE__ */ new Date()
4921
+ };
4922
+ if (params.status !== void 0) {
4923
+ updates.status = params.status;
4924
+ }
4925
+ if (params.lastPolledAt !== void 0) {
4926
+ updates.lastPolledAt = params.lastPolledAt;
4927
+ }
4928
+ if (params.lastProviderStatus !== void 0) {
4929
+ updates.lastProviderStatus = params.lastProviderStatus;
4930
+ }
4931
+ if (params.lastError !== void 0) {
4932
+ updates.lastError = params.lastError;
4933
+ }
4934
+ if (params.nextPollAt !== void 0) {
4935
+ updates.nextPollAt = params.nextPollAt;
4936
+ }
4937
+ if (params.completedAt !== void 0) {
4938
+ updates.completedAt = params.completedAt;
4939
+ }
4940
+ const attemptsExpr = params.incrementAttemptsBy && params.incrementAttemptsBy !== 0 ? drizzleOrm.sql`${billingSubscriptionPollingJobs.attempts} + ${params.incrementAttemptsBy}` : void 0;
4941
+ const result = await this.db.update(billingSubscriptionPollingJobs).set({
4942
+ ...updates,
4943
+ // Rotate the version token on every successful update so
4944
+ // a subsequent UPDATE with the previous token fails.
4945
+ version: drizzleOrm.sql`gen_random_uuid()`,
4946
+ ...attemptsExpr ? { attempts: attemptsExpr } : {}
4947
+ }).where(
4948
+ drizzleOrm.and(drizzleOrm.eq(billingSubscriptionPollingJobs.id, params.id), drizzleOrm.eq(billingSubscriptionPollingJobs.version, params.expectedVersion))
4949
+ ).returning();
4950
+ return firstOrNull(result);
4951
+ }
4952
+ };
4953
+ init_base_repository();
4703
4954
  var QZPaySubscriptionsRepository = class {
4704
4955
  constructor(db) {
4705
4956
  this.db = db;
@@ -5767,6 +6018,7 @@ var QZPayDrizzleStorageAdapter = class {
5767
6018
  checkoutsRepo;
5768
6019
  customersRepo;
5769
6020
  subscriptionsRepo;
6021
+ subscriptionPollingJobsRepo;
5770
6022
  paymentsRepo;
5771
6023
  paymentMethodsRepo;
5772
6024
  invoicesRepo;
@@ -5782,6 +6034,7 @@ var QZPayDrizzleStorageAdapter = class {
5782
6034
  checkouts;
5783
6035
  customers;
5784
6036
  subscriptions;
6037
+ subscriptionPollingJobs;
5785
6038
  payments;
5786
6039
  paymentMethods;
5787
6040
  invoices;
@@ -5799,6 +6052,7 @@ var QZPayDrizzleStorageAdapter = class {
5799
6052
  this.checkoutsRepo = new QZPayCheckoutsRepository(this.db);
5800
6053
  this.customersRepo = new QZPayCustomersRepository(typedDb);
5801
6054
  this.subscriptionsRepo = new QZPaySubscriptionsRepository(typedDb);
6055
+ this.subscriptionPollingJobsRepo = new QZPaySubscriptionPollingJobsRepository(this.db);
5802
6056
  this.paymentsRepo = new QZPayPaymentsRepository(this.db);
5803
6057
  this.paymentMethodsRepo = new QZPayPaymentMethodsRepository(this.db);
5804
6058
  this.invoicesRepo = new QZPayInvoicesRepository(typedDb);
@@ -5813,6 +6067,7 @@ var QZPayDrizzleStorageAdapter = class {
5813
6067
  this.checkouts = this.createCheckoutStorage();
5814
6068
  this.customers = this.createCustomerStorage();
5815
6069
  this.subscriptions = this.createSubscriptionStorage();
6070
+ this.subscriptionPollingJobs = this.createSubscriptionPollingJobStorage();
5816
6071
  this.payments = this.createPaymentStorage();
5817
6072
  this.paymentMethods = this.createPaymentMethodStorage();
5818
6073
  this.invoices = this.createInvoiceStorage();
@@ -5949,6 +6204,48 @@ var QZPayDrizzleStorageAdapter = class {
5949
6204
  }
5950
6205
  };
5951
6206
  }
6207
+ // ==================== Subscription Polling Job Storage ====================
6208
+ createSubscriptionPollingJobStorage() {
6209
+ const repo = this.subscriptionPollingJobsRepo;
6210
+ return {
6211
+ async create(input) {
6212
+ if (!input.provider) {
6213
+ throw new Error(
6214
+ 'QZPaySchedulePollingInput.provider is required when calling subscriptionPollingJobs.create. Pass the configured payment adapter provider (e.g., "mercadopago") explicitly.'
6215
+ );
6216
+ }
6217
+ const drizzleInput = mapPollingScheduleInputToDrizzleInsert({ ...input, provider: input.provider });
6218
+ const row = await repo.create(drizzleInput);
6219
+ return row ? mapDrizzlePollingJobToCore(row) : null;
6220
+ },
6221
+ async update(input) {
6222
+ const row = await repo.tryLockedUpdate({
6223
+ id: input.id,
6224
+ expectedVersion: input.expectedVersion,
6225
+ ...input.status !== void 0 ? { status: input.status } : {},
6226
+ ...input.incrementAttemptsBy !== void 0 ? { incrementAttemptsBy: input.incrementAttemptsBy } : {},
6227
+ ...input.lastPolledAt !== void 0 ? { lastPolledAt: input.lastPolledAt } : {},
6228
+ ...input.lastProviderStatus !== void 0 ? { lastProviderStatus: input.lastProviderStatus } : {},
6229
+ ...input.lastError !== void 0 ? { lastError: input.lastError } : {},
6230
+ ...input.nextPollAt !== void 0 ? { nextPollAt: input.nextPollAt } : {},
6231
+ ...input.completedAt !== void 0 ? { completedAt: input.completedAt } : {}
6232
+ });
6233
+ return row ? mapDrizzlePollingJobToCore(row) : null;
6234
+ },
6235
+ async findById(id) {
6236
+ const row = await repo.findById(id);
6237
+ return row ? mapDrizzlePollingJobToCore(row) : null;
6238
+ },
6239
+ async findActiveBySubscriptionId(subscriptionId) {
6240
+ const row = await repo.findActiveBySubscriptionId(subscriptionId);
6241
+ return row ? mapDrizzlePollingJobToCore(row) : null;
6242
+ },
6243
+ async findDuePending(now, limit) {
6244
+ const rows = await repo.findDuePending(now, limit);
6245
+ return rows.map(mapDrizzlePollingJobToCore);
6246
+ }
6247
+ };
6248
+ }
5952
6249
  // ==================== Payment Storage ====================
5953
6250
  createPaymentStorage() {
5954
6251
  const repo = this.paymentsRepo;
@@ -6504,9 +6801,9 @@ async function runMigrations(config) {
6504
6801
  if (verbose) {
6505
6802
  console.log("[QZPay] Starting database migrations...");
6506
6803
  }
6507
- const sql20 = postgres2__default.default(connectionUrl, { max: 1 });
6804
+ const sql22 = postgres2__default.default(connectionUrl, { max: 1 });
6508
6805
  try {
6509
- const db = postgresJs.drizzle(sql20);
6806
+ const db = postgresJs.drizzle(sql22);
6510
6807
  await migrator.migrate(db, {
6511
6808
  migrationsFolder
6512
6809
  });
@@ -6517,14 +6814,14 @@ async function runMigrations(config) {
6517
6814
  console.error("[QZPay] Migration failed:", error);
6518
6815
  throw error;
6519
6816
  } finally {
6520
- await sql20.end();
6817
+ await sql22.end();
6521
6818
  }
6522
6819
  }
6523
6820
  async function hasPendingMigrations(connectionUrl) {
6524
- const sql20 = postgres2__default.default(connectionUrl, { max: 1 });
6821
+ const sql22 = postgres2__default.default(connectionUrl, { max: 1 });
6525
6822
  try {
6526
- postgresJs.drizzle(sql20);
6527
- const result = await sql20`
6823
+ postgresJs.drizzle(sql22);
6824
+ const result = await sql22`
6528
6825
  SELECT EXISTS (
6529
6826
  SELECT FROM information_schema.tables
6530
6827
  WHERE table_name = 'drizzle_migrations'
@@ -6535,24 +6832,24 @@ async function hasPendingMigrations(connectionUrl) {
6535
6832
  }
6536
6833
  return false;
6537
6834
  } finally {
6538
- await sql20.end();
6835
+ await sql22.end();
6539
6836
  }
6540
6837
  }
6541
6838
  async function ensureDatabase(config) {
6542
6839
  const { connectionUrl, databaseName } = config;
6543
- const sql20 = postgres2__default.default(connectionUrl, { max: 1 });
6840
+ const sql22 = postgres2__default.default(connectionUrl, { max: 1 });
6544
6841
  try {
6545
- const result = await sql20`
6842
+ const result = await sql22`
6546
6843
  SELECT 1 FROM pg_database WHERE datname = ${databaseName}
6547
6844
  `;
6548
6845
  if (result.length === 0) {
6549
- await sql20.unsafe(`CREATE DATABASE "${databaseName}"`);
6846
+ await sql22.unsafe(`CREATE DATABASE "${databaseName}"`);
6550
6847
  console.log(`[QZPay] Created database: ${databaseName}`);
6551
6848
  return true;
6552
6849
  }
6553
6850
  return false;
6554
6851
  } finally {
6555
- await sql20.end();
6852
+ await sql22.end();
6556
6853
  }
6557
6854
  }
6558
6855
 
@@ -6787,6 +7084,7 @@ async function executeTransaction(db, options, fn) {
6787
7084
  return withTransaction(db, executeFn);
6788
7085
  }
6789
7086
 
7087
+ exports.POLLING_JOB_DEFAULTS = POLLING_JOB_DEFAULTS;
6790
7088
  exports.QZPAY_DRIZZLE_SCHEMA_VERSION = QZPAY_DRIZZLE_SCHEMA_VERSION;
6791
7089
  exports.QZPAY_PAGINATION_DEFAULTS = QZPAY_PAGINATION_DEFAULTS;
6792
7090
  exports.QZPayAddonsRepository = QZPayAddonsRepository;
@@ -6802,6 +7100,7 @@ exports.QZPayPaymentsRepository = QZPayPaymentsRepository;
6802
7100
  exports.QZPayPlansRepository = QZPayPlansRepository;
6803
7101
  exports.QZPayPricesRepository = QZPayPricesRepository;
6804
7102
  exports.QZPayPromoCodesRepository = QZPayPromoCodesRepository;
7103
+ exports.QZPaySubscriptionPollingJobsRepository = QZPaySubscriptionPollingJobsRepository;
6805
7104
  exports.QZPaySubscriptionsRepository = QZPaySubscriptionsRepository;
6806
7105
  exports.QZPayUsageRecordsRepository = QZPayUsageRecordsRepository;
6807
7106
  exports.QZPayVendorsRepository = QZPayVendorsRepository;
@@ -6879,6 +7178,10 @@ exports.billingSubscriptionAddonSelectSchema = billingSubscriptionAddonSelectSch
6879
7178
  exports.billingSubscriptionAddons = billingSubscriptionAddons;
6880
7179
  exports.billingSubscriptionAddonsRelations = billingSubscriptionAddonsRelations;
6881
7180
  exports.billingSubscriptionInsertSchema = billingSubscriptionInsertSchema;
7181
+ exports.billingSubscriptionPollingJobInsertSchema = billingSubscriptionPollingJobInsertSchema;
7182
+ exports.billingSubscriptionPollingJobSelectSchema = billingSubscriptionPollingJobSelectSchema;
7183
+ exports.billingSubscriptionPollingJobs = billingSubscriptionPollingJobs;
7184
+ exports.billingSubscriptionPollingJobsRelations = billingSubscriptionPollingJobsRelations;
6882
7185
  exports.billingSubscriptionSelectSchema = billingSubscriptionSelectSchema;
6883
7186
  exports.billingSubscriptions = billingSubscriptions;
6884
7187
  exports.billingSubscriptionsRelations = billingSubscriptionsRelations;
@@ -6963,6 +7266,7 @@ exports.mapDrizzleLimitToCore = mapDrizzleLimitToCore;
6963
7266
  exports.mapDrizzlePaymentMethodToCore = mapDrizzlePaymentMethodToCore;
6964
7267
  exports.mapDrizzlePaymentToCore = mapDrizzlePaymentToCore;
6965
7268
  exports.mapDrizzlePlanToCore = mapDrizzlePlanToCore;
7269
+ exports.mapDrizzlePollingJobToCore = mapDrizzlePollingJobToCore;
6966
7270
  exports.mapDrizzlePriceToCore = mapDrizzlePriceToCore;
6967
7271
  exports.mapDrizzlePromoCodeToCore = mapDrizzlePromoCodeToCore;
6968
7272
  exports.mapDrizzleSubscriptionAddonToCore = mapDrizzleSubscriptionAddonToCore;
@@ -6970,6 +7274,7 @@ exports.mapDrizzleSubscriptionToCore = mapDrizzleSubscriptionToCore;
6970
7274
  exports.mapDrizzleUsageRecordToCore = mapDrizzleUsageRecordToCore;
6971
7275
  exports.mapDrizzleVendorPayoutToCore = mapDrizzleVendorPayoutToCore;
6972
7276
  exports.mapDrizzleVendorToCore = mapDrizzleVendorToCore;
7277
+ exports.mapPollingScheduleInputToDrizzleInsert = mapPollingScheduleInputToDrizzleInsert;
6973
7278
  exports.normalizePaginationOptions = normalizePaginationOptions;
6974
7279
  exports.offsetToPage = offsetToPage;
6975
7280
  exports.onlyDeleted = onlyDeleted;