@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
package/dist/reviews-2CWOI5CV.js
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
getClient,
|
|
4
|
-
resolvePackageName
|
|
5
|
-
} from "./chunk-AA577WVQ.js";
|
|
6
|
-
import {
|
|
7
|
-
isDryRun,
|
|
8
|
-
printDryRun
|
|
9
|
-
} from "./chunk-Y3QZDAKS.js";
|
|
10
|
-
import {
|
|
11
|
-
getOutputFormat
|
|
12
|
-
} from "./chunk-ELXAK7GI.js";
|
|
13
|
-
import {
|
|
14
|
-
isInteractive,
|
|
15
|
-
requireOption
|
|
16
|
-
} from "./chunk-NV75I5VP.js";
|
|
17
|
-
|
|
18
|
-
// src/commands/reviews.ts
|
|
19
|
-
import { loadConfig } from "@gpc-cli/config";
|
|
20
|
-
import {
|
|
21
|
-
listReviews,
|
|
22
|
-
getReview,
|
|
23
|
-
replyToReview,
|
|
24
|
-
exportReviews,
|
|
25
|
-
analyzeReviews,
|
|
26
|
-
formatOutput,
|
|
27
|
-
maybePaginate,
|
|
28
|
-
sortResults
|
|
29
|
-
} from "@gpc-cli/core";
|
|
30
|
-
function registerReviewsCommands(program) {
|
|
31
|
-
const reviews = program.command("reviews").description("Manage user reviews and ratings");
|
|
32
|
-
reviews.command("list").description("List user reviews").option("--stars <n>", "Filter by star rating (1-5)", parseInt).option("--lang <code>", "Filter by reviewer language").option("--since <date>", "Filter reviews after date (ISO 8601)").option("--translate-to <lang>", "Translate reviews to language").option("--max <n>", "Maximum number of reviews per page", parseInt).option("--limit <n>", "Maximum total results", parseInt).option("--next-page <token>", "Resume from page token").option("--sort <field>", "Sort by field (prefix with - for descending)").action(async (options) => {
|
|
33
|
-
const config = await loadConfig();
|
|
34
|
-
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
35
|
-
const client = await getClient(config);
|
|
36
|
-
const format = getOutputFormat(program, config);
|
|
37
|
-
try {
|
|
38
|
-
const result = await listReviews(client, packageName, {
|
|
39
|
-
stars: options.stars,
|
|
40
|
-
language: options.lang,
|
|
41
|
-
since: options.since,
|
|
42
|
-
translationLanguage: options.translateTo,
|
|
43
|
-
maxResults: options.max,
|
|
44
|
-
limit: options.limit,
|
|
45
|
-
nextPage: options.nextPage
|
|
46
|
-
});
|
|
47
|
-
if (Array.isArray(result) && result.length === 0 && format !== "json") {
|
|
48
|
-
console.log("No reviews found.");
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const sorted = sortResults(result, options.sort);
|
|
52
|
-
if (format !== "json" && Array.isArray(sorted)) {
|
|
53
|
-
const rows = sorted.map((r) => {
|
|
54
|
-
const rv = r;
|
|
55
|
-
const comments = rv["comments"];
|
|
56
|
-
const userComment = comments?.[0]?.["userComment"];
|
|
57
|
-
return {
|
|
58
|
-
reviewId: rv["reviewId"] || "-",
|
|
59
|
-
author: rv["authorName"] || "-",
|
|
60
|
-
stars: userComment?.["starRating"] || "-",
|
|
61
|
-
text: String(userComment?.["text"] || "-").slice(0, 80),
|
|
62
|
-
lastModified: userComment?.["lastModified"] ? String(
|
|
63
|
-
userComment["lastModified"]?.["seconds"] || "-"
|
|
64
|
-
) : "-",
|
|
65
|
-
thumbsUp: userComment?.["thumbsUpCount"] || 0
|
|
66
|
-
};
|
|
67
|
-
});
|
|
68
|
-
await maybePaginate(formatOutput(rows, format));
|
|
69
|
-
} else {
|
|
70
|
-
await maybePaginate(formatOutput(sorted, format));
|
|
71
|
-
}
|
|
72
|
-
} catch (error) {
|
|
73
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
74
|
-
process.exit(4);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
reviews.command("get <review-id>").description("Get a single review").option("--translate-to <lang>", "Translate review to language").action(async (reviewId, options) => {
|
|
78
|
-
const config = await loadConfig();
|
|
79
|
-
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
80
|
-
const client = await getClient(config);
|
|
81
|
-
const format = getOutputFormat(program, config);
|
|
82
|
-
try {
|
|
83
|
-
const result = await getReview(client, packageName, reviewId, options.translateTo);
|
|
84
|
-
console.log(formatOutput(result, format));
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
87
|
-
process.exit(4);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
reviews.command("reply <review-id>").description("Reply to a review").option("--text <text>", "Reply text (max 350 chars)").action(async (reviewId, options) => {
|
|
91
|
-
const config = await loadConfig();
|
|
92
|
-
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
93
|
-
const format = getOutputFormat(program, config);
|
|
94
|
-
const interactive = isInteractive(program);
|
|
95
|
-
options.text = await requireOption(
|
|
96
|
-
"text",
|
|
97
|
-
options.text,
|
|
98
|
-
{
|
|
99
|
-
message: "Reply text (max 350 chars):"
|
|
100
|
-
},
|
|
101
|
-
interactive
|
|
102
|
-
);
|
|
103
|
-
if (isDryRun(program)) {
|
|
104
|
-
printDryRun(
|
|
105
|
-
{
|
|
106
|
-
command: "reviews reply",
|
|
107
|
-
action: "reply to",
|
|
108
|
-
target: reviewId,
|
|
109
|
-
details: { text: options.text }
|
|
110
|
-
},
|
|
111
|
-
format,
|
|
112
|
-
formatOutput
|
|
113
|
-
);
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
const client = await getClient(config);
|
|
117
|
-
try {
|
|
118
|
-
const result = await replyToReview(client, packageName, reviewId, options.text);
|
|
119
|
-
if (format !== "json") {
|
|
120
|
-
const charCount = options.text.length;
|
|
121
|
-
console.log(`Reply sent (${charCount}/350 chars)`);
|
|
122
|
-
}
|
|
123
|
-
console.log(formatOutput(result, format));
|
|
124
|
-
} catch (error) {
|
|
125
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
126
|
-
process.exit(4);
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
reviews.command("analyze").description("Analyze reviews: sentiment, topics, keywords, rating distribution").option("--stars <n>", "Filter by star rating (1-5)", parseInt).option("--lang <code>", "Filter by reviewer language").option("--since <date>", "Filter reviews after date (ISO 8601)").option("--max <n>", "Maximum number of reviews to analyze", parseInt).action(async (options) => {
|
|
130
|
-
const config = await loadConfig();
|
|
131
|
-
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
132
|
-
const client = await getClient(config);
|
|
133
|
-
const format = getOutputFormat(program, config);
|
|
134
|
-
try {
|
|
135
|
-
const result = await analyzeReviews(client, packageName, {
|
|
136
|
-
stars: options.stars,
|
|
137
|
-
language: options.lang,
|
|
138
|
-
since: options.since,
|
|
139
|
-
maxResults: options.max
|
|
140
|
-
});
|
|
141
|
-
if (format === "json") {
|
|
142
|
-
console.log(formatOutput(result, format));
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
console.log(`
|
|
146
|
-
Review Analysis \u2014 ${packageName}`);
|
|
147
|
-
console.log(`${"\u2500".repeat(50)}`);
|
|
148
|
-
console.log(`Total reviews: ${result.totalReviews}`);
|
|
149
|
-
console.log(
|
|
150
|
-
`Average rating: ${result.avgRating > 0 ? result.avgRating.toFixed(2) + " \u2605" : "N/A"}`
|
|
151
|
-
);
|
|
152
|
-
console.log(`
|
|
153
|
-
Sentiment:`);
|
|
154
|
-
console.log(
|
|
155
|
-
` Positive: ${result.sentiment.positive} Negative: ${result.sentiment.negative} Neutral: ${result.sentiment.neutral}`
|
|
156
|
-
);
|
|
157
|
-
console.log(` Avg score: ${result.sentiment.avgScore} (range -1 to +1)`);
|
|
158
|
-
if (result.topics.length > 0) {
|
|
159
|
-
console.log(`
|
|
160
|
-
Top topics:`);
|
|
161
|
-
for (const t of result.topics.slice(0, 8)) {
|
|
162
|
-
const bar = t.avgScore > 0.1 ? "+" : t.avgScore < -0.1 ? "-" : "~";
|
|
163
|
-
console.log(` [${bar}] ${t.topic.padEnd(20)} ${t.count} reviews`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
if (result.keywords.length > 0) {
|
|
167
|
-
console.log(
|
|
168
|
-
`
|
|
169
|
-
Top keywords: ${result.keywords.slice(0, 10).map((k) => k.word).join(", ")}`
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
if (Object.keys(result.ratingDistribution).length > 0) {
|
|
173
|
-
console.log(`
|
|
174
|
-
Rating distribution:`);
|
|
175
|
-
for (let star = 5; star >= 1; star--) {
|
|
176
|
-
const count = result.ratingDistribution[star] ?? 0;
|
|
177
|
-
if (count > 0) console.log(` ${star}\u2605 ${count}`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
} catch (error) {
|
|
181
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
182
|
-
process.exit(4);
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
reviews.command("export").description("Export reviews to JSON or CSV").option("--format <type>", "Output format: json or csv", "json").option("--stars <n>", "Filter by star rating (1-5)", parseInt).option("--lang <code>", "Filter by reviewer language").option("--since <date>", "Filter reviews after date (ISO 8601)").option("--translate-to <lang>", "Translate reviews to language").option("--output <file>", "Write output to file instead of stdout").action(async (options) => {
|
|
186
|
-
const config = await loadConfig();
|
|
187
|
-
const packageName = resolvePackageName(program.opts()["app"], config);
|
|
188
|
-
const client = await getClient(config);
|
|
189
|
-
try {
|
|
190
|
-
const result = await exportReviews(client, packageName, {
|
|
191
|
-
format: options.format,
|
|
192
|
-
stars: options.stars,
|
|
193
|
-
language: options.lang,
|
|
194
|
-
since: options.since,
|
|
195
|
-
translationLanguage: options.translateTo
|
|
196
|
-
});
|
|
197
|
-
if (options.output) {
|
|
198
|
-
const { writeFile } = await import("fs/promises");
|
|
199
|
-
await writeFile(options.output, result, "utf-8");
|
|
200
|
-
console.log(`Reviews exported to ${options.output}`);
|
|
201
|
-
} else {
|
|
202
|
-
console.log(result);
|
|
203
|
-
}
|
|
204
|
-
} catch (error) {
|
|
205
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
206
|
-
process.exit(4);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
export {
|
|
211
|
-
registerReviewsCommands
|
|
212
|
-
};
|
|
213
|
-
//# sourceMappingURL=reviews-2CWOI5CV.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/reviews.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport {\n listReviews,\n getReview,\n replyToReview,\n exportReviews,\n analyzeReviews,\n formatOutput,\n maybePaginate,\n sortResults,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { isInteractive, requireOption } from \"../prompt.js\";\n\n\n\nexport function registerReviewsCommands(program: Command): void {\n const reviews = program.command(\"reviews\").description(\"Manage user reviews and ratings\");\n\n reviews\n .command(\"list\")\n .description(\"List user reviews\")\n .option(\"--stars <n>\", \"Filter by star rating (1-5)\", parseInt)\n .option(\"--lang <code>\", \"Filter by reviewer language\")\n .option(\"--since <date>\", \"Filter reviews after date (ISO 8601)\")\n .option(\"--translate-to <lang>\", \"Translate reviews to language\")\n .option(\"--max <n>\", \"Maximum number of reviews per page\", parseInt)\n .option(\"--limit <n>\", \"Maximum total results\", parseInt)\n .option(\"--next-page <token>\", \"Resume from page token\")\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 try {\n const result = await listReviews(client, packageName, {\n stars: options.stars,\n language: options.lang,\n since: options.since,\n translationLanguage: options.translateTo,\n maxResults: options.max,\n limit: options.limit,\n nextPage: options.nextPage,\n });\n if (Array.isArray(result) && result.length === 0 && format !== \"json\") {\n console.log(\"No reviews found.\");\n return;\n }\n const sorted = sortResults(result, options.sort);\n if (format !== \"json\" && Array.isArray(sorted)) {\n const rows = sorted.map((r: unknown) => {\n const rv = r as Record<string, unknown>;\n const comments = rv[\"comments\"] as Record<string, unknown>[] | undefined;\n const userComment = comments?.[0]?.[\"userComment\"] as\n | Record<string, unknown>\n | undefined;\n return {\n reviewId: rv[\"reviewId\"] || \"-\",\n author: rv[\"authorName\"] || \"-\",\n stars: userComment?.[\"starRating\"] || \"-\",\n text: String(userComment?.[\"text\"] || \"-\").slice(0, 80),\n lastModified: userComment?.[\"lastModified\"]\n ? String(\n (userComment[\"lastModified\"] as Record<string, unknown>)?.[\"seconds\"] || \"-\",\n )\n : \"-\",\n thumbsUp: userComment?.[\"thumbsUpCount\"] || 0,\n };\n });\n await maybePaginate(formatOutput(rows, format));\n } else {\n await maybePaginate(formatOutput(sorted, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n reviews\n .command(\"get <review-id>\")\n .description(\"Get a single review\")\n .option(\"--translate-to <lang>\", \"Translate review to language\")\n .action(async (reviewId: 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 try {\n const result = await getReview(client, packageName, reviewId, options.translateTo);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n reviews\n .command(\"reply <review-id>\")\n .description(\"Reply to a review\")\n .option(\"--text <text>\", \"Reply text (max 350 chars)\")\n .action(async (reviewId: string, options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\n options.text = await requireOption(\n \"text\",\n options.text,\n {\n message: \"Reply text (max 350 chars):\",\n },\n interactive,\n );\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"reviews reply\",\n action: \"reply to\",\n target: reviewId,\n details: { text: options.text },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await replyToReview(client, packageName, reviewId, options.text);\n if (format !== \"json\") {\n const charCount = options.text.length;\n console.log(`Reply sent (${charCount}/350 chars)`);\n }\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n reviews\n .command(\"analyze\")\n .description(\"Analyze reviews: sentiment, topics, keywords, rating distribution\")\n .option(\"--stars <n>\", \"Filter by star rating (1-5)\", parseInt)\n .option(\"--lang <code>\", \"Filter by reviewer language\")\n .option(\"--since <date>\", \"Filter reviews after date (ISO 8601)\")\n .option(\"--max <n>\", \"Maximum number of reviews to analyze\", parseInt)\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 try {\n const result = await analyzeReviews(client, packageName, {\n stars: options.stars,\n language: options.lang,\n since: options.since,\n maxResults: options.max,\n });\n\n if (format === \"json\") {\n console.log(formatOutput(result, format));\n return;\n }\n\n console.log(`\\nReview Analysis — ${packageName}`);\n console.log(`${\"─\".repeat(50)}`);\n console.log(`Total reviews: ${result.totalReviews}`);\n console.log(\n `Average rating: ${result.avgRating > 0 ? result.avgRating.toFixed(2) + \" ★\" : \"N/A\"}`,\n );\n console.log(`\\nSentiment:`);\n console.log(\n ` Positive: ${result.sentiment.positive} Negative: ${result.sentiment.negative} Neutral: ${result.sentiment.neutral}`,\n );\n console.log(` Avg score: ${result.sentiment.avgScore} (range -1 to +1)`);\n\n if (result.topics.length > 0) {\n console.log(`\\nTop topics:`);\n for (const t of result.topics.slice(0, 8)) {\n const bar = t.avgScore > 0.1 ? \"+\" : t.avgScore < -0.1 ? \"-\" : \"~\";\n console.log(` [${bar}] ${t.topic.padEnd(20)} ${t.count} reviews`);\n }\n }\n\n if (result.keywords.length > 0) {\n console.log(\n `\\nTop keywords: ${result.keywords\n .slice(0, 10)\n .map((k) => k.word)\n .join(\", \")}`,\n );\n }\n\n if (Object.keys(result.ratingDistribution).length > 0) {\n console.log(`\\nRating distribution:`);\n for (let star = 5; star >= 1; star--) {\n const count = result.ratingDistribution[star] ?? 0;\n if (count > 0) console.log(` ${star}★ ${count}`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n reviews\n .command(\"export\")\n .description(\"Export reviews to JSON or CSV\")\n .option(\"--format <type>\", \"Output format: json or csv\", \"json\")\n .option(\"--stars <n>\", \"Filter by star rating (1-5)\", parseInt)\n .option(\"--lang <code>\", \"Filter by reviewer language\")\n .option(\"--since <date>\", \"Filter reviews after date (ISO 8601)\")\n .option(\"--translate-to <lang>\", \"Translate reviews to language\")\n .option(\"--output <file>\", \"Write output to file instead of stdout\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n\n try {\n const result = await exportReviews(client, packageName, {\n format: options.format as \"json\" | \"csv\",\n stars: options.stars,\n language: options.lang,\n since: options.since,\n translationLanguage: options.translateTo,\n });\n\n if (options.output) {\n const { writeFile } = await import(\"node:fs/promises\");\n await writeFile(options.output, result, \"utf-8\");\n console.log(`Reviews exported to ${options.output}`);\n } else {\n console.log(result);\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/status.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient, createReportingClient } from \"@gpc-cli/api\";\nimport {\n getAppStatus,\n formatStatusTable,\n formatStatusSummary,\n formatStatusDiff,\n computeStatusDiff,\n loadStatusCache,\n saveStatusCache,\n statusHasBreach,\n runWatchLoop,\n trackBreachState,\n sendNotification,\n formatOutput,\n createSpinner,\n} from \"@gpc-cli/core\";\nimport type { AppStatus } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { green, red, dim, gray } from \"../colors.js\";\n\nconst VALID_SECTIONS = new Set([\"releases\", \"vitals\", \"reviews\"]);\nconst VALID_FORMATS = new Set([\"table\", \"summary\"]);\n\nfunction parseSections(raw: string): string[] {\n const sections = raw.split(\",\").map((s) => s.trim().toLowerCase());\n for (const s of sections) {\n if (!VALID_SECTIONS.has(s)) {\n console.error(`Error: Unknown section \"${s}\". Valid sections: releases, vitals, reviews`);\n process.exit(2);\n }\n }\n return sections;\n}\n\nfunction resolveVitalThresholds(config: Record<string, unknown>) {\n const vitals = config[\"vitals\"] as Record<string, unknown> | undefined;\n const t = vitals?.[\"thresholds\"] as Record<string, unknown> | undefined;\n if (!t) return undefined;\n const toN = (v: unknown): number | undefined => {\n if (v === undefined || v === null) return undefined;\n const n = Number(v);\n return isNaN(n) ? undefined : n;\n };\n return {\n crashRate: toN(t[\"crashRate\"]),\n anrRate: toN(t[\"anrRate\"]),\n slowStartRate: toN(t[\"slowStartRate\"]),\n slowRenderingRate: toN(t[\"slowRenderingRate\"]),\n };\n}\n\nconst THRESHOLD_KEYS: Record<string, string> = {\n crashes: \"crashRate\",\n crash: \"crashRate\",\n anr: \"anrRate\",\n \"slow-starts\": \"slowStartRate\",\n \"slow-start\": \"slowStartRate\",\n \"slow-render\": \"slowRenderingRate\",\n \"slow-rendering\": \"slowRenderingRate\",\n};\n\nfunction parseThresholdOverrides(raw: string): Record<string, number> {\n const result: Record<string, number> = {};\n for (const pair of raw.split(\",\")) {\n const [key, val] = pair.split(\"=\").map((s) => s.trim());\n if (!key || !val) continue;\n const mapped = THRESHOLD_KEYS[key.toLowerCase()];\n if (!mapped) {\n console.error(\n `Error: Unknown threshold \"${key}\". Valid: crashes, anr, slow-starts, slow-render`,\n );\n process.exit(2);\n }\n const n = parseFloat(val);\n if (isNaN(n) || n < 0) {\n console.error(\n `Error: Invalid threshold value \"${val}\" for ${key}. Must be a positive number (percent).`,\n );\n process.exit(2);\n }\n result[mapped] = n / 100; // Convert percent to decimal\n }\n return result;\n}\n\nfunction resolvePackages(\n program: Command,\n config: { app?: string; profiles?: Record<string, { app?: string }> },\n allApps?: boolean,\n): string[] {\n const rootApp = (program.opts()[\"app\"] || config.app) as string | undefined;\n if (!allApps) return rootApp ? [rootApp] : [];\n\n const seen = new Set<string>();\n const result: string[] = [];\n if (rootApp) {\n seen.add(rootApp);\n result.push(rootApp);\n }\n for (const profile of Object.values(config.profiles ?? {})) {\n if (profile.app && !seen.has(profile.app)) {\n seen.add(profile.app);\n result.push(profile.app);\n }\n }\n return result;\n}\n\nfunction resolveWatchInterval(watch: string | boolean | undefined): number | null {\n if (watch === undefined) return null;\n if (watch === true || watch === \"\") return 30;\n const n = parseInt(String(watch), 10);\n return isNaN(n) ? 30 : n;\n}\n\nfunction colorizeTrackStatus(s: string): string {\n switch (s) {\n case \"inProgress\":\n case \"completed\":\n return green(s);\n case \"halted\":\n return red(s);\n case \"draft\":\n return dim(s);\n default:\n return gray(s);\n }\n}\n\nfunction applyStatusColors(status: AppStatus): AppStatus {\n if (!status.releases || status.releases.length === 0) return status;\n return {\n ...status,\n releases: status.releases.map((r) => ({\n ...r,\n status: colorizeTrackStatus(r.status),\n })),\n };\n}\n\nfunction makeRenderer(format: string, displayFormat: string): (status: AppStatus) => string {\n return (status: AppStatus): string => {\n if (format === \"json\") {\n const sectionSet = new Set(status.sections);\n const filtered: Record<string, unknown> = {\n packageName: status.packageName,\n fetchedAt: status.fetchedAt,\n cached: status.cached,\n sections: status.sections,\n };\n if (sectionSet.has(\"releases\")) filtered[\"releases\"] = status.releases;\n if (sectionSet.has(\"vitals\")) filtered[\"vitals\"] = status.vitals;\n if (sectionSet.has(\"reviews\")) filtered[\"reviews\"] = status.reviews;\n return formatOutput(filtered, \"json\");\n }\n const colorized = applyStatusColors(status);\n if (displayFormat === \"summary\") return formatStatusSummary(colorized);\n return formatStatusTable(colorized);\n };\n}\n\nexport function registerStatusCommand(program: Command): void {\n program\n .command(\"status\")\n .description(\"Unified app health snapshot: releases, vitals, and reviews\")\n .option(\"--days <n>\", \"Vitals window in days\", (v) => parseInt(v, 10), 7)\n .option(\"--review-days <n>\", \"Reviews window in days\", (v) => parseInt(v, 10), 30)\n .option(\"--cached\", \"Use last fetched data, skip API calls\")\n .option(\"--refresh\", \"Force live fetch, ignore cache TTL\")\n .option(\"--ttl <seconds>\", \"Cache TTL in seconds\", (v) => parseInt(v, 10), 3600)\n .option(\"--format <fmt>\", \"Display style: table (default) or summary\", \"table\")\n .option(\n \"--sections <list>\",\n \"Comma-separated sections: releases,vitals,reviews\",\n \"releases,vitals,reviews\",\n )\n .option(\"--watch [seconds]\", \"Poll every N seconds (min 10, default 30)\")\n .option(\"--since-last\", \"Show diff from last cached status\")\n .option(\"--all-apps\", \"Run status for all configured app profiles (max 5)\")\n .option(\"--notify\", \"Send desktop notification on threshold breach or clear\")\n .option(\"--threshold <overrides>\", \"Override vitals thresholds: crashes=1.5,anr=0.5 (percent)\")\n .action(\n async (opts: {\n days: number;\n reviewDays: number;\n cached?: boolean;\n refresh?: boolean;\n ttl: number;\n format: string;\n sections: string;\n watch?: string | boolean;\n sinceLast?: boolean;\n allApps?: boolean;\n threshold?: string;\n notify?: boolean;\n }) => {\n if (!VALID_FORMATS.has(opts.format)) {\n console.error(`Error: Unknown format \"${opts.format}\". Valid: table, summary`);\n process.exit(2);\n }\n\n const sections = parseSections(opts.sections);\n\n if (!Number.isFinite(opts.days) || opts.days < 1) {\n console.error(`Error: --days must be a positive integer (got: ${opts.days})`);\n process.exit(2);\n }\n\n if (!Number.isFinite(opts.reviewDays) || opts.reviewDays < 1) {\n console.error(\n `Error: --review-days must be a positive integer (got: ${opts.reviewDays})`,\n );\n process.exit(2);\n }\n\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n const render = makeRenderer(format, opts.format);\n let vitalThresholds: RunCtx[\"vitalThresholds\"] = resolveVitalThresholds(\n config as unknown as Record<string, unknown>,\n );\n if (opts.threshold) {\n const overrides = parseThresholdOverrides(opts.threshold);\n vitalThresholds = { ...vitalThresholds, ...overrides } as RunCtx[\"vitalThresholds\"];\n }\n const watchInterval = resolveWatchInterval(opts.watch);\n const packages = resolvePackages(program, config, opts.allApps);\n\n if (packages.length === 0) {\n console.error(\n \"Error: No package name. Use --app <package> or gpc config set app <package>\",\n );\n process.exit(2);\n }\n if (opts.allApps && packages.length > 5) {\n console.error(\n `Error: --all-apps found ${packages.length} apps (max 5). Use --app to target a specific app.`,\n );\n process.exit(2);\n }\n\n const authConfig = (config as unknown as Record<string, unknown>)[\"auth\"] as\n | Record<string, string>\n | undefined;\n\n const makeClients = async () => {\n const auth = await resolveAuth({ serviceAccountPath: authConfig?.[\"serviceAccount\"] });\n return {\n client: createApiClient({ auth }),\n reporting: createReportingClient({ auth }),\n };\n };\n\n let anyBreach = false;\n\n for (const packageName of packages) {\n if (packages.length > 1) console.log(`\\n=== ${packageName} ===`);\n\n try {\n const breach = await runStatusForPackage({\n packageName,\n opts,\n sections,\n format,\n vitalThresholds,\n watchInterval,\n render,\n makeClients,\n });\n if (breach) anyBreach = true;\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n if (packages.length === 1) process.exit(4);\n // For --all-apps, continue to next app on error\n }\n }\n\n if (anyBreach) process.exit(6);\n },\n );\n}\n\ninterface RunCtx {\n packageName: string;\n opts: {\n days: number;\n reviewDays: number;\n cached?: boolean;\n refresh?: boolean;\n ttl: number;\n sinceLast?: boolean;\n notify?: boolean;\n };\n sections: string[];\n format: string;\n vitalThresholds:\n | {\n crashRate?: number;\n anrRate?: number;\n slowStartRate?: number;\n slowRenderingRate?: number;\n }\n | undefined;\n watchInterval: number | null;\n render: (status: AppStatus) => string;\n makeClients: () => Promise<{\n client: ReturnType<typeof createApiClient>;\n reporting: ReturnType<typeof createReportingClient>;\n }>;\n}\n\n/** Override sections on a cached AppStatus with the user-requested sections for display. */\nfunction applyDisplaySections(status: AppStatus, requestedSections: string[]): AppStatus {\n const requested = new Set(requestedSections);\n const filtered = status.sections.filter((s) => requested.has(s));\n if (filtered.length === status.sections.length) return status;\n return { ...status, sections: filtered };\n}\n\n/** Returns true if a breach was detected. */\nasync function runStatusForPackage(ctx: RunCtx): Promise<boolean> {\n const { packageName, opts, sections, vitalThresholds, watchInterval, render } = ctx;\n\n const fetchLive = async (): Promise<AppStatus> => {\n const { client, reporting } = await ctx.makeClients();\n return getAppStatus(client, reporting, packageName, {\n days: opts.days,\n reviewDays: opts.reviewDays,\n sections,\n vitalThresholds: vitalThresholds ?? undefined,\n });\n };\n\n const save = (status: AppStatus) => saveStatusCache(packageName, status, opts.ttl);\n\n if (watchInterval !== null && opts.sinceLast) {\n process.stderr.write(\n \"Warning: --since-last is not supported with --watch and will be ignored.\\n\",\n );\n }\n\n // --watch: hand off entirely to runWatchLoop\n if (watchInterval !== null) {\n await runWatchLoop({ intervalSeconds: watchInterval, render, fetch: fetchLive, save });\n return false;\n }\n\n // --cached: serve from cache only\n if (opts.cached) {\n const cached = await loadStatusCache(packageName, opts.ttl);\n if (!cached) {\n console.error(\"Error: No cached status found. Run without --cached to fetch live data.\");\n process.exit(1);\n }\n const display = applyDisplaySections(cached, sections);\n console.log(render(display));\n await handleNotify(packageName, cached, opts.notify);\n return statusHasBreach(cached);\n }\n\n // Capture prev status before fetching (for --since-last)\n const prevStatus = opts.sinceLast ? await loadStatusCache(packageName, Infinity) : null;\n\n // Try cache (unless --refresh)\n if (!opts.refresh) {\n const cached = await loadStatusCache(packageName, opts.ttl);\n if (cached) {\n const display = applyDisplaySections(cached, sections);\n if (ctx.format !== \"json\" && display.sections.length < cached.sections.length) {\n process.stderr.write(\n `Tip: cache contains all sections. Add --refresh to fetch only the requested sections and reduce API calls.\\n`,\n );\n }\n printWithDiff(display, prevStatus, opts.sinceLast, render, ctx.format);\n await handleNotify(packageName, cached, opts.notify);\n return statusHasBreach(cached);\n }\n }\n\n // Live fetch (with spinner in TTY mode)\n const spinner = createSpinner(\"Fetching app status...\");\n if (ctx.format !== \"json\") spinner.start();\n let status: AppStatus;\n try {\n status = await fetchLive();\n } catch (err) {\n spinner.fail(\"Failed to fetch app status\");\n throw err;\n }\n spinner.stop(\"Done\");\n await save(status);\n\n printWithDiff(status, prevStatus, opts.sinceLast, render, ctx.format);\n await handleNotify(packageName, status, opts.notify);\n return statusHasBreach(status);\n}\n\nfunction relativeTime(isoString: string): string {\n const diffMs = Date.now() - new Date(isoString).getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 1) return \"just now\";\n if (diffMin < 60) return `${diffMin} min ago`;\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24) return `${diffHr}h ago`;\n return `${Math.floor(diffHr / 24)}d ago`;\n}\n\nfunction printWithDiff(\n status: AppStatus,\n prevStatus: AppStatus | null,\n sinceLast: boolean | undefined,\n render: (s: AppStatus) => string,\n format: string,\n): void {\n console.log(render(status));\n\n if (sinceLast && prevStatus) {\n const since = relativeTime(prevStatus.fetchedAt);\n console.log(\"\");\n console.log(formatStatusDiff(computeStatusDiff(prevStatus, status), since));\n } else if (sinceLast && !prevStatus && format !== \"json\") {\n console.log(\"\\n(No prior cached status to diff against)\");\n }\n}\n\nasync function handleNotify(\n packageName: string,\n status: AppStatus,\n notify: boolean | undefined,\n): Promise<void> {\n if (!notify) return;\n const breaching = statusHasBreach(status);\n const changed = await trackBreachState(packageName, breaching);\n if (changed) {\n const title = breaching ? \"GPC Alert\" : \"GPC Status\";\n const body = breaching\n ? `${packageName}: vitals threshold breached`\n : `${packageName}: vitals back to normal`;\n sendNotification(title, body);\n }\n}\n"],"mappings":"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","names":["status"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/subscriptions.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { Option } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport type { Subscription } from \"@gpc-cli/api\";\nimport {\n listSubscriptions,\n getSubscription,\n createSubscription,\n updateSubscription,\n deleteSubscription,\n activateBasePlan,\n deactivateBasePlan,\n deleteBasePlan,\n migratePrices,\n listOffers,\n getOffer,\n createOffer,\n updateOffer,\n deleteOffer,\n activateOffer,\n deactivateOffer,\n diffSubscription,\n getSubscriptionAnalytics,\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 registerSubscriptionsCommands(program: Command): void {\n const subs = program.command(\"subscriptions\").description(\"Manage subscriptions and base plans\");\n\n subs\n .command(\"list\")\n .description(\"List subscriptions\")\n .addOption(new Option(\"--page-size <n>\", \"Results per page\").argParser(parseInt).hideHelp())\n .addOption(new Option(\"--page-token <token>\", \"Page token\").hideHelp())\n .option(\"--limit <n>\", \"Maximum total results\", parseInt)\n .option(\"--next-page <token>\", \"Resume from page token\")\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 try {\n const result = await listSubscriptions(client, packageName, {\n pageSize: options.pageSize,\n pageToken: options.pageToken,\n limit: options.limit,\n nextPage: options.nextPage,\n });\n if (options.sort) {\n result.subscriptions = sortResults(result.subscriptions, options.sort);\n }\n const subs = result.subscriptions || [];\n if (format !== \"json\") {\n if (subs.length === 0) {\n console.log(\"No subscriptions found.\");\n return;\n }\n const summary = subs.map((s: Subscription) => ({\n productId: s.productId,\n basePlans: s.basePlans?.length || 0,\n listings: s.listings ? Object.keys(s.listings).length : 0,\n firstBasePlanState: s.basePlans?.[0]?.state || \"-\",\n }));\n console.log(formatOutput(summary, format));\n } else {\n console.log(formatOutput(subs.length === 0 ? { subscriptions: [] } : result, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n subs\n .command(\"get <product-id>\")\n .description(\"Get a subscription\")\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 try {\n const result = await getSubscription(client, packageName, productId);\n if (format !== \"json\") {\n const s = result as unknown as Record<string, unknown>;\n const basePlans = s[\"basePlans\"] as Array<Record<string, unknown>> | undefined;\n const listings = s[\"listings\"] as\n | Record<string, unknown>\n | Array<Record<string, unknown>>\n | undefined;\n const listingLanguages = listings\n ? Array.isArray(listings)\n ? listings.map((l) => l[\"languageCode\"] || l[\"language\"] || \"?\").join(\", \")\n : Object.keys(listings).join(\", \")\n : \"-\";\n const listingCount = listings\n ? Array.isArray(listings)\n ? listings.length\n : Object.keys(listings).length\n : 0;\n const summary = {\n productId: s[\"productId\"],\n basePlans: basePlans?.length || 0,\n basePlanIds: basePlans?.map((bp) => bp[\"basePlanId\"]).join(\", \") || \"-\",\n listings: listingCount,\n listingLanguages,\n taxCategory: (s[\"taxAndComplianceSettings\"] as Record<string, unknown>)?.[\n \"taxRateInfoByRegionCode\"\n ]\n ? \"configured\"\n : \"-\",\n };\n console.log(formatOutput(summary, format));\n } else {\n console.log(formatOutput(result, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n subs\n .command(\"create\")\n .description(\"Create a subscription from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with subscription data\")\n .option(\"--activate\", \"Activate all base plans after creation\")\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: \"subscriptions create\",\n action: \"create\",\n target: `subscription from ${options.file}`,\n details: options.activate ? { activate: true } : undefined,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = await readJsonFile(options.file);\n const result = await createSubscription(client, packageName, data as any);\n\n if (options.activate && result.basePlans) {\n for (const bp of result.basePlans) {\n if (bp.state === \"DRAFT\") {\n await activateBasePlan(client, packageName, result.productId, bp.basePlanId);\n console.error(`Activated base plan: ${bp.basePlanId}`);\n }\n }\n // Re-fetch to get updated state\n const updated = await getSubscription(client, packageName, result.productId);\n console.log(formatOutput(updated, format));\n } else {\n console.log(formatOutput(result, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n subs\n .command(\"update <product-id>\")\n .description(\"Update a subscription from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with subscription 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: \"subscriptions update\",\n action: \"update\",\n target: productId,\n details: { file: options.file, updateMask: options.updateMask },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = await readJsonFile(options.file);\n const result = await updateSubscription(\n client,\n packageName,\n productId,\n data as any,\n options.updateMask,\n );\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n subs\n .command(\"delete <product-id>\")\n .description(\"Delete a subscription\")\n .action(async (productId: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Delete subscription \"${productId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"subscriptions 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 try {\n await deleteSubscription(client, packageName, productId);\n console.log(`Subscription ${productId} deleted.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // --- Base Plans ---\n const basePlans = subs.command(\"base-plans\").description(\"Manage base plans\");\n\n basePlans\n .command(\"activate <product-id> <base-plan-id>\")\n .description(\"Activate a base plan\")\n .action(async (productId: string, basePlanId: 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: \"subscriptions base-plans activate\",\n action: \"activate\",\n target: `${productId}/${basePlanId}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await activateBasePlan(client, packageName, productId, basePlanId);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n basePlans\n .command(\"deactivate <product-id> <base-plan-id>\")\n .description(\"Deactivate a base plan\")\n .action(async (productId: string, basePlanId: 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: \"subscriptions base-plans deactivate\",\n action: \"deactivate\",\n target: `${productId}/${basePlanId}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await deactivateBasePlan(client, packageName, productId, basePlanId);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n basePlans\n .command(\"delete <product-id> <base-plan-id>\")\n .description(\"Delete a base plan\")\n .action(async (productId: string, basePlanId: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(\n `Delete base plan \"${basePlanId}\" from subscription \"${productId}\"?`,\n program,\n );\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"subscriptions base-plans delete\",\n action: \"delete\",\n target: `${productId}/${basePlanId}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n await deleteBasePlan(client, packageName, productId, basePlanId);\n console.log(`Base plan ${basePlanId} deleted.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n basePlans\n .command(\"migrate-prices <product-id> <base-plan-id>\")\n .description(\"Migrate base plan prices\")\n .requiredOption(\"--file <path>\", \"JSON file with migration data\")\n .action(\n async (\n productId: string,\n basePlanId: 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: \"subscriptions base-plans migrate-prices\",\n action: \"migrate prices for\",\n target: `${productId}/${basePlanId}`,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = await readJsonFile(options.file);\n const result = await migratePrices(\n client,\n packageName,\n productId,\n basePlanId,\n data as any,\n );\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n },\n );\n\n // --- Offers ---\n const offers = subs.command(\"offers\").description(\"Manage subscription offers\");\n\n offers\n .command(\"list <product-id> <base-plan-id>\")\n .description(\"List offers for a base plan\")\n .action(async (productId: string, basePlanId: 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 try {\n const result = await listOffers(client, packageName, productId, basePlanId);\n const offers_list = (result as unknown as Record<string, unknown>)[\"subscriptionOffers\"] as\n | Array<Record<string, unknown>>\n | undefined;\n if (format !== \"json\") {\n if (!offers_list || offers_list.length === 0) {\n console.log(\"No offers found.\");\n return;\n }\n const summary = offers_list.map((o) => ({\n offerId: o[\"offerId\"],\n basePlanId: o[\"basePlanId\"],\n state: o[\"state\"] || \"-\",\n phases: (o[\"phases\"] as unknown[])?.length || 0,\n regionalConfigs: (o[\"regionalConfigs\"] as unknown[])?.length || 0,\n }));\n console.log(formatOutput(summary, format));\n } else {\n console.log(formatOutput(result, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n offers\n .command(\"get <product-id> <base-plan-id> <offer-id>\")\n .description(\"Get an offer\")\n .action(async (productId: string, basePlanId: 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 try {\n const result = await getOffer(client, packageName, productId, basePlanId, offerId);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n offers\n .command(\"create <product-id> <base-plan-id>\")\n .description(\"Create an offer from JSON file\")\n .requiredOption(\"--file <path>\", \"JSON file with offer data\")\n .action(\n async (\n productId: string,\n basePlanId: 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: \"subscriptions offers create\",\n action: \"create offer for\",\n target: `${productId}/${basePlanId}`,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = await readJsonFile(options.file);\n const result = await createOffer(client, packageName, productId, basePlanId, data as any);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n },\n );\n\n offers\n .command(\"update <product-id> <base-plan-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 basePlanId: 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: \"subscriptions offers update\",\n action: \"update offer\",\n target: `${productId}/${basePlanId}/${offerId}`,\n details: { file: options.file, updateMask: options.updateMask },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const data = await readJsonFile(options.file);\n const result = await updateOffer(\n client,\n packageName,\n productId,\n basePlanId,\n offerId,\n data as any,\n options.updateMask,\n );\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n },\n );\n\n offers\n .command(\"delete <product-id> <base-plan-id> <offer-id>\")\n .description(\"Delete an offer\")\n .action(async (productId: string, basePlanId: string, offerId: string) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Delete offer \"${offerId}\"?`, program);\n\n if (isDryRun(program)) {\n const format = getOutputFormat(program, config);\n printDryRun(\n {\n command: \"subscriptions offers delete\",\n action: \"delete offer\",\n target: `${productId}/${basePlanId}/${offerId}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n await deleteOffer(client, packageName, productId, basePlanId, offerId);\n console.log(`Offer ${offerId} deleted.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n offers\n .command(\"activate <product-id> <base-plan-id> <offer-id>\")\n .description(\"Activate an offer\")\n .action(async (productId: string, basePlanId: string, offerId: 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: \"subscriptions offers activate\",\n action: \"activate offer\",\n target: `${productId}/${basePlanId}/${offerId}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await activateOffer(client, packageName, productId, basePlanId, offerId);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n offers\n .command(\"deactivate <product-id> <base-plan-id> <offer-id>\")\n .description(\"Deactivate an offer\")\n .action(async (productId: string, basePlanId: string, offerId: 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: \"subscriptions offers deactivate\",\n action: \"deactivate offer\",\n target: `${productId}/${basePlanId}/${offerId}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await deactivateOffer(client, packageName, productId, basePlanId, offerId);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // --- Diff ---\n subs\n .command(\"diff <product-id>\")\n .description(\"Compare local JSON file against remote subscription\")\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 try {\n const localData = (await readJsonFile(options.file)) as Subscription;\n const diffs = await diffSubscription(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 } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n subs\n .command(\"analytics\")\n .description(\"Subscription catalog analytics: active plans, offer counts, state breakdown\")\n .action(async () => {\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 try {\n const result = await getSubscriptionAnalytics(client, packageName);\n\n if (format === \"json\") {\n console.log(formatOutput(result, format));\n return;\n }\n\n console.log(`\\nSubscription Analytics — ${packageName}`);\n console.log(`${\"─\".repeat(50)}`);\n console.log(`Total subscriptions: ${result.totalSubscriptions}`);\n console.log(`Active subscriptions: ${result.activeCount}`);\n console.log(`Active base plans: ${result.activeBasePlans}`);\n console.log(`Draft base plans: ${result.trialBasePlans}`);\n console.log(`Inactive base plans: ${result.pausedBasePlans}`);\n console.log(`Total offers: ${result.offerCount}`);\n\n if (result.byProductId.length > 0) {\n console.log(`\\nBy product:`);\n console.log(formatOutput(result.byProductId, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":["subs","basePlans"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/testers.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\n\nimport {\n listTesters,\n addTesters,\n removeTesters,\n importTestersFromCsv,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { isInteractive, requireOption, requireConfirm } from \"../prompt.js\";\n\n\n\nexport function registerTestersCommands(program: Command): void {\n const testers = program.command(\"testers\").description(\"Manage testers and tester groups\");\n\n testers\n .command(\"list\")\n .description(\"List testers for a track\")\n .option(\"--track <track>\", \"Track name (e.g., internal, alpha, beta)\")\n .option(\"--sort <field>\", \"Sort by field (prefix with - for descending, e.g., email or -email)\")\n .option(\"--limit <n>\", \"Maximum results to return\")\n .option(\"--next-page <token>\", \"Pagination token for next page\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const interactive = isInteractive(program);\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: [\"internal\", \"alpha\", \"beta\"],\n },\n interactive,\n );\n\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await listTesters(client, packageName, options.track);\n if (options.sort && result.googleGroups) {\n const descending = options.sort.startsWith(\"-\");\n result.googleGroups = [...result.googleGroups].sort((a: string, b: string) =>\n descending ? b.localeCompare(a) : a.localeCompare(b),\n );\n }\n if (format !== \"json\") {\n const groups = (result.googleGroups || []) as string[];\n const rows = groups.map((g: string) => ({ googleGroup: g }));\n if (rows.length > 0) {\n console.log(formatOutput(rows, format));\n } else {\n console.log(\"No testers found.\");\n }\n } else {\n console.log(formatOutput(result, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n testers\n .command(\"add <emails...>\")\n .description(\"Add testers (Google Group emails) to a track\")\n .option(\"--track <track>\", \"Track name (e.g., internal, alpha, beta)\")\n .action(async (emails: string[], options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: [\"internal\", \"alpha\", \"beta\"],\n },\n interactive,\n );\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"testers add\",\n action: \"add testers to\",\n target: options.track,\n details: { emails },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await addTesters(client, packageName, options.track, emails);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n testers\n .command(\"remove <emails...>\")\n .description(\"Remove testers (Google Group emails) from a track\")\n .option(\"--track <track>\", \"Track name (e.g., internal, alpha, beta)\")\n .action(async (emails: string[], options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: [\"internal\", \"alpha\", \"beta\"],\n },\n interactive,\n );\n\n await requireConfirm(`Remove ${emails.length} tester(s) from ${options.track}?`, program);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"testers remove\",\n action: \"remove testers from\",\n target: options.track,\n details: { emails },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await removeTesters(client, packageName, options.track, emails);\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n testers\n .command(\"import\")\n .description(\"Import testers from a CSV file\")\n .option(\"--track <track>\", \"Track name (e.g., internal, alpha, beta)\")\n .option(\"--file <path>\", \"CSV file with email addresses\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: [\"internal\", \"alpha\", \"beta\"],\n },\n interactive,\n );\n\n options.file = await requireOption(\n \"file\",\n options.file,\n {\n message: \"CSV file path:\",\n },\n interactive,\n );\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"testers import\",\n action: \"import testers to\",\n target: options.track,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await importTestersFromCsv(client, packageName, options.track, options.file);\n console.log(formatOutput({ added: result.added, testers: result.testers }, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":[]}
|
package/dist/tracks-NERFFEDT.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
isDryRun,
|
|
4
|
-
printDryRun
|
|
5
|
-
} from "./chunk-Y3QZDAKS.js";
|
|
6
|
-
import {
|
|
7
|
-
getOutputFormat
|
|
8
|
-
} from "./chunk-ELXAK7GI.js";
|
|
9
|
-
|
|
10
|
-
// src/commands/tracks.ts
|
|
11
|
-
import { readFile } from "fs/promises";
|
|
12
|
-
import { loadConfig } from "@gpc-cli/config";
|
|
13
|
-
import { resolveAuth } from "@gpc-cli/auth";
|
|
14
|
-
import { createApiClient } from "@gpc-cli/api";
|
|
15
|
-
import { listTracks, createTrack, updateTrackConfig } from "@gpc-cli/core";
|
|
16
|
-
import { formatOutput } from "@gpc-cli/core";
|
|
17
|
-
function registerTracksCommands(program) {
|
|
18
|
-
const tracks = program.command("tracks").description("Manage tracks");
|
|
19
|
-
tracks.command("list").description("List all tracks").option("--limit <n>", "Maximum results to return").option("--next-page <token>", "Pagination token for next page").action(async (_options) => {
|
|
20
|
-
const config = await loadConfig();
|
|
21
|
-
const packageName = program.opts()["app"] || config.app;
|
|
22
|
-
if (!packageName) {
|
|
23
|
-
console.error(
|
|
24
|
-
"Error: No package name. Use --app <package> or gpc config set app <package>"
|
|
25
|
-
);
|
|
26
|
-
process.exit(2);
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
|
|
30
|
-
const client = createApiClient({ auth });
|
|
31
|
-
const trackList = await listTracks(client, packageName);
|
|
32
|
-
const format = getOutputFormat(program, config);
|
|
33
|
-
const summary = trackList.map((t) => ({
|
|
34
|
-
track: t.track,
|
|
35
|
-
releases: t.releases?.length || 0,
|
|
36
|
-
latestStatus: t.releases?.[0]?.status || "none",
|
|
37
|
-
latestVersion: t.releases?.[0]?.versionCodes?.[0] || "-"
|
|
38
|
-
}));
|
|
39
|
-
console.log(formatOutput(summary, format));
|
|
40
|
-
} catch (error) {
|
|
41
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
|
-
process.exit(4);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
tracks.command("create <name>").description("Create a custom track").action(async (name) => {
|
|
46
|
-
const config = await loadConfig();
|
|
47
|
-
const packageName = program.opts()["app"] || config.app;
|
|
48
|
-
if (!packageName) {
|
|
49
|
-
console.error(
|
|
50
|
-
"Error: No package name. Use --app <package> or gpc config set app <package>"
|
|
51
|
-
);
|
|
52
|
-
process.exit(2);
|
|
53
|
-
}
|
|
54
|
-
const format = getOutputFormat(program, config);
|
|
55
|
-
if (isDryRun(program)) {
|
|
56
|
-
printDryRun(
|
|
57
|
-
{ command: "tracks create", action: "create custom track", target: name },
|
|
58
|
-
format,
|
|
59
|
-
formatOutput
|
|
60
|
-
);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
try {
|
|
64
|
-
const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
|
|
65
|
-
const client = createApiClient({ auth });
|
|
66
|
-
const track = await createTrack(client, packageName, name);
|
|
67
|
-
console.log(formatOutput(track, format));
|
|
68
|
-
} catch (error) {
|
|
69
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
70
|
-
process.exit(4);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
tracks.command("update <name>").description("Update track configuration from a JSON file").requiredOption("--file <path>", "Path to JSON config file").action(async (name, options) => {
|
|
74
|
-
const config = await loadConfig();
|
|
75
|
-
const packageName = program.opts()["app"] || config.app;
|
|
76
|
-
if (!packageName) {
|
|
77
|
-
console.error(
|
|
78
|
-
"Error: No package name. Use --app <package> or gpc config set app <package>"
|
|
79
|
-
);
|
|
80
|
-
process.exit(2);
|
|
81
|
-
}
|
|
82
|
-
const format = getOutputFormat(program, config);
|
|
83
|
-
if (isDryRun(program)) {
|
|
84
|
-
printDryRun(
|
|
85
|
-
{ command: "tracks update", action: "update track config from", target: options.file },
|
|
86
|
-
format,
|
|
87
|
-
formatOutput
|
|
88
|
-
);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
try {
|
|
92
|
-
const raw = await readFile(options.file, "utf-8");
|
|
93
|
-
const trackConfig = JSON.parse(raw);
|
|
94
|
-
const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
|
|
95
|
-
const client = createApiClient({ auth });
|
|
96
|
-
const track = await updateTrackConfig(client, packageName, name, trackConfig);
|
|
97
|
-
console.log(formatOutput(track, format));
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
100
|
-
process.exit(4);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
export {
|
|
105
|
-
registerTracksCommands
|
|
106
|
-
};
|
|
107
|
-
//# sourceMappingURL=tracks-NERFFEDT.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/tracks.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport { listTracks, createTrack, updateTrackConfig } from \"@gpc-cli/core\";\nimport { formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\n\nexport function registerTracksCommands(program: Command): void {\n const tracks = program.command(\"tracks\").description(\"Manage tracks\");\n\n tracks\n .command(\"list\")\n .description(\"List all tracks\")\n .option(\"--limit <n>\", \"Maximum results to return\")\n .option(\"--next-page <token>\", \"Pagination token for next page\")\n .action(async (_options) => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n console.error(\n \"Error: No package name. Use --app <package> or gpc config set app <package>\",\n );\n process.exit(2);\n }\n\n try {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const trackList = await listTracks(client, packageName);\n const format = getOutputFormat(program, config);\n\n const summary = trackList.map((t) => ({\n track: t.track,\n releases: t.releases?.length || 0,\n latestStatus: t.releases?.[0]?.status || \"none\",\n latestVersion: t.releases?.[0]?.versionCodes?.[0] || \"-\",\n }));\n\n console.log(formatOutput(summary, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n tracks\n .command(\"create <name>\")\n .description(\"Create a custom track\")\n .action(async (name: string) => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n console.error(\n \"Error: No package name. Use --app <package> or gpc config set app <package>\",\n );\n process.exit(2);\n }\n\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"tracks create\", action: \"create custom track\", target: name },\n format,\n formatOutput,\n );\n return;\n }\n\n try {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const track = await createTrack(client, packageName, name);\n console.log(formatOutput(track, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n tracks\n .command(\"update <name>\")\n .description(\"Update track configuration from a JSON file\")\n .requiredOption(\"--file <path>\", \"Path to JSON config file\")\n .action(async (name: string, options: { file: string }) => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n console.error(\n \"Error: No package name. Use --app <package> or gpc config set app <package>\",\n );\n process.exit(2);\n }\n\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"tracks update\", action: \"update track config from\", target: options.file },\n format,\n formatOutput,\n );\n return;\n }\n\n try {\n const raw = await readFile(options.file, \"utf-8\");\n const trackConfig = JSON.parse(raw) as Record<string, unknown>;\n\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const track = await updateTrackConfig(client, packageName, name, trackConfig);\n console.log(formatOutput(track, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/train.ts"],"sourcesContent":["import { resolvePackageName } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient, createReportingClient } from \"@gpc-cli/api\";\nimport {\n startTrain,\n getTrainStatus,\n pauseTrain,\n abortTrain,\n advanceTrain,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport type { TrainConfig } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { requireConfirm } from \"../prompt.js\";\n\n\nasync function getClients(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return {\n apiClient: createApiClient({ auth }),\n reportingClient: createReportingClient({ auth }),\n };\n}\n\nasync function loadTrainConfig(file: string): Promise<TrainConfig> {\n const { readFile } = await import(\"node:fs/promises\");\n try {\n const raw = await readFile(file, \"utf-8\");\n return JSON.parse(raw) as TrainConfig;\n } catch {\n console.error(`Error: Could not read train config from \"${file}\"`);\n process.exit(2);\n }\n}\n\nexport function registerTrainCommands(program: Command): void {\n const train = program\n .command(\"train\")\n .description(\"Manage config-driven staged rollout release trains\");\n\n train\n .command(\"start\")\n .description(\"Start a release train from a config file\")\n .option(\"--config <file>\", \"Train config file (JSON)\", \".gpcrc-train.json\")\n .option(\"--force\", \"Restart even if a train is already running\")\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 const trainConfig = await loadTrainConfig(options.config as string);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"train start\",\n action: \"start release train\",\n target: packageName,\n details: { stages: trainConfig.stages.length, gates: trainConfig.gates },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const { apiClient } = await getClients(config);\n\n try {\n const state = await startTrain(apiClient, packageName, trainConfig, {\n force: options.force as boolean,\n });\n console.log(formatOutput(state, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n train\n .command(\"status\")\n .description(\"Show current release train state\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n try {\n const state = await getTrainStatus(packageName);\n if (!state) {\n if (format === \"json\") {\n console.log(formatOutput(null, format));\n } else {\n console.log(`No active release train for ${packageName}.`);\n }\n return;\n }\n console.log(formatOutput(state, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n train\n .command(\"advance\")\n .description(\"Advance the train to the next stage (after delay and gate checks pass)\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const { apiClient, reportingClient } = await getClients(config);\n\n try {\n const state = await advanceTrain(apiClient, reportingClient, packageName);\n if (!state) {\n console.log(`No active release train for ${packageName}.`);\n return;\n }\n console.log(formatOutput(state, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n train\n .command(\"pause\")\n .description(\"Pause the release train\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n try {\n const state = await pauseTrain(packageName);\n if (!state) {\n console.log(`No active release train for ${packageName}.`);\n return;\n }\n console.log(formatOutput(state, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n train\n .command(\"abort\")\n .description(\"Abort and clear the release train state\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n\n await requireConfirm(`Abort release train for ${packageName}?`, program);\n\n try {\n await abortTrain(packageName);\n console.log(`Release train aborted for ${packageName}.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/update.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport {\n checkForUpdate,\n fetchChecksums,\n updateViaNpm,\n updateViaBrew,\n updateBinaryInPlace,\n getPlatformAsset,\n getCurrentBinaryPath,\n} from \"../updater.js\";\nimport { createSpinner } from \"@gpc-cli/core\";\n\nexport function registerUpdateCommand(program: Command): void {\n program\n .command(\"update\")\n .description(\"Update gpc to the latest version\")\n .option(\"--check\", \"Check for updates without installing (exits 0 always)\")\n .option(\"--force\", \"Update even if already on the latest version\")\n .action(async (opts: { check?: boolean; force?: boolean }, cmd) => {\n const parentOpts = (cmd.parent?.opts() ?? {}) as Record<string, unknown>;\n const jsonMode = !!(parentOpts[\"json\"] || parentOpts[\"output\"] === \"json\");\n const currentVersion = process.env[\"__GPC_VERSION\"] ?? \"0.0.0\";\n\n // Dev build guard\n if (currentVersion === \"0.0.0\") {\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: false,\n reason: \"Cannot update a development build\",\n current: currentVersion,\n }),\n );\n } else {\n console.log(\"Cannot update a development build (version: 0.0.0).\");\n }\n return;\n }\n\n const spinner = createSpinner(\"Checking for updates...\");\n spinner.start();\n\n let result;\n try {\n result = await checkForUpdate(currentVersion);\n } catch (err) {\n spinner.fail(\"Failed to check for updates\");\n throw err;\n }\n\n // --check mode: always exit 0, communicate via output\n if (opts.check) {\n spinner.stop();\n if (jsonMode) {\n console.log(\n JSON.stringify({\n current: result.current,\n latest: result.latest,\n updateAvailable: result.updateAvailable,\n installMethod: result.installMethod,\n releaseUrl: result.release.html_url,\n }),\n );\n } else if (result.updateAvailable) {\n console.log(`Update available: ${result.current} → ${result.latest}`);\n console.log(`Install method: ${result.installMethod}`);\n console.log(`Release: ${result.release.html_url}`);\n console.log(`\\nRun: gpc update`);\n } else {\n console.log(`Already on latest version: v${result.current}`);\n console.log(`Install method: ${result.installMethod}`);\n }\n return;\n }\n\n // Already up to date\n if (!result.updateAvailable && !opts.force) {\n spinner.stop(`Already on latest version: v${result.current}`);\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n current: result.current,\n latest: result.latest,\n updated: false,\n installMethod: result.installMethod,\n }),\n );\n }\n return;\n }\n\n spinner.update(\n `Updating v${result.current} → v${result.latest} (${result.installMethod})...`,\n );\n\n switch (result.installMethod) {\n case \"npm\":\n spinner.stop();\n await updateViaNpm({ silent: jsonMode });\n break;\n\n case \"homebrew\":\n spinner.stop();\n await updateViaBrew({ silent: jsonMode });\n break;\n\n case \"binary\": {\n const assetName = getPlatformAsset();\n if (!assetName) {\n spinner.fail();\n console.error(`Error: Unsupported platform: ${process.platform}/${process.arch}`);\n console.error(`Download manually: ${result.release.html_url}`);\n process.exit(1);\n }\n\n const assetObj = result.release.assets.find((a) => a.name === assetName);\n if (!assetObj) {\n spinner.fail();\n console.error(`Error: No binary found for ${assetName} in release ${result.latestTag}`);\n console.error(`Check: ${result.release.html_url}`);\n process.exit(1);\n }\n\n const sizeMB = (assetObj.size / (1024 * 1024)).toFixed(1);\n spinner.stop();\n\n const checksums = await fetchChecksums(result.release);\n const expectedHash = checksums.get(assetName) ?? \"\";\n const binaryPath = getCurrentBinaryPath();\n\n if (jsonMode) {\n await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath);\n } else {\n // Show live download progress on a single overwriting line\n const label = `Downloading ${assetName} (${sizeMB} MB)`;\n process.stdout.write(`${label}...\\n`);\n let lastPct = -1;\n await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath, {\n onProgress(downloaded, total) {\n if (total <= 0) return;\n const pct = Math.min(100, Math.round((downloaded / total) * 100));\n if (pct === lastPct) return; // avoid redundant writes\n lastPct = pct;\n const dlMB = (downloaded / (1024 * 1024)).toFixed(1);\n process.stdout.write(\n `\\r${label} ${dlMB} / ${sizeMB} MB (${String(pct).padStart(3)}%) `,\n );\n },\n });\n process.stdout.write(\"\\n\");\n }\n break;\n }\n\n case \"unknown\":\n spinner.fail();\n console.error(\"Error: Could not detect install method. Update manually:\");\n console.error(` npm: npm install -g @gpc-cli/cli@latest`);\n console.error(` Homebrew: brew upgrade yasserstudio/tap/gpc`);\n console.error(` Binary: https://github.com/yasserstudio/gpc/releases/latest`);\n process.exit(1);\n }\n\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n previous: result.current,\n current: result.latest,\n method: result.installMethod,\n }),\n );\n } else {\n console.log(`\\n✔ Updated to v${result.latest}`);\n }\n });\n}\n"],"mappings":"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","names":[]}
|