@absolutejs/absolute 0.20.0-beta.80 → 0.20.0-beta.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/build.js +1200 -222
- package/dist/build.js.map +7 -5
- package/dist/cli/{compile-x4hfth3p.js → compile-t73ac1zb.js} +2 -2
- package/dist/cli/{config-z8wwxatc.js → config-naw5fer4.js} +1 -1
- package/dist/cli/{dev-8vv459ty.js → dev-skb8dz33.js} +1 -1
- package/dist/cli/{index-w5y7wxn9.js → index-8gksmws3.js} +1 -1
- package/dist/cli/{index-6fb7k6dg.js → index-czw3jd8f.js} +47 -1
- package/dist/cli/{index-d4ar3mwd.js → index-q78x1k9q.js} +2 -2
- package/dist/cli/index.js +5 -5
- package/dist/cli/{mobile-mfp26v2d.js → mobile-hkxh2ab5.js} +390 -136
- package/dist/cli/{start-dtrp1pry.js → start-jbgfw27x.js} +3 -3
- package/dist/index.js +2073 -1095
- package/dist/index.js.map +7 -5
- package/dist/mobile/index.js +976 -4
- package/dist/mobile/index.js.map +7 -5
- package/dist/mobile/remoteMacAgentEntry.js +222 -222
- package/dist/src/mobile/config.d.ts +8 -0
- package/dist/src/mobile/index.d.ts +1 -0
- package/dist/src/mobile/updateServer.d.ts +34 -0
- package/dist/types/build.d.ts +16 -0
- package/package.json +7 -2
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
} from "./index-zh6hhrwy.js";
|
|
5
5
|
import {
|
|
6
6
|
start
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-q78x1k9q.js";
|
|
8
8
|
import {
|
|
9
9
|
ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT,
|
|
10
10
|
ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
|
|
11
11
|
resolveAbsoluteMobileRoute
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-8gksmws3.js";
|
|
13
13
|
import"./index-bzs19w3r.js";
|
|
14
14
|
import"./index-s2tazax7.js";
|
|
15
15
|
import {
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
import"./index-w5vswatm.js";
|
|
50
50
|
import {
|
|
51
51
|
normalizeAbsoluteMobileConfig
|
|
52
|
-
} from "./index-
|
|
52
|
+
} from "./index-czw3jd8f.js";
|
|
53
53
|
import {
|
|
54
54
|
ABSOLUTE_MOBILE_UPDATE_FORMAT,
|
|
55
55
|
absoluteDeviceNativeRequirements,
|
|
@@ -16768,15 +16768,15 @@ var require_main = __commonJS(function(exports) {
|
|
|
16768
16768
|
|
|
16769
16769
|
// src/cli/scripts/mobile.ts
|
|
16770
16770
|
import {
|
|
16771
|
-
access as
|
|
16772
|
-
mkdir as
|
|
16771
|
+
access as access12,
|
|
16772
|
+
mkdir as mkdir12,
|
|
16773
16773
|
mkdtemp as mkdtemp3,
|
|
16774
16774
|
readFile as readFile16,
|
|
16775
16775
|
rm as rm6,
|
|
16776
16776
|
writeFile as writeFile14
|
|
16777
16777
|
} from "fs/promises";
|
|
16778
|
-
import { createPublicKey } from "crypto";
|
|
16779
|
-
import { join as join13, relative as
|
|
16778
|
+
import { createPublicKey as createPublicKey2 } from "crypto";
|
|
16779
|
+
import { join as join13, relative as relative11, resolve as resolve12 } from "path";
|
|
16780
16780
|
import { createInterface } from "readline/promises";
|
|
16781
16781
|
|
|
16782
16782
|
// src/mobile/nativeDeepLinks.ts
|
|
@@ -19083,8 +19083,8 @@ var waitForAbsoluteAndroidHmrApply = async (session, options) => {
|
|
|
19083
19083
|
};
|
|
19084
19084
|
|
|
19085
19085
|
// src/mobile/releaseDoctor.ts
|
|
19086
|
-
import { access as
|
|
19087
|
-
import { dirname as
|
|
19086
|
+
import { access as access4, readFile as readFile8, readdir as readdir3 } from "fs/promises";
|
|
19087
|
+
import { dirname as dirname5, extname, join as join7, relative as relative3 } from "path";
|
|
19088
19088
|
|
|
19089
19089
|
// src/mobile/mobileBundleInspection.ts
|
|
19090
19090
|
import { createHash } from "crypto";
|
|
@@ -19240,6 +19240,202 @@ var inspectAbsoluteMobileBundle = async (config, projectRoot) => {
|
|
|
19240
19240
|
}
|
|
19241
19241
|
};
|
|
19242
19242
|
|
|
19243
|
+
// src/mobile/updateServer.ts
|
|
19244
|
+
import {
|
|
19245
|
+
createPrivateKey,
|
|
19246
|
+
createPublicKey,
|
|
19247
|
+
X509Certificate
|
|
19248
|
+
} from "crypto";
|
|
19249
|
+
import { access as access3, mkdir as mkdir5 } from "fs/promises";
|
|
19250
|
+
import { dirname as dirname4, isAbsolute, relative as relative2, resolve as resolve4, sep } from "path";
|
|
19251
|
+
import { pathToFileURL } from "url";
|
|
19252
|
+
import { Elysia as Elysia2 } from "elysia";
|
|
19253
|
+
var ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT = 1;
|
|
19254
|
+
var DEFAULT_MOBILE_UPDATE_REGISTRY_MODULE = "mobile.update.ts";
|
|
19255
|
+
var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19256
|
+
var projectPath = (projectRoot, requested) => {
|
|
19257
|
+
const root = resolve4(projectRoot);
|
|
19258
|
+
const path = resolve4(root, requested);
|
|
19259
|
+
const projectRelative = relative2(root, path);
|
|
19260
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep}`) || isAbsolute(projectRelative))
|
|
19261
|
+
throw new TypeError("mobile.updates.server.registry must remain inside the project.");
|
|
19262
|
+
return path;
|
|
19263
|
+
};
|
|
19264
|
+
var isRegistry = (value) => object(value) && [
|
|
19265
|
+
"publishUpdate",
|
|
19266
|
+
"promoteUpdate",
|
|
19267
|
+
"rollbackUpdate",
|
|
19268
|
+
"resolveUpdate",
|
|
19269
|
+
"readUpdateFile"
|
|
19270
|
+
].every((method) => typeof value[method] === "function");
|
|
19271
|
+
var serverMetadata = (value) => {
|
|
19272
|
+
if (!object(value))
|
|
19273
|
+
throw new TypeError("Mobile update registry must export valid absoluteMobileUpdateServer metadata. Run `absolute mobile update provision`.");
|
|
19274
|
+
const { format, provider, storage } = value;
|
|
19275
|
+
if (format !== ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT || storage !== "local" && storage !== "durable" || typeof provider !== "string" || !provider)
|
|
19276
|
+
throw new TypeError("Mobile update registry must export valid absoluteMobileUpdateServer metadata. Run `absolute mobile update provision`.");
|
|
19277
|
+
const metadata = {
|
|
19278
|
+
format: ABSOLUTE_MOBILE_UPDATE_SERVER_FORMAT,
|
|
19279
|
+
provider,
|
|
19280
|
+
storage
|
|
19281
|
+
};
|
|
19282
|
+
return metadata;
|
|
19283
|
+
};
|
|
19284
|
+
var loadAbsoluteMobileUpdateServerModule = async (projectRoot, requestedModulePath = DEFAULT_MOBILE_UPDATE_REGISTRY_MODULE) => {
|
|
19285
|
+
const modulePath = projectPath(projectRoot, requestedModulePath);
|
|
19286
|
+
await access3(modulePath).catch(() => {
|
|
19287
|
+
throw new TypeError(`Mobile update server registry does not exist: ${modulePath}. Run \`absolute mobile update provision\`.`);
|
|
19288
|
+
});
|
|
19289
|
+
const loaded = await import(pathToFileURL(modulePath).href);
|
|
19290
|
+
if (!object(loaded))
|
|
19291
|
+
throw new TypeError("Mobile update registry module has no exports.");
|
|
19292
|
+
const registry = loaded.default ?? loaded.registry;
|
|
19293
|
+
if (!isRegistry(registry))
|
|
19294
|
+
throw new TypeError("Mobile update registry must implement publication, promotion, rollback, resolution, and file reads.");
|
|
19295
|
+
const metadata = serverMetadata(loaded.absoluteMobileUpdateServer);
|
|
19296
|
+
const verifier = loaded.verifyAbsoluteMobileUpdateServer;
|
|
19297
|
+
if (metadata.storage === "durable" && typeof verifier !== "function")
|
|
19298
|
+
throw new TypeError("Mobile update registries marked durable must export verifyAbsoluteMobileUpdateServer(). Re-run `absolute mobile update provision --storage s3 --force` or provide an active durability check.");
|
|
19299
|
+
return {
|
|
19300
|
+
metadata,
|
|
19301
|
+
registry,
|
|
19302
|
+
...typeof verifier === "function" ? {
|
|
19303
|
+
verifyDurability: async () => {
|
|
19304
|
+
await verifier();
|
|
19305
|
+
}
|
|
19306
|
+
} : {}
|
|
19307
|
+
};
|
|
19308
|
+
};
|
|
19309
|
+
var verifyDurableModule = async (module) => {
|
|
19310
|
+
if (module.metadata.storage !== "durable")
|
|
19311
|
+
throw new TypeError("Mobile production updates require durable object storage. Re-run `absolute mobile update provision --storage s3 --force` or configure a durable adapter.");
|
|
19312
|
+
try {
|
|
19313
|
+
await module.verifyDurability?.();
|
|
19314
|
+
} catch (error) {
|
|
19315
|
+
throw new TypeError(`Durable mobile update storage verification failed for ${module.metadata.provider}. Check the bucket, endpoint, credentials, and read/write/delete permissions.`, { cause: error });
|
|
19316
|
+
}
|
|
19317
|
+
};
|
|
19318
|
+
var expoSigningOptions = (config) => {
|
|
19319
|
+
if (!config.updates?.expoCodeSigning)
|
|
19320
|
+
return;
|
|
19321
|
+
const entries = Object.entries(config.updateServer?.expoCodeSigningKeys ?? {});
|
|
19322
|
+
const keys = Object.fromEntries(entries.map(([keyId, key]) => {
|
|
19323
|
+
const privateKey = process.env[key.privateKeyEnv];
|
|
19324
|
+
if (!privateKey)
|
|
19325
|
+
throw new TypeError(`Expo update serving requires ${key.privateKeyEnv} on the trusted server.`);
|
|
19326
|
+
try {
|
|
19327
|
+
const certificate = new X509Certificate(key.certificatePem);
|
|
19328
|
+
const expected = certificate.publicKey.export({
|
|
19329
|
+
format: "der",
|
|
19330
|
+
type: "spki"
|
|
19331
|
+
});
|
|
19332
|
+
const actual = createPublicKey(createPrivateKey(privateKey)).export({
|
|
19333
|
+
format: "der",
|
|
19334
|
+
type: "spki"
|
|
19335
|
+
});
|
|
19336
|
+
if (!expected.equals(actual))
|
|
19337
|
+
throw new Error("key mismatch");
|
|
19338
|
+
} catch (error) {
|
|
19339
|
+
throw new TypeError(`${key.privateKeyEnv} must contain the RSA private key matching Expo update key ${keyId}.`, { cause: error });
|
|
19340
|
+
}
|
|
19341
|
+
return [keyId, { certificate: key.certificatePem, privateKey }];
|
|
19342
|
+
}));
|
|
19343
|
+
return { keys };
|
|
19344
|
+
};
|
|
19345
|
+
var inspectAbsoluteMobileUpdateServer = async (config, projectRoot) => {
|
|
19346
|
+
if (!config.updates)
|
|
19347
|
+
return;
|
|
19348
|
+
const module = await loadAbsoluteMobileUpdateServerModule(projectRoot, config.updateServer?.registryModule);
|
|
19349
|
+
await verifyDurableModule(module);
|
|
19350
|
+
if (config.engine === "expo")
|
|
19351
|
+
expoSigningOptions(config);
|
|
19352
|
+
return module.metadata;
|
|
19353
|
+
};
|
|
19354
|
+
var publicKeysSource = (publicKeys) => JSON.stringify(publicKeys, null, "\t");
|
|
19355
|
+
var renderAbsoluteMobileUpdateRegistry = (options) => {
|
|
19356
|
+
const metadata = `export const absoluteMobileUpdateServer = {
|
|
19357
|
+
format: 1,
|
|
19358
|
+
provider: '${options.storage}',
|
|
19359
|
+
storage: '${options.storage === "local" ? "local" : "durable"}'
|
|
19360
|
+
} as const;`;
|
|
19361
|
+
if (options.storage === "local")
|
|
19362
|
+
return `import { fileURLToPath } from 'node:url';
|
|
19363
|
+
import { localBlobStore } from '@absolutejs/blob/local';
|
|
19364
|
+
import { createMobileUpdateRegistry } from '@absolutejs/deploy/mobile-update';
|
|
19365
|
+
|
|
19366
|
+
${metadata}
|
|
19367
|
+
|
|
19368
|
+
const store = localBlobStore({
|
|
19369
|
+
root: process.env.ABSOLUTE_MOBILE_UPDATE_LOCAL_ROOT ??
|
|
19370
|
+
fileURLToPath(new URL('./.absolutejs/mobile/update-registry/', import.meta.url))
|
|
19371
|
+
});
|
|
19372
|
+
|
|
19373
|
+
export default createMobileUpdateRegistry({
|
|
19374
|
+
publicKeys: ${publicKeysSource(options.publicKeys)},
|
|
19375
|
+
store
|
|
19376
|
+
});
|
|
19377
|
+
`;
|
|
19378
|
+
return `import { randomUUID } from 'node:crypto';
|
|
19379
|
+
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
|
19380
|
+
import { awsS3BlobStore } from '@absolutejs/blob/aws-s3';
|
|
19381
|
+
import { createMobileUpdateRegistry } from '@absolutejs/deploy/mobile-update';
|
|
19382
|
+
|
|
19383
|
+
${metadata}
|
|
19384
|
+
|
|
19385
|
+
const required = (name: string) => {
|
|
19386
|
+
const value = process.env[name];
|
|
19387
|
+
if (!value) throw new Error(\`Missing \${name}\`);
|
|
19388
|
+
return value;
|
|
19389
|
+
};
|
|
19390
|
+
|
|
19391
|
+
const bucket = required('ABSOLUTE_MOBILE_UPDATE_S3_BUCKET');
|
|
19392
|
+
const client = new S3Client({
|
|
19393
|
+
region: process.env.ABSOLUTE_MOBILE_UPDATE_S3_REGION ?? 'auto',
|
|
19394
|
+
forcePathStyle: process.env.ABSOLUTE_MOBILE_UPDATE_S3_FORCE_PATH_STYLE === '1',
|
|
19395
|
+
...(process.env.ABSOLUTE_MOBILE_UPDATE_S3_ENDPOINT
|
|
19396
|
+
? { endpoint: process.env.ABSOLUTE_MOBILE_UPDATE_S3_ENDPOINT }
|
|
19397
|
+
: {})
|
|
19398
|
+
});
|
|
19399
|
+
const store = awsS3BlobStore({ bucket, client });
|
|
19400
|
+
|
|
19401
|
+
export const verifyAbsoluteMobileUpdateServer = async () => {
|
|
19402
|
+
const key = \`absolutejs/mobile-updates/_health/\${randomUUID()}\`;
|
|
19403
|
+
const expected = randomUUID();
|
|
19404
|
+
let stored = false;
|
|
19405
|
+
try {
|
|
19406
|
+
await client.send(new PutObjectCommand({ Bucket: bucket, Key: key, Body: expected }));
|
|
19407
|
+
stored = true;
|
|
19408
|
+
const response = await client.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
|
|
19409
|
+
if ((await response.Body?.transformToString()) !== expected)
|
|
19410
|
+
throw new Error('Durability probe read did not match its write.');
|
|
19411
|
+
} finally {
|
|
19412
|
+
if (stored) await client.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
|
|
19413
|
+
}
|
|
19414
|
+
};
|
|
19415
|
+
|
|
19416
|
+
export default createMobileUpdateRegistry({
|
|
19417
|
+
publicKeys: ${publicKeysSource(options.publicKeys)},
|
|
19418
|
+
store
|
|
19419
|
+
});
|
|
19420
|
+
`;
|
|
19421
|
+
};
|
|
19422
|
+
var writeAbsoluteMobileUpdateRegistry = async (options) => {
|
|
19423
|
+
const path = projectPath(options.projectRoot, options.modulePath ?? DEFAULT_MOBILE_UPDATE_REGISTRY_MODULE);
|
|
19424
|
+
if (!options.force) {
|
|
19425
|
+
await access3(path).then(() => {
|
|
19426
|
+
throw new TypeError(`Mobile update registry already exists: ${path}. Pass --force to replace it.`);
|
|
19427
|
+
}, () => {
|
|
19428
|
+
return;
|
|
19429
|
+
});
|
|
19430
|
+
}
|
|
19431
|
+
await mkdir5(dirname4(path), { recursive: true });
|
|
19432
|
+
await Bun.write(path, renderAbsoluteMobileUpdateRegistry({
|
|
19433
|
+
publicKeys: options.publicKeys,
|
|
19434
|
+
storage: options.storage
|
|
19435
|
+
}));
|
|
19436
|
+
return path;
|
|
19437
|
+
};
|
|
19438
|
+
|
|
19243
19439
|
// src/mobile/releaseDoctor.ts
|
|
19244
19440
|
var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1;
|
|
19245
19441
|
var HMR_ASSET_PATTERN = /(?:__HMR_WS__|hmr-timing|__absolute_target|absolutejs-error-overlay)/u;
|
|
@@ -19262,7 +19458,7 @@ var MANUAL_REVIEW = [
|
|
|
19262
19458
|
];
|
|
19263
19459
|
var pathExists2 = async (path) => {
|
|
19264
19460
|
try {
|
|
19265
|
-
await
|
|
19461
|
+
await access4(path);
|
|
19266
19462
|
return true;
|
|
19267
19463
|
} catch {
|
|
19268
19464
|
return false;
|
|
@@ -19298,6 +19494,16 @@ var warn = (id, detail, path, remediation) => ({
|
|
|
19298
19494
|
remediation,
|
|
19299
19495
|
status: "warn"
|
|
19300
19496
|
});
|
|
19497
|
+
var mobileUpdateServerCheck = async (config, projectRoot) => {
|
|
19498
|
+
if (!config.updates)
|
|
19499
|
+
return;
|
|
19500
|
+
try {
|
|
19501
|
+
const metadata = await inspectAbsoluteMobileUpdateServer(config, projectRoot);
|
|
19502
|
+
return pass("updates.trusted-server", `The trusted update server proved durable ${metadata?.provider ?? "object"} storage read/write/delete access, supports publish/promote/rollback, and has valid server-only signing material.`, config.updateServer?.registryModule);
|
|
19503
|
+
} catch (error) {
|
|
19504
|
+
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.");
|
|
19505
|
+
}
|
|
19506
|
+
};
|
|
19301
19507
|
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19302
19508
|
var readJsonObject = async (path) => {
|
|
19303
19509
|
const value = JSON.parse(await readFile8(path, "utf8"));
|
|
@@ -19445,7 +19651,7 @@ var manifestReleaseCheck = async (manifestPath) => {
|
|
|
19445
19651
|
const source = await readFile8(manifestPath, "utf8");
|
|
19446
19652
|
const cleartext = /android:usesCleartextTraffic=["']true["']/u.test(source);
|
|
19447
19653
|
const networkConfigName = source.match(/android:networkSecurityConfig=["']@xml\/([a-z0-9_]+)["']/u)?.[1];
|
|
19448
|
-
const networkConfigPath = networkConfigName ? join7(
|
|
19654
|
+
const networkConfigPath = networkConfigName ? join7(dirname5(manifestPath), "res", "xml", `${networkConfigName}.xml`) : undefined;
|
|
19449
19655
|
const developmentTrustReference = /android:networkSecurityConfig=["']@xml\/absolutejs_dev_network_security["']/u.test(source);
|
|
19450
19656
|
const developmentTrustContents = networkConfigPath ? await readFile8(networkConfigPath, "utf8").then((value) => value.includes("@raw/absolutejs_dev_ca")).catch(() => false) : false;
|
|
19451
19657
|
const developmentTrust = developmentTrustReference || developmentTrustContents;
|
|
@@ -19657,7 +19863,7 @@ var nativeObservabilityProjectionCheck = async (config, platform) => {
|
|
|
19657
19863
|
return registration && plugin ? pass("android.native-observability", "The Android process-exit collector is projected and registered.", plugin) : fail("android.native-observability", "The Android process-exit collector is missing or unregistered.", plugin ?? sourceRoot, "Run `absolute mobile sync android` before building the release.");
|
|
19658
19864
|
};
|
|
19659
19865
|
var iosNativeSecurityCheck = async (iosRoot) => {
|
|
19660
|
-
const applicationFiles = async (extensions) => (await sourceFiles(iosRoot, extensions)).filter((path) => !
|
|
19866
|
+
const applicationFiles = async (extensions) => (await sourceFiles(iosRoot, extensions)).filter((path) => !relative3(iosRoot, path).split(/[\\/]/u).some((part) => ["Pods", "DerivedData", "build"].includes(part)));
|
|
19661
19867
|
const entitlementPaths = await applicationFiles(new Set([".entitlements"]));
|
|
19662
19868
|
const unsafeEntitlements = await containsPattern(entitlementPaths, /<key>(?:com\.apple\.security\.)?get-task-allow<\/key>\s*<true\s*\/>/u);
|
|
19663
19869
|
if (unsafeEntitlements)
|
|
@@ -19671,12 +19877,12 @@ var iosNativeSecurityCheck = async (iosRoot) => {
|
|
|
19671
19877
|
var iosDeepLinkProjectionCheck = async (config, iosRoot) => {
|
|
19672
19878
|
const infoPath = join7(iosRoot, "App/App/Info.plist");
|
|
19673
19879
|
const entitlementsPath = join7(iosRoot, "App/AbsoluteJS.entitlements");
|
|
19674
|
-
const
|
|
19880
|
+
const projectPath2 = join7(iosRoot, "App/App.xcodeproj/project.pbxproj");
|
|
19675
19881
|
try {
|
|
19676
19882
|
const [info, entitlements, project] = await Promise.all([
|
|
19677
19883
|
readFile8(infoPath, "utf8"),
|
|
19678
19884
|
readFile8(entitlementsPath, "utf8"),
|
|
19679
|
-
readFile8(
|
|
19885
|
+
readFile8(projectPath2, "utf8")
|
|
19680
19886
|
]);
|
|
19681
19887
|
if (config.deepLinkScheme && (!info.includes("<key>CFBundleURLTypes</key>") || !info.includes(`<string>${config.deepLinkScheme}</string>`)))
|
|
19682
19888
|
throw new TypeError("iOS custom URL scheme does not match mobile config.");
|
|
@@ -19761,8 +19967,8 @@ var expoIosPushCapabilityCheck = async (iosRoot, requirements) => {
|
|
|
19761
19967
|
};
|
|
19762
19968
|
var expoIosCapabilityProjectionCheck = async (config, requirements) => {
|
|
19763
19969
|
const iosRoot = join7(config.nativeProjectDirectory, "ios");
|
|
19764
|
-
const
|
|
19765
|
-
const project = await readFile8(
|
|
19970
|
+
const projectPath2 = await uniqueExpoIosFile(iosRoot, "**/*.xcodeproj/project.pbxproj", "Xcode project");
|
|
19971
|
+
const project = await readFile8(projectPath2, "utf8");
|
|
19766
19972
|
const privacy = await expoIosPrivacyCapabilityCheck(iosRoot, project, requirements);
|
|
19767
19973
|
if (privacy)
|
|
19768
19974
|
return privacy;
|
|
@@ -19780,10 +19986,10 @@ var iosCapabilityProjectionCheck = async (config, requirements) => {
|
|
|
19780
19986
|
return fail("mobile.device-capabilities", "iOS system-bar capability is missing its required view-controller setting.", infoPath, "Run `absolute mobile sync ios` to regenerate native capability settings.");
|
|
19781
19987
|
if (requirements.iosPrivacyAccessedApis.length > 0) {
|
|
19782
19988
|
const privacyPath = join7(appRoot, "PrivacyInfo.xcprivacy");
|
|
19783
|
-
const
|
|
19989
|
+
const projectPath2 = join7(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
19784
19990
|
const [privacy, project] = await Promise.all([
|
|
19785
19991
|
readFile8(privacyPath, "utf8").catch(() => ""),
|
|
19786
|
-
readFile8(
|
|
19992
|
+
readFile8(projectPath2, "utf8").catch(() => "")
|
|
19787
19993
|
]);
|
|
19788
19994
|
const missing = requirements.iosPrivacyAccessedApis.some(({ api, reasons }) => !privacy.includes(`<string>${api}</string>`) || reasons.some((reason) => !privacy.includes(`<string>${reason}</string>`)));
|
|
19789
19995
|
if (missing || !project.includes("PrivacyInfo.xcprivacy in Resources"))
|
|
@@ -19856,7 +20062,7 @@ var inspectAndroidRelease = async (config, projectRoot) => {
|
|
|
19856
20062
|
]);
|
|
19857
20063
|
return checks.filter((check) => check !== undefined).map((check) => ({
|
|
19858
20064
|
...check,
|
|
19859
|
-
path: check.path ?
|
|
20065
|
+
path: check.path ? relative3(projectRoot, check.path).replaceAll("\\", "/") || "." : undefined
|
|
19860
20066
|
}));
|
|
19861
20067
|
};
|
|
19862
20068
|
var inspectExpoAndroidRelease = async (config, projectRoot) => {
|
|
@@ -19878,7 +20084,7 @@ var inspectExpoAndroidRelease = async (config, projectRoot) => {
|
|
|
19878
20084
|
]);
|
|
19879
20085
|
return checks.filter((check) => check !== undefined).map((check) => ({
|
|
19880
20086
|
...check,
|
|
19881
|
-
path: check.path ?
|
|
20087
|
+
path: check.path ? relative3(projectRoot, check.path).replaceAll("\\", "/") || "." : undefined
|
|
19882
20088
|
}));
|
|
19883
20089
|
};
|
|
19884
20090
|
var uniqueExpoIosFile = async (iosRoot, pattern, label) => {
|
|
@@ -19892,7 +20098,7 @@ var uniqueExpoIosFile = async (iosRoot, pattern, label) => {
|
|
|
19892
20098
|
};
|
|
19893
20099
|
var expoIosNativeProjectionCheck = async (config, iosRoot) => {
|
|
19894
20100
|
try {
|
|
19895
|
-
const [infoPath, entitlementsPath,
|
|
20101
|
+
const [infoPath, entitlementsPath, projectPath2] = await Promise.all([
|
|
19896
20102
|
uniqueExpoIosFile(iosRoot, "**/Info.plist", "Info.plist"),
|
|
19897
20103
|
uniqueExpoIosFile(iosRoot, "**/*.entitlements", "entitlements"),
|
|
19898
20104
|
uniqueExpoIosFile(iosRoot, "**/*.xcodeproj/project.pbxproj", "Xcode project")
|
|
@@ -19900,7 +20106,7 @@ var expoIosNativeProjectionCheck = async (config, iosRoot) => {
|
|
|
19900
20106
|
const [info, entitlements, project] = await Promise.all([
|
|
19901
20107
|
readFile8(infoPath, "utf8"),
|
|
19902
20108
|
readFile8(entitlementsPath, "utf8"),
|
|
19903
|
-
readFile8(
|
|
20109
|
+
readFile8(projectPath2, "utf8")
|
|
19904
20110
|
]);
|
|
19905
20111
|
if (/<key>NSAllowsArbitraryLoads<\/key>\s*<true\s*\/>/u.test(info))
|
|
19906
20112
|
throw new TypeError("Expo iOS App Transport Security permits arbitrary network loads.");
|
|
@@ -19936,7 +20142,7 @@ var inspectExpoIosRelease = async (config, projectRoot) => {
|
|
|
19936
20142
|
checks.push(nativeObservability);
|
|
19937
20143
|
return checks.map((check) => ({
|
|
19938
20144
|
...check,
|
|
19939
|
-
path: check.path ?
|
|
20145
|
+
path: check.path ? relative3(projectRoot, check.path).replaceAll("\\", "/") || "." : undefined
|
|
19940
20146
|
}));
|
|
19941
20147
|
};
|
|
19942
20148
|
var inspectIosRelease = async (config, projectRoot) => {
|
|
@@ -19978,7 +20184,7 @@ var inspectIosRelease = async (config, projectRoot) => {
|
|
|
19978
20184
|
checks.push(updateWatchdog);
|
|
19979
20185
|
return checks.map((check) => ({
|
|
19980
20186
|
...check,
|
|
19981
|
-
path: check.path ?
|
|
20187
|
+
path: check.path ? relative3(projectRoot, check.path).replaceAll("\\", "/") || "." : undefined
|
|
19982
20188
|
}));
|
|
19983
20189
|
};
|
|
19984
20190
|
var createAbsoluteMobileComplianceReport = (config, result) => {
|
|
@@ -20006,11 +20212,12 @@ var inspectAbsoluteMobileRelease = async (config, projectRoot) => {
|
|
|
20006
20212
|
Promise.resolve(productionOriginCheck(config, projectRoot)),
|
|
20007
20213
|
Promise.resolve(associationIdentityCheck(config, projectRoot)),
|
|
20008
20214
|
dependencyLockCheck(projectRoot),
|
|
20009
|
-
config.engine === "expo" ? expoVersionCheck(config) : capacitorVersionCheck(config, projectRoot)
|
|
20215
|
+
config.engine === "expo" ? expoVersionCheck(config) : capacitorVersionCheck(config, projectRoot),
|
|
20216
|
+
mobileUpdateServerCheck(config, projectRoot)
|
|
20010
20217
|
]);
|
|
20011
|
-
const checks = globalChecks.map((check) => ({
|
|
20218
|
+
const checks = globalChecks.filter((check) => check !== undefined).map((check) => ({
|
|
20012
20219
|
...check,
|
|
20013
|
-
path: check.path ?
|
|
20220
|
+
path: check.path ? relative3(projectRoot, check.path).replaceAll("\\", "/") || "." : undefined
|
|
20014
20221
|
}));
|
|
20015
20222
|
if (config.platforms.includes("android"))
|
|
20016
20223
|
checks.push(...config.engine === "expo" ? await inspectExpoAndroidRelease(config, projectRoot) : await inspectAndroidRelease(config, projectRoot));
|
|
@@ -20020,13 +20227,13 @@ var inspectAbsoluteMobileRelease = async (config, projectRoot) => {
|
|
|
20020
20227
|
if (syncSchema) {
|
|
20021
20228
|
checks.push({
|
|
20022
20229
|
...syncSchema,
|
|
20023
|
-
path: syncSchema.path ?
|
|
20230
|
+
path: syncSchema.path ? relative3(projectRoot, syncSchema.path).replaceAll("\\", "/") || "." : undefined
|
|
20024
20231
|
});
|
|
20025
20232
|
}
|
|
20026
20233
|
const deviceCapabilities = await deviceCapabilityReleaseCheck(config, projectRoot);
|
|
20027
20234
|
checks.push({
|
|
20028
20235
|
...deviceCapabilities,
|
|
20029
|
-
path: deviceCapabilities.path ?
|
|
20236
|
+
path: deviceCapabilities.path ? relative3(projectRoot, deviceCapabilities.path).replaceAll("\\", "/") || "." : undefined
|
|
20030
20237
|
});
|
|
20031
20238
|
return {
|
|
20032
20239
|
checks,
|
|
@@ -20037,9 +20244,9 @@ var inspectAbsoluteMobileRelease = async (config, projectRoot) => {
|
|
|
20037
20244
|
// src/mobile/androidRelease.ts
|
|
20038
20245
|
import { createHash as createHash2 } from "crypto";
|
|
20039
20246
|
import {
|
|
20040
|
-
access as
|
|
20247
|
+
access as access5,
|
|
20041
20248
|
copyFile,
|
|
20042
|
-
mkdir as
|
|
20249
|
+
mkdir as mkdir6,
|
|
20043
20250
|
mkdtemp,
|
|
20044
20251
|
readFile as readFile9,
|
|
20045
20252
|
realpath,
|
|
@@ -20048,7 +20255,7 @@ import {
|
|
|
20048
20255
|
stat as stat2,
|
|
20049
20256
|
writeFile as writeFile8
|
|
20050
20257
|
} from "fs/promises";
|
|
20051
|
-
import { dirname as
|
|
20258
|
+
import { dirname as dirname6, isAbsolute as isAbsolute2, join as join8, relative as relative4, resolve as resolve5, sep as sep2 } from "path";
|
|
20052
20259
|
var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1;
|
|
20053
20260
|
var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20054
20261
|
var requireManifest = (value) => {
|
|
@@ -20063,7 +20270,7 @@ var requireManifest = (value) => {
|
|
|
20063
20270
|
};
|
|
20064
20271
|
var pathExists3 = async (path) => {
|
|
20065
20272
|
try {
|
|
20066
|
-
await
|
|
20273
|
+
await access5(path);
|
|
20067
20274
|
return true;
|
|
20068
20275
|
} catch {
|
|
20069
20276
|
return false;
|
|
@@ -20133,10 +20340,10 @@ var fingerprintExpoAndroidProject = async (nativeDirectory) => {
|
|
|
20133
20340
|
return createHash2("sha256").update(records.join("")).digest("hex");
|
|
20134
20341
|
};
|
|
20135
20342
|
var safeOutputDirectory = (projectRoot, requested) => {
|
|
20136
|
-
const root =
|
|
20137
|
-
const output =
|
|
20138
|
-
const projectRelative =
|
|
20139
|
-
if (projectRelative === ".." || projectRelative.startsWith(`..${
|
|
20343
|
+
const root = resolve5(projectRoot);
|
|
20344
|
+
const output = resolve5(root, requested ?? ".absolutejs/mobile/releases/android");
|
|
20345
|
+
const projectRelative = relative4(root, output);
|
|
20346
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep2}`) || isAbsolute2(projectRelative)) {
|
|
20140
20347
|
throw new TypeError("mobile build --outdir must remain inside the project.");
|
|
20141
20348
|
}
|
|
20142
20349
|
return output;
|
|
@@ -20156,8 +20363,8 @@ var installRelease = async (artifactPath, metadata, outputRoot) => {
|
|
|
20156
20363
|
}
|
|
20157
20364
|
return { artifactPath: destination, metadata: existing, releaseRoot };
|
|
20158
20365
|
}
|
|
20159
|
-
await
|
|
20160
|
-
const staging = await mkdtemp(join8(
|
|
20366
|
+
await mkdir6(dirname6(releaseRoot), { recursive: true });
|
|
20367
|
+
const staging = await mkdtemp(join8(dirname6(releaseRoot), ".android-stage-"));
|
|
20161
20368
|
try {
|
|
20162
20369
|
await copyFile(artifactPath, join8(staging, artifactName));
|
|
20163
20370
|
const complete = {
|
|
@@ -20191,7 +20398,7 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
20191
20398
|
if (options.versionCode !== undefined && (!Number.isSafeInteger(options.versionCode) || options.versionCode < 1 || options.versionCode > 2100000000)) {
|
|
20192
20399
|
throw new TypeError("Android versionCode must be an integer from 1 through 2100000000.");
|
|
20193
20400
|
}
|
|
20194
|
-
const projectRoot =
|
|
20401
|
+
const projectRoot = resolve5(options.projectRoot);
|
|
20195
20402
|
const host = options.host ?? detectAbsoluteMobileHost();
|
|
20196
20403
|
if (options.config.engine === "expo" && host === "wsl") {
|
|
20197
20404
|
throw new TypeError("Expo Android production builds from WSL are not available yet. Run the generated CI workflow on Linux or build from native Windows while the WSL projection is completed.");
|
|
@@ -20369,7 +20576,7 @@ var waitForAbsoluteIosHmrLog = async (options) => {
|
|
|
20369
20576
|
};
|
|
20370
20577
|
|
|
20371
20578
|
// src/mobile/nativeTestReport.ts
|
|
20372
|
-
import { mkdir as
|
|
20579
|
+
import { mkdir as mkdir7, readFile as readFile11, writeFile as writeFile9 } from "fs/promises";
|
|
20373
20580
|
import { join as join9 } from "path";
|
|
20374
20581
|
var secretPattern = /(authorization|access[_ -]?token|refresh[_ -]?token|socket[_ -]?ticket|password|cookie)(\s*[=:]\s*)([^\s,;]+)/giu;
|
|
20375
20582
|
var bearerPattern = /bearer\s+[^\s,;]+/giu;
|
|
@@ -20518,7 +20725,7 @@ ${table(report.manualChecks)}
|
|
|
20518
20725
|
`;
|
|
20519
20726
|
};
|
|
20520
20727
|
var writeAbsoluteNativeTestReport = async (directory, report) => {
|
|
20521
|
-
await
|
|
20728
|
+
await mkdir7(directory, { recursive: true });
|
|
20522
20729
|
const jsonPath = join9(directory, "report.json");
|
|
20523
20730
|
const markdownPath = join9(directory, "report.md");
|
|
20524
20731
|
await Promise.all([
|
|
@@ -20774,9 +20981,9 @@ var createAbsoluteAndroidTestReport = (options) => {
|
|
|
20774
20981
|
};
|
|
20775
20982
|
|
|
20776
20983
|
// src/mobile/releasePublisher.ts
|
|
20777
|
-
import { access as
|
|
20778
|
-
import { isAbsolute as
|
|
20779
|
-
import { pathToFileURL } from "url";
|
|
20984
|
+
import { access as access6 } from "fs/promises";
|
|
20985
|
+
import { isAbsolute as isAbsolute3, relative as relative5, resolve as resolve6, sep as sep3 } from "path";
|
|
20986
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
20780
20987
|
var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
20781
20988
|
if (typeof publisher.prepareIosRelease !== "function") {
|
|
20782
20989
|
throw new TypeError("App Store Connect publishing requires a registry module created with @absolutejs/deploy/app-store-connect.");
|
|
@@ -20801,20 +21008,20 @@ var prepareAbsoluteAndroidRelease = async (publisher, options) => {
|
|
|
20801
21008
|
var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20802
21009
|
var isPublisher = (value) => isRecord5(value) && typeof value.publish === "function";
|
|
20803
21010
|
var publisherModulePath = (projectRoot, requested) => {
|
|
20804
|
-
const root =
|
|
20805
|
-
const path =
|
|
20806
|
-
const projectRelative =
|
|
20807
|
-
if (projectRelative === ".." || projectRelative.startsWith(`..${
|
|
21011
|
+
const root = resolve6(projectRoot);
|
|
21012
|
+
const path = resolve6(root, requested);
|
|
21013
|
+
const projectRelative = relative5(root, path);
|
|
21014
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep3}`) || isAbsolute3(projectRelative)) {
|
|
20808
21015
|
throw new TypeError("mobile publish --registry must remain inside the project.");
|
|
20809
21016
|
}
|
|
20810
21017
|
return path;
|
|
20811
21018
|
};
|
|
20812
21019
|
var loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath) => {
|
|
20813
21020
|
const modulePath = publisherModulePath(projectRoot, requestedModulePath);
|
|
20814
|
-
await
|
|
21021
|
+
await access6(modulePath).catch(() => {
|
|
20815
21022
|
throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
|
|
20816
21023
|
});
|
|
20817
|
-
const loaded = await import(
|
|
21024
|
+
const loaded = await import(pathToFileURL2(modulePath).href);
|
|
20818
21025
|
const publisher = isRecord5(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
20819
21026
|
if (!isPublisher(publisher)) {
|
|
20820
21027
|
throw new TypeError("Native release registry module must default-export a registry with publish(options).");
|
|
@@ -20873,8 +21080,8 @@ var publishAbsoluteIosRelease = async (options) => {
|
|
|
20873
21080
|
};
|
|
20874
21081
|
|
|
20875
21082
|
// src/mobile/mobileInspect.ts
|
|
20876
|
-
import { access as
|
|
20877
|
-
import { join as join10, relative as
|
|
21083
|
+
import { access as access7, readFile as readFile12 } from "fs/promises";
|
|
21084
|
+
import { join as join10, relative as relative6, resolve as resolve7 } from "path";
|
|
20878
21085
|
var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1;
|
|
20879
21086
|
var MOBILE_PACKAGE_NAMES = new Set([
|
|
20880
21087
|
"@absolutejs/absolute",
|
|
@@ -20889,12 +21096,12 @@ var MOBILE_PACKAGE_NAMES = new Set([
|
|
|
20889
21096
|
]);
|
|
20890
21097
|
var isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20891
21098
|
var portablePath2 = (projectRoot, path) => {
|
|
20892
|
-
const value =
|
|
21099
|
+
const value = relative6(resolve7(projectRoot), resolve7(path)).replaceAll("\\", "/");
|
|
20893
21100
|
return value || ".";
|
|
20894
21101
|
};
|
|
20895
21102
|
var pathExists4 = async (path) => {
|
|
20896
21103
|
try {
|
|
20897
|
-
await
|
|
21104
|
+
await access7(path);
|
|
20898
21105
|
return true;
|
|
20899
21106
|
} catch {
|
|
20900
21107
|
return false;
|
|
@@ -21035,8 +21242,8 @@ var renderAbsoluteMobileProjectInspection = (report) => {
|
|
|
21035
21242
|
|
|
21036
21243
|
// src/mobile/ciWorkflow.ts
|
|
21037
21244
|
import { existsSync } from "fs";
|
|
21038
|
-
import { access as
|
|
21039
|
-
import { dirname as
|
|
21245
|
+
import { access as access8, mkdir as mkdir8, readFile as readFile13, writeFile as writeFile10 } from "fs/promises";
|
|
21246
|
+
import { dirname as dirname7, extname as extname2, relative as relative7, resolve as resolve8, sep as sep4 } from "path";
|
|
21040
21247
|
var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1;
|
|
21041
21248
|
var SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/u;
|
|
21042
21249
|
var CI_ENV_INDENTATION = 6;
|
|
@@ -21057,18 +21264,18 @@ var RESERVED_SECRET_NAMES = new Set([
|
|
|
21057
21264
|
]);
|
|
21058
21265
|
var exists2 = async (path) => {
|
|
21059
21266
|
try {
|
|
21060
|
-
await
|
|
21267
|
+
await access8(path);
|
|
21061
21268
|
return true;
|
|
21062
21269
|
} catch {
|
|
21063
21270
|
return false;
|
|
21064
21271
|
}
|
|
21065
21272
|
};
|
|
21066
21273
|
var yamlString = (value) => `'${value.replaceAll("'", "''")}'`;
|
|
21067
|
-
var
|
|
21068
|
-
const root =
|
|
21069
|
-
const path =
|
|
21070
|
-
const portable =
|
|
21071
|
-
if (portable === ".." || portable.startsWith(`..${
|
|
21274
|
+
var projectPath2 = (projectRoot, value, field, options = {}) => {
|
|
21275
|
+
const root = resolve8(projectRoot);
|
|
21276
|
+
const path = resolve8(root, value);
|
|
21277
|
+
const portable = relative7(root, path).replaceAll("\\", "/");
|
|
21278
|
+
if (portable === ".." || portable.startsWith(`..${sep4}`) || portable.startsWith("../") || portable === "") {
|
|
21072
21279
|
throw new TypeError(`${field} must remain inside the project root.`);
|
|
21073
21280
|
}
|
|
21074
21281
|
if (/\r|\n/u.test(portable) || portable.startsWith("-"))
|
|
@@ -21078,11 +21285,11 @@ var projectPath = (projectRoot, value, field, options = {}) => {
|
|
|
21078
21285
|
return portable;
|
|
21079
21286
|
};
|
|
21080
21287
|
var workflowOutputPath = (projectRoot, value) => {
|
|
21081
|
-
const root =
|
|
21082
|
-
const workflows =
|
|
21083
|
-
const path =
|
|
21084
|
-
const portable =
|
|
21085
|
-
if (portable === ".." || portable.startsWith(`..${
|
|
21288
|
+
const root = resolve8(projectRoot);
|
|
21289
|
+
const workflows = resolve8(root, ".github/workflows");
|
|
21290
|
+
const path = resolve8(root, value ?? ".github/workflows/absolute-mobile.yml");
|
|
21291
|
+
const portable = relative7(workflows, path);
|
|
21292
|
+
if (portable === ".." || portable.startsWith(`..${sep4}`) || extname2(path) !== ".yml" && extname2(path) !== ".yaml") {
|
|
21086
21293
|
throw new TypeError("mobile ci github --output must be a .yml or .yaml file inside .github/workflows.");
|
|
21087
21294
|
}
|
|
21088
21295
|
return path;
|
|
@@ -21449,9 +21656,9 @@ var createAbsoluteMobileGithubWorkflow = (options) => {
|
|
|
21449
21656
|
].sort();
|
|
21450
21657
|
const includePublishing = options.includePublishing === true;
|
|
21451
21658
|
const customSecrets = normalizeSecretEnvironment(options.secretEnvironment);
|
|
21452
|
-
const serverEntry =
|
|
21453
|
-
const configPath = options.configPath ?
|
|
21454
|
-
const registryModule =
|
|
21659
|
+
const serverEntry = projectPath2(options.projectRoot, options.serverEntry ?? "server.ts", "mobile ci github server entry");
|
|
21660
|
+
const configPath = options.configPath ? projectPath2(options.projectRoot, options.configPath, "mobile ci github --config") : undefined;
|
|
21661
|
+
const registryModule = projectPath2(options.projectRoot, options.registryModule ?? "mobile.release.ts", "mobile ci github --registry", { allowMissing: !includePublishing });
|
|
21455
21662
|
const environment = commandEnvironment({
|
|
21456
21663
|
configPath,
|
|
21457
21664
|
registryModule,
|
|
@@ -21513,9 +21720,9 @@ var writeAbsoluteMobileGithubWorkflow = async (options) => {
|
|
|
21513
21720
|
const generated = createAbsoluteMobileGithubWorkflow(options);
|
|
21514
21721
|
const previous = await exists2(path) ? await readFile13(path, "utf8") : undefined;
|
|
21515
21722
|
if (previous !== undefined && previous !== generated.workflow && !options.force)
|
|
21516
|
-
throw new TypeError(`${
|
|
21723
|
+
throw new TypeError(`${relative7(options.projectRoot, path)} already exists and differs. Rerun with --force to replace the generated workflow.`);
|
|
21517
21724
|
if (previous !== generated.workflow) {
|
|
21518
|
-
await
|
|
21725
|
+
await mkdir8(dirname7(path), { recursive: true });
|
|
21519
21726
|
await writeFile10(path, generated.workflow);
|
|
21520
21727
|
}
|
|
21521
21728
|
return {
|
|
@@ -21532,7 +21739,7 @@ var writeAbsoluteMobileGithubWorkflow = async (options) => {
|
|
|
21532
21739
|
import { createHash as createHash3, sign, verify } from "crypto";
|
|
21533
21740
|
import {
|
|
21534
21741
|
cp,
|
|
21535
|
-
mkdir as
|
|
21742
|
+
mkdir as mkdir9,
|
|
21536
21743
|
mkdtemp as mkdtemp2,
|
|
21537
21744
|
readdir as readdir4,
|
|
21538
21745
|
readFile as readFile14,
|
|
@@ -21541,7 +21748,7 @@ import {
|
|
|
21541
21748
|
stat as stat4,
|
|
21542
21749
|
writeFile as writeFile11
|
|
21543
21750
|
} from "fs/promises";
|
|
21544
|
-
import { dirname as
|
|
21751
|
+
import { dirname as dirname8, join as join11, relative as relative8, resolve as resolve9 } from "path";
|
|
21545
21752
|
var UPDATE_MANIFEST_FILE = "update.json";
|
|
21546
21753
|
var UPDATE_FILES_DIRECTORY = "files";
|
|
21547
21754
|
var sha256 = (value) => createHash3("sha256").update(value).digest("hex");
|
|
@@ -21553,7 +21760,7 @@ var listFiles = async (root, directory = root) => {
|
|
|
21553
21760
|
return listFiles(root, path);
|
|
21554
21761
|
if (!entry.isFile())
|
|
21555
21762
|
throw new TypeError("Mobile updates cannot contain links or special files.");
|
|
21556
|
-
return [
|
|
21763
|
+
return [relative8(root, path).replaceAll("\\", "/")];
|
|
21557
21764
|
}));
|
|
21558
21765
|
return paths.flat().sort((left, right) => left.localeCompare(right));
|
|
21559
21766
|
};
|
|
@@ -21567,8 +21774,8 @@ var inspectFiles = async (root, paths) => Promise.all(paths.map(async (path) =>
|
|
|
21567
21774
|
}));
|
|
21568
21775
|
var releaseIdFor = (value) => `amu_${sha256(canonicalizeAbsoluteMobileUpdate(value))}`;
|
|
21569
21776
|
var buildAbsoluteMobileUpdate = async (options) => {
|
|
21570
|
-
const bundleDirectory =
|
|
21571
|
-
const outputRoot =
|
|
21777
|
+
const bundleDirectory = resolve9(options.bundleDirectory);
|
|
21778
|
+
const outputRoot = resolve9(options.outputDirectory);
|
|
21572
21779
|
if (outputRoot === bundleDirectory || outputRoot.startsWith(`${bundleDirectory}/`))
|
|
21573
21780
|
throw new TypeError("Mobile update output must be outside the embedded bundle.");
|
|
21574
21781
|
const paths = await listFiles(bundleDirectory);
|
|
@@ -21596,7 +21803,7 @@ var buildAbsoluteMobileUpdate = async (options) => {
|
|
|
21596
21803
|
value: signature.toString("base64")
|
|
21597
21804
|
}
|
|
21598
21805
|
});
|
|
21599
|
-
await
|
|
21806
|
+
await mkdir9(outputRoot, { recursive: true });
|
|
21600
21807
|
const outputDirectory = join11(outputRoot, manifest.releaseId);
|
|
21601
21808
|
const staging = await mkdtemp2(join11(outputRoot, ".stage-"));
|
|
21602
21809
|
try {
|
|
@@ -21619,7 +21826,7 @@ var buildAbsoluteMobileUpdate = async (options) => {
|
|
|
21619
21826
|
outputDirectory
|
|
21620
21827
|
};
|
|
21621
21828
|
};
|
|
21622
|
-
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile14(join11(
|
|
21829
|
+
var readAbsoluteMobileUpdate = async (directory) => parseAbsoluteMobileUpdateManifest(JSON.parse(await readFile14(join11(resolve9(directory), UPDATE_MANIFEST_FILE), "utf8")));
|
|
21623
21830
|
var verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
|
|
21624
21831
|
const manifest = parseAbsoluteMobileUpdateManifest(manifestValue);
|
|
21625
21832
|
const valid = verify("sha256", absoluteMobileUpdateSigningPayload(unsignedAbsoluteMobileUpdate(manifest)), { dsaEncoding: "ieee-p1363", key: publicKey }, Buffer.from(manifest.signature.value, "base64"));
|
|
@@ -21629,11 +21836,11 @@ var verifyAbsoluteMobileUpdateSignature = (manifestValue, publicKey) => {
|
|
|
21629
21836
|
};
|
|
21630
21837
|
|
|
21631
21838
|
// src/mobile/expoUpdate.ts
|
|
21632
|
-
import { access as
|
|
21633
|
-
import { dirname as
|
|
21839
|
+
import { access as access9, mkdir as mkdir10, readFile as readFile15, writeFile as writeFile12 } from "fs/promises";
|
|
21840
|
+
import { dirname as dirname9, extname as extname3, join as join12 } from "path";
|
|
21634
21841
|
var ABSOLUTE_EXPO_UPDATE_DESCRIPTOR = "_absolute/expo-update.json";
|
|
21635
21842
|
var ABSOLUTE_EXPO_UPDATE_FORMAT = 1;
|
|
21636
|
-
var
|
|
21843
|
+
var object2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21637
21844
|
var safePath = (value, field) => {
|
|
21638
21845
|
if (typeof value !== "string" || value.length === 0)
|
|
21639
21846
|
throw new TypeError(`Expo update ${field} is invalid.`);
|
|
@@ -21652,7 +21859,7 @@ var extension = (value, path) => {
|
|
|
21652
21859
|
return value;
|
|
21653
21860
|
};
|
|
21654
21861
|
var asset = (value) => {
|
|
21655
|
-
if (!
|
|
21862
|
+
if (!object2(value))
|
|
21656
21863
|
throw new TypeError("Expo update asset is invalid.");
|
|
21657
21864
|
const path = safePath(value.path, "asset path");
|
|
21658
21865
|
const normalizedExtension = extension(value.extension ?? value.ext, path);
|
|
@@ -21662,9 +21869,9 @@ var asset = (value) => {
|
|
|
21662
21869
|
};
|
|
21663
21870
|
};
|
|
21664
21871
|
var platform = (value) => {
|
|
21665
|
-
if (!
|
|
21872
|
+
if (!object2(value) || !Array.isArray(value.assets))
|
|
21666
21873
|
throw new TypeError("Expo update platform metadata is invalid.");
|
|
21667
|
-
const launchValue =
|
|
21874
|
+
const launchValue = object2(value.launchAsset) ? value.launchAsset : { path: value.bundle };
|
|
21668
21875
|
const launchPath = safePath(launchValue.path, "launch bundle");
|
|
21669
21876
|
const launchExtension = extension(launchValue.extension ?? null, launchPath);
|
|
21670
21877
|
const assets = value.assets.map(asset);
|
|
@@ -21677,7 +21884,7 @@ var platform = (value) => {
|
|
|
21677
21884
|
};
|
|
21678
21885
|
};
|
|
21679
21886
|
var parseAbsoluteExpoUpdateDescriptor = (value) => {
|
|
21680
|
-
if (!
|
|
21887
|
+
if (!object2(value) || value.engine !== "expo" || value.format !== ABSOLUTE_EXPO_UPDATE_FORMAT || !object2(value.expoConfig) || !object2(value.platforms) || typeof value.runtimeVersion !== "string" || !/^[a-f0-9]{64}$/u.test(value.runtimeVersion))
|
|
21681
21888
|
throw new TypeError("AbsoluteJS Expo update descriptor is invalid.");
|
|
21682
21889
|
const platforms = {};
|
|
21683
21890
|
for (const name of ["android", "ios"]) {
|
|
@@ -21697,7 +21904,7 @@ var parseAbsoluteExpoUpdateDescriptor = (value) => {
|
|
|
21697
21904
|
};
|
|
21698
21905
|
var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
21699
21906
|
const metadata = JSON.parse(await readFile15(join12(options.exportDirectory, "metadata.json"), "utf8"));
|
|
21700
|
-
if (!
|
|
21907
|
+
if (!object2(metadata) || !object2(metadata.fileMetadata))
|
|
21701
21908
|
throw new TypeError("Expo export metadata.json is invalid.");
|
|
21702
21909
|
const descriptor = parseAbsoluteExpoUpdateDescriptor({
|
|
21703
21910
|
engine: "expo",
|
|
@@ -21707,11 +21914,11 @@ var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
|
21707
21914
|
runtimeVersion: options.runtimeVersion
|
|
21708
21915
|
});
|
|
21709
21916
|
const referenced = Object.values(descriptor.platforms).flatMap((entry) => entry ? [entry.launchAsset, ...entry.assets] : []);
|
|
21710
|
-
await Promise.all(referenced.map(({ path }) =>
|
|
21917
|
+
await Promise.all(referenced.map(({ path }) => access9(join12(options.exportDirectory, path)).catch(() => {
|
|
21711
21918
|
throw new TypeError(`Expo export metadata references missing asset ${path}.`);
|
|
21712
21919
|
})));
|
|
21713
21920
|
const destination = join12(options.exportDirectory, ABSOLUTE_EXPO_UPDATE_DESCRIPTOR);
|
|
21714
|
-
await
|
|
21921
|
+
await mkdir10(dirname9(destination), { recursive: true });
|
|
21715
21922
|
await writeFile12(destination, `${JSON.stringify(descriptor, null, "\t")}
|
|
21716
21923
|
`);
|
|
21717
21924
|
return { descriptor, path: destination };
|
|
@@ -21719,18 +21926,18 @@ var finalizeAbsoluteExpoUpdateExport = async (options) => {
|
|
|
21719
21926
|
|
|
21720
21927
|
// src/mobile/expoCodeSigning.ts
|
|
21721
21928
|
var import_code_signing_certificates = __toESM(require_main(), 1);
|
|
21722
|
-
import { access as
|
|
21723
|
-
import { dirname as
|
|
21724
|
-
var exists3 = async (path) =>
|
|
21929
|
+
import { access as access10, mkdir as mkdir11, writeFile as writeFile13 } from "fs/promises";
|
|
21930
|
+
import { dirname as dirname10, isAbsolute as isAbsolute4, relative as relative9, resolve as resolve10, sep as sep5 } from "path";
|
|
21931
|
+
var exists3 = async (path) => access10(path).then(() => true).catch(() => false);
|
|
21725
21932
|
var inside = (root, path) => {
|
|
21726
|
-
const location =
|
|
21727
|
-
return location === "" || location !== ".." && !location.startsWith(`..${
|
|
21933
|
+
const location = relative9(root, path);
|
|
21934
|
+
return location === "" || location !== ".." && !location.startsWith(`..${sep5}`) && !isAbsolute4(location);
|
|
21728
21935
|
};
|
|
21729
21936
|
var generateAbsoluteExpoCodeSigning = async (options) => {
|
|
21730
|
-
const root =
|
|
21731
|
-
const certificatePath =
|
|
21732
|
-
const privateKeyPath =
|
|
21733
|
-
const publicKeyPath =
|
|
21937
|
+
const root = resolve10(options.projectRoot);
|
|
21938
|
+
const certificatePath = resolve10(root, options.certificatePath);
|
|
21939
|
+
const privateKeyPath = resolve10(root, options.privateKeyPath);
|
|
21940
|
+
const publicKeyPath = resolve10(root, options.publicKeyPath ?? resolve10(dirname10(privateKeyPath), "public-key.pem"));
|
|
21734
21941
|
if (!inside(root, certificatePath))
|
|
21735
21942
|
throw new TypeError("Expo code-signing certificate must be written inside the project so store builds can embed it.");
|
|
21736
21943
|
if (inside(root, privateKeyPath) || inside(root, publicKeyPath))
|
|
@@ -21760,7 +21967,7 @@ var generateAbsoluteExpoCodeSigning = async (options) => {
|
|
|
21760
21967
|
import_code_signing_certificates.validateSelfSignedCertificate(certificate, keyPair);
|
|
21761
21968
|
const { privateKeyPEM, publicKeyPEM } = import_code_signing_certificates.convertKeyPairToPEM(keyPair);
|
|
21762
21969
|
const certificatePem = import_code_signing_certificates.convertCertificateToCertificatePEM(certificate);
|
|
21763
|
-
await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) =>
|
|
21970
|
+
await Promise.all([certificatePath, privateKeyPath, publicKeyPath].map((path) => mkdir11(dirname10(path), { recursive: true })));
|
|
21764
21971
|
await Promise.all([
|
|
21765
21972
|
writeFile13(certificatePath, certificatePem, { flag: "wx", mode: 420 }),
|
|
21766
21973
|
writeFile13(privateKeyPath, privateKeyPEM, { flag: "wx", mode: 384 }),
|
|
@@ -21775,26 +21982,26 @@ var generateAbsoluteExpoCodeSigning = async (options) => {
|
|
|
21775
21982
|
};
|
|
21776
21983
|
|
|
21777
21984
|
// src/mobile/updatePublisher.ts
|
|
21778
|
-
import { access as
|
|
21779
|
-
import { isAbsolute as
|
|
21780
|
-
import { pathToFileURL as
|
|
21781
|
-
var
|
|
21782
|
-
var isPublisher2 = (value) =>
|
|
21783
|
-
var
|
|
21784
|
-
const root =
|
|
21785
|
-
const path =
|
|
21786
|
-
const projectRelative =
|
|
21787
|
-
if (projectRelative === ".." || projectRelative.startsWith(`..${
|
|
21985
|
+
import { access as access11 } from "fs/promises";
|
|
21986
|
+
import { isAbsolute as isAbsolute5, relative as relative10, resolve as resolve11, sep as sep6 } from "path";
|
|
21987
|
+
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
21988
|
+
var object3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21989
|
+
var isPublisher2 = (value) => object3(value) && typeof value.publishUpdate === "function" && typeof value.promoteUpdate === "function" && typeof value.rollbackUpdate === "function";
|
|
21990
|
+
var projectPath3 = (projectRoot, requested, label) => {
|
|
21991
|
+
const root = resolve11(projectRoot);
|
|
21992
|
+
const path = resolve11(root, requested);
|
|
21993
|
+
const projectRelative = relative10(root, path);
|
|
21994
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep6}`) || isAbsolute5(projectRelative))
|
|
21788
21995
|
throw new TypeError(`${label} must remain inside the project.`);
|
|
21789
21996
|
return path;
|
|
21790
21997
|
};
|
|
21791
21998
|
var loadAbsoluteMobileUpdatePublisher = async (projectRoot, requestedModulePath) => {
|
|
21792
|
-
const modulePath =
|
|
21793
|
-
await
|
|
21999
|
+
const modulePath = projectPath3(projectRoot, requestedModulePath, "mobile update registry");
|
|
22000
|
+
await access11(modulePath).catch(() => {
|
|
21794
22001
|
throw new TypeError(`Mobile update registry does not exist: ${modulePath}`);
|
|
21795
22002
|
});
|
|
21796
|
-
const loaded = await import(
|
|
21797
|
-
const publisher =
|
|
22003
|
+
const loaded = await import(pathToFileURL3(modulePath).href);
|
|
22004
|
+
const publisher = object3(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
21798
22005
|
if (!isPublisher2(publisher))
|
|
21799
22006
|
throw new TypeError("Mobile update registry must implement publishUpdate, promoteUpdate, and rollbackUpdate.");
|
|
21800
22007
|
return publisher;
|
|
@@ -21812,7 +22019,7 @@ var promoteAbsoluteMobileUpdate = async (options) => {
|
|
|
21812
22019
|
return result;
|
|
21813
22020
|
};
|
|
21814
22021
|
var publishAbsoluteMobileUpdate = async (options) => {
|
|
21815
|
-
const releaseDirectory =
|
|
22022
|
+
const releaseDirectory = projectPath3(options.projectRoot, options.releaseDirectory, "mobile update release directory");
|
|
21816
22023
|
const manifest = await readAbsoluteMobileUpdate(releaseDirectory);
|
|
21817
22024
|
const result = await options.publisher.publishUpdate({
|
|
21818
22025
|
manifest,
|
|
@@ -21948,7 +22155,7 @@ var requireMobileConfig = (value) => {
|
|
|
21948
22155
|
var capacitorExecutable = async (projectRoot) => {
|
|
21949
22156
|
const executable = join13(projectRoot, "node_modules", ".bin", "cap");
|
|
21950
22157
|
try {
|
|
21951
|
-
await
|
|
22158
|
+
await access12(executable);
|
|
21952
22159
|
return executable;
|
|
21953
22160
|
} catch {
|
|
21954
22161
|
throw new TypeError(`Capacitor is not installed in this app. Run: bun add ${CAPACITOR_PACKAGES.join(" ")}`);
|
|
@@ -21971,7 +22178,7 @@ var runCapacitorForPlatforms = (projectRoot, command, platforms) => platforms.re
|
|
|
21971
22178
|
var expoExecutable = async (project) => {
|
|
21972
22179
|
const executable = join13(project, "node_modules", ".bin", "expo");
|
|
21973
22180
|
try {
|
|
21974
|
-
await
|
|
22181
|
+
await access12(executable);
|
|
21975
22182
|
return executable;
|
|
21976
22183
|
} catch {
|
|
21977
22184
|
throw new TypeError("Expo dependencies are not installed in the generated shell. Run `absolute mobile init --yes`.");
|
|
@@ -22206,7 +22413,7 @@ var sync = async (args) => {
|
|
|
22206
22413
|
};
|
|
22207
22414
|
var associations = async (args) => {
|
|
22208
22415
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
22209
|
-
const outputDirectory =
|
|
22416
|
+
const outputDirectory = resolve12(projectRoot, valueAfter(args, "--outdir") ?? ".absolutejs/mobile/associations");
|
|
22210
22417
|
if (args.includes("--verify")) {
|
|
22211
22418
|
const result2 = await verifyAbsoluteMobileAssociationFiles(mobile);
|
|
22212
22419
|
console.log(`Verified ${result2.results.length} hosted association files`);
|
|
@@ -22258,7 +22465,7 @@ var generateGithubCi = async (args) => {
|
|
|
22258
22465
|
const publicResult = {
|
|
22259
22466
|
changed: result.changed,
|
|
22260
22467
|
format: result.format,
|
|
22261
|
-
path:
|
|
22468
|
+
path: relative11(projectRoot, result.path).replaceAll("\\", "/"),
|
|
22262
22469
|
platforms: result.platforms,
|
|
22263
22470
|
publishing: result.publishing,
|
|
22264
22471
|
requiredSecrets: result.requiredSecrets
|
|
@@ -22370,7 +22577,7 @@ var prepareExpoMobileUpdateExport = async (options) => {
|
|
|
22370
22577
|
};
|
|
22371
22578
|
await ensureExpoPackages(mobile.nativeProjectDirectory, options.args);
|
|
22372
22579
|
const temporaryParent = join13(options.projectRoot, ".absolutejs", "mobile", "expo-update-exports");
|
|
22373
|
-
await
|
|
22580
|
+
await mkdir12(temporaryParent, { recursive: true });
|
|
22374
22581
|
const temporaryDirectory = await mkdtemp3(join13(temporaryParent, ".stage-"));
|
|
22375
22582
|
try {
|
|
22376
22583
|
await runExpo(mobile.nativeProjectDirectory, [
|
|
@@ -22430,9 +22637,9 @@ var buildMobileUpdate = async (args) => {
|
|
|
22430
22637
|
const runtimeFingerprint = isRecord6(embedded) ? embedded.nativeRuntime : undefined;
|
|
22431
22638
|
if (typeof runtimeFingerprint !== "string" || !/^[a-f0-9]{64}$/u.test(runtimeFingerprint))
|
|
22432
22639
|
throw new TypeError("Prepared mobile bundle is missing its native runtime fingerprint.");
|
|
22433
|
-
const privateKey = await readFile16(
|
|
22640
|
+
const privateKey = await readFile16(resolve12(projectRoot, signingKeyPath));
|
|
22434
22641
|
const configuredPublicKey = Buffer.from(mobile.updates.publicKeys[keyId], "base64");
|
|
22435
|
-
const derivedPublicKey =
|
|
22642
|
+
const derivedPublicKey = createPublicKey2(privateKey).export({
|
|
22436
22643
|
format: "der",
|
|
22437
22644
|
type: "spki"
|
|
22438
22645
|
});
|
|
@@ -22493,7 +22700,7 @@ var generateExpoUpdateSigning = async (args) => {
|
|
|
22493
22700
|
...valueAfter(args, "--public-key") ? { publicKeyPath: valueAfter(args, "--public-key") } : {},
|
|
22494
22701
|
...validityYears === undefined ? {} : { validityYears }
|
|
22495
22702
|
});
|
|
22496
|
-
const certificatePath =
|
|
22703
|
+
const certificatePath = relative11(projectRoot, result.certificatePath).replaceAll("\\", "/");
|
|
22497
22704
|
sendTelemetryEvent("mobile:update-code-signing-generated", {
|
|
22498
22705
|
engine: "expo",
|
|
22499
22706
|
validityYears: validityYears ?? 10
|
|
@@ -22516,13 +22723,56 @@ var updateRollout = (args, fallback) => {
|
|
|
22516
22723
|
return rollout;
|
|
22517
22724
|
};
|
|
22518
22725
|
var mobileUpdatePublisher = async (args) => {
|
|
22519
|
-
const { projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
22520
|
-
|
|
22726
|
+
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
22727
|
+
if (!mobile.updates || !mobile.updateServer)
|
|
22728
|
+
throw new TypeError("Mobile updates are not configured.");
|
|
22729
|
+
const modulePath = valueAfter(args, "--registry") ?? mobile.updateServer.registryModule;
|
|
22521
22730
|
return {
|
|
22522
22731
|
projectRoot,
|
|
22523
22732
|
publisher: await loadAbsoluteMobileUpdatePublisher(projectRoot, modulePath)
|
|
22524
22733
|
};
|
|
22525
22734
|
};
|
|
22735
|
+
var provisionMobileUpdate = async (args) => {
|
|
22736
|
+
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
22737
|
+
if (!mobile.updates || !mobile.updateServer)
|
|
22738
|
+
throw new TypeError("mobile update provision requires mobile.updates.publicKeys in absolute.config.ts.");
|
|
22739
|
+
const requestedStorage = valueAfter(args, "--storage") ?? "local";
|
|
22740
|
+
if (requestedStorage !== "local" && requestedStorage !== "s3")
|
|
22741
|
+
throw new TypeError("--storage must be local or s3.");
|
|
22742
|
+
const modulePath = valueAfter(args, "--registry") ?? mobile.updateServer.registryModule;
|
|
22743
|
+
const packages = [
|
|
22744
|
+
"@absolutejs/deploy@0.25.6",
|
|
22745
|
+
"@absolutejs/blob@0.5.2",
|
|
22746
|
+
...requestedStorage === "s3" ? [
|
|
22747
|
+
"@aws-sdk/client-s3@3.1095.0",
|
|
22748
|
+
"@aws-sdk/lib-storage@3.1095.0",
|
|
22749
|
+
"@aws-sdk/s3-request-presigner@3.1095.0"
|
|
22750
|
+
] : []
|
|
22751
|
+
];
|
|
22752
|
+
const installed = await directProjectPackages(projectRoot);
|
|
22753
|
+
const missing = packages.filter((spec) => !installed.has(packageNameFromSpec(spec)));
|
|
22754
|
+
await installApprovedPackages(projectRoot, args, `Mobile update serving needs ${missing.map(packageNameFromSpec).join(", ")}. Install them now?`, missing);
|
|
22755
|
+
const path = await writeAbsoluteMobileUpdateRegistry({
|
|
22756
|
+
force: args.includes("--force"),
|
|
22757
|
+
modulePath,
|
|
22758
|
+
projectRoot,
|
|
22759
|
+
publicKeys: mobile.updates.publicKeys,
|
|
22760
|
+
storage: requestedStorage
|
|
22761
|
+
});
|
|
22762
|
+
console.log(`Provisioned ${requestedStorage === "local" ? "local development" : "durable S3-compatible"} mobile update storage in ${relative11(projectRoot, path).replaceAll("\\", "/")}.`);
|
|
22763
|
+
if (requestedStorage === "local")
|
|
22764
|
+
console.log("Production release checks will require durable storage. Re-run with --storage s3 --force before deploying.");
|
|
22765
|
+
else
|
|
22766
|
+
console.log("Set ABSOLUTE_MOBILE_UPDATE_S3_BUCKET and standard AWS credentials on the trusted server; endpoint and region overrides are optional.");
|
|
22767
|
+
const expoSigning = mobile.updates.expoCodeSigning;
|
|
22768
|
+
if (expoSigning) {
|
|
22769
|
+
const signingKey = mobile.updateServer.expoCodeSigningKeys[expoSigning.keyId];
|
|
22770
|
+
if (!signingKey)
|
|
22771
|
+
throw new TypeError("The active Expo server signing key is missing.");
|
|
22772
|
+
console.log(`Set ${signingKey.privateKeyEnv} only on the trusted server.`);
|
|
22773
|
+
}
|
|
22774
|
+
return path;
|
|
22775
|
+
};
|
|
22526
22776
|
var publishMobileUpdate = async (args) => {
|
|
22527
22777
|
const releaseDirectory = args.find((value, index) => {
|
|
22528
22778
|
if (value.startsWith("-"))
|
|
@@ -23144,7 +23394,7 @@ var requireAndroidTestPort = (args, projectRoot) => {
|
|
|
23144
23394
|
}
|
|
23145
23395
|
return { https: args.includes("--https"), port };
|
|
23146
23396
|
}
|
|
23147
|
-
const instances = listLiveInstances().filter((instance2) =>
|
|
23397
|
+
const instances = listLiveInstances().filter((instance2) => resolve12(instance2.cwd) === resolve12(projectRoot) && instance2.source === "dev" && instance2.port !== null);
|
|
23148
23398
|
if (instances.length !== 1) {
|
|
23149
23399
|
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>.");
|
|
23150
23400
|
}
|
|
@@ -23191,8 +23441,8 @@ var selectAndroidSerial = (adb, explicitSerial) => {
|
|
|
23191
23441
|
return selected;
|
|
23192
23442
|
};
|
|
23193
23443
|
var safeArtifactRoot = (projectRoot, value) => {
|
|
23194
|
-
const root =
|
|
23195
|
-
if (root !== projectRoot && !root.startsWith(`${
|
|
23444
|
+
const root = resolve12(projectRoot, value ?? ".absolutejs/mobile/test-artifacts");
|
|
23445
|
+
if (root !== projectRoot && !root.startsWith(`${resolve12(projectRoot)}/`)) {
|
|
23196
23446
|
throw new TypeError("mobile test --artifacts must remain inside the project.");
|
|
23197
23447
|
}
|
|
23198
23448
|
return root;
|
|
@@ -23220,7 +23470,7 @@ var waitForRequestedAndroidHmr = async (args, session, checks, timeoutMs) => {
|
|
|
23220
23470
|
});
|
|
23221
23471
|
};
|
|
23222
23472
|
var writeAndroidFailureArtifacts = async (options) => {
|
|
23223
|
-
await
|
|
23473
|
+
await mkdir12(options.artifactRoot, { recursive: true });
|
|
23224
23474
|
const screenshot = options.session ? await options.session.screenshot(join13(options.artifactRoot, "android-failure.png")).catch(() => {
|
|
23225
23475
|
return;
|
|
23226
23476
|
}) : undefined;
|
|
@@ -23359,14 +23609,14 @@ var requireIosTestContext = (args, projectRoot) => {
|
|
|
23359
23609
|
const port = Number(explicit);
|
|
23360
23610
|
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
23361
23611
|
throw new TypeError("mobile test --port must be a valid TCP port.");
|
|
23362
|
-
const instance2 = listLiveInstances().find((candidate) =>
|
|
23612
|
+
const instance2 = listLiveInstances().find((candidate) => resolve12(candidate.cwd) === resolve12(projectRoot) && candidate.source === "dev" && candidate.port === port);
|
|
23363
23613
|
return {
|
|
23364
23614
|
https: instance2?.https ?? args.includes("--https"),
|
|
23365
23615
|
instance: instance2,
|
|
23366
23616
|
port
|
|
23367
23617
|
};
|
|
23368
23618
|
}
|
|
23369
|
-
const instances = listLiveInstances().filter((instance2) =>
|
|
23619
|
+
const instances = listLiveInstances().filter((instance2) => resolve12(instance2.cwd) === resolve12(projectRoot) && instance2.source === "dev" && instance2.port !== null);
|
|
23370
23620
|
if (instances.length !== 1)
|
|
23371
23621
|
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>.");
|
|
23372
23622
|
const [instance] = instances;
|
|
@@ -23489,7 +23739,7 @@ var requireCapturedCommand = (command, label) => {
|
|
|
23489
23739
|
return result;
|
|
23490
23740
|
};
|
|
23491
23741
|
var writeIosFailureArtifacts = async (options) => {
|
|
23492
|
-
await
|
|
23742
|
+
await mkdir12(options.artifactRoot, { recursive: true });
|
|
23493
23743
|
const screenshot = join13(options.artifactRoot, "ios-failure.png");
|
|
23494
23744
|
const screenshotResult = captureCommand2([
|
|
23495
23745
|
options.xcrun,
|
|
@@ -23527,8 +23777,8 @@ var nativeReportRoot = (args, projectRoot, platform2) => {
|
|
|
23527
23777
|
var absolutejsVersionForReport = async () => {
|
|
23528
23778
|
let absolutejsVersion = process.env.ABSOLUTE_VERSION ?? "unknown";
|
|
23529
23779
|
const versions = await Promise.all([
|
|
23530
|
-
|
|
23531
|
-
|
|
23780
|
+
resolve12(import.meta.dir, "..", "..", "package.json"),
|
|
23781
|
+
resolve12(import.meta.dir, "..", "..", "..", "package.json")
|
|
23532
23782
|
].map((candidate) => readPackageVersionForIosReport(candidate).catch(() => "unknown")));
|
|
23533
23783
|
for (const version of versions) {
|
|
23534
23784
|
if (version === "unknown")
|
|
@@ -23752,7 +24002,7 @@ var testIos = async (args) => {
|
|
|
23752
24002
|
mobile.appId
|
|
23753
24003
|
], "iOS app launch");
|
|
23754
24004
|
await waitForIosHmrClient({ https, port, timeoutMs });
|
|
23755
|
-
await
|
|
24005
|
+
await mkdir12(artifactRoot, { recursive: true });
|
|
23756
24006
|
const screenshot = join13(artifactRoot, "ios-simulator.png");
|
|
23757
24007
|
requireCapturedCommand([xcrun, "simctl", "io", simulator.udid, "screenshot", screenshot], "iOS simulator screenshot");
|
|
23758
24008
|
const hmrApply = await waitForRequestedIosHmr(args, instance, timeoutMs);
|
|
@@ -23895,6 +24145,10 @@ var runMobile = async (args) => {
|
|
|
23895
24145
|
await buildMobileUpdate(args.slice(2));
|
|
23896
24146
|
return;
|
|
23897
24147
|
}
|
|
24148
|
+
if (command === "update" && args[1] === "provision") {
|
|
24149
|
+
await provisionMobileUpdate(args.slice(2));
|
|
24150
|
+
return;
|
|
24151
|
+
}
|
|
23898
24152
|
if (command === "update" && args[1] === "signing" && args[2] === "generate") {
|
|
23899
24153
|
await generateExpoUpdateSigning(args.slice(3));
|
|
23900
24154
|
return;
|
|
@@ -23919,7 +24173,7 @@ var runMobile = async (args) => {
|
|
|
23919
24173
|
await publishIos(args.slice(2));
|
|
23920
24174
|
return;
|
|
23921
24175
|
}
|
|
23922
|
-
throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [inspect [name] [--json] | clean [name] --yes | --json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | inspect [--json] [--require-bundle] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--outdir dir] [--web-outdir dir] [--unsigned] | 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] | publish android [server-entry] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--remote name] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--route path] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--serial id] [--artifacts dir] [--json] | test ios [--device identifier [--remote name] | --udid id] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--artifacts dir] [--json]> [--config path]");
|
|
24176
|
+
throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [inspect [name] [--json] | clean [name] --yes | --json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | inspect [--json] [--require-bundle] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--outdir dir] [--web-outdir dir] [--unsigned] | 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] | publish android [server-entry] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--remote name] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--route path] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--serial id] [--artifacts dir] [--json] | test ios [--device identifier [--remote name] | --udid id] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--artifacts dir] [--json]> [--config path]");
|
|
23923
24177
|
};
|
|
23924
24178
|
export {
|
|
23925
24179
|
runMobile
|