@gpc-cli/core 0.9.61 → 0.9.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GPC Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { OutputFormat, ResolvedConfig, WebhookConfig } from '@gpc-cli/config';
2
2
  import { AuthClient } from '@gpc-cli/auth';
3
3
  import { GpcPlugin, PluginManifest, CommandEvent, CommandResult, PluginError, RequestEvent, ResponseEvent, PluginCommand } from '@gpc-cli/plugin-sdk';
4
- import { PlayApiClient, EditCommitOptions, Track, ExternallyHostedApk, ExternallyHostedApkResponse, DeobfuscationFileType, UploadProgressEvent, ResumableUploadOptions, Listing, ImageType, CountryAvailability, Image, AppDetails, Review, ReviewReplyResponse, Subscription, SubscriptionOffer, OffersListResponse, BasePlanMigratePricesRequest, InAppProduct, Order, SubscriptionDeferResponse, SubscriptionsV2DeferResponse, ProductPurchase, ProductPurchaseV2, SubscriptionPurchaseV2, VoidedPurchase, UsersApiClient, User, DeveloperLevelPermission, Grant, MetricRow, ReportingDimension, ReportingAggregation, VitalsMetricSet, ReportingApiClient, AnomalyDetectionResponse, MetricSetResponse, ErrorIssuesResponse, ConvertRegionPricesResponse, ReportType, StatsDimension, ReportBucket, Testers, AppRecoveryTargeting, AppRecoveryAction, CreateAppRecoveryActionRequest, DataSafety, ExternalTransaction, ExternalTransactionRefund, DeviceTierConfig, OneTimeOffer, OneTimeProduct, OneTimeOffersListResponse, OneTimeProductsListResponse, GamesApiClient, Achievement, GameEvent, Leaderboard, EnterpriseApiClient, CustomApp, GeneratedApk, Bundle } from '@gpc-cli/api';
4
+ import { PlayApiClient, EditCommitOptions, Track, ExternallyHostedApk, ExternallyHostedApkResponse, DeobfuscationFileType, UploadProgressEvent, ResumableUploadOptions, Listing, ImageType, CountryAvailability, Image, AppDetails, Review, ReviewReplyResponse, Subscription, SubscriptionOffer, OffersListResponse, BasePlanMigratePricesRequest, InAppProduct, Order, SubscriptionDeferResponse, SubscriptionsV2DeferResponse, ProductPurchase, ProductPurchaseV2, SubscriptionPurchaseV2, VoidedPurchase, UsersApiClient, User, DeveloperLevelPermission, Grant, MetricRow, ReportingDimension, ReportingAggregation, VitalsMetricSet, ReportingApiClient, AnomalyDetectionResponse, MetricSetResponse, ErrorIssuesResponse, ConvertRegionPricesResponse, ReportType, StatsDimension, ReportBucket, Testers, AppRecoveryTargeting, AppRecoveryAction, CreateAppRecoveryActionRequest, DataSafetyResponse, DataSafetyRequest, ExternalTransaction, ExternalTransactionRefund, DeviceTierConfig, OneTimeOffer, OneTimeProduct, OneTimeOffersListResponse, OneTimeProductsListResponse, GamesApiClient, Achievement, GameEvent, Leaderboard, EnterpriseApiClient, CustomApp, GeneratedApk, Bundle } from '@gpc-cli/api';
5
5
 
6
6
  declare class GpcError extends Error {
7
7
  readonly code: string;
@@ -779,8 +779,8 @@ declare function deployRecoveryAction(client: PlayApiClient, packageName: string
779
779
  declare function createRecoveryAction(client: PlayApiClient, packageName: string, request: CreateAppRecoveryActionRequest): Promise<AppRecoveryAction>;
780
780
  declare function addRecoveryTargeting(client: PlayApiClient, packageName: string, actionId: string, targeting: AppRecoveryTargeting): Promise<AppRecoveryAction>;
781
781
 
782
- declare function updateDataSafety(client: PlayApiClient, packageName: string, data: DataSafety): Promise<DataSafety>;
783
- declare function importDataSafety(client: PlayApiClient, packageName: string, filePath: string): Promise<DataSafety>;
782
+ declare function updateDataSafety(client: PlayApiClient, packageName: string, data: DataSafetyRequest): Promise<DataSafetyResponse>;
783
+ declare function importDataSafety(client: PlayApiClient, packageName: string, filePath: string): Promise<DataSafetyResponse>;
784
784
 
785
785
  declare function createExternalTransaction(client: PlayApiClient, packageName: string, data: ExternalTransaction): Promise<ExternalTransaction>;
786
786
  declare function getExternalTransaction(client: PlayApiClient, packageName: string, transactionId: string): Promise<ExternalTransaction>;
package/dist/index.js CHANGED
@@ -3975,24 +3975,41 @@ async function addRecoveryTargeting(client, packageName, actionId, targeting) {
3975
3975
  }
3976
3976
 
3977
3977
  // src/commands/data-safety.ts
3978
- import { readFile as readFile6 } from "fs/promises";
3978
+ import { readFile as readFile6, stat as stat4 } from "fs/promises";
3979
+ var MAX_CSV_BYTES = 1 * 1024 * 1024;
3979
3980
  async function updateDataSafety(client, packageName, data) {
3980
3981
  return client.dataSafety.update(packageName, data);
3981
3982
  }
3982
3983
  async function importDataSafety(client, packageName, filePath) {
3983
- const content = await readFile6(filePath, "utf-8");
3984
- let data;
3984
+ let fileStat;
3985
3985
  try {
3986
- data = JSON.parse(content);
3986
+ fileStat = await stat4(filePath);
3987
3987
  } catch {
3988
3988
  throw new GpcError(
3989
- `Failed to parse data safety JSON from "${filePath}"`,
3990
- "INVALID_JSON",
3989
+ `Cannot read data safety CSV: "${filePath}"`,
3990
+ "FILE_NOT_FOUND",
3991
3991
  1,
3992
- "Ensure the file contains valid JSON matching the data safety schema."
3992
+ "Check the file path and ensure the file exists."
3993
3993
  );
3994
3994
  }
3995
- return updateDataSafety(client, packageName, data);
3995
+ if (fileStat.size === 0) {
3996
+ throw new GpcError(
3997
+ `Data safety CSV is empty: "${filePath}"`,
3998
+ "INVALID_INPUT",
3999
+ 1,
4000
+ "Export your data safety form from Play Console and provide the CSV."
4001
+ );
4002
+ }
4003
+ if (fileStat.size > MAX_CSV_BYTES) {
4004
+ throw new GpcError(
4005
+ `Data safety CSV exceeds 1 MB (${fileStat.size} bytes): "${filePath}"`,
4006
+ "FILE_TOO_LARGE",
4007
+ 1,
4008
+ "The CSV should be a few KB. Check that you are passing the correct file."
4009
+ );
4010
+ }
4011
+ const csvContent = await readFile6(filePath, "utf-8");
4012
+ return updateDataSafety(client, packageName, { safetyLabels: csvContent });
3996
4013
  }
3997
4014
 
3998
4015
  // src/commands/external-transactions.ts
@@ -4667,11 +4684,11 @@ function safePathWithin(userPath, baseDir) {
4667
4684
  }
4668
4685
 
4669
4686
  // src/commands/init.ts
4670
- import { mkdir as mkdir6, writeFile as writeFile6, stat as stat4 } from "fs/promises";
4687
+ import { mkdir as mkdir6, writeFile as writeFile6, stat as stat5 } from "fs/promises";
4671
4688
  import { join as join7 } from "path";
4672
4689
  async function exists2(path) {
4673
4690
  try {
4674
- await stat4(path);
4691
+ await stat5(path);
4675
4692
  return true;
4676
4693
  } catch {
4677
4694
  return false;
@@ -5756,7 +5773,7 @@ ${fileList}` + (hasPageSizeCompat ? "\nandroid:pageSizeCompat is set, so the app
5756
5773
  }
5757
5774
 
5758
5775
  // src/preflight/scanners/metadata-scanner.ts
5759
- import { readdir as readdir4, stat as stat5, readFile as readFile10 } from "fs/promises";
5776
+ import { readdir as readdir4, stat as stat6, readFile as readFile10 } from "fs/promises";
5760
5777
  import { join as join8 } from "path";
5761
5778
  var SAFE_LANG = /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$/;
5762
5779
  var FILE_MAP2 = {
@@ -5809,7 +5826,7 @@ var metadataScanner = {
5809
5826
  }
5810
5827
  for (const lang of locales) {
5811
5828
  const langDir = join8(dir, lang);
5812
- const langStat = await stat5(langDir).catch(() => null);
5829
+ const langStat = await stat6(langDir).catch(() => null);
5813
5830
  if (!langStat?.isDirectory()) continue;
5814
5831
  const fields = {};
5815
5832
  for (const [fileName, field] of Object.entries(FILE_MAP2)) {
@@ -5916,7 +5933,7 @@ var metadataScanner = {
5916
5933
  import { readFile as readFile11 } from "fs/promises";
5917
5934
 
5918
5935
  // src/preflight/scan-files.ts
5919
- import { readdir as readdir5, stat as stat6 } from "fs/promises";
5936
+ import { readdir as readdir5, stat as stat7 } from "fs/promises";
5920
5937
  import { join as join9, extname as extname2 } from "path";
5921
5938
  var DEFAULT_SKIP_DIRS = /* @__PURE__ */ new Set([
5922
5939
  ".git",
@@ -5941,7 +5958,7 @@ async function collectSourceFiles(dir, extensions, skipDirs = DEFAULT_SKIP_DIRS,
5941
5958
  for (const entry of entries) {
5942
5959
  if (skipDirs.has(entry)) continue;
5943
5960
  const fullPath = join9(dir, entry);
5944
- const s = await stat6(fullPath).catch(() => null);
5961
+ const s = await stat7(fullPath).catch(() => null);
5945
5962
  if (!s) continue;
5946
5963
  if (s.isDirectory()) {
5947
5964
  const sub = await collectSourceFiles(fullPath, extensions, skipDirs, maxDepth - 1);
@@ -6863,7 +6880,7 @@ async function downloadGeneratedApk(client, packageName, versionCode, apkId, out
6863
6880
  }
6864
6881
 
6865
6882
  // src/commands/bundle-analysis.ts
6866
- import { readFile as readFile14, stat as stat7 } from "fs/promises";
6883
+ import { readFile as readFile14, stat as stat8 } from "fs/promises";
6867
6884
  var EOCD_SIGNATURE = 101010256;
6868
6885
  var CD_SIGNATURE = 33639248;
6869
6886
  var MODULE_SUBDIRS = /* @__PURE__ */ new Set(["dex", "manifest", "res", "assets", "lib", "resources.pb", "root"]);
@@ -6939,7 +6956,7 @@ function detectFileType2(filePath) {
6939
6956
  return "apk";
6940
6957
  }
6941
6958
  async function analyzeBundle(filePath) {
6942
- const fileInfo = await stat7(filePath).catch(() => null);
6959
+ const fileInfo = await stat8(filePath).catch(() => null);
6943
6960
  if (!fileInfo || !fileInfo.isFile()) {
6944
6961
  throw new Error(`File not found: ${filePath}`);
6945
6962
  }
@@ -8359,10 +8376,10 @@ function compareFingerprints(a, b) {
8359
8376
 
8360
8377
  // src/utils/hash.ts
8361
8378
  import { createHash } from "crypto";
8362
- import { stat as stat8 } from "fs/promises";
8379
+ import { stat as stat9 } from "fs/promises";
8363
8380
  async function sha256File(filePath) {
8364
8381
  const hash = createHash("sha256");
8365
- const { size } = await stat8(filePath);
8382
+ const { size } = await stat9(filePath);
8366
8383
  if (size === 0) return hash.digest("hex");
8367
8384
  const { createReadStream } = await import("fs");
8368
8385
  const stream = createReadStream(filePath);