@better-update/cli 0.33.1 → 0.34.0

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
@@ -34,7 +34,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
34
34
 
35
35
  //#endregion
36
36
  //#region package.json
37
- var version = "0.33.1";
37
+ var version = "0.34.0";
38
38
 
39
39
  //#endregion
40
40
  //#region src/lib/interactive-mode.ts
@@ -355,7 +355,15 @@ var OrgVault = class extends Schema.Class("OrgVault")({
355
355
  organizationId: Id,
356
356
  vaultVersion: VaultVersion,
357
357
  createdAt: DateTimeString,
358
- updatedAt: DateTimeString
358
+ updatedAt: DateTimeString,
359
+ /**
360
+ * A recipient was dropped out-of-band (member removed/downgraded); the live key
361
+ * is considered compromised and must be rotated. While true, credential-download
362
+ * paths fail closed (409). `rotate` clears it.
363
+ */
364
+ rotationPending: Schema.Boolean,
365
+ rotationPendingSince: Schema.NullOr(DateTimeString),
366
+ rotationPendingReason: Schema.NullOr(Schema.String)
359
367
  }) {};
360
368
  /**
361
369
  * One wrap of the org vault key to a recipient's public key — an `age` blob the
@@ -1045,7 +1053,7 @@ const projectIdParam$5 = HttpApiSchema.param("projectId", Schema.String);
1045
1053
  var BuildCredentialsGroup = class extends HttpApiGroup.make("buildCredentials").add(HttpApiEndpoint.post("resolve")`/api/projects/${projectIdParam$5}/build-credentials/resolve`.setPayload(ResolveBuildCredentialsBody).addSuccess(ResolveBuildCredentialsResult).annotateContext(OpenApi.annotations({
1046
1054
  title: "Resolve build credentials",
1047
1055
  description: "Return decrypted signing assets for a project build. Regenerates the iOS provisioning profile via Apple ASC when the registered device roster has changed since the profile was last generated."
1048
- }))).addError(NotFound).addError(BadRequest).addError(Forbidden).annotateContext(OpenApi.annotations({
1056
+ }))).addError(NotFound).addError(BadRequest).addError(Forbidden).addError(Conflict).annotateContext(OpenApi.annotations({
1049
1057
  title: "Build Credentials",
1050
1058
  description: "Materialize signing assets needed by a CLI build run"
1051
1059
  })) {};
@@ -19985,7 +19993,6 @@ const DISTRIBUTION_TO_CERTIFICATE_TYPE = {
19985
19993
  DEVELOPMENT: AppleUtils.CertificateType.IOS_DEVELOPMENT
19986
19994
  };
19987
19995
  var AppleIdGenerateFailedError = class extends Data.TaggedError("AppleIdGenerateFailedError") {};
19988
- var ApnsKeyLimitError = class extends Data.TaggedError("ApnsKeyLimitError") {};
19989
19996
  const CERT_LIMIT_PATTERN = /already have a current.*certificate|pending certificate request/iu;
19990
19997
  const messageOf = (cause) => cause instanceof Error ? cause.message : String(cause);
19991
19998
  const wrap = (step, run) => Effect.tryPromise({
@@ -20130,8 +20137,12 @@ const generateAndUploadProvisioningProfileViaAppleId = (api, input) => Effect.ge
20130
20137
  developerPortalIdentifier: created.developerPortalIdentifier
20131
20138
  };
20132
20139
  });
20140
+
20141
+ //#endregion
20142
+ //#region src/lib/credentials-generator-apns.ts
20133
20143
  const APNS_SERVICE_ID = "U27F4V844T";
20134
20144
  const APNS_KEY_LIMIT_PATTERN = /maximum allowed number of .*keys/iu;
20145
+ var ApnsKeyLimitError = class extends Data.TaggedError("ApnsKeyLimitError") {};
20135
20146
  const wrapKeyCreate = (run) => Effect.tryPromise({
20136
20147
  try: run,
20137
20148
  catch: (cause) => {
@@ -20169,7 +20180,8 @@ const generateAndUploadApnsKeyViaAppleId = (api, input) => Effect.gen(function*
20169
20180
  });
20170
20181
  return yield* api.applePushKeys.upload({ payload: {
20171
20182
  ...toUploadEnvelope(envelope),
20172
- ...metadata
20183
+ ...metadata,
20184
+ ...compact({ appleTeamName: toOptional(input.appleTeamName) })
20173
20185
  } });
20174
20186
  }).pipe(Effect.catchAll((cause) => Effect.gen(function* () {
20175
20187
  const rescuePath = yield* writeRescueP8(key.id, p8Pem).pipe(Effect.catchAll(() => Effect.succeed(null)));
@@ -20308,6 +20320,7 @@ const createApnsKeyViaAppleId = (api, name) => Effect.gen(function* () {
20308
20320
  const generate = generateAndUploadApnsKeyViaAppleId(api, {
20309
20321
  context: ctx,
20310
20322
  appleTeamIdentifier: session.teamId,
20323
+ appleTeamName: session.teamName,
20311
20324
  name
20312
20325
  });
20313
20326
  return yield* generate.pipe(Effect.catchTag("ApnsKeyLimitError", () => apnsKeyLimitRecover(ctx).pipe(Effect.flatMap(() => generate))));
@@ -22274,12 +22287,14 @@ const exportDecryptedEnvVars = (api, projectId, environment) => Effect.gen(funct
22274
22287
  });
22275
22288
  /**
22276
22289
  * Pull + decrypt environment variables flattened into a key/value map for
22277
- * injection into a build/subprocess.
22290
+ * injection into a build/subprocess. Reports which variables were loaded (names
22291
+ * only — values stay secret) so users can see what the server contributed.
22278
22292
  */
22279
22293
  const pullEnvVars = (api, { projectId, environment }) => Effect.gen(function* () {
22280
22294
  const validated = coerceEnvironment(environment);
22281
22295
  if (!validated) return yield* new EnvExportError({ message: `Invalid environment "${environment}": must be lowercase letters, digits, and hyphens, starting with a letter.` });
22282
22296
  const items = yield* exportDecryptedEnvVars(api, projectId, validated);
22297
+ yield* printHuman(items.length === 0 ? `No environment variables found for the "${validated}" environment.` : `Environment variables loaded from the "${validated}" environment: ${items.map((item) => item.key).join(", ")}`);
22283
22298
  return Object.fromEntries(items.map((item) => [item.key, item.value]));
22284
22299
  });
22285
22300
  /**
@@ -22547,13 +22562,14 @@ const inferPlatforms = (config) => {
22547
22562
  };
22548
22563
  /**
22549
22564
  * Resolve a build platform from an explicit flag, or fall back to the Expo
22550
- * config (`expo.platforms` or the presence of `ios`/`android` sections). Prompts
22551
- * when the config declares both platforms; fails when ambiguous and prompts are
22552
- * disallowed.
22565
+ * config (`expo.platforms` or the presence of `ios`/`android` sections). The
22566
+ * config is loaded lazily so an explicit `--platform` skips evaluating
22567
+ * `app.config.js`/`.ts` entirely. Prompts when the config declares both
22568
+ * platforms; fails when ambiguous and prompts are disallowed.
22553
22569
  */
22554
- const detectPlatform = (explicit, config) => Effect.gen(function* () {
22570
+ const detectPlatform = (explicit, loadConfig) => Effect.gen(function* () {
22555
22571
  if (explicit !== void 0) return explicit;
22556
- const candidates = inferPlatforms(config);
22572
+ const candidates = inferPlatforms(yield* loadConfig);
22557
22573
  if (candidates.length === 0) return yield* new BuildProfileError({ message: "Cannot infer build platform. Add an `ios` or `android` section to your Expo config, or pass --platform." });
22558
22574
  if (candidates.length === 1) {
22559
22575
  const [only] = candidates;
@@ -23675,11 +23691,6 @@ const runBuildWorkflow = (options) => Effect.scoped(Effect.gen(function* () {
23675
23691
  const projectId = yield* readProjectId;
23676
23692
  const profile = yield* readBuildProfile(userCwd, yield* resolveProfileName(userCwd, options.profileName));
23677
23693
  if (profile.developmentClient === true) yield* warnIfDevClientMissing(userCwd);
23678
- const platform = isExpo ? yield* detectPlatform(options.platform, yield* readExpoConfig(userCwd)) : yield* detectPlatformGeneric(options.platform, {
23679
- profile,
23680
- hasAndroidDir: yield* dirExists(userCwd, "android"),
23681
- hasIosDir: yield* dirExists(userCwd, "ios")
23682
- });
23683
23694
  const envVars = {
23684
23695
  ...yield* pullEnvVars(api, {
23685
23696
  projectId,
@@ -23687,6 +23698,11 @@ const runBuildWorkflow = (options) => Effect.scoped(Effect.gen(function* () {
23687
23698
  }),
23688
23699
  ...profile.env
23689
23700
  };
23701
+ const platform = isExpo ? yield* detectPlatform(options.platform, readExpoConfig(userCwd, envVars)) : yield* detectPlatformGeneric(options.platform, {
23702
+ profile,
23703
+ hasAndroidDir: yield* dirExists(userCwd, "android"),
23704
+ hasIosDir: yield* dirExists(userCwd, "ios")
23705
+ });
23690
23706
  const { appMeta, runtimeVersion } = isExpo ? yield* resolveExpoBuildMeta({
23691
23707
  userCwd,
23692
23708
  platform,
@@ -26837,9 +26853,14 @@ const listCommand$6 = defineCommand({
26837
26853
  },
26838
26854
  run: async () => runEffect(Effect.gen(function* () {
26839
26855
  const api = yield* apiClient;
26840
- const [{ recipients, vaultVersion }, { items }] = yield* Effect.all([api.orgVault.listWraps(), api.userEncryptionKeys.list()]);
26856
+ const [{ recipients, vaultVersion }, { items }, vault] = yield* Effect.all([
26857
+ api.orgVault.listWraps(),
26858
+ api.userEncryptionKeys.list(),
26859
+ api.orgVault.get()
26860
+ ]);
26841
26861
  const byId = new Map(items.map((key) => [key.id, key]));
26842
26862
  yield* printHuman(`Vault version ${vaultVersion}`);
26863
+ if (vault.rotationPending) yield* printHuman(`⚠ Rotation pending — a recipient was removed (${vault.rotationPendingReason ?? "vault access revoked"}). Credential downloads are blocked until you run \`credentials access rotate\`.`);
26843
26864
  yield* printHumanList([
26844
26865
  "Key ID",
26845
26866
  "Kind",
@@ -26856,6 +26877,7 @@ const listCommand$6 = defineCommand({
26856
26877
  }), "No recipients hold the vault key yet.");
26857
26878
  return {
26858
26879
  vaultVersion,
26880
+ rotationPending: vault.rotationPending,
26859
26881
  recipients: recipients.map((recipient) => toRecipientView(recipient.userEncryptionKeyId, byId.get(recipient.userEncryptionKeyId)))
26860
26882
  };
26861
26883
  }), { json: "value" })