@absolutejs/absolute 0.20.0-beta.52 → 0.20.0-beta.54

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.
@@ -4133,6 +4133,8 @@ var ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION = 3;
4133
4133
  var PROFILE_FORMAT = 1;
4134
4134
  var REMOTE_STDIN_FLUSH_ATTEMPTS = 3;
4135
4135
  var REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000;
4136
+ var REMOTE_RELEASE_LEASE_HEARTBEAT_MS = 15000;
4137
+ var REMOTE_RELEASE_LEASE_STALE_SECONDS = 120;
4136
4138
  var PROFILE_NAME = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/u;
4137
4139
  var SSH_DESTINATION = /^(?:[A-Za-z0-9._-]+@)?[A-Za-z0-9._:-]+$/u;
4138
4140
  var defaultProfilePath = () => join7(homedir2(), ".absolutejs", "mobile", "remote-macs.json");
@@ -4350,6 +4352,114 @@ var createAbsoluteRemoteIosDevProject = (config, projectRoot, profile) => ({
4350
4352
  xcodebuild: "remote:xcodebuild",
4351
4353
  xcrun: "remote:xcrun"
4352
4354
  });
4355
+ var releaseLeasePath = (project) => posix.join(posix.dirname(project.remoteProjectRoot), ".release-lease");
4356
+ var acquireAbsoluteRemoteMacReleaseLease = async (project, options = {}) => {
4357
+ options.signal?.throwIfAborted();
4358
+ const token = randomUUID4();
4359
+ const path = releaseLeasePath(project);
4360
+ const stalePath = `${path}.stale-${token}`;
4361
+ const staleSeconds = options.staleSeconds ?? REMOTE_RELEASE_LEASE_STALE_SECONDS;
4362
+ if (!Number.isSafeInteger(staleSeconds) || staleSeconds < 30)
4363
+ throw new TypeError("Remote Mac release lease expiry must be at least 30 seconds.");
4364
+ const owner = JSON.stringify({
4365
+ acquiredAt: new Date().toISOString(),
4366
+ appId: project.config.appId,
4367
+ host: process.env.HOSTNAME ?? "unknown",
4368
+ pid: process.pid,
4369
+ token
4370
+ });
4371
+ const script = [
4372
+ "set -eu",
4373
+ "umask 077",
4374
+ `mkdir -p ${shellQuote(posix.dirname(path))}`,
4375
+ `if mkdir ${shellQuote(path)} 2>/dev/null; then status=ACQUIRED; else now=$(date +%s); modified=$(stat -f %m ${shellQuote(path)} 2>/dev/null || printf '0'); age=$((now-modified)); if [ "$age" -le ${staleSeconds} ]; then printf 'BUSY\\n'; cat ${shellQuote(posix.join(path, "owner.json"))} 2>/dev/null || true; exit 73; fi; if mv ${shellQuote(path)} ${shellQuote(stalePath)} 2>/dev/null && mkdir ${shellQuote(path)} 2>/dev/null; then status=RECOVERED; rm -rf ${shellQuote(stalePath)}; else printf 'BUSY\\n'; exit 73; fi; fi`,
4376
+ `printf '%s\\n' ${shellQuote(token)} > ${shellQuote(posix.join(path, "token"))}`,
4377
+ `printf '%s\\n' ${shellQuote(owner)} > ${shellQuote(posix.join(path, "owner.json"))}`,
4378
+ `touch ${shellQuote(path)}`,
4379
+ `printf '%s\\n' "$status"`
4380
+ ].join("; ");
4381
+ const capture = options.transport?.capture ?? defaultTransport.capture;
4382
+ const result = await capture([
4383
+ ...absoluteRemoteMacSshBase(project.profile),
4384
+ "/bin/sh -lc",
4385
+ shellQuote(script)
4386
+ ]);
4387
+ if (result.exitCode !== 0) {
4388
+ if (result.exitCode === 73 || result.stdout.startsWith("BUSY"))
4389
+ throw new Error(`Remote Mac ${project.profile.name} is already building ${project.config.appId}. Wait for that release to finish; a crashed lease recovers automatically after ${staleSeconds} seconds.${result.stdout.split(`
4390
+ `).slice(1).join(" ").trim() ? ` Owner: ${result.stdout.split(`
4391
+ `).slice(1).join(" ").trim()}` : ""}`);
4392
+ requireRemoteSuccess(result, "Remote Mac release lease acquisition");
4393
+ }
4394
+ const recovered = result.stdout.trim().split(/\r?\n/u).at(-1) === "RECOVERED";
4395
+ const runOwned = async (action) => {
4396
+ const ownedScript = `test -f ${shellQuote(posix.join(path, "token"))} && ` + `test "$(cat ${shellQuote(posix.join(path, "token"))})" = ${shellQuote(token)} && ${action}`;
4397
+ const owned = await capture([
4398
+ ...absoluteRemoteMacSshBase(project.profile),
4399
+ "/bin/sh -lc",
4400
+ shellQuote(ownedScript)
4401
+ ]);
4402
+ requireRemoteSuccess(owned, "Remote Mac release lease ownership check");
4403
+ };
4404
+ return {
4405
+ path,
4406
+ recovered,
4407
+ token,
4408
+ heartbeat: () => runOwned(`touch ${shellQuote(path)}`),
4409
+ release: () => runOwned(`rm -rf ${shellQuote(path)}`)
4410
+ };
4411
+ };
4412
+ var inspectAbsoluteRemoteMacWorkspace = async (profile, transport) => {
4413
+ const root = profile.workspaceRoot;
4414
+ const script = [
4415
+ "set -eu",
4416
+ `mkdir -p ${shellQuote(root)}`,
4417
+ `bytes=$(du -sk ${shellQuote(root)} 2>/dev/null | awk '{print $1 * 1024}')`,
4418
+ `projects=$(find ${shellQuote(posix.join(root, "projects"))} -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l | tr -d ' ')`,
4419
+ `agents=$(find ${shellQuote(posix.join(root, "agents"))} -mindepth 2 -maxdepth 2 -type d 2>/dev/null | wc -l | tr -d ' ')`,
4420
+ `leases=$(find ${shellQuote(posix.join(root, "projects"))} -mindepth 2 -maxdepth 2 -type d -name .release-lease 2>/dev/null | wc -l | tr -d ' ')`,
4421
+ `printf '%s\\n%s\\n%s\\n%s\\n' "${"$"}{bytes:-0}" "${"$"}{projects:-0}" "${"$"}{agents:-0}" "${"$"}{leases:-0}"`
4422
+ ].join("; ");
4423
+ const result = await (transport?.capture ?? defaultTransport.capture)([
4424
+ ...absoluteRemoteMacSshBase(profile),
4425
+ "/bin/sh -lc",
4426
+ shellQuote(script)
4427
+ ]);
4428
+ const [bytes, projectCount, agentCount, leaseCount] = requireRemoteSuccess(result, "Remote Mac workspace inspection").split(/\r?\n/u).map(Number);
4429
+ if ([bytes, projectCount, agentCount, leaseCount].some((value) => typeof value !== "number" || !Number.isSafeInteger(value) || value < 0))
4430
+ throw new TypeError("Remote Mac returned invalid workspace statistics.");
4431
+ return {
4432
+ agentCount: agentCount ?? 0,
4433
+ bytes: bytes ?? 0,
4434
+ leaseCount: leaseCount ?? 0,
4435
+ profile: profile.name,
4436
+ projectCount: projectCount ?? 0,
4437
+ workspaceRoot: root
4438
+ };
4439
+ };
4440
+ var cleanAbsoluteRemoteMacWorkspace = async (profile, transport) => {
4441
+ const root = profile.workspaceRoot;
4442
+ const projects = posix.join(root, "projects");
4443
+ const script = [
4444
+ "set -eu",
4445
+ `mkdir -p ${shellQuote(root)}`,
4446
+ `project_staging=$(find ${shellQuote(projects)} -mindepth 2 -maxdepth 2 -type d \\( -name '.incoming-*' -o -name '.previous' -o -name '.release-lease.stale-*' \\) -mtime +0 -prune -print 2>/dev/null | wc -l | tr -d ' ')`,
4447
+ `mobile_staging=$(find ${shellQuote(projects)} -type d \\( -path '*/current/.absolutejs/mobile/.ios-build-*' -o -path '*/current/.absolutejs/mobile/.ios-stage-*' -o -path '*/current/.absolutejs/mobile/*.incoming-*' \\) -mtime +0 -prune -print 2>/dev/null | wc -l | tr -d ' ')`,
4448
+ `count=$((project_staging+mobile_staging))`,
4449
+ `find ${shellQuote(projects)} -mindepth 2 -maxdepth 2 -type d \\( -name '.incoming-*' -o -name '.previous' -o -name '.release-lease.stale-*' \\) -mtime +0 -prune -exec rm -rf {} + 2>/dev/null || true`,
4450
+ `find ${shellQuote(projects)} -type d \\( -path '*/current/.absolutejs/mobile/.ios-build-*' -o -path '*/current/.absolutejs/mobile/.ios-stage-*' -o -path '*/current/.absolutejs/mobile/*.incoming-*' \\) -mtime +0 -prune -exec rm -rf {} + 2>/dev/null || true`,
4451
+ `printf '%s\\n' "$count"`
4452
+ ].join("; ");
4453
+ const result = await (transport?.capture ?? defaultTransport.capture)([
4454
+ ...absoluteRemoteMacSshBase(profile),
4455
+ "/bin/sh -lc",
4456
+ shellQuote(script)
4457
+ ]);
4458
+ const removed = Number(requireRemoteSuccess(result, "Remote Mac workspace cleanup"));
4459
+ if (!Number.isSafeInteger(removed) || removed < 0)
4460
+ throw new TypeError("Remote Mac returned an invalid cleanup result.");
4461
+ return { profile: profile.name, removed, workspaceRoot: root };
4462
+ };
4353
4463
  var installAbsoluteRemoteMacAgent = async (project) => {
4354
4464
  const artifact = await materializeAbsoluteRemoteMacAgent(project.projectRoot);
4355
4465
  const directory = posix.join(project.profile.workspaceRoot, "agents", `protocol-${ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION}`, artifact.sha256);
@@ -4504,13 +4614,16 @@ var absoluteRemoteProjectSyncCommands = (project) => {
4504
4614
  ]
4505
4615
  };
4506
4616
  };
4507
- var syncAbsoluteRemoteMacProject = async (project) => {
4617
+ var syncAbsoluteRemoteMacProject = async (project, options = {}) => {
4618
+ options.signal?.throwIfAborted();
4508
4619
  const commands = absoluteRemoteProjectSyncCommands(project);
4509
4620
  const archive = Bun.spawn(commands.tar, {
4621
+ signal: options.signal,
4510
4622
  stderr: "pipe",
4511
4623
  stdout: "pipe"
4512
4624
  });
4513
4625
  const upload = Bun.spawn(commands.remote, {
4626
+ signal: options.signal,
4514
4627
  stderr: "pipe",
4515
4628
  stdin: archive.stdout,
4516
4629
  stdout: "pipe"
@@ -4558,13 +4671,16 @@ var absoluteRemoteReleaseInputSyncCommands = (project) => {
4558
4671
  tar: ["tar", "-cf", "-", "-C", project.config.bundleDirectory, "."]
4559
4672
  };
4560
4673
  };
4561
- var syncAbsoluteRemoteMacReleaseInputs = async (project) => {
4674
+ var syncAbsoluteRemoteMacReleaseInputs = async (project, options = {}) => {
4675
+ options.signal?.throwIfAborted();
4562
4676
  const commands = absoluteRemoteReleaseInputSyncCommands(project);
4563
4677
  const archive = Bun.spawn(commands.tar, {
4678
+ signal: options.signal,
4564
4679
  stderr: "pipe",
4565
4680
  stdout: "pipe"
4566
4681
  });
4567
4682
  const upload = Bun.spawn(commands.remote, {
4683
+ signal: options.signal,
4568
4684
  stderr: "pipe",
4569
4685
  stdin: archive.stdout,
4570
4686
  stdout: "pipe"
@@ -4660,114 +4776,176 @@ var consumeLines2 = async (stream, onLine) => {
4660
4776
  };
4661
4777
  var buildAbsoluteRemoteIosRelease = async (options) => {
4662
4778
  const startedAt = performance.now();
4663
- const syncStartedAt = performance.now();
4664
- await (options.syncProject ?? syncAbsoluteRemoteMacProject)(options.project);
4665
- await (options.syncReleaseInputs ?? syncAbsoluteRemoteMacReleaseInputs)(options.project);
4666
- const syncDuration = performance.now() - syncStartedAt;
4779
+ options.signal?.throwIfAborted();
4780
+ const operation = new AbortController;
4781
+ const abort = () => operation.abort(options.signal?.reason ?? new Error("Remote iOS release cancelled."));
4782
+ options.signal?.addEventListener("abort", abort, { once: true });
4783
+ let lease;
4784
+ const leaseStartedAt = performance.now();
4785
+ try {
4786
+ lease = await (options.acquireLease ?? ((project, signal) => acquireAbsoluteRemoteMacReleaseLease(project, {
4787
+ signal,
4788
+ transport: options.transport
4789
+ })))(options.project, operation.signal);
4790
+ } catch (error) {
4791
+ options.signal?.removeEventListener("abort", abort);
4792
+ throw error;
4793
+ }
4794
+ options.log?.(`${lease.recovered ? "Recovered stale" : "Acquired"} Remote Mac release lease for ${options.project.config.appId}.`);
4795
+ const leaseDuration = performance.now() - leaseStartedAt;
4667
4796
  options.onPhaseTiming?.({
4668
- durationMs: syncDuration,
4669
- phase: "remote-release-sync"
4797
+ durationMs: leaseDuration,
4798
+ phase: "remote-release-lease"
4670
4799
  });
4671
- const agentStartedAt = performance.now();
4672
- const agent = await (options.installAgent ?? installAbsoluteRemoteMacAgent)(options.project);
4673
- const agentDuration = performance.now() - agentStartedAt;
4674
- const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
4675
- const remoteCommand = [
4676
- `cd ${shellQuote(options.project.remoteProjectRoot)}`,
4677
- "&&",
4678
- "exec",
4679
- shellQuote(options.project.profile.bunPath),
4680
- shellQuote(agent.remotePath),
4681
- "--release-ios",
4682
- "--mobile-config",
4683
- shellQuote(encodedConfig),
4684
- ...options.allowUnsigned ? ["--unsigned"] : [],
4685
- ...options.prepareBuildNumber ? ["--request-build-number"] : [],
4686
- ...options.developmentTeam ? ["--development-team", shellQuote(options.developmentTeam)] : []
4687
- ].join(" ");
4688
- const process2 = (options.transport?.spawn ?? defaultTransport.spawn)([
4689
- ...absoluteRemoteMacSshBase(options.project.profile),
4690
- "/bin/sh -lc",
4691
- shellQuote(remoteCommand)
4692
- ], {});
4693
- let failure;
4694
- let metadata;
4695
- const responses = [];
4696
- const stdoutDone = consumeLines2(process2.stdout, (line) => {
4697
- if (!line.startsWith(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX))
4800
+ let heartbeat;
4801
+ const heartbeatTimer = setInterval(() => {
4802
+ if (heartbeat)
4698
4803
  return;
4699
- try {
4700
- const event = JSON.parse(line.slice(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX.length));
4701
- if (event.v !== ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION)
4702
- throw new Error("Remote Mac protocol version mismatch.");
4703
- if (event.type === "log")
4704
- options.log?.(event.message);
4705
- if (event.type === "timing") {
4706
- const durationMs = Reflect.get(event, "durationMs");
4707
- const phase = Reflect.get(event, "phase");
4708
- if (typeof durationMs === "number" && typeof phase === "string")
4709
- options.onPhaseTiming?.({ durationMs, phase });
4710
- }
4711
- if (event.type === "fatal")
4712
- failure = new Error(event.error);
4713
- if (event.type === "release")
4714
- metadata = requireAbsoluteIosReleaseMetadata(event.metadata);
4715
- if (event.type === "build-number-request") {
4716
- if (!options.prepareBuildNumber || !/^[a-f0-9]{64}$/u.test(event.buildIdentity) || !event.id)
4717
- throw new TypeError("Remote Mac requested an invalid iOS build number.");
4718
- responses.push(options.prepareBuildNumber(event.buildIdentity).then(async (buildNumber) => {
4719
- if (!Number.isSafeInteger(buildNumber) || buildNumber < 1)
4720
- throw new TypeError("iOS release publisher returned an invalid build number.");
4721
- process2.stdin.write(`${JSON.stringify({ buildNumber, command: "build-number", id: event.id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
4804
+ heartbeat = lease.heartbeat().catch((error) => operation.abort(error)).finally(() => {
4805
+ heartbeat = undefined;
4806
+ });
4807
+ }, REMOTE_RELEASE_LEASE_HEARTBEAT_MS);
4808
+ heartbeatTimer.unref();
4809
+ try {
4810
+ const syncStartedAt = performance.now();
4811
+ if (options.syncProject)
4812
+ await options.syncProject(options.project);
4813
+ else
4814
+ await syncAbsoluteRemoteMacProject(options.project, {
4815
+ signal: operation.signal
4816
+ });
4817
+ operation.signal.throwIfAborted();
4818
+ if (options.syncReleaseInputs)
4819
+ await options.syncReleaseInputs(options.project);
4820
+ else
4821
+ await syncAbsoluteRemoteMacReleaseInputs(options.project, {
4822
+ signal: operation.signal
4823
+ });
4824
+ operation.signal.throwIfAborted();
4825
+ const syncDuration = performance.now() - syncStartedAt;
4826
+ options.onPhaseTiming?.({
4827
+ durationMs: syncDuration,
4828
+ phase: "remote-release-sync"
4829
+ });
4830
+ const agentStartedAt = performance.now();
4831
+ const agent = await (options.installAgent ?? installAbsoluteRemoteMacAgent)(options.project);
4832
+ operation.signal.throwIfAborted();
4833
+ const agentDuration = performance.now() - agentStartedAt;
4834
+ const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
4835
+ const remoteCommand = [
4836
+ `cd ${shellQuote(options.project.remoteProjectRoot)}`,
4837
+ "&&",
4838
+ "exec",
4839
+ shellQuote(options.project.profile.bunPath),
4840
+ shellQuote(agent.remotePath),
4841
+ "--release-ios",
4842
+ "--mobile-config",
4843
+ shellQuote(encodedConfig),
4844
+ ...options.allowUnsigned ? ["--unsigned"] : [],
4845
+ ...options.prepareBuildNumber ? ["--request-build-number"] : [],
4846
+ ...options.developmentTeam ? ["--development-team", shellQuote(options.developmentTeam)] : []
4847
+ ].join(" ");
4848
+ const process2 = (options.transport?.spawn ?? defaultTransport.spawn)([
4849
+ ...absoluteRemoteMacSshBase(options.project.profile),
4850
+ "/bin/sh -lc",
4851
+ shellQuote(remoteCommand)
4852
+ ], { signal: operation.signal });
4853
+ const killOnAbort = () => process2.kill();
4854
+ operation.signal.addEventListener("abort", killOnAbort, { once: true });
4855
+ let failure;
4856
+ let metadata;
4857
+ const responses = [];
4858
+ const stdoutDone = consumeLines2(process2.stdout, (line) => {
4859
+ if (!line.startsWith(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX))
4860
+ return;
4861
+ try {
4862
+ const event = JSON.parse(line.slice(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX.length));
4863
+ if (event.v !== ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION)
4864
+ throw new Error("Remote Mac protocol version mismatch.");
4865
+ if (event.type === "log")
4866
+ options.log?.(event.message);
4867
+ if (event.type === "timing") {
4868
+ const durationMs = Reflect.get(event, "durationMs");
4869
+ const phase = Reflect.get(event, "phase");
4870
+ if (typeof durationMs === "number" && typeof phase === "string")
4871
+ options.onPhaseTiming?.({ durationMs, phase });
4872
+ }
4873
+ if (event.type === "fatal")
4874
+ failure = new Error(event.error);
4875
+ if (event.type === "release")
4876
+ metadata = requireAbsoluteIosReleaseMetadata(event.metadata);
4877
+ if (event.type === "build-number-request") {
4878
+ if (!options.prepareBuildNumber || !/^[a-f0-9]{64}$/u.test(event.buildIdentity) || !event.id)
4879
+ throw new TypeError("Remote Mac requested an invalid iOS build number.");
4880
+ responses.push(options.prepareBuildNumber(event.buildIdentity).then(async (buildNumber) => {
4881
+ if (!Number.isSafeInteger(buildNumber) || buildNumber < 1)
4882
+ throw new TypeError("iOS release publisher returned an invalid build number.");
4883
+ process2.stdin.write(`${JSON.stringify({ buildNumber, command: "build-number", id: event.id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
4722
4884
  `);
4723
- for (let attempt = 0;attempt < REMOTE_STDIN_FLUSH_ATTEMPTS; attempt++) {
4724
- try {
4725
- await process2.stdin.flush();
4726
- break;
4727
- } catch {
4728
- await Promise.resolve();
4885
+ for (let attempt = 0;attempt < REMOTE_STDIN_FLUSH_ATTEMPTS; attempt++) {
4886
+ try {
4887
+ await process2.stdin.flush();
4888
+ break;
4889
+ } catch {
4890
+ await Promise.resolve();
4891
+ }
4729
4892
  }
4730
- }
4731
- }).catch((error) => {
4732
- failure = error instanceof Error ? error : new Error("Failed to allocate an iOS build number.");
4733
- process2.kill();
4734
- return;
4735
- }));
4893
+ }).catch((error) => {
4894
+ failure = error instanceof Error ? error : new Error("Failed to allocate an iOS build number.");
4895
+ process2.kill();
4896
+ return;
4897
+ }));
4898
+ }
4899
+ } catch (error) {
4900
+ failure = error instanceof Error ? error : new Error("Remote Mac emitted an invalid release event.");
4901
+ process2.kill();
4736
4902
  }
4903
+ });
4904
+ const stderrDone = consumeLines2(process2.stderr, (line) => options.log?.(`[remote] ${line}`));
4905
+ const exitCode = await process2.exited;
4906
+ operation.signal.removeEventListener("abort", killOnAbort);
4907
+ try {
4908
+ process2.stdin.end();
4909
+ } catch {}
4910
+ await Promise.all([stdoutDone, stderrDone, ...responses]);
4911
+ operation.signal.throwIfAborted();
4912
+ if (failure)
4913
+ throw failure;
4914
+ if (exitCode !== 0)
4915
+ throw new Error(`Remote iOS release agent exited with status ${exitCode}.`);
4916
+ if (!metadata)
4917
+ throw new Error("Remote iOS release agent did not return an IPA.");
4918
+ const downloadStartedAt = performance.now();
4919
+ const release = await (options.retrieveRelease ?? retrieveAbsoluteRemoteIosRelease)(options.project, metadata, options.outputDirectory);
4920
+ const downloadDuration = performance.now() - downloadStartedAt;
4921
+ options.onPhaseTiming?.({
4922
+ durationMs: downloadDuration,
4923
+ phase: "remote-release-download"
4924
+ });
4925
+ options.log?.(`Remote Mac ${options.project.profile.name} built and verified iOS release ${metadata.releaseId} in ${(performance.now() - startedAt).toFixed(2)}ms (agent ${agent.uploaded ? "uploaded" : "cache hit"}).`);
4926
+ return {
4927
+ ...release,
4928
+ timings: {
4929
+ "remote-agent": agentDuration,
4930
+ "remote-release-download": downloadDuration,
4931
+ "remote-release-lease": leaseDuration,
4932
+ "remote-release-sync": syncDuration,
4933
+ total: performance.now() - startedAt
4934
+ }
4935
+ };
4936
+ } finally {
4937
+ clearInterval(heartbeatTimer);
4938
+ await heartbeat?.catch(() => {
4939
+ return;
4940
+ });
4941
+ options.signal?.removeEventListener("abort", abort);
4942
+ try {
4943
+ await lease.release();
4944
+ options.log?.("Released Remote Mac release lease.");
4737
4945
  } catch (error) {
4738
- failure = error instanceof Error ? error : new Error("Remote Mac emitted an invalid release event.");
4739
- process2.kill();
4740
- }
4741
- });
4742
- const stderrDone = consumeLines2(process2.stderr, (line) => options.log?.(`[remote] ${line}`));
4743
- const exitCode = await process2.exited;
4744
- try {
4745
- process2.stdin.end();
4746
- } catch {}
4747
- await Promise.all([stdoutDone, stderrDone, ...responses]);
4748
- if (failure)
4749
- throw failure;
4750
- if (exitCode !== 0)
4751
- throw new Error(`Remote iOS release agent exited with status ${exitCode}.`);
4752
- if (!metadata)
4753
- throw new Error("Remote iOS release agent did not return an IPA.");
4754
- const downloadStartedAt = performance.now();
4755
- const release = await (options.retrieveRelease ?? retrieveAbsoluteRemoteIosRelease)(options.project, metadata, options.outputDirectory);
4756
- const downloadDuration = performance.now() - downloadStartedAt;
4757
- options.onPhaseTiming?.({
4758
- durationMs: downloadDuration,
4759
- phase: "remote-release-download"
4760
- });
4761
- options.log?.(`Remote Mac ${options.project.profile.name} built and verified iOS release ${metadata.releaseId} in ${(performance.now() - startedAt).toFixed(2)}ms (agent ${agent.uploaded ? "uploaded" : "cache hit"}).`);
4762
- return {
4763
- ...release,
4764
- timings: {
4765
- "remote-agent": agentDuration,
4766
- "remote-release-download": downloadDuration,
4767
- "remote-release-sync": syncDuration,
4768
- total: performance.now() - startedAt
4946
+ options.log?.(`Remote Mac release lease cleanup failed and will recover after expiry: ${error instanceof Error ? error.message : String(error)}`);
4769
4947
  }
4770
- };
4948
+ }
4771
4949
  };
4772
4950
  var startAbsoluteRemoteExpoIosDevSession = async (options) => {
4773
4951
  const session = await startAbsoluteRemoteDevSession({
@@ -10706,6 +10884,7 @@ export {
10706
10884
  absoluteRemoteReleaseInputSyncCommands,
10707
10885
  acceptsAbsoluteMobilePage,
10708
10886
  acceptsAbsoluteNativeRouteData,
10887
+ acquireAbsoluteRemoteMacReleaseLease,
10709
10888
  activateAbsoluteMobilePage,
10710
10889
  applyAbsoluteNativeDeepLinks,
10711
10890
  applyAbsoluteNativeDeviceCapabilities,
@@ -10717,6 +10896,7 @@ export {
10717
10896
  captureAbsoluteMobileRouteGraph,
10718
10897
  captureAbsoluteRemoteMacCommand,
10719
10898
  carryForwardAbsoluteMobileCompatibilityReleases,
10899
+ cleanAbsoluteRemoteMacWorkspace,
10720
10900
  createAbsoluteExpoBridgeError,
10721
10901
  createAbsoluteExpoBridgeResponse,
10722
10902
  createAbsoluteIosNativeWatcher,
@@ -10753,6 +10933,7 @@ export {
10753
10933
  inspectAbsoluteMobileRouteMetadata,
10754
10934
  inspectAbsoluteRemoteMac,
10755
10935
  inspectAbsoluteRemoteMacLanHost,
10936
+ inspectAbsoluteRemoteMacWorkspace,
10756
10937
  installAbsoluteIosRelease,
10757
10938
  installAbsoluteMobileAuthEnvironment,
10758
10939
  installAbsoluteMobileShellHttp,
@@ -10830,5 +11011,5 @@ export {
10830
11011
  writeAbsoluteMobileGithubWorkflow
10831
11012
  };
10832
11013
 
10833
- //# debugId=F76EB3F5E0BCCF1964756E2164756E21
11014
+ //# debugId=61B4FE527637B49864756E2164756E21
10834
11015
  //# sourceMappingURL=index.js.map