@absolutejs/absolute 0.20.0-beta.1 → 0.20.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/cli/index.js +763 -58
- package/dist/index.js +11 -1
- package/dist/index.js.map +3 -3
- package/dist/mobile/index.js +640 -151
- package/dist/mobile/index.js.map +8 -6
- package/dist/src/mobile/androidEmulatorController.d.ts +2 -1
- package/dist/src/mobile/androidRelease.d.ts +4 -0
- package/dist/src/mobile/config.d.ts +1 -0
- package/dist/src/mobile/index.d.ts +2 -0
- package/dist/src/mobile/iosRelease.d.ts +61 -0
- package/dist/src/mobile/releasePublisher.d.ts +130 -0
- package/dist/types/build.d.ts +4 -0
- package/package.json +7 -7
package/dist/mobile/index.js
CHANGED
|
@@ -615,7 +615,7 @@ var verifyAbsoluteMobileCompatibilityProducer = async (release, maxProducerBytes
|
|
|
615
615
|
return release;
|
|
616
616
|
};
|
|
617
617
|
// src/mobile/androidRelease.ts
|
|
618
|
-
import { createHash as
|
|
618
|
+
import { createHash as createHash4 } from "crypto";
|
|
619
619
|
import {
|
|
620
620
|
access as access3,
|
|
621
621
|
copyFile as copyFile2,
|
|
@@ -702,6 +702,7 @@ import {
|
|
|
702
702
|
rm as rm2,
|
|
703
703
|
writeFile as writeFile3
|
|
704
704
|
} from "fs/promises";
|
|
705
|
+
import { createHash as createHash3, randomUUID } from "crypto";
|
|
705
706
|
import {
|
|
706
707
|
dirname,
|
|
707
708
|
isAbsolute,
|
|
@@ -762,6 +763,8 @@ var writeAbsoluteCapacitorConfig = async (config, options) => {
|
|
|
762
763
|
// src/mobile/androidEmulatorController.ts
|
|
763
764
|
init_getDurationString();
|
|
764
765
|
var HASH_RADIX = 16;
|
|
766
|
+
var EXECUTABLE_MODE_MASK = 73;
|
|
767
|
+
var NATIVE_PUBLIC_PATH_SEGMENTS = 5;
|
|
765
768
|
var CAPACITOR_PROJECT_DIRECTORY_PATTERN = /project\(['"](:[^'"]+)['"]\)\.projectDir\s*=\s*new File\(['"]([^'"]+)['"]\)/gu;
|
|
766
769
|
var pathExists = async (path) => {
|
|
767
770
|
try {
|
|
@@ -826,6 +829,75 @@ var throwIfAborted = (signal) => {
|
|
|
826
829
|
return;
|
|
827
830
|
throw new DOMException("Android development startup was cancelled.", "AbortError");
|
|
828
831
|
};
|
|
832
|
+
var nativeDependencySources = async (nativeDirectory) => {
|
|
833
|
+
const settings = await readFile3(join3(nativeDirectory, "capacitor.settings.gradle"), "utf8");
|
|
834
|
+
const pattern = new RegExp(CAPACITOR_PROJECT_DIRECTORY_PATTERN.source, CAPACITOR_PROJECT_DIRECTORY_PATTERN.flags);
|
|
835
|
+
const dependencies = [...settings.matchAll(pattern)].map((match) => ({
|
|
836
|
+
name: (match[1] ?? "").slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_"),
|
|
837
|
+
source: resolve2(nativeDirectory, match[2] ?? "")
|
|
838
|
+
}));
|
|
839
|
+
if (dependencies.length === 0) {
|
|
840
|
+
throw new Error("Capacitor Android settings did not declare any native dependencies.");
|
|
841
|
+
}
|
|
842
|
+
return { dependencies, settings };
|
|
843
|
+
};
|
|
844
|
+
var shouldIgnoreNativePath = (relativePath, ignorePublicBundle) => {
|
|
845
|
+
const parts = relativePath.split(sep);
|
|
846
|
+
if (parts.includes(".gradle") || parts.includes("build") || parts.includes(".absolutejs-dependencies")) {
|
|
847
|
+
return true;
|
|
848
|
+
}
|
|
849
|
+
return ignorePublicBundle && parts.slice(0, NATIVE_PUBLIC_PATH_SEGMENTS).join("/") === "app/src/main/assets/public";
|
|
850
|
+
};
|
|
851
|
+
var collectNativePath = async (root, label, path, isDirectory, isFile, isSymbolicLink, ignorePublicBundle) => {
|
|
852
|
+
const relativePath = relative2(root, path);
|
|
853
|
+
if (shouldIgnoreNativePath(relativePath, ignorePublicBundle))
|
|
854
|
+
return [];
|
|
855
|
+
const identity = `${label}:${relativePath.split(sep).join("/")}\x00`;
|
|
856
|
+
if (isDirectory) {
|
|
857
|
+
return collectNativeDirectory(root, label, path, ignorePublicBundle);
|
|
858
|
+
}
|
|
859
|
+
if (isSymbolicLink) {
|
|
860
|
+
return [`link\x00${identity}${await readlink(path)}\x00`];
|
|
861
|
+
}
|
|
862
|
+
if (!isFile)
|
|
863
|
+
return [];
|
|
864
|
+
const [metadata, contents] = await Promise.all([
|
|
865
|
+
lstat(path),
|
|
866
|
+
readFile3(path)
|
|
867
|
+
]);
|
|
868
|
+
const contentDigest = createHash3("sha256").update(contents).digest("hex");
|
|
869
|
+
return [
|
|
870
|
+
`file\x00${identity}${metadata.mode & EXECUTABLE_MODE_MASK}\x00${contentDigest}\x00`
|
|
871
|
+
];
|
|
872
|
+
};
|
|
873
|
+
var collectNativeDirectory = async (root, label, directory, ignorePublicBundle) => {
|
|
874
|
+
const entries = await readdir2(directory, { withFileTypes: true });
|
|
875
|
+
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
876
|
+
const records = await Promise.all(entries.map((entry) => collectNativePath(root, label, join3(directory, entry.name), entry.isDirectory(), entry.isFile(), entry.isSymbolicLink(), ignorePublicBundle)));
|
|
877
|
+
return records.flat();
|
|
878
|
+
};
|
|
879
|
+
var hashNativeTree = async (root, label, ignorePublicBundle) => {
|
|
880
|
+
const resolvedRoot = await realpath(root);
|
|
881
|
+
const records = await collectNativeDirectory(resolvedRoot, label, resolvedRoot, ignorePublicBundle);
|
|
882
|
+
return createHash3("sha256").update(records.join("")).digest("hex");
|
|
883
|
+
};
|
|
884
|
+
var fingerprintAbsoluteAndroidNativeProject = async (project) => {
|
|
885
|
+
const { dependencies } = await nativeDependencySources(project.nativeDirectory);
|
|
886
|
+
const roots = [
|
|
887
|
+
{
|
|
888
|
+
ignorePublicBundle: true,
|
|
889
|
+
label: "android",
|
|
890
|
+
source: project.nativeDirectory
|
|
891
|
+
},
|
|
892
|
+
...dependencies.sort((left, right) => left.name.localeCompare(right.name)).map((dependency) => ({
|
|
893
|
+
ignorePublicBundle: false,
|
|
894
|
+
label: `dependency:${dependency.name}`,
|
|
895
|
+
source: dependency.source
|
|
896
|
+
}))
|
|
897
|
+
];
|
|
898
|
+
const treeDigests = await Promise.all(roots.map((root) => hashNativeTree(root.source, root.label, root.ignorePublicBundle)));
|
|
899
|
+
return createHash3("sha256").update(treeDigests.join("\x00")).digest("hex");
|
|
900
|
+
};
|
|
829
901
|
var windowsPathFromWsl = (path, capture) => {
|
|
830
902
|
const result = capture(["wslpath", "-w", path]);
|
|
831
903
|
if (result.exitCode !== 0 || !result.stdout.trim()) {
|
|
@@ -851,12 +923,13 @@ var mirroredCapacitorDependencies = async (project, capture) => {
|
|
|
851
923
|
}
|
|
852
924
|
return { dependencies, rewrittenSettings };
|
|
853
925
|
};
|
|
854
|
-
var encodedWindowsGradleCommand = (windowsSource, windowsDirectory, windowsAndroidRoot, dependencies, rewrittenSettings, task) => {
|
|
926
|
+
var encodedWindowsGradleCommand = (windowsSource, windowsDirectory, windowsAndroidRoot, dependencies, rewrittenSettings, task, gradleArguments) => {
|
|
855
927
|
const sourceDirectory = Buffer.from(windowsSource, "utf8").toString("base64");
|
|
856
928
|
const buildDirectory = Buffer.from(windowsDirectory, "utf8").toString("base64");
|
|
857
929
|
const androidRoot = Buffer.from(windowsAndroidRoot, "utf8").toString("base64");
|
|
858
930
|
const dependencyData = Buffer.from(JSON.stringify(dependencies), "utf8").toString("base64");
|
|
859
931
|
const settingsData = Buffer.from(rewrittenSettings, "utf8").toString("base64");
|
|
932
|
+
const argumentsData = Buffer.from(JSON.stringify(gradleArguments), "utf8").toString("base64");
|
|
860
933
|
const source = [
|
|
861
934
|
"$ErrorActionPreference = 'Stop'",
|
|
862
935
|
`$source = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${sourceDirectory}'))`,
|
|
@@ -864,6 +937,7 @@ var encodedWindowsGradleCommand = (windowsSource, windowsDirectory, windowsAndro
|
|
|
864
937
|
`$androidHome = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${androidRoot}'))`,
|
|
865
938
|
`$dependencies = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${dependencyData}')) | ConvertFrom-Json`,
|
|
866
939
|
`$settings = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${settingsData}'))`,
|
|
940
|
+
`$gradleArguments = @([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${argumentsData}')) | ConvertFrom-Json)`,
|
|
867
941
|
"$env:ANDROID_HOME = $androidHome",
|
|
868
942
|
"$env:ANDROID_SDK_ROOT = $androidHome",
|
|
869
943
|
"New-Item -ItemType Directory -Force -Path $directory | Out-Null",
|
|
@@ -873,7 +947,7 @@ var encodedWindowsGradleCommand = (windowsSource, windowsDirectory, windowsAndro
|
|
|
873
947
|
"foreach ($dependency in @($dependencies)) { $target = Join-Path $directory ('.absolutejs-dependencies\\' + $dependency.name); New-Item -ItemType Directory -Force -Path $target | Out-Null; & robocopy.exe $dependency.windowsSource $target /MIR /XD .gradle build /NFL /NDL /NJH /NJS /NP; if ($LASTEXITCODE -ge 8) { exit $LASTEXITCODE } }",
|
|
874
948
|
"[IO.File]::WriteAllText((Join-Path $directory 'capacitor.settings.gradle'), $settings)",
|
|
875
949
|
"$wrapper = Join-Path $directory 'gradlew.bat'",
|
|
876
|
-
`& $wrapper --no-daemon --console=plain -p $directory ${task}`,
|
|
950
|
+
`& $wrapper --no-daemon --console=plain -p $directory @gradleArguments ${task}`,
|
|
877
951
|
"if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }",
|
|
878
952
|
"exit 0"
|
|
879
953
|
].join("; ");
|
|
@@ -901,6 +975,7 @@ var buildAbsoluteAndroidGradleArtifact = async (options) => {
|
|
|
901
975
|
const capture = options.capture ?? captureCommand;
|
|
902
976
|
const run = options.run ?? runCommand;
|
|
903
977
|
const env = options.env ?? process.env;
|
|
978
|
+
const gradleArguments = options.gradleArguments ?? [];
|
|
904
979
|
if (project.host === "wsl") {
|
|
905
980
|
const windowsSource = windowsPathFromWsl(project.nativeDirectory, capture);
|
|
906
981
|
const buildId = Bun.hash(project.projectRoot).toString(HASH_RADIX);
|
|
@@ -912,7 +987,7 @@ var buildAbsoluteAndroidGradleArtifact = async (options) => {
|
|
|
912
987
|
"powershell.exe",
|
|
913
988
|
"-NoProfile",
|
|
914
989
|
"-EncodedCommand",
|
|
915
|
-
encodedWindowsGradleCommand(windowsSource, windowsDirectory, windowsAndroidRoot, dependencies, rewrittenSettings, task)
|
|
990
|
+
encodedWindowsGradleCommand(windowsSource, windowsDirectory, windowsAndroidRoot, dependencies, rewrittenSettings, task, gradleArguments)
|
|
916
991
|
], "Android Gradle build", run, { env, signal: options.signal });
|
|
917
992
|
const artifactPath2 = await resolveGradleArtifactPath(managedBuildDirectory, task);
|
|
918
993
|
const unsigned = artifactPath2.endsWith("-unsigned.apk");
|
|
@@ -922,7 +997,7 @@ var buildAbsoluteAndroidGradleArtifact = async (options) => {
|
|
|
922
997
|
};
|
|
923
998
|
}
|
|
924
999
|
const wrapper = project.host === "windows" ? "gradlew.bat" : "./gradlew";
|
|
925
|
-
await requireSuccess([wrapper, "--no-daemon", "--console=plain", task], "Android Gradle build", run, { cwd: project.nativeDirectory, env, signal: options.signal });
|
|
1000
|
+
await requireSuccess([wrapper, "--no-daemon", "--console=plain", ...gradleArguments, task], "Android Gradle build", run, { cwd: project.nativeDirectory, env, signal: options.signal });
|
|
926
1001
|
const artifactPath = await resolveGradleArtifactPath(project.nativeDirectory, task);
|
|
927
1002
|
return { artifactPath, installPath: artifactPath };
|
|
928
1003
|
};
|
|
@@ -983,7 +1058,7 @@ var verifyAabSignature = (artifactPath, capture, jarsigner) => {
|
|
|
983
1058
|
]);
|
|
984
1059
|
return result.exitCode === 0 && /jar verified/iu.test(result.stdout);
|
|
985
1060
|
};
|
|
986
|
-
var sha256File = async (path) =>
|
|
1061
|
+
var sha256File = async (path) => createHash4("sha256").update(await readFile4(path)).digest("hex");
|
|
987
1062
|
var safeOutputDirectory = (projectRoot, requested) => {
|
|
988
1063
|
const root = resolve3(projectRoot);
|
|
989
1064
|
const output = resolve3(root, requested ?? ".absolutejs/mobile/releases/android");
|
|
@@ -1037,12 +1112,32 @@ var requireManifestIdentity = (value, expected) => {
|
|
|
1037
1112
|
return { ...expected, artifact };
|
|
1038
1113
|
};
|
|
1039
1114
|
var buildAbsoluteAndroidRelease = async (options) => {
|
|
1115
|
+
if (options.versionCode !== undefined && options.prepareVersionCode) {
|
|
1116
|
+
throw new TypeError("Android release versionCode and prepareVersionCode cannot be combined.");
|
|
1117
|
+
}
|
|
1118
|
+
if (options.versionCode !== undefined && (!Number.isSafeInteger(options.versionCode) || options.versionCode < 1 || options.versionCode > 2100000000)) {
|
|
1119
|
+
throw new TypeError("Android versionCode must be an integer from 1 through 2100000000.");
|
|
1120
|
+
}
|
|
1040
1121
|
const projectRoot = resolve3(options.projectRoot);
|
|
1041
1122
|
const host = options.host ?? detectAbsoluteMobileHost();
|
|
1042
1123
|
const androidRoot = options.androidRoot ?? process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host);
|
|
1043
1124
|
const nativeDirectory = join4(options.config.nativeProjectDirectory, "android");
|
|
1125
|
+
const manifest = requireManifest(JSON.parse(await readFile4(join4(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
1126
|
+
if (manifest.appId !== options.config.appId) {
|
|
1127
|
+
throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
|
|
1128
|
+
}
|
|
1129
|
+
let { versionCode } = options;
|
|
1130
|
+
if (options.prepareVersionCode) {
|
|
1131
|
+
const nativeFingerprint = await fingerprintAbsoluteAndroidNativeProject({ nativeDirectory });
|
|
1132
|
+
const buildIdentity = createHash4("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}`).digest("hex");
|
|
1133
|
+
versionCode = await options.prepareVersionCode(buildIdentity);
|
|
1134
|
+
}
|
|
1135
|
+
if (versionCode !== undefined && (!Number.isSafeInteger(versionCode) || versionCode < 1 || versionCode > 2100000000)) {
|
|
1136
|
+
throw new TypeError("Android versionCode must be an integer from 1 through 2100000000.");
|
|
1137
|
+
}
|
|
1044
1138
|
const { artifactPath } = await buildAbsoluteAndroidGradleArtifact({
|
|
1045
1139
|
capture: options.capture,
|
|
1140
|
+
gradleArguments: versionCode === undefined ? [] : [`-Pandroid.injected.version.code=${versionCode}`],
|
|
1046
1141
|
project: {
|
|
1047
1142
|
androidRoot,
|
|
1048
1143
|
config: options.config,
|
|
@@ -1064,10 +1159,6 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
1064
1159
|
if (!signed && !options.allowUnsigned) {
|
|
1065
1160
|
throw new TypeError("Android Gradle produced an unsigned App Bundle. Configure the release signingConfig in the source-owned Android project (prefer external Gradle properties), or pass --unsigned only for a non-publishable build.");
|
|
1066
1161
|
}
|
|
1067
|
-
const manifest = requireManifest(JSON.parse(await readFile4(join4(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
1068
|
-
if (manifest.appId !== options.config.appId) {
|
|
1069
|
-
throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
|
|
1070
|
-
}
|
|
1071
1162
|
const [bytes, sha256] = await Promise.all([
|
|
1072
1163
|
stat(artifactPath).then(({ size }) => size),
|
|
1073
1164
|
sha256File(artifactPath)
|
|
@@ -1084,32 +1175,314 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
1084
1175
|
runtime: manifest.runtime,
|
|
1085
1176
|
sha256,
|
|
1086
1177
|
signed: signed === true,
|
|
1087
|
-
type: "aab"
|
|
1178
|
+
type: "aab",
|
|
1179
|
+
...versionCode === undefined ? {} : { versionCode }
|
|
1088
1180
|
};
|
|
1089
1181
|
return installRelease(artifactPath, metadata, safeOutputDirectory(projectRoot, options.outputDirectory));
|
|
1090
1182
|
};
|
|
1091
|
-
// src/mobile/
|
|
1183
|
+
// src/mobile/iosRelease.ts
|
|
1184
|
+
import { createHash as createHash5 } from "crypto";
|
|
1092
1185
|
import {
|
|
1093
1186
|
access as access4,
|
|
1187
|
+
copyFile as copyFile3,
|
|
1094
1188
|
mkdir as mkdir4,
|
|
1189
|
+
mkdtemp as mkdtemp3,
|
|
1190
|
+
readdir as readdir3,
|
|
1095
1191
|
readFile as readFile5,
|
|
1096
1192
|
rename as rename5,
|
|
1097
1193
|
rm as rm4,
|
|
1194
|
+
stat as stat2,
|
|
1098
1195
|
writeFile as writeFile5
|
|
1099
1196
|
} from "fs/promises";
|
|
1100
|
-
import { resolve as
|
|
1197
|
+
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join5, relative as relative4, resolve as resolve4, sep as sep3 } from "path";
|
|
1198
|
+
var ABSOLUTE_IOS_RELEASE_FORMAT = 1;
|
|
1199
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1200
|
+
var requireManifest2 = (value) => {
|
|
1201
|
+
if (!isRecord2(value) || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.runtime !== "string") {
|
|
1202
|
+
throw new TypeError("Invalid embedded AbsoluteJS mobile manifest.");
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
appBuild: value.appBuild,
|
|
1206
|
+
appId: value.appId,
|
|
1207
|
+
runtime: value.runtime
|
|
1208
|
+
};
|
|
1209
|
+
};
|
|
1210
|
+
var pathExists3 = async (path) => {
|
|
1211
|
+
try {
|
|
1212
|
+
await access4(path);
|
|
1213
|
+
return true;
|
|
1214
|
+
} catch {
|
|
1215
|
+
return false;
|
|
1216
|
+
}
|
|
1217
|
+
};
|
|
1218
|
+
var defaultRun = async (command, options = {}) => {
|
|
1219
|
+
const process2 = Bun.spawn(command, {
|
|
1220
|
+
cwd: options.cwd,
|
|
1221
|
+
env: options.env,
|
|
1222
|
+
stderr: "inherit",
|
|
1223
|
+
stdin: "inherit",
|
|
1224
|
+
stdout: "inherit"
|
|
1225
|
+
});
|
|
1226
|
+
return process2.exited;
|
|
1227
|
+
};
|
|
1228
|
+
var defaultCapture2 = (command, options = {}) => {
|
|
1229
|
+
try {
|
|
1230
|
+
const result = Bun.spawnSync(command, {
|
|
1231
|
+
cwd: options.cwd,
|
|
1232
|
+
env: options.env,
|
|
1233
|
+
stderr: "pipe",
|
|
1234
|
+
stdin: "ignore",
|
|
1235
|
+
stdout: "pipe"
|
|
1236
|
+
});
|
|
1237
|
+
return {
|
|
1238
|
+
exitCode: result.exitCode,
|
|
1239
|
+
stderr: result.stderr.toString(),
|
|
1240
|
+
stdout: result.stdout.toString()
|
|
1241
|
+
};
|
|
1242
|
+
} catch (error) {
|
|
1243
|
+
return {
|
|
1244
|
+
exitCode: 1,
|
|
1245
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
1246
|
+
stdout: ""
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
var ignoredFingerprintDirectories = new Set([
|
|
1251
|
+
"Pods",
|
|
1252
|
+
"DerivedData",
|
|
1253
|
+
"build",
|
|
1254
|
+
"xcuserdata"
|
|
1255
|
+
]);
|
|
1256
|
+
var fingerprintFiles = async (root, current = root) => {
|
|
1257
|
+
const entries = await readdir3(current, { withFileTypes: true });
|
|
1258
|
+
const nested = await Promise.all(entries.sort((left, right) => left.name.localeCompare(right.name)).map(async (entry) => {
|
|
1259
|
+
const path = join5(current, entry.name);
|
|
1260
|
+
const projectRelative = relative4(root, path).replaceAll("\\", "/");
|
|
1261
|
+
const ignored = entry.isDirectory() && (ignoredFingerprintDirectories.has(entry.name) || projectRelative === "App/App/public");
|
|
1262
|
+
if (ignored)
|
|
1263
|
+
return [];
|
|
1264
|
+
if (entry.isDirectory())
|
|
1265
|
+
return fingerprintFiles(root, path);
|
|
1266
|
+
return entry.isFile() ? [path] : [];
|
|
1267
|
+
}));
|
|
1268
|
+
return nested.flat();
|
|
1269
|
+
};
|
|
1270
|
+
var fingerprintAbsoluteIosNativeProject = async (nativeDirectory) => {
|
|
1271
|
+
const hasher = createHash5("sha256");
|
|
1272
|
+
const files = await fingerprintFiles(nativeDirectory);
|
|
1273
|
+
const contents = await Promise.all(files.map((file) => readFile5(file)));
|
|
1274
|
+
files.forEach((file, index) => {
|
|
1275
|
+
hasher.update(relative4(nativeDirectory, file).replaceAll("\\", "/"));
|
|
1276
|
+
hasher.update("\x00");
|
|
1277
|
+
hasher.update(contents[index] ?? new Uint8Array);
|
|
1278
|
+
hasher.update("\x00");
|
|
1279
|
+
});
|
|
1280
|
+
return hasher.digest("hex");
|
|
1281
|
+
};
|
|
1282
|
+
var safeOutputDirectory2 = (projectRoot, requested) => {
|
|
1283
|
+
const root = resolve4(projectRoot);
|
|
1284
|
+
const output = resolve4(root, requested ?? ".absolutejs/mobile/releases/ios");
|
|
1285
|
+
const projectRelative = relative4(root, output);
|
|
1286
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep3}`) || isAbsolute3(projectRelative)) {
|
|
1287
|
+
throw new TypeError("mobile build --outdir must remain inside the project.");
|
|
1288
|
+
}
|
|
1289
|
+
return output;
|
|
1290
|
+
};
|
|
1291
|
+
var sha256File2 = async (path) => createHash5("sha256").update(await readFile5(path)).digest("hex");
|
|
1292
|
+
var findByExtension = async (root, extension) => {
|
|
1293
|
+
if (!await pathExists3(root))
|
|
1294
|
+
return;
|
|
1295
|
+
const entries = await readdir3(root, { withFileTypes: true });
|
|
1296
|
+
const matches = await Promise.all(entries.map(async (entry) => {
|
|
1297
|
+
const path = join5(root, entry.name);
|
|
1298
|
+
if (entry.isDirectory() && entry.name.endsWith(extension))
|
|
1299
|
+
return path;
|
|
1300
|
+
if (entry.isFile() && entry.name.endsWith(extension))
|
|
1301
|
+
return path;
|
|
1302
|
+
return entry.isDirectory() ? findByExtension(path, extension) : undefined;
|
|
1303
|
+
}));
|
|
1304
|
+
return matches.find((match) => match !== undefined);
|
|
1305
|
+
};
|
|
1306
|
+
var exportOptions = () => `<?xml version="1.0" encoding="UTF-8"?>
|
|
1307
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
1308
|
+
<plist version="1.0"><dict>
|
|
1309
|
+
<key>destination</key><string>export</string>
|
|
1310
|
+
<key>manageAppVersionAndBuildNumber</key><false/>
|
|
1311
|
+
<key>method</key><string>app-store-connect</string>
|
|
1312
|
+
<key>signingStyle</key><string>automatic</string>
|
|
1313
|
+
<key>stripSwiftSymbols</key><true/>
|
|
1314
|
+
<key>uploadSymbols</key><true/>
|
|
1315
|
+
</dict></plist>
|
|
1316
|
+
`;
|
|
1317
|
+
var requireBuildNumber = (value) => {
|
|
1318
|
+
if (value !== undefined && (!Number.isSafeInteger(value) || value < 1))
|
|
1319
|
+
throw new TypeError("iOS build number must be a positive integer.");
|
|
1320
|
+
return value;
|
|
1321
|
+
};
|
|
1322
|
+
var installRelease2 = async (artifactPath, metadata, outputRoot) => {
|
|
1323
|
+
const releaseRoot = join5(outputRoot, metadata.releaseId);
|
|
1324
|
+
const destination = join5(releaseRoot, "App.ipa");
|
|
1325
|
+
if (await pathExists3(releaseRoot)) {
|
|
1326
|
+
const value = JSON.parse(await readFile5(join5(releaseRoot, "release.json"), "utf8"));
|
|
1327
|
+
if (!isRecord2(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
|
|
1328
|
+
throw new TypeError(`Immutable iOS release ${metadata.releaseId} does not match its content.`);
|
|
1329
|
+
}
|
|
1330
|
+
const [bytes, sha256] = await Promise.all([
|
|
1331
|
+
stat2(destination).then(({ size }) => size),
|
|
1332
|
+
sha256File2(destination)
|
|
1333
|
+
]);
|
|
1334
|
+
if (bytes !== metadata.bytes || sha256 !== metadata.sha256)
|
|
1335
|
+
throw new TypeError(`Immutable iOS release ${metadata.releaseId} artifact is missing or modified.`);
|
|
1336
|
+
return {
|
|
1337
|
+
artifactPath: destination,
|
|
1338
|
+
metadata: {
|
|
1339
|
+
...metadata,
|
|
1340
|
+
artifact: "App.ipa"
|
|
1341
|
+
},
|
|
1342
|
+
releaseRoot
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
await mkdir4(dirname3(releaseRoot), { recursive: true });
|
|
1346
|
+
const staging = await mkdtemp3(join5(dirname3(releaseRoot), ".ios-stage-"));
|
|
1347
|
+
try {
|
|
1348
|
+
await copyFile3(artifactPath, join5(staging, "App.ipa"));
|
|
1349
|
+
const complete = {
|
|
1350
|
+
...metadata,
|
|
1351
|
+
artifact: "App.ipa"
|
|
1352
|
+
};
|
|
1353
|
+
await writeFile5(join5(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
|
|
1354
|
+
`, { flag: "wx" });
|
|
1355
|
+
await rename5(staging, releaseRoot);
|
|
1356
|
+
return { artifactPath: destination, metadata: complete, releaseRoot };
|
|
1357
|
+
} finally {
|
|
1358
|
+
await rm4(staging, { force: true, recursive: true }).catch(() => {
|
|
1359
|
+
return;
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
var buildAbsoluteIosRelease = async (options) => {
|
|
1364
|
+
if (options.buildNumber !== undefined && options.prepareBuildNumber)
|
|
1365
|
+
throw new TypeError("iOS release buildNumber and prepareBuildNumber cannot be combined.");
|
|
1366
|
+
if ((options.host ?? detectAbsoluteMobileHost()) !== "macos")
|
|
1367
|
+
throw new TypeError("iOS release builds require macOS and Xcode.");
|
|
1368
|
+
const marketingVersion = options.config.iosVersion;
|
|
1369
|
+
if (!marketingVersion)
|
|
1370
|
+
throw new TypeError("iOS release builds require mobile.ios.version in absolutejs.config.ts.");
|
|
1371
|
+
const manifest = requireManifest2(JSON.parse(await readFile5(join5(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
1372
|
+
if (manifest.appId !== options.config.appId)
|
|
1373
|
+
throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
|
|
1374
|
+
const nativeDirectory = join5(options.config.nativeProjectDirectory, "ios");
|
|
1375
|
+
let buildNumber = requireBuildNumber(options.buildNumber);
|
|
1376
|
+
if (options.prepareBuildNumber) {
|
|
1377
|
+
const nativeFingerprint = await fingerprintAbsoluteIosNativeProject(nativeDirectory);
|
|
1378
|
+
const buildIdentity = createHash5("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}\x00${marketingVersion}`).digest("hex");
|
|
1379
|
+
buildNumber = requireBuildNumber(await options.prepareBuildNumber(buildIdentity));
|
|
1380
|
+
}
|
|
1381
|
+
const stagingParent = resolve4(options.projectRoot, ".absolutejs/mobile");
|
|
1382
|
+
await mkdir4(stagingParent, { recursive: true });
|
|
1383
|
+
const staging = await mkdtemp3(join5(stagingParent, ".ios-build-"));
|
|
1384
|
+
const archivePath = join5(staging, "App.xcarchive");
|
|
1385
|
+
const exportPath = join5(staging, "export");
|
|
1386
|
+
const exportPlist = join5(staging, "ExportOptions.plist");
|
|
1387
|
+
await mkdir4(exportPath, { recursive: true });
|
|
1388
|
+
await writeFile5(exportPlist, exportOptions());
|
|
1389
|
+
const run = options.run ?? defaultRun;
|
|
1390
|
+
try {
|
|
1391
|
+
const versionArguments = [
|
|
1392
|
+
`MARKETING_VERSION=${marketingVersion}`,
|
|
1393
|
+
...buildNumber === undefined ? [] : [`CURRENT_PROJECT_VERSION=${buildNumber}`]
|
|
1394
|
+
];
|
|
1395
|
+
const archiveExit = await run([
|
|
1396
|
+
"xcodebuild",
|
|
1397
|
+
"-workspace",
|
|
1398
|
+
join5(nativeDirectory, "App", "App.xcworkspace"),
|
|
1399
|
+
"-scheme",
|
|
1400
|
+
"App",
|
|
1401
|
+
"-configuration",
|
|
1402
|
+
"Release",
|
|
1403
|
+
"-destination",
|
|
1404
|
+
"generic/platform=iOS",
|
|
1405
|
+
"-archivePath",
|
|
1406
|
+
archivePath,
|
|
1407
|
+
...versionArguments,
|
|
1408
|
+
"archive"
|
|
1409
|
+
], { cwd: nativeDirectory });
|
|
1410
|
+
if (archiveExit !== 0)
|
|
1411
|
+
throw new TypeError("Xcode failed to archive the iOS app.");
|
|
1412
|
+
const archivedApp = await findByExtension(join5(archivePath, "Products", "Applications"), ".app");
|
|
1413
|
+
const capture = options.capture ?? defaultCapture2;
|
|
1414
|
+
const signed = archivedApp ? capture([
|
|
1415
|
+
"codesign",
|
|
1416
|
+
"--verify",
|
|
1417
|
+
"--deep",
|
|
1418
|
+
"--strict",
|
|
1419
|
+
archivedApp
|
|
1420
|
+
]).exitCode === 0 : false;
|
|
1421
|
+
if (!signed && !options.allowUnsigned)
|
|
1422
|
+
throw new TypeError("Xcode produced an unsigned iOS archive. Configure signing in the source-owned Xcode project, or pass --unsigned only for a non-publishable build.");
|
|
1423
|
+
const exportExit = await run([
|
|
1424
|
+
"xcodebuild",
|
|
1425
|
+
"-exportArchive",
|
|
1426
|
+
"-archivePath",
|
|
1427
|
+
archivePath,
|
|
1428
|
+
"-exportPath",
|
|
1429
|
+
exportPath,
|
|
1430
|
+
"-exportOptionsPlist",
|
|
1431
|
+
exportPlist
|
|
1432
|
+
], { cwd: nativeDirectory });
|
|
1433
|
+
if (exportExit !== 0)
|
|
1434
|
+
throw new TypeError("Xcode failed to export the App Store IPA.");
|
|
1435
|
+
const artifactPath = await findByExtension(exportPath, ".ipa");
|
|
1436
|
+
if (!artifactPath)
|
|
1437
|
+
throw new TypeError("Xcode did not produce an exported IPA.");
|
|
1438
|
+
const [bytes, sha256] = await Promise.all([
|
|
1439
|
+
stat2(artifactPath).then(({ size }) => size),
|
|
1440
|
+
sha256File2(artifactPath)
|
|
1441
|
+
]);
|
|
1442
|
+
const releaseId = `amobile_ios_${sha256}`;
|
|
1443
|
+
return await installRelease2(artifactPath, {
|
|
1444
|
+
appBuild: manifest.appBuild,
|
|
1445
|
+
appId: manifest.appId,
|
|
1446
|
+
...buildNumber === undefined ? {} : { buildNumber },
|
|
1447
|
+
bytes,
|
|
1448
|
+
engine: "capacitor",
|
|
1449
|
+
format: 1,
|
|
1450
|
+
marketingVersion,
|
|
1451
|
+
platform: "ios",
|
|
1452
|
+
releaseId,
|
|
1453
|
+
runtime: manifest.runtime,
|
|
1454
|
+
sha256,
|
|
1455
|
+
signed,
|
|
1456
|
+
type: "ipa"
|
|
1457
|
+
}, safeOutputDirectory2(options.projectRoot, options.outputDirectory));
|
|
1458
|
+
} finally {
|
|
1459
|
+
await rm4(staging, { force: true, recursive: true }).catch(() => {
|
|
1460
|
+
return;
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
// src/mobile/associationFiles.ts
|
|
1465
|
+
import {
|
|
1466
|
+
access as access5,
|
|
1467
|
+
mkdir as mkdir5,
|
|
1468
|
+
readFile as readFile6,
|
|
1469
|
+
rename as rename6,
|
|
1470
|
+
rm as rm5,
|
|
1471
|
+
writeFile as writeFile6
|
|
1472
|
+
} from "fs/promises";
|
|
1473
|
+
import { resolve as resolve6 } from "path";
|
|
1101
1474
|
import { Elysia } from "elysia";
|
|
1102
1475
|
|
|
1103
1476
|
// src/mobile/config.ts
|
|
1104
|
-
import { resolve as
|
|
1477
|
+
import { resolve as resolve5 } from "path";
|
|
1105
1478
|
var APP_ID_PATTERN = /^[A-Za-z][\w]*(?:\.[A-Za-z][\w]*)+$/;
|
|
1106
1479
|
var SCHEME_PATTERN = /^[a-z][a-z0-9+.-]*$/;
|
|
1107
1480
|
var APPLE_APP_ID_PREFIX_PATTERN = /^[A-Z0-9]{10}$/;
|
|
1108
1481
|
var CERTIFICATE_FINGERPRINT_PATTERN = /^[0-9A-F]{64}$/;
|
|
1109
1482
|
var HOSTNAME_PATTERN = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/;
|
|
1110
1483
|
var resolveProjectPath = (projectRoot, value, field) => {
|
|
1111
|
-
const root =
|
|
1112
|
-
const path =
|
|
1484
|
+
const root = resolve5(projectRoot);
|
|
1485
|
+
const path = resolve5(root, value);
|
|
1113
1486
|
if (path !== root && !path.startsWith(`${root}/`)) {
|
|
1114
1487
|
throw new TypeError(`${field} must remain inside the project root.`);
|
|
1115
1488
|
}
|
|
@@ -1172,6 +1545,15 @@ var normalizeAppleAppIdPrefix = (value) => {
|
|
|
1172
1545
|
}
|
|
1173
1546
|
return normalized;
|
|
1174
1547
|
};
|
|
1548
|
+
var normalizeIosVersion = (value) => {
|
|
1549
|
+
if (value === undefined)
|
|
1550
|
+
return;
|
|
1551
|
+
const normalized = requireText(value, "mobile.ios.version");
|
|
1552
|
+
if (!/^\d+(?:\.\d+){0,2}$/u.test(normalized)) {
|
|
1553
|
+
throw new TypeError("mobile.ios.version must contain one to three dot-separated integer components, for example 1.4.0.");
|
|
1554
|
+
}
|
|
1555
|
+
return normalized;
|
|
1556
|
+
};
|
|
1175
1557
|
var normalizeCertificateFingerprints = (values) => [
|
|
1176
1558
|
...new Set((values ?? []).map((value) => requireText(value, "mobile.deepLinks.android.sha256CertificateFingerprints").replaceAll(":", "").toUpperCase()).map((value) => {
|
|
1177
1559
|
if (!CERTIFICATE_FINGERPRINT_PATTERN.test(value)) {
|
|
@@ -1200,6 +1582,7 @@ var normalizeAbsoluteMobileConfig = (config, projectRoot) => {
|
|
|
1200
1582
|
deepLinkScheme,
|
|
1201
1583
|
engine: "capacitor",
|
|
1202
1584
|
entry: normalizeEntry(config.entry),
|
|
1585
|
+
iosVersion: normalizeIosVersion(config.ios?.version),
|
|
1203
1586
|
nativeProjectDirectory: resolveProjectPath(projectRoot, config.nativeProject?.directory ?? "mobile", "mobile.nativeProject.directory"),
|
|
1204
1587
|
platforms: normalizePlatforms(config.platforms),
|
|
1205
1588
|
productionOrigin
|
|
@@ -1287,7 +1670,7 @@ var createAbsoluteMobileAssociationPlugin = (mobile, projectRoot, options = {})
|
|
|
1287
1670
|
var writeAtomic = async (path, source) => {
|
|
1288
1671
|
let current;
|
|
1289
1672
|
try {
|
|
1290
|
-
current = await
|
|
1673
|
+
current = await readFile6(path, "utf8");
|
|
1291
1674
|
} catch (error) {
|
|
1292
1675
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
|
|
1293
1676
|
throw error;
|
|
@@ -1296,23 +1679,23 @@ var writeAtomic = async (path, source) => {
|
|
|
1296
1679
|
if (current === source)
|
|
1297
1680
|
return false;
|
|
1298
1681
|
const temporary = `${path}.${crypto.randomUUID()}.tmp`;
|
|
1299
|
-
await
|
|
1300
|
-
await
|
|
1682
|
+
await writeFile6(temporary, source, { flag: "wx" });
|
|
1683
|
+
await rename6(temporary, path);
|
|
1301
1684
|
return true;
|
|
1302
1685
|
};
|
|
1303
1686
|
var exists2 = async (path) => {
|
|
1304
1687
|
try {
|
|
1305
|
-
await
|
|
1688
|
+
await access5(path);
|
|
1306
1689
|
return true;
|
|
1307
1690
|
} catch {
|
|
1308
1691
|
return false;
|
|
1309
1692
|
}
|
|
1310
1693
|
};
|
|
1311
1694
|
var assertOwnedOutput = async (root) => {
|
|
1312
|
-
const path =
|
|
1695
|
+
const path = resolve6(root, OWNERSHIP_FILE);
|
|
1313
1696
|
let ownership;
|
|
1314
1697
|
try {
|
|
1315
|
-
ownership = JSON.parse(await
|
|
1698
|
+
ownership = JSON.parse(await readFile6(path, "utf8"));
|
|
1316
1699
|
} catch {
|
|
1317
1700
|
throw new TypeError(`Association output ${root} already exists and is not owned by AbsoluteJS.`);
|
|
1318
1701
|
}
|
|
@@ -1326,22 +1709,22 @@ var publishGeneratedDirectory = async (temporary, root) => {
|
|
|
1326
1709
|
await assertOwnedOutput(root);
|
|
1327
1710
|
const backup = `${root}.${crypto.randomUUID()}.previous`;
|
|
1328
1711
|
if (hasCurrent)
|
|
1329
|
-
await
|
|
1712
|
+
await rename6(root, backup);
|
|
1330
1713
|
try {
|
|
1331
|
-
await
|
|
1714
|
+
await rename6(temporary, root);
|
|
1332
1715
|
} catch (error) {
|
|
1333
1716
|
if (hasCurrent)
|
|
1334
|
-
await
|
|
1717
|
+
await rename6(backup, root);
|
|
1335
1718
|
throw error;
|
|
1336
1719
|
}
|
|
1337
1720
|
if (hasCurrent)
|
|
1338
|
-
await
|
|
1721
|
+
await rm5(backup, { force: true, recursive: true });
|
|
1339
1722
|
};
|
|
1340
1723
|
var materializeHost = async (root, host, files) => {
|
|
1341
|
-
const directory =
|
|
1342
|
-
await
|
|
1724
|
+
const directory = resolve6(root, host, ".well-known");
|
|
1725
|
+
await mkdir5(directory, { recursive: true });
|
|
1343
1726
|
return Promise.all(files.map(async ([name, document]) => {
|
|
1344
|
-
const path =
|
|
1727
|
+
const path = resolve6(directory, name);
|
|
1345
1728
|
await writeAtomic(path, `${JSON.stringify(document, null, 2)}
|
|
1346
1729
|
`);
|
|
1347
1730
|
return path;
|
|
@@ -1366,7 +1749,7 @@ var associationEndpoints = (config, documents) => config.deepLinkHosts.flatMap((
|
|
|
1366
1749
|
return endpoints;
|
|
1367
1750
|
});
|
|
1368
1751
|
var materializeAbsoluteMobileAssociationFiles = async (config, outputDirectory) => {
|
|
1369
|
-
const root =
|
|
1752
|
+
const root = resolve6(outputDirectory);
|
|
1370
1753
|
const temporary = `${root}.${crypto.randomUUID()}.tmp`;
|
|
1371
1754
|
const documents = createAbsoluteMobileAssociationDocuments(config, {
|
|
1372
1755
|
requireAll: true
|
|
@@ -1377,16 +1760,16 @@ var materializeAbsoluteMobileAssociationFiles = async (config, outputDirectory)
|
|
|
1377
1760
|
if (documents.apple) {
|
|
1378
1761
|
files.push(["apple-app-site-association", documents.apple]);
|
|
1379
1762
|
}
|
|
1380
|
-
await
|
|
1763
|
+
await mkdir5(temporary, { recursive: true });
|
|
1381
1764
|
try {
|
|
1382
1765
|
const temporaryPaths = (await Promise.all(config.deepLinkHosts.map((host) => materializeHost(temporary, host, files)))).flat();
|
|
1383
|
-
await writeAtomic(
|
|
1766
|
+
await writeAtomic(resolve6(temporary, OWNERSHIP_FILE), `${JSON.stringify({ format: 1, hosts: config.deepLinkHosts }, null, 2)}
|
|
1384
1767
|
`);
|
|
1385
1768
|
await publishGeneratedDirectory(temporary, root);
|
|
1386
|
-
const written = temporaryPaths.map((path) =>
|
|
1769
|
+
const written = temporaryPaths.map((path) => resolve6(root, path.slice(temporary.length + 1)));
|
|
1387
1770
|
return { root, written };
|
|
1388
1771
|
} catch (error) {
|
|
1389
|
-
await
|
|
1772
|
+
await rm5(temporary, { force: true, recursive: true });
|
|
1390
1773
|
throw error;
|
|
1391
1774
|
}
|
|
1392
1775
|
};
|
|
@@ -1431,10 +1814,10 @@ var frameworks2 = new Set([
|
|
|
1431
1814
|
"svelte",
|
|
1432
1815
|
"vue"
|
|
1433
1816
|
]);
|
|
1434
|
-
var
|
|
1817
|
+
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1435
1818
|
var isPageFramework2 = (value) => typeof value === "string" && frameworks2.has(value);
|
|
1436
1819
|
var parseAbsoluteMobileBuildPageMetadata = (value) => {
|
|
1437
|
-
if (!
|
|
1820
|
+
if (!isRecord3(value))
|
|
1438
1821
|
return;
|
|
1439
1822
|
if (typeof value.bundleKey !== "string" || typeof value.contract !== "string" || !isPageFramework2(value.framework) || typeof value.pageId !== "string" || typeof value.propsSchemaHash !== "string") {
|
|
1440
1823
|
return;
|
|
@@ -1448,23 +1831,23 @@ var parseAbsoluteMobileBuildPageMetadata = (value) => {
|
|
|
1448
1831
|
};
|
|
1449
1832
|
};
|
|
1450
1833
|
// src/mobile/buildPipeline.ts
|
|
1451
|
-
import { readFile as
|
|
1452
|
-
import { join as
|
|
1834
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
1835
|
+
import { join as join9, resolve as resolve9 } from "path";
|
|
1453
1836
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
1454
1837
|
|
|
1455
1838
|
// src/mobile/buildRelease.ts
|
|
1456
|
-
import { createHash as
|
|
1457
|
-
import { readFile as
|
|
1458
|
-
import { join as
|
|
1459
|
-
var sha256 = (bytes) =>
|
|
1839
|
+
import { createHash as createHash6 } from "crypto";
|
|
1840
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
1841
|
+
import { join as join6, relative as relative5, resolve as resolve7 } from "path";
|
|
1842
|
+
var sha256 = (bytes) => createHash6("sha256").update(bytes).digest("hex");
|
|
1460
1843
|
var readPageMetadata = (route) => parseAbsoluteMobileBuildPageMetadata(route.hooks?.detail?.[ABSOLUTE_MOBILE_ROUTE_DETAIL]);
|
|
1461
1844
|
var resolveAssetPath = (buildDirectory, assetPath) => {
|
|
1462
|
-
const resolvedBuildDirectory =
|
|
1463
|
-
const resolvedAsset =
|
|
1845
|
+
const resolvedBuildDirectory = resolve7(buildDirectory);
|
|
1846
|
+
const resolvedAsset = resolve7(assetPath);
|
|
1464
1847
|
if (resolvedAsset.startsWith(`${resolvedBuildDirectory}/`)) {
|
|
1465
1848
|
return resolvedAsset;
|
|
1466
1849
|
}
|
|
1467
|
-
return
|
|
1850
|
+
return join6(buildDirectory, assetPath.replace(/^\/+/, ""));
|
|
1468
1851
|
};
|
|
1469
1852
|
var pageFor = async (metadata, manifest, buildDirectory) => {
|
|
1470
1853
|
const assetPath = manifest[metadata.bundleKey];
|
|
@@ -1472,8 +1855,8 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
|
|
|
1472
1855
|
throw new TypeError(`Mobile page ${metadata.pageId} references missing manifest asset ${metadata.bundleKey}.`);
|
|
1473
1856
|
}
|
|
1474
1857
|
const resolvedAssetPath = resolveAssetPath(buildDirectory, assetPath);
|
|
1475
|
-
const bytes = await
|
|
1476
|
-
const bundlePath = `/${
|
|
1858
|
+
const bytes = await readFile7(resolvedAssetPath);
|
|
1859
|
+
const bundlePath = `/${relative5(resolve7(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
|
|
1477
1860
|
return {
|
|
1478
1861
|
bundleHash: sha256(bytes),
|
|
1479
1862
|
bundlePath,
|
|
@@ -1486,7 +1869,7 @@ var pageFor = async (metadata, manifest, buildDirectory) => {
|
|
|
1486
1869
|
var buildAbsoluteMobileCompatibilityRelease = async (options) => {
|
|
1487
1870
|
const [captured, producerBytes] = await Promise.all([
|
|
1488
1871
|
captureAbsoluteMobileRouteGraph(options.app),
|
|
1489
|
-
|
|
1872
|
+
readFile7(options.producerPath)
|
|
1490
1873
|
]);
|
|
1491
1874
|
if (captured.length === 0) {
|
|
1492
1875
|
throw new TypeError("No instrumented AbsoluteJS mobile page routes were found in the finalized Elysia route graph.");
|
|
@@ -1566,16 +1949,16 @@ var captureAbsoluteMobileRouteGraph = async (app) => {
|
|
|
1566
1949
|
|
|
1567
1950
|
// src/mobile/capacitorBundle.ts
|
|
1568
1951
|
import {
|
|
1569
|
-
copyFile as
|
|
1570
|
-
mkdir as
|
|
1571
|
-
mkdtemp as
|
|
1572
|
-
readFile as
|
|
1573
|
-
rename as
|
|
1574
|
-
rm as
|
|
1575
|
-
writeFile as
|
|
1952
|
+
copyFile as copyFile4,
|
|
1953
|
+
mkdir as mkdir6,
|
|
1954
|
+
mkdtemp as mkdtemp4,
|
|
1955
|
+
readFile as readFile8,
|
|
1956
|
+
rename as rename7,
|
|
1957
|
+
rm as rm6,
|
|
1958
|
+
writeFile as writeFile7
|
|
1576
1959
|
} from "fs/promises";
|
|
1577
1960
|
import { existsSync as existsSync2 } from "fs";
|
|
1578
|
-
import { basename, dirname as
|
|
1961
|
+
import { basename, dirname as dirname4, extname, join as join7, resolve as resolve8 } from "path";
|
|
1579
1962
|
|
|
1580
1963
|
// src/mobile/routeMatcher.ts
|
|
1581
1964
|
var REGEXP_SPECIAL_CHARACTERS = /[.*+?^${}()|[\]\\]/g;
|
|
@@ -1731,14 +2114,14 @@ var envelopeResponse = (response, status) => new Response(JSON.stringify({
|
|
|
1731
2114
|
protocol: ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
|
|
1732
2115
|
response
|
|
1733
2116
|
}), { headers: responseHeaders(), status });
|
|
1734
|
-
var
|
|
2117
|
+
var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1735
2118
|
var normalizeJsonValue = (value) => {
|
|
1736
2119
|
const serialized = JSON.stringify(value);
|
|
1737
2120
|
if (serialized === undefined) {
|
|
1738
2121
|
throw new TypeError("Mobile page props must be JSON-serializable.");
|
|
1739
2122
|
}
|
|
1740
2123
|
const parsed = JSON.parse(serialized);
|
|
1741
|
-
if (!
|
|
2124
|
+
if (!isRecord4(parsed)) {
|
|
1742
2125
|
throw new TypeError("Mobile page props must serialize to an object.");
|
|
1743
2126
|
}
|
|
1744
2127
|
return parsed;
|
|
@@ -1863,14 +2246,14 @@ var upgradeReasons = new Set([
|
|
|
1863
2246
|
"protocol",
|
|
1864
2247
|
"runtime"
|
|
1865
2248
|
]);
|
|
1866
|
-
var
|
|
2249
|
+
var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1867
2250
|
var isFramework = (value) => typeof value === "string" && frameworks4.has(value);
|
|
1868
2251
|
var isUpgradeReason = (value) => typeof value === "string" && upgradeReasons.has(value);
|
|
1869
2252
|
var parsePageResult = (value) => {
|
|
1870
2253
|
if (typeof value.contract !== "string" || !isFramework(value.framework) || typeof value.pageId !== "string" || typeof value.status !== "number") {
|
|
1871
2254
|
throw new AbsoluteMobilePageProtocolError("invalid-envelope", "The mobile page response is missing required page metadata.");
|
|
1872
2255
|
}
|
|
1873
|
-
if (!
|
|
2256
|
+
if (!isRecord5(value.props)) {
|
|
1874
2257
|
throw new AbsoluteMobilePageProtocolError("invalid-props", "The mobile page response must contain an object props value.");
|
|
1875
2258
|
}
|
|
1876
2259
|
return {
|
|
@@ -1916,7 +2299,7 @@ var activateAbsoluteMobilePage = async (value, options) => {
|
|
|
1916
2299
|
};
|
|
1917
2300
|
};
|
|
1918
2301
|
var parseAbsoluteMobilePageEnvelope = (value) => {
|
|
1919
|
-
if (!
|
|
2302
|
+
if (!isRecord5(value) || !isRecord5(value.response)) {
|
|
1920
2303
|
throw new AbsoluteMobilePageProtocolError("invalid-envelope", "The server did not return an AbsoluteJS mobile page envelope.");
|
|
1921
2304
|
}
|
|
1922
2305
|
if (value.protocol !== ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION) {
|
|
@@ -2009,7 +2392,7 @@ var INDEX_FILE = "index.html";
|
|
|
2009
2392
|
var CLIENT_IMPORT_PATTERN = /(?:\bfrom\s*|\bimport\s*\(\s*|\bimport\s*)["'](\/[^"']+)["']/gu;
|
|
2010
2393
|
var errorHasCode2 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code;
|
|
2011
2394
|
var shellBootstrapModule = () => {
|
|
2012
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
2395
|
+
const candidate = ["js", "ts"].map((extension) => join7(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync2);
|
|
2013
2396
|
if (candidate)
|
|
2014
2397
|
return candidate;
|
|
2015
2398
|
throw new TypeError("AbsoluteJS mobile shell bootstrap module is missing.");
|
|
@@ -2030,8 +2413,8 @@ var indexHtml = (appName) => `<!doctype html>
|
|
|
2030
2413
|
</html>
|
|
2031
2414
|
`;
|
|
2032
2415
|
var sourceAssetPath = (buildDirectory, bundlePath) => {
|
|
2033
|
-
const root =
|
|
2034
|
-
const asset =
|
|
2416
|
+
const root = resolve8(buildDirectory);
|
|
2417
|
+
const asset = resolve8(root, bundlePath.replace(/^\/+/, ""));
|
|
2035
2418
|
if (!asset.startsWith(`${root}/`)) {
|
|
2036
2419
|
throw new TypeError("Mobile page bundle escaped the build directory.");
|
|
2037
2420
|
}
|
|
@@ -2039,8 +2422,8 @@ var sourceAssetPath = (buildDirectory, bundlePath) => {
|
|
|
2039
2422
|
};
|
|
2040
2423
|
var buildShellBootstrap = async (staging) => {
|
|
2041
2424
|
const modulePath = shellBootstrapModule();
|
|
2042
|
-
const entryPath =
|
|
2043
|
-
await
|
|
2425
|
+
const entryPath = join7(staging, ".absolute-mobile-entry.ts");
|
|
2426
|
+
await writeFile7(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
|
|
2044
2427
|
void startAbsoluteMobileShell();
|
|
2045
2428
|
`);
|
|
2046
2429
|
const build = await Bun.build({
|
|
@@ -2052,31 +2435,31 @@ void startAbsoluteMobileShell();
|
|
|
2052
2435
|
if (!build.success || build.outputs.length !== 1) {
|
|
2053
2436
|
throw new AggregateError(build.logs, "Failed to build the AbsoluteJS Capacitor shell.");
|
|
2054
2437
|
}
|
|
2055
|
-
await
|
|
2056
|
-
await
|
|
2438
|
+
await rename7(build.outputs[0]?.path ?? "", join7(staging, BOOTSTRAP_FILE));
|
|
2439
|
+
await rm6(entryPath, { force: true });
|
|
2057
2440
|
};
|
|
2058
2441
|
var removePreviousBundle = async (backup, moved) => {
|
|
2059
2442
|
if (!moved)
|
|
2060
2443
|
return;
|
|
2061
|
-
await
|
|
2444
|
+
await rm6(backup, { force: true, recursive: true });
|
|
2062
2445
|
};
|
|
2063
2446
|
var restorePreviousBundle = async (backup, destination, moved) => {
|
|
2064
2447
|
if (!moved)
|
|
2065
2448
|
return;
|
|
2066
|
-
await
|
|
2449
|
+
await rename7(backup, destination);
|
|
2067
2450
|
};
|
|
2068
2451
|
var installBundle = async (staging, destination) => {
|
|
2069
2452
|
const backup = `${destination}.previous-${crypto.randomUUID()}`;
|
|
2070
2453
|
let movedPrevious = false;
|
|
2071
2454
|
try {
|
|
2072
|
-
await
|
|
2455
|
+
await rename7(destination, backup);
|
|
2073
2456
|
movedPrevious = true;
|
|
2074
2457
|
} catch (error) {
|
|
2075
2458
|
if (!errorHasCode2(error, "ENOENT"))
|
|
2076
2459
|
throw error;
|
|
2077
2460
|
}
|
|
2078
2461
|
try {
|
|
2079
|
-
await
|
|
2462
|
+
await rename7(staging, destination);
|
|
2080
2463
|
await removePreviousBundle(backup, movedPrevious);
|
|
2081
2464
|
} catch (error) {
|
|
2082
2465
|
await restorePreviousBundle(backup, destination, movedPrevious);
|
|
@@ -2090,12 +2473,12 @@ var copyClientPage = async (page, buildDirectory, staging, copiedDependencies) =
|
|
|
2090
2473
|
const extension = extname(page.bundlePath) || ".js";
|
|
2091
2474
|
const localBundlePath = `./pages/${page.bundleHash}${extension}`;
|
|
2092
2475
|
const source = sourceAssetPath(buildDirectory, page.bundlePath);
|
|
2093
|
-
await
|
|
2476
|
+
await copyFile4(source, join7(staging, localBundlePath));
|
|
2094
2477
|
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copiedDependencies);
|
|
2095
2478
|
return { ...page, localBundlePath };
|
|
2096
2479
|
};
|
|
2097
2480
|
var absoluteClientImports = async (sourcePath) => {
|
|
2098
|
-
const source = await
|
|
2481
|
+
const source = await readFile8(sourcePath, "utf8");
|
|
2099
2482
|
return [...source.matchAll(CLIENT_IMPORT_PATTERN)].flatMap((match) => {
|
|
2100
2483
|
const [specifier] = match.slice(1);
|
|
2101
2484
|
return specifier ? [specifier.split(/[?#]/u, 1)[0] ?? specifier] : [];
|
|
@@ -2106,9 +2489,9 @@ var copyAbsoluteClientDependency = async (specifier, buildDirectory, staging, co
|
|
|
2106
2489
|
return;
|
|
2107
2490
|
copied.add(specifier);
|
|
2108
2491
|
const source = sourceAssetPath(buildDirectory, specifier);
|
|
2109
|
-
const destination =
|
|
2110
|
-
await
|
|
2111
|
-
await
|
|
2492
|
+
const destination = join7(staging, specifier.replace(/^\/+/, ""));
|
|
2493
|
+
await mkdir6(dirname4(destination), { recursive: true });
|
|
2494
|
+
await copyFile4(source, destination);
|
|
2112
2495
|
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copied);
|
|
2113
2496
|
};
|
|
2114
2497
|
var copyAbsoluteClientDependencies = async (sourcePath, buildDirectory, staging, copied) => {
|
|
@@ -2120,11 +2503,11 @@ var materializeAbsoluteCapacitorWebBundle = async (options) => {
|
|
|
2120
2503
|
throw new TypeError(`mobile.entry ${options.config.entry} is not a captured mobile page route.`);
|
|
2121
2504
|
}
|
|
2122
2505
|
const destination = options.config.bundleDirectory;
|
|
2123
|
-
await
|
|
2124
|
-
const staging = await
|
|
2506
|
+
await mkdir6(dirname4(destination), { recursive: true });
|
|
2507
|
+
const staging = await mkdtemp4(join7(dirname4(destination), `.${basename(destination)}.stage-`));
|
|
2125
2508
|
try {
|
|
2126
|
-
const pageDirectory =
|
|
2127
|
-
await
|
|
2509
|
+
const pageDirectory = join7(staging, "pages");
|
|
2510
|
+
await mkdir6(pageDirectory, { recursive: true });
|
|
2128
2511
|
const copiedDependencies = new Set;
|
|
2129
2512
|
const pages = await Promise.all(options.artifact.pages.map((page) => copyClientPage(page, options.buildDirectory, staging, copiedDependencies)));
|
|
2130
2513
|
const manifest = {
|
|
@@ -2141,48 +2524,48 @@ var materializeAbsoluteCapacitorWebBundle = async (options) => {
|
|
|
2141
2524
|
runtime: options.artifact.runtime
|
|
2142
2525
|
};
|
|
2143
2526
|
await Promise.all([
|
|
2144
|
-
|
|
2527
|
+
writeFile7(join7(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
2145
2528
|
`),
|
|
2146
|
-
|
|
2529
|
+
writeFile7(join7(staging, INDEX_FILE), indexHtml(options.config.appName)),
|
|
2147
2530
|
buildShellBootstrap(staging)
|
|
2148
2531
|
]);
|
|
2149
2532
|
await installBundle(staging, destination);
|
|
2150
2533
|
return manifest;
|
|
2151
2534
|
} catch (error) {
|
|
2152
|
-
await
|
|
2535
|
+
await rm6(staging, { force: true, recursive: true });
|
|
2153
2536
|
throw error;
|
|
2154
2537
|
}
|
|
2155
2538
|
};
|
|
2156
2539
|
|
|
2157
2540
|
// src/mobile/materializedBundle.ts
|
|
2158
|
-
import { createHash as
|
|
2541
|
+
import { createHash as createHash7 } from "crypto";
|
|
2159
2542
|
import {
|
|
2160
|
-
access as
|
|
2161
|
-
mkdir as
|
|
2162
|
-
mkdtemp as
|
|
2163
|
-
readFile as
|
|
2164
|
-
rename as
|
|
2165
|
-
rm as
|
|
2166
|
-
writeFile as
|
|
2543
|
+
access as access6,
|
|
2544
|
+
mkdir as mkdir7,
|
|
2545
|
+
mkdtemp as mkdtemp5,
|
|
2546
|
+
readFile as readFile9,
|
|
2547
|
+
rename as rename8,
|
|
2548
|
+
rm as rm7,
|
|
2549
|
+
writeFile as writeFile8
|
|
2167
2550
|
} from "fs/promises";
|
|
2168
|
-
import { dirname as
|
|
2551
|
+
import { dirname as dirname5, join as join8, resolve as resolvePath2 } from "path";
|
|
2169
2552
|
import { pathToFileURL } from "url";
|
|
2170
2553
|
var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1;
|
|
2171
2554
|
var CURRENT_BUNDLE_FILE = "current.json";
|
|
2172
2555
|
var BUNDLES_DIRECTORY = "bundles";
|
|
2173
2556
|
var ARTIFACT_FILE2 = "artifact.json";
|
|
2174
2557
|
var BUNDLE_ID_PATTERN = /^amb_[a-f0-9]{64}$/;
|
|
2175
|
-
var
|
|
2558
|
+
var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2176
2559
|
var errorHasCode3 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code;
|
|
2177
2560
|
var bundleIdFor = (currentReleaseId, releases) => {
|
|
2178
2561
|
const identity = JSON.stringify({
|
|
2179
2562
|
currentReleaseId,
|
|
2180
2563
|
releases: releases.map(({ releaseId }) => releaseId)
|
|
2181
2564
|
});
|
|
2182
|
-
return `amb_${
|
|
2565
|
+
return `amb_${createHash7("sha256").update(identity).digest("hex")}`;
|
|
2183
2566
|
};
|
|
2184
2567
|
var parseBundleIndex = (value) => {
|
|
2185
|
-
if (!
|
|
2568
|
+
if (!isRecord6(value) || value.format !== ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT || typeof value.bundleId !== "string" || !BUNDLE_ID_PATTERN.test(value.bundleId) || typeof value.currentReleaseId !== "string" || !Array.isArray(value.releases)) {
|
|
2186
2569
|
throw new TypeError("Invalid materialized mobile compatibility bundle.");
|
|
2187
2570
|
}
|
|
2188
2571
|
const releases = value.releases.map(parseAbsoluteMobileCompatibilityArtifact);
|
|
@@ -2205,30 +2588,30 @@ var parseBundleIndex = (value) => {
|
|
|
2205
2588
|
};
|
|
2206
2589
|
};
|
|
2207
2590
|
var writeRelease = async (root, release) => {
|
|
2208
|
-
const directory =
|
|
2209
|
-
const producerPath =
|
|
2210
|
-
await
|
|
2591
|
+
const directory = join8(root, release.artifact.releaseId);
|
|
2592
|
+
const producerPath = join8(directory, release.artifact.producer.module);
|
|
2593
|
+
await mkdir7(dirname5(producerPath), { recursive: true });
|
|
2211
2594
|
await Promise.all([
|
|
2212
|
-
|
|
2595
|
+
writeFile8(join8(directory, ARTIFACT_FILE2), `${JSON.stringify(release.artifact, null, "\t")}
|
|
2213
2596
|
`),
|
|
2214
|
-
|
|
2597
|
+
writeFile8(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
|
|
2215
2598
|
]);
|
|
2216
2599
|
};
|
|
2217
2600
|
var installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
|
|
2218
|
-
const destination =
|
|
2601
|
+
const destination = join8(bundlesRoot, bundleId);
|
|
2219
2602
|
try {
|
|
2220
|
-
await
|
|
2603
|
+
await access6(destination);
|
|
2221
2604
|
return destination;
|
|
2222
2605
|
} catch (error) {
|
|
2223
2606
|
if (!errorHasCode3(error, "ENOENT"))
|
|
2224
2607
|
throw error;
|
|
2225
2608
|
}
|
|
2226
|
-
const staging = await
|
|
2609
|
+
const staging = await mkdtemp5(join8(bundlesRoot, ".stage-"));
|
|
2227
2610
|
try {
|
|
2228
2611
|
await Promise.all(releases.map((release) => writeRelease(staging, release)));
|
|
2229
|
-
await
|
|
2612
|
+
await rename8(staging, destination);
|
|
2230
2613
|
} catch (error) {
|
|
2231
|
-
await
|
|
2614
|
+
await rm7(staging, { force: true, recursive: true });
|
|
2232
2615
|
if (errorHasCode3(error, "EEXIST") || errorHasCode3(error, "ENOTEMPTY")) {
|
|
2233
2616
|
return destination;
|
|
2234
2617
|
}
|
|
@@ -2239,7 +2622,7 @@ var installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
|
|
|
2239
2622
|
var readCompatibilityModule = (modulePath) => import(pathToFileURL(modulePath).href);
|
|
2240
2623
|
var resolveProducerHandler = (loaded, exportName) => {
|
|
2241
2624
|
const value = loaded[exportName];
|
|
2242
|
-
if (!
|
|
2625
|
+
if (!isRecord6(value) || typeof value.handle !== "function") {
|
|
2243
2626
|
throw new TypeError(`Compatibility producer export ${exportName} must expose handle(request).`);
|
|
2244
2627
|
}
|
|
2245
2628
|
const { handle } = value;
|
|
@@ -2257,15 +2640,15 @@ var resolveProducerHandler = (loaded, exportName) => {
|
|
|
2257
2640
|
};
|
|
2258
2641
|
var loadAbsoluteMobileMaterializedBundle = async (root) => {
|
|
2259
2642
|
const resolvedRoot = resolvePath2(root);
|
|
2260
|
-
const serialized = await
|
|
2643
|
+
const serialized = await readFile9(join8(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
|
|
2261
2644
|
const parsed = JSON.parse(serialized);
|
|
2262
2645
|
const index = parseBundleIndex(parsed);
|
|
2263
|
-
const bundleRoot =
|
|
2646
|
+
const bundleRoot = join8(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
|
|
2264
2647
|
return {
|
|
2265
2648
|
artifacts: index.releases,
|
|
2266
2649
|
currentReleaseId: index.currentReleaseId,
|
|
2267
2650
|
loadProducer: async (artifact) => {
|
|
2268
|
-
const modulePath =
|
|
2651
|
+
const modulePath = join8(bundleRoot, artifact.releaseId, artifact.producer.module);
|
|
2269
2652
|
await verifyAbsoluteMobileCompatibilityProducer({
|
|
2270
2653
|
artifact,
|
|
2271
2654
|
producer: Bun.file(modulePath)
|
|
@@ -2292,8 +2675,8 @@ var materializeAbsoluteMobileCompatibilityBundle = async (input) => {
|
|
|
2292
2675
|
return release;
|
|
2293
2676
|
});
|
|
2294
2677
|
const root = resolvePath2(input.root);
|
|
2295
|
-
const bundlesRoot =
|
|
2296
|
-
await
|
|
2678
|
+
const bundlesRoot = join8(root, BUNDLES_DIRECTORY);
|
|
2679
|
+
await mkdir7(bundlesRoot, { recursive: true });
|
|
2297
2680
|
const bundleId = bundleIdFor(input.currentReleaseId, artifacts);
|
|
2298
2681
|
await installImmutableBundle(bundlesRoot, bundleId, orderedReleases);
|
|
2299
2682
|
const index = {
|
|
@@ -2302,22 +2685,22 @@ var materializeAbsoluteMobileCompatibilityBundle = async (input) => {
|
|
|
2302
2685
|
format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
|
|
2303
2686
|
releases: artifacts
|
|
2304
2687
|
};
|
|
2305
|
-
const pointerPath =
|
|
2306
|
-
const temporaryPointerPath =
|
|
2307
|
-
await
|
|
2688
|
+
const pointerPath = join8(root, CURRENT_BUNDLE_FILE);
|
|
2689
|
+
const temporaryPointerPath = join8(root, `.current-${crypto.randomUUID()}.json`);
|
|
2690
|
+
await writeFile8(temporaryPointerPath, `${JSON.stringify(index, null, "\t")}
|
|
2308
2691
|
`, { flag: "wx" });
|
|
2309
|
-
await
|
|
2692
|
+
await rename8(temporaryPointerPath, pointerPath);
|
|
2310
2693
|
return index;
|
|
2311
2694
|
};
|
|
2312
2695
|
var readAbsoluteMobileMaterializedReleases = async (root) => {
|
|
2313
2696
|
const resolvedRoot = resolvePath2(root);
|
|
2314
2697
|
try {
|
|
2315
|
-
const serialized = await
|
|
2698
|
+
const serialized = await readFile9(join8(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
|
|
2316
2699
|
const parsed = JSON.parse(serialized);
|
|
2317
2700
|
const index = parseBundleIndex(parsed);
|
|
2318
|
-
const bundleRoot =
|
|
2701
|
+
const bundleRoot = join8(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
|
|
2319
2702
|
return Promise.all(index.releases.map(async (artifact) => {
|
|
2320
|
-
const producer = Bun.file(
|
|
2703
|
+
const producer = Bun.file(join8(bundleRoot, artifact.releaseId, artifact.producer.module));
|
|
2321
2704
|
await verifyAbsoluteMobileCompatibilityProducer({
|
|
2322
2705
|
artifact,
|
|
2323
2706
|
producer
|
|
@@ -2366,11 +2749,11 @@ var loadServerApp = async (producerPath) => {
|
|
|
2366
2749
|
return { app, exportName };
|
|
2367
2750
|
};
|
|
2368
2751
|
var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
|
|
2369
|
-
const buildDirectory =
|
|
2752
|
+
const buildDirectory = resolve9(options.buildDirectory);
|
|
2370
2753
|
const mobile = normalizeAbsoluteMobileConfig(options.mobile, options.projectRoot);
|
|
2371
|
-
const root =
|
|
2754
|
+
const root = join9(buildDirectory, ".absolutejs", "mobile-compatibility");
|
|
2372
2755
|
const [manifestSource, previous] = await Promise.all([
|
|
2373
|
-
|
|
2756
|
+
readFile10(join9(buildDirectory, "manifest.json"), "utf8"),
|
|
2374
2757
|
readAbsoluteMobileMaterializedReleases(root)
|
|
2375
2758
|
]);
|
|
2376
2759
|
const manifest = JSON.parse(manifestSource);
|
|
@@ -2381,7 +2764,7 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
|
|
|
2381
2764
|
process.env.ABSOLUTE_BUILD_DIR = buildDirectory;
|
|
2382
2765
|
let loaded;
|
|
2383
2766
|
try {
|
|
2384
|
-
loaded = await loadServerApp(
|
|
2767
|
+
loaded = await loadServerApp(resolve9(options.producerPath));
|
|
2385
2768
|
} finally {
|
|
2386
2769
|
restoreBuildDirectory(previousBuildDirectory);
|
|
2387
2770
|
}
|
|
@@ -2392,7 +2775,7 @@ var finalizeAbsoluteMobileCompatibilityBuild = async (options) => {
|
|
|
2392
2775
|
manifest,
|
|
2393
2776
|
previousArtifacts: previous.map(({ artifact }) => artifact),
|
|
2394
2777
|
producerExport: loaded.exportName,
|
|
2395
|
-
producerPath:
|
|
2778
|
+
producerPath: resolve9(options.producerPath),
|
|
2396
2779
|
runtime: String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)
|
|
2397
2780
|
});
|
|
2398
2781
|
const releasesById = new Map([current, ...previous].map((release) => [
|
|
@@ -2486,20 +2869,20 @@ var createAbsoluteMobileCompatibilityDispatcher = (options) => {
|
|
|
2486
2869
|
}).as("global");
|
|
2487
2870
|
};
|
|
2488
2871
|
// src/mobile/nativeDeepLinks.ts
|
|
2489
|
-
import { readFile as
|
|
2490
|
-
import { join as
|
|
2872
|
+
import { readFile as readFile11, rename as rename9, writeFile as writeFile9 } from "fs/promises";
|
|
2873
|
+
import { join as join10 } from "path";
|
|
2491
2874
|
var START_MARKER = "<!-- absolutejs:deep-links:start -->";
|
|
2492
2875
|
var END_MARKER = "<!-- absolutejs:deep-links:end -->";
|
|
2493
2876
|
var IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements";
|
|
2494
2877
|
var NOT_FOUND = -1;
|
|
2495
2878
|
var escapeXml = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
2496
2879
|
var writeChangedFile = async (path, source) => {
|
|
2497
|
-
const current = await
|
|
2880
|
+
const current = await readFile11(path, "utf8");
|
|
2498
2881
|
if (current === source)
|
|
2499
2882
|
return false;
|
|
2500
2883
|
const temporary = `${path}.${crypto.randomUUID()}.tmp`;
|
|
2501
|
-
await
|
|
2502
|
-
await
|
|
2884
|
+
await writeFile9(temporary, source, { flag: "wx" });
|
|
2885
|
+
await rename9(temporary, path);
|
|
2503
2886
|
return true;
|
|
2504
2887
|
};
|
|
2505
2888
|
var replaceManagedRegion = (source, region, insertAt) => {
|
|
@@ -2544,8 +2927,8 @@ ${hosts}
|
|
|
2544
2927
|
`;
|
|
2545
2928
|
};
|
|
2546
2929
|
var configureAndroid = async (config) => {
|
|
2547
|
-
const path =
|
|
2548
|
-
const source = await
|
|
2930
|
+
const path = join10(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
|
|
2931
|
+
const source = await readFile11(path, "utf8");
|
|
2549
2932
|
const mainActivity = source.indexOf('android:name=".MainActivity"');
|
|
2550
2933
|
if (mainActivity === NOT_FOUND) {
|
|
2551
2934
|
throw new TypeError("Android MainActivity was not found.");
|
|
@@ -2570,8 +2953,8 @@ var iosSchemeRegion = (scheme) => ` ${START_MARKER}
|
|
|
2570
2953
|
${END_MARKER}
|
|
2571
2954
|
`;
|
|
2572
2955
|
var configureIosInfo = async (config) => {
|
|
2573
|
-
const path =
|
|
2574
|
-
const source = await
|
|
2956
|
+
const path = join10(config.nativeProjectDirectory, "ios/App/App/Info.plist");
|
|
2957
|
+
const source = await readFile11(path, "utf8");
|
|
2575
2958
|
const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
|
|
2576
2959
|
${END_MARKER}
|
|
2577
2960
|
`;
|
|
@@ -2594,10 +2977,10 @@ ${domains}
|
|
|
2594
2977
|
`;
|
|
2595
2978
|
};
|
|
2596
2979
|
var configureIosEntitlements = async (config) => {
|
|
2597
|
-
const path =
|
|
2980
|
+
const path = join10(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
|
|
2598
2981
|
let current = "";
|
|
2599
2982
|
try {
|
|
2600
|
-
current = await
|
|
2983
|
+
current = await readFile11(path, "utf8");
|
|
2601
2984
|
} catch (error) {
|
|
2602
2985
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
|
|
2603
2986
|
throw error;
|
|
@@ -2607,13 +2990,13 @@ var configureIosEntitlements = async (config) => {
|
|
|
2607
2990
|
if (current === source)
|
|
2608
2991
|
return false;
|
|
2609
2992
|
const temporary = `${path}.${crypto.randomUUID()}.tmp`;
|
|
2610
|
-
await
|
|
2611
|
-
await
|
|
2993
|
+
await writeFile9(temporary, source, { flag: "wx" });
|
|
2994
|
+
await rename9(temporary, path);
|
|
2612
2995
|
return true;
|
|
2613
2996
|
};
|
|
2614
2997
|
var configureIosProject = async (config) => {
|
|
2615
|
-
const path =
|
|
2616
|
-
const source = await
|
|
2998
|
+
const path = join10(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
|
|
2999
|
+
const source = await readFile11(path, "utf8");
|
|
2617
3000
|
const declarations = [
|
|
2618
3001
|
...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
|
|
2619
3002
|
].map((match) => match[1]);
|
|
@@ -2650,15 +3033,113 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
|
|
|
2650
3033
|
changed: results.filter(({ didChange }) => didChange).map(({ platform }) => platform)
|
|
2651
3034
|
};
|
|
2652
3035
|
};
|
|
3036
|
+
// src/mobile/releasePublisher.ts
|
|
3037
|
+
import { access as access7 } from "fs/promises";
|
|
3038
|
+
import { isAbsolute as isAbsolute4, relative as relative6, resolve as resolve10, sep as sep4 } from "path";
|
|
3039
|
+
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
3040
|
+
var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
3041
|
+
if (typeof publisher.prepareIosRelease !== "function") {
|
|
3042
|
+
throw new TypeError("App Store Connect publishing requires a registry module created with @absolutejs/deploy/app-store-connect.");
|
|
3043
|
+
}
|
|
3044
|
+
const { buildNumber } = await publisher.prepareIosRelease(options);
|
|
3045
|
+
if (!Number.isSafeInteger(buildNumber) || buildNumber < 1) {
|
|
3046
|
+
throw new TypeError("App Store Connect publisher returned an invalid iOS build number.");
|
|
3047
|
+
}
|
|
3048
|
+
return buildNumber;
|
|
3049
|
+
};
|
|
3050
|
+
var prepareAbsoluteAndroidRelease = async (publisher, options) => {
|
|
3051
|
+
if (typeof publisher.prepareAndroidRelease !== "function") {
|
|
3052
|
+
throw new TypeError("Google Play publishing requires a registry module created with @absolutejs/deploy/google-play.");
|
|
3053
|
+
}
|
|
3054
|
+
const prepared = await publisher.prepareAndroidRelease(options);
|
|
3055
|
+
const { versionCode } = prepared;
|
|
3056
|
+
if (typeof versionCode !== "number" || !Number.isSafeInteger(versionCode) || versionCode < 1 || versionCode > 2100000000) {
|
|
3057
|
+
throw new TypeError("Google Play publisher returned an invalid Android versionCode.");
|
|
3058
|
+
}
|
|
3059
|
+
return versionCode;
|
|
3060
|
+
};
|
|
3061
|
+
var isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3062
|
+
var isPublisher = (value) => isRecord7(value) && typeof value.publish === "function";
|
|
3063
|
+
var publisherModulePath = (projectRoot, requested) => {
|
|
3064
|
+
const root = resolve10(projectRoot);
|
|
3065
|
+
const path = resolve10(root, requested);
|
|
3066
|
+
const projectRelative = relative6(root, path);
|
|
3067
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep4}`) || isAbsolute4(projectRelative)) {
|
|
3068
|
+
throw new TypeError("mobile publish --registry must remain inside the project.");
|
|
3069
|
+
}
|
|
3070
|
+
return path;
|
|
3071
|
+
};
|
|
3072
|
+
var loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath) => {
|
|
3073
|
+
const modulePath = publisherModulePath(projectRoot, requestedModulePath);
|
|
3074
|
+
await access7(modulePath).catch(() => {
|
|
3075
|
+
throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
|
|
3076
|
+
});
|
|
3077
|
+
const loaded = await import(pathToFileURL3(modulePath).href);
|
|
3078
|
+
const publisher = isRecord7(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
3079
|
+
if (!isPublisher(publisher)) {
|
|
3080
|
+
throw new TypeError("Native release registry module must default-export a registry with publish(options).");
|
|
3081
|
+
}
|
|
3082
|
+
return publisher;
|
|
3083
|
+
};
|
|
3084
|
+
var publishAbsoluteAndroidRelease = async (options) => {
|
|
3085
|
+
const publisher = await loadAbsoluteNativeReleasePublisher(options.projectRoot, options.modulePath);
|
|
3086
|
+
const publication = await publisher.publish({
|
|
3087
|
+
allowUnsigned: options.allowUnsigned,
|
|
3088
|
+
channel: options.channel,
|
|
3089
|
+
googlePlay: options.googlePlay,
|
|
3090
|
+
releaseRoot: options.release.releaseRoot,
|
|
3091
|
+
signal: options.signal
|
|
3092
|
+
});
|
|
3093
|
+
const expected = options.release.metadata;
|
|
3094
|
+
const actual = publication.record?.metadata;
|
|
3095
|
+
if (!actual || actual.appId !== expected.appId || actual.platform !== "android" || actual.releaseId !== expected.releaseId || actual.sha256 !== expected.sha256 || actual.signed !== expected.signed || actual.versionCode !== expected.versionCode || typeof publication.reused !== "boolean") {
|
|
3096
|
+
throw new TypeError("Native release registry returned a different Android release identity.");
|
|
3097
|
+
}
|
|
3098
|
+
if (options.channel !== undefined && (publication.channel?.channel !== options.channel || publication.channel.releaseId !== expected.releaseId)) {
|
|
3099
|
+
throw new TypeError("Native release registry did not promote the requested channel.");
|
|
3100
|
+
}
|
|
3101
|
+
const { googlePlay } = publication;
|
|
3102
|
+
if (options.googlePlay) {
|
|
3103
|
+
if (!expected.versionCode || !googlePlay || googlePlay.receipt.provider !== "google-play" || googlePlay.receipt.packageName !== expected.appId || googlePlay.receipt.releaseId !== expected.releaseId || googlePlay.receipt.sha256 !== expected.sha256 || googlePlay.receipt.stage !== "committed" || googlePlay.receipt.intent.track !== options.googlePlay.track || typeof googlePlay.receipt.versionCode !== "string" || !/^\d+$/.test(googlePlay.receipt.versionCode) || Number(googlePlay.receipt.versionCode) !== expected.versionCode || typeof googlePlay.reused !== "boolean") {
|
|
3104
|
+
throw new TypeError("Native release publisher did not commit the requested Google Play release.");
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
return publication;
|
|
3108
|
+
};
|
|
3109
|
+
var publishAbsoluteIosRelease = async (options) => {
|
|
3110
|
+
const publisher = await loadAbsoluteNativeReleasePublisher(options.projectRoot, options.modulePath);
|
|
3111
|
+
const publication = await publisher.publish({
|
|
3112
|
+
allowUnsigned: options.allowUnsigned,
|
|
3113
|
+
appStoreConnect: options.appStoreConnect,
|
|
3114
|
+
channel: options.channel,
|
|
3115
|
+
releaseRoot: options.release.releaseRoot,
|
|
3116
|
+
signal: options.signal
|
|
3117
|
+
});
|
|
3118
|
+
const expected = options.release.metadata;
|
|
3119
|
+
const actual = publication.record?.metadata;
|
|
3120
|
+
if (!actual || actual.appId !== expected.appId || actual.platform !== "ios" || actual.releaseId !== expected.releaseId || actual.sha256 !== expected.sha256 || actual.signed !== expected.signed || actual.buildNumber !== expected.buildNumber || actual.marketingVersion !== expected.marketingVersion || typeof publication.reused !== "boolean") {
|
|
3121
|
+
throw new TypeError("Native release registry returned a different iOS release identity.");
|
|
3122
|
+
}
|
|
3123
|
+
if (options.channel !== undefined && (publication.channel?.channel !== options.channel || publication.channel.releaseId !== expected.releaseId)) {
|
|
3124
|
+
throw new TypeError("Native release registry did not promote the requested channel.");
|
|
3125
|
+
}
|
|
3126
|
+
if (options.appStoreConnect) {
|
|
3127
|
+
const distributed = publication.appStoreConnect;
|
|
3128
|
+
if (!expected.buildNumber || !distributed || distributed.receipt.provider !== "app-store-connect" || distributed.receipt.releaseId !== expected.releaseId || distributed.receipt.sha256 !== expected.sha256 || distributed.receipt.buildNumber !== expected.buildNumber || distributed.receipt.marketingVersion !== expected.marketingVersion || !["distributed", "review-submitted"].includes(distributed.receipt.stage) || JSON.stringify([...distributed.receipt.intent.groups].sort()) !== JSON.stringify([...options.appStoreConnect.groups ?? []].sort()) || distributed.receipt.intent.submitForReview !== (options.appStoreConnect.submitForReview ?? false) || typeof distributed.reused !== "boolean") {
|
|
3129
|
+
throw new TypeError("Native release publisher did not complete the requested App Store Connect release.");
|
|
3130
|
+
}
|
|
3131
|
+
}
|
|
3132
|
+
return publication;
|
|
3133
|
+
};
|
|
2653
3134
|
// src/mobile/routeMetadataTransform.ts
|
|
2654
3135
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
2655
|
-
import { dirname as
|
|
3136
|
+
import { dirname as dirname6, extname as extname2, relative as relative7, resolve as resolve11 } from "path";
|
|
2656
3137
|
import ts from "typescript";
|
|
2657
3138
|
var ROUTE_METHODS = new Set(["get", "head"]);
|
|
2658
3139
|
var SOURCE_FILTER = /\.[cm]?[jt]sx?$/;
|
|
2659
3140
|
var PAGE_HANDLER = "handleReactPageRequest";
|
|
2660
3141
|
var posixPath = (value) => value.replace(/\\/g, "/");
|
|
2661
|
-
var findTsconfig = (entry, projectRoot) => ts.findConfigFile(
|
|
3142
|
+
var findTsconfig = (entry, projectRoot) => ts.findConfigFile(dirname6(entry), existsSync3, "tsconfig.json") ?? ts.findConfigFile(projectRoot, existsSync3, "tsconfig.json");
|
|
2662
3143
|
var createProgram = (entry, projectRoot) => {
|
|
2663
3144
|
const configPath = findTsconfig(entry, projectRoot);
|
|
2664
3145
|
if (!configPath) {
|
|
@@ -2670,7 +3151,7 @@ var createProgram = (entry, projectRoot) => {
|
|
|
2670
3151
|
target: ts.ScriptTarget.ESNext
|
|
2671
3152
|
});
|
|
2672
3153
|
}
|
|
2673
|
-
const parsed = ts.parseJsonConfigFileContent(ts.readConfigFile(configPath, (path) => readFileSync2(path, "utf8")).config, ts.sys,
|
|
3154
|
+
const parsed = ts.parseJsonConfigFileContent(ts.readConfigFile(configPath, (path) => readFileSync2(path, "utf8")).config, ts.sys, dirname6(configPath));
|
|
2674
3155
|
if (!parsed.fileNames.includes(entry))
|
|
2675
3156
|
parsed.fileNames.push(entry);
|
|
2676
3157
|
return ts.createProgram(parsed.fileNames, parsed.options);
|
|
@@ -2776,7 +3257,7 @@ var resolvePageIdentity = (expression, sourceFile, checker, projectRoot) => {
|
|
|
2776
3257
|
const declaration = symbol?.declarations?.[0];
|
|
2777
3258
|
const file = declaration?.getSourceFile().fileName ?? sourceFile.fileName;
|
|
2778
3259
|
const exportedName = symbol?.name ?? expression.getText(sourceFile);
|
|
2779
|
-
const source = posixPath(
|
|
3260
|
+
const source = posixPath(relative7(projectRoot, file));
|
|
2780
3261
|
return `${source}#${exportedName}`;
|
|
2781
3262
|
};
|
|
2782
3263
|
var resolveAlias = (symbol, checker) => {
|
|
@@ -2883,7 +3364,7 @@ var analyzeProgram = (program, projectRoot) => {
|
|
|
2883
3364
|
const checker = program.getTypeChecker();
|
|
2884
3365
|
const analyzed = new Map;
|
|
2885
3366
|
for (const sourceFile of program.getSourceFiles()) {
|
|
2886
|
-
const resolvedFile =
|
|
3367
|
+
const resolvedFile = resolve11(sourceFile.fileName);
|
|
2887
3368
|
if (!isProjectSource(sourceFile, resolvedFile, projectRoot))
|
|
2888
3369
|
continue;
|
|
2889
3370
|
const analysis = analyzeSourceFile(sourceFile, checker, projectRoot);
|
|
@@ -2966,14 +3447,14 @@ var transformFile = (source, fileName, analysis) => {
|
|
|
2966
3447
|
};
|
|
2967
3448
|
var ABSOLUTE_MOBILE_TRANSFORM_PROTOCOL = ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION;
|
|
2968
3449
|
var createAbsoluteMobileRouteMetadataPlugin = (options) => {
|
|
2969
|
-
const projectRoot =
|
|
2970
|
-
const entry =
|
|
3450
|
+
const projectRoot = resolve11(options.projectRoot ?? process.cwd());
|
|
3451
|
+
const entry = resolve11(options.entry);
|
|
2971
3452
|
const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
|
|
2972
3453
|
return {
|
|
2973
3454
|
name: "absolute-mobile-route-metadata",
|
|
2974
3455
|
setup(build) {
|
|
2975
3456
|
build.onLoad({ filter: SOURCE_FILTER }, async ({ path }) => {
|
|
2976
|
-
const analysis = analyzed.get(
|
|
3457
|
+
const analysis = analyzed.get(resolve11(path));
|
|
2977
3458
|
if (!analysis)
|
|
2978
3459
|
return;
|
|
2979
3460
|
const source = await Bun.file(path).text();
|
|
@@ -2986,11 +3467,11 @@ var createAbsoluteMobileRouteMetadataPlugin = (options) => {
|
|
|
2986
3467
|
};
|
|
2987
3468
|
};
|
|
2988
3469
|
var inspectAbsoluteMobileRouteMetadata = (options) => {
|
|
2989
|
-
const projectRoot =
|
|
2990
|
-
const entry =
|
|
3470
|
+
const projectRoot = resolve11(options.projectRoot ?? process.cwd());
|
|
3471
|
+
const entry = resolve11(options.entry);
|
|
2991
3472
|
const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
|
|
2992
3473
|
return [...analyzed.entries()].flatMap(([file, analysis]) => [...analysis.byRouteCall.values()].map(({ metadata }) => ({
|
|
2993
|
-
file: posixPath(
|
|
3474
|
+
file: posixPath(relative7(projectRoot, file)),
|
|
2994
3475
|
metadata
|
|
2995
3476
|
})));
|
|
2996
3477
|
};
|
|
@@ -3004,6 +3485,10 @@ export {
|
|
|
3004
3485
|
resolveAbsoluteMobileDeepLink,
|
|
3005
3486
|
resolveAbsoluteMobileCompatibilityRelease,
|
|
3006
3487
|
readAbsoluteMobileMaterializedReleases,
|
|
3488
|
+
publishAbsoluteIosRelease,
|
|
3489
|
+
publishAbsoluteAndroidRelease,
|
|
3490
|
+
prepareAbsoluteIosRelease,
|
|
3491
|
+
prepareAbsoluteAndroidRelease,
|
|
3007
3492
|
parseAbsoluteMobilePageRequest,
|
|
3008
3493
|
parseAbsoluteMobilePageEnvelope,
|
|
3009
3494
|
parseAbsoluteMobileCompatibilityArtifact,
|
|
@@ -3014,10 +3499,12 @@ export {
|
|
|
3014
3499
|
materializeAbsoluteMobileAssociationFiles,
|
|
3015
3500
|
materializeAbsoluteCapacitorWebBundle,
|
|
3016
3501
|
matchesAbsoluteMobileRoutePattern,
|
|
3502
|
+
loadAbsoluteNativeReleasePublisher,
|
|
3017
3503
|
loadAbsoluteMobileMaterializedBundle,
|
|
3018
3504
|
inspectAbsoluteMobileRouteMetadata,
|
|
3019
3505
|
hashAbsoluteMobilePropsSchema,
|
|
3020
3506
|
getCurrentAbsoluteMobileProducerContext,
|
|
3507
|
+
fingerprintAbsoluteIosNativeProject,
|
|
3021
3508
|
finalizeAbsoluteMobilePage,
|
|
3022
3509
|
finalizeAbsoluteMobileCompatibilityBuild,
|
|
3023
3510
|
fetchAbsoluteMobilePage,
|
|
@@ -3035,6 +3522,7 @@ export {
|
|
|
3035
3522
|
carryForwardAbsoluteMobileCompatibilityReleases,
|
|
3036
3523
|
captureAbsoluteMobileRouteGraph,
|
|
3037
3524
|
buildAbsoluteMobileCompatibilityRelease,
|
|
3525
|
+
buildAbsoluteIosRelease,
|
|
3038
3526
|
buildAbsoluteAndroidRelease,
|
|
3039
3527
|
applyAbsoluteNativeDeepLinks,
|
|
3040
3528
|
activateAbsoluteMobilePage,
|
|
@@ -3051,8 +3539,9 @@ export {
|
|
|
3051
3539
|
ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
|
|
3052
3540
|
ABSOLUTE_MOBILE_COMPATIBILITY_FORMAT,
|
|
3053
3541
|
ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT,
|
|
3542
|
+
ABSOLUTE_IOS_RELEASE_FORMAT,
|
|
3054
3543
|
ABSOLUTE_ANDROID_RELEASE_FORMAT
|
|
3055
3544
|
};
|
|
3056
3545
|
|
|
3057
|
-
//# debugId=
|
|
3546
|
+
//# debugId=8F6E00755BF98A2E64756E2164756E21
|
|
3058
3547
|
//# sourceMappingURL=index.js.map
|