@gpc-cli/cli 0.9.44 → 0.9.46
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/{anomalies-NU2IN2GJ.js → anomalies-UDE4NGHJ.js} +19 -24
- package/dist/anomalies-UDE4NGHJ.js.map +1 -0
- package/dist/{apps-J2446UDA.js → apps-FKD3ZG5X.js} +31 -35
- package/dist/apps-FKD3ZG5X.js.map +1 -0
- package/dist/{audit-N2CRHWUN.js → audit-JASSHRWN.js} +47 -62
- package/dist/audit-JASSHRWN.js.map +1 -0
- package/dist/{auth-XGSTT5G5.js → auth-OTA3SV3J.js} +145 -103
- package/dist/auth-OTA3SV3J.js.map +1 -0
- package/dist/bin.js +6 -4
- package/dist/bin.js.map +1 -1
- package/dist/bundle-F7MUVC5J.js +204 -0
- package/dist/bundle-F7MUVC5J.js.map +1 -0
- package/dist/{cache-SLNFRTI2.js → cache-XKPLZYEB.js} +4 -5
- package/dist/cache-XKPLZYEB.js.map +1 -0
- package/dist/changelog-7COFZO7Q.js +48 -0
- package/dist/changelog-7COFZO7Q.js.map +1 -0
- package/dist/{chunk-4O4D5SGL.js → chunk-3SJ6OXCZ.js} +4 -5
- package/dist/chunk-3SJ6OXCZ.js.map +1 -0
- package/dist/{chunk-7LURVNQV.js → chunk-6OWN6S6X.js} +53 -49
- package/dist/{chunk-7LURVNQV.js.map → chunk-6OWN6S6X.js.map} +1 -1
- package/dist/{chunk-U6ZTQ34I.js → chunk-BCBXQC7J.js} +45 -11
- package/dist/chunk-BCBXQC7J.js.map +1 -0
- package/dist/{chunk-AA577WVQ.js → chunk-NQH4G7BI.js} +9 -3
- package/dist/chunk-NQH4G7BI.js.map +1 -0
- package/dist/chunk-SLNJEAMK.js +23 -0
- package/dist/chunk-SLNJEAMK.js.map +1 -0
- package/dist/{chunk-NV75I5VP.js → chunk-YFUBD2XB.js} +10 -8
- package/dist/chunk-YFUBD2XB.js.map +1 -0
- package/dist/{config-222P3MKK.js → config-2FTCYEGD.js} +8 -5
- package/dist/config-2FTCYEGD.js.map +1 -0
- package/dist/{data-safety-Q7FTCEWU.js → data-safety-AFMD6MYI.js} +12 -27
- package/dist/data-safety-AFMD6MYI.js.map +1 -0
- package/dist/{device-tiers-MIOQEXYY.js → device-tiers-AQAMUQXI.js} +23 -38
- package/dist/device-tiers-AQAMUQXI.js.map +1 -0
- package/dist/diff-6EO4ID6W.js +91 -0
- package/dist/diff-6EO4ID6W.js.map +1 -0
- package/dist/{docs-7DUXIKA3.js → docs-4D2SJ4LY.js} +4 -3
- package/dist/docs-4D2SJ4LY.js.map +1 -0
- package/dist/doctor-H4X7Q57B.js +691 -0
- package/dist/doctor-H4X7Q57B.js.map +1 -0
- package/dist/{enterprise-7THXNBTC.js → enterprise-7PWXMSUN.js} +11 -21
- package/dist/enterprise-7PWXMSUN.js.map +1 -0
- package/dist/{external-transactions-2GWIMUVM.js → external-transactions-LCZALS3V.js} +12 -28
- package/dist/external-transactions-LCZALS3V.js.map +1 -0
- package/dist/{feedback-2W2XJGZX.js → feedback-XP765TOO.js} +4 -4
- package/dist/{games-BT777WUO.js → games-ZSNGEI7A.js} +17 -32
- package/dist/games-ZSNGEI7A.js.map +1 -0
- package/dist/{generated-apks-RJWTIX7L.js → generated-apks-RX2IUWSF.js} +30 -38
- package/dist/generated-apks-RX2IUWSF.js.map +1 -0
- package/dist/{grants-TKQJ3IER.js → grants-EBPECI26.js} +22 -40
- package/dist/grants-EBPECI26.js.map +1 -0
- package/dist/{iap-ICAEQLK5.js → iap-OUI5YYN4.js} +30 -51
- package/dist/iap-OUI5YYN4.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{init-JZ2THPMS.js → init-WSTQTJOD.js} +5 -4
- package/dist/init-WSTQTJOD.js.map +1 -0
- package/dist/{install-skills-OV4HVANW.js → install-skills-6QDUXI5F.js} +5 -6
- package/dist/{install-skills-OV4HVANW.js.map → install-skills-6QDUXI5F.js.map} +1 -1
- package/dist/{internal-sharing-3U2XFHA4.js → internal-sharing-ONNIWIAT.js} +3 -4
- package/dist/{internal-sharing-3U2XFHA4.js.map → internal-sharing-ONNIWIAT.js.map} +1 -1
- package/dist/{listings-77HZW4S5.js → listings-7SGQ4SRX.js} +118 -157
- package/dist/listings-7SGQ4SRX.js.map +1 -0
- package/dist/migrate-ZQCJGQQS.js +138 -0
- package/dist/migrate-ZQCJGQQS.js.map +1 -0
- package/dist/{one-time-products-LHZAXQES.js → one-time-products-MGZTU7OM.js} +65 -120
- package/dist/one-time-products-MGZTU7OM.js.map +1 -0
- package/dist/{preflight-H3HEBYQW.js → preflight-N7ZRG2JI.js} +58 -55
- package/dist/preflight-N7ZRG2JI.js.map +1 -0
- package/dist/{pricing-XQSDTTK5.js → pricing-JJZFICFL.js} +8 -8
- package/dist/{pricing-XQSDTTK5.js.map → pricing-JJZFICFL.js.map} +1 -1
- package/dist/{prompt-BSV22CQZ.js → prompt-GXC2JSLA.js} +2 -2
- package/dist/{publish-Q5ZKEKZ5.js → publish-JPTI4EBT.js} +34 -30
- package/dist/publish-JPTI4EBT.js.map +1 -0
- package/dist/{purchase-options-CKRN4VIW.js → purchase-options-KFWW4JW2.js} +16 -11
- package/dist/purchase-options-KFWW4JW2.js.map +1 -0
- package/dist/purchases-DAWTMXP6.js +383 -0
- package/dist/purchases-DAWTMXP6.js.map +1 -0
- package/dist/{quickstart-4HB62YEL.js → quickstart-Z5Y3FYJU.js} +5 -3
- package/dist/quickstart-Z5Y3FYJU.js.map +1 -0
- package/dist/{quota-UHIQQYOY.js → quota-MZRWYJGR.js} +5 -15
- package/dist/quota-MZRWYJGR.js.map +1 -0
- package/dist/{recovery-5EV2R476.js → recovery-YE3Z7NIN.js} +32 -61
- package/dist/recovery-YE3Z7NIN.js.map +1 -0
- package/dist/{releases-C2WC2K4E.js → releases-2I3WBULC.js} +184 -185
- package/dist/releases-2I3WBULC.js.map +1 -0
- package/dist/{reports-2YX3RDOS.js → reports-CIB2T3XT.js} +19 -21
- package/dist/reports-CIB2T3XT.js.map +1 -0
- package/dist/reviews-BCCXIQ6C.js +188 -0
- package/dist/reviews-BCCXIQ6C.js.map +1 -0
- package/dist/{status-WHGLODGV.js → status-6LH5W4FU.js} +105 -83
- package/dist/status-6LH5W4FU.js.map +1 -0
- package/dist/{subscriptions-CI3JH3VQ.js → subscriptions-DZP3Y7O7.js} +142 -232
- package/dist/subscriptions-DZP3Y7O7.js.map +1 -0
- package/dist/{testers-NZOFA3EF.js → testers-LSMBXCA2.js} +24 -44
- package/dist/testers-LSMBXCA2.js.map +1 -0
- package/dist/tracks-YHMO2A6B.js +98 -0
- package/dist/tracks-YHMO2A6B.js.map +1 -0
- package/dist/{train-XKE4JN3Y.js → train-MDD2EBHS.js} +35 -55
- package/dist/train-MDD2EBHS.js.map +1 -0
- package/dist/{update-QMPRL5Y6.js → update-OMALGIBR.js} +30 -15
- package/dist/update-OMALGIBR.js.map +1 -0
- package/dist/{users-2YTC4Q36.js → users-UKG7VIQH.js} +45 -67
- package/dist/users-UKG7VIQH.js.map +1 -0
- package/dist/{validate-UOVTM6L3.js → validate-QIYSA3N7.js} +8 -10
- package/dist/validate-QIYSA3N7.js.map +1 -0
- package/dist/{version-NK5SJLHJ.js → version-NCSNXNVN.js} +4 -4
- package/dist/{vitals-A4CS4MSS.js → vitals-C23L2Y2E.js} +153 -172
- package/dist/vitals-C23L2Y2E.js.map +1 -0
- package/package.json +6 -6
- package/dist/anomalies-NU2IN2GJ.js.map +0 -1
- package/dist/apps-J2446UDA.js.map +0 -1
- package/dist/audit-N2CRHWUN.js.map +0 -1
- package/dist/auth-XGSTT5G5.js.map +0 -1
- package/dist/bundle-F43TD2BQ.js +0 -218
- package/dist/bundle-F43TD2BQ.js.map +0 -1
- package/dist/cache-SLNFRTI2.js.map +0 -1
- package/dist/changelog-OYUZOCOL.js +0 -53
- package/dist/changelog-OYUZOCOL.js.map +0 -1
- package/dist/chunk-4O4D5SGL.js.map +0 -1
- package/dist/chunk-AA577WVQ.js.map +0 -1
- package/dist/chunk-FWKYRLKY.js +0 -19
- package/dist/chunk-FWKYRLKY.js.map +0 -1
- package/dist/chunk-NV75I5VP.js.map +0 -1
- package/dist/chunk-U6ZTQ34I.js.map +0 -1
- package/dist/config-222P3MKK.js.map +0 -1
- package/dist/data-safety-Q7FTCEWU.js.map +0 -1
- package/dist/device-tiers-MIOQEXYY.js.map +0 -1
- package/dist/diff-V77SMKAQ.js +0 -96
- package/dist/diff-V77SMKAQ.js.map +0 -1
- package/dist/docs-7DUXIKA3.js.map +0 -1
- package/dist/doctor-3Z4ARPM2.js +0 -372
- package/dist/doctor-3Z4ARPM2.js.map +0 -1
- package/dist/enterprise-7THXNBTC.js.map +0 -1
- package/dist/external-transactions-2GWIMUVM.js.map +0 -1
- package/dist/games-BT777WUO.js.map +0 -1
- package/dist/generated-apks-RJWTIX7L.js.map +0 -1
- package/dist/grants-TKQJ3IER.js.map +0 -1
- package/dist/iap-ICAEQLK5.js.map +0 -1
- package/dist/init-JZ2THPMS.js.map +0 -1
- package/dist/listings-77HZW4S5.js.map +0 -1
- package/dist/migrate-SQT6RD6T.js +0 -143
- package/dist/migrate-SQT6RD6T.js.map +0 -1
- package/dist/one-time-products-LHZAXQES.js.map +0 -1
- package/dist/preflight-H3HEBYQW.js.map +0 -1
- package/dist/publish-Q5ZKEKZ5.js.map +0 -1
- package/dist/purchase-options-CKRN4VIW.js.map +0 -1
- package/dist/purchases-HSMCOG4A.js +0 -330
- package/dist/purchases-HSMCOG4A.js.map +0 -1
- package/dist/quickstart-4HB62YEL.js.map +0 -1
- package/dist/quota-UHIQQYOY.js.map +0 -1
- package/dist/recovery-5EV2R476.js.map +0 -1
- package/dist/releases-C2WC2K4E.js.map +0 -1
- package/dist/reports-2YX3RDOS.js.map +0 -1
- package/dist/reviews-2CWOI5CV.js +0 -213
- package/dist/reviews-2CWOI5CV.js.map +0 -1
- package/dist/status-WHGLODGV.js.map +0 -1
- package/dist/subscriptions-CI3JH3VQ.js.map +0 -1
- package/dist/testers-NZOFA3EF.js.map +0 -1
- package/dist/tracks-NERFFEDT.js +0 -107
- package/dist/tracks-NERFFEDT.js.map +0 -1
- package/dist/train-XKE4JN3Y.js.map +0 -1
- package/dist/update-QMPRL5Y6.js.map +0 -1
- package/dist/users-2YTC4Q36.js.map +0 -1
- package/dist/validate-UOVTM6L3.js.map +0 -1
- package/dist/vitals-A4CS4MSS.js.map +0 -1
- /package/dist/{feedback-2W2XJGZX.js.map → feedback-XP765TOO.js.map} +0 -0
- /package/dist/{prompt-BSV22CQZ.js.map → prompt-GXC2JSLA.js.map} +0 -0
- /package/dist/{version-NK5SJLHJ.js.map → version-NCSNXNVN.js.map} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
readJsonFile
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SLNJEAMK.js";
|
|
5
5
|
import {
|
|
6
6
|
getClient,
|
|
7
7
|
resolvePackageName
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NQH4G7BI.js";
|
|
9
9
|
import {
|
|
10
10
|
isDryRun,
|
|
11
11
|
printDryRun
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./chunk-ELXAK7GI.js";
|
|
16
16
|
import {
|
|
17
17
|
requireConfirm
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-YFUBD2XB.js";
|
|
19
19
|
|
|
20
20
|
// src/commands/one-time-products.ts
|
|
21
21
|
import { loadConfig } from "@gpc-cli/config";
|
|
@@ -41,30 +41,25 @@ function registerOneTimeProductsCommands(program) {
|
|
|
41
41
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
42
42
|
const client = await getClient(config);
|
|
43
43
|
const format = getOutputFormat(program, config);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const summary = products.map((p) => ({
|
|
56
|
-
productId: p.productId,
|
|
57
|
-
purchaseType: p["purchaseType"] || "-",
|
|
58
|
-
listings: p.listings ? Object.keys(p.listings).length : 0,
|
|
59
|
-
firstTitle: p.listings ? Object.values(p.listings)[0]?.title || "-" : "-"
|
|
60
|
-
}));
|
|
61
|
-
console.log(formatOutput(summary, format));
|
|
62
|
-
} else {
|
|
63
|
-
console.log(formatOutput(result, format));
|
|
44
|
+
const result = await listOneTimeProducts(client, packageName);
|
|
45
|
+
if (options.sort) {
|
|
46
|
+
result.oneTimeProducts = sortResults(result.oneTimeProducts, options.sort);
|
|
47
|
+
}
|
|
48
|
+
const products = result.oneTimeProducts || [];
|
|
49
|
+
if (format !== "json") {
|
|
50
|
+
if (products.length === 0) {
|
|
51
|
+
console.log("No one-time products found.");
|
|
52
|
+
return;
|
|
64
53
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
54
|
+
const summary = products.map((p) => ({
|
|
55
|
+
productId: p.productId,
|
|
56
|
+
purchaseType: p["purchaseType"] || "-",
|
|
57
|
+
listings: p.listings ? Object.keys(p.listings).length : 0,
|
|
58
|
+
firstTitle: p.listings ? Object.values(p.listings)[0]?.title || "-" : "-"
|
|
59
|
+
}));
|
|
60
|
+
console.log(formatOutput(summary, format));
|
|
61
|
+
} else {
|
|
62
|
+
console.log(formatOutput(result, format));
|
|
68
63
|
}
|
|
69
64
|
});
|
|
70
65
|
otp.command("get <product-id>").description("Get a one-time product").action(async (productId) => {
|
|
@@ -72,13 +67,8 @@ function registerOneTimeProductsCommands(program) {
|
|
|
72
67
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
73
68
|
const client = await getClient(config);
|
|
74
69
|
const format = getOutputFormat(program, config);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
console.log(formatOutput(result, format));
|
|
78
|
-
} catch (error) {
|
|
79
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
80
|
-
process.exit(4);
|
|
81
|
-
}
|
|
70
|
+
const result = await getOneTimeProduct(client, packageName, productId);
|
|
71
|
+
console.log(formatOutput(result, format));
|
|
82
72
|
});
|
|
83
73
|
otp.command("create").description("Create a one-time product from JSON file").requiredOption("--file <path>", "JSON file with product data").action(async (options) => {
|
|
84
74
|
const config = await loadConfig();
|
|
@@ -97,14 +87,9 @@ function registerOneTimeProductsCommands(program) {
|
|
|
97
87
|
return;
|
|
98
88
|
}
|
|
99
89
|
const client = await getClient(config);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
console.log(formatOutput(result, format));
|
|
104
|
-
} catch (error) {
|
|
105
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
106
|
-
process.exit(4);
|
|
107
|
-
}
|
|
90
|
+
const data = await readJsonFile(options.file);
|
|
91
|
+
const result = await createOneTimeProduct(client, packageName, data);
|
|
92
|
+
console.log(formatOutput(result, format));
|
|
108
93
|
});
|
|
109
94
|
otp.command("update <product-id>").description("Update a one-time product from JSON file").requiredOption("--file <path>", "JSON file with product data").option("--update-mask <fields>", "Comma-separated field mask").action(async (productId, options) => {
|
|
110
95
|
const config = await loadConfig();
|
|
@@ -124,20 +109,15 @@ function registerOneTimeProductsCommands(program) {
|
|
|
124
109
|
return;
|
|
125
110
|
}
|
|
126
111
|
const client = await getClient(config);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
console.log(formatOutput(result, format));
|
|
137
|
-
} catch (error) {
|
|
138
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
139
|
-
process.exit(4);
|
|
140
|
-
}
|
|
112
|
+
const data = await readJsonFile(options.file);
|
|
113
|
+
const result = await updateOneTimeProduct(
|
|
114
|
+
client,
|
|
115
|
+
packageName,
|
|
116
|
+
productId,
|
|
117
|
+
data,
|
|
118
|
+
options.updateMask
|
|
119
|
+
);
|
|
120
|
+
console.log(formatOutput(result, format));
|
|
141
121
|
});
|
|
142
122
|
otp.command("delete <product-id>").description("Delete a one-time product").action(async (productId) => {
|
|
143
123
|
const config = await loadConfig();
|
|
@@ -157,13 +137,8 @@ function registerOneTimeProductsCommands(program) {
|
|
|
157
137
|
return;
|
|
158
138
|
}
|
|
159
139
|
const client = await getClient(config);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
console.log(`One-time product ${productId} deleted.`);
|
|
163
|
-
} catch (error) {
|
|
164
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
165
|
-
process.exit(4);
|
|
166
|
-
}
|
|
140
|
+
await deleteOneTimeProduct(client, packageName, productId);
|
|
141
|
+
console.log(`One-time product ${productId} deleted.`);
|
|
167
142
|
});
|
|
168
143
|
const offers = otp.command("offers").description("Manage one-time product offers");
|
|
169
144
|
offers.command("list <product-id>").description("List offers for a one-time product").option("--sort <field>", "Sort by field (prefix with - for descending)").action(async (productId, options) => {
|
|
@@ -171,29 +146,19 @@ function registerOneTimeProductsCommands(program) {
|
|
|
171
146
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
172
147
|
const client = await getClient(config);
|
|
173
148
|
const format = getOutputFormat(program, config);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
result.oneTimeOffers = sortResults(result.oneTimeOffers, options.sort);
|
|
178
|
-
}
|
|
179
|
-
console.log(formatOutput(result, format));
|
|
180
|
-
} catch (error) {
|
|
181
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
182
|
-
process.exit(4);
|
|
149
|
+
const result = await listOneTimeOffers(client, packageName, productId);
|
|
150
|
+
if (options.sort) {
|
|
151
|
+
result.oneTimeOffers = sortResults(result.oneTimeOffers, options.sort);
|
|
183
152
|
}
|
|
153
|
+
console.log(formatOutput(result, format));
|
|
184
154
|
});
|
|
185
155
|
offers.command("get <product-id> <offer-id>").description("Get an offer for a one-time product").action(async (productId, offerId) => {
|
|
186
156
|
const config = await loadConfig();
|
|
187
157
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
188
158
|
const client = await getClient(config);
|
|
189
159
|
const format = getOutputFormat(program, config);
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
console.log(formatOutput(result, format));
|
|
193
|
-
} catch (error) {
|
|
194
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
195
|
-
process.exit(4);
|
|
196
|
-
}
|
|
160
|
+
const result = await getOneTimeOffer(client, packageName, productId, offerId);
|
|
161
|
+
console.log(formatOutput(result, format));
|
|
197
162
|
});
|
|
198
163
|
offers.command("create <product-id>").description("Create an offer from JSON file").requiredOption("--file <path>", "JSON file with offer data").action(async (productId, options) => {
|
|
199
164
|
const config = await loadConfig();
|
|
@@ -213,14 +178,9 @@ function registerOneTimeProductsCommands(program) {
|
|
|
213
178
|
return;
|
|
214
179
|
}
|
|
215
180
|
const client = await getClient(config);
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
console.log(formatOutput(result, format));
|
|
220
|
-
} catch (error) {
|
|
221
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
222
|
-
process.exit(4);
|
|
223
|
-
}
|
|
181
|
+
const data = await readJsonFile(options.file);
|
|
182
|
+
const result = await createOneTimeOffer(client, packageName, productId, data);
|
|
183
|
+
console.log(formatOutput(result, format));
|
|
224
184
|
});
|
|
225
185
|
offers.command("update <product-id> <offer-id>").description("Update an offer from JSON file").requiredOption("--file <path>", "JSON file with offer data").option("--update-mask <fields>", "Comma-separated field mask").action(
|
|
226
186
|
async (productId, offerId, options) => {
|
|
@@ -241,21 +201,16 @@ function registerOneTimeProductsCommands(program) {
|
|
|
241
201
|
return;
|
|
242
202
|
}
|
|
243
203
|
const client = await getClient(config);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
console.log(formatOutput(result, format));
|
|
255
|
-
} catch (error) {
|
|
256
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
257
|
-
process.exit(4);
|
|
258
|
-
}
|
|
204
|
+
const data = await readJsonFile(options.file);
|
|
205
|
+
const result = await updateOneTimeOffer(
|
|
206
|
+
client,
|
|
207
|
+
packageName,
|
|
208
|
+
productId,
|
|
209
|
+
offerId,
|
|
210
|
+
data,
|
|
211
|
+
options.updateMask
|
|
212
|
+
);
|
|
213
|
+
console.log(formatOutput(result, format));
|
|
259
214
|
}
|
|
260
215
|
);
|
|
261
216
|
offers.command("delete <product-id> <offer-id>").description("Delete an offer").action(async (productId, offerId) => {
|
|
@@ -276,34 +231,24 @@ function registerOneTimeProductsCommands(program) {
|
|
|
276
231
|
return;
|
|
277
232
|
}
|
|
278
233
|
const client = await getClient(config);
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
console.log(`Offer ${offerId} deleted.`);
|
|
282
|
-
} catch (error) {
|
|
283
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
284
|
-
process.exit(4);
|
|
285
|
-
}
|
|
234
|
+
await deleteOneTimeOffer(client, packageName, productId, offerId);
|
|
235
|
+
console.log(`Offer ${offerId} deleted.`);
|
|
286
236
|
});
|
|
287
237
|
otp.command("diff <product-id>").description("Compare local JSON file against remote one-time product").requiredOption("--file <path>", "Local JSON file to compare against remote").action(async (productId, options) => {
|
|
288
238
|
const config = await loadConfig();
|
|
289
239
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
290
240
|
const client = await getClient(config);
|
|
291
241
|
const format = getOutputFormat(program, config);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
console.log(formatOutput(diffs, format));
|
|
299
|
-
}
|
|
300
|
-
} catch (error) {
|
|
301
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
302
|
-
process.exit(4);
|
|
242
|
+
const localData = await readJsonFile(options.file);
|
|
243
|
+
const diffs = await diffOneTimeProduct(client, packageName, productId, localData);
|
|
244
|
+
if (diffs.length === 0) {
|
|
245
|
+
console.log("No differences found.");
|
|
246
|
+
} else {
|
|
247
|
+
console.log(formatOutput(diffs, format));
|
|
303
248
|
}
|
|
304
249
|
});
|
|
305
250
|
}
|
|
306
251
|
export {
|
|
307
252
|
registerOneTimeProductsCommands
|
|
308
253
|
};
|
|
309
|
-
//# sourceMappingURL=one-time-products-
|
|
254
|
+
//# sourceMappingURL=one-time-products-MGZTU7OM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/one-time-products.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport type { OneTimeProduct } from \"@gpc-cli/api\";\nimport {\n listOneTimeProducts,\n getOneTimeProduct,\n createOneTimeProduct,\n updateOneTimeProduct,\n deleteOneTimeProduct,\n listOneTimeOffers,\n getOneTimeOffer,\n createOneTimeOffer,\n updateOneTimeOffer,\n deleteOneTimeOffer,\n diffOneTimeProduct,\n formatOutput,\n sortResults,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { requireConfirm } from \"../prompt.js\";\nimport { readJsonFile } from \"../json.js\";\n\n\n\nexport function registerOneTimeProductsCommands(program: Command): void {\n const otp = program\n .command(\"one-time-products\")\n .alias(\"otp\")\n .description(\"Manage one-time products and offers (modern OTP API)\");\n\n otp\n .command(\"list\")\n .description(\"List one-time products\")\n .option(\"--sort <field>\", \"Sort by field (prefix with - for descending)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listOneTimeProducts(client, packageName);\n if (options.sort) {\n result.oneTimeProducts = sortResults(result.oneTimeProducts, options.sort);\n }\n const products = result.oneTimeProducts || [];\n if (format !== \"json\") {\n if (products.length === 0) {\n console.log(\"No one-time products found.\");\n return;\n }\n const summary = products.map((p: OneTimeProduct) => ({\n productId: p.productId,\n purchaseType: (p as unknown as Record<string, unknown>)[\"purchaseType\"] || \"-\",\n listings: p.listings ? Object.keys(p.listings).length : 0,\n firstTitle: p.listings ? Object.values(p.listings)[0]?.title || \"-\" : \"-\",\n }));\n console.log(formatOutput(summary, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n otp\n .command(\"get <product-id>\")\n .description(\"Get a one-time product\")\n .action(async (productId: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await getOneTimeProduct(client, packageName, productId);\n console.log(formatOutput(result, format));\n });\n\n otp\n .command(\"create\")\n .description(\"Create a one-time product from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with product data\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"one-time-products create\",\n action: \"create\",\n target: `one-time product from ${options.file}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const data = await readJsonFile(options.file);\n const result = await createOneTimeProduct(client, packageName, data as any);\n console.log(formatOutput(result, format));\n });\n\n otp\n .command(\"update <product-id>\")\n .description(\"Update a one-time product from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with product data\")\n .option(\"--update-mask <fields>\", \"Comma-separated field mask\")\n .action(async (productId: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"one-time-products update\",\n action: \"update\",\n target: productId,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const data = await readJsonFile(options.file);\n const result = await updateOneTimeProduct(\n client,\n packageName,\n productId,\n data as any,\n options.updateMask,\n );\n console.log(formatOutput(result, format));\n });\n\n otp\n .command(\"delete <product-id>\")\n .description(\"Delete a one-time product\")\n .action(async (productId: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Delete one-time product \"${productId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"one-time-products delete\",\n action: \"delete\",\n target: productId,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await deleteOneTimeProduct(client, packageName, productId);\n console.log(`One-time product ${productId} deleted.`);\n });\n\n // --- Offers ---\n const offers = otp.command(\"offers\").description(\"Manage one-time product offers\");\n\n offers\n .command(\"list <product-id>\")\n .description(\"List offers for a one-time product\")\n .option(\"--sort <field>\", \"Sort by field (prefix with - for descending)\")\n .action(async (productId: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listOneTimeOffers(client, packageName, productId);\n if (options.sort) {\n result.oneTimeOffers = sortResults(result.oneTimeOffers, options.sort);\n }\n console.log(formatOutput(result, format));\n });\n\n offers\n .command(\"get <product-id> <offer-id>\")\n .description(\"Get an offer for a one-time product\")\n .action(async (productId: string, offerId: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await getOneTimeOffer(client, packageName, productId, offerId);\n console.log(formatOutput(result, format));\n });\n\n offers\n .command(\"create <product-id>\")\n .description(\"Create an offer from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with offer data\")\n .action(async (productId: string, options: { file: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"one-time-products offers create\",\n action: \"create offer for\",\n target: productId,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const data = await readJsonFile(options.file);\n const result = await createOneTimeOffer(client, packageName, productId, data as any);\n console.log(formatOutput(result, format));\n });\n\n offers\n .command(\"update <product-id> <offer-id>\")\n .description(\"Update an offer from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with offer data\")\n .option(\"--update-mask <fields>\", \"Comma-separated field mask\")\n .action(\n async (\n productId: string,\n offerId: string,\n options: { file: string; updateMask?: string },\n ) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"one-time-products offers update\",\n action: \"update offer\",\n target: `${productId}/${offerId}`,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const data = await readJsonFile(options.file);\n const result = await updateOneTimeOffer(\n client,\n packageName,\n productId,\n offerId,\n data as any,\n options.updateMask,\n );\n console.log(formatOutput(result, format));\n },\n );\n\n offers\n .command(\"delete <product-id> <offer-id>\")\n .description(\"Delete an offer\")\n .action(async (productId: string, offerId: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Delete offer \"${offerId}\" for product \"${productId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"one-time-products offers delete\",\n action: \"delete offer\",\n target: `${productId}/${offerId}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await deleteOneTimeOffer(client, packageName, productId, offerId);\n console.log(`Offer ${offerId} deleted.`);\n });\n\n // --- Diff ---\n otp\n .command(\"diff <product-id>\")\n .description(\"Compare local JSON file against remote one-time product\")\n .requiredOption(\"--file <path>\", \"Local JSON file to compare against remote\")\n .action(async (productId: string, options: { file: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const localData = (await readJsonFile(options.file)) as OneTimeProduct;\n const diffs = await diffOneTimeProduct(client, packageName, productId, localData);\n if (diffs.length === 0) {\n console.log(\"No differences found.\");\n } else {\n console.log(formatOutput(diffs, format));\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "./chunk-ELXAK7GI.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/preflight.ts
|
|
14
|
-
import { runPreflight, getAllScannerNames, formatOutput } from "@gpc-cli/core";
|
|
14
|
+
import { runPreflight, getAllScannerNames, formatOutput, GpcError } from "@gpc-cli/core";
|
|
15
15
|
import { loadConfig } from "@gpc-cli/config";
|
|
16
16
|
var SEVERITY_ICONS = {
|
|
17
17
|
critical: "\u2717",
|
|
@@ -62,82 +62,85 @@ function registerPreflightCommand(program) {
|
|
|
62
62
|
}
|
|
63
63
|
async function runPreflightAction(program, file, options) {
|
|
64
64
|
if (!file && !options["metadata"] && !options["source"]) {
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
throw new GpcError(
|
|
66
|
+
"Provide an AAB file, --metadata <dir>, or --source <dir>",
|
|
67
|
+
"MISSING_INPUT",
|
|
68
|
+
2,
|
|
69
|
+
"gpc preflight app.aab"
|
|
70
|
+
);
|
|
67
71
|
}
|
|
68
72
|
const failOn = options["failOn"];
|
|
69
73
|
const validSeverities = /* @__PURE__ */ new Set(["critical", "error", "warning", "info"]);
|
|
70
74
|
if (failOn && !validSeverities.has(failOn)) {
|
|
71
|
-
|
|
72
|
-
`
|
|
75
|
+
throw new GpcError(
|
|
76
|
+
`Invalid --fail-on value "${failOn}". Use: critical, error, warning, info`,
|
|
77
|
+
"INVALID_OPTION",
|
|
78
|
+
2
|
|
73
79
|
);
|
|
74
|
-
process.exit(2);
|
|
75
80
|
}
|
|
76
81
|
const scannerNames = options["scanners"]?.split(",").map((s) => s.trim());
|
|
77
82
|
if (scannerNames) {
|
|
78
83
|
const known = new Set(getAllScannerNames());
|
|
79
84
|
const unknown = scannerNames.filter((s) => !known.has(s));
|
|
80
85
|
if (unknown.length > 0) {
|
|
81
|
-
|
|
82
|
-
`
|
|
86
|
+
throw new GpcError(
|
|
87
|
+
`Unknown scanner(s): ${unknown.join(", ")}. Available: ${getAllScannerNames().join(", ")}`,
|
|
88
|
+
"UNKNOWN_SCANNER",
|
|
89
|
+
2
|
|
83
90
|
);
|
|
84
|
-
process.exit(2);
|
|
85
91
|
}
|
|
86
92
|
}
|
|
87
93
|
const config = await loadConfig();
|
|
88
94
|
const format = getOutputFormat(program, config);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
const result = await runPreflight({
|
|
96
|
+
aabPath: file,
|
|
97
|
+
metadataDir: options["metadata"],
|
|
98
|
+
sourceDir: options["source"],
|
|
99
|
+
scanners: scannerNames,
|
|
100
|
+
failOn,
|
|
101
|
+
configPath: options["config"]
|
|
102
|
+
});
|
|
103
|
+
if (format === "json") {
|
|
104
|
+
console.log(formatOutput(result, format));
|
|
105
|
+
} else {
|
|
106
|
+
console.log(bold("GPC Preflight Scanner"));
|
|
107
|
+
if (file) console.log(dim(`File: ${file}`));
|
|
108
|
+
console.log(dim(`Scanners: ${result.scanners.join(", ")}`));
|
|
109
|
+
console.log("");
|
|
110
|
+
if (result.findings.length === 0) {
|
|
111
|
+
console.log(green("\u2713 No issues found"));
|
|
100
112
|
} else {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
finding.severity,
|
|
112
|
-
`${icon} ${finding.severity.toUpperCase()}`
|
|
113
|
-
);
|
|
114
|
-
console.log(`${label} ${finding.title}`);
|
|
115
|
-
console.log(` ${dim(finding.message)}`);
|
|
116
|
-
if (finding.suggestion) {
|
|
117
|
-
console.log(` ${dim("\u2192")} ${finding.suggestion}`);
|
|
118
|
-
}
|
|
119
|
-
if (finding.policyUrl) {
|
|
120
|
-
console.log(` ${dim(finding.policyUrl)}`);
|
|
121
|
-
}
|
|
122
|
-
console.log("");
|
|
113
|
+
for (const finding of result.findings) {
|
|
114
|
+
const icon = SEVERITY_ICONS[finding.severity];
|
|
115
|
+
const label = severityColor(
|
|
116
|
+
finding.severity,
|
|
117
|
+
`${icon} ${finding.severity.toUpperCase()}`
|
|
118
|
+
);
|
|
119
|
+
console.log(`${label} ${finding.title}`);
|
|
120
|
+
console.log(` ${dim(finding.message)}`);
|
|
121
|
+
if (finding.suggestion) {
|
|
122
|
+
console.log(` ${dim("\u2192")} ${finding.suggestion}`);
|
|
123
123
|
}
|
|
124
|
+
if (finding.policyUrl) {
|
|
125
|
+
console.log(` ${dim(finding.policyUrl)}`);
|
|
126
|
+
}
|
|
127
|
+
console.log("");
|
|
124
128
|
}
|
|
125
|
-
const parts = [];
|
|
126
|
-
if (result.summary.critical > 0) parts.push(bold(red(`${result.summary.critical} critical`)));
|
|
127
|
-
if (result.summary.error > 0) parts.push(red(`${result.summary.error} error`));
|
|
128
|
-
if (result.summary.warning > 0) parts.push(yellow(`${result.summary.warning} warning`));
|
|
129
|
-
if (result.summary.info > 0) parts.push(dim(`${result.summary.info} info`));
|
|
130
|
-
const summaryLine = parts.length > 0 ? parts.join(", ") : green("0 issues");
|
|
131
|
-
const passedLabel = result.passed ? green("\u2713 PASSED") : red("\u2717 FAILED");
|
|
132
|
-
console.log(`${passedLabel} ${summaryLine} ${dim(`(${result.durationMs}ms)`)}`);
|
|
133
129
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
const parts = [];
|
|
131
|
+
if (result.summary.critical > 0) parts.push(bold(red(`${result.summary.critical} critical`)));
|
|
132
|
+
if (result.summary.error > 0) parts.push(red(`${result.summary.error} error`));
|
|
133
|
+
if (result.summary.warning > 0) parts.push(yellow(`${result.summary.warning} warning`));
|
|
134
|
+
if (result.summary.info > 0) parts.push(dim(`${result.summary.info} info`));
|
|
135
|
+
const summaryLine = parts.length > 0 ? parts.join(", ") : green("0 issues");
|
|
136
|
+
const passedLabel = result.passed ? green("\u2713 PASSED") : red("\u2717 FAILED");
|
|
137
|
+
console.log(`${passedLabel} ${summaryLine} ${dim(`(${result.durationMs}ms)`)}`);
|
|
138
|
+
}
|
|
139
|
+
if (!result.passed) {
|
|
140
|
+
process.exitCode = 6;
|
|
138
141
|
}
|
|
139
142
|
}
|
|
140
143
|
export {
|
|
141
144
|
registerPreflightCommand
|
|
142
145
|
};
|
|
143
|
-
//# sourceMappingURL=preflight-
|
|
146
|
+
//# sourceMappingURL=preflight-N7ZRG2JI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/preflight.ts"],"sourcesContent":["// Named exports only. No default export.\n\nimport type { Command } from \"commander\";\nimport { runPreflight, getAllScannerNames, formatOutput, GpcError } from \"@gpc-cli/core\";\nimport type { FindingSeverity } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { green, red, yellow, dim, bold } from \"../colors.js\";\n\nconst SEVERITY_ICONS: Record<FindingSeverity, string> = {\n critical: \"✗\",\n error: \"✗\",\n warning: \"⚠\",\n info: \"ℹ\",\n};\n\nfunction severityColor(severity: FindingSeverity, text: string): string {\n switch (severity) {\n case \"critical\":\n return bold(red(text));\n case \"error\":\n return red(text);\n case \"warning\":\n return yellow(text);\n case \"info\":\n return dim(text);\n }\n}\n\nexport function registerPreflightCommand(program: Command): void {\n const cmd = program\n .command(\"preflight [file]\")\n .description(\"Pre-submission compliance scanner for AAB files (offline)\")\n .option(\n \"--fail-on <severity>\",\n \"Fail if any finding meets or exceeds severity: critical, error, warning, info\",\n \"error\",\n )\n .option(\"--scanners <names>\", \"Comma-separated scanner names to run (default: all)\")\n .option(\"--metadata <dir>\", \"Path to metadata directory (Fastlane format) for listing checks\")\n .option(\"--source <dir>\", \"Path to source directory for code scanning\")\n .option(\"--config <path>\", \"Path to .preflightrc.json config file\")\n .action(async (file: string | undefined, options) => {\n await runPreflightAction(program, file, options);\n });\n\n // Subcommand: preflight manifest\n cmd\n .command(\"manifest <file>\")\n .description(\"Run manifest scanner only\")\n .option(\"--fail-on <severity>\", \"Fail threshold\", \"error\")\n .action(async (file: string, options) => {\n await runPreflightAction(program, file, { ...options, scanners: \"manifest\" });\n });\n\n // Subcommand: preflight permissions\n cmd\n .command(\"permissions <file>\")\n .description(\"Run permissions scanner only\")\n .option(\"--fail-on <severity>\", \"Fail threshold\", \"error\")\n .action(async (file: string, options) => {\n await runPreflightAction(program, file, { ...options, scanners: \"permissions\" });\n });\n\n // Subcommand: preflight metadata\n cmd\n .command(\"metadata <dir>\")\n .description(\"Run metadata scanner on a listings directory\")\n .option(\"--fail-on <severity>\", \"Fail threshold\", \"error\")\n .action(async (dir: string, options) => {\n await runPreflightAction(program, undefined, {\n ...options,\n metadata: dir,\n scanners: \"metadata\",\n });\n });\n\n // Subcommand: preflight codescan\n cmd\n .command(\"codescan <dir>\")\n .description(\"Run code scanners (secrets, billing, privacy) on source directory\")\n .option(\"--fail-on <severity>\", \"Fail threshold\", \"error\")\n .action(async (dir: string, options) => {\n await runPreflightAction(program, undefined, {\n ...options,\n source: dir,\n scanners: \"secrets,billing,privacy\",\n });\n });\n}\n\nasync function runPreflightAction(\n program: Command,\n file: string | undefined,\n options: Record<string, string | undefined>,\n): Promise<void> {\n if (!file && !options[\"metadata\"] && !options[\"source\"]) {\n throw new GpcError(\n \"Provide an AAB file, --metadata <dir>, or --source <dir>\",\n \"MISSING_INPUT\",\n 2,\n \"gpc preflight app.aab\",\n );\n }\n\n const failOn = options[\"failOn\"] as FindingSeverity | undefined;\n const validSeverities = new Set([\"critical\", \"error\", \"warning\", \"info\"]);\n if (failOn && !validSeverities.has(failOn)) {\n throw new GpcError(\n `Invalid --fail-on value \"${failOn}\". Use: critical, error, warning, info`,\n \"INVALID_OPTION\",\n 2,\n );\n }\n\n const scannerNames = options[\"scanners\"]?.split(\",\").map((s) => s.trim());\n if (scannerNames) {\n const known = new Set(getAllScannerNames());\n const unknown = scannerNames.filter((s) => !known.has(s));\n if (unknown.length > 0) {\n throw new GpcError(\n `Unknown scanner(s): ${unknown.join(\", \")}. Available: ${getAllScannerNames().join(\", \")}`,\n \"UNKNOWN_SCANNER\",\n 2,\n );\n }\n }\n\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n\n const result = await runPreflight({\n aabPath: file,\n metadataDir: options[\"metadata\"],\n sourceDir: options[\"source\"],\n scanners: scannerNames,\n failOn,\n configPath: options[\"config\"],\n });\n\n if (format === \"json\") {\n console.log(formatOutput(result, format));\n } else {\n // Header\n console.log(bold(\"GPC Preflight Scanner\"));\n if (file) console.log(dim(`File: ${file}`));\n console.log(dim(`Scanners: ${result.scanners.join(\", \")}`));\n console.log(\"\");\n\n if (result.findings.length === 0) {\n console.log(green(\"✓ No issues found\"));\n } else {\n // Group by severity\n for (const finding of result.findings) {\n const icon = SEVERITY_ICONS[finding.severity];\n const label = severityColor(\n finding.severity,\n `${icon} ${finding.severity.toUpperCase()}`,\n );\n console.log(`${label} ${finding.title}`);\n console.log(` ${dim(finding.message)}`);\n if (finding.suggestion) {\n console.log(` ${dim(\"→\")} ${finding.suggestion}`);\n }\n if (finding.policyUrl) {\n console.log(` ${dim(finding.policyUrl)}`);\n }\n console.log(\"\");\n }\n }\n\n // Summary line\n const parts: string[] = [];\n if (result.summary.critical > 0) parts.push(bold(red(`${result.summary.critical} critical`)));\n if (result.summary.error > 0) parts.push(red(`${result.summary.error} error`));\n if (result.summary.warning > 0) parts.push(yellow(`${result.summary.warning} warning`));\n if (result.summary.info > 0) parts.push(dim(`${result.summary.info} info`));\n\n const summaryLine = parts.length > 0 ? parts.join(\", \") : green(\"0 issues\");\n const passedLabel = result.passed ? green(\"✓ PASSED\") : red(\"✗ FAILED\");\n console.log(`${passedLabel} ${summaryLine} ${dim(`(${result.durationMs}ms)`)}`);\n }\n\n if (!result.passed) {\n process.exitCode = 6;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getClient,
|
|
4
4
|
resolvePackageName
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-NQH4G7BI.js";
|
|
6
6
|
import {
|
|
7
7
|
getOutputFormat
|
|
8
8
|
} from "./chunk-ELXAK7GI.js";
|
|
@@ -15,7 +15,7 @@ function registerPricingCommands(program) {
|
|
|
15
15
|
pricing.command("convert").description("Convert a price to all regional prices").option("--from <currency>", "Source currency code (e.g. USD)").option("--amount <number>", "Price amount (e.g. 4.99)").action(async (options) => {
|
|
16
16
|
const config = await loadConfig();
|
|
17
17
|
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
18
|
-
const { isInteractive, requireOption } = await import("./prompt-
|
|
18
|
+
const { isInteractive, requireOption } = await import("./prompt-GXC2JSLA.js");
|
|
19
19
|
const interactive = isInteractive(program);
|
|
20
20
|
options.from = await requireOption(
|
|
21
21
|
"from",
|
|
@@ -61,17 +61,17 @@ function registerPricingCommands(program) {
|
|
|
61
61
|
} catch (error) {
|
|
62
62
|
const { PlayApiError } = await import("@gpc-cli/api");
|
|
63
63
|
if (error instanceof PlayApiError && (error.code === "API_HTTP_400" || error.code === "API_EDIT_EXPIRED")) {
|
|
64
|
-
|
|
65
|
-
"
|
|
64
|
+
const err = new Error(
|
|
65
|
+
"Price conversion is not available for this app. Ensure the app has monetization configured in Google Play Console (at least one paid product or subscription)."
|
|
66
66
|
);
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
Object.assign(err, { code: "API_PRICING_UNAVAILABLE", exitCode: 4 });
|
|
68
|
+
throw err;
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
throw error;
|
|
71
71
|
}
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
export {
|
|
75
75
|
registerPricingCommands
|
|
76
76
|
};
|
|
77
|
-
//# sourceMappingURL=pricing-
|
|
77
|
+
//# sourceMappingURL=pricing-JJZFICFL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/pricing.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport { convertRegionPrices, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\n\n\nexport function registerPricingCommands(program: Command): void {\n const pricing = program.command(\"pricing\").description(\"Pricing and regional price conversion\");\n\n pricing\n .command(\"convert\")\n .description(\"Convert a price to all regional prices\")\n .option(\"--from <currency>\", \"Source currency code (e.g. USD)\")\n .option(\"--amount <number>\", \"Price amount (e.g. 4.99)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const { isInteractive, requireOption } = await import(\"../prompt.js\");\n const interactive = isInteractive(program);\n\n options.from = await requireOption(\n \"from\",\n options.from,\n {\n message: \"Source currency code (e.g. USD):\",\n default: \"USD\",\n },\n interactive,\n );\n\n options.amount = await requireOption(\n \"amount\",\n options.amount,\n {\n message: \"Price amount (e.g. 4.99):\",\n },\n interactive,\n );\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await convertRegionPrices(client, packageName, options.from, options.amount);\n if (format !== \"json\") {\n const prices = (result as unknown as Record<string, unknown>)[\"convertedRegionPrices\"] as\n | Record<string, Record<string, unknown>>\n | undefined;\n if (prices) {\n const rows = Object.entries(prices).map(([region, data]) => {\n const money = data[\"price\"] as Record<string, unknown> | undefined;\n const units = money?.[\"units\"] || \"0\";\n const nanos = String(money?.[\"nanos\"] || 0)\n .padStart(9, \"0\")\n .slice(0, 2);\n return {\n region,\n price: money\n ? `${units}.${nanos}`\n : data[\"priceMicros\"]\n ? String(Number(data[\"priceMicros\"]) / 1_000_000)\n : \"-\",\n currencyCode: (money?.[\"currencyCode\"] || data[\"currencyCode\"] || \"-\") as string,\n };\n });\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(result, format));\n }\n } else {\n console.log(formatOutput(result, format));\n }\n } catch (error) {\n const { PlayApiError } = await import(\"@gpc-cli/api\");\n if (\n error instanceof PlayApiError &&\n (error.code === \"API_HTTP_400\" || error.code === \"API_EDIT_EXPIRED\")\n ) {\n
|
|
1
|
+
{"version":3,"sources":["../src/commands/pricing.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport { convertRegionPrices, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\n\n\nexport function registerPricingCommands(program: Command): void {\n const pricing = program.command(\"pricing\").description(\"Pricing and regional price conversion\");\n\n pricing\n .command(\"convert\")\n .description(\"Convert a price to all regional prices\")\n .option(\"--from <currency>\", \"Source currency code (e.g. USD)\")\n .option(\"--amount <number>\", \"Price amount (e.g. 4.99)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const { isInteractive, requireOption } = await import(\"../prompt.js\");\n const interactive = isInteractive(program);\n\n options.from = await requireOption(\n \"from\",\n options.from,\n {\n message: \"Source currency code (e.g. USD):\",\n default: \"USD\",\n },\n interactive,\n );\n\n options.amount = await requireOption(\n \"amount\",\n options.amount,\n {\n message: \"Price amount (e.g. 4.99):\",\n },\n interactive,\n );\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await convertRegionPrices(client, packageName, options.from, options.amount);\n if (format !== \"json\") {\n const prices = (result as unknown as Record<string, unknown>)[\"convertedRegionPrices\"] as\n | Record<string, Record<string, unknown>>\n | undefined;\n if (prices) {\n const rows = Object.entries(prices).map(([region, data]) => {\n const money = data[\"price\"] as Record<string, unknown> | undefined;\n const units = money?.[\"units\"] || \"0\";\n const nanos = String(money?.[\"nanos\"] || 0)\n .padStart(9, \"0\")\n .slice(0, 2);\n return {\n region,\n price: money\n ? `${units}.${nanos}`\n : data[\"priceMicros\"]\n ? String(Number(data[\"priceMicros\"]) / 1_000_000)\n : \"-\",\n currencyCode: (money?.[\"currencyCode\"] || data[\"currencyCode\"] || \"-\") as string,\n };\n });\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(result, format));\n }\n } else {\n console.log(formatOutput(result, format));\n }\n } catch (error) {\n const { PlayApiError } = await import(\"@gpc-cli/api\");\n if (\n error instanceof PlayApiError &&\n (error.code === \"API_HTTP_400\" || error.code === \"API_EDIT_EXPIRED\")\n ) {\n const err = new Error(\n \"Price conversion is not available for this app. \" +\n \"Ensure the app has monetization configured in Google Play Console (at least one paid product or subscription).\",\n );\n Object.assign(err, { code: \"API_PRICING_UNAVAILABLE\", exitCode: 4 });\n throw err;\n }\n throw error;\n }\n });\n}\n"],"mappings":";;;;;;;;;;AAEA,SAAS,kBAAkB;AAE3B,SAAS,qBAAqB,oBAAoB;AAK3C,SAAS,wBAAwB,SAAwB;AAC9D,QAAM,UAAU,QAAQ,QAAQ,SAAS,EAAE,YAAY,uCAAuC;AAE9F,UACG,QAAQ,SAAS,EACjB,YAAY,wCAAwC,EACpD,OAAO,qBAAqB,iCAAiC,EAC7D,OAAO,qBAAqB,0BAA0B,EACtD,OAAO,OAAO,YAAY;AACzB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,EAAE,eAAe,cAAc,IAAI,MAAM,OAAO,sBAAc;AACpE,UAAM,cAAc,cAAc,OAAO;AAEzC,YAAQ,OAAO,MAAM;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAEA,YAAQ,SAAS,MAAM;AAAA,MACrB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,QACE,SAAS;AAAA,MACX;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI;AACF,YAAM,SAAS,MAAM,oBAAoB,QAAQ,aAAa,QAAQ,MAAM,QAAQ,MAAM;AAC1F,UAAI,WAAW,QAAQ;AACrB,cAAM,SAAU,OAA8C,uBAAuB;AAGrF,YAAI,QAAQ;AACV,gBAAM,OAAO,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,IAAI,MAAM;AAC1D,kBAAM,QAAQ,KAAK,OAAO;AAC1B,kBAAM,QAAQ,QAAQ,OAAO,KAAK;AAClC,kBAAM,QAAQ,OAAO,QAAQ,OAAO,KAAK,CAAC,EACvC,SAAS,GAAG,GAAG,EACf,MAAM,GAAG,CAAC;AACb,mBAAO;AAAA,cACL;AAAA,cACA,OAAO,QACH,GAAG,KAAK,IAAI,KAAK,KACjB,KAAK,aAAa,IAChB,OAAO,OAAO,KAAK,aAAa,CAAC,IAAI,GAAS,IAC9C;AAAA,cACN,cAAe,QAAQ,cAAc,KAAK,KAAK,cAAc,KAAK;AAAA,YACpE;AAAA,UACF,CAAC;AACD,kBAAQ,IAAI,aAAa,MAAM,MAAM,CAAC;AAAA,QACxC,OAAO;AACL,kBAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,QAC1C;AAAA,MACF,OAAO;AACL,gBAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,MAC1C;AAAA,IACF,SAAS,OAAO;AACd,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,cAAc;AACpD,UACE,iBAAiB,iBAChB,MAAM,SAAS,kBAAkB,MAAM,SAAS,qBACjD;AACA,cAAM,MAAM,IAAI;AAAA,UACd;AAAA,QAEF;AACA,eAAO,OAAO,KAAK,EAAE,MAAM,2BAA2B,UAAU,EAAE,CAAC;AACnE,cAAM;AAAA,MACR;AACA,YAAM;AAAA,IACR;AAAA,EACF,CAAC;AACL;","names":[]}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
requireConfirm,
|
|
8
8
|
requireOption,
|
|
9
9
|
skipConfirm
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-YFUBD2XB.js";
|
|
11
11
|
export {
|
|
12
12
|
isInteractive,
|
|
13
13
|
promptConfirm,
|
|
@@ -17,4 +17,4 @@ export {
|
|
|
17
17
|
requireOption,
|
|
18
18
|
skipConfirm
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=prompt-
|
|
20
|
+
//# sourceMappingURL=prompt-GXC2JSLA.js.map
|