@absolutejs/absolute 0.20.0-beta.48 → 0.20.0-beta.49
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/README.md +3 -1
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/cli/index.js +205 -55
- package/dist/mobile/index.js +26 -5
- package/dist/mobile/index.js.map +4 -4
- package/dist/src/mobile/androidRelease.d.ts +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -284,7 +284,9 @@ The generated workflow keeps signing and provider credentials behind the
|
|
|
284
284
|
An experimental Expo Router hybrid is also available behind
|
|
285
285
|
`mobile.engine: 'expo'`. Explicit React Native routes use native UI while every
|
|
286
286
|
unclaimed AbsoluteJS route remains an embedded, signed web route regardless of
|
|
287
|
-
framework. Capacitor is still the default
|
|
287
|
+
framework. Capacitor is still the default; Expo Android now supports audited,
|
|
288
|
+
signed production AABs, generated CI, and Google Play publishing while Expo iOS
|
|
289
|
+
release automation remains experimental. See the
|
|
288
290
|
[Expo hybrid experiment](docs/MOBILE_EXPO_EXPERIMENT.md).
|
|
289
291
|
For Expo development, `bun dev` now owns the Bun server, Metro development
|
|
290
292
|
client, configured emulator/simulator builds, categorized logs, and both native
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
|
-
// .angular-partial-tmp-
|
|
4
|
+
// .angular-partial-tmp-gW9hwe/src/core/streamingSlotRegistrar.ts
|
|
5
5
|
var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
|
|
6
6
|
var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
|
|
7
7
|
var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
|
-
// .angular-partial-tmp-
|
|
4
|
+
// .angular-partial-tmp-gW9hwe/src/core/streamingSlotRegistrar.ts
|
|
5
5
|
var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
|
|
6
6
|
var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
|
|
7
7
|
var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
|
|
@@ -48,7 +48,7 @@ var warnMissingStreamingSlotCollector = (primitiveName) => {
|
|
|
48
48
|
getWarningController()?.maybeWarn(primitiveName);
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
// .angular-partial-tmp-
|
|
51
|
+
// .angular-partial-tmp-gW9hwe/src/core/streamingSlotRegistry.ts
|
|
52
52
|
var STREAMING_SLOT_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotAsyncLocalStorage");
|
|
53
53
|
var isObjectRecord2 = (value) => Boolean(value) && typeof value === "object";
|
|
54
54
|
var isAsyncLocalStorage = (value) => isObjectRecord2(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
|
package/dist/cli/index.js
CHANGED
|
@@ -19717,7 +19717,7 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
19717
19717
|
path,
|
|
19718
19718
|
remediation,
|
|
19719
19719
|
status: "warn"
|
|
19720
|
-
}), readJsonObject = async (path) => {
|
|
19720
|
+
}), isRecord14 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), readJsonObject = async (path) => {
|
|
19721
19721
|
const value = JSON.parse(await readFile18(path, "utf8"));
|
|
19722
19722
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
19723
19723
|
throw new TypeError("JSON root must be an object.");
|
|
@@ -19759,6 +19759,37 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
19759
19759
|
} catch (error) {
|
|
19760
19760
|
return fail5("mobile.capacitor-versions", error instanceof Error ? error.message : "Capacitor package versions could not be validated.", manifestPath, "Pin @capacitor/core, @capacitor/cli, and each configured platform to exact versions on the same major/minor line, then reinstall.");
|
|
19761
19761
|
}
|
|
19762
|
+
}, satisfiesGeneratedVersion = (declared, installed) => {
|
|
19763
|
+
if (EXACT_VERSION_PATTERN.test(declared))
|
|
19764
|
+
return declared === installed;
|
|
19765
|
+
if (!declared.startsWith("~"))
|
|
19766
|
+
return false;
|
|
19767
|
+
const expected = declared.slice(1).split(".").map(Number);
|
|
19768
|
+
const actual = installed.split(".").map(Number);
|
|
19769
|
+
return actual[0] === expected[0] && actual[1] === expected[1] && (actual[2] ?? NOT_FOUND3) >= (expected[2] ?? 0);
|
|
19770
|
+
}, expoVersionCheck = async (config) => {
|
|
19771
|
+
const manifestPath = join52(config.nativeProjectDirectory, "package.json");
|
|
19772
|
+
try {
|
|
19773
|
+
const manifest = await readJsonObject(manifestPath);
|
|
19774
|
+
const declarations = packageDeclarations(manifest);
|
|
19775
|
+
const required = ["expo", "expo-router", "react", "react-native"];
|
|
19776
|
+
const missingRequired = required.find((name) => !declarations.has(name));
|
|
19777
|
+
if (missingRequired)
|
|
19778
|
+
throw new TypeError(`Generated Expo project is missing ${missingRequired}.`);
|
|
19779
|
+
const installedVersions = await Promise.all([...declarations].map(async ([name, declared]) => ({
|
|
19780
|
+
declared,
|
|
19781
|
+
installed: await readJsonObject(join52(config.nativeProjectDirectory, "node_modules", name, "package.json")),
|
|
19782
|
+
name
|
|
19783
|
+
})));
|
|
19784
|
+
const mismatch = installedVersions.find(({ declared, installed }) => typeof installed.version !== "string" || !satisfiesGeneratedVersion(declared, installed.version));
|
|
19785
|
+
if (mismatch)
|
|
19786
|
+
throw new TypeError(`Generated Expo dependency ${mismatch.name}@${mismatch.declared} does not match its installed version.`);
|
|
19787
|
+
if (!await pathExists6(join52(config.nativeProjectDirectory, "bun.lock")))
|
|
19788
|
+
throw new TypeError("Generated Expo dependency lockfile is missing.");
|
|
19789
|
+
return pass("mobile.expo-versions", `Generated Expo SDK dependencies are pinned, installed, and locked (${declarations.get("expo")}).`, manifestPath);
|
|
19790
|
+
} catch (error) {
|
|
19791
|
+
return fail5("mobile.expo-versions", error instanceof Error ? error.message : "Generated Expo dependency versions could not be validated.", manifestPath, "Run `absolute mobile init --yes`, then rebuild the production Expo project.");
|
|
19792
|
+
}
|
|
19762
19793
|
}, dependencyLockCheck = async (projectRoot) => {
|
|
19763
19794
|
const present = (await Promise.all(LOCK_FILES.map(async (name) => ({
|
|
19764
19795
|
exists: await pathExists6(join52(projectRoot, name)),
|
|
@@ -19850,6 +19881,63 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
19850
19881
|
} catch (error) {
|
|
19851
19882
|
return fail5(`${platform6}.content-security-policy`, error instanceof Error ? error.message : "Packaged shell CSP could not be validated.", path, "Rebuild the production mobile bundle with the AbsoluteJS-generated shell.");
|
|
19852
19883
|
}
|
|
19884
|
+
}, expoApplicationConfigCheck = async (config) => {
|
|
19885
|
+
const path = join52(config.nativeProjectDirectory, "app.json");
|
|
19886
|
+
try {
|
|
19887
|
+
const root = await readJsonObject(path);
|
|
19888
|
+
if (!isRecord14(root.expo))
|
|
19889
|
+
throw new TypeError("Generated Expo application config is invalid.");
|
|
19890
|
+
const { expo } = root;
|
|
19891
|
+
if (expo.name !== config.appName || !isRecord14(expo.android) || expo.android.package !== config.appId) {
|
|
19892
|
+
throw new TypeError("Generated Expo Android identity does not match mobile config.");
|
|
19893
|
+
}
|
|
19894
|
+
if (!isRecord14(expo.runtimeVersion) || expo.runtimeVersion.policy !== "appVersion") {
|
|
19895
|
+
throw new TypeError("Generated Expo runtimeVersion must follow the native app version.");
|
|
19896
|
+
}
|
|
19897
|
+
if (Array.isArray(expo.plugins) && expo.plugins.some((plugin) => typeof plugin === "string" && plugin.includes("withAbsoluteDevelopmentCa"))) {
|
|
19898
|
+
throw new TypeError("Generated Expo production config includes the development CA plugin.");
|
|
19899
|
+
}
|
|
19900
|
+
return pass("expo.app-config", "Expo application identity and runtime policy match the production mobile config.", path);
|
|
19901
|
+
} catch (error) {
|
|
19902
|
+
return fail5("expo.app-config", error instanceof Error ? error.message : "Generated Expo application config could not be validated.", path, "Run `absolute mobile build android`; do not edit the generated Expo project.");
|
|
19903
|
+
}
|
|
19904
|
+
}, expoEmbeddedAssetsCheck = async (config) => {
|
|
19905
|
+
const generated = join52(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
19906
|
+
const assetsRoot = join52(config.nativeProjectDirectory, "assets", "absolute");
|
|
19907
|
+
try {
|
|
19908
|
+
const [source, manifest] = await Promise.all([
|
|
19909
|
+
readFile18(generated, "utf8"),
|
|
19910
|
+
readJsonObject(join52(config.bundleDirectory, "absolute-mobile-manifest.json"))
|
|
19911
|
+
]);
|
|
19912
|
+
if (source.includes("embedded AbsoluteJS bundle is unavailable") || typeof manifest.appBuild !== "string" || !source.includes(JSON.stringify(manifest.appBuild)) || !source.includes(JSON.stringify(config.productionOrigin))) {
|
|
19913
|
+
throw new TypeError("Generated Expo assets do not contain the prepared production release identity.");
|
|
19914
|
+
}
|
|
19915
|
+
const sourceFiles = (await Array.fromAsync(new Bun.Glob("**/*").scan({
|
|
19916
|
+
cwd: config.bundleDirectory,
|
|
19917
|
+
onlyFiles: true
|
|
19918
|
+
}))).sort();
|
|
19919
|
+
const embeddedFiles = (await Array.fromAsync(new Bun.Glob("*.absasset").scan({
|
|
19920
|
+
cwd: assetsRoot,
|
|
19921
|
+
onlyFiles: true
|
|
19922
|
+
}))).sort();
|
|
19923
|
+
if (sourceFiles.length === 0 || sourceFiles.length !== embeddedFiles.length)
|
|
19924
|
+
throw new TypeError("Generated Expo asset count does not match the prepared mobile bundle.");
|
|
19925
|
+
const matches = await Promise.all(sourceFiles.map(async (path, index) => {
|
|
19926
|
+
const embedded = embeddedFiles[index];
|
|
19927
|
+
if (!embedded)
|
|
19928
|
+
return false;
|
|
19929
|
+
const [left, right] = await Promise.all([
|
|
19930
|
+
readFile18(join52(config.bundleDirectory, path)),
|
|
19931
|
+
readFile18(join52(assetsRoot, embedded))
|
|
19932
|
+
]);
|
|
19933
|
+
return left.equals(right);
|
|
19934
|
+
}));
|
|
19935
|
+
if (matches.some((value) => !value))
|
|
19936
|
+
throw new TypeError("Generated Expo asset bytes differ from the prepared mobile bundle.");
|
|
19937
|
+
return pass("expo.bundle-projection", `Expo embeds the complete signed mobile bundle as ${embeddedFiles.length} opaque asset(s).`, generated);
|
|
19938
|
+
} catch (error) {
|
|
19939
|
+
return fail5("expo.bundle-projection", error instanceof Error ? error.message : "Generated Expo assets could not be validated.", generated, "Run `absolute mobile build android` to regenerate and verify the production asset projection.");
|
|
19940
|
+
}
|
|
19853
19941
|
}, sourceFiles = async (root, extensions) => {
|
|
19854
19942
|
if (!await pathExists6(root))
|
|
19855
19943
|
return [];
|
|
@@ -19882,13 +19970,8 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
19882
19970
|
}, androidDeepLinkProjectionCheck = async (config, manifestPath) => {
|
|
19883
19971
|
try {
|
|
19884
19972
|
const source = await readFile18(manifestPath, "utf8");
|
|
19885
|
-
const
|
|
19886
|
-
|
|
19887
|
-
"android.intent.category.BROWSABLE",
|
|
19888
|
-
...config.deepLinkHosts.map((host2) => `android:scheme="https" android:host="${host2}"`),
|
|
19889
|
-
...config.deepLinkScheme ? [`android:scheme="${config.deepLinkScheme}"`] : []
|
|
19890
|
-
];
|
|
19891
|
-
if (required.some((value) => !source.includes(value)))
|
|
19973
|
+
const hasWebHost = (host2) => [...source.matchAll(/<data\b[^>]*>/giu)].some(([tag]) => tag.includes('android:scheme="https"') && tag.includes(`android:host="${host2}"`));
|
|
19974
|
+
if (!source.includes('android:autoVerify="true"') || !source.includes("android.intent.category.BROWSABLE") || config.deepLinkHosts.some((host2) => !hasWebHost(host2)) || config.deepLinkScheme && !source.includes(`android:scheme="${config.deepLinkScheme}"`))
|
|
19892
19975
|
throw new TypeError("Android App Link or custom-scheme projection does not match mobile config.");
|
|
19893
19976
|
return pass("android.deep-links", "Android verified links and custom scheme match the effective mobile config.", manifestPath);
|
|
19894
19977
|
} catch (error) {
|
|
@@ -19997,8 +20080,21 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
19997
20080
|
}, deviceCapabilityReleaseCheck = async (config, projectRoot) => {
|
|
19998
20081
|
const manifestPath = join52(projectRoot, "package.json");
|
|
19999
20082
|
try {
|
|
20000
|
-
const plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot);
|
|
20001
|
-
|
|
20083
|
+
const plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot, config.engine);
|
|
20084
|
+
const assertPackages = async () => {
|
|
20085
|
+
if (config.engine === "capacitor")
|
|
20086
|
+
return assertAbsoluteDeviceCapabilityPackages(projectRoot, plan);
|
|
20087
|
+
const generated = await readJsonObject(join52(config.nativeProjectDirectory, "package.json"));
|
|
20088
|
+
const declarations = packageDeclarations(generated);
|
|
20089
|
+
const missing = plan.requiredPackages.filter((spec) => {
|
|
20090
|
+
const separator = spec.lastIndexOf("@");
|
|
20091
|
+
return declarations.get(spec.slice(0, separator)) !== spec.slice(separator + 1);
|
|
20092
|
+
});
|
|
20093
|
+
if (missing.length > 0)
|
|
20094
|
+
throw new TypeError(`Generated Expo project is missing detected capability packages: ${missing.join(", ")}.`);
|
|
20095
|
+
return;
|
|
20096
|
+
};
|
|
20097
|
+
await assertPackages();
|
|
20002
20098
|
const requirements = absoluteDeviceNativeRequirements(plan);
|
|
20003
20099
|
const androidCheck = await androidDevicePermissionCheck(config, requirements.androidPermissions);
|
|
20004
20100
|
if (androidCheck)
|
|
@@ -20035,6 +20131,26 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
20035
20131
|
...check2,
|
|
20036
20132
|
path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
|
|
20037
20133
|
}));
|
|
20134
|
+
}, inspectExpoAndroidRelease = async (config, projectRoot) => {
|
|
20135
|
+
const androidRoot = join52(config.nativeProjectDirectory, "android");
|
|
20136
|
+
const manifestPath = join52(androidRoot, "app", "src", "main", "AndroidManifest.xml");
|
|
20137
|
+
const journalPath = join52(projectRoot, ".absolutejs", "mobile", "expo-dev-session", "journal.json");
|
|
20138
|
+
const checks = await Promise.all([
|
|
20139
|
+
journalReleaseCheck(journalPath, "android"),
|
|
20140
|
+
expoApplicationConfigCheck(config),
|
|
20141
|
+
expoEmbeddedAssetsCheck(config),
|
|
20142
|
+
manifestReleaseCheck(manifestPath),
|
|
20143
|
+
hmrAssetsReleaseCheck(config.bundleDirectory),
|
|
20144
|
+
embeddedBundleReleaseCheck(config, projectRoot, "android", config.bundleDirectory),
|
|
20145
|
+
contentSecurityPolicyCheck(config, "android", config.bundleDirectory),
|
|
20146
|
+
androidNativeSecurityCheck(androidRoot),
|
|
20147
|
+
androidExportedComponentsCheck(manifestPath),
|
|
20148
|
+
androidDeepLinkProjectionCheck(config, manifestPath)
|
|
20149
|
+
]);
|
|
20150
|
+
return checks.map((check2) => ({
|
|
20151
|
+
...check2,
|
|
20152
|
+
path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
|
|
20153
|
+
}));
|
|
20038
20154
|
}, inspectIosRelease = async (config, projectRoot) => {
|
|
20039
20155
|
const iosAppRoot = join52(config.nativeProjectDirectory, "ios", "App", "App");
|
|
20040
20156
|
const nativeConfigPath = join52(iosAppRoot, "capacitor.config.json");
|
|
@@ -20094,17 +20210,18 @@ var ABSOLUTE_MOBILE_COMPLIANCE_REPORT_FORMAT = 1, HMR_ASSET_PATTERN, RELEASE_ASS
|
|
|
20094
20210
|
Promise.resolve(productionOriginCheck(config, projectRoot)),
|
|
20095
20211
|
Promise.resolve(associationIdentityCheck(config, projectRoot)),
|
|
20096
20212
|
dependencyLockCheck(projectRoot),
|
|
20097
|
-
capacitorVersionCheck(config, projectRoot)
|
|
20213
|
+
config.engine === "expo" ? expoVersionCheck(config) : capacitorVersionCheck(config, projectRoot)
|
|
20098
20214
|
]);
|
|
20099
20215
|
const checks = globalChecks.map((check2) => ({
|
|
20100
20216
|
...check2,
|
|
20101
20217
|
path: check2.path ? relative26(projectRoot, check2.path).replaceAll("\\", "/") || "." : undefined
|
|
20102
20218
|
}));
|
|
20103
20219
|
if (config.platforms.includes("android"))
|
|
20104
|
-
checks.push(...await inspectAndroidRelease(config, projectRoot));
|
|
20105
|
-
if (config.platforms.includes("ios"))
|
|
20106
|
-
checks.push(...
|
|
20107
|
-
|
|
20220
|
+
checks.push(...config.engine === "expo" ? await inspectExpoAndroidRelease(config, projectRoot) : await inspectAndroidRelease(config, projectRoot));
|
|
20221
|
+
if (config.platforms.includes("ios"))
|
|
20222
|
+
checks.push(...config.engine === "expo" ? [
|
|
20223
|
+
fail5("expo.ios-release", "Expo iOS production release automation is not implemented yet.", config.nativeProjectDirectory, "Build Android independently or wait for the Expo iOS signing checkpoint.")
|
|
20224
|
+
] : await inspectIosRelease(config, projectRoot));
|
|
20108
20225
|
const syncSchema = syncSchemaReleaseCheck(projectRoot);
|
|
20109
20226
|
if (syncSchema) {
|
|
20110
20227
|
checks.push({
|
|
@@ -20161,14 +20278,15 @@ import {
|
|
|
20161
20278
|
mkdir as mkdir13,
|
|
20162
20279
|
mkdtemp as mkdtemp6,
|
|
20163
20280
|
readFile as readFile19,
|
|
20281
|
+
realpath as realpath2,
|
|
20164
20282
|
rename as rename13,
|
|
20165
20283
|
rm as rm9,
|
|
20166
20284
|
stat as stat3,
|
|
20167
20285
|
writeFile as writeFile15
|
|
20168
20286
|
} from "fs/promises";
|
|
20169
20287
|
import { dirname as dirname31, isAbsolute as isAbsolute7, join as join53, relative as relative27, resolve as resolve40, sep as sep7 } from "path";
|
|
20170
|
-
var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1,
|
|
20171
|
-
if (!
|
|
20288
|
+
var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord15 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), requireManifest2 = (value) => {
|
|
20289
|
+
if (!isRecord15(value) || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.runtime !== "string") {
|
|
20172
20290
|
throw new TypeError("Invalid embedded AbsoluteJS mobile manifest.");
|
|
20173
20291
|
}
|
|
20174
20292
|
return {
|
|
@@ -20230,7 +20348,18 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord14 = (value) => typeof value ==
|
|
|
20230
20348
|
]);
|
|
20231
20349
|
if (result.exitCode !== 0)
|
|
20232
20350
|
throw new TypeError("jarsigner could not sign the Android App Bundle with the configured CI identity.");
|
|
20233
|
-
}, sha256File2 = async (path) => createHash14("sha256").update(await readFile19(path)).digest("hex"),
|
|
20351
|
+
}, sha256File2 = async (path) => createHash14("sha256").update(await readFile19(path)).digest("hex"), fingerprintExpoAndroidProject = async (nativeDirectory) => {
|
|
20352
|
+
const root = await realpath2(nativeDirectory);
|
|
20353
|
+
const files = await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: root, onlyFiles: true }));
|
|
20354
|
+
const records = await Promise.all(files.filter((path) => {
|
|
20355
|
+
const parts = path.replaceAll("\\", "/").split("/");
|
|
20356
|
+
return !parts.includes(".gradle") && !parts.includes("build");
|
|
20357
|
+
}).sort().map(async (path) => {
|
|
20358
|
+
const contents = await readFile19(join53(root, path));
|
|
20359
|
+
return `${path.replaceAll("\\", "/")}\x00${createHash14("sha256").update(contents).digest("hex")}\x00`;
|
|
20360
|
+
}));
|
|
20361
|
+
return createHash14("sha256").update(records.join("")).digest("hex");
|
|
20362
|
+
}, safeOutputDirectory2 = (projectRoot, requested) => {
|
|
20234
20363
|
const root = resolve40(projectRoot);
|
|
20235
20364
|
const output = resolve40(root, requested ?? ".absolutejs/mobile/releases/android");
|
|
20236
20365
|
const projectRelative = relative27(root, output);
|
|
@@ -20271,7 +20400,7 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord14 = (value) => typeof value ==
|
|
|
20271
20400
|
});
|
|
20272
20401
|
}
|
|
20273
20402
|
}, requireManifestIdentity = (value, expected) => {
|
|
20274
|
-
if (!
|
|
20403
|
+
if (!isRecord15(value)) {
|
|
20275
20404
|
throw new TypeError("Existing Android release metadata is invalid.");
|
|
20276
20405
|
}
|
|
20277
20406
|
const { artifact } = value;
|
|
@@ -20288,6 +20417,9 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord14 = (value) => typeof value ==
|
|
|
20288
20417
|
}
|
|
20289
20418
|
const projectRoot = resolve40(options.projectRoot);
|
|
20290
20419
|
const host2 = options.host ?? detectAbsoluteMobileHost();
|
|
20420
|
+
if (options.config.engine === "expo" && host2 === "wsl") {
|
|
20421
|
+
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.");
|
|
20422
|
+
}
|
|
20291
20423
|
const androidRoot = options.androidRoot ?? process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2);
|
|
20292
20424
|
const nativeDirectory = join53(options.config.nativeProjectDirectory, "android");
|
|
20293
20425
|
const manifest = requireManifest2(JSON.parse(await readFile19(join53(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
@@ -20296,7 +20428,9 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord14 = (value) => typeof value ==
|
|
|
20296
20428
|
}
|
|
20297
20429
|
let { versionCode } = options;
|
|
20298
20430
|
if (options.prepareVersionCode) {
|
|
20299
|
-
const nativeFingerprint = await fingerprintAbsoluteAndroidNativeProject({
|
|
20431
|
+
const nativeFingerprint = options.config.engine === "expo" ? await fingerprintExpoAndroidProject(nativeDirectory) : await fingerprintAbsoluteAndroidNativeProject({
|
|
20432
|
+
nativeDirectory
|
|
20433
|
+
});
|
|
20300
20434
|
const buildIdentity = createHash14("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}`).digest("hex");
|
|
20301
20435
|
versionCode = await options.prepareVersionCode(buildIdentity);
|
|
20302
20436
|
}
|
|
@@ -20305,6 +20439,7 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord14 = (value) => typeof value ==
|
|
|
20305
20439
|
}
|
|
20306
20440
|
const { artifactPath } = await buildAbsoluteAndroidGradleArtifact({
|
|
20307
20441
|
capture: options.capture,
|
|
20442
|
+
env: options.env,
|
|
20308
20443
|
gradleArguments: versionCode === undefined ? [] : [`-Pandroid.injected.version.code=${versionCode}`],
|
|
20309
20444
|
project: {
|
|
20310
20445
|
androidRoot,
|
|
@@ -20345,7 +20480,7 @@ var ABSOLUTE_ANDROID_RELEASE_FORMAT = 1, isRecord14 = (value) => typeof value ==
|
|
|
20345
20480
|
appBuild: manifest.appBuild,
|
|
20346
20481
|
appId: manifest.appId,
|
|
20347
20482
|
bytes,
|
|
20348
|
-
engine:
|
|
20483
|
+
engine: options.config.engine,
|
|
20349
20484
|
format: ABSOLUTE_ANDROID_RELEASE_FORMAT,
|
|
20350
20485
|
platform: "android",
|
|
20351
20486
|
releaseId,
|
|
@@ -20841,7 +20976,7 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
|
20841
20976
|
throw new TypeError("Google Play publisher returned an invalid Android versionCode.");
|
|
20842
20977
|
}
|
|
20843
20978
|
return versionCode;
|
|
20844
|
-
},
|
|
20979
|
+
}, isRecord16 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), isPublisher = (value) => isRecord16(value) && typeof value.publish === "function", publisherModulePath = (projectRoot, requested) => {
|
|
20845
20980
|
const root = resolve41(projectRoot);
|
|
20846
20981
|
const path = resolve41(root, requested);
|
|
20847
20982
|
const projectRelative = relative28(root, path);
|
|
@@ -20855,7 +20990,7 @@ var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
|
20855
20990
|
throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
|
|
20856
20991
|
});
|
|
20857
20992
|
const loaded = await import(pathToFileURL2(modulePath).href);
|
|
20858
|
-
const publisher =
|
|
20993
|
+
const publisher = isRecord16(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
20859
20994
|
if (!isPublisher(publisher)) {
|
|
20860
20995
|
throw new TypeError("Native release registry module must default-export a registry with publish(options).");
|
|
20861
20996
|
}
|
|
@@ -20957,7 +21092,7 @@ var ABSOLUTE_MOBILE_INSPECTION_FORMAT = 1, MOBILE_PACKAGE_NAMES, isObject3 = (va
|
|
|
20957
21092
|
let capabilityIssue;
|
|
20958
21093
|
let plugins = [];
|
|
20959
21094
|
try {
|
|
20960
|
-
const plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot);
|
|
21095
|
+
const plan = resolveAbsoluteDeviceCapabilityPlan(projectRoot, config.engine);
|
|
20961
21096
|
currentCapabilities = plan.capabilities;
|
|
20962
21097
|
plugins = plan.requiredPackages;
|
|
20963
21098
|
} catch {
|
|
@@ -21410,8 +21545,10 @@ ${releaseAuditSteps("ios")}
|
|
|
21410
21545
|
...custom
|
|
21411
21546
|
], createAbsoluteMobileGithubWorkflow = (options) => {
|
|
21412
21547
|
const platforms = [
|
|
21413
|
-
...options.config.platforms
|
|
21548
|
+
...options.config.engine === "expo" ? options.config.platforms.filter((platform6) => platform6 === "android") : options.config.platforms
|
|
21414
21549
|
].sort();
|
|
21550
|
+
if (platforms.length === 0)
|
|
21551
|
+
throw new TypeError("Generated Expo production CI currently requires android in mobile.platforms; Expo iOS release automation is the next checkpoint.");
|
|
21415
21552
|
const includePublishing = options.includePublishing === true;
|
|
21416
21553
|
const customSecrets = normalizeSecretEnvironment(options.secretEnvironment);
|
|
21417
21554
|
const serverEntry = projectPath(options.projectRoot, options.serverEntry ?? "server.ts", "mobile ci github server entry");
|
|
@@ -21486,7 +21623,7 @@ ${bundleAuditSteps}${platforms.includes("android") ? androidJob({ customSecrets,
|
|
|
21486
21623
|
changed: previous !== generated.workflow,
|
|
21487
21624
|
format: ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT,
|
|
21488
21625
|
path,
|
|
21489
|
-
platforms: [...options.config.platforms].sort(),
|
|
21626
|
+
platforms: options.config.engine === "expo" ? options.config.platforms.filter((platform6) => platform6 === "android") : [...options.config.platforms].sort(),
|
|
21490
21627
|
publishing: options.includePublishing === true,
|
|
21491
21628
|
requiredSecrets: generated.requiredSecrets
|
|
21492
21629
|
};
|
|
@@ -21545,14 +21682,14 @@ __export(exports_mobile, {
|
|
|
21545
21682
|
import { access as access16, mkdir as mkdir16, readFile as readFile24, writeFile as writeFile18 } from "fs/promises";
|
|
21546
21683
|
import { join as join56, relative as relative31, resolve as resolve44 } from "path";
|
|
21547
21684
|
import { createInterface } from "readline/promises";
|
|
21548
|
-
var NOT_FOUND4 = -1,
|
|
21685
|
+
var NOT_FOUND4 = -1, isRecord17 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), CAPACITOR_PACKAGES, CAPACITOR_PACKAGE_SPECS, CAPACITOR_SYNC_PACKAGE_SPECS, packageNameFromSpec = (spec) => spec.slice(0, spec.lastIndexOf("@")), directProjectPackages = async (projectRoot) => {
|
|
21549
21686
|
const manifest = JSON.parse(await readFile24(join56(projectRoot, "package.json"), "utf8"));
|
|
21550
|
-
if (!
|
|
21687
|
+
if (!isRecord17(manifest))
|
|
21551
21688
|
throw new TypeError("Application package.json must contain an object.");
|
|
21552
21689
|
const names = new Set;
|
|
21553
21690
|
for (const field of ["dependencies", "devDependencies"]) {
|
|
21554
21691
|
const dependencies = Reflect.get(manifest, field);
|
|
21555
|
-
if (
|
|
21692
|
+
if (isRecord17(dependencies))
|
|
21556
21693
|
for (const name of Object.keys(dependencies))
|
|
21557
21694
|
names.add(name);
|
|
21558
21695
|
}
|
|
@@ -21560,7 +21697,7 @@ var NOT_FOUND4 = -1, isRecord16 = (value) => typeof value === "object" && value
|
|
|
21560
21697
|
}, resolvedPackageVersion = async (projectRoot, packageName) => {
|
|
21561
21698
|
try {
|
|
21562
21699
|
const manifest = JSON.parse(await readFile24(join56(projectRoot, "node_modules", packageName, "package.json"), "utf8"));
|
|
21563
|
-
return
|
|
21700
|
+
return isRecord17(manifest) && typeof manifest.version === "string" ? manifest.version : undefined;
|
|
21564
21701
|
} catch {
|
|
21565
21702
|
return;
|
|
21566
21703
|
}
|
|
@@ -21609,13 +21746,13 @@ var NOT_FOUND4 = -1, isRecord16 = (value) => typeof value === "object" && value
|
|
|
21609
21746
|
}
|
|
21610
21747
|
}, runCapacitor = async (projectRoot, args) => {
|
|
21611
21748
|
const executable = await capacitorExecutable(projectRoot);
|
|
21612
|
-
const
|
|
21749
|
+
const subprocess = Bun.spawn([executable, ...args], {
|
|
21613
21750
|
cwd: projectRoot,
|
|
21614
21751
|
stderr: "inherit",
|
|
21615
21752
|
stdin: "inherit",
|
|
21616
21753
|
stdout: "inherit"
|
|
21617
21754
|
});
|
|
21618
|
-
const exitCode = await
|
|
21755
|
+
const exitCode = await subprocess.exited;
|
|
21619
21756
|
if (exitCode !== 0) {
|
|
21620
21757
|
throw new TypeError(`Capacitor exited with status ${exitCode}.`);
|
|
21621
21758
|
}
|
|
@@ -21627,15 +21764,26 @@ var NOT_FOUND4 = -1, isRecord16 = (value) => typeof value === "object" && value
|
|
|
21627
21764
|
} catch {
|
|
21628
21765
|
throw new TypeError("Expo dependencies are not installed in the generated shell. Run `absolute mobile init --yes`.");
|
|
21629
21766
|
}
|
|
21630
|
-
},
|
|
21767
|
+
}, expoProductionEnvironment = () => {
|
|
21768
|
+
const env6 = { ...process.env };
|
|
21769
|
+
delete env6.ABSOLUTE_EXPO_DEVELOPMENT;
|
|
21770
|
+
delete env6.ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH;
|
|
21771
|
+
delete env6.EXPO_PUBLIC_ABSOLUTE_DEV_ANDROID_ORIGIN;
|
|
21772
|
+
delete env6.EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN;
|
|
21773
|
+
env6.BABEL_ENV = "production";
|
|
21774
|
+
env6.NODE_ENV = "production";
|
|
21775
|
+
return env6;
|
|
21776
|
+
}, runExpo = async (project, args, options = {}) => {
|
|
21631
21777
|
const executable = await expoExecutable(project);
|
|
21632
|
-
const
|
|
21778
|
+
const env6 = options.production ? expoProductionEnvironment() : { ...process.env };
|
|
21779
|
+
const subprocess = Bun.spawn([executable, ...args], {
|
|
21633
21780
|
cwd: project,
|
|
21781
|
+
env: env6,
|
|
21634
21782
|
stderr: "inherit",
|
|
21635
21783
|
stdin: "inherit",
|
|
21636
21784
|
stdout: "inherit"
|
|
21637
21785
|
});
|
|
21638
|
-
const exitCode = await
|
|
21786
|
+
const exitCode = await subprocess.exited;
|
|
21639
21787
|
if (exitCode !== 0)
|
|
21640
21788
|
throw new TypeError(`Expo exited with status ${exitCode}.`);
|
|
21641
21789
|
}, ensureExpoPackages = async (project, args) => {
|
|
@@ -21682,10 +21830,9 @@ var NOT_FOUND4 = -1, isRecord16 = (value) => typeof value === "object" && value
|
|
|
21682
21830
|
}, requireCapacitorEngine = (mobile, command) => {
|
|
21683
21831
|
if (mobile.engine === "capacitor")
|
|
21684
21832
|
return;
|
|
21685
|
-
throw new TypeError(`${command} is not available for the
|
|
21833
|
+
throw new TypeError(`${command} is not available for the Expo engine yet.`);
|
|
21686
21834
|
}, inspectMobile = async (args) => {
|
|
21687
21835
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
21688
|
-
requireCapacitorEngine(mobile, "mobile inspect");
|
|
21689
21836
|
const report = await inspectAbsoluteMobileProject(mobile, projectRoot, {
|
|
21690
21837
|
absolutejsVersion: await absolutejsVersionForReport()
|
|
21691
21838
|
});
|
|
@@ -21741,7 +21888,7 @@ var NOT_FOUND4 = -1, isRecord16 = (value) => typeof value === "object" && value
|
|
|
21741
21888
|
}, initialize = async (args) => {
|
|
21742
21889
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
21743
21890
|
if (mobile.engine === "expo") {
|
|
21744
|
-
console.warn("Experimental: Expo
|
|
21891
|
+
console.warn("Experimental: Expo Android builds and publishing are available; iOS releases and physical-device acceptance are not complete.");
|
|
21745
21892
|
const generated2 = await writeAbsoluteExpoProject(mobile, {
|
|
21746
21893
|
force: args.includes("--force"),
|
|
21747
21894
|
projectRoot
|
|
@@ -21835,7 +21982,6 @@ var NOT_FOUND4 = -1, isRecord16 = (value) => typeof value === "object" && value
|
|
|
21835
21982
|
throw new TypeError("Usage: absolute mobile ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] [--config path]");
|
|
21836
21983
|
const configPath2 = valueAfter(args, "--config");
|
|
21837
21984
|
const { mobile, projectRoot } = await loadMobile(configPath2);
|
|
21838
|
-
requireCapacitorEngine(mobile, "mobile ci github");
|
|
21839
21985
|
const result = await writeAbsoluteMobileGithubWorkflow({
|
|
21840
21986
|
config: mobile,
|
|
21841
21987
|
configPath: configPath2,
|
|
@@ -21901,7 +22047,6 @@ var NOT_FOUND4 = -1, isRecord16 = (value) => typeof value === "object" && value
|
|
|
21901
22047
|
}
|
|
21902
22048
|
}, runReleaseDoctor = async (args) => {
|
|
21903
22049
|
const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
|
|
21904
|
-
requireCapacitorEngine(mobile, "mobile doctor release");
|
|
21905
22050
|
const platform6 = args.find((value) => value === "android" || value === "ios");
|
|
21906
22051
|
const effectiveMobile = platform6 ? { ...mobile, platforms: [platform6] } : mobile;
|
|
21907
22052
|
const result = await inspectAbsoluteMobileRelease(effectiveMobile, projectRoot);
|
|
@@ -22083,31 +22228,37 @@ Mobile release security and compliance checks failed.`);
|
|
|
22083
22228
|
keystorePath,
|
|
22084
22229
|
storePasswordEnvironment: "ABSOLUTE_ANDROID_KEYSTORE_PASSWORD"
|
|
22085
22230
|
};
|
|
22086
|
-
},
|
|
22231
|
+
}, prepareExpoAndroidReleaseProject = async (mobile, projectRoot, args) => {
|
|
22232
|
+
await writeAbsoluteExpoProject(mobile, { projectRoot });
|
|
22233
|
+
await ensureExpoPackages(mobile.nativeProjectDirectory, [...args, "--yes"]);
|
|
22234
|
+
await syncAbsoluteExpoWebAssets(mobile);
|
|
22235
|
+
await runExpo(mobile.nativeProjectDirectory, ["prebuild", "--clean", "--no-install", "--platform", "android"], { production: true });
|
|
22236
|
+
}, prepareCapacitorAndroidReleaseProject = async (mobile, projectRoot) => {
|
|
22237
|
+
await writeAbsoluteCapacitorConfig(mobile, { projectRoot });
|
|
22238
|
+
await runCapacitorForPlatforms(projectRoot, "sync", ["android"]);
|
|
22239
|
+
await applyAbsoluteNativeDeepLinks(mobile, ["android"]);
|
|
22240
|
+
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile, [
|
|
22241
|
+
"android"
|
|
22242
|
+
]);
|
|
22243
|
+
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, ["android"]);
|
|
22244
|
+
}, prepareAndroidReleaseProject = (mobile, projectRoot, args) => mobile.engine === "expo" ? prepareExpoAndroidReleaseProject(mobile, projectRoot, args) : prepareCapacitorAndroidReleaseProject(mobile, projectRoot), buildAndroid = async (args, prepareVersionCode) => {
|
|
22087
22245
|
const configPath2 = valueAfter(args, "--config");
|
|
22088
22246
|
const { mobile, projectRoot } = await loadMobile(configPath2);
|
|
22089
|
-
requireCapacitorEngine(mobile, "mobile build android");
|
|
22090
22247
|
if (!mobile.platforms.includes("android")) {
|
|
22091
22248
|
throw new TypeError("mobile build android requires android in mobile.platforms.");
|
|
22092
22249
|
}
|
|
22093
22250
|
const startedAt = performance.now();
|
|
22094
22251
|
let success = false;
|
|
22095
22252
|
try {
|
|
22096
|
-
|
|
22253
|
+
if (mobile.engine === "capacitor")
|
|
22254
|
+
await repairAbsoluteAndroidDevSession(projectRoot);
|
|
22097
22255
|
await start(mobileBuildServerEntry(args), valueAfter(args, "--web-outdir"), configPath2, { prepareOnly: true });
|
|
22098
|
-
await
|
|
22099
|
-
await runCapacitorForPlatforms(projectRoot, "sync", ["android"]);
|
|
22100
|
-
await applyAbsoluteNativeDeepLinks(mobile, ["android"]);
|
|
22101
|
-
await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile, [
|
|
22102
|
-
"android"
|
|
22103
|
-
]);
|
|
22104
|
-
await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, [
|
|
22105
|
-
"android"
|
|
22106
|
-
]);
|
|
22256
|
+
await prepareAndroidReleaseProject(mobile, projectRoot, args);
|
|
22107
22257
|
await requireAndroidReleaseReady(mobile, projectRoot);
|
|
22108
22258
|
const release = await buildAbsoluteAndroidRelease({
|
|
22109
22259
|
allowUnsigned: args.includes("--unsigned"),
|
|
22110
22260
|
config: mobile,
|
|
22261
|
+
...mobile.engine === "expo" ? { env: expoProductionEnvironment() } : {},
|
|
22111
22262
|
outputDirectory: valueAfter(args, "--outdir"),
|
|
22112
22263
|
projectRoot,
|
|
22113
22264
|
signing: androidCiSigning(),
|
|
@@ -22122,7 +22273,7 @@ Mobile release security and compliance checks failed.`);
|
|
|
22122
22273
|
} finally {
|
|
22123
22274
|
sendTelemetryEvent("mobile:android-release-build", {
|
|
22124
22275
|
durationMs: Math.round(performance.now() - startedAt),
|
|
22125
|
-
engine:
|
|
22276
|
+
engine: mobile.engine,
|
|
22126
22277
|
platform: "android",
|
|
22127
22278
|
success,
|
|
22128
22279
|
type: "aab",
|
|
@@ -22140,7 +22291,6 @@ Mobile release security and compliance checks failed.`);
|
|
|
22140
22291
|
const configPath2 = valueAfter(args, "--config");
|
|
22141
22292
|
const googlePlay = googlePlayTarget(args);
|
|
22142
22293
|
const { mobile, projectRoot } = await loadMobile(configPath2);
|
|
22143
|
-
requireCapacitorEngine(mobile, "mobile publish android");
|
|
22144
22294
|
const startedAt = performance.now();
|
|
22145
22295
|
let reused = false;
|
|
22146
22296
|
let success = false;
|
|
@@ -22653,7 +22803,7 @@ Emulator setup verification:`);
|
|
|
22653
22803
|
return;
|
|
22654
22804
|
});
|
|
22655
22805
|
const status2 = response?.ok ? await response.json().catch(() => null) : null;
|
|
22656
|
-
const targets =
|
|
22806
|
+
const targets = isRecord17(status2) && isRecord17(status2.connectedTargets) ? status2.connectedTargets : undefined;
|
|
22657
22807
|
if (targets && typeof targets["capacitor-ios"] === "number" && targets["capacitor-ios"] > 0)
|
|
22658
22808
|
return;
|
|
22659
22809
|
await Bun.sleep(100);
|
package/dist/mobile/index.js
CHANGED
|
@@ -1653,6 +1653,7 @@ import {
|
|
|
1653
1653
|
mkdir as mkdir3,
|
|
1654
1654
|
mkdtemp as mkdtemp2,
|
|
1655
1655
|
readFile as readFile4,
|
|
1656
|
+
realpath as realpath2,
|
|
1656
1657
|
rename as rename4,
|
|
1657
1658
|
rm as rm3,
|
|
1658
1659
|
stat,
|
|
@@ -2283,6 +2284,18 @@ var signAab = (artifactPath, capture, jarsigner, signing) => {
|
|
|
2283
2284
|
throw new TypeError("jarsigner could not sign the Android App Bundle with the configured CI identity.");
|
|
2284
2285
|
};
|
|
2285
2286
|
var sha256File = async (path) => createHash4("sha256").update(await readFile4(path)).digest("hex");
|
|
2287
|
+
var fingerprintExpoAndroidProject = async (nativeDirectory) => {
|
|
2288
|
+
const root = await realpath2(nativeDirectory);
|
|
2289
|
+
const files = await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: root, onlyFiles: true }));
|
|
2290
|
+
const records = await Promise.all(files.filter((path) => {
|
|
2291
|
+
const parts = path.replaceAll("\\", "/").split("/");
|
|
2292
|
+
return !parts.includes(".gradle") && !parts.includes("build");
|
|
2293
|
+
}).sort().map(async (path) => {
|
|
2294
|
+
const contents = await readFile4(join4(root, path));
|
|
2295
|
+
return `${path.replaceAll("\\", "/")}\x00${createHash4("sha256").update(contents).digest("hex")}\x00`;
|
|
2296
|
+
}));
|
|
2297
|
+
return createHash4("sha256").update(records.join("")).digest("hex");
|
|
2298
|
+
};
|
|
2286
2299
|
var safeOutputDirectory = (projectRoot, requested) => {
|
|
2287
2300
|
const root = resolve3(projectRoot);
|
|
2288
2301
|
const output = resolve3(root, requested ?? ".absolutejs/mobile/releases/android");
|
|
@@ -2344,6 +2357,9 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
2344
2357
|
}
|
|
2345
2358
|
const projectRoot = resolve3(options.projectRoot);
|
|
2346
2359
|
const host = options.host ?? detectAbsoluteMobileHost();
|
|
2360
|
+
if (options.config.engine === "expo" && host === "wsl") {
|
|
2361
|
+
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.");
|
|
2362
|
+
}
|
|
2347
2363
|
const androidRoot = options.androidRoot ?? process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host);
|
|
2348
2364
|
const nativeDirectory = join4(options.config.nativeProjectDirectory, "android");
|
|
2349
2365
|
const manifest = requireManifest(JSON.parse(await readFile4(join4(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
@@ -2352,7 +2368,9 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
2352
2368
|
}
|
|
2353
2369
|
let { versionCode } = options;
|
|
2354
2370
|
if (options.prepareVersionCode) {
|
|
2355
|
-
const nativeFingerprint = await fingerprintAbsoluteAndroidNativeProject({
|
|
2371
|
+
const nativeFingerprint = options.config.engine === "expo" ? await fingerprintExpoAndroidProject(nativeDirectory) : await fingerprintAbsoluteAndroidNativeProject({
|
|
2372
|
+
nativeDirectory
|
|
2373
|
+
});
|
|
2356
2374
|
const buildIdentity = createHash4("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}`).digest("hex");
|
|
2357
2375
|
versionCode = await options.prepareVersionCode(buildIdentity);
|
|
2358
2376
|
}
|
|
@@ -2361,6 +2379,7 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
2361
2379
|
}
|
|
2362
2380
|
const { artifactPath } = await buildAbsoluteAndroidGradleArtifact({
|
|
2363
2381
|
capture: options.capture,
|
|
2382
|
+
env: options.env,
|
|
2364
2383
|
gradleArguments: versionCode === undefined ? [] : [`-Pandroid.injected.version.code=${versionCode}`],
|
|
2365
2384
|
project: {
|
|
2366
2385
|
androidRoot,
|
|
@@ -2401,7 +2420,7 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
2401
2420
|
appBuild: manifest.appBuild,
|
|
2402
2421
|
appId: manifest.appId,
|
|
2403
2422
|
bytes,
|
|
2404
|
-
engine:
|
|
2423
|
+
engine: options.config.engine,
|
|
2405
2424
|
format: ABSOLUTE_ANDROID_RELEASE_FORMAT,
|
|
2406
2425
|
platform: "android",
|
|
2407
2426
|
releaseId,
|
|
@@ -8687,8 +8706,10 @@ var requiredSecrets = (platforms, includePublishing, custom) => [
|
|
|
8687
8706
|
];
|
|
8688
8707
|
var createAbsoluteMobileGithubWorkflow = (options) => {
|
|
8689
8708
|
const platforms = [
|
|
8690
|
-
...options.config.platforms
|
|
8709
|
+
...options.config.engine === "expo" ? options.config.platforms.filter((platform) => platform === "android") : options.config.platforms
|
|
8691
8710
|
].sort();
|
|
8711
|
+
if (platforms.length === 0)
|
|
8712
|
+
throw new TypeError("Generated Expo production CI currently requires android in mobile.platforms; Expo iOS release automation is the next checkpoint.");
|
|
8692
8713
|
const includePublishing = options.includePublishing === true;
|
|
8693
8714
|
const customSecrets = normalizeSecretEnvironment(options.secretEnvironment);
|
|
8694
8715
|
const serverEntry = projectPath(options.projectRoot, options.serverEntry ?? "server.ts", "mobile ci github server entry");
|
|
@@ -8764,7 +8785,7 @@ var writeAbsoluteMobileGithubWorkflow = async (options) => {
|
|
|
8764
8785
|
changed: previous !== generated.workflow,
|
|
8765
8786
|
format: ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT,
|
|
8766
8787
|
path,
|
|
8767
|
-
platforms: [...options.config.platforms].sort(),
|
|
8788
|
+
platforms: options.config.engine === "expo" ? options.config.platforms.filter((platform) => platform === "android") : [...options.config.platforms].sort(),
|
|
8768
8789
|
publishing: options.includePublishing === true,
|
|
8769
8790
|
requiredSecrets: generated.requiredSecrets
|
|
8770
8791
|
};
|
|
@@ -10494,5 +10515,5 @@ export {
|
|
|
10494
10515
|
writeAbsoluteMobileGithubWorkflow
|
|
10495
10516
|
};
|
|
10496
10517
|
|
|
10497
|
-
//# debugId=
|
|
10518
|
+
//# debugId=9EFFDF4D91097A2464756E2164756E21
|
|
10498
10519
|
//# sourceMappingURL=index.js.map
|