@better-update/cli 0.41.2 → 0.42.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -35,7 +35,7 @@ var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
35
35
 
36
36
  //#endregion
37
37
  //#region package.json
38
- var version = "0.41.2";
38
+ var version = "0.42.1";
39
39
 
40
40
  //#endregion
41
41
  //#region src/lib/interactive-mode.ts
@@ -489,6 +489,8 @@ const RotateVaultBody = Schema.Struct({
489
489
  var AndroidUploadKeystore = class extends Schema.Class("AndroidUploadKeystore")({
490
490
  id: Id,
491
491
  organizationId: Id,
492
+ /** User-supplied label from `credentials upload --name`; null for keystores uploaded before names were stored or generated via keytool. */
493
+ name: Schema.NullOr(Schema.String),
492
494
  keyAlias: Schema.String,
493
495
  md5Fingerprint: Schema.NullOr(Schema.String),
494
496
  sha1Fingerprint: Schema.NullOr(Schema.String),
@@ -505,6 +507,7 @@ var AndroidUploadKeystore = class extends Schema.Class("AndroidUploadKeystore")(
505
507
  const UploadAndroidUploadKeystoreBody = Schema.Struct({
506
508
  id: Id,
507
509
  ...encryptedEnvelopeFields,
510
+ name: Schema.optional(Schema.String.pipe(Schema.maxLength(200))),
508
511
  keyAlias: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(200)),
509
512
  md5Fingerprint: Schema.optional(Schema.String.pipe(Schema.maxLength(200))),
510
513
  sha1Fingerprint: Schema.optional(Schema.String.pipe(Schema.maxLength(200))),
@@ -21978,6 +21981,7 @@ const generateAndUploadKeystore = (api, input) => Effect.scoped(Effect.gen(funct
21978
21981
  });
21979
21982
  const session = yield* openVaultSessionInteractive(api);
21980
21983
  const metadata = compact({
21984
+ name: input.name,
21981
21985
  keyAlias: input.keyAlias,
21982
21986
  md5Fingerprint: fingerprints.md5,
21983
21987
  sha1Fingerprint: fingerprints.sha1,
@@ -22954,15 +22958,17 @@ const makeAppleTeamLabeler = (teams) => {
22954
22958
  return (internalTeamId) => byId.get(internalTeamId) ?? internalTeamId;
22955
22959
  };
22956
22960
  /**
22957
- * Keystore aliases are often cryptic, so surface the type + creation date in the
22958
- * label and the SHA-1 fingerprint (which matches the Play Console upload key) on
22959
- * the active-row hint.
22961
+ * Aliases collide across white-label apps (many keystores share `jmango`), so
22962
+ * lead with the user-supplied name when present and keep the alias alongside it;
22963
+ * surface the type + creation date in the label and the SHA-1 fingerprint (which
22964
+ * matches the Play Console upload key) on the active-row hint.
22960
22965
  */
22961
22966
  const keystoreChoice = (item) => {
22962
22967
  const details = [item.keystoreType, `created ${isoDate(item.createdAt)}`].filter((part) => part !== null);
22968
+ const title = item.name ? `${item.name} (alias ${item.keyAlias})` : item.keyAlias;
22963
22969
  return {
22964
22970
  value: item.id,
22965
- label: `${item.keyAlias} (${details.join(", ")})`,
22971
+ label: `${title} (${details.join(", ")})`,
22966
22972
  hint: item.sha1Fingerprint ? `SHA-1 ${item.sha1Fingerprint}` : `id ${item.id.slice(0, 8)}…`
22967
22973
  };
22968
22974
  };
@@ -24527,6 +24533,7 @@ const resolveIosStrategy = (profile, projectType) => {
24527
24533
 
24528
24534
  //#endregion
24529
24535
  //#region src/lib/gradle-config.ts
24536
+ const isValidAndroidPackageName = Schema.is(AndroidPackageName);
24530
24537
  /**
24531
24538
  * Parse Groovy `build.gradle` to extract key Android config values.
24532
24539
  * Returns `undefined` if:
@@ -24573,12 +24580,27 @@ const parseVersionCode = (raw) => {
24573
24580
  const extractGradleConfig = (parsed) => {
24574
24581
  const defaultConfig = asRecord(asRecord(parsed["android"])?.["defaultConfig"]);
24575
24582
  return compact({
24576
- applicationId: typeof defaultConfig?.["applicationId"] === "string" ? unquote(defaultConfig["applicationId"]) : void 0,
24583
+ applicationId: extractApplicationId(defaultConfig?.["applicationId"]),
24577
24584
  versionCode: parseVersionCode(defaultConfig?.["versionCode"]),
24578
24585
  versionName: typeof defaultConfig?.["versionName"] === "string" ? unquote(defaultConfig["versionName"]) : void 0
24579
24586
  });
24580
24587
  };
24581
24588
  const unquote = (input) => input.startsWith("\"") && input.endsWith("\"") ? input.slice(1, -1) : input;
24589
+ /**
24590
+ * Extract a usable Android `applicationId` from the parsed Gradle value.
24591
+ *
24592
+ * react-native-config and similar setups make the id dynamic and env-driven
24593
+ * (e.g. `applicationId project.env.get("APP_ID")`, or a `def` variable). The
24594
+ * Groovy parser surfaces the raw expression text (`project.env.get("APP_ID")`,
24595
+ * `appId`, …), which is not a real package name. Treat anything that isn't a
24596
+ * valid reverse-domain package as unresolved so callers fall back to the
24597
+ * Expo/eas config value instead of building with — or validating — junk.
24598
+ */
24599
+ const extractApplicationId = (raw) => {
24600
+ if (typeof raw !== "string") return;
24601
+ const value = unquote(raw);
24602
+ return isValidAndroidPackageName(value) ? value : void 0;
24603
+ };
24582
24604
 
24583
24605
  //#endregion
24584
24606
  //#region src/application/platform-build.ts
@@ -26854,6 +26876,13 @@ const uploadIosPushCertificate = (api, input, bytes) => Effect.gen(function* ()
26854
26876
 
26855
26877
  //#endregion
26856
26878
  //#region src/lib/credentials-manager.ts
26879
+ /** Build a list row, defaulting the optional columns most credential types lack. */
26880
+ const makeRow = (fields) => ({
26881
+ name: null,
26882
+ distribution: null,
26883
+ sha1Fingerprint: null,
26884
+ ...fields
26885
+ });
26857
26886
  const formatDistribution = (value) => value.toLowerCase().replaceAll("_", "-");
26858
26887
  const listAllCredentials = (api) => Effect.gen(function* () {
26859
26888
  const [certs, pushKeys, pushCerts, payCerts, passCerts, ascKeys, profiles, keystores, googleKeys] = yield* Effect.all([
@@ -26868,68 +26897,72 @@ const listAllCredentials = (api) => Effect.gen(function* () {
26868
26897
  api.googleServiceAccountKeys.list()
26869
26898
  ], { concurrency: "unbounded" });
26870
26899
  return [
26871
- ...certs.items.map((cert) => ({
26900
+ ...certs.items.map((cert) => makeRow({
26872
26901
  id: cert.id,
26873
- name: cert.serialNumber,
26902
+ identifier: cert.serialNumber,
26874
26903
  platform: "ios",
26875
26904
  type: "distribution-certificate",
26876
- distribution: null
26905
+ createdAt: cert.createdAt
26877
26906
  })),
26878
- ...pushKeys.items.map((key) => ({
26907
+ ...pushKeys.items.map((key) => makeRow({
26879
26908
  id: key.id,
26880
- name: key.keyId,
26909
+ identifier: key.keyId,
26881
26910
  platform: "ios",
26882
26911
  type: "push-key",
26883
- distribution: null
26912
+ createdAt: key.createdAt
26884
26913
  })),
26885
- ...pushCerts.items.map((cert) => ({
26914
+ ...pushCerts.items.map((cert) => makeRow({
26886
26915
  id: cert.id,
26887
- name: cert.bundleIdentifier,
26916
+ identifier: cert.bundleIdentifier,
26888
26917
  platform: "ios",
26889
26918
  type: "push-certificate",
26890
- distribution: null
26919
+ createdAt: cert.createdAt
26891
26920
  })),
26892
- ...payCerts.items.map((cert) => ({
26921
+ ...payCerts.items.map((cert) => makeRow({
26893
26922
  id: cert.id,
26894
- name: cert.merchantIdentifier,
26923
+ identifier: cert.merchantIdentifier,
26895
26924
  platform: "ios",
26896
26925
  type: "apple-pay-certificate",
26897
- distribution: null
26926
+ createdAt: cert.createdAt
26898
26927
  })),
26899
- ...passCerts.items.map((cert) => ({
26928
+ ...passCerts.items.map((cert) => makeRow({
26900
26929
  id: cert.id,
26901
- name: cert.passTypeIdentifier,
26930
+ identifier: cert.passTypeIdentifier,
26902
26931
  platform: "ios",
26903
26932
  type: "pass-type-certificate",
26904
- distribution: null
26933
+ createdAt: cert.createdAt
26905
26934
  })),
26906
- ...ascKeys.items.map((key) => ({
26935
+ ...ascKeys.items.map((key) => makeRow({
26907
26936
  id: key.id,
26908
26937
  name: key.name,
26938
+ identifier: key.keyId,
26909
26939
  platform: "ios",
26910
26940
  type: "asc-api-key",
26911
- distribution: null
26941
+ createdAt: key.createdAt
26912
26942
  })),
26913
- ...profiles.items.map((profile) => ({
26943
+ ...profiles.items.map((profile) => makeRow({
26914
26944
  id: profile.id,
26915
- name: profile.profileName ?? profile.bundleIdentifier,
26945
+ identifier: profile.profileName ?? profile.bundleIdentifier,
26916
26946
  platform: "ios",
26917
26947
  type: "provisioning-profile",
26918
- distribution: formatDistribution(profile.distributionType)
26948
+ distribution: formatDistribution(profile.distributionType),
26949
+ createdAt: profile.createdAt
26919
26950
  })),
26920
- ...keystores.items.map((ks) => ({
26951
+ ...keystores.items.map((ks) => makeRow({
26921
26952
  id: ks.id,
26922
- name: ks.keyAlias,
26953
+ name: ks.name,
26954
+ identifier: ks.keyAlias,
26923
26955
  platform: "android",
26924
26956
  type: "keystore",
26925
- distribution: null
26957
+ sha1Fingerprint: ks.sha1Fingerprint,
26958
+ createdAt: ks.createdAt
26926
26959
  })),
26927
- ...googleKeys.items.map((key) => ({
26960
+ ...googleKeys.items.map((key) => makeRow({
26928
26961
  id: key.id,
26929
- name: key.clientEmail,
26962
+ identifier: key.clientEmail,
26930
26963
  platform: "android",
26931
26964
  type: "google-service-account-key",
26932
- distribution: null
26965
+ createdAt: key.createdAt
26933
26966
  }))
26934
26967
  ];
26935
26968
  });
@@ -27046,6 +27079,7 @@ const uploadAndroidKeystore = (api, input, bytes) => Effect.gen(function* () {
27046
27079
  storePassword: input.password
27047
27080
  });
27048
27081
  const metadata = compact({
27082
+ name: input.name,
27049
27083
  keyAlias: parsed.keyAlias,
27050
27084
  md5Fingerprint: fingerprints.md5,
27051
27085
  sha1Fingerprint: fingerprints.sha1,
@@ -27224,7 +27258,7 @@ const TYPE_LABELS = {
27224
27258
  keystore: "Android keystore",
27225
27259
  "google-service-account-key": "Google service account key"
27226
27260
  };
27227
- const formatRowLabel$1 = (row) => `${row.name} (${row.id.slice(0, 8)}…)`;
27261
+ const formatRowLabel$1 = (row) => `${row.name ?? row.identifier} (${row.id.slice(0, 8)}…)`;
27228
27262
  const pickAndDelete = (ctx, type, humanLabel) => Effect.gen(function* () {
27229
27263
  const matches = filterCredentials(yield* listAllCredentials(ctx.api), { type });
27230
27264
  if (matches.length === 0) return yield* Console.log(`No ${humanLabel} entries found.`);
@@ -27389,6 +27423,7 @@ const setupAndroidProjectCredentials = (ctx) => Effect.gen(function* () {
27389
27423
  });
27390
27424
  const generateAndroidKeystoreInteractive = (ctx) => Effect.gen(function* () {
27391
27425
  const alias = yield* promptText("Key alias", { placeholder: "upload-key" });
27426
+ const name = yield* promptText("Display name (label shown in lists)", { placeholder: alias });
27392
27427
  const storePassword = yield* promptPassword("Keystore password");
27393
27428
  const keyPassword = yield* promptPassword("Key password");
27394
27429
  const commonName = yield* promptText("Common name (CN)", { placeholder: "Your App" });
@@ -27396,6 +27431,7 @@ const generateAndroidKeystoreInteractive = (ctx) => Effect.gen(function* () {
27396
27431
  yield* Console.log("Generating keystore with keytool...");
27397
27432
  const created = yield* generateAndUploadKeystore(ctx.api, {
27398
27433
  keyAlias: alias,
27434
+ name: name.trim().length > 0 ? name : alias,
27399
27435
  storePassword,
27400
27436
  keyPassword,
27401
27437
  commonName,
@@ -27407,12 +27443,13 @@ const generateAndroidKeystoreInteractive = (ctx) => Effect.gen(function* () {
27407
27443
  const uploadAndroidKeystoreInteractive = (ctx) => Effect.gen(function* () {
27408
27444
  const filePath = yield* promptText("Path to the keystore (.jks/.keystore) file");
27409
27445
  const keyAlias = yield* promptText("Key alias");
27446
+ const name = yield* promptText("Display name (label shown in lists)", { placeholder: keyAlias });
27410
27447
  const storePassword = yield* promptPassword("Keystore password");
27411
27448
  const keyPassword = yield* promptPassword("Key password");
27412
27449
  const created = yield* uploadCredential(ctx.api, {
27413
27450
  platform: "android",
27414
27451
  type: "keystore",
27415
- name: keyAlias,
27452
+ name: name.trim().length > 0 ? name : keyAlias,
27416
27453
  filePath,
27417
27454
  keyAlias,
27418
27455
  keyPassword,
@@ -29448,13 +29485,17 @@ const resolveKeystoreInput = (args) => Effect.gen(function* () {
29448
29485
  const commonName = args["common-name"] !== void 0 && args["common-name"].trim().length > 0 ? args["common-name"] : yield* promptText("Common name (CN)", { placeholder: "Your App" });
29449
29486
  const organization = args.organization !== void 0 && args.organization.trim().length > 0 ? args.organization : yield* promptText("Organization (O)", { placeholder: "Your Company" });
29450
29487
  const validityDays = yield* parseValidityDays(args["validity-days"]);
29488
+ const name = args.name !== void 0 && args.name.trim().length > 0 ? args.name : void 0;
29451
29489
  return {
29452
29490
  alias: yield* ensureNonEmpty(alias, "alias"),
29453
29491
  storePassword: yield* ensureNonEmpty(storePassword, "store-password"),
29454
29492
  keyPassword: yield* ensureNonEmpty(keyPassword, "key-password"),
29455
29493
  commonName: yield* ensureNonEmpty(commonName, "common-name"),
29456
29494
  organization: yield* ensureNonEmpty(organization, "organization"),
29457
- ...compact({ validityDays })
29495
+ ...compact({
29496
+ validityDays,
29497
+ name
29498
+ })
29458
29499
  };
29459
29500
  });
29460
29501
  const keystoreCommand = defineCommand({
@@ -29463,6 +29504,10 @@ const keystoreCommand = defineCommand({
29463
29504
  description: "Generate a new Android upload keystore via keytool and store it server-side"
29464
29505
  },
29465
29506
  args: {
29507
+ name: {
29508
+ type: "string",
29509
+ description: "Display name (label shown in `credentials list`)"
29510
+ },
29466
29511
  alias: {
29467
29512
  type: "string",
29468
29513
  description: "Key alias"
@@ -29498,7 +29543,10 @@ const keystoreCommand = defineCommand({
29498
29543
  keyPassword: resolved.keyPassword,
29499
29544
  commonName: resolved.commonName,
29500
29545
  organization: resolved.organization,
29501
- ...compact({ validityDays: resolved.validityDays })
29546
+ ...compact({
29547
+ validityDays: resolved.validityDays,
29548
+ name: resolved.name
29549
+ })
29502
29550
  });
29503
29551
  yield* printHuman("");
29504
29552
  yield* printHuman("Keystore generated and uploaded.");
@@ -29893,15 +29941,19 @@ const listCommand$4 = defineCommand({
29893
29941
  yield* printList([
29894
29942
  "ID",
29895
29943
  "Name",
29944
+ "Identifier",
29896
29945
  "Platform",
29897
29946
  "Type",
29898
- "Distribution"
29947
+ "Created",
29948
+ "SHA-1"
29899
29949
  ], filterCredentials(yield* listAllCredentials(yield* apiClient), args.platform ? { platform: args.platform } : {}).map((row) => [
29900
29950
  row.id,
29901
- row.name,
29951
+ row.name ?? "-",
29952
+ row.identifier,
29902
29953
  row.platform,
29903
29954
  row.type,
29904
- row.distribution ?? "-"
29955
+ isoDate(row.createdAt),
29956
+ row.sha1Fingerprint ?? "-"
29905
29957
  ]), "No credentials found.");
29906
29958
  }))
29907
29959
  });
@@ -30012,8 +30064,9 @@ const CREDENTIAL_TYPES$2 = [
30012
30064
  const isPlatform = (value) => value === "ios" || value === "android";
30013
30065
  const isType = (value) => CREDENTIAL_TYPES$2.includes(value);
30014
30066
  const formatRowLabel = (row) => {
30067
+ const label = row.name ? `${row.name} (${row.identifier})` : row.identifier;
30015
30068
  const distro = row.distribution ? ` (${row.distribution})` : "";
30016
- return `${row.type}: ${row.name}${distro} — ${row.id.slice(0, 8)}…`;
30069
+ return `${row.type}: ${label}${distro} — ${row.id.slice(0, 8)}…`;
30017
30070
  };
30018
30071
  const removeCommand = defineCommand({
30019
30072
  meta: {
@@ -31183,7 +31236,12 @@ const viewKeystore = (api, id) => Effect.gen(function* () {
31183
31236
  pairs: [
31184
31237
  ["ID", item.id],
31185
31238
  ["Type", "Android upload keystore"],
31239
+ ["Name", item.name ?? "-"],
31186
31240
  ["Key alias", item.keyAlias],
31241
+ ["Keystore type", item.keystoreType ?? "-"],
31242
+ ["SHA-1", item.sha1Fingerprint ?? "-"],
31243
+ ["SHA-256", item.sha256Fingerprint ?? "-"],
31244
+ ["MD5", item.md5Fingerprint ?? "-"],
31187
31245
  ["Created", item.createdAt],
31188
31246
  ["Updated", item.updatedAt]
31189
31247
  ],