@absolutejs/absolute 0.20.0-beta.52 → 0.20.0-beta.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/cli/index.js +323 -106
- package/dist/mobile/index.js +284 -103
- package/dist/mobile/index.js.map +3 -3
- package/dist/mobile/remoteMacAgentEntry.js +85 -85
- package/dist/src/mobile/remoteMacProtocol.d.ts +46 -3
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
|
-
// .angular-partial-tmp-
|
|
4
|
+
// .angular-partial-tmp-Ul3n0I/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-Ul3n0I/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-Ul3n0I/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";
|
package/dist/cli/index.js
CHANGED
|
@@ -5957,7 +5957,7 @@ import {
|
|
|
5957
5957
|
resolve as resolvePath,
|
|
5958
5958
|
sep as sep5
|
|
5959
5959
|
} from "path";
|
|
5960
|
-
var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000, PROFILE_NAME, SSH_DESTINATION, defaultProfilePath = () => join15(homedir4(), ".absolutejs", "mobile", "remote-macs.json"), emptyStore = () => ({
|
|
5960
|
+
var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000, REMOTE_RELEASE_LEASE_HEARTBEAT_MS = 15000, REMOTE_RELEASE_LEASE_STALE_SECONDS = 120, PROFILE_NAME, SSH_DESTINATION, defaultProfilePath = () => join15(homedir4(), ".absolutejs", "mobile", "remote-macs.json"), emptyStore = () => ({
|
|
5961
5961
|
format: PROFILE_FORMAT,
|
|
5962
5962
|
profiles: {}
|
|
5963
5963
|
}), loadStore = async (path = defaultProfilePath()) => {
|
|
@@ -6142,7 +6142,111 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6142
6142
|
remoteProjectRoot: posix.join(profile.workspaceRoot, "projects", projectIdentity(projectRoot, config.appId), "current"),
|
|
6143
6143
|
xcodebuild: "remote:xcodebuild",
|
|
6144
6144
|
xcrun: "remote:xcrun"
|
|
6145
|
-
}),
|
|
6145
|
+
}), releaseLeasePath = (project) => posix.join(posix.dirname(project.remoteProjectRoot), ".release-lease"), acquireAbsoluteRemoteMacReleaseLease = async (project, options = {}) => {
|
|
6146
|
+
options.signal?.throwIfAborted();
|
|
6147
|
+
const token = randomUUID4();
|
|
6148
|
+
const path = releaseLeasePath(project);
|
|
6149
|
+
const stalePath = `${path}.stale-${token}`;
|
|
6150
|
+
const staleSeconds = options.staleSeconds ?? REMOTE_RELEASE_LEASE_STALE_SECONDS;
|
|
6151
|
+
if (!Number.isSafeInteger(staleSeconds) || staleSeconds < 30)
|
|
6152
|
+
throw new TypeError("Remote Mac release lease expiry must be at least 30 seconds.");
|
|
6153
|
+
const owner = JSON.stringify({
|
|
6154
|
+
acquiredAt: new Date().toISOString(),
|
|
6155
|
+
appId: project.config.appId,
|
|
6156
|
+
host: process.env.HOSTNAME ?? "unknown",
|
|
6157
|
+
pid: process.pid,
|
|
6158
|
+
token
|
|
6159
|
+
});
|
|
6160
|
+
const script = [
|
|
6161
|
+
"set -eu",
|
|
6162
|
+
"umask 077",
|
|
6163
|
+
`mkdir -p ${shellQuote(posix.dirname(path))}`,
|
|
6164
|
+
`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`,
|
|
6165
|
+
`printf '%s\\n' ${shellQuote(token)} > ${shellQuote(posix.join(path, "token"))}`,
|
|
6166
|
+
`printf '%s\\n' ${shellQuote(owner)} > ${shellQuote(posix.join(path, "owner.json"))}`,
|
|
6167
|
+
`touch ${shellQuote(path)}`,
|
|
6168
|
+
`printf '%s\\n' "$status"`
|
|
6169
|
+
].join("; ");
|
|
6170
|
+
const capture = options.transport?.capture ?? defaultTransport.capture;
|
|
6171
|
+
const result = await capture([
|
|
6172
|
+
...absoluteRemoteMacSshBase(project.profile),
|
|
6173
|
+
"/bin/sh -lc",
|
|
6174
|
+
shellQuote(script)
|
|
6175
|
+
]);
|
|
6176
|
+
if (result.exitCode !== 0) {
|
|
6177
|
+
if (result.exitCode === 73 || result.stdout.startsWith("BUSY"))
|
|
6178
|
+
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(`
|
|
6179
|
+
`).slice(1).join(" ").trim() ? ` Owner: ${result.stdout.split(`
|
|
6180
|
+
`).slice(1).join(" ").trim()}` : ""}`);
|
|
6181
|
+
requireRemoteSuccess(result, "Remote Mac release lease acquisition");
|
|
6182
|
+
}
|
|
6183
|
+
const recovered = result.stdout.trim().split(/\r?\n/u).at(-1) === "RECOVERED";
|
|
6184
|
+
const runOwned = async (action) => {
|
|
6185
|
+
const ownedScript = `test -f ${shellQuote(posix.join(path, "token"))} && ` + `test "$(cat ${shellQuote(posix.join(path, "token"))})" = ${shellQuote(token)} && ${action}`;
|
|
6186
|
+
const owned = await capture([
|
|
6187
|
+
...absoluteRemoteMacSshBase(project.profile),
|
|
6188
|
+
"/bin/sh -lc",
|
|
6189
|
+
shellQuote(ownedScript)
|
|
6190
|
+
]);
|
|
6191
|
+
requireRemoteSuccess(owned, "Remote Mac release lease ownership check");
|
|
6192
|
+
};
|
|
6193
|
+
return {
|
|
6194
|
+
path,
|
|
6195
|
+
recovered,
|
|
6196
|
+
token,
|
|
6197
|
+
heartbeat: () => runOwned(`touch ${shellQuote(path)}`),
|
|
6198
|
+
release: () => runOwned(`rm -rf ${shellQuote(path)}`)
|
|
6199
|
+
};
|
|
6200
|
+
}, inspectAbsoluteRemoteMacWorkspace = async (profile, transport) => {
|
|
6201
|
+
const root = profile.workspaceRoot;
|
|
6202
|
+
const script = [
|
|
6203
|
+
"set -eu",
|
|
6204
|
+
`mkdir -p ${shellQuote(root)}`,
|
|
6205
|
+
`bytes=$(du -sk ${shellQuote(root)} 2>/dev/null | awk '{print $1 * 1024}')`,
|
|
6206
|
+
`projects=$(find ${shellQuote(posix.join(root, "projects"))} -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l | tr -d ' ')`,
|
|
6207
|
+
`agents=$(find ${shellQuote(posix.join(root, "agents"))} -mindepth 2 -maxdepth 2 -type d 2>/dev/null | wc -l | tr -d ' ')`,
|
|
6208
|
+
`leases=$(find ${shellQuote(posix.join(root, "projects"))} -mindepth 2 -maxdepth 2 -type d -name .release-lease 2>/dev/null | wc -l | tr -d ' ')`,
|
|
6209
|
+
`printf '%s\\n%s\\n%s\\n%s\\n' "${"$"}{bytes:-0}" "${"$"}{projects:-0}" "${"$"}{agents:-0}" "${"$"}{leases:-0}"`
|
|
6210
|
+
].join("; ");
|
|
6211
|
+
const result = await (transport?.capture ?? defaultTransport.capture)([
|
|
6212
|
+
...absoluteRemoteMacSshBase(profile),
|
|
6213
|
+
"/bin/sh -lc",
|
|
6214
|
+
shellQuote(script)
|
|
6215
|
+
]);
|
|
6216
|
+
const [bytes, projectCount, agentCount, leaseCount] = requireRemoteSuccess(result, "Remote Mac workspace inspection").split(/\r?\n/u).map(Number);
|
|
6217
|
+
if ([bytes, projectCount, agentCount, leaseCount].some((value) => typeof value !== "number" || !Number.isSafeInteger(value) || value < 0))
|
|
6218
|
+
throw new TypeError("Remote Mac returned invalid workspace statistics.");
|
|
6219
|
+
return {
|
|
6220
|
+
agentCount: agentCount ?? 0,
|
|
6221
|
+
bytes: bytes ?? 0,
|
|
6222
|
+
leaseCount: leaseCount ?? 0,
|
|
6223
|
+
profile: profile.name,
|
|
6224
|
+
projectCount: projectCount ?? 0,
|
|
6225
|
+
workspaceRoot: root
|
|
6226
|
+
};
|
|
6227
|
+
}, cleanAbsoluteRemoteMacWorkspace = async (profile, transport) => {
|
|
6228
|
+
const root = profile.workspaceRoot;
|
|
6229
|
+
const projects = posix.join(root, "projects");
|
|
6230
|
+
const script = [
|
|
6231
|
+
"set -eu",
|
|
6232
|
+
`mkdir -p ${shellQuote(root)}`,
|
|
6233
|
+
`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 ' ')`,
|
|
6234
|
+
`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 ' ')`,
|
|
6235
|
+
`count=$((project_staging+mobile_staging))`,
|
|
6236
|
+
`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`,
|
|
6237
|
+
`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`,
|
|
6238
|
+
`printf '%s\\n' "$count"`
|
|
6239
|
+
].join("; ");
|
|
6240
|
+
const result = await (transport?.capture ?? defaultTransport.capture)([
|
|
6241
|
+
...absoluteRemoteMacSshBase(profile),
|
|
6242
|
+
"/bin/sh -lc",
|
|
6243
|
+
shellQuote(script)
|
|
6244
|
+
]);
|
|
6245
|
+
const removed = Number(requireRemoteSuccess(result, "Remote Mac workspace cleanup"));
|
|
6246
|
+
if (!Number.isSafeInteger(removed) || removed < 0)
|
|
6247
|
+
throw new TypeError("Remote Mac returned an invalid cleanup result.");
|
|
6248
|
+
return { profile: profile.name, removed, workspaceRoot: root };
|
|
6249
|
+
}, installAbsoluteRemoteMacAgent = async (project) => {
|
|
6146
6250
|
const artifact = await materializeAbsoluteRemoteMacAgent(project.projectRoot);
|
|
6147
6251
|
const directory = posix.join(project.profile.workspaceRoot, "agents", `protocol-${ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION}`, artifact.sha256);
|
|
6148
6252
|
const remotePath = posix.join(directory, "agent.js");
|
|
@@ -6291,13 +6395,16 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6291
6395
|
"."
|
|
6292
6396
|
]
|
|
6293
6397
|
};
|
|
6294
|
-
}, syncAbsoluteRemoteMacProject = async (project) => {
|
|
6398
|
+
}, syncAbsoluteRemoteMacProject = async (project, options = {}) => {
|
|
6399
|
+
options.signal?.throwIfAborted();
|
|
6295
6400
|
const commands = absoluteRemoteProjectSyncCommands(project);
|
|
6296
6401
|
const archive = Bun.spawn(commands.tar, {
|
|
6402
|
+
signal: options.signal,
|
|
6297
6403
|
stderr: "pipe",
|
|
6298
6404
|
stdout: "pipe"
|
|
6299
6405
|
});
|
|
6300
6406
|
const upload = Bun.spawn(commands.remote, {
|
|
6407
|
+
signal: options.signal,
|
|
6301
6408
|
stderr: "pipe",
|
|
6302
6409
|
stdin: archive.stdout,
|
|
6303
6410
|
stdout: "pipe"
|
|
@@ -6342,13 +6449,16 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6342
6449
|
],
|
|
6343
6450
|
tar: ["tar", "-cf", "-", "-C", project.config.bundleDirectory, "."]
|
|
6344
6451
|
};
|
|
6345
|
-
}, syncAbsoluteRemoteMacReleaseInputs = async (project) => {
|
|
6452
|
+
}, syncAbsoluteRemoteMacReleaseInputs = async (project, options = {}) => {
|
|
6453
|
+
options.signal?.throwIfAborted();
|
|
6346
6454
|
const commands = absoluteRemoteReleaseInputSyncCommands(project);
|
|
6347
6455
|
const archive = Bun.spawn(commands.tar, {
|
|
6456
|
+
signal: options.signal,
|
|
6348
6457
|
stderr: "pipe",
|
|
6349
6458
|
stdout: "pipe"
|
|
6350
6459
|
});
|
|
6351
6460
|
const upload = Bun.spawn(commands.remote, {
|
|
6461
|
+
signal: options.signal,
|
|
6352
6462
|
stderr: "pipe",
|
|
6353
6463
|
stdin: archive.stdout,
|
|
6354
6464
|
stdout: "pipe"
|
|
@@ -6440,114 +6550,176 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
6440
6550
|
}
|
|
6441
6551
|
}, buildAbsoluteRemoteIosRelease = async (options) => {
|
|
6442
6552
|
const startedAt = performance.now();
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6553
|
+
options.signal?.throwIfAborted();
|
|
6554
|
+
const operation2 = new AbortController;
|
|
6555
|
+
const abort = () => operation2.abort(options.signal?.reason ?? new Error("Remote iOS release cancelled."));
|
|
6556
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
6557
|
+
let lease;
|
|
6558
|
+
const leaseStartedAt = performance.now();
|
|
6559
|
+
try {
|
|
6560
|
+
lease = await (options.acquireLease ?? ((project, signal) => acquireAbsoluteRemoteMacReleaseLease(project, {
|
|
6561
|
+
signal,
|
|
6562
|
+
transport: options.transport
|
|
6563
|
+
})))(options.project, operation2.signal);
|
|
6564
|
+
} catch (error) {
|
|
6565
|
+
options.signal?.removeEventListener("abort", abort);
|
|
6566
|
+
throw error;
|
|
6567
|
+
}
|
|
6568
|
+
options.log?.(`${lease.recovered ? "Recovered stale" : "Acquired"} Remote Mac release lease for ${options.project.config.appId}.`);
|
|
6569
|
+
const leaseDuration = performance.now() - leaseStartedAt;
|
|
6447
6570
|
options.onPhaseTiming?.({
|
|
6448
|
-
durationMs:
|
|
6449
|
-
phase: "remote-release-
|
|
6571
|
+
durationMs: leaseDuration,
|
|
6572
|
+
phase: "remote-release-lease"
|
|
6450
6573
|
});
|
|
6451
|
-
|
|
6452
|
-
const
|
|
6453
|
-
|
|
6454
|
-
const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
|
|
6455
|
-
const remoteCommand = [
|
|
6456
|
-
`cd ${shellQuote(options.project.remoteProjectRoot)}`,
|
|
6457
|
-
"&&",
|
|
6458
|
-
"exec",
|
|
6459
|
-
shellQuote(options.project.profile.bunPath),
|
|
6460
|
-
shellQuote(agent.remotePath),
|
|
6461
|
-
"--release-ios",
|
|
6462
|
-
"--mobile-config",
|
|
6463
|
-
shellQuote(encodedConfig),
|
|
6464
|
-
...options.allowUnsigned ? ["--unsigned"] : [],
|
|
6465
|
-
...options.prepareBuildNumber ? ["--request-build-number"] : [],
|
|
6466
|
-
...options.developmentTeam ? ["--development-team", shellQuote(options.developmentTeam)] : []
|
|
6467
|
-
].join(" ");
|
|
6468
|
-
const process2 = (options.transport?.spawn ?? defaultTransport.spawn)([
|
|
6469
|
-
...absoluteRemoteMacSshBase(options.project.profile),
|
|
6470
|
-
"/bin/sh -lc",
|
|
6471
|
-
shellQuote(remoteCommand)
|
|
6472
|
-
], {});
|
|
6473
|
-
let failure;
|
|
6474
|
-
let metadata;
|
|
6475
|
-
const responses = [];
|
|
6476
|
-
const stdoutDone = consumeLines2(process2.stdout, (line) => {
|
|
6477
|
-
if (!line.startsWith(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX))
|
|
6574
|
+
let heartbeat;
|
|
6575
|
+
const heartbeatTimer = setInterval(() => {
|
|
6576
|
+
if (heartbeat)
|
|
6478
6577
|
return;
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6578
|
+
heartbeat = lease.heartbeat().catch((error) => operation2.abort(error)).finally(() => {
|
|
6579
|
+
heartbeat = undefined;
|
|
6580
|
+
});
|
|
6581
|
+
}, REMOTE_RELEASE_LEASE_HEARTBEAT_MS);
|
|
6582
|
+
heartbeatTimer.unref();
|
|
6583
|
+
try {
|
|
6584
|
+
const syncStartedAt = performance.now();
|
|
6585
|
+
if (options.syncProject)
|
|
6586
|
+
await options.syncProject(options.project);
|
|
6587
|
+
else
|
|
6588
|
+
await syncAbsoluteRemoteMacProject(options.project, {
|
|
6589
|
+
signal: operation2.signal
|
|
6590
|
+
});
|
|
6591
|
+
operation2.signal.throwIfAborted();
|
|
6592
|
+
if (options.syncReleaseInputs)
|
|
6593
|
+
await options.syncReleaseInputs(options.project);
|
|
6594
|
+
else
|
|
6595
|
+
await syncAbsoluteRemoteMacReleaseInputs(options.project, {
|
|
6596
|
+
signal: operation2.signal
|
|
6597
|
+
});
|
|
6598
|
+
operation2.signal.throwIfAborted();
|
|
6599
|
+
const syncDuration = performance.now() - syncStartedAt;
|
|
6600
|
+
options.onPhaseTiming?.({
|
|
6601
|
+
durationMs: syncDuration,
|
|
6602
|
+
phase: "remote-release-sync"
|
|
6603
|
+
});
|
|
6604
|
+
const agentStartedAt = performance.now();
|
|
6605
|
+
const agent = await (options.installAgent ?? installAbsoluteRemoteMacAgent)(options.project);
|
|
6606
|
+
operation2.signal.throwIfAborted();
|
|
6607
|
+
const agentDuration = performance.now() - agentStartedAt;
|
|
6608
|
+
const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
|
|
6609
|
+
const remoteCommand = [
|
|
6610
|
+
`cd ${shellQuote(options.project.remoteProjectRoot)}`,
|
|
6611
|
+
"&&",
|
|
6612
|
+
"exec",
|
|
6613
|
+
shellQuote(options.project.profile.bunPath),
|
|
6614
|
+
shellQuote(agent.remotePath),
|
|
6615
|
+
"--release-ios",
|
|
6616
|
+
"--mobile-config",
|
|
6617
|
+
shellQuote(encodedConfig),
|
|
6618
|
+
...options.allowUnsigned ? ["--unsigned"] : [],
|
|
6619
|
+
...options.prepareBuildNumber ? ["--request-build-number"] : [],
|
|
6620
|
+
...options.developmentTeam ? ["--development-team", shellQuote(options.developmentTeam)] : []
|
|
6621
|
+
].join(" ");
|
|
6622
|
+
const process2 = (options.transport?.spawn ?? defaultTransport.spawn)([
|
|
6623
|
+
...absoluteRemoteMacSshBase(options.project.profile),
|
|
6624
|
+
"/bin/sh -lc",
|
|
6625
|
+
shellQuote(remoteCommand)
|
|
6626
|
+
], { signal: operation2.signal });
|
|
6627
|
+
const killOnAbort = () => process2.kill();
|
|
6628
|
+
operation2.signal.addEventListener("abort", killOnAbort, { once: true });
|
|
6629
|
+
let failure;
|
|
6630
|
+
let metadata;
|
|
6631
|
+
const responses = [];
|
|
6632
|
+
const stdoutDone = consumeLines2(process2.stdout, (line) => {
|
|
6633
|
+
if (!line.startsWith(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX))
|
|
6634
|
+
return;
|
|
6635
|
+
try {
|
|
6636
|
+
const event = JSON.parse(line.slice(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX.length));
|
|
6637
|
+
if (event.v !== ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION)
|
|
6638
|
+
throw new Error("Remote Mac protocol version mismatch.");
|
|
6639
|
+
if (event.type === "log")
|
|
6640
|
+
options.log?.(event.message);
|
|
6641
|
+
if (event.type === "timing") {
|
|
6642
|
+
const durationMs = Reflect.get(event, "durationMs");
|
|
6643
|
+
const phase = Reflect.get(event, "phase");
|
|
6644
|
+
if (typeof durationMs === "number" && typeof phase === "string")
|
|
6645
|
+
options.onPhaseTiming?.({ durationMs, phase });
|
|
6646
|
+
}
|
|
6647
|
+
if (event.type === "fatal")
|
|
6648
|
+
failure = new Error(event.error);
|
|
6649
|
+
if (event.type === "release")
|
|
6650
|
+
metadata = requireAbsoluteIosReleaseMetadata(event.metadata);
|
|
6651
|
+
if (event.type === "build-number-request") {
|
|
6652
|
+
if (!options.prepareBuildNumber || !/^[a-f0-9]{64}$/u.test(event.buildIdentity) || !event.id)
|
|
6653
|
+
throw new TypeError("Remote Mac requested an invalid iOS build number.");
|
|
6654
|
+
responses.push(options.prepareBuildNumber(event.buildIdentity).then(async (buildNumber) => {
|
|
6655
|
+
if (!Number.isSafeInteger(buildNumber) || buildNumber < 1)
|
|
6656
|
+
throw new TypeError("iOS release publisher returned an invalid build number.");
|
|
6657
|
+
process2.stdin.write(`${JSON.stringify({ buildNumber, command: "build-number", id: event.id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
|
|
6502
6658
|
`);
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6659
|
+
for (let attempt = 0;attempt < REMOTE_STDIN_FLUSH_ATTEMPTS; attempt++) {
|
|
6660
|
+
try {
|
|
6661
|
+
await process2.stdin.flush();
|
|
6662
|
+
break;
|
|
6663
|
+
} catch {
|
|
6664
|
+
await Promise.resolve();
|
|
6665
|
+
}
|
|
6509
6666
|
}
|
|
6510
|
-
}
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
}
|
|
6667
|
+
}).catch((error) => {
|
|
6668
|
+
failure = error instanceof Error ? error : new Error("Failed to allocate an iOS build number.");
|
|
6669
|
+
process2.kill();
|
|
6670
|
+
return;
|
|
6671
|
+
}));
|
|
6672
|
+
}
|
|
6673
|
+
} catch (error) {
|
|
6674
|
+
failure = error instanceof Error ? error : new Error("Remote Mac emitted an invalid release event.");
|
|
6675
|
+
process2.kill();
|
|
6676
|
+
}
|
|
6677
|
+
});
|
|
6678
|
+
const stderrDone = consumeLines2(process2.stderr, (line) => options.log?.(`[remote] ${line}`));
|
|
6679
|
+
const exitCode = await process2.exited;
|
|
6680
|
+
operation2.signal.removeEventListener("abort", killOnAbort);
|
|
6681
|
+
try {
|
|
6682
|
+
process2.stdin.end();
|
|
6683
|
+
} catch {}
|
|
6684
|
+
await Promise.all([stdoutDone, stderrDone, ...responses]);
|
|
6685
|
+
operation2.signal.throwIfAborted();
|
|
6686
|
+
if (failure)
|
|
6687
|
+
throw failure;
|
|
6688
|
+
if (exitCode !== 0)
|
|
6689
|
+
throw new Error(`Remote iOS release agent exited with status ${exitCode}.`);
|
|
6690
|
+
if (!metadata)
|
|
6691
|
+
throw new Error("Remote iOS release agent did not return an IPA.");
|
|
6692
|
+
const downloadStartedAt = performance.now();
|
|
6693
|
+
const release = await (options.retrieveRelease ?? retrieveAbsoluteRemoteIosRelease)(options.project, metadata, options.outputDirectory);
|
|
6694
|
+
const downloadDuration = performance.now() - downloadStartedAt;
|
|
6695
|
+
options.onPhaseTiming?.({
|
|
6696
|
+
durationMs: downloadDuration,
|
|
6697
|
+
phase: "remote-release-download"
|
|
6698
|
+
});
|
|
6699
|
+
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"}).`);
|
|
6700
|
+
return {
|
|
6701
|
+
...release,
|
|
6702
|
+
timings: {
|
|
6703
|
+
"remote-agent": agentDuration,
|
|
6704
|
+
"remote-release-download": downloadDuration,
|
|
6705
|
+
"remote-release-lease": leaseDuration,
|
|
6706
|
+
"remote-release-sync": syncDuration,
|
|
6707
|
+
total: performance.now() - startedAt
|
|
6516
6708
|
}
|
|
6709
|
+
};
|
|
6710
|
+
} finally {
|
|
6711
|
+
clearInterval(heartbeatTimer);
|
|
6712
|
+
await heartbeat?.catch(() => {
|
|
6713
|
+
return;
|
|
6714
|
+
});
|
|
6715
|
+
options.signal?.removeEventListener("abort", abort);
|
|
6716
|
+
try {
|
|
6717
|
+
await lease.release();
|
|
6718
|
+
options.log?.("Released Remote Mac release lease.");
|
|
6517
6719
|
} catch (error) {
|
|
6518
|
-
|
|
6519
|
-
process2.kill();
|
|
6520
|
-
}
|
|
6521
|
-
});
|
|
6522
|
-
const stderrDone = consumeLines2(process2.stderr, (line) => options.log?.(`[remote] ${line}`));
|
|
6523
|
-
const exitCode = await process2.exited;
|
|
6524
|
-
try {
|
|
6525
|
-
process2.stdin.end();
|
|
6526
|
-
} catch {}
|
|
6527
|
-
await Promise.all([stdoutDone, stderrDone, ...responses]);
|
|
6528
|
-
if (failure)
|
|
6529
|
-
throw failure;
|
|
6530
|
-
if (exitCode !== 0)
|
|
6531
|
-
throw new Error(`Remote iOS release agent exited with status ${exitCode}.`);
|
|
6532
|
-
if (!metadata)
|
|
6533
|
-
throw new Error("Remote iOS release agent did not return an IPA.");
|
|
6534
|
-
const downloadStartedAt = performance.now();
|
|
6535
|
-
const release = await (options.retrieveRelease ?? retrieveAbsoluteRemoteIosRelease)(options.project, metadata, options.outputDirectory);
|
|
6536
|
-
const downloadDuration = performance.now() - downloadStartedAt;
|
|
6537
|
-
options.onPhaseTiming?.({
|
|
6538
|
-
durationMs: downloadDuration,
|
|
6539
|
-
phase: "remote-release-download"
|
|
6540
|
-
});
|
|
6541
|
-
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"}).`);
|
|
6542
|
-
return {
|
|
6543
|
-
...release,
|
|
6544
|
-
timings: {
|
|
6545
|
-
"remote-agent": agentDuration,
|
|
6546
|
-
"remote-release-download": downloadDuration,
|
|
6547
|
-
"remote-release-sync": syncDuration,
|
|
6548
|
-
total: performance.now() - startedAt
|
|
6720
|
+
options.log?.(`Remote Mac release lease cleanup failed and will recover after expiry: ${error instanceof Error ? error.message : String(error)}`);
|
|
6549
6721
|
}
|
|
6550
|
-
}
|
|
6722
|
+
}
|
|
6551
6723
|
}, startAbsoluteRemoteExpoIosDevSession = async (options) => {
|
|
6552
6724
|
const session = await startAbsoluteRemoteDevSession({
|
|
6553
6725
|
certificateAuthorityPath: options.certificateAuthorityPath,
|
|
@@ -22251,6 +22423,32 @@ var NOT_FOUND4 = -1, isRecord17 = (value) => typeof value === "object" && value
|
|
|
22251
22423
|
});
|
|
22252
22424
|
console.log(`Paired remote Mac ${profile.name} (${profile.xcodeVersion}) and selected it as the default iOS development host.`);
|
|
22253
22425
|
}, listRemoteMacs = async (args) => {
|
|
22426
|
+
if (args[0] === "inspect") {
|
|
22427
|
+
const requested = args[1]?.startsWith("-") ? undefined : args[1];
|
|
22428
|
+
const profile = await getAbsoluteRemoteMacProfile(requested, remoteProfilePath());
|
|
22429
|
+
if (!profile)
|
|
22430
|
+
throw new TypeError("No Remote Mac is selected. Pair one before inspecting its workspace.");
|
|
22431
|
+
const inspection = await inspectAbsoluteRemoteMacWorkspace(profile);
|
|
22432
|
+
console.log(args.includes("--json") ? JSON.stringify(inspection, null, 2) : [
|
|
22433
|
+
`Remote Mac: ${inspection.profile}`,
|
|
22434
|
+
`Workspace: ${inspection.workspaceRoot}`,
|
|
22435
|
+
`Cache: ${(inspection.bytes / 1048576).toFixed(1)} MiB across ${inspection.projectCount} project(s) and ${inspection.agentCount} agent artifact(s)`,
|
|
22436
|
+
`Active release leases: ${inspection.leaseCount}`
|
|
22437
|
+
].join(`
|
|
22438
|
+
`));
|
|
22439
|
+
return;
|
|
22440
|
+
}
|
|
22441
|
+
if (args[0] === "clean") {
|
|
22442
|
+
if (!args.includes("--yes"))
|
|
22443
|
+
throw new TypeError("Remote Mac cleanup requires --yes. It removes only abandoned staging directories older than one day.");
|
|
22444
|
+
const requested = args[1]?.startsWith("-") ? undefined : args[1];
|
|
22445
|
+
const profile = await getAbsoluteRemoteMacProfile(requested, remoteProfilePath());
|
|
22446
|
+
if (!profile)
|
|
22447
|
+
throw new TypeError("No Remote Mac is selected. Pair one before cleaning its workspace.");
|
|
22448
|
+
const result2 = await cleanAbsoluteRemoteMacWorkspace(profile);
|
|
22449
|
+
console.log(`Removed ${result2.removed} abandoned Remote Mac staging director${result2.removed === 1 ? "y" : "ies"}; project caches, releases, and active leases were retained.`);
|
|
22450
|
+
return;
|
|
22451
|
+
}
|
|
22254
22452
|
const result = await listAbsoluteRemoteMacProfiles(remoteProfilePath());
|
|
22255
22453
|
if (args.includes("--json")) {
|
|
22256
22454
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -22748,6 +22946,18 @@ Mobile release security and compliance checks failed.`);
|
|
|
22748
22946
|
...options.prepareBuildNumber === undefined ? {} : { prepareBuildNumber: options.prepareBuildNumber },
|
|
22749
22947
|
projectRoot: options.projectRoot
|
|
22750
22948
|
});
|
|
22949
|
+
}, listenForRemoteReleaseCancellation = (cancellation) => {
|
|
22950
|
+
if (!cancellation)
|
|
22951
|
+
return () => {
|
|
22952
|
+
return;
|
|
22953
|
+
};
|
|
22954
|
+
const cancel = () => cancellation.abort(new Error("Remote iOS release interrupted."));
|
|
22955
|
+
process.once("SIGINT", cancel);
|
|
22956
|
+
process.once("SIGTERM", cancel);
|
|
22957
|
+
return () => {
|
|
22958
|
+
process.removeListener("SIGINT", cancel);
|
|
22959
|
+
process.removeListener("SIGTERM", cancel);
|
|
22960
|
+
};
|
|
22751
22961
|
}, buildIos = async (args, prepareBuildNumber) => {
|
|
22752
22962
|
const configPath2 = valueAfter(args, "--config");
|
|
22753
22963
|
const { mobile, projectRoot } = await loadMobile(configPath2);
|
|
@@ -22762,10 +22972,15 @@ Mobile release security and compliance checks failed.`);
|
|
|
22762
22972
|
if (process.platform !== "darwin" && !remoteProfile)
|
|
22763
22973
|
throw new TypeError("iOS release builds require macOS or a paired Remote Mac. Run `absolute mobile pair mac <name> <user@host>`.");
|
|
22764
22974
|
let success = false;
|
|
22975
|
+
const cancellation = remoteProfile ? new AbortController : undefined;
|
|
22976
|
+
let stopListeningForCancellation = () => {
|
|
22977
|
+
return;
|
|
22978
|
+
};
|
|
22765
22979
|
try {
|
|
22766
22980
|
if (!remoteProfile && mobile.engine === "capacitor")
|
|
22767
22981
|
await repairAbsoluteIosDevSession(projectRoot);
|
|
22768
22982
|
await start(mobileBuildServerEntry(args), valueAfter(args, "--web-outdir"), configPath2, { prepareOnly: true });
|
|
22983
|
+
stopListeningForCancellation = listenForRemoteReleaseCancellation(cancellation);
|
|
22769
22984
|
const release = remoteProfile ? await buildAbsoluteRemoteIosRelease({
|
|
22770
22985
|
allowUnsigned: args.includes("--unsigned"),
|
|
22771
22986
|
developmentTeam: process.env.ABSOLUTE_IOS_DEVELOPMENT_TEAM,
|
|
@@ -22782,7 +22997,8 @@ Mobile release security and compliance checks failed.`);
|
|
|
22782
22997
|
});
|
|
22783
22998
|
},
|
|
22784
22999
|
...prepareBuildNumber === undefined ? {} : { prepareBuildNumber },
|
|
22785
|
-
project: createAbsoluteRemoteIosDevProject(mobile, projectRoot, remoteProfile)
|
|
23000
|
+
project: createAbsoluteRemoteIosDevProject(mobile, projectRoot, remoteProfile),
|
|
23001
|
+
signal: cancellation?.signal
|
|
22786
23002
|
}) : await buildLocalIosRelease({
|
|
22787
23003
|
args,
|
|
22788
23004
|
mobile,
|
|
@@ -22796,6 +23012,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
22796
23012
|
console.log(`Metadata: ${join56(release.releaseRoot, "release.json")}`);
|
|
22797
23013
|
return release;
|
|
22798
23014
|
} finally {
|
|
23015
|
+
stopListeningForCancellation();
|
|
22799
23016
|
sendTelemetryEvent("mobile:ios-release-build", {
|
|
22800
23017
|
durationMs: Math.round(performance.now() - startedAt),
|
|
22801
23018
|
engine: mobile.engine,
|
|
@@ -23722,7 +23939,7 @@ Emulator setup verification:`);
|
|
|
23722
23939
|
await publishIos(args.slice(2));
|
|
23723
23940
|
return;
|
|
23724
23941
|
}
|
|
23725
|
-
throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [--json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | inspect [--json] [--require-bundle] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--outdir dir] [--web-outdir dir] [--unsigned] | publish android [server-entry] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--remote name] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--route path] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--serial id] [--artifacts dir] [--json] | test ios [--device identifier [--remote name] | --udid id] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--artifacts dir] [--json]> [--config path]");
|
|
23942
|
+
throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [inspect [name] [--json] | clean [name] --yes | --json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | inspect [--json] [--require-bundle] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--outdir dir] [--web-outdir dir] [--unsigned] | publish android [server-entry] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--remote name] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--route path] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--serial id] [--artifacts dir] [--json] | test ios [--device identifier [--remote name] | --udid id] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--artifacts dir] [--json]> [--config path]");
|
|
23726
23943
|
};
|
|
23727
23944
|
var init_mobile = __esm(() => {
|
|
23728
23945
|
init_dependencies();
|