@absolutejs/absolute 0.20.0-beta.105 → 0.20.0-beta.107
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/CHANGELOG.md +14 -0
- package/README.md +6 -0
- package/changelog.json +50 -0
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/cli/{dev-9cp5t2n1.js → dev-f6b6hkke.js} +1 -1
- package/dist/cli/{index-7fxrgx5q.js → index-jf1f6npt.js} +232 -3
- package/dist/cli/index.js +2 -2
- package/dist/cli/{mobile-fbtq3s5x.js → mobile-7v8hfmdq.js} +812 -189
- package/dist/cli/{remoteMacProtocol-bbramzh6.js → remoteMacProtocol-dybpgazw.js} +5 -1
- package/dist/mobile/index.js +762 -101
- package/dist/mobile/index.js.map +8 -7
- package/dist/mobile/remoteMacAgentEntry.js +295 -295
- package/dist/src/mobile/index.d.ts +1 -0
- package/dist/src/mobile/iosReleaseAcceptance.d.ts +3 -0
- package/dist/src/mobile/nativeTestReport.d.ts +1 -0
- package/dist/src/mobile/releaseCertification.d.ts +59 -0
- package/dist/src/mobile/remoteMacProtocol.d.ts +44 -3
- package/dist/src/mobile/remoteMacWire.d.ts +1 -1
- package/package.json +1 -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.107 — 2026-09-16
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Mobile releases gain content-addressed installed-app certification** (`ABSOLUTE_MOBILE_RELEASE_CERTIFICATION_FORMAT`, `AbsoluteMobileCertifiableRelease`, `AbsoluteMobileCertificationEvidence`, `AbsoluteMobileCertificationRelease`, `AbsoluteMobileCertificationRequirement`, `AbsoluteMobileCertificationStrength`, `AbsoluteMobileReleaseCertification`, `AbsoluteMobileReleaseCertificationPaths`, `CreateAbsoluteMobileReleaseCertificationOptions`, `createAbsoluteMobileReleaseCertification`, `readAbsoluteMobileReleaseCertification`, `renderAbsoluteMobileReleaseCertification`, `verifyAbsoluteMobileReleaseCertification`, `writeAbsoluteMobileReleaseCertification`)
|
|
14
|
+
`absolute mobile certify` revalidates immutable Android and iOS releases plus sanitized installed-app reports, binds the exact artifact, embedded runtime, app version, and evidence tier into an atomic content-addressed record, and verifies promotion policy without native tools or credentials. Android requires installed offline proof; iOS preserves the honest Simulator, registered-device, and Apple-processed TestFlight hierarchy.
|
|
15
|
+
|
|
16
|
+
## 0.20.0-beta.106 — 2026-09-16
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **Remote Macs run all three installed iOS release acceptance lanes** (`ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION`, `AbsoluteRemoteIosReleaseAcceptance`, `BuildAbsoluteRemoteIosReleaseOptions`, `RunAbsoluteRemoteIosReleaseAcceptanceOptions`, `cleanAbsoluteRemoteMacWorkspace`, `inspectAbsoluteRemoteMacWorkspace`, `runAbsoluteIosDeviceReleaseAcceptance`, `runAbsoluteIosSimulatorReleaseAcceptance`, `runAbsoluteRemoteIosReleaseAcceptance`, `syncAbsoluteRemoteMacAcceptanceRelease`)
|
|
21
|
+
Paired developer-owned Macs can now export and return the same-archive registered-device IPA, then execute source-equivalent Simulator, archive-equivalent registered-device, and store-delivered TestFlight acceptance from Windows or Linux. Protocol v4 atomically synchronizes and re-hashes immutable releases, validates returned evidence locally, propagates cancellation into Xcode and device tools, and emits sanitized remote-host reports and phase telemetry without transferring signing or publication credentials.
|
|
22
|
+
|
|
9
23
|
## 0.20.0-beta.105 — 2026-09-16
|
|
10
24
|
|
|
11
25
|
### Added
|
package/README.md
CHANGED
|
@@ -281,6 +281,12 @@ The generated workflow keeps signing and provider credentials behind the
|
|
|
281
281
|
`absolute-mobile-release` GitHub environment. See
|
|
282
282
|
[mobile CI and store releases](docs/MOBILE_CI.md).
|
|
283
283
|
|
|
284
|
+
After testing the immutable Android or iOS release, bind its exact artifact and
|
|
285
|
+
runtime identity to the installed, Simulator, device, or store evidence with
|
|
286
|
+
`absolute mobile certify`. The content-addressed result can be checked again in
|
|
287
|
+
CI without credentials or native tooling. See
|
|
288
|
+
[mobile release certification](docs/MOBILE_RELEASE_CERTIFICATION.md).
|
|
289
|
+
|
|
284
290
|
An experimental Expo Router hybrid is also available behind
|
|
285
291
|
`mobile.engine: 'expo'`. Explicit React Native routes use native UI while every
|
|
286
292
|
unclaimed AbsoluteJS route remains an embedded, signed web route regardless of
|
package/changelog.json
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
"contract": 1,
|
|
3
3
|
"name": "@absolutejs/absolute",
|
|
4
4
|
"releases": [
|
|
5
|
+
{
|
|
6
|
+
"changes": [
|
|
7
|
+
{
|
|
8
|
+
"detail": "`absolute mobile certify` revalidates immutable Android and iOS releases plus sanitized installed-app reports, binds the exact artifact, embedded runtime, app version, and evidence tier into an atomic content-addressed record, and verifies promotion policy without native tools or credentials. Android requires installed offline proof; iOS preserves the honest Simulator, registered-device, and Apple-processed TestFlight hierarchy.",
|
|
9
|
+
"kind": "added",
|
|
10
|
+
"summary": "Mobile releases gain content-addressed installed-app certification",
|
|
11
|
+
"symbols": [
|
|
12
|
+
"ABSOLUTE_MOBILE_RELEASE_CERTIFICATION_FORMAT",
|
|
13
|
+
"AbsoluteMobileCertifiableRelease",
|
|
14
|
+
"AbsoluteMobileCertificationEvidence",
|
|
15
|
+
"AbsoluteMobileCertificationRelease",
|
|
16
|
+
"AbsoluteMobileCertificationRequirement",
|
|
17
|
+
"AbsoluteMobileCertificationStrength",
|
|
18
|
+
"AbsoluteMobileReleaseCertification",
|
|
19
|
+
"AbsoluteMobileReleaseCertificationPaths",
|
|
20
|
+
"CreateAbsoluteMobileReleaseCertificationOptions",
|
|
21
|
+
"createAbsoluteMobileReleaseCertification",
|
|
22
|
+
"readAbsoluteMobileReleaseCertification",
|
|
23
|
+
"renderAbsoluteMobileReleaseCertification",
|
|
24
|
+
"verifyAbsoluteMobileReleaseCertification",
|
|
25
|
+
"writeAbsoluteMobileReleaseCertification"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"date": "2026-09-16",
|
|
30
|
+
"version": "0.20.0-beta.107"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"changes": [
|
|
34
|
+
{
|
|
35
|
+
"detail": "Paired developer-owned Macs can now export and return the same-archive registered-device IPA, then execute source-equivalent Simulator, archive-equivalent registered-device, and store-delivered TestFlight acceptance from Windows or Linux. Protocol v4 atomically synchronizes and re-hashes immutable releases, validates returned evidence locally, propagates cancellation into Xcode and device tools, and emits sanitized remote-host reports and phase telemetry without transferring signing or publication credentials.",
|
|
36
|
+
"kind": "added",
|
|
37
|
+
"summary": "Remote Macs run all three installed iOS release acceptance lanes",
|
|
38
|
+
"symbols": [
|
|
39
|
+
"ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION",
|
|
40
|
+
"AbsoluteRemoteIosReleaseAcceptance",
|
|
41
|
+
"BuildAbsoluteRemoteIosReleaseOptions",
|
|
42
|
+
"RunAbsoluteRemoteIosReleaseAcceptanceOptions",
|
|
43
|
+
"cleanAbsoluteRemoteMacWorkspace",
|
|
44
|
+
"inspectAbsoluteRemoteMacWorkspace",
|
|
45
|
+
"runAbsoluteIosDeviceReleaseAcceptance",
|
|
46
|
+
"runAbsoluteIosSimulatorReleaseAcceptance",
|
|
47
|
+
"runAbsoluteRemoteIosReleaseAcceptance",
|
|
48
|
+
"syncAbsoluteRemoteMacAcceptanceRelease"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"date": "2026-09-16",
|
|
53
|
+
"version": "0.20.0-beta.106"
|
|
54
|
+
},
|
|
5
55
|
{
|
|
6
56
|
"changes": [
|
|
7
57
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
|
-
// .angular-partial-tmp-
|
|
4
|
+
// .angular-partial-tmp-M5Hrcs/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-
|
|
4
|
+
// .angular-partial-tmp-M5Hrcs/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-
|
|
51
|
+
// .angular-partial-tmp-M5Hrcs/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";
|
|
@@ -1294,7 +1294,7 @@ var loadAbsoluteMobileDevModules = async () => {
|
|
|
1294
1294
|
import("./emulatorInstaller-3shdna4g.js"),
|
|
1295
1295
|
import("./androidNativeWatcher-2930tb8c.js"),
|
|
1296
1296
|
import("./iosSimulatorController-5n2a9fxv.js"),
|
|
1297
|
-
import("./remoteMacProtocol-
|
|
1297
|
+
import("./remoteMacProtocol-dybpgazw.js"),
|
|
1298
1298
|
import("./iosNativeWatcher-t6gv0p1w.js"),
|
|
1299
1299
|
import("./expoNativeWatcher-rmc95bak.js")
|
|
1300
1300
|
]);
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
|
|
33
33
|
// src/mobile/remoteMacWire.ts
|
|
34
34
|
var ABSOLUTE_REMOTE_MAC_EVENT_PREFIX = "ABSOLUTE_REMOTE_MAC\t";
|
|
35
|
-
var ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION =
|
|
35
|
+
var ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION = 4;
|
|
36
36
|
|
|
37
37
|
// src/mobile/remoteMacProtocol.ts
|
|
38
38
|
var PROFILE_FORMAT = 1;
|
|
@@ -576,6 +576,45 @@ var absoluteRemoteReleaseInputSyncCommands = (project) => {
|
|
|
576
576
|
tar: ["tar", "-cf", "-", "-C", project.config.bundleDirectory, "."]
|
|
577
577
|
};
|
|
578
578
|
};
|
|
579
|
+
var syncAbsoluteRemoteMacAcceptanceRelease = async (project, release, options = {}) => {
|
|
580
|
+
options.signal?.throwIfAborted();
|
|
581
|
+
const destination = posix.join(project.remoteProjectRoot, ".absolutejs", "mobile", "acceptance", "ios", release.metadata.releaseId);
|
|
582
|
+
const staging = `${destination}.incoming-${randomUUID()}`;
|
|
583
|
+
const script = [
|
|
584
|
+
"set -eu",
|
|
585
|
+
"umask 077",
|
|
586
|
+
`rm -rf ${shellQuote(staging)}`,
|
|
587
|
+
`mkdir -p ${shellQuote(staging)}`,
|
|
588
|
+
`tar -xf - -C ${shellQuote(staging)}`,
|
|
589
|
+
`test -f ${shellQuote(posix.join(staging, "release.json"))}`,
|
|
590
|
+
`rm -rf ${shellQuote(destination)}`,
|
|
591
|
+
`mkdir -p ${shellQuote(posix.dirname(destination))}`,
|
|
592
|
+
`mv ${shellQuote(staging)} ${shellQuote(destination)}`
|
|
593
|
+
].join("; ");
|
|
594
|
+
const archive = Bun.spawn(["tar", "-cf", "-", "-C", release.releaseRoot, "."], {
|
|
595
|
+
signal: options.signal,
|
|
596
|
+
stderr: "pipe",
|
|
597
|
+
stdout: "pipe"
|
|
598
|
+
});
|
|
599
|
+
const upload = Bun.spawn([
|
|
600
|
+
...absoluteRemoteMacSshBase(project.profile),
|
|
601
|
+
"/bin/sh -lc",
|
|
602
|
+
shellQuote(script)
|
|
603
|
+
], {
|
|
604
|
+
signal: options.signal,
|
|
605
|
+
stderr: "pipe",
|
|
606
|
+
stdin: archive.stdout,
|
|
607
|
+
stdout: "pipe"
|
|
608
|
+
});
|
|
609
|
+
const [archiveExit, uploadExit, archiveError, uploadError] = await Promise.all([
|
|
610
|
+
archive.exited,
|
|
611
|
+
upload.exited,
|
|
612
|
+
new Response(archive.stderr).text(),
|
|
613
|
+
new Response(upload.stderr).text()
|
|
614
|
+
]);
|
|
615
|
+
if (archiveExit !== 0 || uploadExit !== 0)
|
|
616
|
+
throw new Error(`Remote iOS acceptance artifact synchronization failed: ${(archiveError || uploadError).trim()}`);
|
|
617
|
+
};
|
|
579
618
|
var syncAbsoluteRemoteMacReleaseInputs = async (project, options = {}) => {
|
|
580
619
|
options.signal?.throwIfAborted();
|
|
581
620
|
const commands = absoluteRemoteReleaseInputSyncCommands(project);
|
|
@@ -646,11 +685,28 @@ var retrieveAbsoluteRemoteIosRelease = async (project, metadata, outputDirectory
|
|
|
646
685
|
]);
|
|
647
686
|
if (downloadExit !== 0)
|
|
648
687
|
throw new Error(`Remote iOS release retrieval failed: ${downloadError.trim()}`);
|
|
688
|
+
let registeredArtifactPath;
|
|
689
|
+
if (metadata.registeredDevice) {
|
|
690
|
+
registeredArtifactPath = join(staging, "App.registered-device.ipa");
|
|
691
|
+
const registeredDownload = Bun.spawn([
|
|
692
|
+
...absoluteRemoteMacSshBase(project.profile),
|
|
693
|
+
"/bin/sh -lc",
|
|
694
|
+
shellQuote(`cat ${shellQuote(posix.join(releaseRoot, metadata.registeredDevice.artifact))}`)
|
|
695
|
+
], { stderr: "pipe", stdout: "pipe" });
|
|
696
|
+
const [registeredExit, registeredError] = await Promise.all([
|
|
697
|
+
registeredDownload.exited,
|
|
698
|
+
new Response(registeredDownload.stderr).text(),
|
|
699
|
+
writeRemoteArtifact(registeredArtifactPath, registeredDownload.stdout)
|
|
700
|
+
]);
|
|
701
|
+
if (registeredExit !== 0)
|
|
702
|
+
throw new Error(`Remote iOS registered-device artifact retrieval failed: ${registeredError.trim()}`);
|
|
703
|
+
}
|
|
649
704
|
return await installAbsoluteIosRelease({
|
|
650
705
|
artifactPath,
|
|
651
706
|
metadata,
|
|
652
707
|
outputDirectory,
|
|
653
|
-
projectRoot: project.projectRoot
|
|
708
|
+
projectRoot: project.projectRoot,
|
|
709
|
+
...registeredArtifactPath ? { registeredArtifactPath } : {}
|
|
654
710
|
});
|
|
655
711
|
} finally {
|
|
656
712
|
await rm(staging, { force: true, recursive: true }).catch(() => {
|
|
@@ -748,6 +804,7 @@ var buildAbsoluteRemoteIosRelease = async (options) => {
|
|
|
748
804
|
shellQuote(encodedConfig),
|
|
749
805
|
...options.allowUnsigned ? ["--unsigned"] : [],
|
|
750
806
|
...options.prepareBuildNumber ? ["--request-build-number"] : [],
|
|
807
|
+
...options.registeredDeviceArtifact ? ["--registered-device-artifact"] : [],
|
|
751
808
|
...options.developmentTeam ? ["--development-team", shellQuote(options.developmentTeam)] : []
|
|
752
809
|
].join(" ");
|
|
753
810
|
const process2 = (options.transport?.spawn ?? defaultTransport.spawn)([
|
|
@@ -852,6 +909,178 @@ var buildAbsoluteRemoteIosRelease = async (options) => {
|
|
|
852
909
|
}
|
|
853
910
|
}
|
|
854
911
|
};
|
|
912
|
+
var requireRemoteIosReleaseAcceptance = (value, release, distribution) => {
|
|
913
|
+
if (typeof value !== "object" || value === null)
|
|
914
|
+
throw new TypeError("Remote Mac returned invalid iOS release evidence.");
|
|
915
|
+
const result = value;
|
|
916
|
+
let expectedExactness = "archive-equivalent";
|
|
917
|
+
if (distribution === "simulator-release")
|
|
918
|
+
expectedExactness = "source-equivalent";
|
|
919
|
+
if (distribution === "testflight")
|
|
920
|
+
expectedExactness = "store-delivered";
|
|
921
|
+
const expectedDistribution = distribution === "testflight" ? "apple-processed" : distribution;
|
|
922
|
+
const expectedTarget = distribution === "simulator-release" ? "simulator" : "device";
|
|
923
|
+
if (result.status !== "pass" || result.embeddedLocal !== true || result.releaseId !== release.metadata.releaseId || result.engine !== release.metadata.engine || result.marketingVersion !== release.metadata.marketingVersion || result.artifactSha256 !== release.metadata.sha256 || result.artifactBytes !== release.metadata.bytes || result.signed !== release.metadata.signed || result.artifactExactness !== expectedExactness || result.distribution !== expectedDistribution || result.target !== expectedTarget || (distribution === "simulator-release" ? result.networkUnavailable !== "not-proven" : result.networkUnavailable !== "user-confirmed") || (release.metadata.buildNumber === undefined ? result.buildNumber !== undefined : result.buildNumber !== release.metadata.buildNumber) || !["durationMs", "installMs", "launchMs", "relaunchMs"].every((field) => typeof result[field] === "number" && Number.isFinite(result[field]) && result[field] >= 0))
|
|
924
|
+
throw new TypeError("Remote Mac iOS release evidence does not match the immutable release or requested lane.");
|
|
925
|
+
return value;
|
|
926
|
+
};
|
|
927
|
+
var runAbsoluteRemoteIosReleaseAcceptance = async (options) => {
|
|
928
|
+
options.signal?.throwIfAborted();
|
|
929
|
+
if (options.distribution !== "simulator-release" && !options.deviceIdentifier)
|
|
930
|
+
throw new TypeError("Remote physical iOS release acceptance requires a device identifier.");
|
|
931
|
+
if (options.distribution !== "simulator-release" && !options.networkUnavailableConfirmed)
|
|
932
|
+
throw new TypeError("Remote physical iOS release acceptance requires explicit network-unavailable confirmation.");
|
|
933
|
+
const operation = new AbortController;
|
|
934
|
+
const abort = () => operation.abort(options.signal?.reason ?? new Error("Remote iOS release acceptance cancelled."));
|
|
935
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
936
|
+
const startedAt = performance.now();
|
|
937
|
+
const leaseStartedAt = performance.now();
|
|
938
|
+
let lease;
|
|
939
|
+
try {
|
|
940
|
+
lease = await (options.acquireLease ?? ((project, signal) => acquireAbsoluteRemoteMacReleaseLease(project, {
|
|
941
|
+
signal,
|
|
942
|
+
transport: options.transport
|
|
943
|
+
})))(options.project, operation.signal);
|
|
944
|
+
} catch (error) {
|
|
945
|
+
options.signal?.removeEventListener("abort", abort);
|
|
946
|
+
throw error;
|
|
947
|
+
}
|
|
948
|
+
const leaseDuration = performance.now() - leaseStartedAt;
|
|
949
|
+
options.onPhaseTiming?.({
|
|
950
|
+
durationMs: leaseDuration,
|
|
951
|
+
phase: "remote-release-acceptance-lease"
|
|
952
|
+
});
|
|
953
|
+
let heartbeat;
|
|
954
|
+
const heartbeatTimer = setInterval(() => {
|
|
955
|
+
if (heartbeat)
|
|
956
|
+
return;
|
|
957
|
+
heartbeat = lease.heartbeat().catch((error) => operation.abort(error)).finally(() => {
|
|
958
|
+
heartbeat = undefined;
|
|
959
|
+
});
|
|
960
|
+
}, REMOTE_RELEASE_LEASE_HEARTBEAT_MS);
|
|
961
|
+
unrefTimer(heartbeatTimer);
|
|
962
|
+
try {
|
|
963
|
+
const syncStartedAt = performance.now();
|
|
964
|
+
if (options.syncProject)
|
|
965
|
+
await options.syncProject(options.project);
|
|
966
|
+
else
|
|
967
|
+
await syncAbsoluteRemoteMacProject(options.project, {
|
|
968
|
+
signal: operation.signal
|
|
969
|
+
});
|
|
970
|
+
operation.signal.throwIfAborted();
|
|
971
|
+
if (options.syncReleaseInputs)
|
|
972
|
+
await options.syncReleaseInputs(options.project);
|
|
973
|
+
else
|
|
974
|
+
await syncAbsoluteRemoteMacReleaseInputs(options.project, {
|
|
975
|
+
signal: operation.signal
|
|
976
|
+
});
|
|
977
|
+
operation.signal.throwIfAborted();
|
|
978
|
+
if (options.syncRelease)
|
|
979
|
+
await options.syncRelease(options.project, options.release);
|
|
980
|
+
else
|
|
981
|
+
await syncAbsoluteRemoteMacAcceptanceRelease(options.project, options.release, { signal: operation.signal });
|
|
982
|
+
operation.signal.throwIfAborted();
|
|
983
|
+
const syncDuration = performance.now() - syncStartedAt;
|
|
984
|
+
options.onPhaseTiming?.({
|
|
985
|
+
durationMs: syncDuration,
|
|
986
|
+
phase: "remote-release-acceptance-sync"
|
|
987
|
+
});
|
|
988
|
+
const agent = await (options.installAgent ?? installAbsoluteRemoteMacAgent)(options.project);
|
|
989
|
+
const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
|
|
990
|
+
const remoteCommand = [
|
|
991
|
+
`cd ${shellQuote(options.project.remoteProjectRoot)}`,
|
|
992
|
+
"&&",
|
|
993
|
+
"exec",
|
|
994
|
+
shellQuote(options.project.profile.bunPath),
|
|
995
|
+
shellQuote(agent.remotePath),
|
|
996
|
+
"--test-ios-release",
|
|
997
|
+
"--mobile-config",
|
|
998
|
+
shellQuote(encodedConfig),
|
|
999
|
+
"--release-id",
|
|
1000
|
+
shellQuote(options.release.metadata.releaseId),
|
|
1001
|
+
"--distribution",
|
|
1002
|
+
shellQuote(options.distribution),
|
|
1003
|
+
...options.deviceIdentifier ? ["--device", shellQuote(options.deviceIdentifier)] : [],
|
|
1004
|
+
...options.simulatorUdid ? ["--simulator-udid", shellQuote(options.simulatorUdid)] : [],
|
|
1005
|
+
...options.networkUnavailableConfirmed ? ["--network-unavailable-confirmed"] : []
|
|
1006
|
+
].join(" ");
|
|
1007
|
+
const process2 = (options.transport?.spawn ?? defaultTransport.spawn)([
|
|
1008
|
+
...absoluteRemoteMacSshBase(options.project.profile),
|
|
1009
|
+
"/bin/sh -lc",
|
|
1010
|
+
shellQuote(remoteCommand)
|
|
1011
|
+
], { signal: operation.signal });
|
|
1012
|
+
const killOnAbort = () => process2.kill();
|
|
1013
|
+
operation.signal.addEventListener("abort", killOnAbort, { once: true });
|
|
1014
|
+
let failure;
|
|
1015
|
+
let accepted;
|
|
1016
|
+
const stdoutDone = consumeLines(process2.stdout, (line) => {
|
|
1017
|
+
if (!line.startsWith(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX))
|
|
1018
|
+
return;
|
|
1019
|
+
try {
|
|
1020
|
+
const event = JSON.parse(line.slice(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX.length));
|
|
1021
|
+
if (event.v !== ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION)
|
|
1022
|
+
throw new Error("Remote Mac protocol version mismatch.");
|
|
1023
|
+
if (event.type === "log")
|
|
1024
|
+
options.log?.(event.message);
|
|
1025
|
+
if (event.type === "timing") {
|
|
1026
|
+
const durationMs = Reflect.get(event, "durationMs");
|
|
1027
|
+
const phase = Reflect.get(event, "phase");
|
|
1028
|
+
if (typeof durationMs === "number" && typeof phase === "string")
|
|
1029
|
+
options.onPhaseTiming?.({ durationMs, phase });
|
|
1030
|
+
}
|
|
1031
|
+
if (event.type === "fatal")
|
|
1032
|
+
failure = new Error(event.error);
|
|
1033
|
+
if (event.type === "release-acceptance") {
|
|
1034
|
+
if (!event.targetId || typeof event.targetId !== "string")
|
|
1035
|
+
throw new TypeError("Remote Mac returned an invalid iOS acceptance target.");
|
|
1036
|
+
accepted = {
|
|
1037
|
+
result: requireRemoteIosReleaseAcceptance(event.result, options.release, options.distribution),
|
|
1038
|
+
targetId: event.targetId
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
} catch (error) {
|
|
1042
|
+
failure = error instanceof Error ? error : new Error("Remote Mac emitted invalid iOS release evidence.");
|
|
1043
|
+
process2.kill();
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
const stderrDone = consumeLines(process2.stderr, (line) => options.log?.(`[remote] ${line}`));
|
|
1047
|
+
const exitCode = await process2.exited;
|
|
1048
|
+
operation.signal.removeEventListener("abort", killOnAbort);
|
|
1049
|
+
try {
|
|
1050
|
+
process2.stdin.end();
|
|
1051
|
+
} catch {}
|
|
1052
|
+
await Promise.all([stdoutDone, stderrDone]);
|
|
1053
|
+
operation.signal.throwIfAborted();
|
|
1054
|
+
if (failure)
|
|
1055
|
+
throw failure;
|
|
1056
|
+
if (exitCode !== 0)
|
|
1057
|
+
throw new Error(`Remote iOS release acceptance agent exited with status ${exitCode}.`);
|
|
1058
|
+
if (!accepted)
|
|
1059
|
+
throw new Error("Remote iOS release acceptance agent returned no evidence.");
|
|
1060
|
+
const total = performance.now() - startedAt;
|
|
1061
|
+
options.log?.(`Remote Mac ${options.project.profile.name} completed ${options.distribution} acceptance for ${options.release.metadata.releaseId} in ${total.toFixed(2)}ms (agent ${agent.uploaded ? "uploaded" : "cache hit"}).`);
|
|
1062
|
+
return {
|
|
1063
|
+
...accepted,
|
|
1064
|
+
timings: {
|
|
1065
|
+
"remote-release-acceptance-lease": leaseDuration,
|
|
1066
|
+
"remote-release-acceptance-sync": syncDuration,
|
|
1067
|
+
total
|
|
1068
|
+
}
|
|
1069
|
+
};
|
|
1070
|
+
} finally {
|
|
1071
|
+
clearInterval(heartbeatTimer);
|
|
1072
|
+
await heartbeat?.catch(() => {
|
|
1073
|
+
return;
|
|
1074
|
+
});
|
|
1075
|
+
options.signal?.removeEventListener("abort", abort);
|
|
1076
|
+
try {
|
|
1077
|
+
await lease.release();
|
|
1078
|
+
options.log?.("Released Remote Mac release acceptance lease.");
|
|
1079
|
+
} catch (error) {
|
|
1080
|
+
options.log?.(`Remote Mac acceptance lease cleanup failed and will recover after expiry: ${error instanceof Error ? error.message : String(error)}`);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
855
1084
|
var startAbsoluteRemoteExpoIosDevSession = async (options) => {
|
|
856
1085
|
let session = await startAbsoluteRemoteDevSession({
|
|
857
1086
|
certificateAuthorityPath: options.certificateAuthorityPath,
|
|
@@ -1147,4 +1376,4 @@ var startAbsoluteRemoteDevSession = async (options) => {
|
|
|
1147
1376
|
return makeSession();
|
|
1148
1377
|
};
|
|
1149
1378
|
|
|
1150
|
-
export { ABSOLUTE_REMOTE_MAC_EVENT_PREFIX, ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION, validateAbsoluteRemoteMacProfileName, validateAbsoluteSshDestination, absoluteRemoteMacSshBase, captureAbsoluteRemoteMacCommand, getAbsoluteRemoteMacProfile, inspectAbsoluteRemoteMac, inspectAbsoluteRemoteMacLanHost, listAbsoluteRemoteMacProfiles, pairAbsoluteRemoteMac, removeAbsoluteRemoteMacProfile, createAbsoluteRemoteExpoIosDevProject, createAbsoluteRemoteIosDevProject, acquireAbsoluteRemoteMacReleaseLease, cleanAbsoluteRemoteMacWorkspace, inspectAbsoluteRemoteMacWorkspace, installAbsoluteRemoteMacAgent, materializeAbsoluteRemoteMacAgent, absoluteRemoteProjectSyncCommands, syncAbsoluteRemoteMacProject, absoluteRemoteReleaseInputSyncCommands, syncAbsoluteRemoteMacReleaseInputs, buildAbsoluteRemoteIosRelease, startAbsoluteRemoteExpoIosDevSession, startAbsoluteRemoteIosDevSession };
|
|
1379
|
+
export { ABSOLUTE_REMOTE_MAC_EVENT_PREFIX, ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION, validateAbsoluteRemoteMacProfileName, validateAbsoluteSshDestination, absoluteRemoteMacSshBase, captureAbsoluteRemoteMacCommand, getAbsoluteRemoteMacProfile, inspectAbsoluteRemoteMac, inspectAbsoluteRemoteMacLanHost, listAbsoluteRemoteMacProfiles, pairAbsoluteRemoteMac, removeAbsoluteRemoteMacProfile, createAbsoluteRemoteExpoIosDevProject, createAbsoluteRemoteIosDevProject, acquireAbsoluteRemoteMacReleaseLease, cleanAbsoluteRemoteMacWorkspace, inspectAbsoluteRemoteMacWorkspace, installAbsoluteRemoteMacAgent, materializeAbsoluteRemoteMacAgent, absoluteRemoteProjectSyncCommands, syncAbsoluteRemoteMacProject, absoluteRemoteReleaseInputSyncCommands, syncAbsoluteRemoteMacAcceptanceRelease, syncAbsoluteRemoteMacReleaseInputs, buildAbsoluteRemoteIosRelease, runAbsoluteRemoteIosReleaseAcceptance, startAbsoluteRemoteExpoIosDevSession, startAbsoluteRemoteIosDevSession };
|
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-
|
|
61
|
+
const { dev } = await import("./dev-f6b6hkke.js");
|
|
62
62
|
await dev(serverEntry, configPath, {
|
|
63
63
|
androidDevice,
|
|
64
64
|
eager: args.includes("--eager"),
|
|
@@ -203,7 +203,7 @@ if (command === "dev") {
|
|
|
203
203
|
sendTelemetryEvent("cli:command", {
|
|
204
204
|
command: `mobile:${workspaceCommand ?? "unknown"}`
|
|
205
205
|
});
|
|
206
|
-
const { runMobile } = await import("./mobile-
|
|
206
|
+
const { runMobile } = await import("./mobile-7v8hfmdq.js");
|
|
207
207
|
try {
|
|
208
208
|
await runMobile(args);
|
|
209
209
|
} catch (error) {
|