@insforge/cli 0.1.61 → 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/README.md +87 -1
- package/dist/index.js +868 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -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 = "
|
|
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
|
}
|
|
@@ -5819,7 +5833,7 @@ function registerDiagnoseCommands(diagnoseCmd2) {
|
|
|
5819
5833
|
const s = !json ? clack10.spinner() : null;
|
|
5820
5834
|
s?.start("Collecting diagnostic data...");
|
|
5821
5835
|
const data2 = await collectDiagnosticData(projectId, ossMode, apiUrl);
|
|
5822
|
-
const cliVersion = "0.1.
|
|
5836
|
+
const cliVersion = "0.1.62";
|
|
5823
5837
|
s?.stop("Data collected");
|
|
5824
5838
|
if (!json) {
|
|
5825
5839
|
console.log(`
|
|
@@ -6046,6 +6060,856 @@ function formatBytesCompact(bytes) {
|
|
|
6046
6060
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
6047
6061
|
}
|
|
6048
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
|
+
|
|
6049
6913
|
// src/index.ts
|
|
6050
6914
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6051
6915
|
var pkg = JSON.parse(readFileSync7(join13(__dirname, "../package.json"), "utf-8"));
|
|
@@ -6117,6 +6981,8 @@ registerLogsCommand(program);
|
|
|
6117
6981
|
registerMetadataCommand(program);
|
|
6118
6982
|
var diagnoseCmd = program.command("diagnose");
|
|
6119
6983
|
registerDiagnoseCommands(diagnoseCmd);
|
|
6984
|
+
var paymentsCmd = program.command("payments").description("Manage Stripe payments");
|
|
6985
|
+
registerPaymentsCommands(paymentsCmd);
|
|
6120
6986
|
var computeCmd = program.command("compute").description("Manage compute services (Docker containers on Fly.io)");
|
|
6121
6987
|
registerComputeListCommand(computeCmd);
|
|
6122
6988
|
registerComputeGetCommand(computeCmd);
|