@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/dist/mobile/index.js
CHANGED
|
@@ -20032,7 +20032,7 @@ __export(exports_mobileUpdate, {
|
|
|
20032
20032
|
parseMobileUpdateManifest: () => parseMobileUpdateManifest
|
|
20033
20033
|
});
|
|
20034
20034
|
import {
|
|
20035
|
-
createHash as
|
|
20035
|
+
createHash as createHash19,
|
|
20036
20036
|
createHmac,
|
|
20037
20037
|
createPrivateKey,
|
|
20038
20038
|
createPublicKey as createPublicKey2,
|
|
@@ -20042,7 +20042,7 @@ import {
|
|
|
20042
20042
|
verify as verify2,
|
|
20043
20043
|
X509Certificate as X509Certificate3
|
|
20044
20044
|
} from "crypto";
|
|
20045
|
-
import { readFile as
|
|
20045
|
+
import { readFile as readFile28, stat as stat7 } from "fs/promises";
|
|
20046
20046
|
import path from "path";
|
|
20047
20047
|
var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updates", MAX_FILE_BYTES, MAX_TOTAL_BYTES, DAY_MS, DEFAULT_MIN_AGE_MS, DEFAULT_GRACE_PERIOD_MS, DEFAULT_RETAIN_RECENT = 5, HASH, RELEASE, APP_ID, NAME, EXPO_DESCRIPTOR = "_absolute/expo-update.json", EXPO_CODE_SIGNING_ALGORITHM = "rsa-v1_5-sha256", HEALTH_TOKEN_VERSION = 1, HEALTH_KINDS, FAILURE_HEALTH_KINDS, MobileUpdateRegistryError, object6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), text2 = (value, field2) => {
|
|
20048
20048
|
if (typeof value !== "string" || value.length === 0)
|
|
@@ -20192,7 +20192,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
20192
20192
|
if (!prefix || prefix.split("/").some((segment) => segment === "." || segment === ".."))
|
|
20193
20193
|
throw new MobileUpdateRegistryError("Mobile update prefix is invalid");
|
|
20194
20194
|
return prefix;
|
|
20195
|
-
}, appHash = (appId) =>
|
|
20195
|
+
}, appHash = (appId) => createHash19("sha256").update(appId).digest("hex"), digest = (bytes) => createHash19("sha256").update(bytes).digest("hex"), json = (value) => new TextEncoder().encode(`${JSON.stringify(value, null, 2)}
|
|
20196
20196
|
`), decode2 = (value) => JSON.parse(new TextDecoder().decode(value)), fileDigest = async (file) => {
|
|
20197
20197
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
20198
20198
|
for await (const chunk of file.stream())
|
|
@@ -20203,7 +20203,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
20203
20203
|
return false;
|
|
20204
20204
|
if (input.rollout === 1)
|
|
20205
20205
|
return true;
|
|
20206
|
-
const value =
|
|
20206
|
+
const value = createHash19("sha256").update(`${input.appId}\x00${input.channel}\x00${input.releaseId}\x00${input.installationId}`).digest().readUInt32BE(0);
|
|
20207
20207
|
return value / 4294967296 < input.rollout;
|
|
20208
20208
|
}, base64Url = (value) => Buffer.from(value).toString("base64url"), healthPromotionId = (channel) => channel.promotionId ?? digest(new TextEncoder().encode(`${channel.appId}\x00${channel.channel}\x00${channel.releaseId ?? "embedded"}\x00${channel.promotedAt}`)), finiteMetric = (value, field2) => {
|
|
20209
20209
|
if (typeof value !== "number" || !Number.isFinite(value) || value < 0)
|
|
@@ -20243,7 +20243,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
20243
20243
|
const releaseRoot = (manifest) => `${root(manifest.appId)}/releases/${manifest.releaseId}`;
|
|
20244
20244
|
const manifestKey = (manifest) => `${releaseRoot(manifest)}/update.json`;
|
|
20245
20245
|
const fileKey = (manifest, file) => `${releaseRoot(manifest)}/files/${file.path}`;
|
|
20246
|
-
const contentBlobKey = (appId,
|
|
20246
|
+
const contentBlobKey = (appId, sha2566) => `${root(appId)}/blobs/${sha2566}`;
|
|
20247
20247
|
const tombstoneKey = (appId, releaseId) => `${root(appId)}/gc/${releaseId}.json`;
|
|
20248
20248
|
const healthRoot = (appId, promotionId, releaseId) => `${root(appId)}/health/${promotionId}/${releaseId}`;
|
|
20249
20249
|
const pauseKey = (appId, promotionId, releaseId) => `${healthRoot(appId, promotionId, releaseId)}/paused.json`;
|
|
@@ -20864,10 +20864,10 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
20864
20864
|
const objectBytesByDigest = new Map;
|
|
20865
20865
|
for (const blobObject of objects) {
|
|
20866
20866
|
if (blobObject.key.startsWith(blobPrefix)) {
|
|
20867
|
-
const
|
|
20868
|
-
if (HASH.test(
|
|
20869
|
-
objectKeysByDigest.set(
|
|
20870
|
-
objectBytesByDigest.set(
|
|
20867
|
+
const sha2566 = blobObject.key.slice(blobPrefix.length);
|
|
20868
|
+
if (HASH.test(sha2566)) {
|
|
20869
|
+
objectKeysByDigest.set(sha2566, blobObject.key);
|
|
20870
|
+
objectBytesByDigest.set(sha2566, blobObject.size);
|
|
20871
20871
|
}
|
|
20872
20872
|
}
|
|
20873
20873
|
if (!blobObject.key.startsWith(releasePrefix))
|
|
@@ -20950,7 +20950,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
20950
20950
|
}).toSorted((left, right) => right.createdAt.localeCompare(left.createdAt));
|
|
20951
20951
|
const protectedReleaseIds = new Set(releases.filter((release) => release.protectedBy.length > 0).map((release) => release.releaseId));
|
|
20952
20952
|
const protectedDigests = new Set(manifests.filter((manifest) => protectedReleaseIds.has(manifest.releaseId)).flatMap((manifest) => manifest.files.map((file) => file.sha256)));
|
|
20953
|
-
const reclaimableContentBytes = [...objectBytesByDigest].filter(([
|
|
20953
|
+
const reclaimableContentBytes = [...objectBytesByDigest].filter(([sha2566]) => !protectedDigests.has(sha2566)).reduce((total, [, bytes]) => total + bytes, 0);
|
|
20954
20954
|
const contentBlobBytes = [...objectBytesByDigest.values()].reduce((total, bytes) => total + bytes, 0);
|
|
20955
20955
|
const releaseBytes = releases.reduce((total, release) => total + release.bytes, 0);
|
|
20956
20956
|
const totalBytes = objects.reduce((total, object22) => total + object22.size, 0);
|
|
@@ -21047,13 +21047,13 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
21047
21047
|
for (const file of manifest?.manifest.files ?? [])
|
|
21048
21048
|
referencedDigests.add(file.sha256);
|
|
21049
21049
|
}
|
|
21050
|
-
for (const [
|
|
21051
|
-
if (referencedDigests.has(
|
|
21050
|
+
for (const [sha2566, key] of afterReleaseSweep.objectKeysByDigest) {
|
|
21051
|
+
if (referencedDigests.has(sha2566))
|
|
21052
21052
|
continue;
|
|
21053
21053
|
const head = await options.store.head(key);
|
|
21054
21054
|
await remove(key);
|
|
21055
21055
|
result.reclaimedBytes += head?.size ?? 0;
|
|
21056
|
-
result.sweptContentBlobs.push(
|
|
21056
|
+
result.sweptContentBlobs.push(sha2566);
|
|
21057
21057
|
}
|
|
21058
21058
|
return result;
|
|
21059
21059
|
};
|
|
@@ -21075,7 +21075,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
21075
21075
|
verifyManifestSignature(manifest, options.publicKeys);
|
|
21076
21076
|
await assertNotMarked(manifest.appId, manifest.releaseId);
|
|
21077
21077
|
const localRoot = path.resolve(input.releaseDirectory);
|
|
21078
|
-
const localManifest = parseMobileUpdateManifest(JSON.parse(await
|
|
21078
|
+
const localManifest = parseMobileUpdateManifest(JSON.parse(await readFile28(path.join(localRoot, "update.json"), "utf8")));
|
|
21079
21079
|
if (JSON.stringify(localManifest) !== JSON.stringify(manifest))
|
|
21080
21080
|
throw new MobileUpdateRegistryError("Local mobile update manifest changed");
|
|
21081
21081
|
const existing = await readManifest(manifest.appId, manifest.releaseId);
|
|
@@ -21208,7 +21208,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
21208
21208
|
}
|
|
21209
21209
|
};
|
|
21210
21210
|
}, expoUpdateId = (releaseId) => {
|
|
21211
|
-
const hash = RELEASE.test(releaseId) ? releaseId.slice("amu_".length, "amu_".length + 32) :
|
|
21211
|
+
const hash = RELEASE.test(releaseId) ? releaseId.slice("amu_".length, "amu_".length + 32) : createHash19("sha256").update(releaseId).digest("hex").slice(0, 32);
|
|
21212
21212
|
return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20)}`;
|
|
21213
21213
|
}, expoContentType = (extension2, launch2) => {
|
|
21214
21214
|
if (launch2)
|
|
@@ -21361,8 +21361,8 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
21361
21361
|
});
|
|
21362
21362
|
}
|
|
21363
21363
|
const pathname = new URL(request.url).pathname.replace(/^\/+/, "");
|
|
21364
|
-
const
|
|
21365
|
-
if (request.method === "POST" &&
|
|
21364
|
+
const relative21 = pathname.startsWith(`${route}/`) ? pathname.slice(route.length + 1) : "";
|
|
21365
|
+
if (request.method === "POST" && relative21 === "health") {
|
|
21366
21366
|
if (!options.registry.recordUpdateHealth)
|
|
21367
21367
|
return new Response(null, { status: 404 });
|
|
21368
21368
|
const appId = request.headers.get("x-absolute-mobile-app");
|
|
@@ -21405,7 +21405,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
21405
21405
|
}
|
|
21406
21406
|
if (request.method !== "GET")
|
|
21407
21407
|
return new Response(null, { status: 405 });
|
|
21408
|
-
if (
|
|
21408
|
+
if (relative21 === "update.json") {
|
|
21409
21409
|
const expoProtocolVersion = request.headers.get("expo-protocol-version");
|
|
21410
21410
|
const expoProtocol = expoProtocolVersion !== null;
|
|
21411
21411
|
if (expoProtocol && expoProtocolVersion !== "1")
|
|
@@ -21523,7 +21523,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
21523
21523
|
}
|
|
21524
21524
|
});
|
|
21525
21525
|
}
|
|
21526
|
-
const match = /^(amu_[a-f0-9]{64})\/files\/(.+)$/.exec(
|
|
21526
|
+
const match = /^(amu_[a-f0-9]{64})\/files\/(.+)$/.exec(relative21);
|
|
21527
21527
|
if (!match?.[1] || !match[2])
|
|
21528
21528
|
return new Response(null, { status: 404 });
|
|
21529
21529
|
const file = await options.registry.readUpdateFile({
|
|
@@ -21616,15 +21616,15 @@ import {
|
|
|
21616
21616
|
createPublicKey as createPublicKey3,
|
|
21617
21617
|
X509Certificate as X509Certificate4
|
|
21618
21618
|
} from "crypto";
|
|
21619
|
-
import { access as
|
|
21620
|
-
import { dirname as dirname22, isAbsolute as
|
|
21619
|
+
import { access as access20, mkdir as mkdir22 } from "fs/promises";
|
|
21620
|
+
import { dirname as dirname22, isAbsolute as isAbsolute12, relative as relative21, resolve as resolve23, sep as sep14 } from "path";
|
|
21621
21621
|
import { pathToFileURL as pathToFileURL5 } from "url";
|
|
21622
21622
|
import { Elysia as Elysia4 } from "elysia";
|
|
21623
21623
|
var ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT = 1, DEFAULT_MOBILE_UPDATE_REGISTRY_MODULE = "mobile.update.ts", object7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), projectPath3 = (projectRoot, requested) => {
|
|
21624
|
-
const root =
|
|
21625
|
-
const path2 =
|
|
21626
|
-
const projectRelative =
|
|
21627
|
-
if (projectRelative === ".." || projectRelative.startsWith(`..${
|
|
21624
|
+
const root = resolve23(projectRoot);
|
|
21625
|
+
const path2 = resolve23(root, requested);
|
|
21626
|
+
const projectRelative = relative21(root, path2);
|
|
21627
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep14}`) || isAbsolute12(projectRelative))
|
|
21628
21628
|
throw new TypeError("mobile.updates.server.registry must remain inside the project.");
|
|
21629
21629
|
return path2;
|
|
21630
21630
|
}, isRegistry4 = (value) => object7(value) && [
|
|
@@ -21647,7 +21647,7 @@ var ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT = 1, DEFAULT_MOBILE_UPDATE_REGISTRY_MOD
|
|
|
21647
21647
|
return metadata;
|
|
21648
21648
|
}, loadAbsoluteMobileUpdateServerModule = async (projectRoot, requestedModulePath = DEFAULT_MOBILE_UPDATE_REGISTRY_MODULE) => {
|
|
21649
21649
|
const modulePath = projectPath3(projectRoot, requestedModulePath);
|
|
21650
|
-
await
|
|
21650
|
+
await access20(modulePath).catch(() => {
|
|
21651
21651
|
throw new TypeError(`Mobile update server registry does not exist: ${modulePath}. Run \`absolute mobile update provision\`.`);
|
|
21652
21652
|
});
|
|
21653
21653
|
const loaded = await import(pathToFileURL5(modulePath).href);
|
|
@@ -21836,13 +21836,13 @@ ${generated}`);
|
|
|
21836
21836
|
}, writeAbsoluteMobileUpdateRegistry = async (options) => {
|
|
21837
21837
|
const path2 = projectPath3(options.projectRoot, options.modulePath ?? DEFAULT_MOBILE_UPDATE_REGISTRY_MODULE);
|
|
21838
21838
|
if (!options.force) {
|
|
21839
|
-
await
|
|
21839
|
+
await access20(path2).then(() => {
|
|
21840
21840
|
throw new TypeError(`Mobile update registry already exists: ${path2}. Pass --force to replace it.`);
|
|
21841
21841
|
}, () => {
|
|
21842
21842
|
return;
|
|
21843
21843
|
});
|
|
21844
21844
|
}
|
|
21845
|
-
await
|
|
21845
|
+
await mkdir22(dirname22(path2), { recursive: true });
|
|
21846
21846
|
await Bun.write(path2, renderAbsoluteMobileUpdateRegistry({
|
|
21847
21847
|
...options.health ? { health: options.health } : {},
|
|
21848
21848
|
...options.rollout ? { rollout: options.rollout } : {},
|
|
@@ -25838,6 +25838,7 @@ var defaultRun3 = async (command, options = {}) => {
|
|
|
25838
25838
|
const process2 = Bun.spawn(command, {
|
|
25839
25839
|
cwd: options.cwd,
|
|
25840
25840
|
env: options.env,
|
|
25841
|
+
signal: options.signal,
|
|
25841
25842
|
stderr: "pipe",
|
|
25842
25843
|
stdin: "ignore",
|
|
25843
25844
|
stdout: "pipe"
|
|
@@ -25925,6 +25926,7 @@ var releaseMarker = (release) => {
|
|
|
25925
25926
|
var waitForSimulatorMarker = async (options) => {
|
|
25926
25927
|
const startedAt = performance.now();
|
|
25927
25928
|
const poll = async () => {
|
|
25929
|
+
options.signal?.throwIfAborted();
|
|
25928
25930
|
if (performance.now() - startedAt >= READY_TIMEOUT_MS)
|
|
25929
25931
|
throw new Error("The installed iOS Release app launched but its embedded content did not become ready.");
|
|
25930
25932
|
const logs = await options.run([
|
|
@@ -25963,7 +25965,12 @@ var launchSimulator = async (options) => {
|
|
|
25963
25965
|
return Math.round(performance.now() - startedAt);
|
|
25964
25966
|
};
|
|
25965
25967
|
var runAbsoluteIosSimulatorReleaseAcceptance = async (options) => {
|
|
25966
|
-
const
|
|
25968
|
+
const baseRun = options.run ?? defaultRun3;
|
|
25969
|
+
const run = (command, commandOptions = {}) => baseRun(command, {
|
|
25970
|
+
...commandOptions,
|
|
25971
|
+
...options.signal ? { signal: options.signal } : {}
|
|
25972
|
+
});
|
|
25973
|
+
options.signal?.throwIfAborted();
|
|
25967
25974
|
const xcodebuild = options.xcodebuild ?? "/usr/bin/xcodebuild";
|
|
25968
25975
|
const xcrun = options.xcrun ?? "/usr/bin/xcrun";
|
|
25969
25976
|
const startedAt = performance.now();
|
|
@@ -26061,7 +26068,12 @@ var observeDeviceLaunch = async (options) => {
|
|
|
26061
26068
|
"--device",
|
|
26062
26069
|
options.device,
|
|
26063
26070
|
options.appId
|
|
26064
|
-
], {
|
|
26071
|
+
], {
|
|
26072
|
+
signal: options.signal,
|
|
26073
|
+
stderr: "pipe",
|
|
26074
|
+
stdin: "ignore",
|
|
26075
|
+
stdout: "pipe"
|
|
26076
|
+
});
|
|
26065
26077
|
const stdoutReader = process2.stdout.getReader();
|
|
26066
26078
|
const stderrReader = process2.stderr.getReader();
|
|
26067
26079
|
const requireMarker = async (reader) => {
|
|
@@ -26148,7 +26160,12 @@ var inspectTestFlightInstallation = async (options) => {
|
|
|
26148
26160
|
var runAbsoluteIosDeviceReleaseAcceptance = async (options) => {
|
|
26149
26161
|
if (!options.networkUnavailableConfirmed)
|
|
26150
26162
|
throw new TypeError("Physical iOS offline acceptance requires explicit confirmation that Airplane Mode is enabled and Wi-Fi is disabled in Settings.");
|
|
26151
|
-
const
|
|
26163
|
+
const baseRun = options.run ?? defaultRun3;
|
|
26164
|
+
const run = (command, commandOptions = {}) => baseRun(command, {
|
|
26165
|
+
...commandOptions,
|
|
26166
|
+
...options.signal ? { signal: options.signal } : {}
|
|
26167
|
+
});
|
|
26168
|
+
options.signal?.throwIfAborted();
|
|
26152
26169
|
const xcrun = options.xcrun ?? "/usr/bin/xcrun";
|
|
26153
26170
|
const startedAt = performance.now();
|
|
26154
26171
|
await requireSuccess3(run, [
|
|
@@ -26167,7 +26184,11 @@ var runAbsoluteIosDeviceReleaseAcceptance = async (options) => {
|
|
|
26167
26184
|
xcrun
|
|
26168
26185
|
};
|
|
26169
26186
|
const installMs = options.distribution === "registered-device" ? await installRegisteredDeviceRelease(installation) : await inspectTestFlightInstallation(installation);
|
|
26170
|
-
const observe = options.observeLaunch ?? ((launch2) => observeDeviceLaunch({
|
|
26187
|
+
const observe = options.observeLaunch ?? ((launch2) => observeDeviceLaunch({
|
|
26188
|
+
...launch2,
|
|
26189
|
+
...options.signal ? { signal: options.signal } : {},
|
|
26190
|
+
xcrun
|
|
26191
|
+
}));
|
|
26171
26192
|
const marker = releaseMarker(options.release);
|
|
26172
26193
|
const launchMs = await observe({
|
|
26173
26194
|
appId: options.release.metadata.appId,
|
|
@@ -27324,7 +27345,7 @@ import {
|
|
|
27324
27345
|
|
|
27325
27346
|
// src/mobile/remoteMacWire.ts
|
|
27326
27347
|
var ABSOLUTE_REMOTE_MAC_EVENT_PREFIX = "ABSOLUTE_REMOTE_MAC\t";
|
|
27327
|
-
var ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION =
|
|
27348
|
+
var ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION = 4;
|
|
27328
27349
|
|
|
27329
27350
|
// src/mobile/remoteMacProtocol.ts
|
|
27330
27351
|
var PROFILE_FORMAT = 1;
|
|
@@ -27868,6 +27889,45 @@ var absoluteRemoteReleaseInputSyncCommands = (project) => {
|
|
|
27868
27889
|
tar: ["tar", "-cf", "-", "-C", project.config.bundleDirectory, "."]
|
|
27869
27890
|
};
|
|
27870
27891
|
};
|
|
27892
|
+
var syncAbsoluteRemoteMacAcceptanceRelease = async (project, release, options = {}) => {
|
|
27893
|
+
options.signal?.throwIfAborted();
|
|
27894
|
+
const destination = posix.join(project.remoteProjectRoot, ".absolutejs", "mobile", "acceptance", "ios", release.metadata.releaseId);
|
|
27895
|
+
const staging = `${destination}.incoming-${randomUUID4()}`;
|
|
27896
|
+
const script = [
|
|
27897
|
+
"set -eu",
|
|
27898
|
+
"umask 077",
|
|
27899
|
+
`rm -rf ${shellQuote(staging)}`,
|
|
27900
|
+
`mkdir -p ${shellQuote(staging)}`,
|
|
27901
|
+
`tar -xf - -C ${shellQuote(staging)}`,
|
|
27902
|
+
`test -f ${shellQuote(posix.join(staging, "release.json"))}`,
|
|
27903
|
+
`rm -rf ${shellQuote(destination)}`,
|
|
27904
|
+
`mkdir -p ${shellQuote(posix.dirname(destination))}`,
|
|
27905
|
+
`mv ${shellQuote(staging)} ${shellQuote(destination)}`
|
|
27906
|
+
].join("; ");
|
|
27907
|
+
const archive = Bun.spawn(["tar", "-cf", "-", "-C", release.releaseRoot, "."], {
|
|
27908
|
+
signal: options.signal,
|
|
27909
|
+
stderr: "pipe",
|
|
27910
|
+
stdout: "pipe"
|
|
27911
|
+
});
|
|
27912
|
+
const upload = Bun.spawn([
|
|
27913
|
+
...absoluteRemoteMacSshBase(project.profile),
|
|
27914
|
+
"/bin/sh -lc",
|
|
27915
|
+
shellQuote(script)
|
|
27916
|
+
], {
|
|
27917
|
+
signal: options.signal,
|
|
27918
|
+
stderr: "pipe",
|
|
27919
|
+
stdin: archive.stdout,
|
|
27920
|
+
stdout: "pipe"
|
|
27921
|
+
});
|
|
27922
|
+
const [archiveExit, uploadExit, archiveError, uploadError] = await Promise.all([
|
|
27923
|
+
archive.exited,
|
|
27924
|
+
upload.exited,
|
|
27925
|
+
new Response(archive.stderr).text(),
|
|
27926
|
+
new Response(upload.stderr).text()
|
|
27927
|
+
]);
|
|
27928
|
+
if (archiveExit !== 0 || uploadExit !== 0)
|
|
27929
|
+
throw new Error(`Remote iOS acceptance artifact synchronization failed: ${(archiveError || uploadError).trim()}`);
|
|
27930
|
+
};
|
|
27871
27931
|
var syncAbsoluteRemoteMacReleaseInputs = async (project, options = {}) => {
|
|
27872
27932
|
options.signal?.throwIfAborted();
|
|
27873
27933
|
const commands = absoluteRemoteReleaseInputSyncCommands(project);
|
|
@@ -27938,11 +27998,28 @@ var retrieveAbsoluteRemoteIosRelease = async (project, metadata, outputDirectory
|
|
|
27938
27998
|
]);
|
|
27939
27999
|
if (downloadExit !== 0)
|
|
27940
28000
|
throw new Error(`Remote iOS release retrieval failed: ${downloadError.trim()}`);
|
|
28001
|
+
let registeredArtifactPath;
|
|
28002
|
+
if (metadata.registeredDevice) {
|
|
28003
|
+
registeredArtifactPath = join10(staging, "App.registered-device.ipa");
|
|
28004
|
+
const registeredDownload = Bun.spawn([
|
|
28005
|
+
...absoluteRemoteMacSshBase(project.profile),
|
|
28006
|
+
"/bin/sh -lc",
|
|
28007
|
+
shellQuote(`cat ${shellQuote(posix.join(releaseRoot, metadata.registeredDevice.artifact))}`)
|
|
28008
|
+
], { stderr: "pipe", stdout: "pipe" });
|
|
28009
|
+
const [registeredExit, registeredError] = await Promise.all([
|
|
28010
|
+
registeredDownload.exited,
|
|
28011
|
+
new Response(registeredDownload.stderr).text(),
|
|
28012
|
+
writeRemoteArtifact(registeredArtifactPath, registeredDownload.stdout)
|
|
28013
|
+
]);
|
|
28014
|
+
if (registeredExit !== 0)
|
|
28015
|
+
throw new Error(`Remote iOS registered-device artifact retrieval failed: ${registeredError.trim()}`);
|
|
28016
|
+
}
|
|
27941
28017
|
return await installAbsoluteIosRelease({
|
|
27942
28018
|
artifactPath,
|
|
27943
28019
|
metadata,
|
|
27944
28020
|
outputDirectory,
|
|
27945
|
-
projectRoot: project.projectRoot
|
|
28021
|
+
projectRoot: project.projectRoot,
|
|
28022
|
+
...registeredArtifactPath ? { registeredArtifactPath } : {}
|
|
27946
28023
|
});
|
|
27947
28024
|
} finally {
|
|
27948
28025
|
await rm8(staging, { force: true, recursive: true }).catch(() => {
|
|
@@ -28040,6 +28117,7 @@ var buildAbsoluteRemoteIosRelease = async (options) => {
|
|
|
28040
28117
|
shellQuote(encodedConfig),
|
|
28041
28118
|
...options.allowUnsigned ? ["--unsigned"] : [],
|
|
28042
28119
|
...options.prepareBuildNumber ? ["--request-build-number"] : [],
|
|
28120
|
+
...options.registeredDeviceArtifact ? ["--registered-device-artifact"] : [],
|
|
28043
28121
|
...options.developmentTeam ? ["--development-team", shellQuote(options.developmentTeam)] : []
|
|
28044
28122
|
].join(" ");
|
|
28045
28123
|
const process2 = (options.transport?.spawn ?? defaultTransport.spawn)([
|
|
@@ -28144,6 +28222,178 @@ var buildAbsoluteRemoteIosRelease = async (options) => {
|
|
|
28144
28222
|
}
|
|
28145
28223
|
}
|
|
28146
28224
|
};
|
|
28225
|
+
var requireRemoteIosReleaseAcceptance = (value, release, distribution) => {
|
|
28226
|
+
if (typeof value !== "object" || value === null)
|
|
28227
|
+
throw new TypeError("Remote Mac returned invalid iOS release evidence.");
|
|
28228
|
+
const result = value;
|
|
28229
|
+
let expectedExactness = "archive-equivalent";
|
|
28230
|
+
if (distribution === "simulator-release")
|
|
28231
|
+
expectedExactness = "source-equivalent";
|
|
28232
|
+
if (distribution === "testflight")
|
|
28233
|
+
expectedExactness = "store-delivered";
|
|
28234
|
+
const expectedDistribution = distribution === "testflight" ? "apple-processed" : distribution;
|
|
28235
|
+
const expectedTarget = distribution === "simulator-release" ? "simulator" : "device";
|
|
28236
|
+
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((field2) => typeof result[field2] === "number" && Number.isFinite(result[field2]) && result[field2] >= 0))
|
|
28237
|
+
throw new TypeError("Remote Mac iOS release evidence does not match the immutable release or requested lane.");
|
|
28238
|
+
return value;
|
|
28239
|
+
};
|
|
28240
|
+
var runAbsoluteRemoteIosReleaseAcceptance = async (options) => {
|
|
28241
|
+
options.signal?.throwIfAborted();
|
|
28242
|
+
if (options.distribution !== "simulator-release" && !options.deviceIdentifier)
|
|
28243
|
+
throw new TypeError("Remote physical iOS release acceptance requires a device identifier.");
|
|
28244
|
+
if (options.distribution !== "simulator-release" && !options.networkUnavailableConfirmed)
|
|
28245
|
+
throw new TypeError("Remote physical iOS release acceptance requires explicit network-unavailable confirmation.");
|
|
28246
|
+
const operation = new AbortController;
|
|
28247
|
+
const abort = () => operation.abort(options.signal?.reason ?? new Error("Remote iOS release acceptance cancelled."));
|
|
28248
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
28249
|
+
const startedAt = performance.now();
|
|
28250
|
+
const leaseStartedAt = performance.now();
|
|
28251
|
+
let lease;
|
|
28252
|
+
try {
|
|
28253
|
+
lease = await (options.acquireLease ?? ((project, signal) => acquireAbsoluteRemoteMacReleaseLease(project, {
|
|
28254
|
+
signal,
|
|
28255
|
+
transport: options.transport
|
|
28256
|
+
})))(options.project, operation.signal);
|
|
28257
|
+
} catch (error) {
|
|
28258
|
+
options.signal?.removeEventListener("abort", abort);
|
|
28259
|
+
throw error;
|
|
28260
|
+
}
|
|
28261
|
+
const leaseDuration = performance.now() - leaseStartedAt;
|
|
28262
|
+
options.onPhaseTiming?.({
|
|
28263
|
+
durationMs: leaseDuration,
|
|
28264
|
+
phase: "remote-release-acceptance-lease"
|
|
28265
|
+
});
|
|
28266
|
+
let heartbeat;
|
|
28267
|
+
const heartbeatTimer = setInterval(() => {
|
|
28268
|
+
if (heartbeat)
|
|
28269
|
+
return;
|
|
28270
|
+
heartbeat = lease.heartbeat().catch((error) => operation.abort(error)).finally(() => {
|
|
28271
|
+
heartbeat = undefined;
|
|
28272
|
+
});
|
|
28273
|
+
}, REMOTE_RELEASE_LEASE_HEARTBEAT_MS);
|
|
28274
|
+
unrefTimer(heartbeatTimer);
|
|
28275
|
+
try {
|
|
28276
|
+
const syncStartedAt = performance.now();
|
|
28277
|
+
if (options.syncProject)
|
|
28278
|
+
await options.syncProject(options.project);
|
|
28279
|
+
else
|
|
28280
|
+
await syncAbsoluteRemoteMacProject(options.project, {
|
|
28281
|
+
signal: operation.signal
|
|
28282
|
+
});
|
|
28283
|
+
operation.signal.throwIfAborted();
|
|
28284
|
+
if (options.syncReleaseInputs)
|
|
28285
|
+
await options.syncReleaseInputs(options.project);
|
|
28286
|
+
else
|
|
28287
|
+
await syncAbsoluteRemoteMacReleaseInputs(options.project, {
|
|
28288
|
+
signal: operation.signal
|
|
28289
|
+
});
|
|
28290
|
+
operation.signal.throwIfAborted();
|
|
28291
|
+
if (options.syncRelease)
|
|
28292
|
+
await options.syncRelease(options.project, options.release);
|
|
28293
|
+
else
|
|
28294
|
+
await syncAbsoluteRemoteMacAcceptanceRelease(options.project, options.release, { signal: operation.signal });
|
|
28295
|
+
operation.signal.throwIfAborted();
|
|
28296
|
+
const syncDuration = performance.now() - syncStartedAt;
|
|
28297
|
+
options.onPhaseTiming?.({
|
|
28298
|
+
durationMs: syncDuration,
|
|
28299
|
+
phase: "remote-release-acceptance-sync"
|
|
28300
|
+
});
|
|
28301
|
+
const agent = await (options.installAgent ?? installAbsoluteRemoteMacAgent)(options.project);
|
|
28302
|
+
const encodedConfig = Buffer.from(JSON.stringify(portableMobileConfig(options.project))).toString("base64url");
|
|
28303
|
+
const remoteCommand = [
|
|
28304
|
+
`cd ${shellQuote(options.project.remoteProjectRoot)}`,
|
|
28305
|
+
"&&",
|
|
28306
|
+
"exec",
|
|
28307
|
+
shellQuote(options.project.profile.bunPath),
|
|
28308
|
+
shellQuote(agent.remotePath),
|
|
28309
|
+
"--test-ios-release",
|
|
28310
|
+
"--mobile-config",
|
|
28311
|
+
shellQuote(encodedConfig),
|
|
28312
|
+
"--release-id",
|
|
28313
|
+
shellQuote(options.release.metadata.releaseId),
|
|
28314
|
+
"--distribution",
|
|
28315
|
+
shellQuote(options.distribution),
|
|
28316
|
+
...options.deviceIdentifier ? ["--device", shellQuote(options.deviceIdentifier)] : [],
|
|
28317
|
+
...options.simulatorUdid ? ["--simulator-udid", shellQuote(options.simulatorUdid)] : [],
|
|
28318
|
+
...options.networkUnavailableConfirmed ? ["--network-unavailable-confirmed"] : []
|
|
28319
|
+
].join(" ");
|
|
28320
|
+
const process2 = (options.transport?.spawn ?? defaultTransport.spawn)([
|
|
28321
|
+
...absoluteRemoteMacSshBase(options.project.profile),
|
|
28322
|
+
"/bin/sh -lc",
|
|
28323
|
+
shellQuote(remoteCommand)
|
|
28324
|
+
], { signal: operation.signal });
|
|
28325
|
+
const killOnAbort = () => process2.kill();
|
|
28326
|
+
operation.signal.addEventListener("abort", killOnAbort, { once: true });
|
|
28327
|
+
let failure;
|
|
28328
|
+
let accepted;
|
|
28329
|
+
const stdoutDone = consumeLines2(process2.stdout, (line) => {
|
|
28330
|
+
if (!line.startsWith(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX))
|
|
28331
|
+
return;
|
|
28332
|
+
try {
|
|
28333
|
+
const event = JSON.parse(line.slice(ABSOLUTE_REMOTE_MAC_EVENT_PREFIX.length));
|
|
28334
|
+
if (event.v !== ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION)
|
|
28335
|
+
throw new Error("Remote Mac protocol version mismatch.");
|
|
28336
|
+
if (event.type === "log")
|
|
28337
|
+
options.log?.(event.message);
|
|
28338
|
+
if (event.type === "timing") {
|
|
28339
|
+
const durationMs = Reflect.get(event, "durationMs");
|
|
28340
|
+
const phase = Reflect.get(event, "phase");
|
|
28341
|
+
if (typeof durationMs === "number" && typeof phase === "string")
|
|
28342
|
+
options.onPhaseTiming?.({ durationMs, phase });
|
|
28343
|
+
}
|
|
28344
|
+
if (event.type === "fatal")
|
|
28345
|
+
failure = new Error(event.error);
|
|
28346
|
+
if (event.type === "release-acceptance") {
|
|
28347
|
+
if (!event.targetId || typeof event.targetId !== "string")
|
|
28348
|
+
throw new TypeError("Remote Mac returned an invalid iOS acceptance target.");
|
|
28349
|
+
accepted = {
|
|
28350
|
+
result: requireRemoteIosReleaseAcceptance(event.result, options.release, options.distribution),
|
|
28351
|
+
targetId: event.targetId
|
|
28352
|
+
};
|
|
28353
|
+
}
|
|
28354
|
+
} catch (error) {
|
|
28355
|
+
failure = error instanceof Error ? error : new Error("Remote Mac emitted invalid iOS release evidence.");
|
|
28356
|
+
process2.kill();
|
|
28357
|
+
}
|
|
28358
|
+
});
|
|
28359
|
+
const stderrDone = consumeLines2(process2.stderr, (line) => options.log?.(`[remote] ${line}`));
|
|
28360
|
+
const exitCode = await process2.exited;
|
|
28361
|
+
operation.signal.removeEventListener("abort", killOnAbort);
|
|
28362
|
+
try {
|
|
28363
|
+
process2.stdin.end();
|
|
28364
|
+
} catch {}
|
|
28365
|
+
await Promise.all([stdoutDone, stderrDone]);
|
|
28366
|
+
operation.signal.throwIfAborted();
|
|
28367
|
+
if (failure)
|
|
28368
|
+
throw failure;
|
|
28369
|
+
if (exitCode !== 0)
|
|
28370
|
+
throw new Error(`Remote iOS release acceptance agent exited with status ${exitCode}.`);
|
|
28371
|
+
if (!accepted)
|
|
28372
|
+
throw new Error("Remote iOS release acceptance agent returned no evidence.");
|
|
28373
|
+
const total = performance.now() - startedAt;
|
|
28374
|
+
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"}).`);
|
|
28375
|
+
return {
|
|
28376
|
+
...accepted,
|
|
28377
|
+
timings: {
|
|
28378
|
+
"remote-release-acceptance-lease": leaseDuration,
|
|
28379
|
+
"remote-release-acceptance-sync": syncDuration,
|
|
28380
|
+
total
|
|
28381
|
+
}
|
|
28382
|
+
};
|
|
28383
|
+
} finally {
|
|
28384
|
+
clearInterval(heartbeatTimer);
|
|
28385
|
+
await heartbeat?.catch(() => {
|
|
28386
|
+
return;
|
|
28387
|
+
});
|
|
28388
|
+
options.signal?.removeEventListener("abort", abort);
|
|
28389
|
+
try {
|
|
28390
|
+
await lease.release();
|
|
28391
|
+
options.log?.("Released Remote Mac release acceptance lease.");
|
|
28392
|
+
} catch (error) {
|
|
28393
|
+
options.log?.(`Remote Mac acceptance lease cleanup failed and will recover after expiry: ${error instanceof Error ? error.message : String(error)}`);
|
|
28394
|
+
}
|
|
28395
|
+
}
|
|
28396
|
+
};
|
|
28147
28397
|
var startAbsoluteRemoteExpoIosDevSession = async (options) => {
|
|
28148
28398
|
let session = await startAbsoluteRemoteDevSession({
|
|
28149
28399
|
certificateAuthorityPath: options.certificateAuthorityPath,
|
|
@@ -34997,9 +35247,412 @@ init_pageProtocol();
|
|
|
34997
35247
|
init_producerContext();
|
|
34998
35248
|
init_releaseArtifact();
|
|
34999
35249
|
|
|
35250
|
+
// src/mobile/releaseCertification.ts
|
|
35251
|
+
import { createHash as createHash16 } from "crypto";
|
|
35252
|
+
import {
|
|
35253
|
+
access as access17,
|
|
35254
|
+
mkdir as mkdir20,
|
|
35255
|
+
mkdtemp as mkdtemp10,
|
|
35256
|
+
readFile as readFile26,
|
|
35257
|
+
rename as rename18,
|
|
35258
|
+
rm as rm15,
|
|
35259
|
+
writeFile as writeFile22
|
|
35260
|
+
} from "fs/promises";
|
|
35261
|
+
import { basename as basename8, isAbsolute as isAbsolute9, join as join30, relative as relative16, resolve as resolve18, sep as sep11 } from "path";
|
|
35262
|
+
var ABSOLUTE_MOBILE_RELEASE_CERTIFICATION_FORMAT = 1;
|
|
35263
|
+
var CERTIFICATION_PREFIX = "amobile_cert_";
|
|
35264
|
+
var SHA256 = /^[a-f0-9]{64}$/u;
|
|
35265
|
+
var STRENGTH_RANK = {
|
|
35266
|
+
device: 1,
|
|
35267
|
+
installed: 0,
|
|
35268
|
+
simulator: 0,
|
|
35269
|
+
store: 2
|
|
35270
|
+
};
|
|
35271
|
+
var isRequirement = (value) => value === "installed" || value === "simulator" || value === "device" || value === "store";
|
|
35272
|
+
var isStrength = (value) => value === "installed" || value === "simulator" || value === "device" || value === "store";
|
|
35273
|
+
var isArtifactExactness = (value) => value === "archive-equivalent" || value === "source-equivalent" || value === "store-delivered";
|
|
35274
|
+
var isDistribution = (value) => value === "apple-processed" || value === "registered-device" || value === "simulator-release";
|
|
35275
|
+
var isRecord14 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
35276
|
+
var inside4 = (root, candidate) => {
|
|
35277
|
+
const path = relative16(resolve18(root), resolve18(candidate));
|
|
35278
|
+
return path === "" || !isAbsolute9(path) && path !== ".." && !path.startsWith(`..${sep11}`);
|
|
35279
|
+
};
|
|
35280
|
+
var exists9 = async (path) => {
|
|
35281
|
+
try {
|
|
35282
|
+
await access17(path);
|
|
35283
|
+
return true;
|
|
35284
|
+
} catch {
|
|
35285
|
+
return false;
|
|
35286
|
+
}
|
|
35287
|
+
};
|
|
35288
|
+
var sha2564 = (bytes) => createHash16("sha256").update(bytes).digest("hex");
|
|
35289
|
+
var requireString2 = (value, name) => {
|
|
35290
|
+
if (typeof value !== "string" || !value)
|
|
35291
|
+
throw new TypeError(`Mobile certification ${name} is invalid.`);
|
|
35292
|
+
return value;
|
|
35293
|
+
};
|
|
35294
|
+
var requirePositiveInteger = (value, name) => {
|
|
35295
|
+
if (!Number.isSafeInteger(value) || Number(value) < 1)
|
|
35296
|
+
throw new TypeError(`Mobile certification ${name} is invalid.`);
|
|
35297
|
+
return Number(value);
|
|
35298
|
+
};
|
|
35299
|
+
var resolveEvidencePath = async (projectRoot, requested) => {
|
|
35300
|
+
const selected = resolve18(projectRoot, requested);
|
|
35301
|
+
if (!inside4(projectRoot, selected))
|
|
35302
|
+
throw new TypeError("Mobile certification evidence must remain inside the project.");
|
|
35303
|
+
if (basename8(selected) === "report.json")
|
|
35304
|
+
return selected;
|
|
35305
|
+
const report = join30(selected, "report.json");
|
|
35306
|
+
if (!await exists9(report))
|
|
35307
|
+
throw new TypeError(`Mobile certification evidence does not contain report.json: ${requested}`);
|
|
35308
|
+
return report;
|
|
35309
|
+
};
|
|
35310
|
+
var releaseIdentity = (release) => {
|
|
35311
|
+
const { metadata } = release;
|
|
35312
|
+
if (!metadata.signed)
|
|
35313
|
+
throw new TypeError("Mobile release certification requires a signed native release.");
|
|
35314
|
+
const common = {
|
|
35315
|
+
appBuild: metadata.appBuild,
|
|
35316
|
+
appId: metadata.appId,
|
|
35317
|
+
artifactBytes: metadata.bytes,
|
|
35318
|
+
artifactSha256: metadata.sha256,
|
|
35319
|
+
engine: metadata.engine,
|
|
35320
|
+
platform: metadata.platform,
|
|
35321
|
+
releaseId: metadata.releaseId,
|
|
35322
|
+
runtime: metadata.runtime,
|
|
35323
|
+
signed: true
|
|
35324
|
+
};
|
|
35325
|
+
if (metadata.platform === "android")
|
|
35326
|
+
return {
|
|
35327
|
+
...common,
|
|
35328
|
+
...metadata.versionCode === undefined ? {} : { versionCode: metadata.versionCode }
|
|
35329
|
+
};
|
|
35330
|
+
return {
|
|
35331
|
+
...common,
|
|
35332
|
+
...metadata.buildNumber === undefined ? {} : { buildNumber: metadata.buildNumber },
|
|
35333
|
+
marketingVersion: metadata.marketingVersion
|
|
35334
|
+
};
|
|
35335
|
+
};
|
|
35336
|
+
var requireCheck = (report, id, accepted = ["PASS"]) => {
|
|
35337
|
+
const checks = report.automatedChecks;
|
|
35338
|
+
if (!Array.isArray(checks))
|
|
35339
|
+
throw new TypeError("Mobile certification evidence has invalid automated checks.");
|
|
35340
|
+
const check = checks.find((candidate) => isRecord14(candidate) && candidate.id === id);
|
|
35341
|
+
if (!isRecord14(check) || !accepted.includes(String(check.result)))
|
|
35342
|
+
throw new TypeError(`Mobile certification evidence does not satisfy ${id}.`);
|
|
35343
|
+
};
|
|
35344
|
+
var validateCommonReport = (report, release) => {
|
|
35345
|
+
if (report.reportVersion !== 1 || report.platform !== release.platform || !isRecord14(report.metadata) || report.metadata.provider !== release.engine || !isRecord14(report.run) || report.run.status !== "pass" || report.run.appId !== release.appId)
|
|
35346
|
+
throw new TypeError("Mobile certification evidence does not match the release platform, provider, application, or successful-run contract.");
|
|
35347
|
+
requireCheck(report, "AUTO-DEV-01");
|
|
35348
|
+
return {
|
|
35349
|
+
generatedAt: requireString2(report.generatedAt, "evidence generatedAt"),
|
|
35350
|
+
run: report.run
|
|
35351
|
+
};
|
|
35352
|
+
};
|
|
35353
|
+
var validateReleaseFields = (value, release) => {
|
|
35354
|
+
if (value.releaseId !== release.releaseId || value.artifactSha256 !== release.artifactSha256 || value.artifactBytes !== release.artifactBytes || value.engine !== release.engine || value.signed !== true)
|
|
35355
|
+
throw new TypeError("Mobile certification evidence does not match the immutable release identity.");
|
|
35356
|
+
};
|
|
35357
|
+
var validateAndroidEvidence = (report, run, release, reportSha256, generatedAt) => {
|
|
35358
|
+
if (!isRecord14(run.release))
|
|
35359
|
+
throw new TypeError("Android certification evidence has no installed release result.");
|
|
35360
|
+
validateReleaseFields(run.release, release);
|
|
35361
|
+
if (run.release.embeddedOffline !== true)
|
|
35362
|
+
throw new TypeError("Android certification evidence did not prove embedded offline relaunch.");
|
|
35363
|
+
requireCheck(report, "AUTO-RELEASE-01");
|
|
35364
|
+
requireCheck(report, "AUTO-RELEASE-OFFLINE-01");
|
|
35365
|
+
return {
|
|
35366
|
+
generatedAt,
|
|
35367
|
+
networkUnavailable: "proven",
|
|
35368
|
+
remote: false,
|
|
35369
|
+
reportSha256,
|
|
35370
|
+
strength: "installed"
|
|
35371
|
+
};
|
|
35372
|
+
};
|
|
35373
|
+
var validateIosEvidence = (report, run, release, reportSha256, generatedAt) => {
|
|
35374
|
+
if (!isRecord14(run.iosRelease))
|
|
35375
|
+
throw new TypeError("iOS certification evidence has no installed release result.");
|
|
35376
|
+
const ios = run.iosRelease;
|
|
35377
|
+
validateReleaseFields(ios, release);
|
|
35378
|
+
if (ios.embeddedLocal !== true)
|
|
35379
|
+
throw new TypeError("iOS certification evidence did not prove embedded local rendering.");
|
|
35380
|
+
requireCheck(report, "AUTO-IOS-RELEASE-01");
|
|
35381
|
+
let strength;
|
|
35382
|
+
if (ios.distribution === "simulator-release" && ios.artifactExactness === "source-equivalent" && run.targetKind === "simulator" && ios.networkUnavailable === "not-proven")
|
|
35383
|
+
strength = "simulator";
|
|
35384
|
+
else if (ios.distribution === "registered-device" && ios.artifactExactness === "archive-equivalent" && run.targetKind === "device" && ios.networkUnavailable === "user-confirmed")
|
|
35385
|
+
strength = "device";
|
|
35386
|
+
else if (ios.distribution === "apple-processed" && ios.artifactExactness === "store-delivered" && run.targetKind === "device" && ios.networkUnavailable === "user-confirmed")
|
|
35387
|
+
strength = "store";
|
|
35388
|
+
else
|
|
35389
|
+
throw new TypeError("iOS certification evidence contains an invalid target, distribution, exactness, or offline-strength combination.");
|
|
35390
|
+
if (strength === "simulator")
|
|
35391
|
+
requireCheck(report, "AUTO-IOS-RELEASE-OFFLINE-01", ["SKIPPED"]);
|
|
35392
|
+
else
|
|
35393
|
+
requireCheck(report, "AUTO-IOS-RELEASE-OFFLINE-01");
|
|
35394
|
+
return {
|
|
35395
|
+
artifactExactness: ios.artifactExactness,
|
|
35396
|
+
distribution: ios.distribution,
|
|
35397
|
+
generatedAt,
|
|
35398
|
+
networkUnavailable: ios.networkUnavailable === "user-confirmed" ? "proven" : "not-proven",
|
|
35399
|
+
remote: ios.remote === true,
|
|
35400
|
+
reportSha256,
|
|
35401
|
+
strength
|
|
35402
|
+
};
|
|
35403
|
+
};
|
|
35404
|
+
var validateEvidence = async (projectRoot, requested, release) => {
|
|
35405
|
+
const path = await resolveEvidencePath(projectRoot, requested);
|
|
35406
|
+
const bytes = await readFile26(path);
|
|
35407
|
+
let value;
|
|
35408
|
+
try {
|
|
35409
|
+
value = JSON.parse(bytes.toString("utf8"));
|
|
35410
|
+
} catch {
|
|
35411
|
+
throw new TypeError("Mobile certification evidence report is not valid JSON.");
|
|
35412
|
+
}
|
|
35413
|
+
if (!isRecord14(value))
|
|
35414
|
+
throw new TypeError("Mobile certification evidence report must contain an object.");
|
|
35415
|
+
const { generatedAt, run } = validateCommonReport(value, release);
|
|
35416
|
+
const digest = sha2564(bytes);
|
|
35417
|
+
return release.platform === "android" ? validateAndroidEvidence(value, run, release, digest, generatedAt) : validateIosEvidence(value, run, release, digest, generatedAt);
|
|
35418
|
+
};
|
|
35419
|
+
var defaultRequirement = (platform4) => platform4 === "android" ? "installed" : "simulator";
|
|
35420
|
+
var validateRequirement = (platform4, requirement) => {
|
|
35421
|
+
if (platform4 === "android" && requirement !== "installed")
|
|
35422
|
+
throw new TypeError("Android certification currently uses its fixed installed/offline requirement; --require simulator, device, and store are iOS policies.");
|
|
35423
|
+
if (platform4 === "ios" && requirement === "installed")
|
|
35424
|
+
throw new TypeError("iOS certification requires simulator, device, or store evidence.");
|
|
35425
|
+
};
|
|
35426
|
+
var satisfiesRequirement = (strength, requirement) => {
|
|
35427
|
+
if (requirement === "installed")
|
|
35428
|
+
return strength === "installed";
|
|
35429
|
+
if (strength === "installed")
|
|
35430
|
+
return false;
|
|
35431
|
+
return STRENGTH_RANK[strength] >= STRENGTH_RANK[requirement];
|
|
35432
|
+
};
|
|
35433
|
+
var validateCertifiedEvidence = (platform4, evidence) => {
|
|
35434
|
+
if (platform4 === "android") {
|
|
35435
|
+
if (evidence.strength !== "installed" || evidence.networkUnavailable !== "proven" || evidence.artifactExactness !== undefined || evidence.distribution !== undefined || evidence.remote)
|
|
35436
|
+
throw new TypeError("Android release certification contains invalid evidence strength.");
|
|
35437
|
+
return;
|
|
35438
|
+
}
|
|
35439
|
+
const simulator = evidence.strength === "simulator" && evidence.artifactExactness === "source-equivalent" && evidence.distribution === "simulator-release" && evidence.networkUnavailable === "not-proven";
|
|
35440
|
+
const device = evidence.strength === "device" && evidence.artifactExactness === "archive-equivalent" && evidence.distribution === "registered-device" && evidence.networkUnavailable === "proven";
|
|
35441
|
+
const store = evidence.strength === "store" && evidence.artifactExactness === "store-delivered" && evidence.distribution === "apple-processed" && evidence.networkUnavailable === "proven";
|
|
35442
|
+
if (!simulator && !device && !store)
|
|
35443
|
+
throw new TypeError("iOS release certification contains invalid evidence strength.");
|
|
35444
|
+
};
|
|
35445
|
+
var canonicalJsonValue = (value) => {
|
|
35446
|
+
if (Array.isArray(value))
|
|
35447
|
+
return value.map(canonicalJsonValue);
|
|
35448
|
+
if (!isRecord14(value))
|
|
35449
|
+
return value;
|
|
35450
|
+
const sorted = {};
|
|
35451
|
+
for (const key of Object.keys(value).sort())
|
|
35452
|
+
sorted[key] = canonicalJsonValue(value[key]);
|
|
35453
|
+
return sorted;
|
|
35454
|
+
};
|
|
35455
|
+
var certificationBody = (certification) => JSON.stringify(canonicalJsonValue(certification));
|
|
35456
|
+
var createAbsoluteMobileReleaseCertification = async (options) => {
|
|
35457
|
+
if (options.evidencePaths.length === 0)
|
|
35458
|
+
throw new TypeError("Mobile release certification requires at least one --evidence report.");
|
|
35459
|
+
const release = releaseIdentity(options.release);
|
|
35460
|
+
const requirement = options.requirement ?? defaultRequirement(release.platform);
|
|
35461
|
+
validateRequirement(release.platform, requirement);
|
|
35462
|
+
const evidence = await Promise.all(options.evidencePaths.map((path) => validateEvidence(options.projectRoot, path, release)));
|
|
35463
|
+
evidence.sort((left, right) => left.reportSha256.localeCompare(right.reportSha256));
|
|
35464
|
+
const [firstEvidence] = evidence;
|
|
35465
|
+
if (!firstEvidence)
|
|
35466
|
+
throw new TypeError("Mobile release certification requires valid evidence.");
|
|
35467
|
+
const strength = evidence.reduce((strongest, candidate) => STRENGTH_RANK[candidate.strength] > STRENGTH_RANK[strongest] ? candidate.strength : strongest, firstEvidence.strength);
|
|
35468
|
+
if (!satisfiesRequirement(strength, requirement))
|
|
35469
|
+
throw new TypeError(`Mobile release evidence strength ${strength} does not satisfy required ${requirement} certification.`);
|
|
35470
|
+
const body = {
|
|
35471
|
+
evidence,
|
|
35472
|
+
format: ABSOLUTE_MOBILE_RELEASE_CERTIFICATION_FORMAT,
|
|
35473
|
+
generatedAt: options.generatedAt ?? evidence.reduce((latest, candidate) => candidate.generatedAt > latest ? candidate.generatedAt : latest, firstEvidence.generatedAt),
|
|
35474
|
+
release,
|
|
35475
|
+
requirement,
|
|
35476
|
+
status: "certified",
|
|
35477
|
+
strength
|
|
35478
|
+
};
|
|
35479
|
+
return {
|
|
35480
|
+
certificationId: `${CERTIFICATION_PREFIX}${sha2564(certificationBody(body))}`,
|
|
35481
|
+
...body
|
|
35482
|
+
};
|
|
35483
|
+
};
|
|
35484
|
+
var parseCertification = (value) => {
|
|
35485
|
+
if (!isRecord14(value) || value.format !== ABSOLUTE_MOBILE_RELEASE_CERTIFICATION_FORMAT || value.status !== "certified" || !isRecord14(value.release) || !Array.isArray(value.evidence))
|
|
35486
|
+
throw new TypeError("Mobile release certification contract is invalid.");
|
|
35487
|
+
const { release } = value;
|
|
35488
|
+
const { platform: platform4 } = release;
|
|
35489
|
+
const { engine } = release;
|
|
35490
|
+
if (platform4 !== "android" && platform4 !== "ios" || engine !== "capacitor" && engine !== "expo" || release.signed !== true)
|
|
35491
|
+
throw new TypeError("Mobile release certification identity is invalid.");
|
|
35492
|
+
const { requirement } = value;
|
|
35493
|
+
const { strength } = value;
|
|
35494
|
+
if (!isRequirement(requirement) || !isStrength(strength))
|
|
35495
|
+
throw new TypeError("Mobile release certification policy is invalid.");
|
|
35496
|
+
validateRequirement(platform4, requirement);
|
|
35497
|
+
if (!satisfiesRequirement(strength, requirement))
|
|
35498
|
+
throw new TypeError("Mobile release certification does not satisfy its declared policy.");
|
|
35499
|
+
const artifactBytes = requirePositiveInteger(release.artifactBytes, "release artifactBytes");
|
|
35500
|
+
const artifactSha256 = requireString2(release.artifactSha256, "release artifactSha256");
|
|
35501
|
+
if (!SHA256.test(artifactSha256))
|
|
35502
|
+
throw new TypeError("Mobile release certification artifact digest is invalid.");
|
|
35503
|
+
const parsedRelease = {
|
|
35504
|
+
appBuild: requireString2(release.appBuild, "release appBuild"),
|
|
35505
|
+
appId: requireString2(release.appId, "release appId"),
|
|
35506
|
+
artifactBytes,
|
|
35507
|
+
artifactSha256,
|
|
35508
|
+
engine,
|
|
35509
|
+
platform: platform4,
|
|
35510
|
+
releaseId: requireString2(release.releaseId, "release releaseId"),
|
|
35511
|
+
runtime: requireString2(release.runtime, "release runtime"),
|
|
35512
|
+
signed: true,
|
|
35513
|
+
...release.buildNumber === undefined ? {} : {
|
|
35514
|
+
buildNumber: requirePositiveInteger(release.buildNumber, "release buildNumber")
|
|
35515
|
+
},
|
|
35516
|
+
...release.marketingVersion === undefined ? {} : {
|
|
35517
|
+
marketingVersion: requireString2(release.marketingVersion, "release marketingVersion")
|
|
35518
|
+
},
|
|
35519
|
+
...release.versionCode === undefined ? {} : {
|
|
35520
|
+
versionCode: requirePositiveInteger(release.versionCode, "release versionCode")
|
|
35521
|
+
}
|
|
35522
|
+
};
|
|
35523
|
+
const evidence = value.evidence.map((candidate) => {
|
|
35524
|
+
if (!isRecord14(candidate) || !SHA256.test(String(candidate.reportSha256)) || !isStrength(candidate.strength) || candidate.networkUnavailable !== "not-proven" && candidate.networkUnavailable !== "proven" || typeof candidate.remote !== "boolean" || typeof candidate.generatedAt !== "string" || candidate.artifactExactness !== undefined && !isArtifactExactness(candidate.artifactExactness) || candidate.distribution !== undefined && !isDistribution(candidate.distribution))
|
|
35525
|
+
throw new TypeError("Mobile release certification evidence is invalid.");
|
|
35526
|
+
const parsedEvidence = {
|
|
35527
|
+
generatedAt: candidate.generatedAt,
|
|
35528
|
+
networkUnavailable: candidate.networkUnavailable,
|
|
35529
|
+
remote: candidate.remote,
|
|
35530
|
+
reportSha256: String(candidate.reportSha256),
|
|
35531
|
+
strength: candidate.strength,
|
|
35532
|
+
...candidate.artifactExactness === undefined ? {} : {
|
|
35533
|
+
artifactExactness: candidate.artifactExactness
|
|
35534
|
+
},
|
|
35535
|
+
...candidate.distribution === undefined ? {} : { distribution: candidate.distribution }
|
|
35536
|
+
};
|
|
35537
|
+
validateCertifiedEvidence(platform4, parsedEvidence);
|
|
35538
|
+
return parsedEvidence;
|
|
35539
|
+
});
|
|
35540
|
+
const strongestEvidence = evidence.reduce((strongest, candidate) => STRENGTH_RANK[candidate.strength] > STRENGTH_RANK[strongest] ? candidate.strength : strongest, evidence[0]?.strength ?? "installed");
|
|
35541
|
+
if (evidence.length === 0 || strongestEvidence !== strength)
|
|
35542
|
+
throw new TypeError("Mobile release certification evidence does not support its declared strength.");
|
|
35543
|
+
const parsed = {
|
|
35544
|
+
certificationId: requireString2(value.certificationId, "certificationId"),
|
|
35545
|
+
evidence,
|
|
35546
|
+
format: ABSOLUTE_MOBILE_RELEASE_CERTIFICATION_FORMAT,
|
|
35547
|
+
generatedAt: requireString2(value.generatedAt, "generatedAt"),
|
|
35548
|
+
release: parsedRelease,
|
|
35549
|
+
requirement,
|
|
35550
|
+
status: "certified",
|
|
35551
|
+
strength
|
|
35552
|
+
};
|
|
35553
|
+
const { certificationId, ...body } = parsed;
|
|
35554
|
+
if (certificationId !== `${CERTIFICATION_PREFIX}${sha2564(certificationBody(body))}`)
|
|
35555
|
+
throw new TypeError("Mobile release certification content digest is invalid.");
|
|
35556
|
+
return parsed;
|
|
35557
|
+
};
|
|
35558
|
+
var readAbsoluteMobileReleaseCertification = async (projectRoot, requested) => {
|
|
35559
|
+
const selected = resolve18(projectRoot, requested);
|
|
35560
|
+
if (!inside4(projectRoot, selected))
|
|
35561
|
+
throw new TypeError("Mobile release certification must remain inside the project.");
|
|
35562
|
+
const path = basename8(selected) === "certification.json" ? selected : join30(selected, "certification.json");
|
|
35563
|
+
const value = JSON.parse(await readFile26(path, "utf8"));
|
|
35564
|
+
return { certification: parseCertification(value), path };
|
|
35565
|
+
};
|
|
35566
|
+
var renderAbsoluteMobileReleaseCertification = (certification) => {
|
|
35567
|
+
const { release } = certification;
|
|
35568
|
+
const version = release.platform === "ios" ? `${release.marketingVersion ?? "unknown"} (${release.buildNumber ?? "unallocated"})` : String(release.versionCode ?? "unallocated");
|
|
35569
|
+
const evidence = certification.evidence.map((item) => `| ${item.strength} | ${item.networkUnavailable} | ${item.remote ? "paired Mac" : "local host"} | ${item.reportSha256} |`).join(`
|
|
35570
|
+
`);
|
|
35571
|
+
return `# AbsoluteJS mobile release certification
|
|
35572
|
+
|
|
35573
|
+
- Status: CERTIFIED
|
|
35574
|
+
- Certification: ${certification.certificationId}
|
|
35575
|
+
- Generated: ${certification.generatedAt}
|
|
35576
|
+
- Platform: ${release.platform}
|
|
35577
|
+
- Engine: ${release.engine}
|
|
35578
|
+
- Requirement: ${certification.requirement}
|
|
35579
|
+
- Evidence strength: ${certification.strength}
|
|
35580
|
+
- Release: ${release.releaseId}
|
|
35581
|
+
- Artifact SHA-256: ${release.artifactSha256}
|
|
35582
|
+
- Runtime fingerprint: ${release.runtime}
|
|
35583
|
+
- Embedded app build: ${release.appBuild}
|
|
35584
|
+
- Version/build: ${version}
|
|
35585
|
+
|
|
35586
|
+
This certification is local and contains no signing credentials, device identifiers, SSH destinations, report paths, application data, or page contents. Re-run verification against the immutable release before using it as a CI or promotion gate.
|
|
35587
|
+
|
|
35588
|
+
| Strength | Network unavailable | Execution | Report SHA-256 |
|
|
35589
|
+
| --- | --- | --- | --- |
|
|
35590
|
+
${evidence}
|
|
35591
|
+
`;
|
|
35592
|
+
};
|
|
35593
|
+
var verifyAbsoluteMobileReleaseCertification = (certification, release, requirement) => {
|
|
35594
|
+
const parsed = parseCertification(certification);
|
|
35595
|
+
const expected = releaseIdentity(release);
|
|
35596
|
+
if (JSON.stringify(parsed.release) !== JSON.stringify(expected))
|
|
35597
|
+
throw new TypeError("Mobile release certification was invalidated by a release identity, artifact, runtime, signing, version, build, or embedded-bundle change.");
|
|
35598
|
+
if (requirement) {
|
|
35599
|
+
validateRequirement(expected.platform, requirement);
|
|
35600
|
+
if (!satisfiesRequirement(parsed.strength, requirement))
|
|
35601
|
+
throw new TypeError(`Mobile release certification strength ${parsed.strength} does not satisfy required ${requirement} policy.`);
|
|
35602
|
+
}
|
|
35603
|
+
return parsed;
|
|
35604
|
+
};
|
|
35605
|
+
var writeAbsoluteMobileReleaseCertification = async (projectRoot, certification, outputDirectory) => {
|
|
35606
|
+
const root = resolve18(projectRoot);
|
|
35607
|
+
const parent = resolve18(root, outputDirectory ?? join30(".absolutejs", "mobile", "certifications", certification.release.platform, certification.release.releaseId));
|
|
35608
|
+
if (!inside4(root, parent))
|
|
35609
|
+
throw new TypeError("Mobile certification output must remain inside the project.");
|
|
35610
|
+
await mkdir20(parent, { recursive: true });
|
|
35611
|
+
const destination = join30(parent, certification.certificationId);
|
|
35612
|
+
const paths = {
|
|
35613
|
+
directory: destination,
|
|
35614
|
+
jsonPath: join30(destination, "certification.json"),
|
|
35615
|
+
markdownPath: join30(destination, "certification.md")
|
|
35616
|
+
};
|
|
35617
|
+
const json = `${JSON.stringify(certification, null, 2)}
|
|
35618
|
+
`;
|
|
35619
|
+
const markdown = renderAbsoluteMobileReleaseCertification(certification);
|
|
35620
|
+
const verifyExisting = async () => {
|
|
35621
|
+
const [existingJson, existingMarkdown] = await Promise.all([
|
|
35622
|
+
readFile26(paths.jsonPath, "utf8"),
|
|
35623
|
+
readFile26(paths.markdownPath, "utf8")
|
|
35624
|
+
]);
|
|
35625
|
+
if (existingJson !== json || existingMarkdown !== markdown)
|
|
35626
|
+
throw new TypeError(`Immutable mobile certification ${certification.certificationId} already exists with different content.`);
|
|
35627
|
+
};
|
|
35628
|
+
if (await exists9(destination)) {
|
|
35629
|
+
await verifyExisting();
|
|
35630
|
+
return paths;
|
|
35631
|
+
}
|
|
35632
|
+
const staging = await mkdtemp10(join30(parent, ".certification-"));
|
|
35633
|
+
try {
|
|
35634
|
+
await Promise.all([
|
|
35635
|
+
writeFile22(join30(staging, "certification.json"), json, {
|
|
35636
|
+
flag: "wx"
|
|
35637
|
+
}),
|
|
35638
|
+
writeFile22(join30(staging, "certification.md"), markdown, {
|
|
35639
|
+
flag: "wx"
|
|
35640
|
+
})
|
|
35641
|
+
]);
|
|
35642
|
+
await rename18(staging, destination).catch(async (error) => {
|
|
35643
|
+
if (await exists9(destination))
|
|
35644
|
+
return;
|
|
35645
|
+
throw error;
|
|
35646
|
+
});
|
|
35647
|
+
} finally {
|
|
35648
|
+
await rm15(staging, { force: true, recursive: true });
|
|
35649
|
+
}
|
|
35650
|
+
await verifyExisting();
|
|
35651
|
+
return paths;
|
|
35652
|
+
};
|
|
35000
35653
|
// src/mobile/releasePublisher.ts
|
|
35001
|
-
import { access as
|
|
35002
|
-
import { isAbsolute as
|
|
35654
|
+
import { access as access18 } from "fs/promises";
|
|
35655
|
+
import { isAbsolute as isAbsolute10, relative as relative17, resolve as resolve19, sep as sep12 } from "path";
|
|
35003
35656
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
35004
35657
|
var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
35005
35658
|
if (typeof publisher.prepareIosRelease !== "function") {
|
|
@@ -35022,24 +35675,24 @@ var prepareAbsoluteAndroidRelease = async (publisher, options) => {
|
|
|
35022
35675
|
}
|
|
35023
35676
|
return versionCode;
|
|
35024
35677
|
};
|
|
35025
|
-
var
|
|
35026
|
-
var isPublisher = (value) =>
|
|
35678
|
+
var isRecord15 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
35679
|
+
var isPublisher = (value) => isRecord15(value) && typeof value.publish === "function";
|
|
35027
35680
|
var publisherModulePath = (projectRoot, requested) => {
|
|
35028
|
-
const root =
|
|
35029
|
-
const path =
|
|
35030
|
-
const projectRelative =
|
|
35031
|
-
if (projectRelative === ".." || projectRelative.startsWith(`..${
|
|
35681
|
+
const root = resolve19(projectRoot);
|
|
35682
|
+
const path = resolve19(root, requested);
|
|
35683
|
+
const projectRelative = relative17(root, path);
|
|
35684
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep12}`) || isAbsolute10(projectRelative)) {
|
|
35032
35685
|
throw new TypeError("mobile publish --registry must remain inside the project.");
|
|
35033
35686
|
}
|
|
35034
35687
|
return path;
|
|
35035
35688
|
};
|
|
35036
35689
|
var loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath) => {
|
|
35037
35690
|
const modulePath = publisherModulePath(projectRoot, requestedModulePath);
|
|
35038
|
-
await
|
|
35691
|
+
await access18(modulePath).catch(() => {
|
|
35039
35692
|
throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
|
|
35040
35693
|
});
|
|
35041
35694
|
const loaded = await import(pathToFileURL3(modulePath).href);
|
|
35042
|
-
const publisher =
|
|
35695
|
+
const publisher = isRecord15(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
35043
35696
|
if (!isPublisher(publisher)) {
|
|
35044
35697
|
throw new TypeError("Native release registry module must default-export a registry with publish(options).");
|
|
35045
35698
|
}
|
|
@@ -35099,7 +35752,7 @@ var publishAbsoluteIosRelease = async (options) => {
|
|
|
35099
35752
|
init_pageProtocol();
|
|
35100
35753
|
init_releaseArtifact();
|
|
35101
35754
|
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
|
|
35102
|
-
import { dirname as dirname20, extname as extname6, relative as
|
|
35755
|
+
import { dirname as dirname20, extname as extname6, relative as relative18, resolve as resolve20 } from "path";
|
|
35103
35756
|
import ts2 from "typescript";
|
|
35104
35757
|
var ROUTE_METHODS = new Set(["get", "head"]);
|
|
35105
35758
|
var SOURCE_FILTER = /\.[cm]?[jt]sx?$/;
|
|
@@ -35268,7 +35921,7 @@ var resolvePageIdentity = (expression, sourceFile, checker, projectRoot) => {
|
|
|
35268
35921
|
const declaration = symbol?.declarations?.[0];
|
|
35269
35922
|
const file = declaration?.getSourceFile().fileName ?? sourceFile.fileName;
|
|
35270
35923
|
const exportedName = symbol?.name ?? expression.getText(sourceFile);
|
|
35271
|
-
const source = posixPath(
|
|
35924
|
+
const source = posixPath(relative18(projectRoot, file));
|
|
35272
35925
|
return `${source}#${exportedName}`;
|
|
35273
35926
|
};
|
|
35274
35927
|
var resolveAlias = (symbol, checker) => {
|
|
@@ -35507,7 +36160,7 @@ var analyzeProgram = (program, projectRoot) => {
|
|
|
35507
36160
|
const checker = program.getTypeChecker();
|
|
35508
36161
|
const analyzed = new Map;
|
|
35509
36162
|
for (const sourceFile of program.getSourceFiles()) {
|
|
35510
|
-
const resolvedFile =
|
|
36163
|
+
const resolvedFile = resolve20(sourceFile.fileName);
|
|
35511
36164
|
if (!isProjectSource(sourceFile, resolvedFile, projectRoot))
|
|
35512
36165
|
continue;
|
|
35513
36166
|
const analysis = analyzeSourceFile(sourceFile, checker, projectRoot);
|
|
@@ -35600,14 +36253,14 @@ var transformFile = (source, fileName, analysis) => {
|
|
|
35600
36253
|
};
|
|
35601
36254
|
var ABSOLUTE_MOBILE_TRANSFORM_PROTOCOL = ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION;
|
|
35602
36255
|
var createAbsoluteMobileRouteMetadataPlugin = (options) => {
|
|
35603
|
-
const projectRoot =
|
|
35604
|
-
const entry =
|
|
36256
|
+
const projectRoot = resolve20(options.projectRoot ?? process.cwd());
|
|
36257
|
+
const entry = resolve20(options.entry);
|
|
35605
36258
|
const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
|
|
35606
36259
|
return {
|
|
35607
36260
|
name: "absolute-mobile-route-metadata",
|
|
35608
36261
|
setup(build) {
|
|
35609
36262
|
build.onLoad({ filter: SOURCE_FILTER }, async ({ path }) => {
|
|
35610
|
-
const analysis = analyzed.get(
|
|
36263
|
+
const analysis = analyzed.get(resolve20(path));
|
|
35611
36264
|
if (!analysis)
|
|
35612
36265
|
return;
|
|
35613
36266
|
const source = await Bun.file(path).text();
|
|
@@ -35620,11 +36273,11 @@ var createAbsoluteMobileRouteMetadataPlugin = (options) => {
|
|
|
35620
36273
|
};
|
|
35621
36274
|
};
|
|
35622
36275
|
var inspectAbsoluteMobileRouteMetadata = (options) => {
|
|
35623
|
-
const projectRoot =
|
|
35624
|
-
const entry =
|
|
36276
|
+
const projectRoot = resolve20(options.projectRoot ?? process.cwd());
|
|
36277
|
+
const entry = resolve20(options.entry);
|
|
35625
36278
|
const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
|
|
35626
36279
|
return [...analyzed.entries()].flatMap(([file, analysis]) => [...analysis.byRouteCall.values()].map(({ metadata }) => ({
|
|
35627
|
-
file: posixPath(
|
|
36280
|
+
file: posixPath(relative18(projectRoot, file)),
|
|
35628
36281
|
metadata
|
|
35629
36282
|
})));
|
|
35630
36283
|
};
|
|
@@ -35958,7 +36611,7 @@ var createCapacitor = (win) => {
|
|
|
35958
36611
|
callbackId
|
|
35959
36612
|
}, callback);
|
|
35960
36613
|
};
|
|
35961
|
-
const p = new Promise((
|
|
36614
|
+
const p = new Promise((resolve21) => call.then(() => resolve21({ remove })));
|
|
35962
36615
|
p.remove = async () => {
|
|
35963
36616
|
console.warn(`Using addListener() without 'await' is deprecated.`);
|
|
35964
36617
|
await remove();
|
|
@@ -36163,11 +36816,11 @@ class CapacitorCookiesPluginWeb extends WebPlugin {
|
|
|
36163
36816
|
var CapacitorCookies = registerPlugin("CapacitorCookies", {
|
|
36164
36817
|
web: () => new CapacitorCookiesPluginWeb
|
|
36165
36818
|
});
|
|
36166
|
-
var readBlobAsBase64 = async (blob) => new Promise((
|
|
36819
|
+
var readBlobAsBase64 = async (blob) => new Promise((resolve21, reject) => {
|
|
36167
36820
|
const reader = new FileReader;
|
|
36168
36821
|
reader.onload = () => {
|
|
36169
36822
|
const base64String = reader.result;
|
|
36170
|
-
|
|
36823
|
+
resolve21(base64String.indexOf(",") >= 0 ? base64String.split(",")[1] : base64String);
|
|
36171
36824
|
};
|
|
36172
36825
|
reader.onerror = (error) => reject(error);
|
|
36173
36826
|
reader.readAsDataURL(blob);
|
|
@@ -36343,7 +36996,7 @@ var REPORT_KINDS = new Set([
|
|
|
36343
36996
|
"signal"
|
|
36344
36997
|
]);
|
|
36345
36998
|
var nativeObservability = registerPlugin("AbsoluteMobileObservability");
|
|
36346
|
-
var
|
|
36999
|
+
var isRecord16 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
36347
37000
|
var redactText = (value) => value.slice(0, MAX_STRING_LENGTH).replace(/\b(Bearer)\s+[A-Za-z0-9._~+/-]+=*/giu, "$1 [REDACTED]").replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\s]*/giu, "$1[REDACTED]").replace(/\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\s*[:=]\s*)[^,\s;]+/giu, "$1[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[REDACTED]");
|
|
36348
37001
|
var redactValue = (value, depth = 0) => {
|
|
36349
37002
|
if (depth >= MAX_REDACTION_DEPTH)
|
|
@@ -36354,7 +37007,7 @@ var redactValue = (value, depth = 0) => {
|
|
|
36354
37007
|
return value;
|
|
36355
37008
|
if (Array.isArray(value))
|
|
36356
37009
|
return value.slice(0, 64).map((entry) => redactValue(entry, depth + 1));
|
|
36357
|
-
if (!
|
|
37010
|
+
if (!isRecord16(value))
|
|
36358
37011
|
return String(value).slice(0, MAX_STRING_LENGTH);
|
|
36359
37012
|
return Object.fromEntries(Object.entries(value).slice(0, 128).map(([key, entry]) => [
|
|
36360
37013
|
key,
|
|
@@ -36362,7 +37015,7 @@ var redactValue = (value, depth = 0) => {
|
|
|
36362
37015
|
]));
|
|
36363
37016
|
};
|
|
36364
37017
|
var parseReport = (value) => {
|
|
36365
|
-
if (!
|
|
37018
|
+
if (!isRecord16(value) || !isRecord16(value.details))
|
|
36366
37019
|
return;
|
|
36367
37020
|
if (typeof value.id !== "string" || !REPORT_ID.test(value.id))
|
|
36368
37021
|
return;
|
|
@@ -36373,7 +37026,7 @@ var parseReport = (value) => {
|
|
|
36373
37026
|
if (value.platform !== "android" && value.platform !== "ios")
|
|
36374
37027
|
return;
|
|
36375
37028
|
const details = redactValue(value.details);
|
|
36376
|
-
if (!
|
|
37029
|
+
if (!isRecord16(details))
|
|
36377
37030
|
return;
|
|
36378
37031
|
if (new TextEncoder().encode(JSON.stringify(details)).byteLength > MAX_DETAIL_BYTES)
|
|
36379
37032
|
return;
|
|
@@ -40827,8 +41480,8 @@ var createBeacon = (options) => {
|
|
|
40827
41480
|
if (await fontAvailable(element))
|
|
40828
41481
|
return;
|
|
40829
41482
|
if (confirmationMs > 0) {
|
|
40830
|
-
await new Promise((
|
|
40831
|
-
const timer2 = window.setTimeout(
|
|
41483
|
+
await new Promise((resolve21) => {
|
|
41484
|
+
const timer2 = window.setTimeout(resolve21, confirmationMs);
|
|
40832
41485
|
cleanups.push(() => window.clearTimeout(timer2));
|
|
40833
41486
|
});
|
|
40834
41487
|
if (document.visibilityState === "hidden")
|
|
@@ -41816,51 +42469,51 @@ var createAbsoluteMobileUpdateClient = (options) => {
|
|
|
41816
42469
|
};
|
|
41817
42470
|
};
|
|
41818
42471
|
// src/mobile/updatePublisher.ts
|
|
41819
|
-
import { access as
|
|
41820
|
-
import { isAbsolute as
|
|
42472
|
+
import { access as access19 } from "fs/promises";
|
|
42473
|
+
import { isAbsolute as isAbsolute11, relative as relative20, resolve as resolve22, sep as sep13 } from "path";
|
|
41821
42474
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
41822
42475
|
|
|
41823
42476
|
// src/mobile/updateSigning.ts
|
|
41824
|
-
import { createHash as
|
|
42477
|
+
import { createHash as createHash17, sign, verify } from "crypto";
|
|
41825
42478
|
import {
|
|
41826
42479
|
cp as cp2,
|
|
41827
|
-
mkdir as
|
|
41828
|
-
mkdtemp as
|
|
42480
|
+
mkdir as mkdir21,
|
|
42481
|
+
mkdtemp as mkdtemp11,
|
|
41829
42482
|
readdir as readdir10,
|
|
41830
|
-
readFile as
|
|
41831
|
-
rename as
|
|
41832
|
-
rm as
|
|
42483
|
+
readFile as readFile27,
|
|
42484
|
+
rename as rename19,
|
|
42485
|
+
rm as rm16,
|
|
41833
42486
|
stat as stat6,
|
|
41834
|
-
writeFile as
|
|
42487
|
+
writeFile as writeFile23
|
|
41835
42488
|
} from "fs/promises";
|
|
41836
|
-
import { dirname as dirname21, join as
|
|
42489
|
+
import { dirname as dirname21, join as join31, relative as relative19, resolve as resolve21 } from "path";
|
|
41837
42490
|
var UPDATE_MANIFEST_FILE = "update.json";
|
|
41838
42491
|
var UPDATE_FILES_DIRECTORY = "files";
|
|
41839
|
-
var
|
|
42492
|
+
var sha2565 = (value) => createHash17("sha256").update(value).digest("hex");
|
|
41840
42493
|
var listFiles = async (root, directory = root) => {
|
|
41841
42494
|
const entries = await readdir10(directory, { withFileTypes: true });
|
|
41842
42495
|
const paths = await Promise.all(entries.map(async (entry) => {
|
|
41843
|
-
const path =
|
|
42496
|
+
const path = join31(directory, entry.name);
|
|
41844
42497
|
if (entry.isDirectory())
|
|
41845
42498
|
return listFiles(root, path);
|
|
41846
42499
|
if (!entry.isFile())
|
|
41847
42500
|
throw new TypeError("Mobile updates cannot contain links or special files.");
|
|
41848
|
-
return [
|
|
42501
|
+
return [relative19(root, path).replaceAll("\\", "/")];
|
|
41849
42502
|
}));
|
|
41850
42503
|
return paths.flat().sort((left, right) => left.localeCompare(right));
|
|
41851
42504
|
};
|
|
41852
42505
|
var inspectFiles = async (root, paths) => Promise.all(paths.map(async (path) => {
|
|
41853
|
-
const source =
|
|
42506
|
+
const source = join31(root, path);
|
|
41854
42507
|
const [metadata, contents] = await Promise.all([
|
|
41855
42508
|
stat6(source),
|
|
41856
|
-
|
|
42509
|
+
readFile27(source)
|
|
41857
42510
|
]);
|
|
41858
|
-
return { bytes: metadata.size, path, sha256:
|
|
42511
|
+
return { bytes: metadata.size, path, sha256: sha2565(contents) };
|
|
41859
42512
|
}));
|
|
41860
|
-
var releaseIdFor = (value) => `amu_${
|
|
42513
|
+
var releaseIdFor = (value) => `amu_${sha2565(canonicalizeAbsoluteMobileUpdate(value))}`;
|
|
41861
42514
|
var buildAbsoluteMobileUpdate = async (options) => {
|
|
41862
|
-
const bundleDirectory =
|
|
41863
|
-
const outputRoot =
|
|
42515
|
+
const bundleDirectory = resolve21(options.bundleDirectory);
|
|
42516
|
+
const outputRoot = resolve21(options.outputDirectory);
|
|
41864
42517
|
if (outputRoot === bundleDirectory || outputRoot.startsWith(`${bundleDirectory}/`))
|
|
41865
42518
|
throw new TypeError("Mobile update output must be outside the embedded bundle.");
|
|
41866
42519
|
const paths = await listFiles(bundleDirectory);
|
|
@@ -41888,38 +42541,38 @@ var buildAbsoluteMobileUpdate = async (options) => {
|
|
|
41888
42541
|
value: signature.toString("base64")
|
|
41889
42542
|
}
|
|
41890
42543
|
});
|
|
41891
|
-
await
|
|
41892
|
-
const outputDirectory =
|
|
41893
|
-
const staging = await
|
|
42544
|
+
await mkdir21(outputRoot, { recursive: true });
|
|
42545
|
+
const outputDirectory = join31(outputRoot, manifest.releaseId);
|
|
42546
|
+
const staging = await mkdtemp11(join31(outputRoot, ".stage-"));
|
|
41894
42547
|
try {
|
|
41895
|
-
await cp2(bundleDirectory,
|
|
42548
|
+
await cp2(bundleDirectory, join31(staging, UPDATE_FILES_DIRECTORY), {
|
|
41896
42549
|
force: true,
|
|
41897
42550
|
recursive: true
|
|
41898
42551
|
});
|
|
41899
|
-
await
|
|
42552
|
+
await writeFile23(join31(staging, UPDATE_MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
41900
42553
|
`);
|
|
41901
|
-
await
|
|
42554
|
+
await rename19(staging, outputDirectory);
|
|
41902
42555
|
} catch (error) {
|
|
41903
|
-
await
|
|
42556
|
+
await rm16(staging, { force: true, recursive: true });
|
|
41904
42557
|
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "EEXIST")
|
|
41905
42558
|
throw new TypeError(`Mobile update ${manifest.releaseId} already exists.`, { cause: error });
|
|
41906
42559
|
throw error;
|
|
41907
42560
|
}
|
|
41908
42561
|
return {
|
|
41909
42562
|
manifest,
|
|
41910
|
-
manifestPath:
|
|
42563
|
+
manifestPath: join31(outputDirectory, UPDATE_MANIFEST_FILE),
|
|
41911
42564
|
outputDirectory
|
|
41912
42565
|
};
|
|
41913
42566
|
};
|
|
41914
42567
|
var copyAbsoluteMobileUpdateFile = async (updateDirectory, path, destination) => {
|
|
41915
|
-
const source =
|
|
41916
|
-
const root =
|
|
42568
|
+
const source = resolve21(updateDirectory, UPDATE_FILES_DIRECTORY, path);
|
|
42569
|
+
const root = resolve21(updateDirectory, UPDATE_FILES_DIRECTORY);
|
|
41917
42570
|
if (!source.startsWith(`${root}/`))
|
|
41918
42571
|
throw new TypeError("Update file escaped its release.");
|
|
41919
|
-
await
|
|
42572
|
+
await mkdir21(dirname21(destination), { recursive: true });
|
|
41920
42573
|
await cp2(source, destination, { force: true });
|
|
41921
42574
|
};
|
|
41922
|
-
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await
|
|
42575
|
+
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile27(join31(resolve21(directory), UPDATE_MANIFEST_FILE), "utf8")));
|
|
41923
42576
|
var verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
|
|
41924
42577
|
const manifest = parseAbsoluteMobileUpdateManifest(manifestValue);
|
|
41925
42578
|
const valid = verify("sha256", absoluteMobileUpdateSigningPayload(unsignedAbsoluteMobileUpdate(manifest)), { dsaEncoding: "ieee-p1363", key: publicKey }, Buffer.from(manifest.signature.value, "base64"));
|
|
@@ -42036,16 +42689,16 @@ var pruneAbsoluteMobileUpdates = async (options) => {
|
|
|
42036
42689
|
var object5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
42037
42690
|
var isPublisher2 = (value) => object5(value) && typeof value.publishUpdate === "function" && typeof value.promoteUpdate === "function" && typeof value.rollbackUpdate === "function";
|
|
42038
42691
|
var projectPath2 = (projectRoot, requested, label) => {
|
|
42039
|
-
const root =
|
|
42040
|
-
const path =
|
|
42041
|
-
const projectRelative =
|
|
42042
|
-
if (projectRelative === ".." || projectRelative.startsWith(`..${
|
|
42692
|
+
const root = resolve22(projectRoot);
|
|
42693
|
+
const path = resolve22(root, requested);
|
|
42694
|
+
const projectRelative = relative20(root, path);
|
|
42695
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep13}`) || isAbsolute11(projectRelative))
|
|
42043
42696
|
throw new TypeError(`${label} must remain inside the project.`);
|
|
42044
42697
|
return path;
|
|
42045
42698
|
};
|
|
42046
42699
|
var loadAbsoluteMobileUpdatePublisher = async (projectRoot, requestedModulePath) => {
|
|
42047
42700
|
const modulePath = projectPath2(projectRoot, requestedModulePath, "mobile update registry");
|
|
42048
|
-
await
|
|
42701
|
+
await access19(modulePath).catch(() => {
|
|
42049
42702
|
throw new TypeError(`Mobile update registry does not exist: ${modulePath}`);
|
|
42050
42703
|
});
|
|
42051
42704
|
const loaded = await import(pathToFileURL4(modulePath).href);
|
|
@@ -42096,7 +42749,7 @@ var rollbackAbsoluteMobileUpdate = async (options) => {
|
|
|
42096
42749
|
return result;
|
|
42097
42750
|
};
|
|
42098
42751
|
// src/mobile/updateRollout.ts
|
|
42099
|
-
import { createHash as
|
|
42752
|
+
import { createHash as createHash18 } from "crypto";
|
|
42100
42753
|
var UUID_PATTERN = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-8][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u;
|
|
42101
42754
|
var requireHeader = (headers, name) => {
|
|
42102
42755
|
const value = headers.get(name);
|
|
@@ -42111,7 +42764,7 @@ var isAbsoluteMobileUpdateRolloutMember = (options) => {
|
|
|
42111
42764
|
return false;
|
|
42112
42765
|
if (options.rollout === 1)
|
|
42113
42766
|
return true;
|
|
42114
|
-
const digest =
|
|
42767
|
+
const digest = createHash18("sha256").update(`${options.appId}\x00${options.channel}\x00${options.releaseId}\x00${options.installationId}`).digest();
|
|
42115
42768
|
const bucket = digest.readUInt32BE(0) / 4294967296;
|
|
42116
42769
|
return bucket < options.rollout;
|
|
42117
42770
|
};
|
|
@@ -42158,6 +42811,7 @@ export {
|
|
|
42158
42811
|
ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE,
|
|
42159
42812
|
ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
|
|
42160
42813
|
ABSOLUTE_MOBILE_PREVIEW_PATH,
|
|
42814
|
+
ABSOLUTE_MOBILE_RELEASE_CERTIFICATION_FORMAT,
|
|
42161
42815
|
ABSOLUTE_MOBILE_RETAINED_GENERATIONS,
|
|
42162
42816
|
ABSOLUTE_MOBILE_ROUTE_DETAIL,
|
|
42163
42817
|
ABSOLUTE_MOBILE_SHELL_ABI,
|
|
@@ -42243,6 +42897,7 @@ export {
|
|
|
42243
42897
|
createAbsoluteMobilePageErrorResponse,
|
|
42244
42898
|
createAbsoluteMobilePageRequest,
|
|
42245
42899
|
createAbsoluteMobilePreviewPlugin,
|
|
42900
|
+
createAbsoluteMobileReleaseCertification,
|
|
42246
42901
|
createAbsoluteMobileRouteMetadataPlugin,
|
|
42247
42902
|
createAbsoluteMobileUpdateClient,
|
|
42248
42903
|
createAbsoluteMobileUpdateRuntimeDescriptor,
|
|
@@ -42352,10 +43007,12 @@ export {
|
|
|
42352
43007
|
readAbsoluteIosRelease,
|
|
42353
43008
|
readAbsoluteMobileLinkIntent,
|
|
42354
43009
|
readAbsoluteMobileMaterializedReleases,
|
|
43010
|
+
readAbsoluteMobileReleaseCertification,
|
|
42355
43011
|
readAbsoluteMobileUpdate,
|
|
42356
43012
|
reconcileAbsoluteMobileUpdateRollout,
|
|
42357
43013
|
redactAbsoluteIosLog,
|
|
42358
43014
|
removeAbsoluteRemoteMacProfile,
|
|
43015
|
+
renderAbsoluteMobileReleaseCertification,
|
|
42359
43016
|
renderAbsoluteMobileUpdateRegistry,
|
|
42360
43017
|
repairAbsoluteIosDevSession,
|
|
42361
43018
|
reportAbsoluteMobileUpdateHealth,
|
|
@@ -42376,6 +43033,7 @@ export {
|
|
|
42376
43033
|
runAbsoluteAndroidUpgradeConformance,
|
|
42377
43034
|
runAbsoluteIosDeviceReleaseAcceptance,
|
|
42378
43035
|
runAbsoluteIosSimulatorReleaseAcceptance,
|
|
43036
|
+
runAbsoluteRemoteIosReleaseAcceptance,
|
|
42379
43037
|
runWithAbsoluteMobileProducer,
|
|
42380
43038
|
serializeAbsoluteMobileAuthEnvironment,
|
|
42381
43039
|
startAbsoluteExpoDevSession,
|
|
@@ -42385,6 +43043,7 @@ export {
|
|
|
42385
43043
|
startAbsoluteRemoteExpoIosDevSession,
|
|
42386
43044
|
startAbsoluteRemoteIosDevSession,
|
|
42387
43045
|
syncAbsoluteExpoWebAssets,
|
|
43046
|
+
syncAbsoluteRemoteMacAcceptanceRelease,
|
|
42388
43047
|
syncAbsoluteRemoteMacProject,
|
|
42389
43048
|
syncAbsoluteRemoteMacReleaseInputs,
|
|
42390
43049
|
testAbsoluteIosPhysicalDevice,
|
|
@@ -42393,13 +43052,15 @@ export {
|
|
|
42393
43052
|
validateAbsoluteSshDestination,
|
|
42394
43053
|
verifyAbsoluteMobileAssociationFiles,
|
|
42395
43054
|
verifyAbsoluteMobileCompatibilityProducer,
|
|
43055
|
+
verifyAbsoluteMobileReleaseCertification,
|
|
42396
43056
|
verifyAbsoluteMobileUpdateSignature,
|
|
42397
43057
|
waitForAbsoluteIosHmrLog,
|
|
42398
43058
|
writeAbsoluteCapacitorConfig,
|
|
42399
43059
|
writeAbsoluteExpoProject,
|
|
42400
43060
|
writeAbsoluteMobileGithubWorkflow,
|
|
43061
|
+
writeAbsoluteMobileReleaseCertification,
|
|
42401
43062
|
writeAbsoluteMobileUpdateRegistry
|
|
42402
43063
|
};
|
|
42403
43064
|
|
|
42404
|
-
//# debugId=
|
|
43065
|
+
//# debugId=DB53CC7C8DF0442B64756E2164756E21
|
|
42405
43066
|
//# sourceMappingURL=index.js.map
|