@absolutejs/absolute 0.20.0-beta.112 → 0.20.0-beta.114
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 +54 -0
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/build.js +54 -2
- package/dist/build.js.map +3 -3
- package/dist/cli/{compile-1d5arbqj.js → compile-ya4kd2sg.js} +3 -3
- package/dist/cli/{config-vq2qcc4p.js → config-rjeexvza.js} +1 -1
- package/dist/cli/{dev-f0safhsr.js → dev-5cqmf7za.js} +2 -2
- package/dist/cli/{expoProject-zkprmjjz.js → expoProject-f5j20xms.js} +1 -1
- package/dist/cli/{index-gps0zk0m.js → index-5fmgn0nx.js} +2 -2
- package/dist/cli/{index-dfqzrznk.js → index-6mbm4n3g.js} +2 -2
- package/dist/cli/{index-0zcebhm4.js → index-dr21p6ae.js} +566 -83
- package/dist/cli/{index-df2mjbdy.js → index-exdd5k1g.js} +55 -0
- package/dist/cli/index.js +6 -6
- package/dist/cli/{mobile-d5wbqynh.js → mobile-55wjg3nd.js} +677 -185
- package/dist/cli/{start-8v6g2y31.js → start-jt61f40d.js} +4 -4
- package/dist/index.js +54 -2
- package/dist/index.js.map +3 -3
- package/dist/mobile/index.js +1683 -913
- package/dist/mobile/index.js.map +8 -6
- package/dist/mobile/remoteMacAgentEntry.js +243 -242
- package/dist/src/mobile/branding.d.ts +92 -0
- package/dist/src/mobile/ciPromotionLedger.d.ts +49 -0
- package/dist/src/mobile/config.d.ts +20 -0
- package/dist/src/mobile/index.d.ts +2 -0
- package/dist/types/build.d.ts +36 -0
- package/package.json +1 -1
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
} from "./index-zh6hhrwy.js";
|
|
8
8
|
import {
|
|
9
9
|
start
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-5fmgn0nx.js";
|
|
11
11
|
import {
|
|
12
12
|
ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT,
|
|
13
13
|
ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
|
|
14
14
|
resolveAbsoluteMobileRoute
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-6mbm4n3g.js";
|
|
16
16
|
import"./index-bzs19w3r.js";
|
|
17
17
|
import"./index-s2tazax7.js";
|
|
18
18
|
import {
|
|
@@ -56,21 +56,25 @@ import {
|
|
|
56
56
|
import"./index-w5vswatm.js";
|
|
57
57
|
import {
|
|
58
58
|
normalizeAbsoluteMobileConfig
|
|
59
|
-
} from "./index-
|
|
59
|
+
} from "./index-exdd5k1g.js";
|
|
60
60
|
import {
|
|
61
|
+
ABSOLUTE_CAPACITOR_ASSETS_SPEC,
|
|
61
62
|
ABSOLUTE_MOBILE_UPDATE_FORMAT,
|
|
62
63
|
absoluteDeviceNativeRequirements,
|
|
63
64
|
absoluteMobileUpdateSigningPayload,
|
|
64
65
|
assertAbsoluteDeviceCapabilityPackages,
|
|
65
66
|
canonicalizeAbsoluteMobileUpdate,
|
|
66
67
|
discoverAbsoluteSyncSchema,
|
|
68
|
+
generateAbsoluteCapacitorBranding,
|
|
69
|
+
inspectAbsoluteMobileBranding,
|
|
67
70
|
parseAbsoluteMobileUpdateManifest,
|
|
71
|
+
renderAbsoluteMobileBrandingPreview,
|
|
68
72
|
resolveAbsoluteDeviceCapabilityPlan,
|
|
69
73
|
resolveAbsoluteMobileUpdateRuntime,
|
|
70
74
|
syncAbsoluteExpoWebAssets,
|
|
71
75
|
unsignedAbsoluteMobileUpdate,
|
|
72
76
|
writeAbsoluteExpoProject
|
|
73
|
-
} from "./index-
|
|
77
|
+
} from "./index-dr21p6ae.js";
|
|
74
78
|
import {
|
|
75
79
|
buildAbsoluteExpoAndroidWslBundle
|
|
76
80
|
} from "./index-28nxv57v.js";
|
|
@@ -16283,9 +16287,9 @@ var require_pkcs7 = __commonJS(function(exports, module) {
|
|
|
16283
16287
|
var jan_1_2050 = new Date("2050-01-01T00:00:00Z");
|
|
16284
16288
|
var date = attr.value;
|
|
16285
16289
|
if (typeof date === "string") {
|
|
16286
|
-
var
|
|
16287
|
-
if (!isNaN(
|
|
16288
|
-
date = new Date(
|
|
16290
|
+
var timestamp2 = Date.parse(date);
|
|
16291
|
+
if (!isNaN(timestamp2)) {
|
|
16292
|
+
date = new Date(timestamp2);
|
|
16289
16293
|
} else if (date.length === 13) {
|
|
16290
16294
|
date = asn1.utcTimeToDate(date);
|
|
16291
16295
|
} else {
|
|
@@ -16779,15 +16783,15 @@ var require_main = __commonJS(function(exports) {
|
|
|
16779
16783
|
|
|
16780
16784
|
// src/cli/scripts/mobile.ts
|
|
16781
16785
|
import {
|
|
16782
|
-
access as
|
|
16783
|
-
mkdir as
|
|
16786
|
+
access as access18,
|
|
16787
|
+
mkdir as mkdir19,
|
|
16784
16788
|
mkdtemp as mkdtemp7,
|
|
16785
|
-
readFile as
|
|
16786
|
-
rm as
|
|
16789
|
+
readFile as readFile23,
|
|
16790
|
+
rm as rm11,
|
|
16787
16791
|
writeFile as writeFile19
|
|
16788
16792
|
} from "fs/promises";
|
|
16789
|
-
import { createPublicKey as createPublicKey2, randomUUID } from "crypto";
|
|
16790
|
-
import { join as
|
|
16793
|
+
import { createHash as createHash7, createPublicKey as createPublicKey2, randomUUID as randomUUID2 } from "crypto";
|
|
16794
|
+
import { join as join19, relative as relative17, resolve as resolve18 } from "path";
|
|
16791
16795
|
import { createInterface } from "readline/promises";
|
|
16792
16796
|
|
|
16793
16797
|
// src/mobile/nativeDeepLinks.ts
|
|
@@ -19779,6 +19783,14 @@ var mobileUpdateServerCheck = async (config, projectRoot) => {
|
|
|
19779
19783
|
return fail("updates.trusted-server", error instanceof Error ? error.message : "The trusted mobile update server is not release-ready.", config.updateServer?.registryModule ?? "mobile.update.ts", "Run `absolute mobile update provision --storage s3 --force`, provision its environment variables on the trusted server, and rerun the release doctor.");
|
|
19780
19784
|
}
|
|
19781
19785
|
};
|
|
19786
|
+
var mobileBrandingCheck = async (config, projectRoot) => {
|
|
19787
|
+
const inspection = await inspectAbsoluteMobileBranding(config, projectRoot);
|
|
19788
|
+
if (inspection.status === "absent")
|
|
19789
|
+
return warn("mobile.branding", inspection.detail, undefined, "Configure mobile.branding and run `absolute mobile assets` before store submission.");
|
|
19790
|
+
if (!inspection.ready)
|
|
19791
|
+
return fail("mobile.branding", inspection.detail, inspection.manifestPath, "Run `absolute mobile assets`, review the generated preview, and commit the native resource changes.");
|
|
19792
|
+
return pass("mobile.branding", inspection.detail, inspection.manifestPath);
|
|
19793
|
+
};
|
|
19782
19794
|
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19783
19795
|
var readJsonObject = async (path) => {
|
|
19784
19796
|
const value = JSON.parse(await readFile9(path, "utf8"));
|
|
@@ -20538,6 +20550,7 @@ var inspectAbsoluteMobileRelease = async (config, projectRoot) => {
|
|
|
20538
20550
|
Promise.resolve(associationIdentityCheck(config, projectRoot)),
|
|
20539
20551
|
dependencyLockCheck(projectRoot),
|
|
20540
20552
|
config.engine === "expo" ? expoVersionCheck(config) : capacitorVersionCheck(config, projectRoot),
|
|
20553
|
+
mobileBrandingCheck(config, projectRoot),
|
|
20541
20554
|
mobileUpdateServerCheck(config, projectRoot)
|
|
20542
20555
|
]);
|
|
20543
20556
|
const checks = globalChecks.filter((check) => check !== undefined).map((check) => ({
|
|
@@ -24279,47 +24292,266 @@ var auditAbsoluteMobileCiPromotion = async (options) => {
|
|
|
24279
24292
|
}
|
|
24280
24293
|
};
|
|
24281
24294
|
|
|
24295
|
+
// src/mobile/ciPromotionLedger.ts
|
|
24296
|
+
import {
|
|
24297
|
+
access as access14,
|
|
24298
|
+
link,
|
|
24299
|
+
lstat,
|
|
24300
|
+
mkdir as mkdir15,
|
|
24301
|
+
open,
|
|
24302
|
+
readFile as readFile20,
|
|
24303
|
+
readdir as readdir7,
|
|
24304
|
+
rename as rename12,
|
|
24305
|
+
rm as rm9
|
|
24306
|
+
} from "fs/promises";
|
|
24307
|
+
import { dirname as dirname13, isAbsolute as isAbsolute9, join as join16, relative as relative13, resolve as resolve14, sep as sep10 } from "path";
|
|
24308
|
+
import { randomUUID } from "crypto";
|
|
24309
|
+
var ABSOLUTE_MOBILE_CI_PROMOTION_OPERATION_FORMAT = 1;
|
|
24310
|
+
var MAX_OPERATION_BYTES = 65536;
|
|
24311
|
+
var MAX_OPERATIONS = 1000;
|
|
24312
|
+
var DISPATCH_ID_PATTERN2 = /^amp_[a-f0-9]{32}$/u;
|
|
24313
|
+
var RUN_ID_PATTERN2 = /^[1-9][0-9]*$/u;
|
|
24314
|
+
var SHA256_PATTERN2 = /^[a-f0-9]{64}$/u;
|
|
24315
|
+
var CERTIFICATION_ID_PATTERN = /^amobile_cert_[a-f0-9]{64}$/u;
|
|
24316
|
+
var RELEASE_ID_PATTERN = /^amobile_(?:android|ios)_[a-f0-9]{64}$/u;
|
|
24317
|
+
var REPOSITORY_PATTERN3 = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u;
|
|
24318
|
+
var LAST_ASCII_CONTROL = 31;
|
|
24319
|
+
var DELETE_CHARACTER = 127;
|
|
24320
|
+
var PHASES = [
|
|
24321
|
+
"dispatching",
|
|
24322
|
+
"dispatched",
|
|
24323
|
+
"discovered",
|
|
24324
|
+
"completed",
|
|
24325
|
+
"audited"
|
|
24326
|
+
];
|
|
24327
|
+
var isRecord10 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24328
|
+
var requiredString2 = (value, label, max = 512) => {
|
|
24329
|
+
const hasControlCharacter = typeof value === "string" && Array.from(value).some((character) => {
|
|
24330
|
+
const code = character.codePointAt(0);
|
|
24331
|
+
return code !== undefined && (code <= LAST_ASCII_CONTROL || code === DELETE_CHARACTER);
|
|
24332
|
+
});
|
|
24333
|
+
if (typeof value !== "string" || value.trim() === "" || value !== value.trim() || value.length > max || hasControlCharacter)
|
|
24334
|
+
throw new TypeError(`${label} is invalid.`);
|
|
24335
|
+
return value;
|
|
24336
|
+
};
|
|
24337
|
+
var optionalString2 = (value, label, max = 512) => {
|
|
24338
|
+
if (value === null)
|
|
24339
|
+
return null;
|
|
24340
|
+
return requiredString2(value, label, max);
|
|
24341
|
+
};
|
|
24342
|
+
var boolean = (value, label) => {
|
|
24343
|
+
if (typeof value !== "boolean")
|
|
24344
|
+
throw new TypeError(`${label} is invalid.`);
|
|
24345
|
+
return value;
|
|
24346
|
+
};
|
|
24347
|
+
var timestamp = (value, label) => {
|
|
24348
|
+
const parsed = requiredString2(value, label, 64);
|
|
24349
|
+
if (!Number.isFinite(Date.parse(parsed)))
|
|
24350
|
+
throw new TypeError(`${label} is invalid.`);
|
|
24351
|
+
return parsed;
|
|
24352
|
+
};
|
|
24353
|
+
var projectRelativePath = (value, label) => {
|
|
24354
|
+
const parsed = requiredString2(value, label, 512);
|
|
24355
|
+
if (isAbsolute9(parsed) || parsed === ".." || parsed.startsWith(`..${sep10}`) || parsed.split(/[\\/]/u).includes(".."))
|
|
24356
|
+
throw new TypeError(`${label} must be project-relative.`);
|
|
24357
|
+
return parsed.replaceAll("\\", "/");
|
|
24358
|
+
};
|
|
24359
|
+
var nullableProjectRelativePath = (value, label) => value === null ? null : projectRelativePath(value, label);
|
|
24360
|
+
var dispatchId2 = (value) => {
|
|
24361
|
+
const parsed = requiredString2(value, "Promotion dispatch ID", 36);
|
|
24362
|
+
if (!DISPATCH_ID_PATTERN2.test(parsed))
|
|
24363
|
+
throw new TypeError("Promotion dispatch ID is invalid.");
|
|
24364
|
+
return parsed;
|
|
24365
|
+
};
|
|
24366
|
+
var runId2 = (value, label) => {
|
|
24367
|
+
const parsed = requiredString2(value, label, 32);
|
|
24368
|
+
if (!RUN_ID_PATTERN2.test(parsed))
|
|
24369
|
+
throw new TypeError(`${label} is invalid.`);
|
|
24370
|
+
return parsed;
|
|
24371
|
+
};
|
|
24372
|
+
var nullableRunId = (value, label) => value === null ? null : runId2(value, label);
|
|
24373
|
+
var operationRoot = (projectRoot) => join16(resolve14(projectRoot), ".absolutejs", "mobile-ci", "promotions");
|
|
24374
|
+
var absoluteMobilePromotionOperationPath = (projectRoot, requestedDispatchId) => join16(operationRoot(projectRoot), dispatchId2(requestedDispatchId), "operation.json");
|
|
24375
|
+
var operationPhase = (value) => {
|
|
24376
|
+
const phase = PHASES.find((candidate) => candidate === value);
|
|
24377
|
+
if (!phase)
|
|
24378
|
+
throw new TypeError("Mobile promotion operation phase is invalid.");
|
|
24379
|
+
return phase;
|
|
24380
|
+
};
|
|
24381
|
+
var parseAbsoluteMobilePromotionOperation = (value) => {
|
|
24382
|
+
if (!isRecord10(value) || value.format !== ABSOLUTE_MOBILE_CI_PROMOTION_OPERATION_FORMAT || value.platform !== "android" && value.platform !== "ios")
|
|
24383
|
+
throw new TypeError("Mobile promotion operation is invalid.");
|
|
24384
|
+
const parsed = {
|
|
24385
|
+
auditDirectory: nullableProjectRelativePath(value.auditDirectory, "Promotion audit directory"),
|
|
24386
|
+
auditOutputDirectory: nullableProjectRelativePath(value.auditOutputDirectory, "Promotion requested audit directory"),
|
|
24387
|
+
auditRequested: boolean(value.auditRequested, "Promotion audit request"),
|
|
24388
|
+
certificationId: requiredString2(value.certificationId, "Promotion certification ID", 256),
|
|
24389
|
+
certificationSha256: requiredString2(value.certificationSha256, "Promotion certification digest", 64),
|
|
24390
|
+
channel: optionalString2(value.channel, "Promotion channel", 128),
|
|
24391
|
+
conclusion: optionalString2(value.conclusion, "Promotion conclusion", 64),
|
|
24392
|
+
createdAt: timestamp(value.createdAt, "Promotion creation time"),
|
|
24393
|
+
dispatchId: dispatchId2(value.dispatchId),
|
|
24394
|
+
format: ABSOLUTE_MOBILE_CI_PROMOTION_OPERATION_FORMAT,
|
|
24395
|
+
githubStatus: optionalString2(value.githubStatus, "Promotion GitHub status", 64),
|
|
24396
|
+
phase: operationPhase(value.phase),
|
|
24397
|
+
platform: value.platform,
|
|
24398
|
+
playTrack: optionalString2(value.playTrack, "Promotion Play track", 128),
|
|
24399
|
+
ref: optionalString2(value.ref, "Promotion ref", 256),
|
|
24400
|
+
releaseId: requiredString2(value.releaseId, "Promotion release ID", 256),
|
|
24401
|
+
repository: optionalString2(value.repository, "Promotion repository", 256),
|
|
24402
|
+
runId: nullableRunId(value.runId, "Promotion run ID"),
|
|
24403
|
+
sourceRunId: runId2(value.sourceRunId, "Promotion source run ID"),
|
|
24404
|
+
testflightGroup: optionalString2(value.testflightGroup, "Promotion TestFlight group", 128),
|
|
24405
|
+
testflightSubmitReview: boolean(value.testflightSubmitReview, "Promotion TestFlight review setting"),
|
|
24406
|
+
updatedAt: timestamp(value.updatedAt, "Promotion update time"),
|
|
24407
|
+
url: optionalString2(value.url, "Promotion run URL", 1024),
|
|
24408
|
+
watchRequested: boolean(value.watchRequested, "Promotion watch request"),
|
|
24409
|
+
workflow: projectRelativePath(value.workflow, "Promotion workflow")
|
|
24410
|
+
};
|
|
24411
|
+
if (!SHA256_PATTERN2.test(parsed.certificationSha256))
|
|
24412
|
+
throw new TypeError("Promotion certification digest is invalid.");
|
|
24413
|
+
if (!CERTIFICATION_ID_PATTERN.test(parsed.certificationId))
|
|
24414
|
+
throw new TypeError("Promotion certification ID is invalid.");
|
|
24415
|
+
if (!RELEASE_ID_PATTERN.test(parsed.releaseId))
|
|
24416
|
+
throw new TypeError("Promotion release ID is invalid.");
|
|
24417
|
+
if (parsed.repository !== null && !REPOSITORY_PATTERN3.test(parsed.repository))
|
|
24418
|
+
throw new TypeError("Promotion repository is invalid.");
|
|
24419
|
+
const discovered = PHASES.indexOf(parsed.phase) >= PHASES.indexOf("discovered");
|
|
24420
|
+
const completed = PHASES.indexOf(parsed.phase) >= PHASES.indexOf("completed");
|
|
24421
|
+
if (discovered && (!parsed.runId || !parsed.url) || !discovered && (parsed.runId || parsed.url) || completed && (parsed.githubStatus !== "completed" || !parsed.conclusion) || !completed && (parsed.githubStatus || parsed.conclusion) || parsed.phase === "audited" && !parsed.auditDirectory || parsed.phase !== "audited" && parsed.auditDirectory)
|
|
24422
|
+
throw new TypeError("Mobile promotion operation phase is incomplete.");
|
|
24423
|
+
if (parsed.url && parsed.runId) {
|
|
24424
|
+
const url = new URL(parsed.url);
|
|
24425
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "" || !url.pathname.endsWith(`/actions/runs/${parsed.runId}`))
|
|
24426
|
+
throw new TypeError("Promotion run URL is invalid.");
|
|
24427
|
+
}
|
|
24428
|
+
if (Date.parse(parsed.updatedAt) < Date.parse(parsed.createdAt))
|
|
24429
|
+
throw new TypeError("Promotion operation time moved backwards.");
|
|
24430
|
+
return parsed;
|
|
24431
|
+
};
|
|
24432
|
+
var serialize = (operation) => `${JSON.stringify(parseAbsoluteMobilePromotionOperation(operation), null, 2)}
|
|
24433
|
+
`;
|
|
24434
|
+
var writeSynced = async (path, source) => {
|
|
24435
|
+
const handle = await open(path, "wx", 384);
|
|
24436
|
+
try {
|
|
24437
|
+
await handle.writeFile(source);
|
|
24438
|
+
await handle.sync();
|
|
24439
|
+
} finally {
|
|
24440
|
+
await handle.close();
|
|
24441
|
+
}
|
|
24442
|
+
};
|
|
24443
|
+
var atomicWrite = async (path, source, exclusive) => {
|
|
24444
|
+
await mkdir15(dirname13(path), { recursive: true });
|
|
24445
|
+
const temporary = join16(dirname13(path), `.operation-${randomUUID()}.tmp`);
|
|
24446
|
+
try {
|
|
24447
|
+
await writeSynced(temporary, source);
|
|
24448
|
+
if (exclusive)
|
|
24449
|
+
await link(temporary, path);
|
|
24450
|
+
else
|
|
24451
|
+
await rename12(temporary, path);
|
|
24452
|
+
} finally {
|
|
24453
|
+
await rm9(temporary, { force: true });
|
|
24454
|
+
}
|
|
24455
|
+
};
|
|
24456
|
+
var advanceAbsoluteMobilePromotionOperation = async (projectRoot, requestedDispatchId, options, now = () => new Date) => {
|
|
24457
|
+
const current = await readAbsoluteMobilePromotionOperation(projectRoot, requestedDispatchId);
|
|
24458
|
+
if (PHASES.indexOf(options.phase) < PHASES.indexOf(current.phase))
|
|
24459
|
+
throw new TypeError("Mobile promotion operation cannot move backwards.");
|
|
24460
|
+
if (current.runId && options.runId && current.runId !== options.runId || current.url && options.url && current.url !== options.url || current.auditDirectory && options.auditDirectory && current.auditDirectory !== options.auditDirectory)
|
|
24461
|
+
throw new TypeError("Mobile promotion operation identity is immutable.");
|
|
24462
|
+
const next = parseAbsoluteMobilePromotionOperation({
|
|
24463
|
+
...current,
|
|
24464
|
+
auditDirectory: options.auditDirectory === undefined ? current.auditDirectory : options.auditDirectory,
|
|
24465
|
+
conclusion: options.conclusion === undefined ? current.conclusion : options.conclusion,
|
|
24466
|
+
githubStatus: options.githubStatus === undefined ? current.githubStatus : options.githubStatus,
|
|
24467
|
+
phase: options.phase,
|
|
24468
|
+
runId: options.runId === undefined ? current.runId : options.runId,
|
|
24469
|
+
updatedAt: now().toISOString(),
|
|
24470
|
+
url: options.url === undefined ? current.url : options.url
|
|
24471
|
+
});
|
|
24472
|
+
await atomicWrite(absoluteMobilePromotionOperationPath(projectRoot, requestedDispatchId), serialize(next), false);
|
|
24473
|
+
return next;
|
|
24474
|
+
};
|
|
24475
|
+
var createAbsoluteMobilePromotionOperation = async (projectRoot, options) => {
|
|
24476
|
+
const now = (options.now ?? (() => new Date))().toISOString();
|
|
24477
|
+
const operation = parseAbsoluteMobilePromotionOperation({
|
|
24478
|
+
...options,
|
|
24479
|
+
auditDirectory: null,
|
|
24480
|
+
conclusion: null,
|
|
24481
|
+
createdAt: now,
|
|
24482
|
+
format: ABSOLUTE_MOBILE_CI_PROMOTION_OPERATION_FORMAT,
|
|
24483
|
+
githubStatus: null,
|
|
24484
|
+
phase: "dispatching",
|
|
24485
|
+
runId: null,
|
|
24486
|
+
updatedAt: now,
|
|
24487
|
+
url: null
|
|
24488
|
+
});
|
|
24489
|
+
await atomicWrite(absoluteMobilePromotionOperationPath(projectRoot, operation.dispatchId), serialize(operation), true);
|
|
24490
|
+
return operation;
|
|
24491
|
+
};
|
|
24492
|
+
var listAbsoluteMobilePromotionOperations = async (projectRoot) => {
|
|
24493
|
+
const root = operationRoot(projectRoot);
|
|
24494
|
+
if (!await access14(root).then(() => true).catch(() => false))
|
|
24495
|
+
return [];
|
|
24496
|
+
const entries = await readdir7(root, { withFileTypes: true });
|
|
24497
|
+
if (entries.length > MAX_OPERATIONS)
|
|
24498
|
+
throw new TypeError("Mobile promotion operation count exceeds the limit.");
|
|
24499
|
+
const operations = await Promise.all(entries.filter((entry) => entry.isDirectory() && DISPATCH_ID_PATTERN2.test(entry.name)).map((entry) => readAbsoluteMobilePromotionOperation(projectRoot, entry.name)));
|
|
24500
|
+
return operations.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
24501
|
+
};
|
|
24502
|
+
var readAbsoluteMobilePromotionOperation = async (projectRoot, requestedDispatchId) => {
|
|
24503
|
+
const path = absoluteMobilePromotionOperationPath(projectRoot, requestedDispatchId);
|
|
24504
|
+
const metadata = await lstat(path).catch(() => null);
|
|
24505
|
+
if (!metadata?.isFile() || metadata.size > MAX_OPERATION_BYTES)
|
|
24506
|
+
throw new TypeError(`Mobile promotion operation ${requestedDispatchId} was not found or is invalid.`);
|
|
24507
|
+
const operation = parseAbsoluteMobilePromotionOperation(JSON.parse(await readFile20(path, "utf8")));
|
|
24508
|
+
if (operation.dispatchId !== requestedDispatchId)
|
|
24509
|
+
throw new TypeError("Mobile promotion operation identity does not match.");
|
|
24510
|
+
return operation;
|
|
24511
|
+
};
|
|
24512
|
+
var relativeAbsoluteMobilePromotionOperationPath = (projectRoot, dispatchIdValue) => relative13(resolve14(projectRoot), absoluteMobilePromotionOperationPath(projectRoot, dispatchIdValue)).replaceAll("\\", "/");
|
|
24513
|
+
|
|
24282
24514
|
// src/mobile/updateSigning.ts
|
|
24283
24515
|
import { createHash as createHash6, sign, verify } from "crypto";
|
|
24284
24516
|
import {
|
|
24285
24517
|
cp,
|
|
24286
|
-
mkdir as
|
|
24518
|
+
mkdir as mkdir16,
|
|
24287
24519
|
mkdtemp as mkdtemp6,
|
|
24288
|
-
readdir as
|
|
24289
|
-
readFile as
|
|
24290
|
-
rename as
|
|
24291
|
-
rm as
|
|
24520
|
+
readdir as readdir8,
|
|
24521
|
+
readFile as readFile21,
|
|
24522
|
+
rename as rename13,
|
|
24523
|
+
rm as rm10,
|
|
24292
24524
|
stat as stat8,
|
|
24293
24525
|
writeFile as writeFile16
|
|
24294
24526
|
} from "fs/promises";
|
|
24295
|
-
import { dirname as
|
|
24527
|
+
import { dirname as dirname14, join as join17, relative as relative14, resolve as resolve15 } from "path";
|
|
24296
24528
|
var UPDATE_MANIFEST_FILE = "update.json";
|
|
24297
24529
|
var UPDATE_FILES_DIRECTORY = "files";
|
|
24298
24530
|
var sha2564 = (value) => createHash6("sha256").update(value).digest("hex");
|
|
24299
24531
|
var listFiles = async (root, directory = root) => {
|
|
24300
|
-
const entries = await
|
|
24532
|
+
const entries = await readdir8(directory, { withFileTypes: true });
|
|
24301
24533
|
const paths = await Promise.all(entries.map(async (entry) => {
|
|
24302
|
-
const path =
|
|
24534
|
+
const path = join17(directory, entry.name);
|
|
24303
24535
|
if (entry.isDirectory())
|
|
24304
24536
|
return listFiles(root, path);
|
|
24305
24537
|
if (!entry.isFile())
|
|
24306
24538
|
throw new TypeError("Mobile updates cannot contain links or special files.");
|
|
24307
|
-
return [
|
|
24539
|
+
return [relative14(root, path).replaceAll("\\", "/")];
|
|
24308
24540
|
}));
|
|
24309
24541
|
return paths.flat().sort((left, right) => left.localeCompare(right));
|
|
24310
24542
|
};
|
|
24311
24543
|
var inspectFiles = async (root, paths) => Promise.all(paths.map(async (path) => {
|
|
24312
|
-
const source =
|
|
24544
|
+
const source = join17(root, path);
|
|
24313
24545
|
const [metadata, contents] = await Promise.all([
|
|
24314
24546
|
stat8(source),
|
|
24315
|
-
|
|
24547
|
+
readFile21(source)
|
|
24316
24548
|
]);
|
|
24317
24549
|
return { bytes: metadata.size, path, sha256: sha2564(contents) };
|
|
24318
24550
|
}));
|
|
24319
24551
|
var releaseIdFor = (value) => `amu_${sha2564(canonicalizeAbsoluteMobileUpdate(value))}`;
|
|
24320
24552
|
var buildAbsoluteMobileUpdate = async (options) => {
|
|
24321
|
-
const bundleDirectory =
|
|
24322
|
-
const outputRoot =
|
|
24553
|
+
const bundleDirectory = resolve15(options.bundleDirectory);
|
|
24554
|
+
const outputRoot = resolve15(options.outputDirectory);
|
|
24323
24555
|
if (outputRoot === bundleDirectory || outputRoot.startsWith(`${bundleDirectory}/`))
|
|
24324
24556
|
throw new TypeError("Mobile update output must be outside the embedded bundle.");
|
|
24325
24557
|
const paths = await listFiles(bundleDirectory);
|
|
@@ -24347,30 +24579,30 @@ var buildAbsoluteMobileUpdate = async (options) => {
|
|
|
24347
24579
|
value: signature.toString("base64")
|
|
24348
24580
|
}
|
|
24349
24581
|
});
|
|
24350
|
-
await
|
|
24351
|
-
const outputDirectory =
|
|
24352
|
-
const staging = await mkdtemp6(
|
|
24582
|
+
await mkdir16(outputRoot, { recursive: true });
|
|
24583
|
+
const outputDirectory = join17(outputRoot, manifest.releaseId);
|
|
24584
|
+
const staging = await mkdtemp6(join17(outputRoot, ".stage-"));
|
|
24353
24585
|
try {
|
|
24354
|
-
await cp(bundleDirectory,
|
|
24586
|
+
await cp(bundleDirectory, join17(staging, UPDATE_FILES_DIRECTORY), {
|
|
24355
24587
|
force: true,
|
|
24356
24588
|
recursive: true
|
|
24357
24589
|
});
|
|
24358
|
-
await writeFile16(
|
|
24590
|
+
await writeFile16(join17(staging, UPDATE_MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
24359
24591
|
`);
|
|
24360
|
-
await
|
|
24592
|
+
await rename13(staging, outputDirectory);
|
|
24361
24593
|
} catch (error) {
|
|
24362
|
-
await
|
|
24594
|
+
await rm10(staging, { force: true, recursive: true });
|
|
24363
24595
|
if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "EEXIST")
|
|
24364
24596
|
throw new TypeError(`Mobile update ${manifest.releaseId} already exists.`, { cause: error });
|
|
24365
24597
|
throw error;
|
|
24366
24598
|
}
|
|
24367
24599
|
return {
|
|
24368
24600
|
manifest,
|
|
24369
|
-
manifestPath:
|
|
24601
|
+
manifestPath: join17(outputDirectory, UPDATE_MANIFEST_FILE),
|
|
24370
24602
|
outputDirectory
|
|
24371
24603
|
};
|
|
24372
24604
|
};
|
|
24373
|
-
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await
|
|
24605
|
+
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile21(join17(resolve15(directory), UPDATE_MANIFEST_FILE), "utf8")));
|
|
24374
24606
|
var verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
|
|
24375
24607
|
const manifest = parseAbsoluteMobileUpdateManifest(manifestValue);
|
|
24376
24608
|
const valid = verify("sha256", absoluteMobileUpdateSigningPayload(unsignedAbsoluteMobileUpdate(manifest)), { dsaEncoding: "ieee-p1363", key: publicKey }, Buffer.from(manifest.signature.value, "base64"));
|
|
@@ -24380,8 +24612,8 @@ var verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
|
|
|
24380
24612
|
};
|
|
24381
24613
|
|
|
24382
24614
|
// src/mobile/expoUpdate.ts
|
|
24383
|
-
import { access as
|
|
24384
|
-
import { dirname as
|
|
24615
|
+
import { access as access15, mkdir as mkdir17, readFile as readFile22, writeFile as writeFile17 } from "fs/promises";
|
|
24616
|
+
import { dirname as dirname15, extname as extname3, join as join18 } from "path";
|
|
24385
24617
|
var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json";
|
|
24386
24618
|
var ABSOLUTE_EXPO_UPDATE_FORMAT = 1;
|
|
24387
24619
|
var object2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -24447,7 +24679,7 @@ var parseAbsoluteExpoUpdateDescriptor = (value) => {
|
|
|
24447
24679
|
};
|
|
24448
24680
|
};
|
|
24449
24681
|
var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
24450
|
-
const metadata = JSON.parse(await
|
|
24682
|
+
const metadata = JSON.parse(await readFile22(join18(options.exportDirectory, "metadata.json"), "utf8"));
|
|
24451
24683
|
if (!object2(metadata) || !object2(metadata.fileMetadata))
|
|
24452
24684
|
throw new TypeError("Expo export metadata.json is invalid.");
|
|
24453
24685
|
const descriptor = parseAbsoluteExpoUpdateDescriptor({
|
|
@@ -24458,11 +24690,11 @@ var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
|
24458
24690
|
runtimeVersion: options.runtimeVersion
|
|
24459
24691
|
});
|
|
24460
24692
|
const referenced = Object.values(descriptor.platforms).flatMap((entry) => entry ? [entry.launchAsset, ...entry.assets] : []);
|
|
24461
|
-
await Promise.all(referenced.map(({ path }) =>
|
|
24693
|
+
await Promise.all(referenced.map(({ path }) => access15(join18(options.exportDirectory, path)).catch(() => {
|
|
24462
24694
|
throw new TypeError(`Expo export metadata references missing asset ${path}.`);
|
|
24463
24695
|
})));
|
|
24464
|
-
const destination =
|
|
24465
|
-
await
|
|
24696
|
+
const destination = join18(options.exportDirectory, ABSOLUTE_EXPO_UPDATE_DESCRIPTOR);
|
|
24697
|
+
await mkdir17(dirname15(destination), { recursive: true });
|
|
24466
24698
|
await writeFile17(destination, `${JSON.stringify(descriptor, null, "\t")}
|
|
24467
24699
|
`);
|
|
24468
24700
|
return { descriptor, path: destination };
|
|
@@ -24470,18 +24702,18 @@ var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
|
24470
24702
|
|
|
24471
24703
|
// src/mobile/expoCodeSigning.ts
|
|
24472
24704
|
var import_code_signing_certificates = __toESM(require_main(), 1);
|
|
24473
|
-
import { access as
|
|
24474
|
-
import { dirname as
|
|
24475
|
-
var exists6 = async (path) =>
|
|
24705
|
+
import { access as access16, mkdir as mkdir18, writeFile as writeFile18 } from "fs/promises";
|
|
24706
|
+
import { dirname as dirname16, isAbsolute as isAbsolute10, relative as relative15, resolve as resolve16, sep as sep11 } from "path";
|
|
24707
|
+
var exists6 = async (path) => access16(path).then(() => true).catch(() => false);
|
|
24476
24708
|
var inside4 = (root, path) => {
|
|
24477
|
-
const location =
|
|
24478
|
-
return location === "" || location !== ".." && !location.startsWith(`..${
|
|
24709
|
+
const location = relative15(root, path);
|
|
24710
|
+
return location === "" || location !== ".." && !location.startsWith(`..${sep11}`) && !isAbsolute10(location);
|
|
24479
24711
|
};
|
|
24480
24712
|
var generateAbsoluteExpoCodeSigning = async (options) => {
|
|
24481
|
-
const root =
|
|
24482
|
-
const certificatePath =
|
|
24483
|
-
const privateKeyPath =
|
|
24484
|
-
const publicKeyPath =
|
|
24713
|
+
const root = resolve16(options.projectRoot);
|
|
24714
|
+
const certificatePath = resolve16(root, options.certificatePath);
|
|
24715
|
+
const privateKeyPath = resolve16(root, options.privateKeyPath);
|
|
24716
|
+
const publicKeyPath = resolve16(root, options.publicKeyPath ?? resolve16(dirname16(privateKeyPath), "public-key.pem"));
|
|
24485
24717
|
if (!inside4(root, certificatePath))
|
|
24486
24718
|
throw new TypeError("Expo code-signing certificate must be written inside the project so store builds can embed it.");
|
|
24487
24719
|
if (inside4(root, privateKeyPath) || inside4(root, publicKeyPath))
|
|
@@ -24511,7 +24743,7 @@ var generateAbsoluteExpoCodeSigning = async (options) => {
|
|
|
24511
24743
|
import_code_signing_certificates.validateSelfSignedCertificate(certificate, keyPair);
|
|
24512
24744
|
const { privateKeyPEM, publicKeyPEM } = import_code_signing_certificates.convertKeyPairToPEM(keyPair);
|
|
24513
24745
|
const certificatePem = import_code_signing_certificates.convertCertificateToCertificatePEM(certificate);
|
|
24514
|
-
await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) =>
|
|
24746
|
+
await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) => mkdir18(dirname16(path), { recursive: true })));
|
|
24515
24747
|
await Promise.all([
|
|
24516
24748
|
writeFile18(certificatePath, certificatePem, { flag: "wx", mode: 420 }),
|
|
24517
24749
|
writeFile18(privateKeyPath, privateKeyPEM, { flag: "wx", mode: 384 }),
|
|
@@ -24526,8 +24758,8 @@ var generateAbsoluteExpoCodeSigning = async (options) => {
|
|
|
24526
24758
|
};
|
|
24527
24759
|
|
|
24528
24760
|
// src/mobile/updatePublisher.ts
|
|
24529
|
-
import { access as
|
|
24530
|
-
import { isAbsolute as
|
|
24761
|
+
import { access as access17 } from "fs/promises";
|
|
24762
|
+
import { isAbsolute as isAbsolute11, relative as relative16, resolve as resolve17, sep as sep12 } from "path";
|
|
24531
24763
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
24532
24764
|
var lifecycleMethod = (publisher, name) => {
|
|
24533
24765
|
const method = publisher[name];
|
|
@@ -24636,16 +24868,16 @@ var pruneAbsoluteMobileUpdates = async (options) => {
|
|
|
24636
24868
|
var object3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24637
24869
|
var isPublisher2 = (value) => object3(value) && typeof value.publishUpdate === "function" && typeof value.promoteUpdate === "function" && typeof value.rollbackUpdate === "function";
|
|
24638
24870
|
var projectPath4 = (projectRoot, requested, label) => {
|
|
24639
|
-
const root =
|
|
24640
|
-
const path =
|
|
24641
|
-
const projectRelative =
|
|
24642
|
-
if (projectRelative === ".." || projectRelative.startsWith(`..${
|
|
24871
|
+
const root = resolve17(projectRoot);
|
|
24872
|
+
const path = resolve17(root, requested);
|
|
24873
|
+
const projectRelative = relative16(root, path);
|
|
24874
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep12}`) || isAbsolute11(projectRelative))
|
|
24643
24875
|
throw new TypeError(`${label} must remain inside the project.`);
|
|
24644
24876
|
return path;
|
|
24645
24877
|
};
|
|
24646
24878
|
var loadAbsoluteMobileUpdatePublisher = async (projectRoot, requestedModulePath) => {
|
|
24647
24879
|
const modulePath = projectPath4(projectRoot, requestedModulePath, "mobile update registry");
|
|
24648
|
-
await
|
|
24880
|
+
await access17(modulePath).catch(() => {
|
|
24649
24881
|
throw new TypeError(`Mobile update registry does not exist: ${modulePath}`);
|
|
24650
24882
|
});
|
|
24651
24883
|
const loaded = await import(pathToFileURL3(modulePath).href);
|
|
@@ -24700,10 +24932,10 @@ var rollbackAbsoluteMobileUpdate = async (options) => {
|
|
|
24700
24932
|
var NOT_FOUND4 = -1;
|
|
24701
24933
|
var ANDROID_EMULATOR_BOOT_POLL_MS = 500;
|
|
24702
24934
|
var ANDROID_EMULATOR_BOOT_TIMEOUT_MS = 180000;
|
|
24703
|
-
var
|
|
24935
|
+
var isRecord11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24704
24936
|
var expoPublicConfig = (config) => {
|
|
24705
24937
|
const result = { ...config };
|
|
24706
|
-
if (!
|
|
24938
|
+
if (!isRecord11(result.updates))
|
|
24707
24939
|
return result;
|
|
24708
24940
|
const {
|
|
24709
24941
|
codeSigningCertificate: _codeSigningCertificate,
|
|
@@ -24743,13 +24975,13 @@ var CAPACITOR_SYNC_PACKAGE_SPECS = [
|
|
|
24743
24975
|
];
|
|
24744
24976
|
var packageNameFromSpec = (spec) => spec.slice(0, spec.lastIndexOf("@"));
|
|
24745
24977
|
var directProjectPackages = async (projectRoot) => {
|
|
24746
|
-
const manifest = JSON.parse(await
|
|
24747
|
-
if (!
|
|
24978
|
+
const manifest = JSON.parse(await readFile23(join19(projectRoot, "package.json"), "utf8"));
|
|
24979
|
+
if (!isRecord11(manifest))
|
|
24748
24980
|
throw new TypeError("Application package.json must contain an object.");
|
|
24749
24981
|
const names = new Set;
|
|
24750
24982
|
for (const field2 of ["dependencies", "devDependencies"]) {
|
|
24751
24983
|
const dependencies = Reflect.get(manifest, field2);
|
|
24752
|
-
if (
|
|
24984
|
+
if (isRecord11(dependencies))
|
|
24753
24985
|
for (const name of Object.keys(dependencies))
|
|
24754
24986
|
names.add(name);
|
|
24755
24987
|
}
|
|
@@ -24757,20 +24989,20 @@ var directProjectPackages = async (projectRoot) => {
|
|
|
24757
24989
|
};
|
|
24758
24990
|
var resolvedPackageVersion = async (projectRoot, packageName) => {
|
|
24759
24991
|
try {
|
|
24760
|
-
const manifest = JSON.parse(await
|
|
24761
|
-
return
|
|
24992
|
+
const manifest = JSON.parse(await readFile23(join19(projectRoot, "node_modules", packageName, "package.json"), "utf8"));
|
|
24993
|
+
return isRecord11(manifest) && typeof manifest.version === "string" ? manifest.version : undefined;
|
|
24762
24994
|
} catch {
|
|
24763
24995
|
return;
|
|
24764
24996
|
}
|
|
24765
24997
|
};
|
|
24766
24998
|
var exactVersionFromSpec = (spec) => spec.slice(spec.lastIndexOf("@") + 1);
|
|
24767
|
-
var installApprovedPackages = async (projectRoot, args, message, specs) => {
|
|
24999
|
+
var installApprovedPackages = async (projectRoot, args, message, specs, dev = false) => {
|
|
24768
25000
|
if (specs.length === 0)
|
|
24769
25001
|
return;
|
|
24770
25002
|
const approved = args.includes("--yes") || await confirmInstall(message);
|
|
24771
25003
|
if (!approved)
|
|
24772
|
-
throw new TypeError(`Mobile
|
|
24773
|
-
if (!installPackages(projectRoot, specs))
|
|
25004
|
+
throw new TypeError(`Mobile tooling requires: bun add${dev ? " --dev" : ""} ${specs.join(" ")}`);
|
|
25005
|
+
if (!installPackages(projectRoot, specs, dev))
|
|
24774
25006
|
throw new TypeError("Failed to install the AbsoluteJS mobile toolchain.");
|
|
24775
25007
|
};
|
|
24776
25008
|
var packagesNeedingExactInstall = async (projectRoot, specs, installed, exactPackages) => (await Promise.all(specs.map(async (spec) => {
|
|
@@ -24791,6 +25023,11 @@ var ensureCapacitorPackages = async (projectRoot, args, mobile) => {
|
|
|
24791
25023
|
const directCapabilityPackages = await directProjectPackages(projectRoot);
|
|
24792
25024
|
const capabilityPackages = await packagesNeedingExactInstall(projectRoot, capabilityPlan.requiredPackages, directCapabilityPackages, new Set(capabilityPlan.requiredPackages.map(packageNameFromSpec)));
|
|
24793
25025
|
await installApprovedPackages(projectRoot, args, `AbsoluteJS detected native device capabilities (${capabilityPlan.capabilities.join(", ")}). Install only their required Capacitor plugins now?`, capabilityPackages);
|
|
25026
|
+
if (mobile?.branding) {
|
|
25027
|
+
const installedBrandingPackages = await directProjectPackages(projectRoot);
|
|
25028
|
+
const brandingPackages = await packagesNeedingExactInstall(projectRoot, [ABSOLUTE_CAPACITOR_ASSETS_SPEC], installedBrandingPackages, new Set(["@capacitor/assets"]));
|
|
25029
|
+
await installApprovedPackages(projectRoot, args, "AbsoluteJS mobile branding uses the pinned official Capacitor asset generator. Install it as a development dependency now?", brandingPackages, true);
|
|
25030
|
+
}
|
|
24794
25031
|
};
|
|
24795
25032
|
var valueAfter = (args, flag) => {
|
|
24796
25033
|
const index = args.indexOf(flag);
|
|
@@ -24821,9 +25058,9 @@ var runCapacitor = async (projectRoot, args) => {
|
|
|
24821
25058
|
};
|
|
24822
25059
|
var runCapacitorForPlatforms = (projectRoot, command, platforms) => platforms.reduce((pending, platform2) => pending.then(() => runCapacitor(projectRoot, [command, platform2])), Promise.resolve());
|
|
24823
25060
|
var expoExecutable = async (project) => {
|
|
24824
|
-
const executable =
|
|
25061
|
+
const executable = join19(project, "node_modules", ".bin", "expo");
|
|
24825
25062
|
try {
|
|
24826
|
-
await
|
|
25063
|
+
await access18(executable);
|
|
24827
25064
|
return executable;
|
|
24828
25065
|
} catch {
|
|
24829
25066
|
throw new TypeError("Expo dependencies are not installed in the generated shell. Run `absolute mobile init --yes`.");
|
|
@@ -24855,14 +25092,14 @@ var runExpo = async (project, args, options = {}) => {
|
|
|
24855
25092
|
};
|
|
24856
25093
|
var ensureExpoPackages = async (project, args) => {
|
|
24857
25094
|
try {
|
|
24858
|
-
const manifest = JSON.parse(await
|
|
25095
|
+
const manifest = JSON.parse(await readFile23(join19(project, "package.json"), "utf8"));
|
|
24859
25096
|
const dependencies = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "dependencies") : undefined;
|
|
24860
25097
|
if (typeof dependencies !== "object" || dependencies === null || Array.isArray(dependencies))
|
|
24861
25098
|
throw new TypeError("Generated Expo dependencies are invalid.");
|
|
24862
25099
|
await Promise.all(Object.entries(dependencies).map(async ([name, expected]) => {
|
|
24863
25100
|
if (typeof expected !== "string")
|
|
24864
25101
|
throw new TypeError("Generated Expo dependency version is invalid.");
|
|
24865
|
-
const installed = JSON.parse(await
|
|
25102
|
+
const installed = JSON.parse(await readFile23(join19(project, "node_modules", name, "package.json"), "utf8"));
|
|
24866
25103
|
const actual = typeof installed === "object" && installed !== null ? Reflect.get(installed, "version") : undefined;
|
|
24867
25104
|
if (typeof actual !== "string")
|
|
24868
25105
|
throw new TypeError("Installed Expo dependency version is invalid.");
|
|
@@ -25015,6 +25252,8 @@ var initialize = async (args) => {
|
|
|
25015
25252
|
if (args.includes("--no-native"))
|
|
25016
25253
|
return;
|
|
25017
25254
|
await runCapacitorForPlatforms(projectRoot, "add", mobile.platforms);
|
|
25255
|
+
if (mobile.branding)
|
|
25256
|
+
await generateAbsoluteCapacitorBranding(mobile, projectRoot);
|
|
25018
25257
|
await applyAbsoluteNativeDeepLinks(mobile);
|
|
25019
25258
|
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile);
|
|
25020
25259
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile);
|
|
@@ -25051,6 +25290,10 @@ var sync = async (args) => {
|
|
|
25051
25290
|
if (platforms.includes("ios"))
|
|
25052
25291
|
await repairAbsoluteIosDevSession(projectRoot);
|
|
25053
25292
|
await runCapacitorForPlatforms(projectRoot, "sync", platforms);
|
|
25293
|
+
if (mobile.branding)
|
|
25294
|
+
await generateAbsoluteCapacitorBranding(mobile, projectRoot, {
|
|
25295
|
+
platforms
|
|
25296
|
+
});
|
|
25054
25297
|
await applyAbsoluteNativeDeepLinks(mobile, platforms);
|
|
25055
25298
|
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile, platforms);
|
|
25056
25299
|
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, platforms);
|
|
@@ -25058,9 +25301,87 @@ var sync = async (args) => {
|
|
|
25058
25301
|
await applyAbsoluteNativeObservability(mobile, platforms);
|
|
25059
25302
|
await applyAbsoluteNativeReleaseReadiness(mobile, platforms);
|
|
25060
25303
|
};
|
|
25304
|
+
var printMobileBrandingInspection = (inspection, json) => {
|
|
25305
|
+
if (json)
|
|
25306
|
+
console.log(JSON.stringify(inspection, null, 2));
|
|
25307
|
+
else
|
|
25308
|
+
console.log(inspection.detail);
|
|
25309
|
+
};
|
|
25310
|
+
var checkMobileBranding = async (mobile, projectRoot, json) => {
|
|
25311
|
+
const inspection = await inspectAbsoluteMobileBranding(mobile, projectRoot);
|
|
25312
|
+
printMobileBrandingInspection(inspection, json);
|
|
25313
|
+
if (!inspection.ready)
|
|
25314
|
+
throw new TypeError("Mobile branding is not current. Run `absolute mobile assets`.");
|
|
25315
|
+
return inspection;
|
|
25316
|
+
};
|
|
25317
|
+
var generateMobileBranding = async (args, mobile, platforms, projectRoot) => {
|
|
25318
|
+
if (!mobile.branding)
|
|
25319
|
+
throw new TypeError("absolute.config.ts must define mobile.branding before generating mobile assets.");
|
|
25320
|
+
if (mobile.engine !== "expo") {
|
|
25321
|
+
await ensureCapacitorPackages(projectRoot, args, mobile);
|
|
25322
|
+
await generateAbsoluteCapacitorBranding(mobile, projectRoot, {
|
|
25323
|
+
platforms
|
|
25324
|
+
});
|
|
25325
|
+
return;
|
|
25326
|
+
}
|
|
25327
|
+
await writeAbsoluteExpoProject(mobile, {
|
|
25328
|
+
force: args.includes("--force"),
|
|
25329
|
+
projectRoot
|
|
25330
|
+
});
|
|
25331
|
+
await ensureExpoPackages(mobile.nativeProjectDirectory, args);
|
|
25332
|
+
await runExpo(mobile.nativeProjectDirectory, [
|
|
25333
|
+
"prebuild",
|
|
25334
|
+
"--no-install",
|
|
25335
|
+
"--platform",
|
|
25336
|
+
platforms.length === 2 ? "all" : platforms[0] ?? "all"
|
|
25337
|
+
]);
|
|
25338
|
+
};
|
|
25339
|
+
var renderMobileBrandingResult = (inspection, json, preview, projectRoot) => {
|
|
25340
|
+
const result = {
|
|
25341
|
+
...inspection,
|
|
25342
|
+
...preview ? { preview: relative17(projectRoot, preview).replaceAll("\\", "/") } : {}
|
|
25343
|
+
};
|
|
25344
|
+
if (json)
|
|
25345
|
+
console.log(JSON.stringify(result, null, 2));
|
|
25346
|
+
else
|
|
25347
|
+
console.log(`\u2713 ${inspection.detail}`);
|
|
25348
|
+
if (!json && result.preview)
|
|
25349
|
+
console.log(`Preview: ${result.preview}`);
|
|
25350
|
+
return result;
|
|
25351
|
+
};
|
|
25352
|
+
var assets = async (args) => {
|
|
25353
|
+
const startedAt = performance.now();
|
|
25354
|
+
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
25355
|
+
const requested = args.find((value) => value === "android" || value === "ios");
|
|
25356
|
+
if (requested && !mobile.platforms.includes(requested))
|
|
25357
|
+
throw new TypeError(`Mobile platform ${requested} is not enabled in mobile.platforms.`);
|
|
25358
|
+
const platforms = requested ? [requested] : [...mobile.platforms];
|
|
25359
|
+
try {
|
|
25360
|
+
if (args.includes("--check"))
|
|
25361
|
+
return await checkMobileBranding(mobile, projectRoot, args.includes("--json"));
|
|
25362
|
+
await generateMobileBranding(args, mobile, platforms, projectRoot);
|
|
25363
|
+
const preview = args.includes("--preview") ? await renderAbsoluteMobileBrandingPreview(mobile, projectRoot) : undefined;
|
|
25364
|
+
const inspection = await inspectAbsoluteMobileBranding(mobile, projectRoot);
|
|
25365
|
+
sendTelemetryEvent("mobile:assets", {
|
|
25366
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
25367
|
+
engine: mobile.engine,
|
|
25368
|
+
platforms: platforms.join(","),
|
|
25369
|
+
success: true
|
|
25370
|
+
});
|
|
25371
|
+
return renderMobileBrandingResult(inspection, args.includes("--json"), preview, projectRoot);
|
|
25372
|
+
} catch (error) {
|
|
25373
|
+
sendTelemetryEvent("mobile:assets", {
|
|
25374
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
25375
|
+
engine: mobile.engine,
|
|
25376
|
+
platforms: platforms.join(","),
|
|
25377
|
+
success: false
|
|
25378
|
+
});
|
|
25379
|
+
throw error;
|
|
25380
|
+
}
|
|
25381
|
+
};
|
|
25061
25382
|
var associations = async (args) => {
|
|
25062
25383
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
25063
|
-
const outputDirectory =
|
|
25384
|
+
const outputDirectory = resolve18(projectRoot, valueAfter(args, "--outdir") ?? ".absolutejs/mobile/associations");
|
|
25064
25385
|
if (args.includes("--verify")) {
|
|
25065
25386
|
const result2 = await verifyAbsoluteMobileAssociationFiles(mobile);
|
|
25066
25387
|
console.log(`Verified ${result2.results.length} hosted association files`);
|
|
@@ -25112,7 +25433,7 @@ var generateGithubCi = async (args) => {
|
|
|
25112
25433
|
const publicResult = {
|
|
25113
25434
|
changed: result.changed,
|
|
25114
25435
|
format: result.format,
|
|
25115
|
-
path:
|
|
25436
|
+
path: relative17(projectRoot, result.path).replaceAll("\\", "/"),
|
|
25116
25437
|
platforms: result.platforms,
|
|
25117
25438
|
publishing: result.publishing,
|
|
25118
25439
|
requiredSecrets: result.requiredSecrets
|
|
@@ -25143,14 +25464,14 @@ var createGithubCertificationVerification = async (args) => {
|
|
|
25143
25464
|
GITHUB_WORKFLOW_REF: process.env.GITHUB_WORKFLOW_REF
|
|
25144
25465
|
});
|
|
25145
25466
|
const path = await writeAbsoluteMobileCertificationVerification(projectRoot, outputPath, verification);
|
|
25146
|
-
console.log(
|
|
25467
|
+
console.log(relative17(projectRoot, path).replaceAll("\\", "/"));
|
|
25147
25468
|
return verification;
|
|
25148
25469
|
};
|
|
25149
25470
|
var auditDispatchedGithubMobilePromotion = async (options) => {
|
|
25150
25471
|
const startedAt = performance.now();
|
|
25151
25472
|
try {
|
|
25152
25473
|
const audited = await auditAbsoluteMobileCiPromotion({
|
|
25153
|
-
outputDirectory:
|
|
25474
|
+
outputDirectory: options.outputDirectory,
|
|
25154
25475
|
projectRoot: options.projectRoot,
|
|
25155
25476
|
...options.repository ? { repository: options.repository } : {},
|
|
25156
25477
|
runId: options.runId
|
|
@@ -25172,7 +25493,125 @@ var auditDispatchedGithubMobilePromotion = async (options) => {
|
|
|
25172
25493
|
throw error;
|
|
25173
25494
|
}
|
|
25174
25495
|
};
|
|
25496
|
+
var promotionPhaseRank = (phase) => ["dispatching", "dispatched", "discovered", "completed", "audited"].indexOf(phase);
|
|
25497
|
+
var promotionRecoveryCommand = (dispatchId3) => `absolute mobile ci promote --resume ${dispatchId3}`;
|
|
25498
|
+
var promotionRecoveryError = (error, dispatchId3) => {
|
|
25499
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
25500
|
+
return new TypeError(`${message}
|
|
25501
|
+
Promotion ${dispatchId3} is recorded. Resume without redispatching: ${promotionRecoveryCommand(dispatchId3)}
|
|
25502
|
+
If immutable audit output already exists, add --outdir with a new project-local directory.`, { cause: error });
|
|
25503
|
+
};
|
|
25504
|
+
var watchAndPersistGithubMobilePromotion = async (options) => {
|
|
25505
|
+
let status;
|
|
25506
|
+
try {
|
|
25507
|
+
status = await watchAbsoluteMobileCiRun({
|
|
25508
|
+
projectRoot: options.projectRoot,
|
|
25509
|
+
...options.operation.repository ? { repository: options.operation.repository } : {},
|
|
25510
|
+
runId: options.runId
|
|
25511
|
+
});
|
|
25512
|
+
} catch (error) {
|
|
25513
|
+
const inspected = await inspectAbsoluteMobileCiRun({
|
|
25514
|
+
projectRoot: options.projectRoot,
|
|
25515
|
+
...options.operation.repository ? { repository: options.operation.repository } : {},
|
|
25516
|
+
runId: options.runId
|
|
25517
|
+
}).catch(() => null);
|
|
25518
|
+
if (inspected?.status === "completed")
|
|
25519
|
+
await advanceAbsoluteMobilePromotionOperation(options.projectRoot, options.operation.dispatchId, {
|
|
25520
|
+
conclusion: inspected.conclusion,
|
|
25521
|
+
githubStatus: inspected.status,
|
|
25522
|
+
phase: "completed"
|
|
25523
|
+
});
|
|
25524
|
+
throw error;
|
|
25525
|
+
}
|
|
25526
|
+
const operation = await advanceAbsoluteMobilePromotionOperation(options.projectRoot, options.operation.dispatchId, {
|
|
25527
|
+
conclusion: status.conclusion,
|
|
25528
|
+
githubStatus: status.status,
|
|
25529
|
+
phase: "completed"
|
|
25530
|
+
});
|
|
25531
|
+
return { operation, status };
|
|
25532
|
+
};
|
|
25533
|
+
var completeGithubMobilePromotion = async (options) => {
|
|
25534
|
+
let { operation } = options;
|
|
25535
|
+
if (!operation.runId || !operation.url) {
|
|
25536
|
+
const promotion = await discoverAbsoluteMobilePromotionRun({
|
|
25537
|
+
dispatchId: operation.dispatchId,
|
|
25538
|
+
projectRoot: options.projectRoot,
|
|
25539
|
+
...operation.repository ? { repository: operation.repository } : {},
|
|
25540
|
+
workflow: operation.workflow
|
|
25541
|
+
});
|
|
25542
|
+
operation = await advanceAbsoluteMobilePromotionOperation(options.projectRoot, operation.dispatchId, {
|
|
25543
|
+
phase: "discovered",
|
|
25544
|
+
runId: promotion.runId,
|
|
25545
|
+
url: promotion.url
|
|
25546
|
+
});
|
|
25547
|
+
}
|
|
25548
|
+
if (!operation.runId || !operation.url)
|
|
25549
|
+
throw new TypeError("Promotion run discovery did not produce an identity.");
|
|
25550
|
+
const promotionRunId = operation.runId;
|
|
25551
|
+
const promotionUrl = operation.url;
|
|
25552
|
+
if (!options.json) {
|
|
25553
|
+
console.log(`Promotion ${operation.dispatchId} is GitHub run ${promotionRunId}.`);
|
|
25554
|
+
console.log(promotionUrl);
|
|
25555
|
+
}
|
|
25556
|
+
let status = null;
|
|
25557
|
+
if (options.watch && promotionPhaseRank(operation.phase) < promotionPhaseRank("completed")) {
|
|
25558
|
+
if (!options.json)
|
|
25559
|
+
console.log(`Watching GitHub run ${promotionRunId} until completion\u2026`);
|
|
25560
|
+
({ operation, status } = await watchAndPersistGithubMobilePromotion({
|
|
25561
|
+
operation,
|
|
25562
|
+
projectRoot: options.projectRoot,
|
|
25563
|
+
runId: promotionRunId
|
|
25564
|
+
}));
|
|
25565
|
+
} else if (options.watch) {
|
|
25566
|
+
status = await inspectAbsoluteMobileCiRun({
|
|
25567
|
+
projectRoot: options.projectRoot,
|
|
25568
|
+
...operation.repository ? { repository: operation.repository } : {},
|
|
25569
|
+
runId: promotionRunId
|
|
25570
|
+
});
|
|
25571
|
+
}
|
|
25572
|
+
if (options.audit && operation.conclusion !== "success")
|
|
25573
|
+
throw new TypeError("Promotion audit requires a successfully completed workflow run.");
|
|
25574
|
+
let audited = null;
|
|
25575
|
+
if (options.audit && operation.phase !== "audited") {
|
|
25576
|
+
audited = await auditDispatchedGithubMobilePromotion({
|
|
25577
|
+
outputDirectory: options.auditOutputDirectory ?? operation.auditOutputDirectory ?? undefined,
|
|
25578
|
+
platform: operation.platform,
|
|
25579
|
+
projectRoot: options.projectRoot,
|
|
25580
|
+
...operation.repository ? { repository: operation.repository } : {},
|
|
25581
|
+
runId: promotionRunId
|
|
25582
|
+
});
|
|
25583
|
+
operation = await advanceAbsoluteMobilePromotionOperation(options.projectRoot, operation.dispatchId, {
|
|
25584
|
+
auditDirectory: relative17(options.projectRoot, audited.directory).replaceAll("\\", "/"),
|
|
25585
|
+
phase: "audited"
|
|
25586
|
+
});
|
|
25587
|
+
}
|
|
25588
|
+
const result = {
|
|
25589
|
+
auditDirectory: operation.auditDirectory,
|
|
25590
|
+
dispatchId: operation.dispatchId,
|
|
25591
|
+
platform: operation.platform,
|
|
25592
|
+
releaseId: operation.releaseId,
|
|
25593
|
+
runId: promotionRunId,
|
|
25594
|
+
sourceRunId: operation.sourceRunId,
|
|
25595
|
+
status: operation.githubStatus ?? operation.phase,
|
|
25596
|
+
url: promotionUrl
|
|
25597
|
+
};
|
|
25598
|
+
if (options.json)
|
|
25599
|
+
console.log(JSON.stringify(result, null, 2));
|
|
25600
|
+
else {
|
|
25601
|
+
if (status)
|
|
25602
|
+
renderGithubMobileRunStatus(status);
|
|
25603
|
+
if (audited)
|
|
25604
|
+
renderGithubMobilePromotionAudit(audited, options.projectRoot);
|
|
25605
|
+
else if (operation.auditDirectory)
|
|
25606
|
+
console.log(`Audit: ${operation.auditDirectory}`);
|
|
25607
|
+
console.log(`Promotion record: ${relativeAbsoluteMobilePromotionOperationPath(options.projectRoot, operation.dispatchId)}`);
|
|
25608
|
+
}
|
|
25609
|
+
return result;
|
|
25610
|
+
};
|
|
25175
25611
|
var dispatchGithubMobilePromotion = async (args) => {
|
|
25612
|
+
const resumeDispatchId = valueAfter(args, "--resume");
|
|
25613
|
+
if (resumeDispatchId)
|
|
25614
|
+
return resumeGithubMobilePromotion(args, resumeDispatchId);
|
|
25176
25615
|
const [platform2] = args;
|
|
25177
25616
|
if (platform2 !== "android" && platform2 !== "ios")
|
|
25178
25617
|
throw new TypeError("Usage: absolute mobile ci promote <android|ios> --run-id id --certification directory-or-json [--channel name] [store options] [--watch] [--audit]");
|
|
@@ -25196,8 +25635,31 @@ var dispatchGithubMobilePromotion = async (args) => {
|
|
|
25196
25635
|
if (certificationBase64.length > 48000)
|
|
25197
25636
|
throw new TypeError("Mobile certification is too large for protected GitHub dispatch.");
|
|
25198
25637
|
const workflow = valueAfter(args, "--workflow") ?? ".github/workflows/absolute-mobile.yml";
|
|
25199
|
-
const
|
|
25638
|
+
const dispatchId3 = `amp_${randomUUID2().replaceAll("-", "")}`;
|
|
25200
25639
|
const repository = valueAfter(args, "--repo");
|
|
25640
|
+
const ref = valueAfter(args, "--ref");
|
|
25641
|
+
const auditRequested = args.includes("--audit");
|
|
25642
|
+
const watchRequested = args.includes("--watch") || auditRequested;
|
|
25643
|
+
const requestedAuditOutputDirectory = valueAfter(args, "--outdir");
|
|
25644
|
+
const auditOutputDirectory = requestedAuditOutputDirectory ? relative17(projectRoot, resolve18(projectRoot, requestedAuditOutputDirectory)).replaceAll("\\", "/") : null;
|
|
25645
|
+
await createAbsoluteMobilePromotionOperation(projectRoot, {
|
|
25646
|
+
auditOutputDirectory,
|
|
25647
|
+
auditRequested,
|
|
25648
|
+
certificationId: certification.certificationId,
|
|
25649
|
+
certificationSha256: createHash7("sha256").update(serializeAbsoluteMobileReleaseCertification(certification)).digest("hex"),
|
|
25650
|
+
channel: channel || null,
|
|
25651
|
+
dispatchId: dispatchId3,
|
|
25652
|
+
platform: platform2,
|
|
25653
|
+
playTrack: platform2 === "android" ? playTrack : null,
|
|
25654
|
+
ref: ref ?? null,
|
|
25655
|
+
releaseId: certification.release.releaseId,
|
|
25656
|
+
repository: repository ?? null,
|
|
25657
|
+
sourceRunId,
|
|
25658
|
+
testflightGroup: platform2 === "ios" ? testflightGroup || null : null,
|
|
25659
|
+
testflightSubmitReview: platform2 === "ios" && args.includes("--testflight-submit-review"),
|
|
25660
|
+
watchRequested,
|
|
25661
|
+
workflow
|
|
25662
|
+
});
|
|
25201
25663
|
const command = [
|
|
25202
25664
|
"workflow",
|
|
25203
25665
|
"run",
|
|
@@ -25209,7 +25671,7 @@ var dispatchGithubMobilePromotion = async (args) => {
|
|
|
25209
25671
|
"-f",
|
|
25210
25672
|
`source_run_id=${sourceRunId}`,
|
|
25211
25673
|
"-f",
|
|
25212
|
-
`dispatch_id=${
|
|
25674
|
+
`dispatch_id=${dispatchId3}`,
|
|
25213
25675
|
"-f",
|
|
25214
25676
|
`certification_base64=${certificationBase64}`,
|
|
25215
25677
|
"-f",
|
|
@@ -25221,74 +25683,98 @@ var dispatchGithubMobilePromotion = async (args) => {
|
|
|
25221
25683
|
command.push("-f", `testflight_group=${testflightGroup}`);
|
|
25222
25684
|
command.push("-f", `submit_testflight_review=${args.includes("--testflight-submit-review")}`);
|
|
25223
25685
|
}
|
|
25224
|
-
const ref = valueAfter(args, "--ref");
|
|
25225
25686
|
if (ref)
|
|
25226
25687
|
command.push("--ref", ref);
|
|
25227
25688
|
if (repository)
|
|
25228
25689
|
command.push("--repo", repository);
|
|
25229
|
-
|
|
25230
|
-
|
|
25231
|
-
|
|
25232
|
-
|
|
25233
|
-
|
|
25234
|
-
|
|
25235
|
-
|
|
25236
|
-
|
|
25237
|
-
|
|
25238
|
-
|
|
25239
|
-
|
|
25240
|
-
|
|
25241
|
-
|
|
25242
|
-
|
|
25243
|
-
|
|
25244
|
-
|
|
25245
|
-
|
|
25246
|
-
|
|
25247
|
-
|
|
25248
|
-
|
|
25249
|
-
|
|
25250
|
-
|
|
25251
|
-
|
|
25252
|
-
|
|
25253
|
-
|
|
25254
|
-
|
|
25255
|
-
|
|
25256
|
-
|
|
25257
|
-
}
|
|
25258
|
-
|
|
25259
|
-
|
|
25260
|
-
|
|
25261
|
-
|
|
25262
|
-
|
|
25263
|
-
|
|
25264
|
-
|
|
25265
|
-
|
|
25266
|
-
|
|
25267
|
-
|
|
25268
|
-
|
|
25269
|
-
|
|
25270
|
-
|
|
25271
|
-
|
|
25272
|
-
|
|
25273
|
-
|
|
25274
|
-
|
|
25275
|
-
|
|
25276
|
-
|
|
25277
|
-
|
|
25278
|
-
|
|
25279
|
-
|
|
25280
|
-
|
|
25281
|
-
|
|
25282
|
-
|
|
25283
|
-
|
|
25284
|
-
|
|
25285
|
-
|
|
25690
|
+
try {
|
|
25691
|
+
const child = Bun.spawn(["gh", ...command], {
|
|
25692
|
+
cwd: projectRoot,
|
|
25693
|
+
stderr: "pipe",
|
|
25694
|
+
stdin: "inherit",
|
|
25695
|
+
stdout: "pipe"
|
|
25696
|
+
});
|
|
25697
|
+
const [exitCode, stderr] = await Promise.all([
|
|
25698
|
+
child.exited,
|
|
25699
|
+
new Response(child.stderr).text(),
|
|
25700
|
+
new Response(child.stdout).text()
|
|
25701
|
+
]);
|
|
25702
|
+
if (exitCode !== 0)
|
|
25703
|
+
throw new TypeError(`GitHub promotion dispatch exited with status ${exitCode}: ${stderr.trim() || "unknown GitHub CLI error"}`);
|
|
25704
|
+
const operation = await advanceAbsoluteMobilePromotionOperation(projectRoot, dispatchId3, { phase: "dispatched" });
|
|
25705
|
+
sendTelemetryEvent("mobile:ci-promotion-dispatched", {
|
|
25706
|
+
discovery: "correlated",
|
|
25707
|
+
platform: platform2,
|
|
25708
|
+
provider: "github-actions",
|
|
25709
|
+
storeTarget: platform2 === "android" ? playTrack !== "registry-only" : testflightGroup !== ""
|
|
25710
|
+
});
|
|
25711
|
+
return await completeGithubMobilePromotion({
|
|
25712
|
+
audit: operation.auditRequested,
|
|
25713
|
+
json: args.includes("--json"),
|
|
25714
|
+
operation,
|
|
25715
|
+
projectRoot,
|
|
25716
|
+
watch: operation.watchRequested
|
|
25717
|
+
});
|
|
25718
|
+
} catch (error) {
|
|
25719
|
+
throw promotionRecoveryError(error, dispatchId3);
|
|
25720
|
+
}
|
|
25721
|
+
};
|
|
25722
|
+
var resumeGithubMobilePromotion = async (args, dispatchId3) => {
|
|
25723
|
+
const projectRoot = process.cwd();
|
|
25724
|
+
const startedAt = performance.now();
|
|
25725
|
+
let resumedPhase = "unread";
|
|
25726
|
+
try {
|
|
25727
|
+
const operation = await readAbsoluteMobilePromotionOperation(projectRoot, dispatchId3);
|
|
25728
|
+
resumedPhase = operation.phase;
|
|
25729
|
+
const audit = args.includes("--audit") || operation.auditRequested;
|
|
25730
|
+
const watch = args.includes("--watch") || audit || operation.watchRequested;
|
|
25731
|
+
if (!args.includes("--json"))
|
|
25732
|
+
console.log(`Resuming ${operation.platform} promotion ${operation.dispatchId} from ${operation.phase}.`);
|
|
25733
|
+
const result = await completeGithubMobilePromotion({
|
|
25734
|
+
audit,
|
|
25735
|
+
auditOutputDirectory: valueAfter(args, "--outdir"),
|
|
25736
|
+
json: args.includes("--json"),
|
|
25737
|
+
operation,
|
|
25738
|
+
projectRoot,
|
|
25739
|
+
watch
|
|
25740
|
+
});
|
|
25741
|
+
sendTelemetryEvent("mobile:ci-promotion-resumed", {
|
|
25742
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
25743
|
+
phase: resumedPhase,
|
|
25744
|
+
provider: "github-actions",
|
|
25745
|
+
success: true
|
|
25746
|
+
});
|
|
25286
25747
|
return result;
|
|
25287
|
-
|
|
25288
|
-
|
|
25289
|
-
|
|
25290
|
-
|
|
25291
|
-
|
|
25748
|
+
} catch (error) {
|
|
25749
|
+
sendTelemetryEvent("mobile:ci-promotion-resumed", {
|
|
25750
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
25751
|
+
phase: resumedPhase,
|
|
25752
|
+
provider: "github-actions",
|
|
25753
|
+
success: false
|
|
25754
|
+
});
|
|
25755
|
+
throw promotionRecoveryError(error, dispatchId3);
|
|
25756
|
+
}
|
|
25757
|
+
};
|
|
25758
|
+
var listGithubMobilePromotions = async (args) => {
|
|
25759
|
+
const projectRoot = process.cwd();
|
|
25760
|
+
const operations = await listAbsoluteMobilePromotionOperations(projectRoot);
|
|
25761
|
+
if (args.includes("--json")) {
|
|
25762
|
+
console.log(JSON.stringify(operations, null, 2));
|
|
25763
|
+
return operations;
|
|
25764
|
+
}
|
|
25765
|
+
if (operations.length === 0) {
|
|
25766
|
+
console.log("No local mobile promotion operations were found.");
|
|
25767
|
+
return operations;
|
|
25768
|
+
}
|
|
25769
|
+
operations.forEach((operation) => {
|
|
25770
|
+
console.log(`${operation.dispatchId} ${operation.platform} ${operation.phase} ${operation.releaseId}`);
|
|
25771
|
+
console.log(` source ${operation.sourceRunId}${operation.runId ? ` \u2192 promotion ${operation.runId}` : ""}`);
|
|
25772
|
+
if (operation.url)
|
|
25773
|
+
console.log(` ${operation.url}`);
|
|
25774
|
+
if (operation.phase !== "audited")
|
|
25775
|
+
console.log(` Resume: ${promotionRecoveryCommand(operation.dispatchId)}`);
|
|
25776
|
+
});
|
|
25777
|
+
return operations;
|
|
25292
25778
|
};
|
|
25293
25779
|
var githubMobileRunId = (args) => {
|
|
25294
25780
|
const value = valueAfter(args, "--run-id");
|
|
@@ -25332,7 +25818,7 @@ var inspectGithubMobileRun = async (args) => {
|
|
|
25332
25818
|
};
|
|
25333
25819
|
var renderGithubMobilePromotionAudit = (result, projectRoot) => {
|
|
25334
25820
|
console.log(`\u2713 Verified ${result.audit.platform} promotion ${result.audit.github.promotionRunId} for ${result.audit.release.releaseId}.`);
|
|
25335
|
-
console.log(`Audit: ${
|
|
25821
|
+
console.log(`Audit: ${relative17(projectRoot, result.directory)}`);
|
|
25336
25822
|
};
|
|
25337
25823
|
var auditGithubMobilePromotion = async (args) => {
|
|
25338
25824
|
const projectRoot = process.cwd();
|
|
@@ -25464,9 +25950,9 @@ var prepareExpoMobileUpdateExport = async (options) => {
|
|
|
25464
25950
|
temporaryDirectory: undefined
|
|
25465
25951
|
};
|
|
25466
25952
|
await ensureExpoPackages(mobile.nativeProjectDirectory, options.args);
|
|
25467
|
-
const temporaryParent =
|
|
25468
|
-
await
|
|
25469
|
-
const temporaryDirectory = await mkdtemp7(
|
|
25953
|
+
const temporaryParent = join19(options.projectRoot, ".absolutejs", "mobile", "expo-update-exports");
|
|
25954
|
+
await mkdir19(temporaryParent, { recursive: true });
|
|
25955
|
+
const temporaryDirectory = await mkdtemp7(join19(temporaryParent, ".stage-"));
|
|
25470
25956
|
try {
|
|
25471
25957
|
await runExpo(mobile.nativeProjectDirectory, [
|
|
25472
25958
|
"export",
|
|
@@ -25478,9 +25964,9 @@ var prepareExpoMobileUpdateExport = async (options) => {
|
|
|
25478
25964
|
temporaryDirectory,
|
|
25479
25965
|
"--clear"
|
|
25480
25966
|
], { production: true });
|
|
25481
|
-
const generatedApp = JSON.parse(await
|
|
25482
|
-
const expoConfig =
|
|
25483
|
-
if (!
|
|
25967
|
+
const generatedApp = JSON.parse(await readFile23(join19(mobile.nativeProjectDirectory, "app.json"), "utf8"));
|
|
25968
|
+
const expoConfig = isRecord11(generatedApp) ? generatedApp.expo : undefined;
|
|
25969
|
+
if (!isRecord11(expoConfig))
|
|
25484
25970
|
throw new TypeError("Generated Expo app configuration is invalid.");
|
|
25485
25971
|
const publicExpoConfig = expoPublicConfig(expoConfig);
|
|
25486
25972
|
const computedRuntime = resolveAbsoluteMobileUpdateRuntime(mobile, options.projectRoot).fingerprint;
|
|
@@ -25496,7 +25982,7 @@ var prepareExpoMobileUpdateExport = async (options) => {
|
|
|
25496
25982
|
temporaryDirectory
|
|
25497
25983
|
};
|
|
25498
25984
|
} catch (error) {
|
|
25499
|
-
await
|
|
25985
|
+
await rm11(temporaryDirectory, { force: true, recursive: true });
|
|
25500
25986
|
throw error;
|
|
25501
25987
|
}
|
|
25502
25988
|
};
|
|
@@ -25521,11 +26007,11 @@ var buildMobileUpdate = async (args) => {
|
|
|
25521
26007
|
let expoExportDirectory;
|
|
25522
26008
|
try {
|
|
25523
26009
|
await start(mobileBuildServerEntry(args), valueAfter(args, "--web-outdir"), configPath, { prepareOnly: true });
|
|
25524
|
-
const embedded = JSON.parse(await
|
|
25525
|
-
const runtimeFingerprint =
|
|
26010
|
+
const embedded = JSON.parse(await readFile23(join19(mobile.bundleDirectory, "absolute-mobile-manifest.json"), "utf8"));
|
|
26011
|
+
const runtimeFingerprint = isRecord11(embedded) ? embedded.nativeRuntime : undefined;
|
|
25526
26012
|
if (typeof runtimeFingerprint !== "string" || !/^[a-f0-9]{64}$/u.test(runtimeFingerprint))
|
|
25527
26013
|
throw new TypeError("Prepared mobile bundle is missing its native runtime fingerprint.");
|
|
25528
|
-
const privateKey = await
|
|
26014
|
+
const privateKey = await readFile23(resolve18(projectRoot, signingKeyPath));
|
|
25529
26015
|
const configuredPublicKey = Buffer.from(mobile.updates.publicKeys[keyId], "base64");
|
|
25530
26016
|
const derivedPublicKey = createPublicKey2(privateKey).export({
|
|
25531
26017
|
format: "der",
|
|
@@ -25546,7 +26032,7 @@ var buildMobileUpdate = async (args) => {
|
|
|
25546
26032
|
channel: mobile.updates.channel,
|
|
25547
26033
|
classification,
|
|
25548
26034
|
keyId,
|
|
25549
|
-
outputDirectory: valueAfter(args, "--outdir") ??
|
|
26035
|
+
outputDirectory: valueAfter(args, "--outdir") ?? join19(projectRoot, ".absolutejs", "mobile", "updates"),
|
|
25550
26036
|
privateKey,
|
|
25551
26037
|
runtimeFingerprint
|
|
25552
26038
|
});
|
|
@@ -25558,7 +26044,7 @@ var buildMobileUpdate = async (args) => {
|
|
|
25558
26044
|
return result;
|
|
25559
26045
|
} finally {
|
|
25560
26046
|
if (expoExportDirectory)
|
|
25561
|
-
await
|
|
26047
|
+
await rm11(expoExportDirectory, { force: true, recursive: true });
|
|
25562
26048
|
sendTelemetryEvent("mobile:update-build", {
|
|
25563
26049
|
classification: classification ?? "invalid",
|
|
25564
26050
|
durationMs: Math.round(performance.now() - startedAt),
|
|
@@ -25588,7 +26074,7 @@ var generateExpoUpdateSigning = async (args) => {
|
|
|
25588
26074
|
...valueAfter(args, "--public-key") ? { publicKeyPath: valueAfter(args, "--public-key") } : {},
|
|
25589
26075
|
...validityYears === undefined ? {} : { validityYears }
|
|
25590
26076
|
});
|
|
25591
|
-
const certificatePath =
|
|
26077
|
+
const certificatePath = relative17(projectRoot, result.certificatePath).replaceAll("\\", "/");
|
|
25592
26078
|
sendTelemetryEvent("mobile:update-code-signing-generated", {
|
|
25593
26079
|
engine: "expo",
|
|
25594
26080
|
validityYears: validityYears ?? 10
|
|
@@ -25650,7 +26136,7 @@ var provisionMobileUpdate = async (args) => {
|
|
|
25650
26136
|
publicKeys: mobile.updates.publicKeys,
|
|
25651
26137
|
storage: requestedStorage
|
|
25652
26138
|
});
|
|
25653
|
-
console.log(`Provisioned ${requestedStorage === "local" ? "local development" : "durable S3-compatible"} mobile update storage in ${
|
|
26139
|
+
console.log(`Provisioned ${requestedStorage === "local" ? "local development" : "durable S3-compatible"} mobile update storage in ${relative17(projectRoot, path).replaceAll("\\", "/")}.`);
|
|
25654
26140
|
if (requestedStorage === "local")
|
|
25655
26141
|
console.log("Production release checks will require durable storage. Re-run with --storage s3 --force before deploying.");
|
|
25656
26142
|
else
|
|
@@ -26127,7 +26613,7 @@ var buildAndroid = async (args, prepareVersionCode) => {
|
|
|
26127
26613
|
const durationMs = Math.round(performance.now() - startedAt);
|
|
26128
26614
|
console.log(`Built ${release.metadata.signed ? "signed" : "unsigned"} Android App Bundle in ${getDurationString(durationMs)}.`);
|
|
26129
26615
|
console.log(`Artifact: ${release.artifactPath}`);
|
|
26130
|
-
console.log(`Metadata: ${
|
|
26616
|
+
console.log(`Metadata: ${join19(release.releaseRoot, "release.json")}`);
|
|
26131
26617
|
return release;
|
|
26132
26618
|
} finally {
|
|
26133
26619
|
sendTelemetryEvent("mobile:android-release-build", {
|
|
@@ -26350,7 +26836,7 @@ var buildIos = async (args, prepareBuildNumber) => {
|
|
|
26350
26836
|
console.log(`Artifact: ${release.artifactPath}`);
|
|
26351
26837
|
if (release.registeredArtifactPath)
|
|
26352
26838
|
console.log(`Registered-device artifact: ${release.registeredArtifactPath}`);
|
|
26353
|
-
console.log(`Metadata: ${
|
|
26839
|
+
console.log(`Metadata: ${join19(release.releaseRoot, "release.json")}`);
|
|
26354
26840
|
return release;
|
|
26355
26841
|
} finally {
|
|
26356
26842
|
stopListeningForCancellation();
|
|
@@ -26501,7 +26987,7 @@ var appendSyncSchemaDoctorCheck = (checks, projectRoot) => {
|
|
|
26501
26987
|
checks.push({
|
|
26502
26988
|
id: "sync.storage-schema",
|
|
26503
26989
|
label: `Offline schema ${schema.components.map((component) => `${component.id}@${component.version}`).join(", ")}`,
|
|
26504
|
-
path:
|
|
26990
|
+
path: join19(projectRoot, "package.json"),
|
|
26505
26991
|
platform: "host",
|
|
26506
26992
|
status: "pass"
|
|
26507
26993
|
});
|
|
@@ -26509,7 +26995,7 @@ var appendSyncSchemaDoctorCheck = (checks, projectRoot) => {
|
|
|
26509
26995
|
checks.push({
|
|
26510
26996
|
id: "sync.storage-schema",
|
|
26511
26997
|
label: "Offline schema metadata is invalid",
|
|
26512
|
-
path:
|
|
26998
|
+
path: join19(projectRoot, "package.json"),
|
|
26513
26999
|
platform: "host",
|
|
26514
27000
|
remediation: error instanceof Error ? error.message : String(error),
|
|
26515
27001
|
status: "fail"
|
|
@@ -26597,7 +27083,7 @@ var requireAndroidTestPort = (args, projectRoot) => {
|
|
|
26597
27083
|
}
|
|
26598
27084
|
return { https: args.includes("--https"), port };
|
|
26599
27085
|
}
|
|
26600
|
-
const instances = listLiveInstances().filter((instance2) =>
|
|
27086
|
+
const instances = listLiveInstances().filter((instance2) => resolve18(instance2.cwd) === resolve18(projectRoot) && instance2.source === "dev" && instance2.port !== null);
|
|
26601
27087
|
if (instances.length !== 1) {
|
|
26602
27088
|
throw new TypeError(instances.length === 0 ? "No running AbsoluteJS dev server was found for this project. Start `bun dev`, wait for Android to report ready, then run `absolute mobile test android`." : "Multiple dev servers are running for this project. Select one with mobile test android --port <port>.");
|
|
26603
27089
|
}
|
|
@@ -26691,8 +27177,8 @@ var selectOrStartAndroidReleaseEmulator = async (adb2, emulator, explicitSerial,
|
|
|
26691
27177
|
return waitForBoot();
|
|
26692
27178
|
};
|
|
26693
27179
|
var safeArtifactRoot = (projectRoot, value) => {
|
|
26694
|
-
const root =
|
|
26695
|
-
if (root !== projectRoot && !root.startsWith(`${
|
|
27180
|
+
const root = resolve18(projectRoot, value ?? ".absolutejs/mobile/test-artifacts");
|
|
27181
|
+
if (root !== projectRoot && !root.startsWith(`${resolve18(projectRoot)}/`)) {
|
|
26696
27182
|
throw new TypeError("mobile test --artifacts must remain inside the project.");
|
|
26697
27183
|
}
|
|
26698
27184
|
return root;
|
|
@@ -26720,11 +27206,11 @@ var waitForRequestedAndroidHmr = async (args, session, checks, timeoutMs) => {
|
|
|
26720
27206
|
});
|
|
26721
27207
|
};
|
|
26722
27208
|
var writeAndroidFailureArtifacts = async (options) => {
|
|
26723
|
-
await
|
|
26724
|
-
const screenshot = options.session ? await options.session.screenshot(
|
|
27209
|
+
await mkdir19(options.artifactRoot, { recursive: true });
|
|
27210
|
+
const screenshot = options.session ? await options.session.screenshot(join19(options.artifactRoot, "android-failure.png")).catch(() => {
|
|
26725
27211
|
return;
|
|
26726
27212
|
}) : undefined;
|
|
26727
|
-
const diagnosticPath =
|
|
27213
|
+
const diagnosticPath = join19(options.artifactRoot, "android-failure.json");
|
|
26728
27214
|
await writeFile19(diagnosticPath, `${JSON.stringify({
|
|
26729
27215
|
diagnostics: options.session?.diagnostics ?? [],
|
|
26730
27216
|
error: options.error instanceof Error ? options.error.message : String(options.error),
|
|
@@ -26800,7 +27286,7 @@ var testAndroidRelease = async (args, mobile, projectRoot) => {
|
|
|
26800
27286
|
release,
|
|
26801
27287
|
serial
|
|
26802
27288
|
});
|
|
26803
|
-
const screenshot = reportRoot ? await captureAndroidReleaseScreenshot(adb2, serial,
|
|
27289
|
+
const screenshot = reportRoot ? await captureAndroidReleaseScreenshot(adb2, serial, join19(reportRoot, "android-release.png")) : undefined;
|
|
26804
27290
|
sendTelemetryEvent("mobile:android-release-conformance", {
|
|
26805
27291
|
durationMs: result.durationMs,
|
|
26806
27292
|
engine: result.engine,
|
|
@@ -26847,8 +27333,8 @@ var testAndroidRelease = async (args, mobile, projectRoot) => {
|
|
|
26847
27333
|
platform: "android",
|
|
26848
27334
|
success: false
|
|
26849
27335
|
});
|
|
26850
|
-
await
|
|
26851
|
-
const diagnosticPath =
|
|
27336
|
+
await mkdir19(artifactRoot, { recursive: true });
|
|
27337
|
+
const diagnosticPath = join19(artifactRoot, "android-release-failure.json");
|
|
26852
27338
|
await writeFile19(diagnosticPath, `${JSON.stringify({
|
|
26853
27339
|
error: sanitizeNativeReportText(error instanceof Error ? error.message : String(error)),
|
|
26854
27340
|
platform: "android",
|
|
@@ -26943,7 +27429,7 @@ var testAndroid = async (args) => {
|
|
|
26943
27429
|
console.log(JSON.stringify(report, null, 2));
|
|
26944
27430
|
else
|
|
26945
27431
|
printAndroidTestReport(report);
|
|
26946
|
-
const screenshot = reportRoot ? await session.screenshot(
|
|
27432
|
+
const screenshot = reportRoot ? await session.screenshot(join19(artifactRoot, "android-emulator.png")) : undefined;
|
|
26947
27433
|
await writeRequestedAndroidReport({
|
|
26948
27434
|
adb: adb2,
|
|
26949
27435
|
args,
|
|
@@ -27012,14 +27498,14 @@ var requireIosTestContext = (args, projectRoot) => {
|
|
|
27012
27498
|
const port = Number(explicit);
|
|
27013
27499
|
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
27014
27500
|
throw new TypeError("mobile test --port must be a valid TCP port.");
|
|
27015
|
-
const instance2 = listLiveInstances().find((candidate) =>
|
|
27501
|
+
const instance2 = listLiveInstances().find((candidate) => resolve18(candidate.cwd) === resolve18(projectRoot) && candidate.source === "dev" && candidate.port === port);
|
|
27016
27502
|
return {
|
|
27017
27503
|
https: instance2?.https ?? args.includes("--https"),
|
|
27018
27504
|
instance: instance2,
|
|
27019
27505
|
port
|
|
27020
27506
|
};
|
|
27021
27507
|
}
|
|
27022
|
-
const instances = listLiveInstances().filter((instance2) =>
|
|
27508
|
+
const instances = listLiveInstances().filter((instance2) => resolve18(instance2.cwd) === resolve18(projectRoot) && instance2.source === "dev" && instance2.port !== null);
|
|
27023
27509
|
if (instances.length !== 1)
|
|
27024
27510
|
throw new TypeError(instances.length === 0 ? "No running AbsoluteJS dev server was found for this project. Start `bun dev`, wait for iOS to report ready, then run `absolute mobile test ios`." : "Multiple dev servers are running for this project. Select one with mobile test ios --port <port>.");
|
|
27025
27511
|
const [instance] = instances;
|
|
@@ -27037,7 +27523,7 @@ var waitForIosHmrClient = async (options) => {
|
|
|
27037
27523
|
return;
|
|
27038
27524
|
});
|
|
27039
27525
|
const status = response?.ok ? await response.json().catch(() => null) : null;
|
|
27040
|
-
const targets =
|
|
27526
|
+
const targets = isRecord11(status) && isRecord11(status.connectedTargets) ? status.connectedTargets : undefined;
|
|
27041
27527
|
if (targets && typeof targets["capacitor-ios"] === "number" && targets["capacitor-ios"] > 0)
|
|
27042
27528
|
return;
|
|
27043
27529
|
await Bun.sleep(100);
|
|
@@ -27163,8 +27649,8 @@ var requireCapturedCommand = (command, label) => {
|
|
|
27163
27649
|
return result;
|
|
27164
27650
|
};
|
|
27165
27651
|
var writeIosFailureArtifacts = async (options) => {
|
|
27166
|
-
await
|
|
27167
|
-
const screenshot =
|
|
27652
|
+
await mkdir19(options.artifactRoot, { recursive: true });
|
|
27653
|
+
const screenshot = join19(options.artifactRoot, "ios-failure.png");
|
|
27168
27654
|
const screenshotResult = captureCommand4([
|
|
27169
27655
|
options.xcrun,
|
|
27170
27656
|
"simctl",
|
|
@@ -27173,7 +27659,7 @@ var writeIosFailureArtifacts = async (options) => {
|
|
|
27173
27659
|
"screenshot",
|
|
27174
27660
|
screenshot
|
|
27175
27661
|
]);
|
|
27176
|
-
const diagnosticPath =
|
|
27662
|
+
const diagnosticPath = join19(options.artifactRoot, "ios-failure.json");
|
|
27177
27663
|
await writeFile19(diagnosticPath, `${JSON.stringify({
|
|
27178
27664
|
appId: options.appId,
|
|
27179
27665
|
error: options.error instanceof Error ? options.error.message : String(options.error),
|
|
@@ -27195,14 +27681,14 @@ var nativeReportRoot = (args, projectRoot, platform2) => {
|
|
|
27195
27681
|
return;
|
|
27196
27682
|
const candidate = args[index + 1];
|
|
27197
27683
|
const explicit = candidate?.startsWith("--") ? undefined : candidate;
|
|
27198
|
-
const
|
|
27199
|
-
return safeArtifactRoot(projectRoot, explicit ?? `.absolutejs/mobile/test-reports/${platform2}-${
|
|
27684
|
+
const timestamp2 = new Date().toISOString().replaceAll(":", "-");
|
|
27685
|
+
return safeArtifactRoot(projectRoot, explicit ?? `.absolutejs/mobile/test-reports/${platform2}-${timestamp2}`);
|
|
27200
27686
|
};
|
|
27201
27687
|
var absolutejsVersionForReport = async () => {
|
|
27202
27688
|
let absolutejsVersion = process.env.ABSOLUTE_VERSION ?? "unknown";
|
|
27203
27689
|
const versions = await Promise.all([
|
|
27204
|
-
|
|
27205
|
-
|
|
27690
|
+
resolve18(import.meta.dir, "..", "..", "package.json"),
|
|
27691
|
+
resolve18(import.meta.dir, "..", "..", "..", "package.json")
|
|
27206
27692
|
].map((candidate) => readPackageVersionForIosReport(candidate).catch(() => "unknown")));
|
|
27207
27693
|
for (const version of versions) {
|
|
27208
27694
|
if (version === "unknown")
|
|
@@ -27579,8 +28065,8 @@ var testIosRelease = async (args, mobile, projectRoot) => {
|
|
|
27579
28065
|
remote: remoteProfile !== undefined,
|
|
27580
28066
|
success: false
|
|
27581
28067
|
});
|
|
27582
|
-
await
|
|
27583
|
-
const diagnosticPath =
|
|
28068
|
+
await mkdir19(artifactRoot, { recursive: true });
|
|
28069
|
+
const diagnosticPath = join19(artifactRoot, "ios-release-failure.json");
|
|
27584
28070
|
await writeFile19(diagnosticPath, `${JSON.stringify({
|
|
27585
28071
|
error: sanitizeIosReportText(error instanceof Error ? error.message : String(error)),
|
|
27586
28072
|
platform: "ios",
|
|
@@ -27674,8 +28160,8 @@ var testIos = async (args) => {
|
|
|
27674
28160
|
mobile.appId
|
|
27675
28161
|
], "iOS app launch");
|
|
27676
28162
|
await waitForIosHmrClient({ https, port, timeoutMs });
|
|
27677
|
-
await
|
|
27678
|
-
const screenshot =
|
|
28163
|
+
await mkdir19(artifactRoot, { recursive: true });
|
|
28164
|
+
const screenshot = join19(artifactRoot, "ios-simulator.png");
|
|
27679
28165
|
requireCapturedCommand([xcrun, "simctl", "io", simulator.udid, "screenshot", screenshot], "iOS simulator screenshot");
|
|
27680
28166
|
const hmrApply = await waitForRequestedIosHmr(args, instance, timeoutMs);
|
|
27681
28167
|
const report = {
|
|
@@ -27885,6 +28371,10 @@ var runMobile = async (args) => {
|
|
|
27885
28371
|
await sync(args.slice(1));
|
|
27886
28372
|
return;
|
|
27887
28373
|
}
|
|
28374
|
+
if (command === "assets") {
|
|
28375
|
+
await assets(args.slice(1));
|
|
28376
|
+
return;
|
|
28377
|
+
}
|
|
27888
28378
|
if (command === "associations") {
|
|
27889
28379
|
await associations(args.slice(1));
|
|
27890
28380
|
return;
|
|
@@ -27892,6 +28382,8 @@ var runMobile = async (args) => {
|
|
|
27892
28382
|
if (command === "ci") {
|
|
27893
28383
|
if (args[1] === "promote")
|
|
27894
28384
|
await dispatchGithubMobilePromotion(args.slice(2));
|
|
28385
|
+
else if (args[1] === "promotions")
|
|
28386
|
+
await listGithubMobilePromotions(args.slice(2));
|
|
27895
28387
|
else if (args[1] === "status")
|
|
27896
28388
|
await inspectGithubMobileRun(args.slice(2));
|
|
27897
28389
|
else if (args[1] === "audit")
|
|
@@ -27978,7 +28470,7 @@ var runMobile = async (args) => {
|
|
|
27978
28470
|
await publishIos(args.slice(2));
|
|
27979
28471
|
return;
|
|
27980
28472
|
}
|
|
27981
|
-
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] | certify <release-dir> [--evidence report-dir]... [--require installed|simulator|device|store] [--outdir dir] [--json] | certify <release-dir> --verify certification-dir [--require installed|simulator|device|store] [--json] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | ci promote <android|ios> --run-id id --certification path [--channel name] [--play-track track|--testflight-group group] [--ref branch] [--repo owner/name] [--watch] [--audit] [--outdir path] [--json] | ci status --run-id id [--watch] [--repo owner/name] [--json] | ci audit --run-id id [--source-run-id id] [--repo owner/name] [--outdir path] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--registered-device-artifact] [--outdir dir] [--web-outdir dir] [--unsigned] | update provision [--storage local|s3] [--registry module] [--force] [--yes] | update signing generate --private-key path [--certificate path] [--public-key path] [--key-id id] [--common-name name] [--validity-years n] | update build [server-entry] --classification bug-fix|content|security --key-id id --signing-key path --within-submitted-purpose [--outdir dir] [--web-outdir dir] | update publish <release-directory> [--rollout fraction] [--registry module] | update promote --release id --rollout fraction [--registry module] | update rollback [--release id] [--registry module] | update status [--registry module] [--json] | update advance [--rollout fraction] [--registry module] [--json] | update pause|resume|cancel|reconcile [--registry module] [--json] | update storage [--retain count] [--min-age-days days] [--registry module] [--json] | update gc [--retain count] [--min-age-days days] [--grace-days days] [--apply] [--registry module] [--json] | publish android [server-entry] [--release release-dir] [--certification certification-dir] [--certification-attestation verification-json] [--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] [--release release-dir] [--certification certification-dir] [--certification-attestation verification-json] [--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 [--release release-dir [--yes] | --route path [--wait-for-hmr] [--port n]] [--report [dir]] [--serial id] [--artifacts dir] [--json] [--config path] | test ios [--release release-dir [--remote name] [--device id [--testflight] --yes] | --wait-for-hmr] [--report [dir]] [--udid id] [--artifacts dir] [--json] [--config path]");
|
|
28473
|
+
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] | assets [ios|android] [--check] [--preview] [--json] [--yes] | inspect [--json] [--require-bundle] | certify <release-dir> [--evidence report-dir]... [--require installed|simulator|device|store] [--outdir dir] [--json] | certify <release-dir> --verify certification-dir [--require installed|simulator|device|store] [--json] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | ci promote <android|ios> --run-id id --certification path [--channel name] [--play-track track|--testflight-group group] [--ref branch] [--repo owner/name] [--watch] [--audit] [--outdir path] [--json] | ci promote --resume dispatch-id [--watch] [--audit] [--outdir path] [--json] | ci promotions [--json] | ci status --run-id id [--watch] [--repo owner/name] [--json] | ci audit --run-id id [--source-run-id id] [--repo owner/name] [--outdir path] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--registered-device-artifact] [--outdir dir] [--web-outdir dir] [--unsigned] | update provision [--storage local|s3] [--registry module] [--force] [--yes] | update signing generate --private-key path [--certificate path] [--public-key path] [--key-id id] [--common-name name] [--validity-years n] | update build [server-entry] --classification bug-fix|content|security --key-id id --signing-key path --within-submitted-purpose [--outdir dir] [--web-outdir dir] | update publish <release-directory> [--rollout fraction] [--registry module] | update promote --release id --rollout fraction [--registry module] | update rollback [--release id] [--registry module] | update status [--registry module] [--json] | update advance [--rollout fraction] [--registry module] [--json] | update pause|resume|cancel|reconcile [--registry module] [--json] | update storage [--retain count] [--min-age-days days] [--registry module] [--json] | update gc [--retain count] [--min-age-days days] [--grace-days days] [--apply] [--registry module] [--json] | publish android [server-entry] [--release release-dir] [--certification certification-dir] [--certification-attestation verification-json] [--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] [--release release-dir] [--certification certification-dir] [--certification-attestation verification-json] [--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 [--release release-dir [--yes] | --route path [--wait-for-hmr] [--port n]] [--report [dir]] [--serial id] [--artifacts dir] [--json] [--config path] | test ios [--release release-dir [--remote name] [--device id [--testflight] --yes] | --wait-for-hmr] [--report [dir]] [--udid id] [--artifacts dir] [--json] [--config path]");
|
|
27982
28474
|
};
|
|
27983
28475
|
export {
|
|
27984
28476
|
runMobile
|