@insforge/cli 0.1.60 → 0.1.62

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { readFileSync as readFileSync7 } from "fs";
5
- import { join as join12, dirname } from "path";
5
+ import { join as join13, dirname } from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import { Command } from "commander";
8
8
  import * as clack11 from "@clack/prompts";
@@ -1237,7 +1237,7 @@ async function reportCliUsage(toolName, success, maxRetries = 1, explicitConfig)
1237
1237
 
1238
1238
  // src/lib/analytics.ts
1239
1239
  import { PostHog } from "posthog-node";
1240
- var POSTHOG_API_KEY = "phc_ueV1ii62wdBTkH7E70ugyeqHIHu8dFDdjs0qq3TZhJz";
1240
+ var POSTHOG_API_KEY = "";
1241
1241
  var POSTHOG_HOST = process.env.POSTHOG_HOST || "https://us.i.posthog.com";
1242
1242
  var client = null;
1243
1243
  function getClient() {
@@ -1269,6 +1269,17 @@ function trackDiagnose(subcommand, config) {
1269
1269
  oss_mode: config.project_id === FAKE_PROJECT_ID
1270
1270
  });
1271
1271
  }
1272
+ function trackPayments(subcommand, config, properties) {
1273
+ captureEvent(config.project_id, "cli_payments_invoked", {
1274
+ subcommand,
1275
+ project_id: config.project_id,
1276
+ project_name: config.project_name,
1277
+ org_id: config.org_id,
1278
+ region: config.region,
1279
+ oss_mode: config.project_id === FAKE_PROJECT_ID,
1280
+ ...properties
1281
+ });
1282
+ }
1272
1283
  async function shutdownAnalytics() {
1273
1284
  try {
1274
1285
  if (client) await client.shutdown();
@@ -1326,6 +1337,9 @@ ${err.nextActions}`;
1326
1337
  if (res.status === 404 && isRouteLevel404 && path5.startsWith("/api/compute")) {
1327
1338
  message = "Compute services are not available on this backend.\nSelf-hosted: upgrade your InsForge instance. Cloud: contact your InsForge admin to enable compute.";
1328
1339
  }
1340
+ if (res.status === 404 && isRouteLevel404 && path5.startsWith("/api/payments")) {
1341
+ message = "Payments are not available on this backend.\nSelf-hosted: upgrade your InsForge instance. Cloud/private preview: contact your InsForge admin to enable payments.";
1342
+ }
1329
1343
  if (res.status === 404 && isRouteLevel404 && path5 === "/api/database/migrations") {
1330
1344
  message = "Database migrations are not available on this backend.\nSelf-hosted: upgrade your InsForge instance. Cloud: contact your InsForge admin about database migration support.";
1331
1345
  }
@@ -4844,11 +4858,13 @@ function registerComputeLogsCommand(computeCmd2) {
4844
4858
  }
4845
4859
 
4846
4860
  // src/commands/compute/deploy.ts
4847
- import { existsSync as existsSync7 } from "fs";
4848
- import { join as join11, resolve as resolve4 } from "path";
4861
+ import { existsSync as existsSync8 } from "fs";
4862
+ import { join as join12, resolve as resolve4 } from "path";
4849
4863
 
4850
4864
  // src/lib/flyctl.ts
4851
4865
  import { spawn, spawnSync } from "child_process";
4866
+ import { existsSync as existsSync7, writeFileSync as writeFileSync5, unlinkSync as unlinkSync2 } from "fs";
4867
+ import { join as join11 } from "path";
4852
4868
  function ensureFlyctlAvailable() {
4853
4869
  const r = spawnSync("flyctl", ["version"], {
4854
4870
  encoding: "utf8",
@@ -4860,8 +4876,41 @@ function ensureFlyctlAvailable() {
4860
4876
  );
4861
4877
  }
4862
4878
  }
4879
+ function ensureFlyTomlStub(opts) {
4880
+ const path5 = join11(opts.dir, "fly.toml");
4881
+ if (existsSync7(path5)) {
4882
+ return () => {
4883
+ };
4884
+ }
4885
+ const stub = `# Auto-generated by @insforge/cli for compute deploy. Safe to delete.
4886
+ app = "${opts.appId}"
4887
+ primary_region = "${opts.region}"
4888
+
4889
+ [build]
4890
+
4891
+ [http_service]
4892
+ internal_port = ${opts.port}
4893
+ force_https = true
4894
+ auto_stop_machines = false
4895
+ auto_start_machines = true
4896
+ min_machines_running = 0
4897
+ `;
4898
+ writeFileSync5(path5, stub, "utf8");
4899
+ return () => {
4900
+ try {
4901
+ unlinkSync2(path5);
4902
+ } catch {
4903
+ }
4904
+ };
4905
+ }
4863
4906
  function flyctlBuildAndPush(opts) {
4864
4907
  return new Promise((resolve5, reject) => {
4908
+ const cleanupStub = ensureFlyTomlStub({
4909
+ dir: opts.dir,
4910
+ appId: opts.appId,
4911
+ region: opts.region,
4912
+ port: opts.port
4913
+ });
4865
4914
  const child = spawn(
4866
4915
  "flyctl",
4867
4916
  [
@@ -4893,9 +4942,11 @@ function flyctlBuildAndPush(opts) {
4893
4942
  process.stderr.write(s);
4894
4943
  });
4895
4944
  child.on("error", (err) => {
4945
+ cleanupStub();
4896
4946
  reject(new CLIError(`flyctl deploy could not start: ${err.message}`));
4897
4947
  });
4898
4948
  child.on("exit", (code) => {
4949
+ cleanupStub();
4899
4950
  if (code !== 0) {
4900
4951
  return reject(
4901
4952
  new CLIError(`flyctl deploy --build-only failed (exit ${code}). See output above.`)
@@ -5003,8 +5054,8 @@ function registerComputeDeployCommand(computeCmd2) {
5003
5054
  return;
5004
5055
  }
5005
5056
  const absDir = resolve4(dir);
5006
- const dockerfilePath = join11(absDir, "Dockerfile");
5007
- if (!existsSync7(dockerfilePath)) {
5057
+ const dockerfilePath = join12(absDir, "Dockerfile");
5058
+ if (!existsSync8(dockerfilePath)) {
5008
5059
  throw new CLIError(
5009
5060
  `No Dockerfile at ${dockerfilePath}.
5010
5061
  Either:
@@ -5046,12 +5097,33 @@ function registerComputeDeployCommand(computeCmd2) {
5046
5097
  const tokenJson = await tokenRes.json();
5047
5098
  const imageLabel = `cli-${Date.now()}`;
5048
5099
  if (!json) outputInfo(`Building & pushing on Fly remote builder...`);
5049
- const { imageRef } = await flyctlBuildAndPush({
5050
- dir: absDir,
5051
- appId: flyAppId,
5052
- imageLabel,
5053
- token: tokenJson.token
5054
- });
5100
+ let imageRef;
5101
+ try {
5102
+ ({ imageRef } = await flyctlBuildAndPush({
5103
+ dir: absDir,
5104
+ appId: flyAppId,
5105
+ imageLabel,
5106
+ token: tokenJson.token,
5107
+ region: opts.region,
5108
+ port
5109
+ }));
5110
+ } catch (buildErr) {
5111
+ if (!existing) {
5112
+ try {
5113
+ await ossFetch(`/api/compute/services/${encodeURIComponent(serviceId)}`, {
5114
+ method: "DELETE"
5115
+ });
5116
+ if (!json) outputInfo(`Rolled back service "${opts.name}" after build failure.`);
5117
+ } catch {
5118
+ if (!json) {
5119
+ outputInfo(
5120
+ `Build failed and rollback also failed. Run: npx @insforge/cli compute delete ${serviceId}`
5121
+ );
5122
+ }
5123
+ }
5124
+ }
5125
+ throw buildErr;
5126
+ }
5055
5127
  if (!json) outputInfo("Launching machine...");
5056
5128
  const updateBody = {
5057
5129
  imageUrl: imageRef,
@@ -5761,7 +5833,7 @@ function registerDiagnoseCommands(diagnoseCmd2) {
5761
5833
  const s = !json ? clack10.spinner() : null;
5762
5834
  s?.start("Collecting diagnostic data...");
5763
5835
  const data2 = await collectDiagnosticData(projectId, ossMode, apiUrl);
5764
- const cliVersion = "0.1.60";
5836
+ const cliVersion = "0.1.62";
5765
5837
  s?.stop("Data collected");
5766
5838
  if (!json) {
5767
5839
  console.log(`
@@ -5988,9 +6060,859 @@ function formatBytesCompact(bytes) {
5988
6060
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
5989
6061
  }
5990
6062
 
6063
+ // src/lib/api/payments.ts
6064
+ function withQuery(path5, params) {
6065
+ const query = new URLSearchParams();
6066
+ for (const [key, value] of Object.entries(params)) {
6067
+ if (value !== void 0) query.set(key, String(value));
6068
+ }
6069
+ const suffix = query.toString();
6070
+ return suffix ? `${path5}?${suffix}` : path5;
6071
+ }
6072
+ async function readJson(res) {
6073
+ return await res.json();
6074
+ }
6075
+ async function getPaymentsStatus() {
6076
+ return readJson(await ossFetch("/api/payments/status"));
6077
+ }
6078
+ async function getPaymentsConfig() {
6079
+ return readJson(await ossFetch("/api/payments/config"));
6080
+ }
6081
+ async function setStripeSecretKey(environment, secretKey) {
6082
+ return readJson(await ossFetch("/api/payments/config", {
6083
+ method: "POST",
6084
+ body: JSON.stringify({ environment, secretKey })
6085
+ }));
6086
+ }
6087
+ async function removeStripeSecretKey(environment) {
6088
+ return readJson(await ossFetch(`/api/payments/config/${encodeURIComponent(environment)}`, {
6089
+ method: "DELETE"
6090
+ }));
6091
+ }
6092
+ async function syncPayments(environment = "all") {
6093
+ return readJson(await ossFetch("/api/payments/sync", {
6094
+ method: "POST",
6095
+ body: JSON.stringify({ environment })
6096
+ }));
6097
+ }
6098
+ async function configurePaymentWebhook(environment) {
6099
+ return readJson(await ossFetch(
6100
+ `/api/payments/webhooks/${encodeURIComponent(environment)}/configure`,
6101
+ { method: "POST" }
6102
+ ));
6103
+ }
6104
+ async function listPaymentCatalog(environment) {
6105
+ return readJson(await ossFetch(withQuery("/api/payments/catalog", { environment })));
6106
+ }
6107
+ async function listPaymentProducts(environment) {
6108
+ return readJson(await ossFetch(withQuery("/api/payments/products", { environment })));
6109
+ }
6110
+ async function getPaymentProduct(environment, productId) {
6111
+ return readJson(await ossFetch(withQuery(
6112
+ `/api/payments/products/${encodeURIComponent(productId)}`,
6113
+ { environment }
6114
+ )));
6115
+ }
6116
+ async function createPaymentProduct(request) {
6117
+ return readJson(await ossFetch("/api/payments/products", {
6118
+ method: "POST",
6119
+ body: JSON.stringify(request)
6120
+ }));
6121
+ }
6122
+ async function updatePaymentProduct(productId, request) {
6123
+ return readJson(await ossFetch(`/api/payments/products/${encodeURIComponent(productId)}`, {
6124
+ method: "PATCH",
6125
+ body: JSON.stringify(request)
6126
+ }));
6127
+ }
6128
+ async function deletePaymentProduct(environment, productId) {
6129
+ return readJson(await ossFetch(withQuery(
6130
+ `/api/payments/products/${encodeURIComponent(productId)}`,
6131
+ { environment }
6132
+ ), { method: "DELETE" }));
6133
+ }
6134
+ async function listPaymentPrices(environment, stripeProductId) {
6135
+ return readJson(await ossFetch(withQuery("/api/payments/prices", {
6136
+ environment,
6137
+ stripeProductId
6138
+ })));
6139
+ }
6140
+ async function getPaymentPrice(environment, priceId) {
6141
+ return readJson(await ossFetch(withQuery(
6142
+ `/api/payments/prices/${encodeURIComponent(priceId)}`,
6143
+ { environment }
6144
+ )));
6145
+ }
6146
+ async function createPaymentPrice(request) {
6147
+ return readJson(await ossFetch("/api/payments/prices", {
6148
+ method: "POST",
6149
+ body: JSON.stringify(request)
6150
+ }));
6151
+ }
6152
+ async function updatePaymentPrice(priceId, request) {
6153
+ return readJson(await ossFetch(`/api/payments/prices/${encodeURIComponent(priceId)}`, {
6154
+ method: "PATCH",
6155
+ body: JSON.stringify(request)
6156
+ }));
6157
+ }
6158
+ async function archivePaymentPrice(environment, priceId) {
6159
+ return readJson(await ossFetch(withQuery(
6160
+ `/api/payments/prices/${encodeURIComponent(priceId)}`,
6161
+ { environment }
6162
+ ), { method: "DELETE" }));
6163
+ }
6164
+ async function listSubscriptions(request) {
6165
+ return readJson(await ossFetch(withQuery("/api/payments/subscriptions", request)));
6166
+ }
6167
+ async function listPaymentHistory(request) {
6168
+ return readJson(await ossFetch(withQuery("/api/payments/payment-history", request)));
6169
+ }
6170
+
6171
+ // src/commands/payments/utils.ts
6172
+ function parseEnvironment(value) {
6173
+ if (value === "test" || value === "live") return value;
6174
+ throw new CLIError('Environment must be "test" or "live".');
6175
+ }
6176
+ function parseEnvironmentOrAll(value) {
6177
+ if (value === "all") return value;
6178
+ return parseEnvironment(value);
6179
+ }
6180
+ function parseBooleanOption(value, flagName) {
6181
+ if (value === void 0) return void 0;
6182
+ const normalized = value.toLowerCase();
6183
+ if (normalized === "true") return true;
6184
+ if (normalized === "false") return false;
6185
+ throw new CLIError(`${flagName} must be "true" or "false".`);
6186
+ }
6187
+ function parseIntegerOption(value, flagName, options = {}) {
6188
+ if (value === void 0) return void 0;
6189
+ const parsed = Number.parseInt(value, 10);
6190
+ if (!Number.isInteger(parsed) || String(parsed) !== value.trim()) {
6191
+ throw new CLIError(`${flagName} must be an integer.`);
6192
+ }
6193
+ if (options.min !== void 0 && parsed < options.min) {
6194
+ throw new CLIError(`${flagName} must be at least ${options.min}.`);
6195
+ }
6196
+ if (options.max !== void 0 && parsed > options.max) {
6197
+ throw new CLIError(`${flagName} must be at most ${options.max}.`);
6198
+ }
6199
+ return parsed;
6200
+ }
6201
+ function parseMetadataOption(value) {
6202
+ if (value === void 0) return void 0;
6203
+ let parsed;
6204
+ try {
6205
+ parsed = JSON.parse(value);
6206
+ } catch {
6207
+ throw new CLIError("Invalid JSON for --metadata.");
6208
+ }
6209
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
6210
+ throw new CLIError("--metadata must be a JSON object.");
6211
+ }
6212
+ const metadata = {};
6213
+ for (const [key, raw] of Object.entries(parsed)) {
6214
+ if (typeof raw !== "string") {
6215
+ throw new CLIError(`Metadata value for "${key}" must be a string.`);
6216
+ }
6217
+ metadata[key] = raw;
6218
+ }
6219
+ return metadata;
6220
+ }
6221
+ function formatDate(value) {
6222
+ if (!value) return "-";
6223
+ const date = new Date(value);
6224
+ return Number.isNaN(date.getTime()) ? value : date.toLocaleString();
6225
+ }
6226
+ function formatAmount(amount, currency) {
6227
+ if (amount === null || amount === void 0) return "-";
6228
+ const code = currency?.toUpperCase();
6229
+ let fractionDigits = 2;
6230
+ if (code) {
6231
+ try {
6232
+ fractionDigits = new Intl.NumberFormat(void 0, {
6233
+ style: "currency",
6234
+ currency: code
6235
+ }).resolvedOptions().maximumFractionDigits;
6236
+ } catch {
6237
+ fractionDigits = 2;
6238
+ }
6239
+ }
6240
+ const divisor = 10 ** fractionDigits;
6241
+ return `${(amount / divisor).toFixed(fractionDigits)} ${code ?? ""}`.trim();
6242
+ }
6243
+ function formatRecurring(interval, intervalCount) {
6244
+ if (!interval) return "one-time";
6245
+ return `${intervalCount && intervalCount > 1 ? `${intervalCount} ` : ""}${interval}`;
6246
+ }
6247
+ async function trackPaymentUsage(subcommand, success, properties = {}) {
6248
+ try {
6249
+ try {
6250
+ const config = getProjectConfig();
6251
+ if (config) {
6252
+ trackPayments(subcommand, config, {
6253
+ success,
6254
+ ...properties
6255
+ });
6256
+ }
6257
+ } catch {
6258
+ }
6259
+ } finally {
6260
+ await shutdownAnalytics();
6261
+ }
6262
+ }
6263
+
6264
+ // src/commands/payments/catalog.ts
6265
+ function registerPaymentsCatalogCommand(paymentsCmd2) {
6266
+ paymentsCmd2.command("catalog").description("List mirrored Stripe products and prices").option("--environment <environment>", "Stripe environment: test or live").action(async (opts, cmd) => {
6267
+ const { json } = getRootOpts(cmd);
6268
+ try {
6269
+ const environment = opts.environment ? parseEnvironment(opts.environment) : void 0;
6270
+ await requireAuth();
6271
+ const data = await listPaymentCatalog(environment);
6272
+ if (json) {
6273
+ outputJson(data);
6274
+ } else {
6275
+ if (data.products.length === 0 && data.prices.length === 0) {
6276
+ console.log("No Stripe catalog records found.");
6277
+ await trackPaymentUsage("catalog", true, { environment });
6278
+ return;
6279
+ }
6280
+ if (data.products.length > 0) {
6281
+ console.log("Products");
6282
+ outputTable(
6283
+ ["Env", "Product ID", "Name", "Active", "Default Price"],
6284
+ data.products.map((product) => [
6285
+ product.environment,
6286
+ product.stripeProductId,
6287
+ product.name,
6288
+ product.active ? "Yes" : "No",
6289
+ product.defaultPriceId ?? "-"
6290
+ ])
6291
+ );
6292
+ }
6293
+ if (data.prices.length > 0) {
6294
+ console.log("Prices");
6295
+ outputTable(
6296
+ ["Env", "Price ID", "Product ID", "Amount", "Type", "Active", "Recurring"],
6297
+ data.prices.map((price) => [
6298
+ price.environment,
6299
+ price.stripePriceId,
6300
+ price.stripeProductId ?? "-",
6301
+ formatAmount(price.unitAmount, price.currency),
6302
+ price.type,
6303
+ price.active ? "Yes" : "No",
6304
+ formatRecurring(price.recurringInterval, price.recurringIntervalCount)
6305
+ ])
6306
+ );
6307
+ }
6308
+ }
6309
+ await trackPaymentUsage("catalog", true, { environment });
6310
+ } catch (err) {
6311
+ await trackPaymentUsage("catalog", false, { environment: opts.environment });
6312
+ handleError(err, json);
6313
+ }
6314
+ });
6315
+ }
6316
+
6317
+ // src/commands/payments/config.ts
6318
+ function outputConfigTable(data) {
6319
+ if (data.keys.length === 0) {
6320
+ console.log("No Stripe keys configured.");
6321
+ return;
6322
+ }
6323
+ outputTable(
6324
+ ["Env", "Configured", "Key"],
6325
+ data.keys.map((key) => [
6326
+ key.environment,
6327
+ key.hasKey ? "Yes" : "No",
6328
+ key.maskedKey ?? "-"
6329
+ ])
6330
+ );
6331
+ }
6332
+ function registerPaymentsConfigCommand(paymentsCmd2) {
6333
+ const configCmd = paymentsCmd2.command("config").description("Manage Stripe API keys for payments").action(async (_opts, cmd) => {
6334
+ const { json } = getRootOpts(cmd);
6335
+ try {
6336
+ await requireAuth();
6337
+ const data = await getPaymentsConfig();
6338
+ if (json) {
6339
+ outputJson(data);
6340
+ } else {
6341
+ outputConfigTable(data);
6342
+ }
6343
+ await trackPaymentUsage("config", true);
6344
+ } catch (err) {
6345
+ await trackPaymentUsage("config", false);
6346
+ handleError(err, json);
6347
+ }
6348
+ });
6349
+ configCmd.command("set <environment> [secretKey]").description("Configure a Stripe secret key for test or live payments").action(async (environmentValue, secretKeyValue, _opts, cmd) => {
6350
+ const { json } = getRootOpts(cmd);
6351
+ try {
6352
+ const environment = parseEnvironment(environmentValue);
6353
+ await requireAuth();
6354
+ let secretKey = secretKeyValue;
6355
+ if (!secretKey) {
6356
+ if (json) {
6357
+ throw new CLIError("Provide secretKey when using --json.");
6358
+ }
6359
+ const input = await password2({
6360
+ message: `Stripe ${environment} secret key`
6361
+ });
6362
+ if (isCancel2(input)) process.exit(0);
6363
+ secretKey = input;
6364
+ }
6365
+ const data = await setStripeSecretKey(environment, secretKey);
6366
+ if (json) {
6367
+ outputJson(data);
6368
+ } else {
6369
+ outputSuccess(`Stripe ${environment} key configured.`);
6370
+ }
6371
+ await trackPaymentUsage("config.set", true, { environment });
6372
+ } catch (err) {
6373
+ await trackPaymentUsage("config.set", false, { environment: environmentValue });
6374
+ handleError(err, json);
6375
+ }
6376
+ });
6377
+ configCmd.command("remove <environment>").alias("delete").description("Remove a configured Stripe secret key").action(async (environmentValue, _opts, cmd) => {
6378
+ const { json, yes } = getRootOpts(cmd);
6379
+ try {
6380
+ const environment = parseEnvironment(environmentValue);
6381
+ await requireAuth();
6382
+ if (json && !yes) {
6383
+ throw new CLIError("Use --yes with --json to remove a Stripe key non-interactively.");
6384
+ }
6385
+ if (!yes) {
6386
+ const confirm3 = await confirm2({
6387
+ message: `Remove Stripe ${environment} key? Payment sync and mutations for this environment will stop.`
6388
+ });
6389
+ if (isCancel2(confirm3) || !confirm3) process.exit(0);
6390
+ }
6391
+ const data = await removeStripeSecretKey(environment);
6392
+ if (json) {
6393
+ outputJson(data);
6394
+ } else {
6395
+ outputSuccess(`Stripe ${environment} key removed.`);
6396
+ }
6397
+ await trackPaymentUsage("config.remove", true, { environment });
6398
+ } catch (err) {
6399
+ await trackPaymentUsage("config.remove", false, { environment: environmentValue });
6400
+ handleError(err, json);
6401
+ }
6402
+ });
6403
+ }
6404
+
6405
+ // src/commands/payments/history.ts
6406
+ function registerPaymentsHistoryCommand(paymentsCmd2) {
6407
+ paymentsCmd2.command("history").description("List mirrored Stripe payment history").requiredOption("--environment <environment>", "Stripe environment: test or live").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) => {
6408
+ const { json } = getRootOpts(cmd);
6409
+ try {
6410
+ const environment = parseEnvironment(opts.environment);
6411
+ const limit = parseIntegerOption(opts.limit, "--limit", { min: 1, max: 100 }) ?? 50;
6412
+ await requireAuth();
6413
+ const data = await listPaymentHistory({
6414
+ environment,
6415
+ limit,
6416
+ ...opts.subjectType !== void 0 ? { subjectType: opts.subjectType } : {},
6417
+ ...opts.subjectId !== void 0 ? { subjectId: opts.subjectId } : {}
6418
+ });
6419
+ if (json) {
6420
+ outputJson(data);
6421
+ } else if (data.paymentHistory.length === 0) {
6422
+ console.log("No Stripe payment history found.");
6423
+ } else {
6424
+ outputTable(
6425
+ ["Type", "Status", "Subject", "Amount", "Customer", "Stripe Object", "When"],
6426
+ data.paymentHistory.map((entry) => [
6427
+ entry.type,
6428
+ entry.status,
6429
+ entry.subjectType && entry.subjectId ? `${entry.subjectType}:${entry.subjectId}` : "-",
6430
+ formatAmount(entry.amount, entry.currency),
6431
+ entry.stripeCustomerId ?? "-",
6432
+ entry.stripeCheckoutSessionId ?? entry.stripeInvoiceId ?? entry.stripePaymentIntentId ?? entry.stripeRefundId ?? "-",
6433
+ formatDate(entry.paidAt ?? entry.failedAt ?? entry.refundedAt ?? entry.stripeCreatedAt)
6434
+ ])
6435
+ );
6436
+ }
6437
+ await trackPaymentUsage("history", true, { environment });
6438
+ } catch (err) {
6439
+ await trackPaymentUsage("history", false, { environment: opts.environment });
6440
+ handleError(err, json);
6441
+ }
6442
+ });
6443
+ }
6444
+
6445
+ // src/commands/payments/prices.ts
6446
+ function nullableString(value) {
6447
+ if (value === void 0) return void 0;
6448
+ return value === "null" ? null : value;
6449
+ }
6450
+ function parseRecurringInterval(value) {
6451
+ if (value === void 0) return void 0;
6452
+ if (value === "day" || value === "week" || value === "month" || value === "year") return value;
6453
+ throw new CLIError("--interval must be one of: day, week, month, year.");
6454
+ }
6455
+ function parseTaxBehavior(value) {
6456
+ if (value === void 0) return void 0;
6457
+ if (value === "exclusive" || value === "inclusive" || value === "unspecified") return value;
6458
+ throw new CLIError("--tax-behavior must be one of: exclusive, inclusive, unspecified.");
6459
+ }
6460
+ function outputPricesTable(prices) {
6461
+ if (prices.length === 0) {
6462
+ console.log("No Stripe prices found.");
6463
+ return;
6464
+ }
6465
+ outputTable(
6466
+ ["Env", "Price ID", "Product ID", "Amount", "Type", "Active", "Recurring", "Synced At"],
6467
+ prices.map((price) => [
6468
+ price.environment,
6469
+ price.stripePriceId,
6470
+ price.stripeProductId ?? "-",
6471
+ formatAmount(price.unitAmount, price.currency),
6472
+ price.type,
6473
+ price.active ? "Yes" : "No",
6474
+ formatRecurring(price.recurringInterval, price.recurringIntervalCount),
6475
+ formatDate(price.syncedAt)
6476
+ ])
6477
+ );
6478
+ }
6479
+ function registerPaymentsPricesCommand(paymentsCmd2) {
6480
+ const pricesCmd = paymentsCmd2.command("prices").description("Manage Stripe prices");
6481
+ pricesCmd.command("list").description("List mirrored Stripe prices").requiredOption("--environment <environment>", "Stripe environment: test or live").option("--product <productId>", "Filter by Stripe product id").action(async (opts, cmd) => {
6482
+ const { json } = getRootOpts(cmd);
6483
+ try {
6484
+ const environment = parseEnvironment(opts.environment);
6485
+ await requireAuth();
6486
+ const data = await listPaymentPrices(environment, opts.product);
6487
+ if (json) {
6488
+ outputJson(data);
6489
+ } else {
6490
+ outputPricesTable(data.prices);
6491
+ }
6492
+ await trackPaymentUsage("prices.list", true, { environment });
6493
+ } catch (err) {
6494
+ await trackPaymentUsage("prices.list", false, { environment: opts.environment });
6495
+ handleError(err, json);
6496
+ }
6497
+ });
6498
+ pricesCmd.command("get <priceId>").description("Show one Stripe price").requiredOption("--environment <environment>", "Stripe environment: test or live").action(async (priceId, opts, cmd) => {
6499
+ const { json } = getRootOpts(cmd);
6500
+ try {
6501
+ const environment = parseEnvironment(opts.environment);
6502
+ await requireAuth();
6503
+ const data = await getPaymentPrice(environment, priceId);
6504
+ if (json) {
6505
+ outputJson(data);
6506
+ } else {
6507
+ outputPricesTable([data.price]);
6508
+ }
6509
+ await trackPaymentUsage("prices.get", true, { environment });
6510
+ } catch (err) {
6511
+ await trackPaymentUsage("prices.get", false, { environment: opts.environment });
6512
+ handleError(err, json);
6513
+ }
6514
+ });
6515
+ pricesCmd.command("create").description("Create a Stripe one-time or recurring price").requiredOption("--environment <environment>", "Stripe environment: test or live").requiredOption("--product <productId>", "Stripe product id").requiredOption("--currency <currency>", "Three-letter currency code, e.g. usd").requiredOption("--unit-amount <amount>", "Unit amount in the smallest currency unit, e.g. cents").option("--interval <interval>", "Recurring interval: day, week, month, or year").option("--interval-count <count>", "Recurring interval count").option("--lookup-key <key>", 'Stripe lookup key, or "null"').option("--active <bool>", "Set active status (true/false)").option("--tax-behavior <behavior>", "exclusive, inclusive, or unspecified").option("--metadata <json>", "Metadata JSON object with string values").option("--idempotency-key <key>", "Caller-stable idempotency key").action(async (opts, cmd) => {
6516
+ const { json } = getRootOpts(cmd);
6517
+ try {
6518
+ const environment = parseEnvironment(opts.environment);
6519
+ await requireAuth();
6520
+ const interval = parseRecurringInterval(opts.interval);
6521
+ const intervalCount = parseIntegerOption(opts.intervalCount, "--interval-count", { min: 1 });
6522
+ if (!interval && intervalCount !== void 0) {
6523
+ throw new CLIError("Provide --interval when using --interval-count.");
6524
+ }
6525
+ const request = {
6526
+ environment,
6527
+ stripeProductId: opts.product,
6528
+ currency: opts.currency,
6529
+ unitAmount: parseIntegerOption(opts.unitAmount, "--unit-amount", { min: 0 }) ?? 0
6530
+ };
6531
+ const lookupKey = nullableString(opts.lookupKey);
6532
+ const active = parseBooleanOption(opts.active, "--active");
6533
+ const taxBehavior = parseTaxBehavior(opts.taxBehavior);
6534
+ const metadata = parseMetadataOption(opts.metadata);
6535
+ if (lookupKey !== void 0) request.lookupKey = lookupKey;
6536
+ if (active !== void 0) request.active = active;
6537
+ if (taxBehavior !== void 0) request.taxBehavior = taxBehavior;
6538
+ if (metadata !== void 0) request.metadata = metadata;
6539
+ if (opts.idempotencyKey !== void 0) request.idempotencyKey = opts.idempotencyKey;
6540
+ if (interval) {
6541
+ request.recurring = {
6542
+ interval,
6543
+ ...intervalCount !== void 0 ? { intervalCount } : {}
6544
+ };
6545
+ }
6546
+ const data = await createPaymentPrice(request);
6547
+ if (json) {
6548
+ outputJson(data);
6549
+ } else {
6550
+ outputSuccess(`Stripe price created: ${data.price.stripePriceId}`);
6551
+ }
6552
+ await trackPaymentUsage("prices.create", true, { environment });
6553
+ } catch (err) {
6554
+ await trackPaymentUsage("prices.create", false, { environment: opts.environment });
6555
+ handleError(err, json);
6556
+ }
6557
+ });
6558
+ pricesCmd.command("update <priceId>").description("Update a Stripe price").requiredOption("--environment <environment>", "Stripe environment: test or live").option("--active <bool>", "Set active status (true/false)").option("--lookup-key <key>", 'Stripe lookup key, or "null"').option("--tax-behavior <behavior>", "exclusive, inclusive, or unspecified").option("--metadata <json>", "Metadata JSON object with string values").action(async (priceId, opts, cmd) => {
6559
+ const { json } = getRootOpts(cmd);
6560
+ try {
6561
+ const environment = parseEnvironment(opts.environment);
6562
+ await requireAuth();
6563
+ const request = { environment };
6564
+ const active = parseBooleanOption(opts.active, "--active");
6565
+ const lookupKey = nullableString(opts.lookupKey);
6566
+ const taxBehavior = parseTaxBehavior(opts.taxBehavior);
6567
+ const metadata = parseMetadataOption(opts.metadata);
6568
+ if (active !== void 0) request.active = active;
6569
+ if (lookupKey !== void 0) request.lookupKey = lookupKey;
6570
+ if (taxBehavior !== void 0) request.taxBehavior = taxBehavior;
6571
+ if (metadata !== void 0) request.metadata = metadata;
6572
+ if (Object.keys(request).length === 1) {
6573
+ throw new CLIError("Provide at least one option to update (--active, --lookup-key, --tax-behavior, --metadata).");
6574
+ }
6575
+ const data = await updatePaymentPrice(priceId, request);
6576
+ if (json) {
6577
+ outputJson(data);
6578
+ } else {
6579
+ outputSuccess(`Stripe price updated: ${data.price.stripePriceId}`);
6580
+ }
6581
+ await trackPaymentUsage("prices.update", true, { environment });
6582
+ } catch (err) {
6583
+ await trackPaymentUsage("prices.update", false, { environment: opts.environment });
6584
+ handleError(err, json);
6585
+ }
6586
+ });
6587
+ pricesCmd.command("archive <priceId>").alias("delete").description("Archive a Stripe price").requiredOption("--environment <environment>", "Stripe environment: test or live").action(async (priceId, opts, cmd) => {
6588
+ const { json } = getRootOpts(cmd);
6589
+ try {
6590
+ const environment = parseEnvironment(opts.environment);
6591
+ await requireAuth();
6592
+ const data = await archivePaymentPrice(environment, priceId);
6593
+ if (json) {
6594
+ outputJson(data);
6595
+ } else {
6596
+ outputSuccess(`Stripe price archived: ${data.price.stripePriceId}`);
6597
+ }
6598
+ await trackPaymentUsage("prices.archive", true, { environment });
6599
+ } catch (err) {
6600
+ await trackPaymentUsage("prices.archive", false, { environment: opts.environment });
6601
+ handleError(err, json);
6602
+ }
6603
+ });
6604
+ }
6605
+
6606
+ // src/commands/payments/products.ts
6607
+ function nullableString2(value) {
6608
+ if (value === void 0) return void 0;
6609
+ return value === "null" ? null : value;
6610
+ }
6611
+ function outputProductsTable(products) {
6612
+ if (products.length === 0) {
6613
+ console.log("No Stripe products found.");
6614
+ return;
6615
+ }
6616
+ outputTable(
6617
+ ["Env", "Product ID", "Name", "Active", "Default Price", "Synced At"],
6618
+ products.map((product) => [
6619
+ product.environment,
6620
+ product.stripeProductId,
6621
+ product.name,
6622
+ product.active ? "Yes" : "No",
6623
+ product.defaultPriceId ?? "-",
6624
+ formatDate(product.syncedAt)
6625
+ ])
6626
+ );
6627
+ }
6628
+ function registerPaymentsProductsCommand(paymentsCmd2) {
6629
+ const productsCmd = paymentsCmd2.command("products").description("Manage Stripe products");
6630
+ productsCmd.command("list").description("List mirrored Stripe products").requiredOption("--environment <environment>", "Stripe environment: test or live").action(async (opts, cmd) => {
6631
+ const { json } = getRootOpts(cmd);
6632
+ try {
6633
+ const environment = parseEnvironment(opts.environment);
6634
+ await requireAuth();
6635
+ const data = await listPaymentProducts(environment);
6636
+ if (json) {
6637
+ outputJson(data);
6638
+ } else {
6639
+ outputProductsTable(data.products);
6640
+ }
6641
+ await trackPaymentUsage("products.list", true, { environment });
6642
+ } catch (err) {
6643
+ await trackPaymentUsage("products.list", false, { environment: opts.environment });
6644
+ handleError(err, json);
6645
+ }
6646
+ });
6647
+ productsCmd.command("get <productId>").description("Show one Stripe product and its prices").requiredOption("--environment <environment>", "Stripe environment: test or live").action(async (productId, opts, cmd) => {
6648
+ const { json } = getRootOpts(cmd);
6649
+ try {
6650
+ const environment = parseEnvironment(opts.environment);
6651
+ await requireAuth();
6652
+ const data = await getPaymentProduct(environment, productId);
6653
+ if (json) {
6654
+ outputJson(data);
6655
+ } else {
6656
+ outputProductsTable([data.product]);
6657
+ if (data.prices.length > 0) {
6658
+ console.log("Prices");
6659
+ outputTable(
6660
+ ["Price ID", "Amount", "Type", "Active", "Lookup Key"],
6661
+ data.prices.map((price) => [
6662
+ price.stripePriceId,
6663
+ formatAmount(price.unitAmount, price.currency),
6664
+ price.type,
6665
+ price.active ? "Yes" : "No",
6666
+ price.lookupKey ?? "-"
6667
+ ])
6668
+ );
6669
+ }
6670
+ }
6671
+ await trackPaymentUsage("products.get", true, { environment });
6672
+ } catch (err) {
6673
+ await trackPaymentUsage("products.get", false, { environment: opts.environment });
6674
+ handleError(err, json);
6675
+ }
6676
+ });
6677
+ productsCmd.command("create").description("Create a Stripe product").requiredOption("--environment <environment>", "Stripe environment: test or live").requiredOption("--name <name>", "Product name").option("--description <description>", 'Product description, or "null"').option("--active <bool>", "Set active status (true/false)").option("--metadata <json>", "Metadata JSON object with string values").option("--idempotency-key <key>", "Caller-stable idempotency key").action(async (opts, cmd) => {
6678
+ const { json } = getRootOpts(cmd);
6679
+ try {
6680
+ const environment = parseEnvironment(opts.environment);
6681
+ await requireAuth();
6682
+ const request = {
6683
+ environment,
6684
+ name: opts.name
6685
+ };
6686
+ const description = nullableString2(opts.description);
6687
+ const active = parseBooleanOption(opts.active, "--active");
6688
+ const metadata = parseMetadataOption(opts.metadata);
6689
+ if (description !== void 0) request.description = description;
6690
+ if (active !== void 0) request.active = active;
6691
+ if (metadata !== void 0) request.metadata = metadata;
6692
+ if (opts.idempotencyKey !== void 0) request.idempotencyKey = opts.idempotencyKey;
6693
+ const data = await createPaymentProduct(request);
6694
+ if (json) {
6695
+ outputJson(data);
6696
+ } else {
6697
+ outputSuccess(`Stripe product created: ${data.product.stripeProductId}`);
6698
+ }
6699
+ await trackPaymentUsage("products.create", true, { environment });
6700
+ } catch (err) {
6701
+ await trackPaymentUsage("products.create", false, { environment: opts.environment });
6702
+ handleError(err, json);
6703
+ }
6704
+ });
6705
+ productsCmd.command("update <productId>").description("Update a Stripe product").requiredOption("--environment <environment>", "Stripe environment: test or live").option("--name <name>", "Product name").option("--description <description>", 'Product description, or "null"').option("--active <bool>", "Set active status (true/false)").option("--metadata <json>", "Metadata JSON object with string values").action(async (productId, opts, cmd) => {
6706
+ const { json } = getRootOpts(cmd);
6707
+ try {
6708
+ const environment = parseEnvironment(opts.environment);
6709
+ await requireAuth();
6710
+ const request = { environment };
6711
+ const description = nullableString2(opts.description);
6712
+ const active = parseBooleanOption(opts.active, "--active");
6713
+ const metadata = parseMetadataOption(opts.metadata);
6714
+ if (opts.name !== void 0) request.name = opts.name;
6715
+ if (description !== void 0) request.description = description;
6716
+ if (active !== void 0) request.active = active;
6717
+ if (metadata !== void 0) request.metadata = metadata;
6718
+ if (Object.keys(request).length === 1) {
6719
+ throw new CLIError("Provide at least one option to update (--name, --description, --active, --metadata).");
6720
+ }
6721
+ const data = await updatePaymentProduct(productId, request);
6722
+ if (json) {
6723
+ outputJson(data);
6724
+ } else {
6725
+ outputSuccess(`Stripe product updated: ${data.product.stripeProductId}`);
6726
+ }
6727
+ await trackPaymentUsage("products.update", true, { environment });
6728
+ } catch (err) {
6729
+ await trackPaymentUsage("products.update", false, { environment: opts.environment });
6730
+ handleError(err, json);
6731
+ }
6732
+ });
6733
+ productsCmd.command("delete <productId>").description("Delete a Stripe product that has no prices").requiredOption("--environment <environment>", "Stripe environment: test or live").action(async (productId, opts, cmd) => {
6734
+ const { json, yes } = getRootOpts(cmd);
6735
+ try {
6736
+ const environment = parseEnvironment(opts.environment);
6737
+ await requireAuth();
6738
+ if (json && !yes) {
6739
+ throw new CLIError("Use --yes with --json to delete a Stripe product non-interactively.");
6740
+ }
6741
+ if (!yes) {
6742
+ const confirm3 = await confirm2({
6743
+ message: `Delete Stripe ${environment} product "${productId}"?`
6744
+ });
6745
+ if (isCancel2(confirm3) || !confirm3) process.exit(0);
6746
+ }
6747
+ const data = await deletePaymentProduct(environment, productId);
6748
+ if (json) {
6749
+ outputJson(data);
6750
+ } else {
6751
+ outputSuccess(`Stripe product deleted: ${data.stripeProductId}`);
6752
+ }
6753
+ await trackPaymentUsage("products.delete", true, { environment });
6754
+ } catch (err) {
6755
+ await trackPaymentUsage("products.delete", false, { environment: opts.environment });
6756
+ handleError(err, json);
6757
+ }
6758
+ });
6759
+ }
6760
+
6761
+ // src/commands/payments/status.ts
6762
+ function registerPaymentsStatusCommand(paymentsCmd2) {
6763
+ paymentsCmd2.command("status").description("Show Stripe payment connection, sync, and webhook status").action(async (_opts, cmd) => {
6764
+ const { json } = getRootOpts(cmd);
6765
+ try {
6766
+ await requireAuth();
6767
+ const data = await getPaymentsStatus();
6768
+ if (json) {
6769
+ outputJson(data);
6770
+ } else if (data.connections.length === 0) {
6771
+ console.log("No Stripe payment environments found.");
6772
+ } else {
6773
+ outputTable(
6774
+ ["Env", "Status", "Key", "Account", "Webhook", "Last Sync", "Synced At"],
6775
+ data.connections.map((connection) => [
6776
+ connection.environment,
6777
+ connection.status,
6778
+ connection.maskedKey ?? "-",
6779
+ connection.stripeAccountId ?? "-",
6780
+ connection.webhookEndpointId ? "Configured" : "-",
6781
+ connection.lastSyncStatus ?? "-",
6782
+ formatDate(connection.lastSyncedAt)
6783
+ ])
6784
+ );
6785
+ }
6786
+ await trackPaymentUsage("status", true);
6787
+ } catch (err) {
6788
+ await trackPaymentUsage("status", false);
6789
+ handleError(err, json);
6790
+ }
6791
+ });
6792
+ }
6793
+
6794
+ // src/commands/payments/subscriptions.ts
6795
+ function registerPaymentsSubscriptionsCommand(paymentsCmd2) {
6796
+ paymentsCmd2.command("subscriptions").description("List mirrored Stripe subscriptions").requiredOption("--environment <environment>", "Stripe environment: test or live").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) => {
6797
+ const { json } = getRootOpts(cmd);
6798
+ try {
6799
+ const environment = parseEnvironment(opts.environment);
6800
+ const limit = parseIntegerOption(opts.limit, "--limit", { min: 1, max: 100 }) ?? 50;
6801
+ await requireAuth();
6802
+ const data = await listSubscriptions({
6803
+ environment,
6804
+ limit,
6805
+ ...opts.subjectType !== void 0 ? { subjectType: opts.subjectType } : {},
6806
+ ...opts.subjectId !== void 0 ? { subjectId: opts.subjectId } : {}
6807
+ });
6808
+ if (json) {
6809
+ outputJson(data);
6810
+ } else if (data.subscriptions.length === 0) {
6811
+ console.log("No Stripe subscriptions found.");
6812
+ } else {
6813
+ outputTable(
6814
+ ["Subscription ID", "Customer", "Subject", "Status", "Items", "Period End"],
6815
+ data.subscriptions.map((subscription) => [
6816
+ subscription.stripeSubscriptionId,
6817
+ subscription.stripeCustomerId,
6818
+ subscription.subjectType && subscription.subjectId ? `${subscription.subjectType}:${subscription.subjectId}` : "-",
6819
+ subscription.status,
6820
+ String(subscription.items?.length ?? 0),
6821
+ formatDate(subscription.currentPeriodEnd)
6822
+ ])
6823
+ );
6824
+ }
6825
+ await trackPaymentUsage("subscriptions", true, { environment });
6826
+ } catch (err) {
6827
+ await trackPaymentUsage("subscriptions", false, { environment: opts.environment });
6828
+ handleError(err, json);
6829
+ }
6830
+ });
6831
+ }
6832
+
6833
+ // src/commands/payments/sync.ts
6834
+ function registerPaymentsSyncCommand(paymentsCmd2) {
6835
+ paymentsCmd2.command("sync").description("Sync configured Stripe products, prices, and subscriptions").option("--environment <environment>", "Stripe environment: test, live, or all", "all").action(async (opts, cmd) => {
6836
+ const { json } = getRootOpts(cmd);
6837
+ try {
6838
+ const environment = parseEnvironmentOrAll(opts.environment);
6839
+ await requireAuth();
6840
+ const data = await syncPayments(environment);
6841
+ if (json) {
6842
+ outputJson(data);
6843
+ } else if (data.results.length === 0) {
6844
+ console.log("No configured Stripe environments to sync.");
6845
+ } else {
6846
+ outputTable(
6847
+ ["Env", "Status", "Products", "Prices", "Subscriptions", "Unmapped", "Synced At"],
6848
+ data.results.map((result) => [
6849
+ result.environment,
6850
+ result.connection.lastSyncStatus ?? result.connection.status,
6851
+ String(result.connection.lastSyncCounts.products ?? 0),
6852
+ String(result.connection.lastSyncCounts.prices ?? 0),
6853
+ String(result.subscriptions?.synced ?? 0),
6854
+ String(result.subscriptions?.unmapped ?? 0),
6855
+ formatDate(result.connection.lastSyncedAt)
6856
+ ])
6857
+ );
6858
+ outputSuccess("Stripe payments synced.");
6859
+ }
6860
+ await trackPaymentUsage("sync", true, { environment });
6861
+ } catch (err) {
6862
+ await trackPaymentUsage("sync", false, { environment: opts.environment });
6863
+ handleError(err, json);
6864
+ }
6865
+ });
6866
+ }
6867
+
6868
+ // src/commands/payments/webhooks.ts
6869
+ function registerPaymentsWebhooksCommand(paymentsCmd2) {
6870
+ const webhooksCmd = paymentsCmd2.command("webhooks").description("Manage InsForge-managed Stripe webhooks");
6871
+ webhooksCmd.command("configure <environment>").description("Create or recreate the managed Stripe webhook endpoint").action(async (environmentValue, _opts, cmd) => {
6872
+ const { json } = getRootOpts(cmd);
6873
+ try {
6874
+ const environment = parseEnvironment(environmentValue);
6875
+ await requireAuth();
6876
+ const data = await configurePaymentWebhook(environment);
6877
+ if (json) {
6878
+ outputJson(data);
6879
+ } else {
6880
+ outputTable(
6881
+ ["Env", "Webhook ID", "URL", "Configured At"],
6882
+ [[
6883
+ data.connection.environment,
6884
+ data.connection.webhookEndpointId ?? "-",
6885
+ data.connection.webhookEndpointUrl ?? "-",
6886
+ formatDate(data.connection.webhookConfiguredAt)
6887
+ ]]
6888
+ );
6889
+ outputSuccess(`Stripe ${environment} webhook configured.`);
6890
+ }
6891
+ await trackPaymentUsage("webhooks.configure", true, { environment });
6892
+ } catch (err) {
6893
+ await trackPaymentUsage("webhooks.configure", false, { environment: environmentValue });
6894
+ handleError(err, json);
6895
+ }
6896
+ });
6897
+ }
6898
+
6899
+ // src/commands/payments/index.ts
6900
+ function registerPaymentsCommands(paymentsCmd2) {
6901
+ paymentsCmd2.description("Manage Stripe payments");
6902
+ registerPaymentsStatusCommand(paymentsCmd2);
6903
+ registerPaymentsConfigCommand(paymentsCmd2);
6904
+ registerPaymentsSyncCommand(paymentsCmd2);
6905
+ registerPaymentsWebhooksCommand(paymentsCmd2);
6906
+ registerPaymentsCatalogCommand(paymentsCmd2);
6907
+ registerPaymentsProductsCommand(paymentsCmd2);
6908
+ registerPaymentsPricesCommand(paymentsCmd2);
6909
+ registerPaymentsSubscriptionsCommand(paymentsCmd2);
6910
+ registerPaymentsHistoryCommand(paymentsCmd2);
6911
+ }
6912
+
5991
6913
  // src/index.ts
5992
6914
  var __dirname = dirname(fileURLToPath(import.meta.url));
5993
- var pkg = JSON.parse(readFileSync7(join12(__dirname, "../package.json"), "utf-8"));
6915
+ var pkg = JSON.parse(readFileSync7(join13(__dirname, "../package.json"), "utf-8"));
5994
6916
  var INSFORGE_LOGO = `
5995
6917
  \u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
5996
6918
  \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
@@ -6059,6 +6981,8 @@ registerLogsCommand(program);
6059
6981
  registerMetadataCommand(program);
6060
6982
  var diagnoseCmd = program.command("diagnose");
6061
6983
  registerDiagnoseCommands(diagnoseCmd);
6984
+ var paymentsCmd = program.command("payments").description("Manage Stripe payments");
6985
+ registerPaymentsCommands(paymentsCmd);
6062
6986
  var computeCmd = program.command("compute").description("Manage compute services (Docker containers on Fly.io)");
6063
6987
  registerComputeListCommand(computeCmd);
6064
6988
  registerComputeGetCommand(computeCmd);