@insforge/cli 0.1.86 → 0.1.88-razorpay.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.js CHANGED
@@ -263,10 +263,11 @@ import * as clack4 from "@clack/prompts";
263
263
 
264
264
  // src/lib/errors.ts
265
265
  var CLIError = class extends Error {
266
- constructor(message, exitCode = 1, code) {
266
+ constructor(message, exitCode = 1, code, statusCode) {
267
267
  super(message);
268
268
  this.exitCode = exitCode;
269
269
  this.code = code;
270
+ this.statusCode = statusCode;
270
271
  this.name = "CLIError";
271
272
  }
272
273
  };
@@ -1172,7 +1173,7 @@ import * as clack5 from "@clack/prompts";
1172
1173
 
1173
1174
  // src/lib/analytics.ts
1174
1175
  import { PostHog } from "posthog-node";
1175
- var POSTHOG_API_KEY = "phc_ueV1ii62wdBTkH7E70ugyeqHIHu8dFDdjs0qq3TZhJz";
1176
+ var POSTHOG_API_KEY = "";
1176
1177
  var POSTHOG_HOST = process.env.POSTHOG_HOST || "https://us.i.posthog.com";
1177
1178
  var client = null;
1178
1179
  function getClient() {
@@ -2066,7 +2067,7 @@ ${err.nextActions}`;
2066
2067
  if (res.status === 404 && isRouteLevel404 && path6.startsWith("/api/ai")) {
2067
2068
  message = "AI Model Gateway setup is not available on this backend.\nUpgrade your InsForge project to a version with Model Gateway support, or keep using the legacy @insforge/sdk AI modules for projects that still rely on the older AI API surface.";
2068
2069
  }
2069
- throw new CLIError(message);
2070
+ throw new CLIError(message, 1, err.error, res.status);
2070
2071
  }
2071
2072
  return res;
2072
2073
  }
@@ -7188,7 +7189,7 @@ function registerDiagnoseCommands(diagnoseCmd2) {
7188
7189
  const s = !json ? clack16.spinner() : null;
7189
7190
  s?.start("Collecting diagnostic data...");
7190
7191
  const data2 = await collectDiagnosticData(projectId, ossMode, apiUrl);
7191
- const cliVersion = "0.1.86";
7192
+ const cliVersion = "0.1.88-razorpay.0";
7192
7193
  s?.stop("Data collected");
7193
7194
  if (!json) {
7194
7195
  console.log(`
@@ -7427,75 +7428,142 @@ function withQuery(path6, params) {
7427
7428
  async function readJson(res) {
7428
7429
  return await res.json();
7429
7430
  }
7430
- function withEnvironmentPath(environment, suffix) {
7431
- return `/api/payments/${encodeURIComponent(environment)}${suffix}`;
7431
+ function withProviderPath(provider, suffix) {
7432
+ return `/api/payments/${encodeURIComponent(provider)}${suffix}`;
7433
+ }
7434
+ function withProviderEnvironmentPath(provider, environment, suffix) {
7435
+ return withProviderPath(
7436
+ provider,
7437
+ `/${encodeURIComponent(environment)}${suffix}`
7438
+ );
7439
+ }
7440
+ async function getStripePaymentsStatus() {
7441
+ return readJson(await ossFetch(withProviderPath("stripe", "/status")));
7432
7442
  }
7433
- async function getPaymentsStatus() {
7434
- return readJson(await ossFetch("/api/payments/status"));
7443
+ async function getRazorpayPaymentsStatus() {
7444
+ return readJson(await ossFetch(withProviderPath("razorpay", "/status")));
7435
7445
  }
7436
- async function getPaymentsConfig() {
7437
- return readJson(await ossFetch("/api/payments/config"));
7446
+ async function getStripePaymentsConfig() {
7447
+ return readJson(await ossFetch(withProviderPath("stripe", "/config")));
7448
+ }
7449
+ async function getRazorpayPaymentsConfig() {
7450
+ return readJson(await ossFetch(withProviderPath("razorpay", "/config")));
7438
7451
  }
7439
7452
  async function setStripeSecretKey(environment, secretKey) {
7453
+ const request = { secretKey };
7440
7454
  return readJson(
7441
- await ossFetch(withEnvironmentPath(environment, "/config"), {
7442
- method: "PUT",
7443
- body: JSON.stringify({ secretKey })
7444
- })
7455
+ await ossFetch(
7456
+ withProviderEnvironmentPath("stripe", environment, "/config"),
7457
+ {
7458
+ method: "PUT",
7459
+ body: JSON.stringify(request)
7460
+ }
7461
+ )
7462
+ );
7463
+ }
7464
+ async function setRazorpayKeys(environment, request) {
7465
+ return readJson(
7466
+ await ossFetch(
7467
+ withProviderEnvironmentPath("razorpay", environment, "/config"),
7468
+ {
7469
+ method: "PUT",
7470
+ body: JSON.stringify(request)
7471
+ }
7472
+ )
7445
7473
  );
7446
7474
  }
7447
7475
  async function removeStripeSecretKey(environment) {
7448
7476
  return readJson(
7449
- await ossFetch(withEnvironmentPath(environment, "/config"), {
7450
- method: "DELETE"
7451
- })
7477
+ await ossFetch(
7478
+ withProviderEnvironmentPath("stripe", environment, "/config"),
7479
+ {
7480
+ method: "DELETE"
7481
+ }
7482
+ )
7483
+ );
7484
+ }
7485
+ async function removeRazorpayKeys(environment) {
7486
+ return readJson(
7487
+ await ossFetch(
7488
+ withProviderEnvironmentPath("razorpay", environment, "/config"),
7489
+ { method: "DELETE" }
7490
+ )
7491
+ );
7492
+ }
7493
+ async function syncStripePayments(environment = "all") {
7494
+ return readJson(
7495
+ await ossFetch(
7496
+ environment === "all" ? withProviderPath("stripe", "/sync") : withProviderEnvironmentPath("stripe", environment, "/sync"),
7497
+ { method: "POST" }
7498
+ )
7452
7499
  );
7453
7500
  }
7454
- async function syncPayments(environment = "all") {
7501
+ async function syncRazorpayPayments(environment = "all") {
7455
7502
  return readJson(
7456
7503
  await ossFetch(
7457
- environment === "all" ? "/api/payments/sync" : withEnvironmentPath(environment, "/sync"),
7504
+ environment === "all" ? withProviderPath("razorpay", "/sync") : withProviderEnvironmentPath("razorpay", environment, "/sync"),
7458
7505
  { method: "POST" }
7459
7506
  )
7460
7507
  );
7461
7508
  }
7462
- async function configurePaymentWebhook(environment) {
7509
+ async function configureStripeWebhook(environment) {
7510
+ return readJson(
7511
+ await ossFetch(
7512
+ withProviderEnvironmentPath("stripe", environment, "/webhook"),
7513
+ {
7514
+ method: "POST"
7515
+ }
7516
+ )
7517
+ );
7518
+ }
7519
+ async function listStripeCatalog(environment) {
7463
7520
  return readJson(
7464
- await ossFetch(withEnvironmentPath(environment, "/webhook"), {
7465
- method: "POST"
7466
- })
7521
+ await ossFetch(
7522
+ withProviderEnvironmentPath("stripe", environment, "/catalog")
7523
+ )
7467
7524
  );
7468
7525
  }
7469
- async function listPaymentCatalog(environment) {
7470
- return readJson(await ossFetch(withEnvironmentPath(environment, "/catalog")));
7526
+ async function listRazorpayCatalog(environment) {
7527
+ return readJson(
7528
+ await ossFetch(
7529
+ withProviderEnvironmentPath("razorpay", environment, "/catalog")
7530
+ )
7531
+ );
7471
7532
  }
7472
- async function listPaymentProducts(environment) {
7533
+ async function listStripeProducts(environment) {
7473
7534
  return readJson(
7474
- await ossFetch(withEnvironmentPath(environment, "/catalog/products"))
7535
+ await ossFetch(
7536
+ withProviderEnvironmentPath("stripe", environment, "/catalog/products")
7537
+ )
7475
7538
  );
7476
7539
  }
7477
- async function getPaymentProduct(environment, productId) {
7540
+ async function getStripeProduct(environment, productId) {
7478
7541
  return readJson(
7479
7542
  await ossFetch(
7480
- withEnvironmentPath(
7543
+ withProviderEnvironmentPath(
7544
+ "stripe",
7481
7545
  environment,
7482
7546
  `/catalog/products/${encodeURIComponent(productId)}`
7483
7547
  )
7484
7548
  )
7485
7549
  );
7486
7550
  }
7487
- async function createPaymentProduct(environment, request) {
7551
+ async function createStripeProduct(environment, request) {
7488
7552
  return readJson(
7489
- await ossFetch(withEnvironmentPath(environment, "/catalog/products"), {
7490
- method: "POST",
7491
- body: JSON.stringify(request)
7492
- })
7553
+ await ossFetch(
7554
+ withProviderEnvironmentPath("stripe", environment, "/catalog/products"),
7555
+ {
7556
+ method: "POST",
7557
+ body: JSON.stringify(request)
7558
+ }
7559
+ )
7493
7560
  );
7494
7561
  }
7495
- async function updatePaymentProduct(environment, productId, request) {
7562
+ async function updateStripeProduct(environment, productId, request) {
7496
7563
  return readJson(
7497
7564
  await ossFetch(
7498
- withEnvironmentPath(
7565
+ withProviderEnvironmentPath(
7566
+ "stripe",
7499
7567
  environment,
7500
7568
  `/catalog/products/${encodeURIComponent(productId)}`
7501
7569
  ),
@@ -7506,10 +7574,11 @@ async function updatePaymentProduct(environment, productId, request) {
7506
7574
  )
7507
7575
  );
7508
7576
  }
7509
- async function deletePaymentProduct(environment, productId) {
7577
+ async function deleteStripeProduct(environment, productId) {
7510
7578
  return readJson(
7511
7579
  await ossFetch(
7512
- withEnvironmentPath(
7580
+ withProviderEnvironmentPath(
7581
+ "stripe",
7513
7582
  environment,
7514
7583
  `/catalog/products/${encodeURIComponent(productId)}`
7515
7584
  ),
@@ -7517,37 +7586,43 @@ async function deletePaymentProduct(environment, productId) {
7517
7586
  )
7518
7587
  );
7519
7588
  }
7520
- async function listPaymentPrices(environment, stripeProductId) {
7589
+ async function listStripePrices(environment, productId) {
7521
7590
  return readJson(
7522
7591
  await ossFetch(
7523
- withQuery(withEnvironmentPath(environment, "/catalog/prices"), {
7524
- stripeProductId
7525
- })
7592
+ withQuery(
7593
+ withProviderEnvironmentPath("stripe", environment, "/catalog/prices"),
7594
+ { productId }
7595
+ )
7526
7596
  )
7527
7597
  );
7528
7598
  }
7529
- async function getPaymentPrice(environment, priceId) {
7599
+ async function getStripePrice(environment, priceId) {
7530
7600
  return readJson(
7531
7601
  await ossFetch(
7532
- withEnvironmentPath(
7602
+ withProviderEnvironmentPath(
7603
+ "stripe",
7533
7604
  environment,
7534
7605
  `/catalog/prices/${encodeURIComponent(priceId)}`
7535
7606
  )
7536
7607
  )
7537
7608
  );
7538
7609
  }
7539
- async function createPaymentPrice(environment, request) {
7610
+ async function createStripePrice(environment, request) {
7540
7611
  return readJson(
7541
- await ossFetch(withEnvironmentPath(environment, "/catalog/prices"), {
7542
- method: "POST",
7543
- body: JSON.stringify(request)
7544
- })
7612
+ await ossFetch(
7613
+ withProviderEnvironmentPath("stripe", environment, "/catalog/prices"),
7614
+ {
7615
+ method: "POST",
7616
+ body: JSON.stringify(request)
7617
+ }
7618
+ )
7545
7619
  );
7546
7620
  }
7547
- async function updatePaymentPrice(environment, priceId, request) {
7621
+ async function updateStripePrice(environment, priceId, request) {
7548
7622
  return readJson(
7549
7623
  await ossFetch(
7550
- withEnvironmentPath(
7624
+ withProviderEnvironmentPath(
7625
+ "stripe",
7551
7626
  environment,
7552
7627
  `/catalog/prices/${encodeURIComponent(priceId)}`
7553
7628
  ),
@@ -7558,10 +7633,11 @@ async function updatePaymentPrice(environment, priceId, request) {
7558
7633
  )
7559
7634
  );
7560
7635
  }
7561
- async function archivePaymentPrice(environment, priceId) {
7636
+ async function archiveStripePrice(environment, priceId) {
7562
7637
  return readJson(
7563
7638
  await ossFetch(
7564
- withEnvironmentPath(
7639
+ withProviderEnvironmentPath(
7640
+ "stripe",
7565
7641
  environment,
7566
7642
  `/catalog/prices/${encodeURIComponent(priceId)}`
7567
7643
  ),
@@ -7569,29 +7645,99 @@ async function archivePaymentPrice(environment, priceId) {
7569
7645
  )
7570
7646
  );
7571
7647
  }
7572
- async function listSubscriptions(environment, request) {
7648
+ async function createRazorpayItem(environment, request) {
7649
+ return readJson(
7650
+ await ossFetch(
7651
+ withProviderEnvironmentPath("razorpay", environment, "/catalog/items"),
7652
+ {
7653
+ method: "POST",
7654
+ body: JSON.stringify(request)
7655
+ }
7656
+ )
7657
+ );
7658
+ }
7659
+ async function updateRazorpayItem(environment, itemId, request) {
7660
+ return readJson(
7661
+ await ossFetch(
7662
+ withProviderEnvironmentPath(
7663
+ "razorpay",
7664
+ environment,
7665
+ `/catalog/items/${encodeURIComponent(itemId)}`
7666
+ ),
7667
+ {
7668
+ method: "PATCH",
7669
+ body: JSON.stringify(request)
7670
+ }
7671
+ )
7672
+ );
7673
+ }
7674
+ async function createRazorpayPlan(environment, request) {
7675
+ return readJson(
7676
+ await ossFetch(
7677
+ withProviderEnvironmentPath("razorpay", environment, "/catalog/plans"),
7678
+ {
7679
+ method: "POST",
7680
+ body: JSON.stringify(request)
7681
+ }
7682
+ )
7683
+ );
7684
+ }
7685
+ async function listStripeSubscriptions(environment, request) {
7686
+ return readJson(
7687
+ await ossFetch(
7688
+ withQuery(
7689
+ withProviderEnvironmentPath("stripe", environment, "/subscriptions"),
7690
+ request
7691
+ )
7692
+ )
7693
+ );
7694
+ }
7695
+ async function listRazorpaySubscriptions(environment, request) {
7573
7696
  return readJson(
7574
7697
  await ossFetch(
7575
- withQuery(withEnvironmentPath(environment, "/subscriptions"), request)
7698
+ withQuery(
7699
+ withProviderEnvironmentPath("razorpay", environment, "/subscriptions"),
7700
+ request
7701
+ )
7576
7702
  )
7577
7703
  );
7578
7704
  }
7579
- async function listPaymentCustomers(environment, request = {}) {
7705
+ async function listPaymentCustomers(provider, environment, request = {}) {
7580
7706
  return readJson(
7581
7707
  await ossFetch(
7582
- withQuery(withEnvironmentPath(environment, "/customers"), request)
7708
+ withQuery(
7709
+ withProviderEnvironmentPath(provider, environment, "/customers"),
7710
+ request
7711
+ )
7583
7712
  )
7584
7713
  );
7585
7714
  }
7586
- async function listPaymentHistory(environment, request) {
7715
+ async function listPaymentTransactions(provider, environment, request) {
7587
7716
  return readJson(
7588
7717
  await ossFetch(
7589
- withQuery(withEnvironmentPath(environment, "/payment-history"), request)
7718
+ withQuery(
7719
+ withProviderEnvironmentPath(provider, environment, "/transactions"),
7720
+ request
7721
+ )
7590
7722
  )
7591
7723
  );
7592
7724
  }
7593
7725
 
7594
7726
  // src/commands/payments/utils.ts
7727
+ var MAX_TELEMETRY_ERROR_MESSAGE_LENGTH = 500;
7728
+ function getErrorTelemetry(error) {
7729
+ const message = error instanceof Error ? error.message : String(error);
7730
+ const truncatedMessage = message.length > MAX_TELEMETRY_ERROR_MESSAGE_LENGTH ? `${message.slice(0, MAX_TELEMETRY_ERROR_MESSAGE_LENGTH)}...` : message;
7731
+ return {
7732
+ error_name: error instanceof Error ? error.name : typeof error,
7733
+ error_message: truncatedMessage,
7734
+ ...error instanceof CLIError ? {
7735
+ error_code: error.code,
7736
+ exit_code: error.exitCode,
7737
+ status_code: error.statusCode
7738
+ } : {}
7739
+ };
7740
+ }
7595
7741
  function parseEnvironment(value) {
7596
7742
  if (value === "test" || value === "live") return value;
7597
7743
  throw new CLIError('Environment must be "test" or "live".');
@@ -7600,6 +7746,15 @@ function parseEnvironmentOrAll(value) {
7600
7746
  if (value === "all") return value;
7601
7747
  return parseEnvironment(value);
7602
7748
  }
7749
+ function parseRazorpayPlanPeriod(value) {
7750
+ if (value === void 0) return void 0;
7751
+ if (value === "daily" || value === "weekly" || value === "monthly" || value === "yearly") {
7752
+ return value;
7753
+ }
7754
+ throw new CLIError(
7755
+ "--period must be one of: daily, weekly, monthly, yearly."
7756
+ );
7757
+ }
7603
7758
  function parseBooleanOption(value, flagName) {
7604
7759
  if (value === void 0) return void 0;
7605
7760
  const normalized = value.toLowerCase();
@@ -7667,13 +7822,14 @@ function formatRecurring(interval, intervalCount) {
7667
7822
  if (!interval) return "one-time";
7668
7823
  return `${intervalCount && intervalCount > 1 ? `${intervalCount} ` : ""}${interval}`;
7669
7824
  }
7670
- async function trackPaymentUsage(subcommand, success, properties = {}) {
7825
+ async function trackPaymentUsage(subcommand, success, properties = {}, error) {
7671
7826
  try {
7672
7827
  const config = getProjectConfig();
7673
7828
  if (config) {
7674
7829
  trackPayments(subcommand, config, {
7675
7830
  success,
7676
- ...properties
7831
+ ...properties,
7832
+ ...error !== void 0 ? getErrorTelemetry(error) : {}
7677
7833
  });
7678
7834
  }
7679
7835
  } catch {
@@ -7683,76 +7839,138 @@ async function trackPaymentUsage(subcommand, success, properties = {}) {
7683
7839
  }
7684
7840
 
7685
7841
  // src/commands/payments/catalog.ts
7686
- function registerPaymentsCatalogCommand(paymentsCmd2) {
7687
- paymentsCmd2.command("catalog").description("List mirrored Stripe products and prices for one environment").requiredOption(
7842
+ function registerPaymentsCatalogCommand(paymentsCmd2, provider) {
7843
+ paymentsCmd2.command("catalog").description("List mirrored provider catalog records for one environment").requiredOption(
7688
7844
  "--environment <environment>",
7689
- "Stripe environment: test or live"
7845
+ "Payment environment: test or live"
7690
7846
  ).action(async (opts, cmd) => {
7691
7847
  const { json } = getRootOpts(cmd);
7692
7848
  try {
7693
7849
  const environment = parseEnvironment(opts.environment);
7694
7850
  await requireAuth();
7695
- const data = await listPaymentCatalog(environment);
7696
- if (json) {
7697
- outputJson(data);
7698
- } else {
7699
- if (data.products.length === 0 && data.prices.length === 0) {
7700
- console.log("No Stripe catalog records found.");
7701
- await trackPaymentUsage("catalog", true, { environment });
7702
- return;
7703
- }
7704
- if (data.products.length > 0) {
7705
- console.log("Products");
7706
- outputTable(
7707
- ["Env", "Product ID", "Name", "Active", "Default Price"],
7708
- data.products.map((product) => [
7709
- product.environment,
7710
- product.stripeProductId,
7711
- product.name,
7712
- product.active ? "Yes" : "No",
7713
- product.defaultPriceId ?? "-"
7714
- ])
7715
- );
7851
+ if (provider === "stripe") {
7852
+ const data = await listStripeCatalog(environment);
7853
+ if (json) {
7854
+ outputJson(data);
7855
+ } else {
7856
+ if (data.products.length === 0 && data.prices.length === 0) {
7857
+ console.log("No Stripe catalog records found.");
7858
+ await trackPaymentUsage("catalog", true, {
7859
+ provider,
7860
+ environment
7861
+ });
7862
+ return;
7863
+ }
7864
+ if (data.products.length > 0) {
7865
+ console.log("Products");
7866
+ outputTable(
7867
+ ["Env", "Product ID", "Name", "Active", "Default Price"],
7868
+ data.products.map((product) => [
7869
+ product.environment,
7870
+ product.productId,
7871
+ product.name,
7872
+ product.active ? "Yes" : "No",
7873
+ product.defaultPriceId ?? "-"
7874
+ ])
7875
+ );
7876
+ }
7877
+ if (data.prices.length > 0) {
7878
+ console.log("Prices");
7879
+ outputTable(
7880
+ [
7881
+ "Env",
7882
+ "Price ID",
7883
+ "Product ID",
7884
+ "Amount",
7885
+ "Type",
7886
+ "Active",
7887
+ "Recurring"
7888
+ ],
7889
+ data.prices.map((price) => [
7890
+ price.environment,
7891
+ price.priceId,
7892
+ price.productId ?? "-",
7893
+ formatAmount(price.unitAmount, price.currency),
7894
+ price.type,
7895
+ price.active ? "Yes" : "No",
7896
+ formatRecurring(
7897
+ price.recurringInterval,
7898
+ price.recurringIntervalCount
7899
+ )
7900
+ ])
7901
+ );
7902
+ }
7716
7903
  }
7717
- if (data.prices.length > 0) {
7718
- console.log("Prices");
7719
- outputTable(
7720
- [
7721
- "Env",
7722
- "Price ID",
7723
- "Product ID",
7724
- "Amount",
7725
- "Type",
7726
- "Active",
7727
- "Recurring"
7728
- ],
7729
- data.prices.map((price) => [
7730
- price.environment,
7731
- price.stripePriceId,
7732
- price.stripeProductId ?? "-",
7733
- formatAmount(price.unitAmount, price.currency),
7734
- price.type,
7735
- price.active ? "Yes" : "No",
7736
- formatRecurring(
7737
- price.recurringInterval,
7738
- price.recurringIntervalCount
7739
- )
7740
- ])
7741
- );
7904
+ } else {
7905
+ const data = await listRazorpayCatalog(environment);
7906
+ if (json) {
7907
+ outputJson(data);
7908
+ } else {
7909
+ if (data.items.length === 0 && data.plans.length === 0) {
7910
+ console.log("No Razorpay catalog records found.");
7911
+ await trackPaymentUsage("catalog", true, {
7912
+ provider,
7913
+ environment
7914
+ });
7915
+ return;
7916
+ }
7917
+ if (data.items.length > 0) {
7918
+ console.log("Items");
7919
+ outputTable(
7920
+ ["Env", "Item ID", "Name", "Amount", "Active", "Type"],
7921
+ data.items.map((item) => [
7922
+ item.environment,
7923
+ item.itemId,
7924
+ item.name,
7925
+ formatAmount(item.amount, item.currency),
7926
+ item.active ? "Yes" : "No",
7927
+ item.type ?? "-"
7928
+ ])
7929
+ );
7930
+ }
7931
+ if (data.plans.length > 0) {
7932
+ console.log("Plans");
7933
+ outputTable(
7934
+ [
7935
+ "Env",
7936
+ "Plan ID",
7937
+ "Item ID",
7938
+ "Amount",
7939
+ "Period",
7940
+ "Interval",
7941
+ "Active"
7942
+ ],
7943
+ data.plans.map((plan) => [
7944
+ plan.environment,
7945
+ plan.planId,
7946
+ plan.itemId,
7947
+ formatAmount(plan.amount, plan.currency),
7948
+ plan.period,
7949
+ String(plan.interval),
7950
+ plan.active ? "Yes" : "No"
7951
+ ])
7952
+ );
7953
+ }
7742
7954
  }
7743
7955
  }
7744
- await trackPaymentUsage("catalog", true, { environment });
7956
+ await trackPaymentUsage("catalog", true, { provider, environment });
7745
7957
  } catch (err) {
7746
- await trackPaymentUsage("catalog", false, {
7747
- environment: opts.environment
7748
- });
7958
+ await trackPaymentUsage(
7959
+ "catalog",
7960
+ false,
7961
+ {
7962
+ provider,
7963
+ environment: opts.environment
7964
+ },
7965
+ err
7966
+ );
7749
7967
  handleError(err, json);
7750
7968
  }
7751
7969
  });
7752
7970
  }
7753
7971
 
7754
7972
  // src/commands/payments/config.ts
7755
- function outputConfigTable(data) {
7973
+ function outputStripeConfigTable(data) {
7756
7974
  if (data.keys.length === 0) {
7757
7975
  console.log("No Stripe keys configured.");
7758
7976
  return;
@@ -7766,32 +7984,111 @@ function outputConfigTable(data) {
7766
7984
  ])
7767
7985
  );
7768
7986
  }
7769
- function registerPaymentsConfigCommand(paymentsCmd2) {
7770
- const configCmd = paymentsCmd2.command("config").description("Manage Stripe API keys for payments").action(async (_opts, cmd) => {
7987
+ function outputRazorpayConfigTable(data) {
7988
+ if (data.razorpayKeys.length === 0) {
7989
+ console.log("No Razorpay keys configured.");
7990
+ return;
7991
+ }
7992
+ outputTable(
7993
+ ["Env", "Type", "Configured", "Key"],
7994
+ data.razorpayKeys.map((key) => [
7995
+ key.environment,
7996
+ key.keyType,
7997
+ key.hasKey ? "Yes" : "No",
7998
+ key.maskedKey ?? "-"
7999
+ ])
8000
+ );
8001
+ }
8002
+ function registerPaymentsConfigCommand(paymentsCmd2, provider) {
8003
+ const configCmd = paymentsCmd2.command("config").description("Manage payment provider keys");
8004
+ configCmd.command("list").description("List configured payment provider keys").action(async (_opts, cmd) => {
7771
8005
  const { json } = getRootOpts(cmd);
7772
8006
  try {
7773
8007
  await requireAuth();
7774
- const data = await getPaymentsConfig();
8008
+ if (provider === "stripe") {
8009
+ const data = await getStripePaymentsConfig();
8010
+ if (json) {
8011
+ outputJson(data);
8012
+ } else {
8013
+ outputStripeConfigTable(data);
8014
+ }
8015
+ } else {
8016
+ const data = await getRazorpayPaymentsConfig();
8017
+ if (json) {
8018
+ outputJson(data);
8019
+ } else {
8020
+ outputRazorpayConfigTable(data);
8021
+ }
8022
+ }
8023
+ await trackPaymentUsage("config", true, { provider });
8024
+ } catch (err) {
8025
+ await trackPaymentUsage("config", false, { provider }, err);
8026
+ handleError(err, json);
8027
+ }
8028
+ });
8029
+ if (provider === "stripe") {
8030
+ registerStripeConfigSetCommand(configCmd);
8031
+ } else {
8032
+ registerRazorpayConfigSetCommand(configCmd);
8033
+ }
8034
+ configCmd.command("remove").description("Remove configured payment provider keys").requiredOption(
8035
+ "--environment <environment>",
8036
+ "Payment environment: test or live"
8037
+ ).action(async (opts, cmd) => {
8038
+ const { json, yes } = getRootOpts(cmd);
8039
+ try {
8040
+ const environment = parseEnvironment(opts.environment);
8041
+ await requireAuth();
8042
+ if (json && !yes) {
8043
+ throw new CLIError(
8044
+ "Use --yes with --json to remove payment keys non-interactively."
8045
+ );
8046
+ }
8047
+ if (!yes) {
8048
+ const confirm8 = await confirm2({
8049
+ message: `Remove ${provider} ${environment} keys? Payment sync and mutations for this environment will stop.`
8050
+ });
8051
+ if (isCancel2(confirm8) || !confirm8) process.exit(0);
8052
+ }
8053
+ const data = provider === "stripe" ? await removeStripeSecretKey(environment) : await removeRazorpayKeys(environment);
7775
8054
  if (json) {
7776
8055
  outputJson(data);
7777
8056
  } else {
7778
- outputConfigTable(data);
8057
+ outputSuccess(`${provider} ${environment} keys removed.`);
7779
8058
  }
7780
- await trackPaymentUsage("config", true);
8059
+ await trackPaymentUsage("config.remove", true, {
8060
+ provider,
8061
+ environment
8062
+ });
7781
8063
  } catch (err) {
7782
- await trackPaymentUsage("config", false);
8064
+ await trackPaymentUsage(
8065
+ "config.remove",
8066
+ false,
8067
+ {
8068
+ provider,
8069
+ environment: opts.environment
8070
+ },
8071
+ err
8072
+ );
7783
8073
  handleError(err, json);
7784
8074
  }
7785
8075
  });
7786
- configCmd.command("set <environment> [secretKey]").description("Configure a Stripe secret key for test or live payments").action(async (environmentValue, secretKeyValue, _opts, cmd) => {
8076
+ }
8077
+ function registerStripeConfigSetCommand(configCmd) {
8078
+ configCmd.command("set [secretKey]").description("Configure a Stripe secret key for test or live payments").requiredOption(
8079
+ "--environment <environment>",
8080
+ "Stripe environment: test or live"
8081
+ ).option("--secret-key <secretKey>", "Stripe secret key").action(async (secretKeyValue, opts, cmd) => {
7787
8082
  const { json } = getRootOpts(cmd);
7788
8083
  try {
7789
- const environment = parseEnvironment(environmentValue);
8084
+ const environment = parseEnvironment(opts.environment);
7790
8085
  await requireAuth();
7791
- let secretKey = secretKeyValue;
8086
+ let secretKey = opts.secretKey ?? secretKeyValue;
7792
8087
  if (!secretKey) {
7793
8088
  if (json) {
7794
- throw new CLIError("Provide secretKey when using --json.");
8089
+ throw new CLIError(
8090
+ "Provide secretKey or --secret-key when using --json."
8091
+ );
7795
8092
  }
7796
8093
  const input = await password2({
7797
8094
  message: `Stripe ${environment} secret key`
@@ -7805,35 +8102,78 @@ function registerPaymentsConfigCommand(paymentsCmd2) {
7805
8102
  } else {
7806
8103
  outputSuccess(`Stripe ${environment} key configured.`);
7807
8104
  }
7808
- await trackPaymentUsage("config.set", true, { environment });
8105
+ await trackPaymentUsage("config.set", true, {
8106
+ provider: "stripe",
8107
+ environment
8108
+ });
7809
8109
  } catch (err) {
7810
- await trackPaymentUsage("config.set", false, { environment: environmentValue });
8110
+ await trackPaymentUsage(
8111
+ "config.set",
8112
+ false,
8113
+ {
8114
+ provider: "stripe",
8115
+ environment: opts.environment
8116
+ },
8117
+ err
8118
+ );
7811
8119
  handleError(err, json);
7812
8120
  }
7813
8121
  });
7814
- configCmd.command("remove <environment>").alias("delete").description("Remove a configured Stripe secret key").action(async (environmentValue, _opts, cmd) => {
7815
- const { json, yes } = getRootOpts(cmd);
8122
+ }
8123
+ function registerRazorpayConfigSetCommand(configCmd) {
8124
+ configCmd.command("set").description("Configure Razorpay keys for test or live payments").requiredOption(
8125
+ "--environment <environment>",
8126
+ "Razorpay environment: test or live"
8127
+ ).option("--key-id <keyId>", "Razorpay key id").option("--key-secret <keySecret>", "Razorpay key secret").action(async (opts, cmd) => {
8128
+ const { json } = getRootOpts(cmd);
7816
8129
  try {
7817
- const environment = parseEnvironment(environmentValue);
8130
+ const environment = parseEnvironment(opts.environment);
7818
8131
  await requireAuth();
7819
- if (json && !yes) {
7820
- throw new CLIError("Use --yes with --json to remove a Stripe key non-interactively.");
8132
+ let keyId = opts.keyId;
8133
+ let keySecret = opts.keySecret;
8134
+ if (!keyId) {
8135
+ if (json) {
8136
+ throw new CLIError("Provide --key-id when using --json.");
8137
+ }
8138
+ const input = await text2({
8139
+ message: `Razorpay ${environment} key id`
8140
+ });
8141
+ if (isCancel2(input)) process.exit(0);
8142
+ keyId = input;
7821
8143
  }
7822
- if (!yes) {
7823
- const confirm8 = await confirm2({
7824
- message: `Remove Stripe ${environment} key? Payment sync and mutations for this environment will stop.`
8144
+ if (!keySecret) {
8145
+ if (json) {
8146
+ throw new CLIError("Provide --key-secret when using --json.");
8147
+ }
8148
+ const input = await password2({
8149
+ message: `Razorpay ${environment} key secret`
7825
8150
  });
7826
- if (isCancel2(confirm8) || !confirm8) process.exit(0);
8151
+ if (isCancel2(input)) process.exit(0);
8152
+ keySecret = input;
7827
8153
  }
7828
- const data = await removeStripeSecretKey(environment);
8154
+ const data = await setRazorpayKeys(environment, {
8155
+ keyId,
8156
+ keySecret
8157
+ });
7829
8158
  if (json) {
7830
8159
  outputJson(data);
7831
8160
  } else {
7832
- outputSuccess(`Stripe ${environment} key removed.`);
8161
+ outputSuccess(`Razorpay ${environment} keys configured.`);
7833
8162
  }
7834
- await trackPaymentUsage("config.remove", true, { environment });
8163
+ await trackPaymentUsage("config.set", true, {
8164
+ provider: "razorpay",
8165
+ environment
8166
+ });
7835
8167
  } catch (err) {
7836
- await trackPaymentUsage("config.remove", false, { environment: environmentValue });
8168
+ await trackPaymentUsage(
8169
+ "config.set",
8170
+ false,
8171
+ {
8172
+ provider: "razorpay",
8173
+ environment: opts.environment
8174
+ },
8175
+ err
8176
+ );
7837
8177
  handleError(err, json);
7838
8178
  }
7839
8179
  });
@@ -7852,21 +8192,23 @@ function formatPaymentMethod(customer) {
7852
8192
  }
7853
8193
  return "-";
7854
8194
  }
7855
- function registerPaymentsCustomersCommand(paymentsCmd2) {
7856
- paymentsCmd2.command("customers").description("List mirrored Stripe customers").requiredOption(
8195
+ function registerPaymentsCustomersCommand(paymentsCmd2, provider) {
8196
+ paymentsCmd2.command("customers").description("List mirrored payment provider customers").requiredOption(
7857
8197
  "--environment <environment>",
7858
- "Stripe environment: test or live"
8198
+ "Payment environment: test or live"
7859
8199
  ).option("--limit <limit>", "Maximum rows to return (1-100)", "50").action(async (opts, cmd) => {
7860
8200
  const { json } = getRootOpts(cmd);
7861
8201
  try {
7862
8202
  const environment = parseEnvironment(opts.environment);
7863
8203
  const limit = parseIntegerOption(opts.limit, "--limit", { min: 1, max: 100 }) ?? 50;
7864
8204
  await requireAuth();
7865
- const data = await listPaymentCustomers(environment, { limit });
8205
+ const data = await listPaymentCustomers(provider, environment, {
8206
+ limit
8207
+ });
7866
8208
  if (json) {
7867
8209
  outputJson(data);
7868
8210
  } else if (data.customers.length === 0) {
7869
- console.log("No Stripe customers found.");
8211
+ console.log(`No ${provider} customers found.`);
7870
8212
  } else {
7871
8213
  outputTable(
7872
8214
  [
@@ -7880,7 +8222,7 @@ function registerPaymentsCustomersCommand(paymentsCmd2) {
7880
8222
  "Country"
7881
8223
  ],
7882
8224
  data.customers.map((customer) => [
7883
- customer.stripeCustomerId,
8225
+ customer.providerCustomerId,
7884
8226
  customer.email ?? "-",
7885
8227
  customer.name ?? "-",
7886
8228
  String(customer.paymentsCount),
@@ -7891,72 +8233,312 @@ function registerPaymentsCustomersCommand(paymentsCmd2) {
7891
8233
  ])
7892
8234
  );
7893
8235
  }
7894
- await trackPaymentUsage("customers", true, { environment });
8236
+ await trackPaymentUsage("customers", true, { provider, environment });
7895
8237
  } catch (err) {
7896
- await trackPaymentUsage("customers", false, {
7897
- environment: opts.environment
7898
- });
8238
+ await trackPaymentUsage(
8239
+ "customers",
8240
+ false,
8241
+ {
8242
+ provider,
8243
+ environment: opts.environment
8244
+ },
8245
+ err
8246
+ );
7899
8247
  handleError(err, json);
7900
8248
  }
7901
8249
  });
7902
8250
  }
7903
8251
 
7904
- // src/commands/payments/history.ts
7905
- function registerPaymentsHistoryCommand(paymentsCmd2) {
7906
- paymentsCmd2.command("history").description("List mirrored Stripe payment history").requiredOption(
8252
+ // src/commands/payments/items.ts
8253
+ function nullableString(value) {
8254
+ if (value === void 0) return void 0;
8255
+ return value === "null" ? null : value;
8256
+ }
8257
+ function outputItemsTable(items) {
8258
+ if (items.length === 0) {
8259
+ console.log("No Razorpay items found.");
8260
+ return;
8261
+ }
8262
+ outputTable(
8263
+ ["Env", "Item ID", "Name", "Amount", "Active", "Type", "Synced At"],
8264
+ items.map((item) => [
8265
+ item.environment,
8266
+ item.itemId,
8267
+ item.name,
8268
+ formatAmount(item.amount, item.currency),
8269
+ item.active ? "Yes" : "No",
8270
+ item.type ?? "-",
8271
+ formatDate(item.syncedAt)
8272
+ ])
8273
+ );
8274
+ }
8275
+ function registerPaymentsItemsCommand(paymentsCmd2) {
8276
+ const itemsCmd = paymentsCmd2.command("items").description("Manage Razorpay items");
8277
+ itemsCmd.command("list").description("List mirrored Razorpay items").requiredOption(
7907
8278
  "--environment <environment>",
7908
- "Stripe environment: test or live"
7909
- ).option("--subject-type <type>", "Filter by billing subject type").option("--subject-id <id>", "Filter by billing subject id").option("--limit <limit>", "Maximum rows to return (1-100)", "50").action(async (opts, cmd) => {
8279
+ "Razorpay environment: test or live"
8280
+ ).action(async (opts, cmd) => {
7910
8281
  const { json } = getRootOpts(cmd);
7911
8282
  try {
7912
8283
  const environment = parseEnvironment(opts.environment);
7913
- const limit = parseIntegerOption(opts.limit, "--limit", { min: 1, max: 100 }) ?? 50;
7914
8284
  await requireAuth();
7915
- const data = await listPaymentHistory(environment, {
7916
- limit,
7917
- ...opts.subjectType !== void 0 ? { subjectType: opts.subjectType } : {},
7918
- ...opts.subjectId !== void 0 ? { subjectId: opts.subjectId } : {}
8285
+ const data = await listRazorpayCatalog(environment);
8286
+ if (json) {
8287
+ outputJson({ items: data.items });
8288
+ } else {
8289
+ outputItemsTable(data.items);
8290
+ }
8291
+ await trackPaymentUsage("items.list", true, {
8292
+ provider: "razorpay",
8293
+ environment
7919
8294
  });
8295
+ } catch (err) {
8296
+ await trackPaymentUsage(
8297
+ "items.list",
8298
+ false,
8299
+ {
8300
+ provider: "razorpay",
8301
+ environment: opts.environment
8302
+ },
8303
+ err
8304
+ );
8305
+ handleError(err, json);
8306
+ }
8307
+ });
8308
+ itemsCmd.command("create").description("Create a Razorpay item").requiredOption(
8309
+ "--environment <environment>",
8310
+ "Razorpay environment: test or live"
8311
+ ).requiredOption("--name <name>", "Item name").requiredOption("--amount <amount>", "Amount in the smallest currency unit").requiredOption(
8312
+ "--currency <currency>",
8313
+ "Three-letter currency code, e.g. inr"
8314
+ ).option("--description <description>", 'Item description, or "null"').option("--metadata <json>", "Metadata JSON object with string values").action(async (opts, cmd) => {
8315
+ const { json } = getRootOpts(cmd);
8316
+ try {
8317
+ const environment = parseEnvironment(opts.environment);
8318
+ await requireAuth();
8319
+ const request = {
8320
+ name: opts.name,
8321
+ amount: parseIntegerOption(opts.amount, "--amount", { min: 0 }) ?? 0,
8322
+ currency: opts.currency
8323
+ };
8324
+ const description = nullableString(opts.description);
8325
+ const metadata = parseMetadataOption(opts.metadata);
8326
+ if (description !== void 0) request.description = description;
8327
+ if (metadata !== void 0) request.metadata = metadata;
8328
+ const data = await createRazorpayItem(environment, request);
7920
8329
  if (json) {
7921
8330
  outputJson(data);
7922
- } else if (data.paymentHistory.length === 0) {
7923
- console.log("No Stripe payment history found.");
7924
8331
  } else {
7925
- outputTable(
7926
- [
7927
- "Type",
7928
- "Status",
7929
- "Subject",
7930
- "Amount",
7931
- "Customer",
7932
- "Stripe Object",
7933
- "When"
7934
- ],
7935
- data.paymentHistory.map((entry) => [
7936
- entry.type,
7937
- entry.status,
7938
- entry.subjectType && entry.subjectId ? `${entry.subjectType}:${entry.subjectId}` : "-",
7939
- formatAmount(entry.amount, entry.currency),
7940
- entry.stripeCustomerId ?? "-",
7941
- entry.stripeCheckoutSessionId ?? entry.stripeInvoiceId ?? entry.stripePaymentIntentId ?? entry.stripeRefundId ?? "-",
7942
- formatDate(
7943
- entry.paidAt ?? entry.failedAt ?? entry.refundedAt ?? entry.stripeCreatedAt
7944
- )
7945
- ])
8332
+ outputSuccess(`Razorpay item created: ${data.item.itemId}`);
8333
+ }
8334
+ await trackPaymentUsage("items.create", true, {
8335
+ provider: "razorpay",
8336
+ environment
8337
+ });
8338
+ } catch (err) {
8339
+ await trackPaymentUsage(
8340
+ "items.create",
8341
+ false,
8342
+ {
8343
+ provider: "razorpay",
8344
+ environment: opts.environment
8345
+ },
8346
+ err
8347
+ );
8348
+ handleError(err, json);
8349
+ }
8350
+ });
8351
+ itemsCmd.command("update <itemId>").description("Update a Razorpay item").requiredOption(
8352
+ "--environment <environment>",
8353
+ "Razorpay environment: test or live"
8354
+ ).option("--name <name>", "Item name").option("--description <description>", 'Item description, or "null"').option("--amount <amount>", "Amount in the smallest currency unit").option("--currency <currency>", "Three-letter currency code").option("--active <bool>", "Set active status (true/false)").option("--metadata <json>", "Metadata JSON object with string values").action(async (itemId, opts, cmd) => {
8355
+ const { json } = getRootOpts(cmd);
8356
+ try {
8357
+ const environment = parseEnvironment(opts.environment);
8358
+ await requireAuth();
8359
+ const request = {};
8360
+ const description = nullableString(opts.description);
8361
+ const amount = parseIntegerOption(opts.amount, "--amount", { min: 0 });
8362
+ const active = parseBooleanOption(opts.active, "--active");
8363
+ const metadata = parseMetadataOption(opts.metadata);
8364
+ if (opts.name !== void 0) request.name = opts.name;
8365
+ if (description !== void 0) request.description = description;
8366
+ if (amount !== void 0) request.amount = amount;
8367
+ if (opts.currency !== void 0) request.currency = opts.currency;
8368
+ if (active !== void 0) request.active = active;
8369
+ if (metadata !== void 0) request.metadata = metadata;
8370
+ if (Object.keys(request).length === 0) {
8371
+ throw new CLIError(
8372
+ "Provide at least one option to update (--name, --description, --amount, --currency, --active, --metadata)."
7946
8373
  );
7947
8374
  }
7948
- await trackPaymentUsage("history", true, { environment });
8375
+ const data = await updateRazorpayItem(environment, itemId, request);
8376
+ if (json) {
8377
+ outputJson(data);
8378
+ } else {
8379
+ outputSuccess(`Razorpay item updated: ${data.item.itemId}`);
8380
+ }
8381
+ await trackPaymentUsage("items.update", true, {
8382
+ provider: "razorpay",
8383
+ environment
8384
+ });
7949
8385
  } catch (err) {
7950
- await trackPaymentUsage("history", false, {
7951
- environment: opts.environment
8386
+ await trackPaymentUsage(
8387
+ "items.update",
8388
+ false,
8389
+ {
8390
+ provider: "razorpay",
8391
+ environment: opts.environment
8392
+ },
8393
+ err
8394
+ );
8395
+ handleError(err, json);
8396
+ }
8397
+ });
8398
+ }
8399
+
8400
+ // src/commands/payments/plans.ts
8401
+ function nullableString2(value) {
8402
+ if (value === void 0) return void 0;
8403
+ return value === "null" ? null : value;
8404
+ }
8405
+ function outputPlansTable(plans) {
8406
+ if (plans.length === 0) {
8407
+ console.log("No Razorpay plans found.");
8408
+ return;
8409
+ }
8410
+ outputTable(
8411
+ [
8412
+ "Env",
8413
+ "Plan ID",
8414
+ "Item ID",
8415
+ "Amount",
8416
+ "Period",
8417
+ "Interval",
8418
+ "Active",
8419
+ "Synced At"
8420
+ ],
8421
+ plans.map((plan) => [
8422
+ plan.environment,
8423
+ plan.planId,
8424
+ plan.itemId,
8425
+ formatAmount(plan.amount, plan.currency),
8426
+ plan.period,
8427
+ String(plan.interval),
8428
+ plan.active ? "Yes" : "No",
8429
+ formatDate(plan.syncedAt)
8430
+ ])
8431
+ );
8432
+ }
8433
+ function registerPaymentsPlansCommand(paymentsCmd2) {
8434
+ const plansCmd = paymentsCmd2.command("plans").description("Manage Razorpay plans");
8435
+ plansCmd.command("list").description("List mirrored Razorpay plans").requiredOption(
8436
+ "--environment <environment>",
8437
+ "Razorpay environment: test or live"
8438
+ ).action(async (opts, cmd) => {
8439
+ const { json } = getRootOpts(cmd);
8440
+ try {
8441
+ const environment = parseEnvironment(opts.environment);
8442
+ await requireAuth();
8443
+ const data = await listRazorpayCatalog(environment);
8444
+ if (json) {
8445
+ outputJson({ plans: data.plans });
8446
+ } else {
8447
+ outputPlansTable(data.plans);
8448
+ }
8449
+ await trackPaymentUsage("plans.list", true, {
8450
+ provider: "razorpay",
8451
+ environment
7952
8452
  });
8453
+ } catch (err) {
8454
+ await trackPaymentUsage(
8455
+ "plans.list",
8456
+ false,
8457
+ {
8458
+ provider: "razorpay",
8459
+ environment: opts.environment
8460
+ },
8461
+ err
8462
+ );
8463
+ handleError(err, json);
8464
+ }
8465
+ });
8466
+ plansCmd.command("create").description("Create a Razorpay subscription plan").requiredOption(
8467
+ "--environment <environment>",
8468
+ "Razorpay environment: test or live"
8469
+ ).requiredOption(
8470
+ "--period <period>",
8471
+ "Plan period: daily, weekly, monthly, or yearly"
8472
+ ).requiredOption("--interval <count>", "Billing interval count").requiredOption("--item-name <name>", "Plan item name").requiredOption(
8473
+ "--item-amount <amount>",
8474
+ "Plan item amount in the smallest currency unit"
8475
+ ).requiredOption(
8476
+ "--item-currency <currency>",
8477
+ "Three-letter currency code, e.g. inr"
8478
+ ).option(
8479
+ "--item-description <description>",
8480
+ 'Plan item description, or "null"'
8481
+ ).option("--metadata <json>", "Metadata JSON object with string values").action(async (opts, cmd) => {
8482
+ const { json } = getRootOpts(cmd);
8483
+ try {
8484
+ const environment = parseEnvironment(opts.environment);
8485
+ const period = parseRazorpayPlanPeriod(opts.period);
8486
+ const interval = parseIntegerOption(opts.interval, "--interval", {
8487
+ min: 1
8488
+ });
8489
+ const itemAmount = parseIntegerOption(
8490
+ opts.itemAmount,
8491
+ "--item-amount",
8492
+ { min: 0 }
8493
+ );
8494
+ if (!period || interval === void 0 || itemAmount === void 0) {
8495
+ throw new CLIError(
8496
+ "Provide --period, --interval, and --item-amount."
8497
+ );
8498
+ }
8499
+ await requireAuth();
8500
+ const request = {
8501
+ period,
8502
+ interval,
8503
+ item: {
8504
+ name: opts.itemName,
8505
+ amount: itemAmount,
8506
+ currency: opts.itemCurrency
8507
+ }
8508
+ };
8509
+ const itemDescription = nullableString2(opts.itemDescription);
8510
+ const metadata = parseMetadataOption(opts.metadata);
8511
+ if (itemDescription !== void 0) {
8512
+ request.item.description = itemDescription;
8513
+ }
8514
+ if (metadata !== void 0) request.metadata = metadata;
8515
+ const data = await createRazorpayPlan(environment, request);
8516
+ if (json) {
8517
+ outputJson(data);
8518
+ } else {
8519
+ outputSuccess(`Razorpay plan created: ${data.plan.planId}`);
8520
+ }
8521
+ await trackPaymentUsage("plans.create", true, {
8522
+ provider: "razorpay",
8523
+ environment
8524
+ });
8525
+ } catch (err) {
8526
+ await trackPaymentUsage(
8527
+ "plans.create",
8528
+ false,
8529
+ {
8530
+ provider: "razorpay",
8531
+ environment: opts.environment
8532
+ },
8533
+ err
8534
+ );
7953
8535
  handleError(err, json);
7954
8536
  }
7955
8537
  });
7956
8538
  }
7957
8539
 
7958
8540
  // src/commands/payments/prices.ts
7959
- function nullableString(value) {
8541
+ function nullableString3(value) {
7960
8542
  if (value === void 0) return void 0;
7961
8543
  return value === "null" ? null : value;
7962
8544
  }
@@ -7998,8 +8580,8 @@ function outputPricesTable(prices) {
7998
8580
  ],
7999
8581
  prices.map((price) => [
8000
8582
  price.environment,
8001
- price.stripePriceId,
8002
- price.stripeProductId ?? "-",
8583
+ price.priceId,
8584
+ price.productId ?? "-",
8003
8585
  formatAmount(price.unitAmount, price.currency),
8004
8586
  price.type,
8005
8587
  price.active ? "Yes" : "No",
@@ -8018,17 +8600,26 @@ function registerPaymentsPricesCommand(paymentsCmd2) {
8018
8600
  try {
8019
8601
  const environment = parseEnvironment(opts.environment);
8020
8602
  await requireAuth();
8021
- const data = await listPaymentPrices(environment, opts.product);
8603
+ const data = await listStripePrices(environment, opts.product);
8022
8604
  if (json) {
8023
8605
  outputJson(data);
8024
8606
  } else {
8025
8607
  outputPricesTable(data.prices);
8026
8608
  }
8027
- await trackPaymentUsage("prices.list", true, { environment });
8028
- } catch (err) {
8029
- await trackPaymentUsage("prices.list", false, {
8030
- environment: opts.environment
8609
+ await trackPaymentUsage("prices.list", true, {
8610
+ provider: "stripe",
8611
+ environment
8031
8612
  });
8613
+ } catch (err) {
8614
+ await trackPaymentUsage(
8615
+ "prices.list",
8616
+ false,
8617
+ {
8618
+ provider: "stripe",
8619
+ environment: opts.environment
8620
+ },
8621
+ err
8622
+ );
8032
8623
  handleError(err, json);
8033
8624
  }
8034
8625
  });
@@ -8040,17 +8631,26 @@ function registerPaymentsPricesCommand(paymentsCmd2) {
8040
8631
  try {
8041
8632
  const environment = parseEnvironment(opts.environment);
8042
8633
  await requireAuth();
8043
- const data = await getPaymentPrice(environment, priceId);
8634
+ const data = await getStripePrice(environment, priceId);
8044
8635
  if (json) {
8045
8636
  outputJson(data);
8046
8637
  } else {
8047
8638
  outputPricesTable([data.price]);
8048
8639
  }
8049
- await trackPaymentUsage("prices.get", true, { environment });
8050
- } catch (err) {
8051
- await trackPaymentUsage("prices.get", false, {
8052
- environment: opts.environment
8640
+ await trackPaymentUsage("prices.get", true, {
8641
+ provider: "stripe",
8642
+ environment
8053
8643
  });
8644
+ } catch (err) {
8645
+ await trackPaymentUsage(
8646
+ "prices.get",
8647
+ false,
8648
+ {
8649
+ provider: "stripe",
8650
+ environment: opts.environment
8651
+ },
8652
+ err
8653
+ );
8054
8654
  handleError(err, json);
8055
8655
  }
8056
8656
  });
@@ -8081,11 +8681,11 @@ function registerPaymentsPricesCommand(paymentsCmd2) {
8081
8681
  throw new CLIError("Provide --interval when using --interval-count.");
8082
8682
  }
8083
8683
  const request = {
8084
- stripeProductId: opts.product,
8684
+ productId: opts.product,
8085
8685
  currency: opts.currency,
8086
8686
  unitAmount: parseIntegerOption(opts.unitAmount, "--unit-amount", { min: 0 }) ?? 0
8087
8687
  };
8088
- const lookupKey = nullableString(opts.lookupKey);
8688
+ const lookupKey = nullableString3(opts.lookupKey);
8089
8689
  const active = parseBooleanOption(opts.active, "--active");
8090
8690
  const taxBehavior = parseTaxBehavior(opts.taxBehavior);
8091
8691
  const metadata = parseMetadataOption(opts.metadata);
@@ -8102,17 +8702,26 @@ function registerPaymentsPricesCommand(paymentsCmd2) {
8102
8702
  ...intervalCount !== void 0 ? { intervalCount } : {}
8103
8703
  };
8104
8704
  }
8105
- const data = await createPaymentPrice(environment, request);
8705
+ const data = await createStripePrice(environment, request);
8106
8706
  if (json) {
8107
8707
  outputJson(data);
8108
8708
  } else {
8109
- outputSuccess(`Stripe price created: ${data.price.stripePriceId}`);
8709
+ outputSuccess(`Stripe price created: ${data.price.priceId}`);
8110
8710
  }
8111
- await trackPaymentUsage("prices.create", true, { environment });
8112
- } catch (err) {
8113
- await trackPaymentUsage("prices.create", false, {
8114
- environment: opts.environment
8711
+ await trackPaymentUsage("prices.create", true, {
8712
+ provider: "stripe",
8713
+ environment
8115
8714
  });
8715
+ } catch (err) {
8716
+ await trackPaymentUsage(
8717
+ "prices.create",
8718
+ false,
8719
+ {
8720
+ provider: "stripe",
8721
+ environment: opts.environment
8722
+ },
8723
+ err
8724
+ );
8116
8725
  handleError(err, json);
8117
8726
  }
8118
8727
  });
@@ -8126,7 +8735,7 @@ function registerPaymentsPricesCommand(paymentsCmd2) {
8126
8735
  await requireAuth();
8127
8736
  const request = {};
8128
8737
  const active = parseBooleanOption(opts.active, "--active");
8129
- const lookupKey = nullableString(opts.lookupKey);
8738
+ const lookupKey = nullableString3(opts.lookupKey);
8130
8739
  const taxBehavior = parseTaxBehavior(opts.taxBehavior);
8131
8740
  const metadata = parseMetadataOption(opts.metadata);
8132
8741
  if (active !== void 0) request.active = active;
@@ -8138,21 +8747,30 @@ function registerPaymentsPricesCommand(paymentsCmd2) {
8138
8747
  "Provide at least one option to update (--active, --lookup-key, --tax-behavior, --metadata)."
8139
8748
  );
8140
8749
  }
8141
- const data = await updatePaymentPrice(environment, priceId, request);
8750
+ const data = await updateStripePrice(environment, priceId, request);
8142
8751
  if (json) {
8143
8752
  outputJson(data);
8144
8753
  } else {
8145
- outputSuccess(`Stripe price updated: ${data.price.stripePriceId}`);
8754
+ outputSuccess(`Stripe price updated: ${data.price.priceId}`);
8146
8755
  }
8147
- await trackPaymentUsage("prices.update", true, { environment });
8148
- } catch (err) {
8149
- await trackPaymentUsage("prices.update", false, {
8150
- environment: opts.environment
8756
+ await trackPaymentUsage("prices.update", true, {
8757
+ provider: "stripe",
8758
+ environment
8151
8759
  });
8760
+ } catch (err) {
8761
+ await trackPaymentUsage(
8762
+ "prices.update",
8763
+ false,
8764
+ {
8765
+ provider: "stripe",
8766
+ environment: opts.environment
8767
+ },
8768
+ err
8769
+ );
8152
8770
  handleError(err, json);
8153
8771
  }
8154
8772
  });
8155
- pricesCmd.command("archive <priceId>").alias("delete").description("Archive a Stripe price").requiredOption(
8773
+ pricesCmd.command("archive <priceId>").description("Archive a Stripe price").requiredOption(
8156
8774
  "--environment <environment>",
8157
8775
  "Stripe environment: test or live"
8158
8776
  ).action(async (priceId, opts, cmd) => {
@@ -8160,24 +8778,33 @@ function registerPaymentsPricesCommand(paymentsCmd2) {
8160
8778
  try {
8161
8779
  const environment = parseEnvironment(opts.environment);
8162
8780
  await requireAuth();
8163
- const data = await archivePaymentPrice(environment, priceId);
8781
+ const data = await archiveStripePrice(environment, priceId);
8164
8782
  if (json) {
8165
8783
  outputJson(data);
8166
8784
  } else {
8167
- outputSuccess(`Stripe price archived: ${data.price.stripePriceId}`);
8785
+ outputSuccess(`Stripe price archived: ${data.price.priceId}`);
8168
8786
  }
8169
- await trackPaymentUsage("prices.archive", true, { environment });
8170
- } catch (err) {
8171
- await trackPaymentUsage("prices.archive", false, {
8172
- environment: opts.environment
8787
+ await trackPaymentUsage("prices.archive", true, {
8788
+ provider: "stripe",
8789
+ environment
8173
8790
  });
8791
+ } catch (err) {
8792
+ await trackPaymentUsage(
8793
+ "prices.archive",
8794
+ false,
8795
+ {
8796
+ provider: "stripe",
8797
+ environment: opts.environment
8798
+ },
8799
+ err
8800
+ );
8174
8801
  handleError(err, json);
8175
8802
  }
8176
8803
  });
8177
8804
  }
8178
8805
 
8179
8806
  // src/commands/payments/products.ts
8180
- function nullableString2(value) {
8807
+ function nullableString4(value) {
8181
8808
  if (value === void 0) return void 0;
8182
8809
  return value === "null" ? null : value;
8183
8810
  }
@@ -8190,7 +8817,7 @@ function outputProductsTable(products) {
8190
8817
  ["Env", "Product ID", "Name", "Active", "Default Price", "Synced At"],
8191
8818
  products.map((product) => [
8192
8819
  product.environment,
8193
- product.stripeProductId,
8820
+ product.productId,
8194
8821
  product.name,
8195
8822
  product.active ? "Yes" : "No",
8196
8823
  product.defaultPriceId ?? "-",
@@ -8208,17 +8835,26 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
8208
8835
  try {
8209
8836
  const environment = parseEnvironment(opts.environment);
8210
8837
  await requireAuth();
8211
- const data = await listPaymentProducts(environment);
8838
+ const data = await listStripeProducts(environment);
8212
8839
  if (json) {
8213
8840
  outputJson(data);
8214
8841
  } else {
8215
8842
  outputProductsTable(data.products);
8216
8843
  }
8217
- await trackPaymentUsage("products.list", true, { environment });
8218
- } catch (err) {
8219
- await trackPaymentUsage("products.list", false, {
8220
- environment: opts.environment
8844
+ await trackPaymentUsage("products.list", true, {
8845
+ provider: "stripe",
8846
+ environment
8221
8847
  });
8848
+ } catch (err) {
8849
+ await trackPaymentUsage(
8850
+ "products.list",
8851
+ false,
8852
+ {
8853
+ provider: "stripe",
8854
+ environment: opts.environment
8855
+ },
8856
+ err
8857
+ );
8222
8858
  handleError(err, json);
8223
8859
  }
8224
8860
  });
@@ -8230,7 +8866,7 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
8230
8866
  try {
8231
8867
  const environment = parseEnvironment(opts.environment);
8232
8868
  await requireAuth();
8233
- const data = await getPaymentProduct(environment, productId);
8869
+ const data = await getStripeProduct(environment, productId);
8234
8870
  if (json) {
8235
8871
  outputJson(data);
8236
8872
  } else {
@@ -8240,7 +8876,7 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
8240
8876
  outputTable(
8241
8877
  ["Price ID", "Amount", "Type", "Active", "Lookup Key"],
8242
8878
  data.prices.map((price) => [
8243
- price.stripePriceId,
8879
+ price.priceId,
8244
8880
  formatAmount(price.unitAmount, price.currency),
8245
8881
  price.type,
8246
8882
  price.active ? "Yes" : "No",
@@ -8249,11 +8885,20 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
8249
8885
  );
8250
8886
  }
8251
8887
  }
8252
- await trackPaymentUsage("products.get", true, { environment });
8253
- } catch (err) {
8254
- await trackPaymentUsage("products.get", false, {
8255
- environment: opts.environment
8888
+ await trackPaymentUsage("products.get", true, {
8889
+ provider: "stripe",
8890
+ environment
8256
8891
  });
8892
+ } catch (err) {
8893
+ await trackPaymentUsage(
8894
+ "products.get",
8895
+ false,
8896
+ {
8897
+ provider: "stripe",
8898
+ environment: opts.environment
8899
+ },
8900
+ err
8901
+ );
8257
8902
  handleError(err, json);
8258
8903
  }
8259
8904
  });
@@ -8266,7 +8911,7 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
8266
8911
  const environment = parseEnvironment(opts.environment);
8267
8912
  await requireAuth();
8268
8913
  const request = { name: opts.name };
8269
- const description = nullableString2(opts.description);
8914
+ const description = nullableString4(opts.description);
8270
8915
  const active = parseBooleanOption(opts.active, "--active");
8271
8916
  const metadata = parseMetadataOption(opts.metadata);
8272
8917
  if (description !== void 0) request.description = description;
@@ -8275,19 +8920,26 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
8275
8920
  if (opts.idempotencyKey !== void 0) {
8276
8921
  request.idempotencyKey = opts.idempotencyKey;
8277
8922
  }
8278
- const data = await createPaymentProduct(environment, request);
8923
+ const data = await createStripeProduct(environment, request);
8279
8924
  if (json) {
8280
8925
  outputJson(data);
8281
8926
  } else {
8282
- outputSuccess(
8283
- `Stripe product created: ${data.product.stripeProductId}`
8284
- );
8927
+ outputSuccess(`Stripe product created: ${data.product.productId}`);
8285
8928
  }
8286
- await trackPaymentUsage("products.create", true, { environment });
8287
- } catch (err) {
8288
- await trackPaymentUsage("products.create", false, {
8289
- environment: opts.environment
8929
+ await trackPaymentUsage("products.create", true, {
8930
+ provider: "stripe",
8931
+ environment
8290
8932
  });
8933
+ } catch (err) {
8934
+ await trackPaymentUsage(
8935
+ "products.create",
8936
+ false,
8937
+ {
8938
+ provider: "stripe",
8939
+ environment: opts.environment
8940
+ },
8941
+ err
8942
+ );
8291
8943
  handleError(err, json);
8292
8944
  }
8293
8945
  });
@@ -8300,7 +8952,7 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
8300
8952
  const environment = parseEnvironment(opts.environment);
8301
8953
  await requireAuth();
8302
8954
  const request = {};
8303
- const description = nullableString2(opts.description);
8955
+ const description = nullableString4(opts.description);
8304
8956
  const active = parseBooleanOption(opts.active, "--active");
8305
8957
  const metadata = parseMetadataOption(opts.metadata);
8306
8958
  if (opts.name !== void 0) request.name = opts.name;
@@ -8312,23 +8964,26 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
8312
8964
  "Provide at least one option to update (--name, --description, --active, --metadata)."
8313
8965
  );
8314
8966
  }
8315
- const data = await updatePaymentProduct(
8316
- environment,
8317
- productId,
8318
- request
8319
- );
8967
+ const data = await updateStripeProduct(environment, productId, request);
8320
8968
  if (json) {
8321
8969
  outputJson(data);
8322
8970
  } else {
8323
- outputSuccess(
8324
- `Stripe product updated: ${data.product.stripeProductId}`
8325
- );
8971
+ outputSuccess(`Stripe product updated: ${data.product.productId}`);
8326
8972
  }
8327
- await trackPaymentUsage("products.update", true, { environment });
8328
- } catch (err) {
8329
- await trackPaymentUsage("products.update", false, {
8330
- environment: opts.environment
8973
+ await trackPaymentUsage("products.update", true, {
8974
+ provider: "stripe",
8975
+ environment
8331
8976
  });
8977
+ } catch (err) {
8978
+ await trackPaymentUsage(
8979
+ "products.update",
8980
+ false,
8981
+ {
8982
+ provider: "stripe",
8983
+ environment: opts.environment
8984
+ },
8985
+ err
8986
+ );
8332
8987
  handleError(err, json);
8333
8988
  }
8334
8989
  });
@@ -8351,153 +9006,357 @@ function registerPaymentsProductsCommand(paymentsCmd2) {
8351
9006
  });
8352
9007
  if (isCancel2(confirm8) || !confirm8) process.exit(0);
8353
9008
  }
8354
- const data = await deletePaymentProduct(environment, productId);
9009
+ const data = await deleteStripeProduct(environment, productId);
8355
9010
  if (json) {
8356
9011
  outputJson(data);
8357
9012
  } else {
8358
- outputSuccess(`Stripe product deleted: ${data.stripeProductId}`);
9013
+ outputSuccess(`Stripe product deleted: ${data.productId}`);
8359
9014
  }
8360
- await trackPaymentUsage("products.delete", true, { environment });
8361
- } catch (err) {
8362
- await trackPaymentUsage("products.delete", false, {
8363
- environment: opts.environment
9015
+ await trackPaymentUsage("products.delete", true, {
9016
+ provider: "stripe",
9017
+ environment
8364
9018
  });
9019
+ } catch (err) {
9020
+ await trackPaymentUsage(
9021
+ "products.delete",
9022
+ false,
9023
+ {
9024
+ provider: "stripe",
9025
+ environment: opts.environment
9026
+ },
9027
+ err
9028
+ );
8365
9029
  handleError(err, json);
8366
9030
  }
8367
9031
  });
8368
9032
  }
8369
9033
 
8370
9034
  // src/commands/payments/status.ts
8371
- function registerPaymentsStatusCommand(paymentsCmd2) {
8372
- paymentsCmd2.command("status").description("Show Stripe payment connection, sync, and webhook status").action(async (_opts, cmd) => {
9035
+ function registerPaymentsStatusCommand(paymentsCmd2, provider) {
9036
+ paymentsCmd2.command("status").description("Show payment connection, sync, and webhook status").action(async (opts, cmd) => {
8373
9037
  const { json } = getRootOpts(cmd);
8374
9038
  try {
8375
9039
  await requireAuth();
8376
- const data = await getPaymentsStatus();
8377
- if (json) {
8378
- outputJson(data);
8379
- } else if (data.connections.length === 0) {
8380
- console.log("No Stripe payment environments found.");
9040
+ if (provider === "stripe") {
9041
+ const data = await getStripePaymentsStatus();
9042
+ if (json) {
9043
+ outputJson(data);
9044
+ } else if (data.connections.length === 0) {
9045
+ console.log("No Stripe payment environments found.");
9046
+ } else {
9047
+ outputTable(
9048
+ [
9049
+ "Env",
9050
+ "Status",
9051
+ "Key",
9052
+ "Account",
9053
+ "Webhook",
9054
+ "Last Sync",
9055
+ "Synced At"
9056
+ ],
9057
+ data.connections.map((connection) => [
9058
+ connection.environment,
9059
+ connection.status,
9060
+ connection.maskedKey ?? "-",
9061
+ connection.accountId ?? "-",
9062
+ connection.webhookEndpointId ? "Configured" : "-",
9063
+ connection.lastSyncStatus ?? "-",
9064
+ formatDate(connection.lastSyncedAt)
9065
+ ])
9066
+ );
9067
+ }
8381
9068
  } else {
8382
- outputTable(
8383
- ["Env", "Status", "Key", "Account", "Webhook", "Last Sync", "Synced At"],
8384
- data.connections.map((connection) => [
8385
- connection.environment,
8386
- connection.status,
8387
- connection.maskedKey ?? "-",
8388
- connection.stripeAccountId ?? "-",
8389
- connection.webhookEndpointId ? "Configured" : "-",
8390
- connection.lastSyncStatus ?? "-",
8391
- formatDate(connection.lastSyncedAt)
8392
- ])
8393
- );
9069
+ const data = await getRazorpayPaymentsStatus();
9070
+ if (json) {
9071
+ outputJson(data);
9072
+ } else if (data.razorpayConnections.length === 0) {
9073
+ console.log("No Razorpay payment environments found.");
9074
+ } else {
9075
+ outputTable(
9076
+ [
9077
+ "Env",
9078
+ "Status",
9079
+ "Key",
9080
+ "Account",
9081
+ "Merchant",
9082
+ "Webhook",
9083
+ "Last Sync",
9084
+ "Synced At"
9085
+ ],
9086
+ data.razorpayConnections.map((connection) => [
9087
+ connection.environment,
9088
+ connection.status,
9089
+ connection.maskedKey ?? "-",
9090
+ connection.accountId ?? "-",
9091
+ connection.merchantName ?? "-",
9092
+ connection.webhookEndpointUrl ? "Manual" : "-",
9093
+ connection.lastSyncStatus ?? "-",
9094
+ formatDate(connection.lastSyncedAt)
9095
+ ])
9096
+ );
9097
+ }
8394
9098
  }
8395
- await trackPaymentUsage("status", true);
9099
+ await trackPaymentUsage("status", true, { provider });
8396
9100
  } catch (err) {
8397
- await trackPaymentUsage("status", false);
9101
+ await trackPaymentUsage("status", false, { provider }, err);
8398
9102
  handleError(err, json);
8399
9103
  }
8400
9104
  });
8401
9105
  }
8402
9106
 
8403
9107
  // src/commands/payments/subscriptions.ts
8404
- function registerPaymentsSubscriptionsCommand(paymentsCmd2) {
8405
- paymentsCmd2.command("subscriptions").description("List mirrored Stripe subscriptions").requiredOption(
9108
+ function formatSubject(subjectType, subjectId) {
9109
+ return subjectType && subjectId ? `${subjectType}:${subjectId}` : "-";
9110
+ }
9111
+ function registerPaymentsSubscriptionsCommand(paymentsCmd2, provider) {
9112
+ paymentsCmd2.command("subscriptions").description("List mirrored payment provider subscriptions").requiredOption(
8406
9113
  "--environment <environment>",
8407
- "Stripe environment: test or live"
8408
- ).option("--subject-type <type>", "Filter by billing subject type").option("--subject-id <id>", "Filter by billing subject id").option("--limit <limit>", "Maximum rows to return (1-100)", "50").action(async (opts, cmd) => {
9114
+ "Payment environment: test or live"
9115
+ ).option("--subject-type <type>", "Filter by app billing subject type").option(
9116
+ "--subject-id <id>",
9117
+ "Filter by app billing subject id, not provider id"
9118
+ ).option("--limit <limit>", "Maximum rows to return (1-100)", "50").action(async (opts, cmd) => {
8409
9119
  const { json } = getRootOpts(cmd);
8410
9120
  try {
8411
9121
  const environment = parseEnvironment(opts.environment);
8412
9122
  const limit = parseIntegerOption(opts.limit, "--limit", { min: 1, max: 100 }) ?? 50;
8413
- await requireAuth();
8414
- const data = await listSubscriptions(environment, {
9123
+ const request = {
8415
9124
  limit,
8416
9125
  ...opts.subjectType !== void 0 ? { subjectType: opts.subjectType } : {},
8417
9126
  ...opts.subjectId !== void 0 ? { subjectId: opts.subjectId } : {}
8418
- });
8419
- if (json) {
8420
- outputJson(data);
8421
- } else if (data.subscriptions.length === 0) {
8422
- console.log("No Stripe subscriptions found.");
9127
+ };
9128
+ await requireAuth();
9129
+ if (provider === "stripe") {
9130
+ const data = await listStripeSubscriptions(environment, request);
9131
+ if (json) {
9132
+ outputJson(data);
9133
+ } else if (data.subscriptions.length === 0) {
9134
+ console.log("No Stripe subscriptions found.");
9135
+ } else {
9136
+ outputTable(
9137
+ [
9138
+ "Subscription ID",
9139
+ "Customer",
9140
+ "Subject",
9141
+ "Status",
9142
+ "Items",
9143
+ "Period End"
9144
+ ],
9145
+ data.subscriptions.map((subscription) => [
9146
+ subscription.subscriptionId,
9147
+ subscription.customerId ?? "-",
9148
+ formatSubject(subscription.subjectType, subscription.subjectId),
9149
+ subscription.status,
9150
+ String(subscription.items?.length ?? 0),
9151
+ formatDate(subscription.currentPeriodEnd)
9152
+ ])
9153
+ );
9154
+ }
8423
9155
  } else {
8424
- outputTable(
8425
- [
8426
- "Subscription ID",
8427
- "Customer",
8428
- "Subject",
8429
- "Status",
8430
- "Items",
8431
- "Period End"
8432
- ],
8433
- data.subscriptions.map((subscription) => [
8434
- subscription.stripeSubscriptionId,
8435
- subscription.stripeCustomerId,
8436
- subscription.subjectType && subscription.subjectId ? `${subscription.subjectType}:${subscription.subjectId}` : "-",
8437
- subscription.status,
8438
- String(subscription.items?.length ?? 0),
8439
- formatDate(subscription.currentPeriodEnd)
8440
- ])
8441
- );
9156
+ const data = await listRazorpaySubscriptions(environment, request);
9157
+ if (json) {
9158
+ outputJson(data);
9159
+ } else if (data.subscriptions.length === 0) {
9160
+ console.log("No Razorpay subscriptions found.");
9161
+ } else {
9162
+ outputTable(
9163
+ [
9164
+ "Subscription ID",
9165
+ "Plan ID",
9166
+ "Customer",
9167
+ "Subject",
9168
+ "Status",
9169
+ "Paid",
9170
+ "Remaining",
9171
+ "Current End"
9172
+ ],
9173
+ data.subscriptions.map((subscription) => [
9174
+ subscription.subscriptionId,
9175
+ subscription.planId,
9176
+ subscription.customerId ?? "-",
9177
+ formatSubject(subscription.subjectType, subscription.subjectId),
9178
+ subscription.status,
9179
+ String(subscription.paidCount ?? "-"),
9180
+ String(subscription.remainingCount ?? "-"),
9181
+ formatDate(subscription.currentEnd)
9182
+ ])
9183
+ );
9184
+ }
8442
9185
  }
8443
- await trackPaymentUsage("subscriptions", true, { environment });
8444
- } catch (err) {
8445
- await trackPaymentUsage("subscriptions", false, {
8446
- environment: opts.environment
9186
+ await trackPaymentUsage("subscriptions", true, {
9187
+ provider,
9188
+ environment
8447
9189
  });
9190
+ } catch (err) {
9191
+ await trackPaymentUsage(
9192
+ "subscriptions",
9193
+ false,
9194
+ {
9195
+ provider,
9196
+ environment: opts.environment
9197
+ },
9198
+ err
9199
+ );
8448
9200
  handleError(err, json);
8449
9201
  }
8450
9202
  });
8451
9203
  }
8452
9204
 
8453
9205
  // src/commands/payments/sync.ts
8454
- function registerPaymentsSyncCommand(paymentsCmd2) {
8455
- paymentsCmd2.command("sync").description(
8456
- "Sync configured Stripe products, prices, customers, and subscriptions"
8457
- ).option(
9206
+ function registerPaymentsSyncCommand(paymentsCmd2, provider) {
9207
+ paymentsCmd2.command("sync").description("Sync configured payment provider data").option(
8458
9208
  "--environment <environment>",
8459
- "Stripe environment: test, live, or all",
9209
+ "Payment environment: test, live, or all",
8460
9210
  "all"
8461
9211
  ).action(async (opts, cmd) => {
8462
9212
  const { json } = getRootOpts(cmd);
8463
9213
  try {
8464
9214
  const environment = parseEnvironmentOrAll(opts.environment);
8465
9215
  await requireAuth();
8466
- const data = await syncPayments(environment);
9216
+ if (provider === "stripe") {
9217
+ const data = await syncStripePayments(environment);
9218
+ if (json) {
9219
+ outputJson(data);
9220
+ } else if (data.results.length === 0) {
9221
+ console.log("No configured Stripe environments to sync.");
9222
+ } else {
9223
+ outputTable(
9224
+ [
9225
+ "Env",
9226
+ "Status",
9227
+ "Products",
9228
+ "Prices",
9229
+ "Customers",
9230
+ "Subscriptions",
9231
+ "Unmapped",
9232
+ "Synced At"
9233
+ ],
9234
+ data.results.map((result) => [
9235
+ result.environment,
9236
+ result.connection.lastSyncStatus ?? result.connection.status,
9237
+ String(result.connection.lastSyncCounts.products ?? 0),
9238
+ String(result.connection.lastSyncCounts.prices ?? 0),
9239
+ String(result.connection.lastSyncCounts.customers ?? 0),
9240
+ String(result.subscriptions?.synced ?? 0),
9241
+ String(result.subscriptions?.unmapped ?? 0),
9242
+ formatDate(result.connection.lastSyncedAt)
9243
+ ])
9244
+ );
9245
+ outputSuccess("Stripe payments synced.");
9246
+ }
9247
+ } else {
9248
+ const data = await syncRazorpayPayments(environment);
9249
+ if (json) {
9250
+ outputJson(data);
9251
+ } else if (data.results.length === 0) {
9252
+ console.log("No configured Razorpay environments to sync.");
9253
+ } else {
9254
+ outputTable(
9255
+ [
9256
+ "Env",
9257
+ "Status",
9258
+ "Items",
9259
+ "Plans",
9260
+ "Customers",
9261
+ "Subscriptions",
9262
+ "Invoices",
9263
+ "Payments",
9264
+ "Synced At"
9265
+ ],
9266
+ data.results.map((result) => [
9267
+ result.environment,
9268
+ result.status,
9269
+ String(result.syncCounts.items),
9270
+ String(result.syncCounts.plans),
9271
+ String(result.syncCounts.customers),
9272
+ String(result.syncCounts.subscriptions),
9273
+ String(result.syncCounts.invoices),
9274
+ String(result.syncCounts.payments),
9275
+ formatDate(result.connection.lastSyncedAt)
9276
+ ])
9277
+ );
9278
+ outputSuccess("Razorpay payments synced.");
9279
+ }
9280
+ }
9281
+ await trackPaymentUsage("sync", true, { provider, environment });
9282
+ } catch (err) {
9283
+ await trackPaymentUsage(
9284
+ "sync",
9285
+ false,
9286
+ {
9287
+ provider,
9288
+ environment: opts.environment
9289
+ },
9290
+ err
9291
+ );
9292
+ handleError(err, json);
9293
+ }
9294
+ });
9295
+ }
9296
+
9297
+ // src/commands/payments/transactions.ts
9298
+ function registerPaymentsTransactionsCommand(paymentsCmd2, provider) {
9299
+ paymentsCmd2.command("transactions").description("List mirrored payment transactions").requiredOption(
9300
+ "--environment <environment>",
9301
+ "Payment environment: test or live"
9302
+ ).option("--subject-type <type>", "Filter by app billing subject type").option(
9303
+ "--subject-id <id>",
9304
+ "Filter by app billing subject id, not provider id"
9305
+ ).option("--limit <limit>", "Maximum rows to return (1-100)", "50").action(async (opts, cmd) => {
9306
+ const { json } = getRootOpts(cmd);
9307
+ try {
9308
+ const environment = parseEnvironment(opts.environment);
9309
+ const limit = parseIntegerOption(opts.limit, "--limit", { min: 1, max: 100 }) ?? 50;
9310
+ await requireAuth();
9311
+ const data = await listPaymentTransactions(provider, environment, {
9312
+ limit,
9313
+ ...opts.subjectType !== void 0 ? { subjectType: opts.subjectType } : {},
9314
+ ...opts.subjectId !== void 0 ? { subjectId: opts.subjectId } : {}
9315
+ });
8467
9316
  if (json) {
8468
9317
  outputJson(data);
8469
- } else if (data.results.length === 0) {
8470
- console.log("No configured Stripe environments to sync.");
9318
+ } else if (data.transactions.length === 0) {
9319
+ console.log(`No ${provider} transactions found.`);
8471
9320
  } else {
8472
9321
  outputTable(
8473
9322
  [
8474
- "Env",
9323
+ "Type",
8475
9324
  "Status",
8476
- "Products",
8477
- "Prices",
8478
- "Customers",
8479
- "Subscriptions",
8480
- "Unmapped",
8481
- "Synced At"
9325
+ "Subject",
9326
+ "Amount",
9327
+ "Refunded",
9328
+ "Customer",
9329
+ "Provider Object",
9330
+ "When"
8482
9331
  ],
8483
- data.results.map((result) => [
8484
- result.environment,
8485
- result.connection.lastSyncStatus ?? result.connection.status,
8486
- String(result.connection.lastSyncCounts.products ?? 0),
8487
- String(result.connection.lastSyncCounts.prices ?? 0),
8488
- String(result.connection.lastSyncCounts.customers ?? 0),
8489
- String(result.subscriptions?.synced ?? 0),
8490
- String(result.subscriptions?.unmapped ?? 0),
8491
- formatDate(result.connection.lastSyncedAt)
9332
+ data.transactions.map((entry) => [
9333
+ entry.type,
9334
+ entry.status,
9335
+ entry.subjectType && entry.subjectId ? `${entry.subjectType}:${entry.subjectId}` : "-",
9336
+ formatAmount(entry.amount, entry.currency),
9337
+ formatAmount(entry.amountRefunded, entry.currency),
9338
+ entry.providerCustomerId ?? entry.customerEmailSnapshot ?? "-",
9339
+ entry.providerReferenceType && entry.providerReferenceId ? `${entry.providerReferenceType}:${entry.providerReferenceId}` : entry.providerReferenceId ?? "-",
9340
+ formatDate(
9341
+ entry.paidAt ?? entry.failedAt ?? entry.refundedAt ?? entry.providerCreatedAt ?? entry.createdAt
9342
+ )
8492
9343
  ])
8493
9344
  );
8494
- outputSuccess("Stripe payments synced.");
8495
9345
  }
8496
- await trackPaymentUsage("sync", true, { environment });
8497
- } catch (err) {
8498
- await trackPaymentUsage("sync", false, {
8499
- environment: opts.environment
9346
+ await trackPaymentUsage("transactions", true, {
9347
+ provider,
9348
+ environment
8500
9349
  });
9350
+ } catch (err) {
9351
+ await trackPaymentUsage(
9352
+ "transactions",
9353
+ false,
9354
+ {
9355
+ provider,
9356
+ environment: opts.environment
9357
+ },
9358
+ err
9359
+ );
8501
9360
  handleError(err, json);
8502
9361
  }
8503
9362
  });
@@ -8505,30 +9364,46 @@ function registerPaymentsSyncCommand(paymentsCmd2) {
8505
9364
 
8506
9365
  // src/commands/payments/webhooks.ts
8507
9366
  function registerPaymentsWebhooksCommand(paymentsCmd2) {
8508
- const webhooksCmd = paymentsCmd2.command("webhooks").description("Manage InsForge-managed Stripe webhooks");
8509
- webhooksCmd.command("configure <environment>").description("Create or recreate the managed Stripe webhook endpoint").action(async (environmentValue, _opts, cmd) => {
9367
+ const webhooksCmd = paymentsCmd2.command("webhooks").description("Manage Stripe webhooks");
9368
+ webhooksCmd.command("configure").description("Create or recreate the managed Stripe webhook endpoint").requiredOption(
9369
+ "--environment <environment>",
9370
+ "Stripe environment: test or live"
9371
+ ).action(async (opts, cmd) => {
8510
9372
  const { json } = getRootOpts(cmd);
8511
9373
  try {
8512
- const environment = parseEnvironment(environmentValue);
9374
+ const environment = parseEnvironment(opts.environment);
8513
9375
  await requireAuth();
8514
- const data = await configurePaymentWebhook(environment);
9376
+ const data = await configureStripeWebhook(environment);
8515
9377
  if (json) {
8516
9378
  outputJson(data);
8517
9379
  } else {
8518
9380
  outputTable(
8519
9381
  ["Env", "Webhook ID", "URL", "Configured At"],
8520
- [[
8521
- data.connection.environment,
8522
- data.connection.webhookEndpointId ?? "-",
8523
- data.connection.webhookEndpointUrl ?? "-",
8524
- formatDate(data.connection.webhookConfiguredAt)
8525
- ]]
9382
+ [
9383
+ [
9384
+ data.connection.environment,
9385
+ data.connection.webhookEndpointId ?? "-",
9386
+ data.connection.webhookEndpointUrl ?? "-",
9387
+ formatDate(data.connection.webhookConfiguredAt)
9388
+ ]
9389
+ ]
8526
9390
  );
8527
9391
  outputSuccess(`Stripe ${environment} webhook configured.`);
8528
9392
  }
8529
- await trackPaymentUsage("webhooks.configure", true, { environment });
9393
+ await trackPaymentUsage("webhooks.configure", true, {
9394
+ provider: "stripe",
9395
+ environment
9396
+ });
8530
9397
  } catch (err) {
8531
- await trackPaymentUsage("webhooks.configure", false, { environment: environmentValue });
9398
+ await trackPaymentUsage(
9399
+ "webhooks.configure",
9400
+ false,
9401
+ {
9402
+ provider: "stripe",
9403
+ environment: opts.environment
9404
+ },
9405
+ err
9406
+ );
8532
9407
  handleError(err, json);
8533
9408
  }
8534
9409
  });
@@ -8536,17 +9411,28 @@ function registerPaymentsWebhooksCommand(paymentsCmd2) {
8536
9411
 
8537
9412
  // src/commands/payments/index.ts
8538
9413
  function registerPaymentsCommands(paymentsCmd2) {
8539
- paymentsCmd2.description("Manage Stripe payments");
8540
- registerPaymentsStatusCommand(paymentsCmd2);
8541
- registerPaymentsConfigCommand(paymentsCmd2);
8542
- registerPaymentsSyncCommand(paymentsCmd2);
8543
- registerPaymentsWebhooksCommand(paymentsCmd2);
8544
- registerPaymentsCatalogCommand(paymentsCmd2);
8545
- registerPaymentsCustomersCommand(paymentsCmd2);
8546
- registerPaymentsProductsCommand(paymentsCmd2);
8547
- registerPaymentsPricesCommand(paymentsCmd2);
8548
- registerPaymentsSubscriptionsCommand(paymentsCmd2);
8549
- registerPaymentsHistoryCommand(paymentsCmd2);
9414
+ paymentsCmd2.description("Manage payments");
9415
+ const stripeCmd = paymentsCmd2.command("stripe").description("Manage Stripe payments");
9416
+ registerPaymentsStatusCommand(stripeCmd, "stripe");
9417
+ registerPaymentsConfigCommand(stripeCmd, "stripe");
9418
+ registerPaymentsSyncCommand(stripeCmd, "stripe");
9419
+ registerPaymentsWebhooksCommand(stripeCmd);
9420
+ registerPaymentsCatalogCommand(stripeCmd, "stripe");
9421
+ registerPaymentsCustomersCommand(stripeCmd, "stripe");
9422
+ registerPaymentsProductsCommand(stripeCmd);
9423
+ registerPaymentsPricesCommand(stripeCmd);
9424
+ registerPaymentsSubscriptionsCommand(stripeCmd, "stripe");
9425
+ registerPaymentsTransactionsCommand(stripeCmd, "stripe");
9426
+ const razorpayCmd = paymentsCmd2.command("razorpay").description("Manage Razorpay payments");
9427
+ registerPaymentsStatusCommand(razorpayCmd, "razorpay");
9428
+ registerPaymentsConfigCommand(razorpayCmd, "razorpay");
9429
+ registerPaymentsSyncCommand(razorpayCmd, "razorpay");
9430
+ registerPaymentsCatalogCommand(razorpayCmd, "razorpay");
9431
+ registerPaymentsCustomersCommand(razorpayCmd, "razorpay");
9432
+ registerPaymentsItemsCommand(razorpayCmd);
9433
+ registerPaymentsPlansCommand(razorpayCmd);
9434
+ registerPaymentsSubscriptionsCommand(razorpayCmd, "razorpay");
9435
+ registerPaymentsTransactionsCommand(razorpayCmd, "razorpay");
8550
9436
  }
8551
9437
 
8552
9438
  // src/commands/posthog/setup.ts
@@ -8950,9 +9836,47 @@ function validateConfig(input) {
8950
9836
  out.project_id = obj.project_id;
8951
9837
  }
8952
9838
  if ("auth" in obj) out.auth = validateAuth(obj.auth);
9839
+ if ("storage" in obj) out.storage = validateStorage(obj.storage);
9840
+ if ("realtime" in obj) out.realtime = validateRetentionSection("realtime", obj.realtime);
9841
+ if ("schedules" in obj) out.schedules = validateRetentionSection("schedules", obj.schedules);
8953
9842
  if ("deployments" in obj) out.deployments = validateDeployments(obj.deployments);
8954
9843
  return out;
8955
9844
  }
9845
+ function validateStorage(input) {
9846
+ if (input === null || typeof input !== "object" || Array.isArray(input)) {
9847
+ throw new ConfigValidationError("storage", "must be an object");
9848
+ }
9849
+ const obj = input;
9850
+ const out = {};
9851
+ if ("max_file_size_mb" in obj) {
9852
+ if (typeof obj.max_file_size_mb !== "number" || !Number.isInteger(obj.max_file_size_mb) || obj.max_file_size_mb < 1 || obj.max_file_size_mb > 200) {
9853
+ throw new ConfigValidationError(
9854
+ "storage.max_file_size_mb",
9855
+ "must be an integer between 1 and 200"
9856
+ );
9857
+ }
9858
+ out.max_file_size_mb = obj.max_file_size_mb;
9859
+ }
9860
+ return out;
9861
+ }
9862
+ function validateRetentionSection(path6, input) {
9863
+ if (input === null || typeof input !== "object" || Array.isArray(input)) {
9864
+ throw new ConfigValidationError(path6, "must be an object");
9865
+ }
9866
+ const obj = input;
9867
+ const out = {};
9868
+ if ("retention_days" in obj) {
9869
+ const v = obj.retention_days;
9870
+ if (v !== null && (typeof v !== "number" || !Number.isInteger(v) || v < 0)) {
9871
+ throw new ConfigValidationError(
9872
+ `${path6}.retention_days`,
9873
+ "must be a non-negative integer or null"
9874
+ );
9875
+ }
9876
+ out.retention_days = v;
9877
+ }
9878
+ return out;
9879
+ }
8956
9880
  function validateDeployments(input) {
8957
9881
  if (input === null || typeof input !== "object" || Array.isArray(input)) {
8958
9882
  throw new ConfigValidationError("deployments", "must be an object");
@@ -9008,6 +9932,12 @@ function validateAuth(input) {
9008
9932
  obj.reset_password_method
9009
9933
  );
9010
9934
  }
9935
+ if ("disable_signup" in obj) {
9936
+ if (typeof obj.disable_signup !== "boolean") {
9937
+ throw new ConfigValidationError("auth.disable_signup", "must be a boolean");
9938
+ }
9939
+ out.disable_signup = obj.disable_signup;
9940
+ }
9011
9941
  if ("password" in obj) out.password = validatePassword(obj.password);
9012
9942
  if ("smtp" in obj) out.smtp = validateSmtp(obj.smtp);
9013
9943
  return out;
@@ -9143,6 +10073,21 @@ function stringifyConfigToml(config) {
9143
10073
  lines.push("");
9144
10074
  }
9145
10075
  }
10076
+ if (config.storage) {
10077
+ lines.push("[storage]");
10078
+ renderStorageFields(config.storage, lines);
10079
+ lines.push("");
10080
+ }
10081
+ if (config.realtime) {
10082
+ lines.push("[realtime]");
10083
+ renderRetentionFields(config.realtime, lines);
10084
+ lines.push("");
10085
+ }
10086
+ if (config.schedules) {
10087
+ lines.push("[schedules]");
10088
+ renderRetentionFields(config.schedules, lines);
10089
+ lines.push("");
10090
+ }
9146
10091
  if (config.deployments) {
9147
10092
  if (typeof config.deployments.subdomain === "string" && config.deployments.subdomain !== "") {
9148
10093
  lines.push("[deployments]");
@@ -9166,6 +10111,9 @@ function renderAuthFlatFields(auth, lines) {
9166
10111
  if (auth.reset_password_method !== void 0) {
9167
10112
  lines.push(`reset_password_method = ${JSON.stringify(auth.reset_password_method)}`);
9168
10113
  }
10114
+ if (auth.disable_signup !== void 0) {
10115
+ lines.push(`disable_signup = ${auth.disable_signup}`);
10116
+ }
9169
10117
  }
9170
10118
  function renderPasswordFields(pw, lines) {
9171
10119
  if (pw.min_length !== void 0) lines.push(`min_length = ${pw.min_length}`);
@@ -9202,9 +10150,19 @@ function renderSmtpFields(smtp, lines) {
9202
10150
  lines.push(`min_interval_seconds = ${smtp.min_interval_seconds}`);
9203
10151
  }
9204
10152
  }
10153
+ function renderStorageFields(storage, lines) {
10154
+ if (storage.max_file_size_mb !== void 0) {
10155
+ lines.push(`max_file_size_mb = ${storage.max_file_size_mb}`);
10156
+ }
10157
+ }
10158
+ function renderRetentionFields(config, lines) {
10159
+ if ("retention_days" in config) {
10160
+ lines.push(`retention_days = ${config.retention_days ?? 0}`);
10161
+ }
10162
+ }
9205
10163
 
9206
10164
  // src/lib/config-metadata.ts
9207
- function liveFromMetadata(raw) {
10165
+ function liveFromMetadata(raw, endpointConfig = {}) {
9208
10166
  const live = { auth: {} };
9209
10167
  const a = isPlainObject(raw.auth) ? raw.auth : void 0;
9210
10168
  if (a && "allowedRedirectUrls" in a) {
@@ -9219,6 +10177,9 @@ function liveFromMetadata(raw) {
9219
10177
  if (a && "resetPasswordMethod" in a && (a.resetPasswordMethod === "code" || a.resetPasswordMethod === "link")) {
9220
10178
  live.auth.reset_password_method = a.resetPasswordMethod;
9221
10179
  }
10180
+ if (a && "disableSignup" in a) {
10181
+ live.auth.disable_signup = a.disableSignup ?? false;
10182
+ }
9222
10183
  if (a && ("passwordMinLength" in a || "requireNumber" in a || "requireLowercase" in a || "requireUppercase" in a || "requireSpecialChar" in a)) {
9223
10184
  live.auth.password = {
9224
10185
  min_length: a.passwordMinLength ?? 8,
@@ -9247,6 +10208,18 @@ function liveFromMetadata(raw) {
9247
10208
  subdomain: typeof d.customSlug === "string" && d.customSlug ? d.customSlug : null
9248
10209
  };
9249
10210
  }
10211
+ const maxFileSizeMb = asNumber(endpointConfig.storageConfig?.maxFileSizeMb);
10212
+ if (maxFileSizeMb !== void 0) {
10213
+ live.storage = { max_file_size_mb: maxFileSizeMb };
10214
+ }
10215
+ const realtimeRetention = asRetentionDays(endpointConfig.realtimeConfig?.retentionDays);
10216
+ if (realtimeRetention !== void 0) {
10217
+ live.realtime = { retention_days: realtimeRetention };
10218
+ }
10219
+ const schedulesRetention = asRetentionDays(endpointConfig.schedulesConfig?.retentionDays);
10220
+ if (schedulesRetention !== void 0) {
10221
+ live.schedules = { retention_days: schedulesRetention };
10222
+ }
9250
10223
  return live;
9251
10224
  }
9252
10225
  function isPlainObject(v) {
@@ -9255,7 +10228,14 @@ function isPlainObject(v) {
9255
10228
  function asStringArray(v) {
9256
10229
  return Array.isArray(v) && v.every((x) => typeof x === "string") ? v : null;
9257
10230
  }
9258
- function configFromMetadata(raw) {
10231
+ function asNumber(v) {
10232
+ return typeof v === "number" && Number.isInteger(v) ? v : void 0;
10233
+ }
10234
+ function asRetentionDays(v) {
10235
+ if (v === null) return null;
10236
+ return asNumber(v);
10237
+ }
10238
+ function configFromMetadata(raw, endpointConfig = {}) {
9259
10239
  const config = {};
9260
10240
  const skipped = [];
9261
10241
  const a = isPlainObject(raw.auth) ? raw.auth : void 0;
@@ -9283,6 +10263,12 @@ function configFromMetadata(raw) {
9283
10263
  } else {
9284
10264
  skipped.push("auth.reset_password_method");
9285
10265
  }
10266
+ if (a && "disableSignup" in a) {
10267
+ config.auth = config.auth ?? {};
10268
+ config.auth.disable_signup = a.disableSignup ?? false;
10269
+ } else {
10270
+ skipped.push("auth.disable_signup");
10271
+ }
9286
10272
  if (a && ("passwordMinLength" in a || "requireNumber" in a || "requireLowercase" in a || "requireUppercase" in a || "requireSpecialChar" in a)) {
9287
10273
  config.auth = config.auth ?? {};
9288
10274
  config.auth.password = {};
@@ -9326,6 +10312,24 @@ function configFromMetadata(raw) {
9326
10312
  } else {
9327
10313
  skipped.push("deployments.subdomain");
9328
10314
  }
10315
+ const maxFileSizeMb = asNumber(endpointConfig.storageConfig?.maxFileSizeMb);
10316
+ if (maxFileSizeMb !== void 0) {
10317
+ config.storage = { max_file_size_mb: maxFileSizeMb };
10318
+ } else {
10319
+ skipped.push("storage.max_file_size_mb");
10320
+ }
10321
+ const realtimeRetention = asRetentionDays(endpointConfig.realtimeConfig?.retentionDays);
10322
+ if (realtimeRetention !== void 0) {
10323
+ config.realtime = { retention_days: realtimeRetention };
10324
+ } else {
10325
+ skipped.push("realtime.retention_days");
10326
+ }
10327
+ const schedulesRetention = asRetentionDays(endpointConfig.schedulesConfig?.retentionDays);
10328
+ if (schedulesRetention !== void 0) {
10329
+ config.schedules = { retention_days: schedulesRetention };
10330
+ } else {
10331
+ skipped.push("schedules.retention_days");
10332
+ }
9329
10333
  return { config, skipped };
9330
10334
  }
9331
10335
 
@@ -9363,7 +10367,16 @@ function registerConfigExportCommand(cfg) {
9363
10367
  }
9364
10368
  const res = await ossFetch("/api/metadata");
9365
10369
  const raw = await res.json();
9366
- const { config, skipped } = configFromMetadata(raw);
10370
+ const [storageConfig, realtimeConfig, schedulesConfig] = await Promise.all([
10371
+ fetchOptionalConfig("/api/storage/config"),
10372
+ fetchOptionalConfig("/api/realtime/config"),
10373
+ fetchOptionalConfig("/api/schedules/config")
10374
+ ]);
10375
+ const { config, skipped } = configFromMetadata(raw, {
10376
+ storageConfig,
10377
+ realtimeConfig,
10378
+ schedulesConfig
10379
+ });
9367
10380
  const toml = stringifyConfigToml(config);
9368
10381
  writeFileSync8(target, toml, "utf8");
9369
10382
  if (json) {
@@ -9399,6 +10412,18 @@ function registerConfigExportCommand(cfg) {
9399
10412
  }
9400
10413
  });
9401
10414
  }
10415
+ async function fetchOptionalConfig(path6) {
10416
+ try {
10417
+ const res = await ossFetch(path6);
10418
+ return await res.json();
10419
+ } catch (err) {
10420
+ if (isMissingOptionalEndpoint(err)) return void 0;
10421
+ throw err;
10422
+ }
10423
+ }
10424
+ function isMissingOptionalEndpoint(err) {
10425
+ return err instanceof CLIError && err.statusCode === 404 && (err.code === void 0 || err.code === "NOT_FOUND");
10426
+ }
9402
10427
 
9403
10428
  // src/commands/config/plan.ts
9404
10429
  import { readFileSync as readFileSync9 } from "fs";
@@ -9462,6 +10487,19 @@ function diffConfig({ live, file }) {
9462
10487
  });
9463
10488
  }
9464
10489
  }
10490
+ if (fileAuth && "disable_signup" in fileAuth) {
10491
+ const fromV = liveAuth.disable_signup ?? false;
10492
+ const toV = fileAuth.disable_signup ?? false;
10493
+ if (fromV !== toV) {
10494
+ changes.push({
10495
+ section: "auth",
10496
+ op: "modify",
10497
+ key: "disable_signup",
10498
+ from: fromV,
10499
+ to: toV
10500
+ });
10501
+ }
10502
+ }
9465
10503
  if (fileAuth?.password) {
9466
10504
  diffPassword(liveAuth.password, fileAuth.password, changes);
9467
10505
  }
@@ -9469,6 +10507,15 @@ function diffConfig({ live, file }) {
9469
10507
  const smtpChange = diffSmtp(liveAuth.smtp, fileAuth.smtp);
9470
10508
  if (smtpChange) changes.push(smtpChange);
9471
10509
  }
10510
+ if (file.storage !== void 0) {
10511
+ diffStorage(live.storage, file.storage, changes);
10512
+ }
10513
+ if (file.realtime !== void 0) {
10514
+ diffRetention("realtime", live.realtime, file.realtime, changes);
10515
+ }
10516
+ if (file.schedules !== void 0) {
10517
+ diffRetention("schedules", live.schedules, file.schedules, changes);
10518
+ }
9472
10519
  const fileDeployments = file.deployments;
9473
10520
  const liveDeployments = live.deployments ?? {};
9474
10521
  if (fileDeployments && "subdomain" in fileDeployments) {
@@ -9517,6 +10564,36 @@ function diffPassword(live, file, changes) {
9517
10564
  }
9518
10565
  }
9519
10566
  }
10567
+ function diffStorage(live, file, changes) {
10568
+ if (file.max_file_size_mb === void 0) return;
10569
+ const fromV = live?.max_file_size_mb ?? EMPTY_STORAGE_CONFIG.max_file_size_mb;
10570
+ if (fromV !== file.max_file_size_mb) {
10571
+ changes.push({
10572
+ section: "storage",
10573
+ op: "modify",
10574
+ key: "max_file_size_mb",
10575
+ from: fromV,
10576
+ to: file.max_file_size_mb
10577
+ });
10578
+ }
10579
+ }
10580
+ function diffRetention(section, live, file, changes) {
10581
+ if (!("retention_days" in file)) return;
10582
+ const fromV = normalizeRetentionDays(live?.retention_days);
10583
+ const toV = normalizeRetentionDays(file.retention_days);
10584
+ if (fromV !== toV) {
10585
+ changes.push({
10586
+ section,
10587
+ op: "modify",
10588
+ key: "retention_days",
10589
+ from: fromV,
10590
+ to: toV
10591
+ });
10592
+ }
10593
+ }
10594
+ function normalizeRetentionDays(value) {
10595
+ return value === void 0 || value === null || value === 0 ? null : value;
10596
+ }
9520
10597
  function diffSmtp(live, fileSmtp) {
9521
10598
  const livedView = renderLiveSmtp(live);
9522
10599
  const tomlView = renderFileSmtp(fileSmtp);
@@ -9575,6 +10652,9 @@ var EMPTY_SMTP_VIEW = {
9575
10652
  sender_name: "",
9576
10653
  min_interval_seconds: 60
9577
10654
  };
10655
+ var EMPTY_STORAGE_CONFIG = {
10656
+ max_file_size_mb: 50
10657
+ };
9578
10658
  var EMPTY_PASSWORD_POLICY = {
9579
10659
  min_length: 8,
9580
10660
  require_number: false,
@@ -9655,7 +10735,7 @@ function formatChange(c) {
9655
10735
  }
9656
10736
 
9657
10737
  // src/lib/config-capabilities.ts
9658
- function metadataSupports(raw, change) {
10738
+ function metadataSupports(raw, change, endpointConfig = {}) {
9659
10739
  if (change.section === "auth" && change.key === "allowed_redirect_urls") {
9660
10740
  return hasAuthKey(raw, "allowedRedirectUrls");
9661
10741
  }
@@ -9668,12 +10748,24 @@ function metadataSupports(raw, change) {
9668
10748
  if (change.section === "auth" && change.key === "reset_password_method") {
9669
10749
  return hasAuthKey(raw, "resetPasswordMethod");
9670
10750
  }
10751
+ if (change.section === "auth" && change.key === "disable_signup") {
10752
+ return hasAuthKey(raw, "disableSignup");
10753
+ }
9671
10754
  if (change.section === "auth.password") {
9672
10755
  return hasAuthKey(raw, AUTH_PASSWORD_WIRE_KEY[change.key]);
9673
10756
  }
9674
10757
  if (change.section === "auth.smtp") {
9675
10758
  return hasAuthKey(raw, "smtpConfig");
9676
10759
  }
10760
+ if (change.section === "storage" && change.key === "max_file_size_mb") {
10761
+ return hasConfigKey(endpointConfig.storageConfig, "maxFileSizeMb");
10762
+ }
10763
+ if (change.section === "realtime" && change.key === "retention_days") {
10764
+ return hasConfigKey(endpointConfig.realtimeConfig, "retentionDays");
10765
+ }
10766
+ if (change.section === "schedules" && change.key === "retention_days") {
10767
+ return hasConfigKey(endpointConfig.schedulesConfig, "retentionDays");
10768
+ }
9677
10769
  if (change.section === "deployments" && change.key === "subdomain") {
9678
10770
  return raw?.deployments !== void 0 && raw.deployments !== null && typeof raw.deployments === "object";
9679
10771
  }
@@ -9685,6 +10777,9 @@ function hasAuthKey(raw, key) {
9685
10777
  const auth = raw?.auth;
9686
10778
  return auth !== void 0 && auth !== null && typeof auth === "object" && key in auth;
9687
10779
  }
10780
+ function hasConfigKey(slice, key) {
10781
+ return slice !== void 0 && slice !== null && typeof slice === "object" && key in slice;
10782
+ }
9688
10783
  var AUTH_PASSWORD_WIRE_KEY = {
9689
10784
  min_length: "passwordMinLength",
9690
10785
  require_number: "requireNumber",
@@ -9713,9 +10808,25 @@ function registerConfigPlanCommand(cfg) {
9713
10808
  const file = parseConfigToml(tomlSource);
9714
10809
  const res = await ossFetch("/api/metadata");
9715
10810
  const raw = await res.json();
9716
- const live = liveFromMetadata(raw);
10811
+ const endpointConfig = {};
10812
+ if (file.storage !== void 0) {
10813
+ endpointConfig.storageConfig = await fetchOptionalConfig2(
10814
+ "/api/storage/config"
10815
+ );
10816
+ }
10817
+ if (file.realtime !== void 0) {
10818
+ endpointConfig.realtimeConfig = await fetchOptionalConfig2(
10819
+ "/api/realtime/config"
10820
+ );
10821
+ }
10822
+ if (file.schedules !== void 0) {
10823
+ endpointConfig.schedulesConfig = await fetchOptionalConfig2(
10824
+ "/api/schedules/config"
10825
+ );
10826
+ }
10827
+ const live = liveFromMetadata(raw, endpointConfig);
9717
10828
  const result = diffConfig({ live, file });
9718
- const skipped = result.changes.filter((c) => !metadataSupports(raw, c)).map((c) => changePath(c));
10829
+ const skipped = result.changes.filter((c) => !metadataSupports(raw, c, endpointConfig)).map((c) => changePath(c));
9719
10830
  if (json) {
9720
10831
  console.log(JSON.stringify({ ...result, skipped }, null, 2));
9721
10832
  } else {
@@ -9751,6 +10862,18 @@ function registerConfigPlanCommand(cfg) {
9751
10862
  }
9752
10863
  });
9753
10864
  }
10865
+ async function fetchOptionalConfig2(path6) {
10866
+ try {
10867
+ const res = await ossFetch(path6);
10868
+ return await res.json();
10869
+ } catch (err) {
10870
+ if (isMissingOptionalEndpoint2(err)) return void 0;
10871
+ throw err;
10872
+ }
10873
+ }
10874
+ function isMissingOptionalEndpoint2(err) {
10875
+ return err instanceof CLIError && err.statusCode === 404 && (err.code === void 0 || err.code === "NOT_FOUND");
10876
+ }
9754
10877
 
9755
10878
  // src/commands/config/apply.ts
9756
10879
  import { readFileSync as readFileSync10 } from "fs";
@@ -9769,7 +10892,23 @@ function registerConfigApplyCommand(cfg) {
9769
10892
  const file = parseConfigToml(tomlSource);
9770
10893
  const res = await ossFetch("/api/metadata");
9771
10894
  const raw = await res.json();
9772
- const live = liveFromMetadata(raw);
10895
+ const endpointConfig = {};
10896
+ if (file.storage !== void 0) {
10897
+ endpointConfig.storageConfig = await fetchOptionalConfig3(
10898
+ "/api/storage/config"
10899
+ );
10900
+ }
10901
+ if (file.realtime !== void 0) {
10902
+ endpointConfig.realtimeConfig = await fetchOptionalConfig3(
10903
+ "/api/realtime/config"
10904
+ );
10905
+ }
10906
+ if (file.schedules !== void 0) {
10907
+ endpointConfig.schedulesConfig = await fetchOptionalConfig3(
10908
+ "/api/schedules/config"
10909
+ );
10910
+ }
10911
+ const live = liveFromMetadata(raw, endpointConfig);
9773
10912
  const result = diffConfig({ live, file });
9774
10913
  const approved = opts.autoApprove || yes;
9775
10914
  const sectionsChanged = Array.from(
@@ -9822,7 +10961,7 @@ function registerConfigApplyCommand(cfg) {
9822
10961
  const skipped = [];
9823
10962
  for (const change of result.changes) {
9824
10963
  const path6 = changePath(change);
9825
- if (!metadataSupports(raw, change)) {
10964
+ if (!metadataSupports(raw, change, endpointConfig)) {
9826
10965
  skipped.push({
9827
10966
  key: path6,
9828
10967
  reason: `your backend doesn't expose ${path6} \u2014 upgrade the project to apply this section`
@@ -9873,6 +11012,18 @@ function registerConfigApplyCommand(cfg) {
9873
11012
  }
9874
11013
  });
9875
11014
  }
11015
+ async function fetchOptionalConfig3(path6) {
11016
+ try {
11017
+ const res = await ossFetch(path6);
11018
+ return await res.json();
11019
+ } catch (err) {
11020
+ if (isMissingOptionalEndpoint3(err)) return void 0;
11021
+ throw err;
11022
+ }
11023
+ }
11024
+ function isMissingOptionalEndpoint3(err) {
11025
+ return err instanceof CLIError && err.statusCode === 404 && (err.code === void 0 || err.code === "NOT_FOUND");
11026
+ }
9876
11027
  async function applyChange(change) {
9877
11028
  if (change.section === "auth" && change.key === "allowed_redirect_urls") {
9878
11029
  await ossFetch("/api/auth/config", {
@@ -9902,6 +11053,13 @@ async function applyChange(change) {
9902
11053
  });
9903
11054
  return;
9904
11055
  }
11056
+ if (change.section === "auth" && change.key === "disable_signup") {
11057
+ await ossFetch("/api/auth/config", {
11058
+ method: "PUT",
11059
+ body: JSON.stringify({ disableSignup: change.to })
11060
+ });
11061
+ return;
11062
+ }
9905
11063
  if (change.section === "auth.password") {
9906
11064
  const wireKey = authPasswordWireKey(change.key);
9907
11065
  await ossFetch("/api/auth/config", {
@@ -9934,6 +11092,27 @@ async function applyChange(change) {
9934
11092
  });
9935
11093
  return;
9936
11094
  }
11095
+ if (change.section === "storage" && change.key === "max_file_size_mb") {
11096
+ await ossFetch("/api/storage/config", {
11097
+ method: "PUT",
11098
+ body: JSON.stringify({ maxFileSizeMb: change.to })
11099
+ });
11100
+ return;
11101
+ }
11102
+ if (change.section === "realtime" && change.key === "retention_days") {
11103
+ await ossFetch("/api/realtime/config", {
11104
+ method: "PATCH",
11105
+ body: JSON.stringify({ retentionDays: change.to })
11106
+ });
11107
+ return;
11108
+ }
11109
+ if (change.section === "schedules" && change.key === "retention_days") {
11110
+ await ossFetch("/api/schedules/config", {
11111
+ method: "PATCH",
11112
+ body: JSON.stringify({ retentionDays: change.to })
11113
+ });
11114
+ return;
11115
+ }
9937
11116
  if (change.section === "deployments" && change.key === "subdomain") {
9938
11117
  await ossFetch("/api/deployments/slug", {
9939
11118
  method: "PUT",