@absolutejs/absolute 0.20.0-beta.103 → 0.20.0-beta.105

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 (32) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/changelog.json +33 -0
  3. package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
  4. package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
  5. package/dist/cli/{compile-4xbpm6hf.js → compile-hsbs1xf6.js} +2 -2
  6. package/dist/cli/{dev-m4r4zs2k.js → dev-9cp5t2n1.js} +4 -4
  7. package/dist/cli/{expoProject-780thyfd.js → expoProject-zkprmjjz.js} +1 -1
  8. package/dist/cli/{index-d5fr1xp3.js → index-0zcebhm4.js} +59 -1
  9. package/dist/cli/{index-wpfvpsk7.js → index-5skbydh0.js} +1 -1
  10. package/dist/cli/{index-3sdvzrv2.js → index-7fxrgx5q.js} +1 -1
  11. package/dist/cli/{index-6ff78meg.js → index-hrzd7e5x.js} +10 -2
  12. package/dist/cli/{index-rvpd4w9t.js → index-mazxtfh4.js} +1 -1
  13. package/dist/cli/{index-qxnptvwn.js → index-q1d4ns4n.js} +100 -9
  14. package/dist/cli/index.js +5 -5
  15. package/dist/cli/{iosNativeWatcher-3k715hq0.js → iosNativeWatcher-t6gv0p1w.js} +2 -2
  16. package/dist/cli/{iosSimulatorController-dr98a0p9.js → iosSimulatorController-5n2a9fxv.js} +2 -2
  17. package/dist/cli/{mobile-6xe6zysv.js → mobile-fbtq3s5x.js} +1240 -370
  18. package/dist/cli/{remoteMacProtocol-kqvkp0qd.js → remoteMacProtocol-bbramzh6.js} +2 -2
  19. package/dist/cli/{start-nmyy64tr.js → start-5grq7nfr.js} +3 -3
  20. package/dist/mobile/index.js +1340 -571
  21. package/dist/mobile/index.js.map +10 -8
  22. package/dist/mobile/remoteMacAgentEntry.js +302 -255
  23. package/dist/src/mobile/index.d.ts +2 -0
  24. package/dist/src/mobile/iosRelease.d.ts +31 -7
  25. package/dist/src/mobile/iosReleaseAcceptance.d.ts +63 -0
  26. package/dist/src/mobile/iosTestReport.d.ts +1 -0
  27. package/dist/src/mobile/nativeReleaseReadiness.d.ts +5 -0
  28. package/dist/src/mobile/nativeTestReport.d.ts +15 -0
  29. package/dist/src/mobile/releaseDoctor.d.ts +2 -0
  30. package/dist/src/mobile/remoteMacProtocol.d.ts +7 -1
  31. package/dist/src/mobile/shellReleaseReadiness.d.ts +2 -0
  32. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -6,6 +6,20 @@ This file is generated by `absolute-changelog` from the entries in
6
6
  `changelog/`. Edit an entry, not this file — and add new ones under
7
7
  `changelog/unreleased/`.
8
8
 
9
+ ## 0.20.0-beta.105 — 2026-09-16
10
+
11
+ ### Added
12
+
13
+ - **iOS releases gain three-lane installed-app acceptance** (`AbsoluteIosReleaseMetadata`, `BuildAbsoluteIosReleaseOptions`, `buildAbsoluteIosRelease`, `buildAbsoluteRemoteIosRelease`, `installAbsoluteIosRelease`, `readAbsoluteIosRelease`, `requireAbsoluteIosReleaseMetadata`, `runAbsoluteIosDeviceReleaseAcceptance`, `runAbsoluteIosSimulatorReleaseAcceptance`)
14
+ `absolute mobile test ios --release` now records honest source-equivalent Simulator, same-archive registered-device, or Apple-processed TestFlight evidence. Capacitor and Expo emit version/build-specific native readiness markers, immutable releases can include a separately hashed registered-device IPA, physical offline claims require explicit confirmation, and sanitized reports retain only artifact classification, outcome, and bounded timings.
15
+
16
+ ## 0.20.0-beta.104 — 2026-09-16
17
+
18
+ ### Added
19
+
20
+ - **Capacitor Android releases gain installed offline AAB acceptance**
21
+ The provider-neutral release command now installs the exact Capacitor AAB-derived APK set on the managed emulator, takes both network transports offline, and requires an AbsoluteJS-owned native readiness signal across a cold launch and process relaunch. Bun workspace-hoisted Capacitor executables and package manifests are resolved only through the application’s governing workspace. Reports and telemetry retain only provider, artifact identity, outcome, and bounded timings.
22
+
9
23
  ## 0.20.0-beta.103 — 2026-09-16
10
24
 
11
25
  ### Added
package/changelog.json CHANGED
@@ -2,6 +2,39 @@
2
2
  "contract": 1,
3
3
  "name": "@absolutejs/absolute",
4
4
  "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "detail": "`absolute mobile test ios --release` now records honest source-equivalent Simulator, same-archive registered-device, or Apple-processed TestFlight evidence. Capacitor and Expo emit version/build-specific native readiness markers, immutable releases can include a separately hashed registered-device IPA, physical offline claims require explicit confirmation, and sanitized reports retain only artifact classification, outcome, and bounded timings.",
9
+ "kind": "added",
10
+ "summary": "iOS releases gain three-lane installed-app acceptance",
11
+ "symbols": [
12
+ "AbsoluteIosReleaseMetadata",
13
+ "BuildAbsoluteIosReleaseOptions",
14
+ "buildAbsoluteIosRelease",
15
+ "buildAbsoluteRemoteIosRelease",
16
+ "installAbsoluteIosRelease",
17
+ "readAbsoluteIosRelease",
18
+ "requireAbsoluteIosReleaseMetadata",
19
+ "runAbsoluteIosDeviceReleaseAcceptance",
20
+ "runAbsoluteIosSimulatorReleaseAcceptance"
21
+ ]
22
+ }
23
+ ],
24
+ "date": "2026-09-16",
25
+ "version": "0.20.0-beta.105"
26
+ },
27
+ {
28
+ "changes": [
29
+ {
30
+ "detail": "The provider-neutral release command now installs the exact Capacitor AAB-derived APK set on the managed emulator, takes both network transports offline, and requires an AbsoluteJS-owned native readiness signal across a cold launch and process relaunch. Bun workspace-hoisted Capacitor executables and package manifests are resolved only through the application’s governing workspace. Reports and telemetry retain only provider, artifact identity, outcome, and bounded timings.",
31
+ "kind": "added",
32
+ "summary": "Capacitor Android releases gain installed offline AAB acceptance"
33
+ }
34
+ ],
35
+ "date": "2026-09-16",
36
+ "version": "0.20.0-beta.104"
37
+ },
5
38
  {
6
39
  "changes": [
7
40
  {
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-nDO3E1/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-WzPLk5/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-nDO3E1/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-WzPLk5/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -48,7 +48,7 @@ var warnMissingStreamingSlotCollector = (primitiveName) => {
48
48
  getWarningController()?.maybeWarn(primitiveName);
49
49
  };
50
50
 
51
- // .angular-partial-tmp-nDO3E1/src/core/streamingSlotRegistry.ts
51
+ // .angular-partial-tmp-WzPLk5/src/core/streamingSlotRegistry.ts
52
52
  var STREAMING_SLOT_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotAsyncLocalStorage");
53
53
  var isObjectRecord2 = (value) => Boolean(value) && typeof value === "object";
54
54
  var isAsyncLocalStorage = (value) => isObjectRecord2(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
@@ -15,7 +15,7 @@ import {
15
15
  createIslandRegistryDefinitionPlugin,
16
16
  finalizeAbsoluteMobileCompatibilityBuild,
17
17
  resolveServerBundleExternals
18
- } from "./index-6ff78meg.js";
18
+ } from "./index-hrzd7e5x.js";
19
19
  import {
20
20
  loadIslandRegistryBuildInfo
21
21
  } from "./index-bzs19w3r.js";
@@ -36,7 +36,7 @@ import"./index-w5vswatm.js";
36
36
  import {
37
37
  normalizeAbsoluteMobileConfig
38
38
  } from "./index-rd2hbttb.js";
39
- import"./index-d5fr1xp3.js";
39
+ import"./index-0zcebhm4.js";
40
40
  import {
41
41
  ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV,
42
42
  installAbsoluteMobileAuthEnvironment
@@ -1286,16 +1286,16 @@ var loadAbsoluteMobileDevModules = async () => {
1286
1286
  expoNativeWatcher
1287
1287
  ] = await Promise.all([
1288
1288
  import("./config-vy04mqce.js"),
1289
- import("./expoProject-780thyfd.js"),
1289
+ import("./expoProject-zkprmjjz.js"),
1290
1290
  import("./expoDevController-zz516pdd.js"),
1291
1291
  import("./nativeAuth-zx4tsb1f.js"),
1292
1292
  import("./androidEmulatorController-nybhzc6c.js"),
1293
1293
  import("./emulatorDoctor-y2nqmaha.js"),
1294
1294
  import("./emulatorInstaller-3shdna4g.js"),
1295
1295
  import("./androidNativeWatcher-2930tb8c.js"),
1296
- import("./iosSimulatorController-dr98a0p9.js"),
1297
- import("./remoteMacProtocol-kqvkp0qd.js"),
1298
- import("./iosNativeWatcher-3k715hq0.js"),
1296
+ import("./iosSimulatorController-5n2a9fxv.js"),
1297
+ import("./remoteMacProtocol-bbramzh6.js"),
1298
+ import("./iosNativeWatcher-t6gv0p1w.js"),
1299
1299
  import("./expoNativeWatcher-rmc95bak.js")
1300
1300
  ]);
1301
1301
  return {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  syncAbsoluteExpoWebAssets,
4
4
  writeAbsoluteExpoProject
5
- } from "./index-d5fr1xp3.js";
5
+ } from "./index-0zcebhm4.js";
6
6
  import"./index-ar4gz15x.js";
7
7
  import"./index-mywsk201.js";
8
8
  export {
@@ -1416,9 +1416,59 @@ var moduleConfig2 = `${JSON.stringify({
1416
1416
  "expo.modules.absoluteactivityresultrecovery.AbsoluteActivityResultRecoveryModule"
1417
1417
  ]
1418
1418
  },
1419
- platforms: ["android"]
1419
+ apple: { modules: ["AbsoluteActivityResultRecoveryModule"] },
1420
+ platforms: ["apple", "android"]
1420
1421
  }, null, 2)}
1421
1422
  `;
1423
+ var podspec2 = `${HEADER2}Pod::Spec.new do |s|
1424
+ s.name = 'AbsoluteActivityResultRecovery'
1425
+ s.version = '0.0.1'
1426
+ s.summary = 'AbsoluteJS native runtime readiness bridge'
1427
+ s.description = 'Generated lifecycle and embedded-content readiness bridge for an AbsoluteJS Expo application.'
1428
+ s.author = 'AbsoluteJS'
1429
+ s.homepage = 'https://absolutejs.com'
1430
+ s.platforms = { :ios => '16.4' }
1431
+ s.source = { git: '' }
1432
+ s.static_framework = true
1433
+ s.dependency 'ExpoModulesCore'
1434
+ s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
1435
+ s.source_files = '**/*.{h,m,mm,swift,hpp,cpp}'
1436
+ end
1437
+ `;
1438
+ var iosModule2 = `${HEADER2}import ExpoModulesCore
1439
+
1440
+ public final class AbsoluteActivityResultRecoveryModule: Module {
1441
+ public func definition() -> ModuleDefinition {
1442
+ Name("AbsoluteActivityResultRecovery")
1443
+
1444
+ Function("markApplicationRuntimeReady") { }
1445
+
1446
+ Function("markEmbeddedWebReady") {
1447
+ let info = Bundle.main.infoDictionary ?? [:]
1448
+ let version = info["CFBundleShortVersionString"] as? String ?? "unknown"
1449
+ let build = info["CFBundleVersion"] as? String ?? "unknown"
1450
+ NSLog("AbsoluteJS: Expo embedded web content ready; version=%@; build=%@", version, build)
1451
+ }
1452
+
1453
+ Function("markEmbeddedWebPhase") { (phase: String) in
1454
+ let allowed = [
1455
+ "assets-start", "assets-ready", "assets-root-failed",
1456
+ "assets-directory-failed", "assets-destination-failed",
1457
+ "assets-module-failed", "assets-source-failed",
1458
+ "assets-download-failed", "assets-copy-failed",
1459
+ "assets-read-failed", "assets-write-failed",
1460
+ "assets-finalize-failed", "assets-unexpected-failed",
1461
+ "devices-start", "devices-ready", "devices-failed"
1462
+ ]
1463
+ if allowed.contains(phase) {
1464
+ NSLog("AbsoluteJS: Expo embedded web phase: %@", phase)
1465
+ }
1466
+ }
1467
+
1468
+ Function("takePendingCancellation") { false }
1469
+ }
1470
+ }
1471
+ `;
1422
1472
  var androidBuild2 = `${HEADER2}plugins {
1423
1473
  id 'com.android.library'
1424
1474
  id 'expo-module-gradle-plugin'
@@ -1595,6 +1645,14 @@ var absoluteExpoActivityResultRecoveryFiles = (project) => new Map([
1595
1645
  join4(project, "modules/absolute-activity-result-recovery/expo-module.config.json"),
1596
1646
  moduleConfig2
1597
1647
  ],
1648
+ [
1649
+ join4(project, "modules/absolute-activity-result-recovery/ios/AbsoluteActivityResultRecovery.podspec"),
1650
+ podspec2
1651
+ ],
1652
+ [
1653
+ join4(project, "modules/absolute-activity-result-recovery/ios/AbsoluteActivityResultRecoveryModule.swift"),
1654
+ iosModule2
1655
+ ],
1598
1656
  [
1599
1657
  join4(project, "modules/absolute-activity-result-recovery/android/build.gradle"),
1600
1658
  androidBuild2
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  fingerprintAbsoluteIosNativeProject
4
- } from "./index-qxnptvwn.js";
4
+ } from "./index-q1d4ns4n.js";
5
5
  import {
6
6
  normalizeAbsoluteIosDeviceHost,
7
7
  normalizeAbsoluteIosDeviceIdentifier,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  installAbsoluteIosRelease,
4
4
  requireAbsoluteIosReleaseMetadata
5
- } from "./index-qxnptvwn.js";
5
+ } from "./index-q1d4ns4n.js";
6
6
  import {
7
7
  unrefTimer
8
8
  } from "./index-bw4ktfnz.js";
@@ -10,7 +10,7 @@ import {
10
10
  resolveAbsoluteMobileUpdateRuntime,
11
11
  syncAbsoluteExpoWebAssets,
12
12
  writeAbsoluteExpoProject
13
- } from "./index-d5fr1xp3.js";
13
+ } from "./index-0zcebhm4.js";
14
14
 
15
15
  // src/build/islandRegistryTransform.ts
16
16
  import { basename } from "path";
@@ -847,6 +847,12 @@ var shellUpdateModule = () => {
847
847
  return candidate;
848
848
  throw new TypeError("AbsoluteJS mobile update shell module is missing.");
849
849
  };
850
+ var shellReleaseReadinessModule = () => {
851
+ const candidate = ["js", "ts"].map((extension) => join2(import.meta.dir, `shellReleaseReadiness.${extension}`)).find(existsSync);
852
+ if (candidate)
853
+ return candidate;
854
+ throw new TypeError("AbsoluteJS mobile release-readiness module is missing.");
855
+ };
850
856
  var escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
851
857
  var contentSecurityPolicy = (productionOrigin) => {
852
858
  const backend = new URL(productionOrigin);
@@ -937,6 +943,7 @@ const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absolu
937
943
  const entryPath = join2(staging, ".absolute-mobile-entry.ts");
938
944
  const baseAdapterModule = capacitor ? await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor") : shellExpoDevicesModule();
939
945
  const adapterImport = capacitor ? `import { installCapacitorDeviceAdapterIfNative } from ${JSON.stringify(baseAdapterModule)};` : `import { createAbsoluteExpoBridgeFetch, installAbsoluteExpoWebDeviceAdapter } from ${JSON.stringify(baseAdapterModule)};`;
946
+ const readinessImport = capacitor ? `import { markAbsoluteMobileShellReady } from ${JSON.stringify(shellReleaseReadinessModule())};` : "";
940
947
  const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : `installAbsoluteExpoWebDeviceAdapter(${JSON.stringify(deviceCapabilities.capabilities)});`;
941
948
  const shellOptionProperties = [
942
949
  `engine: ${JSON.stringify(engine)}`
@@ -954,9 +961,10 @@ const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absolu
954
961
  const shellOptions = `{ ${shellOptionProperties.join(", ")} }`;
955
962
  await writeFile2(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
956
963
  ${adapterImport}
964
+ ${readinessImport}
957
965
  ${authImport}${syncImport}${pushImport}${updateImport}${capabilityImports}
958
966
  ${pushSetup}${adapterInstall}
959
- void startAbsoluteMobileShell(${shellOptions});
967
+ void startAbsoluteMobileShell(${shellOptions})${capacitor ? ".then(markAbsoluteMobileShellReady)" : ""};
960
968
  `);
961
969
  const build = await Bun.build({
962
970
  entrypoints: [entryPath],
@@ -6,7 +6,7 @@ import {
6
6
  createIslandRegistryDefinitionPlugin,
7
7
  finalizeAbsoluteMobileCompatibilityBuild,
8
8
  resolveServerBundleExternals
9
- } from "./index-6ff78meg.js";
9
+ } from "./index-hrzd7e5x.js";
10
10
  import {
11
11
  loadIslandRegistryBuildInfo
12
12
  } from "./index-bzs19w3r.js";
@@ -120,6 +120,25 @@ var safeOutputDirectory = (projectRoot, requested) => {
120
120
  return output;
121
121
  };
122
122
  var sha256File = async (path) => createHash("sha256").update(await readFile(path)).digest("hex");
123
+ var verifyRegisteredReleaseArtifact = async (releaseRoot, metadata) => {
124
+ if (!metadata.registeredDevice)
125
+ return;
126
+ const destination = join(releaseRoot, metadata.registeredDevice.artifact);
127
+ const [bytes, sha256] = await Promise.all([
128
+ stat(destination).then(({ size }) => size),
129
+ sha256File(destination)
130
+ ]);
131
+ if (bytes !== metadata.registeredDevice.bytes || sha256 !== metadata.registeredDevice.sha256)
132
+ throw new TypeError(`Immutable iOS release ${metadata.releaseId} registered-device artifact is missing or modified.`);
133
+ return destination;
134
+ };
135
+ var copyRegisteredReleaseArtifact = async (staging, metadata, registeredArtifactPath) => {
136
+ if (!metadata.registeredDevice)
137
+ return;
138
+ if (!registeredArtifactPath)
139
+ throw new TypeError("iOS release metadata requires a registered-device artifact.");
140
+ await copyFile(registeredArtifactPath, join(staging, metadata.registeredDevice.artifact));
141
+ };
123
142
  var findByExtension = async (root, extension) => {
124
143
  if (!await pathExists(root))
125
144
  return;
@@ -175,12 +194,12 @@ var resolveAbsoluteIosXcodeProject = async (nativeDirectory, options = {}) => {
175
194
  throw new TypeError(schemes.length > 1 ? `iOS release found multiple shared Xcode schemes: ${schemes.join(", ")}. Pass an explicit scheme.` : "iOS release could not find a shared Xcode scheme.");
176
195
  return { scheme: schemes[0], workspacePath };
177
196
  };
178
- var exportOptions = () => `<?xml version="1.0" encoding="UTF-8"?>
197
+ var exportOptions = (method) => `<?xml version="1.0" encoding="UTF-8"?>
179
198
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
180
199
  <plist version="1.0"><dict>
181
200
  <key>destination</key><string>export</string>
182
201
  <key>manageAppVersionAndBuildNumber</key><false/>
183
- <key>method</key><string>app-store-connect</string>
202
+ <key>method</key><string>${method}</string>
184
203
  <key>signingStyle</key><string>automatic</string>
185
204
  <key>stripSwiftSymbols</key><true/>
186
205
  <key>uploadSymbols</key><true/>
@@ -191,7 +210,19 @@ var requireBuildNumber = (value) => {
191
210
  throw new TypeError("iOS build number must be a positive integer.");
192
211
  return value;
193
212
  };
213
+ var normalizeRegisteredDevice = (value) => {
214
+ if (value === undefined)
215
+ return;
216
+ if (!isRecord(value) || value.artifact !== "App.registered.ipa" || typeof value.bytes !== "number" || !Number.isSafeInteger(value.bytes) || value.bytes < 1 || typeof value.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(value.sha256))
217
+ throw new TypeError("Invalid AbsoluteJS iOS release metadata.");
218
+ return {
219
+ artifact: "App.registered.ipa",
220
+ bytes: value.bytes,
221
+ sha256: value.sha256
222
+ };
223
+ };
194
224
  var requireAbsoluteIosReleaseMetadata = (value) => {
225
+ const registeredDevice = normalizeRegisteredDevice(isRecord(value) ? value.registeredDevice : undefined);
195
226
  if (!isRecord(value) || value.artifact !== "App.ipa" || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.bytes !== "number" || !Number.isSafeInteger(value.bytes) || value.bytes < 1 || value.engine !== "capacitor" && value.engine !== "expo" || value.format !== ABSOLUTE_IOS_RELEASE_FORMAT || typeof value.marketingVersion !== "string" || value.platform !== "ios" || typeof value.releaseId !== "string" || typeof value.runtime !== "string" || typeof value.sha256 !== "string" || typeof value.signed !== "boolean" || value.type !== "ipa" || value.buildNumber !== undefined && (typeof value.buildNumber !== "number" || !Number.isSafeInteger(value.buildNumber) || value.buildNumber < 1) || !/^amobile_ios_[a-f0-9]{64}$/u.test(value.releaseId) || !/^[a-f0-9]{64}$/u.test(value.sha256) || value.releaseId !== `amobile_ios_${value.sha256}`) {
196
227
  throw new TypeError("Invalid AbsoluteJS iOS release metadata.");
197
228
  }
@@ -205,6 +236,7 @@ var requireAbsoluteIosReleaseMetadata = (value) => {
205
236
  format: value.format,
206
237
  marketingVersion: value.marketingVersion,
207
238
  platform: value.platform,
239
+ ...registeredDevice ? { registeredDevice } : {},
208
240
  releaseId: value.releaseId,
209
241
  runtime: value.runtime,
210
242
  sha256: value.sha256,
@@ -212,12 +244,13 @@ var requireAbsoluteIosReleaseMetadata = (value) => {
212
244
  type: value.type
213
245
  };
214
246
  };
215
- var installRelease = async (artifactPath, metadata, outputRoot) => {
247
+ var installRelease = async (artifactPath, metadata, outputRoot, registeredArtifactPath) => {
216
248
  const releaseRoot = join(outputRoot, metadata.releaseId);
217
249
  const destination = join(releaseRoot, "App.ipa");
218
250
  if (await pathExists(releaseRoot)) {
219
251
  const value = JSON.parse(await readFile(join(releaseRoot, "release.json"), "utf8"));
220
- if (!isRecord(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
252
+ const existing = requireAbsoluteIosReleaseMetadata(value);
253
+ if (JSON.stringify(existing) !== JSON.stringify({ ...metadata, artifact: "App.ipa" })) {
221
254
  throw new TypeError(`Immutable iOS release ${metadata.releaseId} does not match its content.`);
222
255
  }
223
256
  const [bytes, sha256] = await Promise.all([
@@ -226,12 +259,14 @@ var installRelease = async (artifactPath, metadata, outputRoot) => {
226
259
  ]);
227
260
  if (bytes !== metadata.bytes || sha256 !== metadata.sha256)
228
261
  throw new TypeError(`Immutable iOS release ${metadata.releaseId} artifact is missing or modified.`);
262
+ const registeredDestination = await verifyRegisteredReleaseArtifact(releaseRoot, metadata);
229
263
  return {
230
264
  artifactPath: destination,
231
265
  metadata: {
232
266
  ...metadata,
233
267
  artifact: "App.ipa"
234
268
  },
269
+ ...registeredDestination ? { registeredArtifactPath: registeredDestination } : {},
235
270
  releaseRoot
236
271
  };
237
272
  }
@@ -239,6 +274,7 @@ var installRelease = async (artifactPath, metadata, outputRoot) => {
239
274
  const staging = await mkdtemp(join(dirname(releaseRoot), ".ios-stage-"));
240
275
  try {
241
276
  await copyFile(artifactPath, join(staging, "App.ipa"));
277
+ await copyRegisteredReleaseArtifact(staging, metadata, registeredArtifactPath);
242
278
  const complete = {
243
279
  ...metadata,
244
280
  artifact: "App.ipa"
@@ -246,13 +282,50 @@ var installRelease = async (artifactPath, metadata, outputRoot) => {
246
282
  await writeFile(join(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
247
283
  `, { flag: "wx" });
248
284
  await rename(staging, releaseRoot);
249
- return { artifactPath: destination, metadata: complete, releaseRoot };
285
+ return {
286
+ artifactPath: destination,
287
+ metadata: complete,
288
+ ...metadata.registeredDevice ? {
289
+ registeredArtifactPath: join(releaseRoot, metadata.registeredDevice.artifact)
290
+ } : {},
291
+ releaseRoot
292
+ };
250
293
  } finally {
251
294
  await rm(staging, { force: true, recursive: true }).catch(() => {
252
295
  return;
253
296
  });
254
297
  }
255
298
  };
299
+ var exportRegisteredDeviceArtifact = async (options) => {
300
+ const exportPath = join(options.staging, "registered-export");
301
+ const exportPlist = join(options.staging, "RegisteredExportOptions.plist");
302
+ await mkdir(exportPath, { recursive: true });
303
+ await writeFile(exportPlist, exportOptions("debugging"));
304
+ const exitCode = await options.run([
305
+ "xcodebuild",
306
+ "-exportArchive",
307
+ "-archivePath",
308
+ options.archivePath,
309
+ "-exportPath",
310
+ exportPath,
311
+ "-exportOptionsPlist",
312
+ exportPlist
313
+ ], { cwd: options.nativeDirectory, env: options.env });
314
+ if (exitCode !== 0)
315
+ throw new TypeError("Xcode failed to export the registered-device IPA. Confirm the selected development team includes the test device.");
316
+ const artifactPath = await findByExtension(exportPath, ".ipa");
317
+ if (!artifactPath)
318
+ throw new TypeError("Xcode did not produce a registered-device IPA.");
319
+ const [bytes, sha256] = await Promise.all([
320
+ stat(artifactPath).then(({ size }) => size),
321
+ sha256File(artifactPath)
322
+ ]);
323
+ const metadata = { artifact: "App.registered.ipa", bytes, sha256 };
324
+ return {
325
+ artifactPath,
326
+ metadata
327
+ };
328
+ };
256
329
  var buildAbsoluteIosRelease = async (options) => {
257
330
  if (options.buildNumber !== undefined && options.prepareBuildNumber)
258
331
  throw new TypeError("iOS release buildNumber and prepareBuildNumber cannot be combined.");
@@ -282,7 +355,7 @@ var buildAbsoluteIosRelease = async (options) => {
282
355
  const exportPath = join(staging, "export");
283
356
  const exportPlist = join(staging, "ExportOptions.plist");
284
357
  await mkdir(exportPath, { recursive: true });
285
- await writeFile(exportPlist, exportOptions());
358
+ await writeFile(exportPlist, exportOptions("app-store-connect"));
286
359
  const run = options.run ?? defaultRun;
287
360
  try {
288
361
  const developmentTeam = developmentTeamArgument(options.developmentTeam);
@@ -339,6 +412,13 @@ var buildAbsoluteIosRelease = async (options) => {
339
412
  sha256File(artifactPath)
340
413
  ]);
341
414
  const releaseId = `amobile_ios_${sha256}`;
415
+ const registered = options.registeredDeviceArtifact ? await exportRegisteredDeviceArtifact({
416
+ archivePath,
417
+ ...options.env ? { env: options.env } : {},
418
+ nativeDirectory,
419
+ run,
420
+ staging
421
+ }) : undefined;
342
422
  return await installRelease(artifactPath, {
343
423
  appBuild: manifest.appBuild,
344
424
  appId: manifest.appId,
@@ -348,12 +428,13 @@ var buildAbsoluteIosRelease = async (options) => {
348
428
  format: 1,
349
429
  marketingVersion,
350
430
  platform: "ios",
431
+ ...registered ? { registeredDevice: registered.metadata } : {},
351
432
  releaseId,
352
433
  runtime: manifest.runtime,
353
434
  sha256,
354
435
  signed,
355
436
  type: "ipa"
356
- }, safeOutputDirectory(options.projectRoot, options.outputDirectory));
437
+ }, safeOutputDirectory(options.projectRoot, options.outputDirectory), registered?.artifactPath);
357
438
  } finally {
358
439
  await rm(staging, { force: true, recursive: true }).catch(() => {
359
440
  return;
@@ -368,8 +449,18 @@ var installAbsoluteIosRelease = async (options) => {
368
449
  ]);
369
450
  if (bytes !== metadata.bytes || sha256 !== metadata.sha256)
370
451
  throw new TypeError("Remote iOS release artifact does not match its signed metadata.");
452
+ if (metadata.registeredDevice) {
453
+ if (!options.registeredArtifactPath)
454
+ throw new TypeError("Remote iOS release metadata requires its registered-device artifact.");
455
+ const [registeredBytes, registeredSha256] = await Promise.all([
456
+ stat(options.registeredArtifactPath).then(({ size }) => size),
457
+ sha256File(options.registeredArtifactPath)
458
+ ]);
459
+ if (registeredBytes !== metadata.registeredDevice.bytes || registeredSha256 !== metadata.registeredDevice.sha256)
460
+ throw new TypeError("Remote iOS registered-device artifact does not match its signed metadata.");
461
+ }
371
462
  const { artifact: _artifact, ...releaseMetadata } = metadata;
372
- return installRelease(options.artifactPath, releaseMetadata, safeOutputDirectory(options.projectRoot, options.outputDirectory));
463
+ return installRelease(options.artifactPath, releaseMetadata, safeOutputDirectory(options.projectRoot, options.outputDirectory), options.registeredArtifactPath);
373
464
  };
374
465
 
375
- export { fingerprintAbsoluteIosNativeProject, requireAbsoluteIosReleaseMetadata, buildAbsoluteIosRelease, installAbsoluteIosRelease };
466
+ export { fingerprintAbsoluteIosNativeProject, resolveAbsoluteIosXcodeProject, requireAbsoluteIosReleaseMetadata, buildAbsoluteIosRelease, installAbsoluteIosRelease };
package/dist/cli/index.js CHANGED
@@ -58,7 +58,7 @@ if (command === "dev") {
58
58
  }
59
59
  const positionalArgs = stripNamedArgs("--config", "--android-device", "--ios-device").filter((arg) => arg !== "--no-mobile" && arg !== "--eager");
60
60
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
61
- const { dev } = await import("./dev-m4r4zs2k.js");
61
+ const { dev } = await import("./dev-9cp5t2n1.js");
62
62
  await dev(serverEntry, configPath, {
63
63
  androidDevice,
64
64
  eager: args.includes("--eager"),
@@ -71,7 +71,7 @@ if (command === "dev") {
71
71
  const configPath = parseNamedArg("--config");
72
72
  const positionalArgs = stripNamedArgs("--outdir", "--config").filter((arg) => arg !== "--prebuilt");
73
73
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
74
- const { start } = await import("./start-nmyy64tr.js");
74
+ const { start } = await import("./start-5grq7nfr.js");
75
75
  await start(serverEntry, outdir, configPath, {
76
76
  prebuilt: args.includes("--prebuilt")
77
77
  });
@@ -81,7 +81,7 @@ if (command === "dev") {
81
81
  const configPath = parseNamedArg("--config");
82
82
  const positionalArgs = stripNamedArgs("--outdir", "--config");
83
83
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
84
- const { start } = await import("./start-nmyy64tr.js");
84
+ const { start } = await import("./start-5grq7nfr.js");
85
85
  await start(serverEntry, outdir, configPath, { prepareOnly: true });
86
86
  } else if (command === "build") {
87
87
  sendTelemetryEvent("cli:command", { command });
@@ -197,13 +197,13 @@ if (command === "dev") {
197
197
  const configPath = parseNamedArg("--config");
198
198
  const positionalArgs = stripNamedArgs("--outdir", "--outfile", "--config");
199
199
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
200
- const { compile } = await import("./compile-4xbpm6hf.js");
200
+ const { compile } = await import("./compile-hsbs1xf6.js");
201
201
  await compile(serverEntry, outdir, outfile, configPath);
202
202
  } else if (command === "mobile") {
203
203
  sendTelemetryEvent("cli:command", {
204
204
  command: `mobile:${workspaceCommand ?? "unknown"}`
205
205
  });
206
- const { runMobile } = await import("./mobile-6xe6zysv.js");
206
+ const { runMobile } = await import("./mobile-fbtq3s5x.js");
207
207
  try {
208
208
  await runMobile(args);
209
209
  } catch (error) {
@@ -1,8 +1,8 @@
1
1
  // @bun
2
2
  import {
3
3
  fingerprintAbsoluteIosDevProject
4
- } from "./index-wpfvpsk7.js";
5
- import"./index-qxnptvwn.js";
4
+ } from "./index-5skbydh0.js";
5
+ import"./index-q1d4ns4n.js";
6
6
  import"./index-j66p8hn5.js";
7
7
  import"./index-28pbrd3q.js";
8
8
  import"./index-knt92dm8.js";
@@ -10,8 +10,8 @@ import {
10
10
  redactAbsoluteIosLog,
11
11
  repairAbsoluteIosDevSession,
12
12
  startAbsoluteIosDevSession
13
- } from "./index-wpfvpsk7.js";
14
- import"./index-qxnptvwn.js";
13
+ } from "./index-5skbydh0.js";
14
+ import"./index-q1d4ns4n.js";
15
15
  import"./index-j66p8hn5.js";
16
16
  import"./index-28pbrd3q.js";
17
17
  import"./index-knt92dm8.js";