@gpc-cli/core 0.9.14 → 0.9.16
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 +121 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -150,6 +150,14 @@ ${formatYaml(value, indent + 1)}`;
|
|
|
150
150
|
}
|
|
151
151
|
return String(data);
|
|
152
152
|
}
|
|
153
|
+
function cellValue(val) {
|
|
154
|
+
if (val === null || val === void 0) return "";
|
|
155
|
+
if (typeof val === "object") {
|
|
156
|
+
if (Array.isArray(val)) return val.length === 0 ? "" : JSON.stringify(val);
|
|
157
|
+
return JSON.stringify(val);
|
|
158
|
+
}
|
|
159
|
+
return String(val);
|
|
160
|
+
}
|
|
153
161
|
function formatTable(data) {
|
|
154
162
|
const rows = toRows(data);
|
|
155
163
|
if (rows.length === 0) return "";
|
|
@@ -158,11 +166,11 @@ function formatTable(data) {
|
|
|
158
166
|
const keys = Object.keys(firstRow);
|
|
159
167
|
if (keys.length === 0) return "";
|
|
160
168
|
const widths = keys.map(
|
|
161
|
-
(key) => Math.max(key.length, ...rows.map((row) =>
|
|
169
|
+
(key) => Math.max(key.length, ...rows.map((row) => cellValue(row[key]).length))
|
|
162
170
|
);
|
|
163
171
|
const header = keys.map((key, i) => key.padEnd(widths[i] ?? 0)).join(" ");
|
|
164
172
|
const separator = widths.map((w) => "-".repeat(w)).join(" ");
|
|
165
|
-
const body = rows.map((row) => keys.map((key, i) =>
|
|
173
|
+
const body = rows.map((row) => keys.map((key, i) => cellValue(row[key]).padEnd(widths[i] ?? 0)).join(" ")).join("\n");
|
|
166
174
|
return `${header}
|
|
167
175
|
${separator}
|
|
168
176
|
${body}`;
|
|
@@ -175,12 +183,12 @@ function formatMarkdown(data) {
|
|
|
175
183
|
const keys = Object.keys(firstRow);
|
|
176
184
|
if (keys.length === 0) return "";
|
|
177
185
|
const widths = keys.map(
|
|
178
|
-
(key) => Math.max(key.length, ...rows.map((row) =>
|
|
186
|
+
(key) => Math.max(key.length, ...rows.map((row) => cellValue(row[key]).length))
|
|
179
187
|
);
|
|
180
188
|
const header = `| ${keys.map((key, i) => key.padEnd(widths[i] ?? 0)).join(" | ")} |`;
|
|
181
189
|
const separator = `| ${widths.map((w) => "-".repeat(w)).join(" | ")} |`;
|
|
182
190
|
const body = rows.map(
|
|
183
|
-
(row) => `| ${keys.map((key, i) =>
|
|
191
|
+
(row) => `| ${keys.map((key, i) => cellValue(row[key]).padEnd(widths[i] ?? 0)).join(" | ")} |`
|
|
184
192
|
).join("\n");
|
|
185
193
|
return `${header}
|
|
186
194
|
${separator}
|
|
@@ -2048,6 +2056,105 @@ function checkThreshold(value, threshold) {
|
|
|
2048
2056
|
|
|
2049
2057
|
// src/commands/subscriptions.ts
|
|
2050
2058
|
import { paginateAll as paginateAll2 } from "@gpc-cli/api";
|
|
2059
|
+
function coerceMoneyUnits(money) {
|
|
2060
|
+
if (money.units !== void 0 && typeof money.units !== "string") {
|
|
2061
|
+
return { ...money, units: String(money.units) };
|
|
2062
|
+
}
|
|
2063
|
+
return money;
|
|
2064
|
+
}
|
|
2065
|
+
function sanitizeSubscription(data) {
|
|
2066
|
+
const { ...cleaned } = data;
|
|
2067
|
+
delete cleaned["state"];
|
|
2068
|
+
delete cleaned["archived"];
|
|
2069
|
+
if (cleaned.basePlans) {
|
|
2070
|
+
cleaned.basePlans = cleaned.basePlans.map((bp) => {
|
|
2071
|
+
const { state: _s, archived: _a, ...cleanBp } = bp;
|
|
2072
|
+
if (cleanBp.regionalConfigs) {
|
|
2073
|
+
cleanBp.regionalConfigs = cleanBp.regionalConfigs.map((rc) => ({
|
|
2074
|
+
...rc,
|
|
2075
|
+
price: coerceMoneyUnits(rc.price)
|
|
2076
|
+
}));
|
|
2077
|
+
}
|
|
2078
|
+
return cleanBp;
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
return cleaned;
|
|
2082
|
+
}
|
|
2083
|
+
function sanitizeOffer(data) {
|
|
2084
|
+
const { state: _s, ...cleaned } = data;
|
|
2085
|
+
delete cleaned["archived"];
|
|
2086
|
+
return cleaned;
|
|
2087
|
+
}
|
|
2088
|
+
function parseDuration(iso) {
|
|
2089
|
+
const match = iso.match(/^P(\d+)D$/);
|
|
2090
|
+
return match?.[1] ? parseInt(match[1], 10) : 0;
|
|
2091
|
+
}
|
|
2092
|
+
var PRORATION_MODE_PREFIX = "SUBSCRIPTION_PRORATION_MODE_";
|
|
2093
|
+
var VALID_PRORATION_MODES = [
|
|
2094
|
+
"SUBSCRIPTION_PRORATION_MODE_CHARGE_ON_NEXT_BILLING_DATE",
|
|
2095
|
+
"SUBSCRIPTION_PRORATION_MODE_CHARGE_FULL_PRICE_IMMEDIATELY"
|
|
2096
|
+
];
|
|
2097
|
+
function autoFixProrationMode(data) {
|
|
2098
|
+
if (!data.basePlans) return;
|
|
2099
|
+
for (const bp of data.basePlans) {
|
|
2100
|
+
const mode = bp.autoRenewingBasePlanType?.prorationMode;
|
|
2101
|
+
if (mode && !mode.startsWith(PRORATION_MODE_PREFIX)) {
|
|
2102
|
+
bp.autoRenewingBasePlanType.prorationMode = `${PRORATION_MODE_PREFIX}${mode}`;
|
|
2103
|
+
}
|
|
2104
|
+
if (bp.autoRenewingBasePlanType?.prorationMode) {
|
|
2105
|
+
const fullMode = bp.autoRenewingBasePlanType.prorationMode;
|
|
2106
|
+
if (!VALID_PRORATION_MODES.includes(fullMode)) {
|
|
2107
|
+
throw new GpcError(
|
|
2108
|
+
`Invalid prorationMode: "${fullMode}"`,
|
|
2109
|
+
"INVALID_SUBSCRIPTION_DATA",
|
|
2110
|
+
2,
|
|
2111
|
+
`Valid values: ${VALID_PRORATION_MODES.join(", ")}`
|
|
2112
|
+
);
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
function validateSubscriptionData(data) {
|
|
2118
|
+
autoFixProrationMode(data);
|
|
2119
|
+
if (data.listings) {
|
|
2120
|
+
for (const [lang, listing] of Object.entries(data.listings)) {
|
|
2121
|
+
if (listing.benefits && listing.benefits.length > 4) {
|
|
2122
|
+
throw new GpcError(
|
|
2123
|
+
`Listing "${lang}" has ${listing.benefits.length} benefits (max 4)`,
|
|
2124
|
+
"INVALID_SUBSCRIPTION_DATA",
|
|
2125
|
+
2,
|
|
2126
|
+
"Google Play allows a maximum of 4 benefits per subscription listing"
|
|
2127
|
+
);
|
|
2128
|
+
}
|
|
2129
|
+
if (listing.description && listing.description.length > 80) {
|
|
2130
|
+
throw new GpcError(
|
|
2131
|
+
`Listing "${lang}" description is ${listing.description.length} chars (max 80)`,
|
|
2132
|
+
"INVALID_SUBSCRIPTION_DATA",
|
|
2133
|
+
2,
|
|
2134
|
+
"Google Play limits subscription descriptions to 80 characters"
|
|
2135
|
+
);
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
if (data.basePlans) {
|
|
2140
|
+
for (const bp of data.basePlans) {
|
|
2141
|
+
const autoType = bp.autoRenewingBasePlanType;
|
|
2142
|
+
if (autoType?.gracePeriodDuration && autoType?.accountHoldDuration) {
|
|
2143
|
+
const grace = parseDuration(autoType.gracePeriodDuration);
|
|
2144
|
+
const hold = parseDuration(autoType.accountHoldDuration);
|
|
2145
|
+
const sum = grace + hold;
|
|
2146
|
+
if (sum < 30 || sum > 60) {
|
|
2147
|
+
throw new GpcError(
|
|
2148
|
+
`Base plan "${bp.basePlanId}": gracePeriodDuration (${grace}d) + accountHoldDuration (${hold}d) = ${sum}d (must be 30-60)`,
|
|
2149
|
+
"INVALID_SUBSCRIPTION_DATA",
|
|
2150
|
+
2,
|
|
2151
|
+
"gracePeriodDuration + accountHoldDuration must sum to between P30D and P60D"
|
|
2152
|
+
);
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2051
2158
|
async function listSubscriptions(client, packageName, options) {
|
|
2052
2159
|
validatePackageName(packageName);
|
|
2053
2160
|
if (options?.limit || options?.nextPage) {
|
|
@@ -2075,12 +2182,16 @@ async function getSubscription(client, packageName, productId) {
|
|
|
2075
2182
|
}
|
|
2076
2183
|
async function createSubscription(client, packageName, data) {
|
|
2077
2184
|
validatePackageName(packageName);
|
|
2078
|
-
|
|
2185
|
+
validateSubscriptionData(data);
|
|
2186
|
+
const sanitized = sanitizeSubscription(data);
|
|
2187
|
+
return client.subscriptions.create(packageName, sanitized, data.productId);
|
|
2079
2188
|
}
|
|
2080
2189
|
async function updateSubscription(client, packageName, productId, data, updateMask) {
|
|
2081
2190
|
validatePackageName(packageName);
|
|
2082
2191
|
validateSku(productId);
|
|
2083
|
-
|
|
2192
|
+
validateSubscriptionData(data);
|
|
2193
|
+
const sanitized = sanitizeSubscription(data);
|
|
2194
|
+
return client.subscriptions.update(packageName, productId, sanitized, updateMask);
|
|
2084
2195
|
}
|
|
2085
2196
|
async function deleteSubscription(client, packageName, productId) {
|
|
2086
2197
|
validatePackageName(packageName);
|
|
@@ -2120,17 +2231,19 @@ async function getOffer(client, packageName, productId, basePlanId, offerId) {
|
|
|
2120
2231
|
async function createOffer(client, packageName, productId, basePlanId, data) {
|
|
2121
2232
|
validatePackageName(packageName);
|
|
2122
2233
|
validateSku(productId);
|
|
2123
|
-
|
|
2234
|
+
const sanitized = sanitizeOffer(data);
|
|
2235
|
+
return client.subscriptions.createOffer(packageName, productId, basePlanId, sanitized, data.offerId);
|
|
2124
2236
|
}
|
|
2125
2237
|
async function updateOffer(client, packageName, productId, basePlanId, offerId, data, updateMask) {
|
|
2126
2238
|
validatePackageName(packageName);
|
|
2127
2239
|
validateSku(productId);
|
|
2240
|
+
const sanitized = sanitizeOffer(data);
|
|
2128
2241
|
return client.subscriptions.updateOffer(
|
|
2129
2242
|
packageName,
|
|
2130
2243
|
productId,
|
|
2131
2244
|
basePlanId,
|
|
2132
2245
|
offerId,
|
|
2133
|
-
|
|
2246
|
+
sanitized,
|
|
2134
2247
|
updateMask
|
|
2135
2248
|
);
|
|
2136
2249
|
}
|