hot-updater 1.0.0 → 1.0.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.
Files changed (24) hide show
  1. package/dist/index.mjs +240 -76
  2. package/dist/infra-templates/aws/lambda/index.cjs +1 -1
  3. package/dist/infra-templates/aws/template.json +10 -10
  4. package/dist/infra-templates/cloudflare/template.json +10 -10
  5. package/dist/infra-templates/cloudflare/worker/dist/README.md +1 -1
  6. package/dist/infra-templates/cloudflare/worker/dist/index.js +1 -1
  7. package/dist/infra-templates/cloudflare/worker/dist/index.js.map +2 -2
  8. package/dist/infra-templates/firebase/ENVIRONMENT.md +2 -1
  9. package/dist/infra-templates/firebase/SETUP.md +19 -8
  10. package/dist/infra-templates/firebase/app/hot-updater.config.bare.ts +1 -0
  11. package/dist/infra-templates/firebase/app/hot-updater.config.expo.ts +1 -0
  12. package/dist/infra-templates/firebase/app/hot-updater.config.rock.ts +1 -0
  13. package/dist/infra-templates/firebase/app/hotUpdater.ts +1 -0
  14. package/dist/infra-templates/firebase/firebase/firebase.json +2 -1
  15. package/dist/infra-templates/firebase/firebase/functions/index.cjs +8 -4
  16. package/dist/infra-templates/firebase/template.json +17 -11
  17. package/dist/infra-templates/supabase/supabase/functions/hot-updater-v1/_hot-updater/hot-updater-protocol/dist/index.cjs +5 -0
  18. package/dist/infra-templates/supabase/supabase/functions/hot-updater-v1/_hot-updater/hot-updater-protocol/dist/index.d.cts +14 -0
  19. package/dist/infra-templates/supabase/supabase/functions/hot-updater-v1/_hot-updater/hot-updater-protocol/dist/index.d.mts +14 -0
  20. package/dist/infra-templates/supabase/supabase/functions/hot-updater-v1/_hot-updater/hot-updater-protocol/dist/index.mjs +5 -0
  21. package/dist/infra-templates/supabase/supabase/functions/hot-updater-v1/_hot-updater/hot-updater-server/dist/package.cjs +1 -1
  22. package/dist/infra-templates/supabase/supabase/functions/hot-updater-v1/_hot-updater/hot-updater-server/dist/package.mjs +1 -1
  23. package/dist/infra-templates/supabase/template.json +10 -10
  24. package/package.json +20 -20
package/dist/index.mjs CHANGED
@@ -3870,26 +3870,112 @@ async function handleAgentInfra(operation, options) {
3870
3870
  await handleInfraScaffold(operation, options);
3871
3871
  }
3872
3872
  //#endregion
3873
- //#region src/utils/version/getAndroidVersion.ts
3874
- const getAndroidVersionFromAppBuildGradle = async () => {
3875
- const buildGradlePath = path.join(getCwd(), "android", "app", "build.gradle");
3876
- try {
3877
- return (await fs$3.readFile(buildGradlePath, "utf8")).match(/versionName\s+['"]([^"]+)['"]/)?.[1] ?? null;
3878
- } catch {
3879
- return null;
3880
- }
3873
+ //#region src/utils/version/appVersionCandidates.ts
3874
+ /** One version only when every candidate declares the same literal. */
3875
+ const resolveFromCandidates = (candidates) => {
3876
+ const versions = new Set(candidates.map((candidate) => candidate.version));
3877
+ const [version] = versions;
3878
+ return {
3879
+ version: versions.size === 1 && version ? version : null,
3880
+ candidates
3881
+ };
3881
3882
  };
3882
- const AndroidVersionParsers = { "app-build-gradle": getAndroidVersionFromAppBuildGradle };
3883
- const getAndroidVersion = async ({ parser, validateWithSemver = false }) => {
3884
- const parsers = Array.isArray(parser) ? parser : [parser];
3885
- for (const parserKey of parsers) {
3886
- const parsedVersion = await AndroidVersionParsers[parserKey]();
3887
- if (!parsedVersion) continue;
3888
- if (validateWithSemver && !normalizeRange(parsedVersion)) continue;
3889
- return parsedVersion;
3883
+ /** Several candidates and no single version: the caller must pick one. */
3884
+ const isAmbiguousAppVersion = ({ version, candidates }) => version === null && candidates.length > 1;
3885
+ const formatAppVersionCandidates = (candidates) => candidates.map(({ label, version }) => `${label}: ${version ?? "unresolved"}`).join(", ");
3886
+ //#endregion
3887
+ //#region src/utils/version/getAndroidVersion.ts
3888
+ const stripComments = (source) => source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
3889
+ /** The body of the `{ ... }` block that opens at or after `from`. */
3890
+ const readBlock = (source, from) => {
3891
+ const open = source.indexOf("{", from);
3892
+ if (open === -1) return null;
3893
+ let depth = 0;
3894
+ for (let index = open; index < source.length; index++) {
3895
+ if (source[index] === "{") depth++;
3896
+ if (source[index] === "}" && --depth === 0) return {
3897
+ body: source.slice(open + 1, index),
3898
+ end: index + 1
3899
+ };
3890
3900
  }
3891
3901
  return null;
3892
3902
  };
3903
+ /** The top-level `name { ... }` blocks in a block body. */
3904
+ const readNamedBlocks = (body) => {
3905
+ const blocks = [];
3906
+ const header = /(?:create\(\s*["']([\w-]+)["']\s*\)|([\w-]+))\s*\{/g;
3907
+ let match;
3908
+ while (match = header.exec(body)) {
3909
+ const block = readBlock(body, match.index);
3910
+ if (!block) break;
3911
+ blocks.push({
3912
+ name: match[1] ?? match[2],
3913
+ body: block.body
3914
+ });
3915
+ header.lastIndex = block.end;
3916
+ }
3917
+ return blocks;
3918
+ };
3919
+ /** The first block called `name`, in file order, at any depth. */
3920
+ const findBlock = (source, name) => readNamedBlocks(source).flatMap((block) => block.name === name ? [block] : [findBlock(block.body, name)]).find((block) => block !== void 0);
3921
+ /** A literal setting declared directly in a block body; null when not literal. */
3922
+ const readSetting = (body, setting) => {
3923
+ const match = readNamedBlocks(body).reduce((rest, block) => rest.replace(block.body, ""), body).match(new RegExp(`\\b${setting}\\b\\s*=?\\s*(?:(['"])([^'"]*)\\1|(\\S+))`));
3924
+ if (!match) return void 0;
3925
+ return match[2] || null;
3926
+ };
3927
+ const capitalize = (value) => value.charAt(0).toUpperCase() + value.slice(1);
3928
+ /**
3929
+ * Whether a variant builds a flavor: `stagingRelease` builds `staging`, and
3930
+ * with flavor dimensions `brandAStagingRelease` builds `brandA` and `staging`.
3931
+ */
3932
+ const variantBuildsFlavor = (variant, flavor) => new RegExp(`${capitalize(flavor)}(?=[A-Z]|$)`).test(capitalize(variant));
3933
+ /**
3934
+ * Reads versionName from defaultConfig and from each product flavor, so an
3935
+ * app whose flavors (brands, environments) override the version is reported
3936
+ * as ambiguous instead of resolving to the first versionName in the file.
3937
+ */
3938
+ const getAndroidVersionFromAppBuildGradle = async (scope = {}) => {
3939
+ const buildGradlePath = path.join(getCwd(), "android", scope.appModuleName ?? "app", "build.gradle");
3940
+ let buildGradle;
3941
+ try {
3942
+ buildGradle = stripComments(await fs$3.readFile(buildGradlePath, "utf8"));
3943
+ } catch {
3944
+ return {
3945
+ version: null,
3946
+ candidates: []
3947
+ };
3948
+ }
3949
+ const android = findBlock(buildGradle, "android")?.body ?? "";
3950
+ const defaultConfig = findBlock(android, "defaultConfig");
3951
+ const defaultVersion = defaultConfig ? readSetting(defaultConfig.body, "versionName") : void 0;
3952
+ const flavorsBlock = findBlock(android, "productFlavors");
3953
+ const flavors = (flavorsBlock ? readNamedBlocks(flavorsBlock.body) : []).map((flavor) => ({
3954
+ name: flavor.name,
3955
+ applicationId: readSetting(flavor.body, "applicationId"),
3956
+ versionName: readSetting(flavor.body, "versionName")
3957
+ }));
3958
+ const defaultCandidate = defaultVersion === void 0 ? [] : [{
3959
+ label: "defaultConfig",
3960
+ version: defaultVersion
3961
+ }];
3962
+ const flavorCandidates = (flavorList) => flavorList.flatMap((flavor) => flavor.versionName === void 0 ? [] : [{
3963
+ label: `${flavor.name} flavor`,
3964
+ version: flavor.versionName
3965
+ }]);
3966
+ const { variant, applicationId } = scope;
3967
+ if (variant || applicationId) {
3968
+ const builtFlavors = flavors.filter((flavor) => applicationId !== void 0 && flavor.applicationId === applicationId || variant !== void 0 && variantBuildsFlavor(variant, flavor.name));
3969
+ if (builtFlavors.length > 0) {
3970
+ const overrides = flavorCandidates(builtFlavors);
3971
+ return resolveFromCandidates(overrides.length > 0 ? overrides : defaultCandidate);
3972
+ }
3973
+ }
3974
+ const overrides = flavorCandidates(flavors);
3975
+ const everyFlavorOverrides = flavors.length > 0 && overrides.length === flavors.length;
3976
+ return resolveFromCandidates([...everyFlavorOverrides ? [] : defaultCandidate, ...overrides]);
3977
+ };
3978
+ const resolveAndroidAppVersion = (scope) => getAndroidVersionFromAppBuildGradle(scope);
3893
3979
  //#endregion
3894
3980
  //#region ../../node_modules/.pnpm/@bacons+xcode@1.0.0-alpha.33/node_modules/@bacons/xcode/build/api/utils/constants.js
3895
3981
  var require_constants = /* @__PURE__ */ __commonJSMin(((exports) => {
@@ -19406,81 +19492,138 @@ const isFileExist = async (path) => {
19406
19492
  return false;
19407
19493
  }
19408
19494
  };
19409
- const getIOSVersionFromInfoPlist = async () => {
19495
+ const isResolved = (value) => typeof value === "string" && value.length > 0 && !value.includes("$(");
19496
+ const readInfoPlistVersion = async (plistPath) => {
19410
19497
  try {
19411
- const iosAppTargetDirectory = getIosAppTargetDirectoryName();
19412
- if (!iosAppTargetDirectory) return null;
19413
- const plistPath = path.join(getCwd(), "ios", iosAppTargetDirectory, "Info.plist");
19414
19498
  if (!await isFileExist(plistPath)) return null;
19415
19499
  const fileBuffer = await fs$3.readFile(plistPath);
19416
19500
  const appVersion = parsePlist(fileBuffer)["CFBundleShortVersionString"];
19417
- if (typeof appVersion !== "string" || appVersion.includes("$(")) return null;
19418
- return appVersion;
19501
+ return isResolved(appVersion) ? appVersion : null;
19419
19502
  } catch {
19420
19503
  return null;
19421
19504
  }
19422
19505
  };
19423
- const getIOSVersionFromXcodeProject = async () => {
19506
+ const getIOSVersionFromInfoPlist = async () => {
19507
+ const iosAppTargetDirectory = getIosAppTargetDirectoryName();
19508
+ if (!iosAppTargetDirectory) return null;
19509
+ return readInfoPlistVersion(path.join(getCwd(), "ios", iosAppTargetDirectory, "Info.plist"));
19510
+ };
19511
+ const APPLICATION_PRODUCT_TYPE = "com.apple.product-type.application";
19512
+ /**
19513
+ * Reads MARKETING_VERSION per application target, so a project whose targets
19514
+ * (brands, environments) ship different versions is reported as ambiguous
19515
+ * instead of resolving to whichever configuration comes first in the file.
19516
+ */
19517
+ const getIOSVersionFromXcodeProject = async (scope = {}) => {
19518
+ const notFound = {
19519
+ version: null,
19520
+ candidates: []
19521
+ };
19424
19522
  try {
19523
+ const iosDirectory = path.join(getCwd(), "ios");
19425
19524
  const [xcodeprojPath] = import_out.default.globSync("*.xcodeproj/project.pbxproj", {
19426
- cwd: path.join(getCwd(), "ios"),
19525
+ cwd: iosDirectory,
19427
19526
  absolute: true,
19428
19527
  onlyFiles: true
19429
19528
  });
19430
- if (!xcodeprojPath) return null;
19431
- const objects = import_build.XcodeProject.open(xcodeprojPath).toJSON().objects ?? {};
19432
- for (const key of Object.keys(objects)) {
19433
- const obj = objects[key];
19434
- if (!obj || typeof obj !== "object") continue;
19435
- const record = obj;
19436
- if (record.isa !== "XCBuildConfiguration" || record.name !== "Release") continue;
19437
- const marketingVersion = record.buildSettings?.MARKETING_VERSION;
19438
- if (marketingVersion) return marketingVersion;
19439
- }
19440
- return null;
19529
+ if (!xcodeprojPath) return notFound;
19530
+ const project = import_build.XcodeProject.open(xcodeprojPath).toJSON();
19531
+ const objects = project.objects ?? {};
19532
+ const configurationName = scope.configuration ?? "Release";
19533
+ const findConfiguration = (listId) => (listId ? objects[listId]?.buildConfigurations ?? [] : []).map((id) => objects[id]).find((config) => config?.name === configurationName);
19534
+ const rootProject = project.rootObject ? objects[project.rootObject] : void 0;
19535
+ const projectSettings = findConfiguration(rootProject?.buildConfigurationList)?.buildSettings ?? {};
19536
+ const appTargets = (rootProject?.targets ?? []).map((id) => objects[id]).filter((target) => target?.isa === "PBXNativeTarget" && target.productType === APPLICATION_PRODUCT_TYPE).map((target) => {
19537
+ const settings = {
19538
+ ...projectSettings,
19539
+ ...findConfiguration(target.buildConfigurationList)?.buildSettings
19540
+ };
19541
+ const infoPlistFile = typeof settings.INFOPLIST_FILE === "string" ? settings.INFOPLIST_FILE.replace("$(SRCROOT)", iosDirectory) : void 0;
19542
+ return {
19543
+ name: target.name ?? "unknown",
19544
+ bundleIdentifier: settings.PRODUCT_BUNDLE_IDENTIFIER,
19545
+ marketingVersion: settings.MARKETING_VERSION,
19546
+ infoPlistPath: isResolved(infoPlistFile) ? path.resolve(iosDirectory, infoPlistFile) : void 0
19547
+ };
19548
+ });
19549
+ if (appTargets.length === 0) {
19550
+ const candidates = Object.values(objects).filter((object) => object?.isa === "XCBuildConfiguration" && object.name === configurationName && object.buildSettings?.MARKETING_VERSION !== void 0).map((object) => ({
19551
+ label: configurationName,
19552
+ version: isResolved(object?.buildSettings?.MARKETING_VERSION) ? object.buildSettings.MARKETING_VERSION : null
19553
+ }));
19554
+ return resolveFromCandidates(candidates);
19555
+ }
19556
+ const scopedTargets = scope.scheme || scope.bundleIdentifier ? appTargets.filter((target) => target.name === scope.scheme || scope.bundleIdentifier !== void 0 && target.bundleIdentifier === scope.bundleIdentifier) : [];
19557
+ const targets = scopedTargets.length > 0 ? scopedTargets : appTargets;
19558
+ return resolveFromCandidates(await Promise.all(targets.map(async (target) => ({
19559
+ label: `${target.name} (${configurationName})`,
19560
+ version: (target.infoPlistPath ? await readInfoPlistVersion(target.infoPlistPath) : null) ?? (isResolved(target.marketingVersion) ? target.marketingVersion : null)
19561
+ }))));
19441
19562
  } catch {
19442
- return null;
19563
+ return notFound;
19443
19564
  }
19444
19565
  };
19445
- const IOSVersionParsers = {
19446
- xcodeproj: getIOSVersionFromXcodeProject,
19447
- "info-plist": getIOSVersionFromInfoPlist
19448
- };
19449
- const getIOSVersion = async ({ parser, validateWithSemver = false }) => {
19450
- const parsers = Array.isArray(parser) ? parser : [parser];
19451
- for (const parserKey of parsers) {
19452
- const parsedVersion = await IOSVersionParsers[parserKey]();
19453
- if (!parsedVersion) continue;
19454
- if (validateWithSemver && !normalizeRange(parsedVersion)) continue;
19455
- return parsedVersion;
19456
- }
19457
- return null;
19566
+ /**
19567
+ * The iOS app version: Info.plist first, project.pbxproj as a fallback.
19568
+ *
19569
+ * CFBundleShortVersionString is the version the built app actually reports,
19570
+ * so it is the more correct source (#84). It is also far cheaper: reading
19571
+ * Info.plist is a small file read, whereas the pbxproj parser is synchronous
19572
+ * and blocks the event loop for the length of the parse. On a large
19573
+ * project.pbxproj that can take minutes. The React Native template ships
19574
+ * Info.plist with CFBundleShortVersionString set to "$(MARKETING_VERSION)",
19575
+ * which the plist parser cannot resolve, so the real version only lives in
19576
+ * project.pbxproj for most projects.
19577
+ */
19578
+ const resolveIOSAppVersion = async (scope) => {
19579
+ const plistVersion = await getIOSVersionFromInfoPlist();
19580
+ if (plistVersion) return {
19581
+ version: plistVersion,
19582
+ candidates: [{
19583
+ label: "Info.plist",
19584
+ version: plistVersion
19585
+ }]
19586
+ };
19587
+ return getIOSVersionFromXcodeProject(scope);
19458
19588
  };
19459
19589
  //#endregion
19460
19590
  //#region src/utils/version/getNativeAppVersion.ts
19461
- const getNativeAppVersion = async (platform) => {
19591
+ /**
19592
+ * The version the native project builds, with every place it is declared.
19593
+ * A project that builds several apps (Xcode targets, product flavors) with
19594
+ * different versions resolves to null unless `scope` names the one built.
19595
+ */
19596
+ const resolveNativeAppVersion = async (platform, scope = {}) => {
19462
19597
  switch (platform) {
19463
- case "ios": return getIOSVersion({ parser: ["info-plist", "xcodeproj"] });
19464
- case "android": return getAndroidVersion({ parser: "app-build-gradle" });
19465
- default: return null;
19598
+ case "ios": return resolveIOSAppVersion(scope.ios);
19599
+ case "android": return resolveAndroidAppVersion(scope.android);
19600
+ default: return {
19601
+ version: null,
19602
+ candidates: []
19603
+ };
19466
19604
  }
19467
19605
  };
19606
+ const getNativeAppVersion = async (platform, scope) => (await resolveNativeAppVersion(platform, scope)).version;
19468
19607
  //#endregion
19469
19608
  //#region src/commands/appVersion.ts
19470
19609
  const readAppVersions = async () => {
19471
- const [androidVersion, iosVersion] = await Promise.all([getNativeAppVersion("android"), getNativeAppVersion("ios")]);
19610
+ const [android, ios] = await Promise.all([resolveNativeAppVersion("android"), resolveNativeAppVersion("ios")]);
19472
19611
  return {
19473
- android: androidVersion,
19474
- ios: iosVersion
19612
+ android,
19613
+ ios
19475
19614
  };
19476
19615
  };
19616
+ const formatVersion = (resolved) => isAmbiguousAppVersion(resolved) ? ui.warning(`several (${formatAppVersionCandidates(resolved.candidates)}); deploy needs -t`) : ui.version(resolved.version);
19477
19617
  const handleAppVersion = async (options = {}) => {
19478
19618
  const versions = await readAppVersions();
19479
19619
  if (options.json) {
19480
- console.log(JSON.stringify(versions, null, 2));
19620
+ console.log(JSON.stringify({
19621
+ android: versions.android.version,
19622
+ ios: versions.ios.version
19623
+ }, null, 2));
19481
19624
  return;
19482
19625
  }
19483
- p.log.message(ui.block("App version", [ui.kv("Android", ui.version(versions.android)), ui.kv("iOS", ui.version(versions.ios))]));
19626
+ p.log.message(ui.block("App version", [ui.kv("Android", formatVersion(versions.android)), ui.kv("iOS", formatVersion(versions.ios))]));
19484
19627
  };
19485
19628
  //#endregion
19486
19629
  //#region ../../node_modules/.pnpm/is-plain-obj@4.1.0/node_modules/is-plain-obj/index.js
@@ -25767,11 +25910,25 @@ async function prepareNativeBuild(options) {
25767
25910
  } else if (config.updateStrategy === "appVersion") {
25768
25911
  const s = p.spinner();
25769
25912
  s.start(`Get native app version (${platform})`);
25770
- const appVersion = await getNativeAppVersion(platform);
25913
+ const iosScheme = config.nativeBuild.ios[scheme];
25914
+ const androidScheme = config.nativeBuild.android[scheme];
25915
+ const resolved = await resolveNativeAppVersion(platform, {
25916
+ ios: iosScheme && {
25917
+ scheme: iosScheme.scheme,
25918
+ bundleIdentifier: iosScheme.bundleIdentifier,
25919
+ configuration: iosScheme.configuration
25920
+ },
25921
+ android: androidScheme && {
25922
+ variant: androidScheme.variant,
25923
+ applicationId: androidScheme.applicationId ?? androidScheme.packageName,
25924
+ appModuleName: androidScheme.appModuleName
25925
+ }
25926
+ });
25927
+ const appVersion = resolved.version;
25771
25928
  s.stop(`App Version(${platform}): ${appVersion}`);
25772
25929
  target.appVersion = appVersion;
25773
25930
  if (!target.appVersion) {
25774
- p.log.error(`Failed to retrieve native app version of ${platform}`);
25931
+ p.log.error(isAmbiguousAppVersion(resolved) ? platform === "ios" ? `nativeBuild.ios.${scheme} (scheme ${iosScheme?.scheme}, bundleIdentifier ${iosScheme?.bundleIdentifier}) does not pick one of the app targets in project.pbxproj, which declare different versions (${formatAppVersionCandidates(resolved.candidates)}). Make its scheme match the name of the app target it builds.` : `nativeBuild.android.${scheme} (variant ${androidScheme?.variant ?? "Release"}) does not pick one of the product flavors that set versionName, which declare different versions (${formatAppVersionCandidates(resolved.candidates)}). Set its variant to the flavor it builds, such as brandARelease.` : `Failed to retrieve native app version of ${platform}`);
25775
25932
  return null;
25776
25933
  }
25777
25934
  }
@@ -26913,18 +27070,23 @@ async function validateSigningConfig(config, options = {}) {
26913
27070
  }
26914
27071
  //#endregion
26915
27072
  //#region src/utils/version/getDefaultTargetAppVersion.ts
27073
+ /**
27074
+ * The target app version deploy defaults to, as a range. `version` is null
27075
+ * when the native files declare none, or several (see `candidates`).
27076
+ */
26916
27077
  const getDefaultTargetAppVersion = async (platform) => {
26917
- let version = null;
26918
- switch (platform) {
26919
- case "ios":
26920
- version = await getIOSVersion({ parser: ["info-plist", "xcodeproj"] });
26921
- break;
26922
- case "android": version = await getAndroidVersion({ parser: "app-build-gradle" });
26923
- }
26924
- if (!version) return null;
26925
- if (!(/^\d+\.\d+$/.test(version) || normalizeRange(version))) return null;
27078
+ const resolved = await resolveNativeAppVersion(platform);
27079
+ let version = resolved.version;
27080
+ if (!version) return resolved;
27081
+ if (!(/^\d+\.\d+$/.test(version) || normalizeRange(version))) return {
27082
+ ...resolved,
27083
+ version: null
27084
+ };
26926
27085
  if (version.split(".").length - 1 === 1) version = `${version}.x`;
26927
- return version;
27086
+ return {
27087
+ ...resolved,
27088
+ version
27089
+ };
26928
27090
  };
26929
27091
  //#endregion
26930
27092
  //#region src/commands/deployTransaction.ts
@@ -27250,18 +27412,20 @@ const deployPlatform = async ({ config, core, database, deferAutoPatches, option
27250
27412
  target.fingerprintHash = newFingerprint.hash;
27251
27413
  s.stop(`Fingerprint(${platform}): ${newFingerprint.hash}`);
27252
27414
  } else {
27253
- const defaultTargetAppVersion = await getDefaultTargetAppVersion(platform);
27415
+ const defaultTargetAppVersion = options.targetAppVersion ? null : await getDefaultTargetAppVersion(platform);
27416
+ const ambiguousVersions = defaultTargetAppVersion && isAmbiguousAppVersion(defaultTargetAppVersion) ? formatAppVersionCandidates(defaultTargetAppVersion.candidates) : null;
27417
+ const defaultVersion = defaultTargetAppVersion?.version ?? null;
27254
27418
  const targetAppVersion = options.targetAppVersion ?? (options.interactive ? await p.text({
27255
- message: "Target app version",
27256
- placeholder: defaultTargetAppVersion ?? "1.0.0",
27257
- initialValue: defaultTargetAppVersion ?? "1.0.0",
27419
+ message: ambiguousVersions ? `Target app version (the native project builds several versions: ${ambiguousVersions})` : "Target app version",
27420
+ placeholder: defaultVersion ?? "1.0.0",
27421
+ initialValue: defaultVersion ?? (ambiguousVersions ? "" : "1.0.0"),
27258
27422
  validate: (value) => {
27259
27423
  if (!value || !normalizeRange(value)) return "Invalid semver format (e.g. 1.0.0, 1.x.x)";
27260
27424
  }
27261
- }) : defaultTargetAppVersion);
27425
+ }) : defaultVersion);
27262
27426
  if (p.isCancel(targetAppVersion)) return null;
27263
27427
  if (!targetAppVersion) {
27264
- p.log.error("Target app version not found in native files (Info.plist for iOS, build.gradle for Android). Pass -t <targetAppVersion> explicitly, or check your native config.");
27428
+ p.log.error(ambiguousVersions ? `The native project builds several app versions (${ambiguousVersions}), so the target app version for this deploy cannot be read from it. Pass -t <targetAppVersion> for the app this deploy targets.` : "Target app version not found in native files (Info.plist or project.pbxproj for iOS, build.gradle for Android). Pass -t <targetAppVersion> explicitly, or check your native config.");
27265
27429
  return null;
27266
27430
  }
27267
27431
  target.appVersion = targetAppVersion;
@@ -4550,7 +4550,7 @@ const createKvAdapter = ({ store, tablePrefix = "" }) => {
4550
4550
  };
4551
4551
  //#endregion
4552
4552
  //#region ../../packages/server/dist/version.mjs
4553
- const HOT_UPDATER_SERVER_VERSION = "1.0.0";
4553
+ const HOT_UPDATER_SERVER_VERSION = "1.0.1";
4554
4554
  //#endregion
4555
4555
  //#region ../../packages/server/dist/handlerVersionRoutes.mjs
4556
4556
  /**
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "provider": "aws",
4
- "cliVersion": "1.0.0",
5
- "providerVersion": "1.0.0",
6
- "serverVersion": "1.0.0",
4
+ "cliVersion": "1.0.1",
5
+ "providerVersion": "1.0.1",
6
+ "serverVersion": "1.0.1",
7
7
  "infrastructureGeneration": 1,
8
8
  "clientAuth": {
9
9
  "plugin": "apiKeys",
@@ -65,13 +65,13 @@
65
65
  }
66
66
  ],
67
67
  "packages": {
68
- "hot-updater": "1.0.0",
69
- "@hot-updater/server": "1.0.0",
70
- "@hot-updater/react-native": "1.0.0",
71
- "@hot-updater/aws": "1.0.0",
72
- "@hot-updater/bare": "1.0.0",
73
- "@hot-updater/rock": "1.0.0",
74
- "@hot-updater/expo": "1.0.0",
68
+ "hot-updater": "1.0.1",
69
+ "@hot-updater/server": "1.0.1",
70
+ "@hot-updater/react-native": "1.0.1",
71
+ "@hot-updater/aws": "1.0.1",
72
+ "@hot-updater/bare": "1.0.1",
73
+ "@hot-updater/rock": "1.0.1",
74
+ "@hot-updater/expo": "1.0.1",
75
75
  "@aws-sdk/credential-providers": "3.1066.0"
76
76
  },
77
77
  "requiredInputs": {
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "provider": "cloudflare",
4
- "cliVersion": "1.0.0",
5
- "providerVersion": "1.0.0",
6
- "serverVersion": "1.0.0",
4
+ "cliVersion": "1.0.1",
5
+ "providerVersion": "1.0.1",
6
+ "serverVersion": "1.0.1",
7
7
  "infrastructureGeneration": 1,
8
8
  "clientAuth": {
9
9
  "plugin": "apiKeys",
@@ -61,13 +61,13 @@
61
61
  }
62
62
  ],
63
63
  "packages": {
64
- "hot-updater": "1.0.0",
65
- "@hot-updater/server": "1.0.0",
66
- "@hot-updater/react-native": "1.0.0",
67
- "@hot-updater/cloudflare": "1.0.0",
68
- "@hot-updater/bare": "1.0.0",
69
- "@hot-updater/rock": "1.0.0",
70
- "@hot-updater/expo": "1.0.0"
64
+ "hot-updater": "1.0.1",
65
+ "@hot-updater/server": "1.0.1",
66
+ "@hot-updater/react-native": "1.0.1",
67
+ "@hot-updater/cloudflare": "1.0.1",
68
+ "@hot-updater/bare": "1.0.1",
69
+ "@hot-updater/rock": "1.0.1",
70
+ "@hot-updater/expo": "1.0.1"
71
71
  },
72
72
  "requiredInputs": {
73
73
  "workerName": null,
@@ -1 +1 @@
1
- This folder contains the built output assets for the worker "hot-updater" generated at 2026-10-11T01:49:38.431Z.
1
+ This folder contains the built output assets for the worker "hot-updater" generated at 2026-10-12T01:32:33.502Z.
@@ -4510,7 +4510,7 @@ var createSqlAdapter = /* @__PURE__ */ __name(({ executor, tablePrefix = "", max
4510
4510
  }, "createSqlAdapter");
4511
4511
 
4512
4512
  // ../../packages/server/dist/package.mjs
4513
- var version = "1.0.0";
4513
+ var version = "1.0.1";
4514
4514
 
4515
4515
  // ../../packages/server/dist/version.mjs
4516
4516
  var HOT_UPDATER_SERVER_VERSION = version;