@absolutejs/absolute 0.20.0-beta.44 → 0.20.0-beta.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/build.js +3 -2
- package/dist/build.js.map +3 -3
- package/dist/cli/index.js +1409 -1247
- package/dist/index.js +34 -7
- package/dist/index.js.map +5 -5
- package/dist/mobile/browser.js.map +1 -1
- package/dist/mobile/index.js +223 -39
- package/dist/mobile/index.js.map +9 -9
- package/dist/mobile/remoteMacAgentEntry.js +157 -45
- package/dist/mobile/shellExpoSync.js +104 -0
- package/dist/src/mobile/devDeviceAdapter.d.ts +1 -1
- package/dist/src/mobile/expoBridge.d.ts +12 -12
- package/dist/src/mobile/nativeAuth.d.ts +3 -0
- package/dist/src/mobile/shellExpoSync.d.ts +18 -0
- package/package.json +3 -2
package/dist/cli/index.js
CHANGED
|
@@ -850,7 +850,7 @@ var init_config = __esm(() => {
|
|
|
850
850
|
// src/mobile/nativeAuth.ts
|
|
851
851
|
import { readFileSync as readFileSync5 } from "fs";
|
|
852
852
|
import { join as join5 } from "path";
|
|
853
|
-
var ABSOLUTE_AUTH_PACKAGE = "@absolutejs/auth", ABSOLUTE_EXPO_AUTH_CORE_VERSION = "0.75.6", ABSOLUTE_EXPO_AUTH_PACKAGE = "@absolutejs/auth-expo", ABSOLUTE_EXPO_AUTH_VERSION = "0.0.2", ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV = "ABSOLUTE_AUTH_NATIVE_CLIENTS", ABSOLUTE_NATIVE_AUTH_SCOPES, ABSOLUTE_SYNC_PACKAGE = "@absolutejs/sync", readPackageManifest = (projectRoot) => {
|
|
853
|
+
var ABSOLUTE_AUTH_PACKAGE = "@absolutejs/auth", ABSOLUTE_EXPO_AUTH_CORE_VERSION = "0.75.6", ABSOLUTE_EXPO_AUTH_PACKAGE = "@absolutejs/auth-expo", ABSOLUTE_EXPO_AUTH_VERSION = "0.0.2", ABSOLUTE_EXPO_SYNC_CORE_VERSION = "2.31.0", ABSOLUTE_EXPO_SYNC_PACKAGE = "@absolutejs/sync-expo", ABSOLUTE_EXPO_SYNC_VERSION = "0.0.2", ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV = "ABSOLUTE_AUTH_NATIVE_CLIENTS", ABSOLUTE_NATIVE_AUTH_SCOPES, ABSOLUTE_SYNC_PACKAGE = "@absolutejs/sync", readPackageManifest = (projectRoot) => {
|
|
854
854
|
try {
|
|
855
855
|
return JSON.parse(readFileSync5(join5(projectRoot, "package.json"), "utf8"));
|
|
856
856
|
} catch {
|
|
@@ -891,162 +891,699 @@ var init_nativeAuth = __esm(() => {
|
|
|
891
891
|
ABSOLUTE_NATIVE_AUTH_SCOPES = ["openid", "profile"];
|
|
892
892
|
});
|
|
893
893
|
|
|
894
|
-
//
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
} catch {
|
|
914
|
-
return false;
|
|
894
|
+
// node_modules/@absolutejs/sync/dist/client/index.js
|
|
895
|
+
var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")) && Array.isArray(Reflect.get(value, "clients")), registry, pools, SyncLocalDataPolicyError, SyncLocalStoreSchemaError, positiveVersion = (value, label) => {
|
|
896
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
897
|
+
throw new SyncLocalStoreSchemaError("INVALID_PLAN", `${label} must be a positive safe integer`);
|
|
898
|
+
return value;
|
|
899
|
+
}, isSchemaBundle = (schema) => ("components" in schema), validatePolicyMatch = (match, label) => {
|
|
900
|
+
if (match.length === 0 || match.trim() !== match || /^\*+$/.test(match) || match.includes("**"))
|
|
901
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.match must be an exact name or a non-empty glob without adjacent wildcards.`);
|
|
902
|
+
}, validateSyncLocalDataPolicy = (policy, label = "localData") => {
|
|
903
|
+
if (policy.maxBytesPerNamespace !== undefined && (!Number.isSafeInteger(policy.maxBytesPerNamespace) || policy.maxBytesPerNamespace < 1))
|
|
904
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.maxBytesPerNamespace must be a positive safe integer.`);
|
|
905
|
+
for (const [index, rule] of (policy.collections ?? []).entries()) {
|
|
906
|
+
validatePolicyMatch(rule.match, `${label}.collections[${index}]`);
|
|
907
|
+
if (rule.maxAgeMs !== undefined && (!Number.isSafeInteger(rule.maxAgeMs) || rule.maxAgeMs < 1))
|
|
908
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}].maxAgeMs must be a positive safe integer.`);
|
|
909
|
+
if (rule.persistence === "memory-only" && rule.protection === "required")
|
|
910
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] cannot require at-rest protection when it is memory-only.`);
|
|
911
|
+
if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
|
|
912
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] declares ${rule.sensitivity} data without required protection or memory-only persistence.`);
|
|
915
913
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
914
|
+
for (const [index, rule] of (policy.mutations ?? []).entries()) {
|
|
915
|
+
validatePolicyMatch(rule.match, `${label}.mutations[${index}]`);
|
|
916
|
+
if (rule.conflict !== undefined && rule.conflict.strategy !== "client-wins" && rule.conflict.strategy !== "manual" && rule.conflict.strategy !== "server-wins")
|
|
917
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.strategy is invalid.`);
|
|
918
|
+
if (rule.conflict?.maxAttempts !== undefined && (!Number.isSafeInteger(rule.conflict.maxAttempts) || rule.conflict.maxAttempts < 1))
|
|
919
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.maxAttempts must be a positive safe integer.`);
|
|
920
|
+
if (rule.conflict?.maxAttempts !== undefined && rule.conflict.strategy !== "client-wins")
|
|
921
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.maxAttempts is only valid for client-wins.`);
|
|
922
|
+
if (rule.persistence === "memory-only" && rule.protection === "required")
|
|
923
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] cannot require at-rest protection when it is memory-only.`);
|
|
924
|
+
if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
|
|
925
|
+
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] declares ${rule.sensitivity} arguments without required protection.`);
|
|
924
926
|
}
|
|
925
|
-
return
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
"expo-haptics": "~57.0.2",
|
|
938
|
-
"expo-linking": "~57.0.8",
|
|
939
|
-
"expo-router": "~57.0.17",
|
|
940
|
-
...auth ? {
|
|
941
|
-
"expo-secure-store": "~57.0.2",
|
|
942
|
-
"expo-web-browser": "~57.0.2"
|
|
943
|
-
} : {},
|
|
944
|
-
react: "19.2.3",
|
|
945
|
-
"react-native": "0.86.3",
|
|
946
|
-
"react-native-safe-area-context": "~5.7.0",
|
|
947
|
-
"react-native-screens": "4.26.0",
|
|
948
|
-
"react-native-webview": "13.16.1"
|
|
949
|
-
},
|
|
950
|
-
devDependencies: {
|
|
951
|
-
"@types/react": "~19.2.2",
|
|
952
|
-
typescript: "~6.0.3"
|
|
953
|
-
},
|
|
954
|
-
main: "expo-router/entry",
|
|
955
|
-
name: "absolutejs-expo-shell",
|
|
956
|
-
private: true,
|
|
957
|
-
scripts: {
|
|
958
|
-
android: "expo run:android",
|
|
959
|
-
ios: "expo run:ios",
|
|
960
|
-
start: "expo start --dev-client"
|
|
961
|
-
},
|
|
962
|
-
version: "0.0.0"
|
|
963
|
-
}), expoAppConfig = (config, auth) => ({
|
|
964
|
-
expo: {
|
|
965
|
-
android: {
|
|
966
|
-
intentFilters: config.deepLinkHosts.map((host) => ({
|
|
967
|
-
action: "VIEW",
|
|
968
|
-
autoVerify: true,
|
|
969
|
-
category: ["BROWSABLE", "DEFAULT"],
|
|
970
|
-
data: [{ host, pathPrefix: "/", scheme: "https" }]
|
|
971
|
-
})),
|
|
972
|
-
package: config.appId
|
|
973
|
-
},
|
|
974
|
-
experiments: { typedRoutes: true },
|
|
975
|
-
ios: {
|
|
976
|
-
associatedDomains: config.deepLinkHosts.map((host) => `applinks:${host}`),
|
|
977
|
-
bundleIdentifier: config.appId,
|
|
978
|
-
...config.iosVersion ? { buildNumber: config.iosVersion } : {}
|
|
979
|
-
},
|
|
980
|
-
name: config.appName,
|
|
981
|
-
plugins: [
|
|
982
|
-
"expo-router",
|
|
983
|
-
["expo-dev-client", { launchMode: "most-recent" }],
|
|
984
|
-
...auth ? ["expo-secure-store"] : []
|
|
985
|
-
],
|
|
986
|
-
runtimeVersion: { policy: "appVersion" },
|
|
987
|
-
scheme: config.deepLinkScheme,
|
|
988
|
-
slug: config.appId.toLowerCase().replaceAll(".", "-"),
|
|
989
|
-
version: config.iosVersion ?? "0.1.0"
|
|
927
|
+
return policy;
|
|
928
|
+
}, normalizeSyncLocalSchemaComponents = (schema = { version: 1 }) => {
|
|
929
|
+
const components = isSchemaBundle(schema) ? [...schema.components] : [{ ...schema, id: "@absolutejs/app" }];
|
|
930
|
+
const ids = new Set;
|
|
931
|
+
for (const component of components) {
|
|
932
|
+
if (typeof component.id !== "string" || component.id.trim() !== component.id || component.id.length === 0)
|
|
933
|
+
throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Sync schema component id must be non-empty and trimmed");
|
|
934
|
+
if (ids.has(component.id))
|
|
935
|
+
throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync schema component "${component.id}" is declared more than once`);
|
|
936
|
+
ids.add(component.id);
|
|
937
|
+
if (component.localData)
|
|
938
|
+
validateSyncLocalDataPolicy(component.localData, `${component.id}.localData`);
|
|
990
939
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
940
|
+
return components.sort((a, b) => a.id.localeCompare(b.id));
|
|
941
|
+
}, resolveSyncLocalSchemaComponents = (storedVersions, schema = { version: 1 }) => {
|
|
942
|
+
const components = normalizeSyncLocalSchemaComponents(schema).map((component) => {
|
|
943
|
+
const current = resolveSyncLocalMigrations(component.version, component);
|
|
944
|
+
return {
|
|
945
|
+
id: component.id,
|
|
946
|
+
...resolveSyncLocalMigrations(storedVersions[component.id] ?? current.minimumCompatibleVersion, component)
|
|
947
|
+
};
|
|
948
|
+
});
|
|
949
|
+
const active = new Set(components.map((component) => component.id));
|
|
950
|
+
const orphanedComponents = Object.keys(storedVersions).filter((id) => !active.has(id)).sort();
|
|
951
|
+
return { components, orphanedComponents };
|
|
952
|
+
}, resolveSyncLocalMigrations = (storedVersion, schema = { version: 1 }) => {
|
|
953
|
+
positiveVersion(storedVersion, "Stored Sync schema version");
|
|
954
|
+
const targetVersion = positiveVersion(schema.version, "Target Sync schema version");
|
|
955
|
+
const migrations = [...schema.migrations ?? []].sort((a, b) => a.toVersion - b.toVersion);
|
|
956
|
+
const versions = new Set;
|
|
957
|
+
for (const migration of migrations) {
|
|
958
|
+
positiveVersion(migration.toVersion, "Sync migration toVersion");
|
|
959
|
+
if (versions.has(migration.toVersion))
|
|
960
|
+
throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync migration ${migration.toVersion} is declared more than once`);
|
|
961
|
+
versions.add(migration.toVersion);
|
|
962
|
+
}
|
|
963
|
+
const inferredMinimum = migrations[0] ? migrations[0].toVersion - 1 : targetVersion;
|
|
964
|
+
const minimumCompatibleVersion = positiveVersion(schema.minimumCompatibleVersion ?? inferredMinimum, "Minimum compatible Sync schema version");
|
|
965
|
+
if (minimumCompatibleVersion > targetVersion)
|
|
966
|
+
throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Minimum compatible Sync schema version cannot exceed its target");
|
|
967
|
+
if (storedVersion > targetVersion)
|
|
968
|
+
throw new SyncLocalStoreSchemaError("SCHEMA_TOO_NEW", `Stored Sync schema ${storedVersion} is newer than this runtime's schema ${targetVersion}`, { storedVersion, targetVersion });
|
|
969
|
+
if (storedVersion < minimumCompatibleVersion)
|
|
970
|
+
throw new SyncLocalStoreSchemaError("SCHEMA_TOO_OLD", `Stored Sync schema ${storedVersion} is older than the minimum compatible schema ${minimumCompatibleVersion}`, { storedVersion, targetVersion });
|
|
971
|
+
const steps = [];
|
|
972
|
+
for (let version = storedVersion + 1;version <= targetVersion; version++) {
|
|
973
|
+
const migration = migrations.find((candidate) => candidate.toVersion === version);
|
|
974
|
+
if (migration === undefined)
|
|
975
|
+
throw new SyncLocalStoreSchemaError("MIGRATION_MISSING", `Sync migration ${version - 1} -> ${version} is missing`, { storedVersion, targetVersion });
|
|
976
|
+
steps.push(migration);
|
|
977
|
+
}
|
|
978
|
+
return { minimumCompatibleVersion, steps, targetVersion };
|
|
979
|
+
};
|
|
980
|
+
var init_client = __esm(() => {
|
|
981
|
+
RUNTIME_TRANSPORT = Symbol.for("@absolutejs/sync/client-runtime-transport");
|
|
982
|
+
host = globalThis;
|
|
983
|
+
registry = (() => {
|
|
984
|
+
const existing = host[RUNTIME_TRANSPORT];
|
|
985
|
+
if (isRegistry(existing))
|
|
986
|
+
return existing;
|
|
987
|
+
if (typeof existing === "object" && existing !== null && Array.isArray(Reflect.get(existing, "installations"))) {
|
|
988
|
+
Reflect.set(existing, "clients", []);
|
|
989
|
+
return existing;
|
|
990
|
+
}
|
|
991
|
+
const created = { clients: [], installations: [] };
|
|
992
|
+
Object.defineProperty(host, RUNTIME_TRANSPORT, {
|
|
993
|
+
configurable: false,
|
|
994
|
+
enumerable: false,
|
|
995
|
+
value: created,
|
|
996
|
+
writable: false
|
|
997
|
+
});
|
|
998
|
+
return created;
|
|
999
|
+
})();
|
|
1000
|
+
pools = new Map;
|
|
1001
|
+
SyncLocalDataPolicyError = class SyncLocalDataPolicyError extends Error {
|
|
1002
|
+
code;
|
|
1003
|
+
constructor(code, message) {
|
|
1004
|
+
super(message);
|
|
1005
|
+
this.name = "SyncLocalDataPolicyError";
|
|
1006
|
+
this.code = code;
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
SyncLocalStoreSchemaError = class SyncLocalStoreSchemaError extends Error {
|
|
1010
|
+
code;
|
|
1011
|
+
storedVersion;
|
|
1012
|
+
targetVersion;
|
|
1013
|
+
constructor(code, message, versions = {}) {
|
|
1014
|
+
super(message);
|
|
1015
|
+
this.name = "SyncLocalStoreSchemaError";
|
|
1016
|
+
this.code = code;
|
|
1017
|
+
this.storedVersion = versions.storedVersion;
|
|
1018
|
+
this.targetVersion = versions.targetVersion;
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1034
1021
|
});
|
|
1035
|
-
export const getAbsoluteExpoAuthPrincipal = () => currentPrincipal;
|
|
1036
|
-
|
|
1037
|
-
let startPromise: Promise<void> | undefined;
|
|
1038
|
-
export const startAbsoluteExpoAuth = () => {
|
|
1039
|
-
startPromise ??= absoluteExpoAuth.start().then(async () => {
|
|
1040
|
-
await absoluteExpoAuth.principal();
|
|
1041
|
-
});
|
|
1042
1022
|
|
|
1043
|
-
|
|
1044
|
-
};
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
"
|
|
1049
|
-
|
|
1023
|
+
// src/mobile/syncSchema.ts
|
|
1024
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
1025
|
+
import { dirname as dirname3, join as join6, resolve as resolve3 } from "path";
|
|
1026
|
+
var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value), manifestAt = (path) => {
|
|
1027
|
+
try {
|
|
1028
|
+
const value = JSON.parse(readFileSync6(path, "utf8"));
|
|
1029
|
+
return object(value) ? value : undefined;
|
|
1030
|
+
} catch {
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
}, localSchemaMetadata = (manifest) => {
|
|
1034
|
+
const absolutejs = Reflect.get(manifest, "absolutejs");
|
|
1035
|
+
if (!object(absolutejs))
|
|
1036
|
+
return;
|
|
1037
|
+
const sync = Reflect.get(absolutejs, "sync");
|
|
1038
|
+
if (!object(sync))
|
|
1039
|
+
return;
|
|
1040
|
+
return Reflect.get(sync, "localSchema");
|
|
1041
|
+
}, packageManifestPath = (projectRoot, packageName) => {
|
|
1042
|
+
let directory = resolve3(projectRoot);
|
|
1043
|
+
while (true) {
|
|
1044
|
+
const candidate = join6(directory, "node_modules", packageName, "package.json");
|
|
1045
|
+
const manifest = manifestAt(candidate);
|
|
1046
|
+
if (manifest && Reflect.get(manifest, "name") === packageName)
|
|
1047
|
+
return candidate;
|
|
1048
|
+
const parent = dirname3(directory);
|
|
1049
|
+
if (parent === directory)
|
|
1050
|
+
return;
|
|
1051
|
+
directory = parent;
|
|
1052
|
+
}
|
|
1053
|
+
}, metadataError = (id, detail) => new TypeError(`Invalid AbsoluteJS Sync schema metadata for ${id}: ${detail}`), positiveVersion2 = (value, id, field) => {
|
|
1054
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
|
|
1055
|
+
throw metadataError(id, `${field} must be a positive safe integer.`);
|
|
1056
|
+
return value;
|
|
1057
|
+
}, nonEmpty = (value, id, field) => {
|
|
1058
|
+
if (typeof value !== "string" || value.trim() !== value || value.length === 0)
|
|
1059
|
+
throw metadataError(id, `${field} must be a non-empty trimmed string.`);
|
|
1060
|
+
return value;
|
|
1061
|
+
}, requireObject = (value, id, detail) => {
|
|
1062
|
+
if (!object(value))
|
|
1063
|
+
throw metadataError(id, detail);
|
|
1064
|
+
return value;
|
|
1065
|
+
}, unknownField = (record, key) => record[key], normalizeJsonValue = (value, id, field) => {
|
|
1066
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
1067
|
+
return value;
|
|
1068
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
1069
|
+
return value;
|
|
1070
|
+
if (Array.isArray(value))
|
|
1071
|
+
return value.map((entry) => normalizeJsonValue(entry, id, field));
|
|
1072
|
+
if (object(value))
|
|
1073
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
1074
|
+
key,
|
|
1075
|
+
normalizeJsonValue(entry, id, field)
|
|
1076
|
+
]));
|
|
1077
|
+
throw metadataError(id, `${field} must be JSON-safe.`);
|
|
1078
|
+
}, operation = (value, id, index) => {
|
|
1079
|
+
const record = requireObject(value, id, `migration operation ${index} must be an object.`);
|
|
1080
|
+
const type = Reflect.get(record, "type");
|
|
1081
|
+
const collection = nonEmpty(Reflect.get(record, "collection"), id, `operation ${index}.collection`);
|
|
1082
|
+
if (type === "delete-collection")
|
|
1083
|
+
return { collection, type };
|
|
1084
|
+
if (type === "rename-field")
|
|
1085
|
+
return {
|
|
1086
|
+
collection,
|
|
1087
|
+
from: nonEmpty(Reflect.get(record, "from"), id, `operation ${index}.from`),
|
|
1088
|
+
to: nonEmpty(Reflect.get(record, "to"), id, `operation ${index}.to`),
|
|
1089
|
+
type
|
|
1090
|
+
};
|
|
1091
|
+
const field = nonEmpty(Reflect.get(record, "field"), id, `operation ${index}.field`);
|
|
1092
|
+
if (type === "remove-field")
|
|
1093
|
+
return { collection, field, type };
|
|
1094
|
+
if (type === "set-default")
|
|
1095
|
+
return {
|
|
1096
|
+
collection,
|
|
1097
|
+
field,
|
|
1098
|
+
type,
|
|
1099
|
+
value: normalizeJsonValue(Reflect.get(record, "value"), id, `operation ${index}.value`)
|
|
1100
|
+
};
|
|
1101
|
+
throw metadataError(id, `operation ${index}.type is not supported.`);
|
|
1102
|
+
}, migration = (value, id, index) => {
|
|
1103
|
+
const record = requireObject(value, id, `migration ${index} must be an object.`);
|
|
1104
|
+
const allowed = new Set(["operations", "toVersion"]);
|
|
1105
|
+
const unsupported = Object.keys(record).find((key) => !allowed.has(key));
|
|
1106
|
+
if (unsupported)
|
|
1107
|
+
throw metadataError(id, `migration ${index}.${unsupported} is not declarative metadata.`);
|
|
1108
|
+
const declaredOperations = Reflect.get(record, "operations");
|
|
1109
|
+
if (declaredOperations !== undefined && !Array.isArray(declaredOperations))
|
|
1110
|
+
throw metadataError(id, `migration ${index}.operations must be an array.`);
|
|
1111
|
+
const operations = Array.isArray(declaredOperations) ? declaredOperations : [];
|
|
1112
|
+
return {
|
|
1113
|
+
operations: operations.map((entry, operationIndex) => operation(entry, id, operationIndex)),
|
|
1114
|
+
toVersion: positiveVersion2(Reflect.get(record, "toVersion"), id, `migration ${index}.toVersion`)
|
|
1115
|
+
};
|
|
1116
|
+
}, localDataPolicy = (value, id) => {
|
|
1117
|
+
const record = requireObject(value, id, "localData must be an object.");
|
|
1118
|
+
const allowed = new Set([
|
|
1119
|
+
"collections",
|
|
1120
|
+
"maxBytesPerNamespace",
|
|
1121
|
+
"mutations"
|
|
1122
|
+
]);
|
|
1123
|
+
const unsupported = Object.keys(record).find((key) => !allowed.has(key));
|
|
1124
|
+
if (unsupported)
|
|
1125
|
+
throw metadataError(id, `localData.${unsupported} is not supported.`);
|
|
1126
|
+
const collectionRules = Reflect.get(record, "collections");
|
|
1127
|
+
const mutationRules = Reflect.get(record, "mutations");
|
|
1128
|
+
if (collectionRules !== undefined && !Array.isArray(collectionRules))
|
|
1129
|
+
throw metadataError(id, "localData.collections must be an array.");
|
|
1130
|
+
if (mutationRules !== undefined && !Array.isArray(mutationRules))
|
|
1131
|
+
throw metadataError(id, "localData.mutations must be an array.");
|
|
1132
|
+
const collections = Array.isArray(collectionRules) ? collectionRules.map((entry, index) => {
|
|
1133
|
+
const rule = requireObject(entry, id, `localData.collections[${index}] must be an object.`);
|
|
1134
|
+
const allowedRuleKeys = new Set([
|
|
1135
|
+
"evictionPriority",
|
|
1136
|
+
"match",
|
|
1137
|
+
"maxAgeMs",
|
|
1138
|
+
"onProtectionUnavailable",
|
|
1139
|
+
"persistence",
|
|
1140
|
+
"protection",
|
|
1141
|
+
"sensitivity"
|
|
1142
|
+
]);
|
|
1143
|
+
const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
|
|
1144
|
+
if (unsupportedRuleKey)
|
|
1145
|
+
throw metadataError(id, `localData.collections[${index}].${unsupportedRuleKey} is not supported.`);
|
|
1146
|
+
const match = nonEmpty(Reflect.get(rule, "match"), id, `localData.collections[${index}].match`);
|
|
1147
|
+
const persistence = unknownField(rule, "persistence");
|
|
1148
|
+
const sensitivity = unknownField(rule, "sensitivity");
|
|
1149
|
+
const protection = unknownField(rule, "protection");
|
|
1150
|
+
const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
|
|
1151
|
+
const evictionPriority = unknownField(rule, "evictionPriority");
|
|
1152
|
+
const maxAge = unknownField(rule, "maxAgeMs");
|
|
1153
|
+
if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
|
|
1154
|
+
throw metadataError(id, `localData.collections[${index}].persistence is invalid.`);
|
|
1155
|
+
if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
|
|
1156
|
+
throw metadataError(id, `localData.collections[${index}].sensitivity is invalid.`);
|
|
1157
|
+
if (protection !== undefined && protection !== "none" && protection !== "required")
|
|
1158
|
+
throw metadataError(id, `localData.collections[${index}].protection is invalid.`);
|
|
1159
|
+
if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
|
|
1160
|
+
throw metadataError(id, `localData.collections[${index}].onProtectionUnavailable is invalid.`);
|
|
1161
|
+
if (evictionPriority !== undefined && evictionPriority !== "critical" && evictionPriority !== "normal" && evictionPriority !== "disposable")
|
|
1162
|
+
throw metadataError(id, `localData.collections[${index}].evictionPriority is invalid.`);
|
|
1163
|
+
return {
|
|
1164
|
+
match,
|
|
1165
|
+
...sensitivity ? { sensitivity } : {},
|
|
1166
|
+
...persistence ? { persistence } : {},
|
|
1167
|
+
...protection ? { protection } : {},
|
|
1168
|
+
...onProtectionUnavailable ? {
|
|
1169
|
+
onProtectionUnavailable
|
|
1170
|
+
} : {},
|
|
1171
|
+
...evictionPriority ? { evictionPriority } : {},
|
|
1172
|
+
...maxAge === undefined ? {} : {
|
|
1173
|
+
maxAgeMs: positiveVersion2(maxAge, id, `localData.collections[${index}].maxAgeMs`)
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
}) : undefined;
|
|
1177
|
+
const mutations = Array.isArray(mutationRules) ? mutationRules.map((entry, index) => {
|
|
1178
|
+
const rule = requireObject(entry, id, `localData.mutations[${index}] must be an object.`);
|
|
1179
|
+
const allowedRuleKeys = new Set([
|
|
1180
|
+
"conflict",
|
|
1181
|
+
"match",
|
|
1182
|
+
"onProtectionUnavailable",
|
|
1183
|
+
"persistence",
|
|
1184
|
+
"protection",
|
|
1185
|
+
"sensitivity"
|
|
1186
|
+
]);
|
|
1187
|
+
const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
|
|
1188
|
+
if (unsupportedRuleKey)
|
|
1189
|
+
throw metadataError(id, `localData.mutations[${index}].${unsupportedRuleKey} is not supported.`);
|
|
1190
|
+
const protection = unknownField(rule, "protection");
|
|
1191
|
+
const sensitivity = unknownField(rule, "sensitivity");
|
|
1192
|
+
const persistence = unknownField(rule, "persistence");
|
|
1193
|
+
const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
|
|
1194
|
+
const declaredConflict = unknownField(rule, "conflict");
|
|
1195
|
+
let conflict;
|
|
1196
|
+
if (declaredConflict !== undefined) {
|
|
1197
|
+
const conflictRecord = requireObject(declaredConflict, id, `localData.mutations[${index}].conflict must be an object.`);
|
|
1198
|
+
const unsupportedConflictKey = Object.keys(conflictRecord).find((key) => key !== "maxAttempts" && key !== "strategy");
|
|
1199
|
+
if (unsupportedConflictKey)
|
|
1200
|
+
throw metadataError(id, `localData.mutations[${index}].conflict.${unsupportedConflictKey} is not supported.`);
|
|
1201
|
+
const strategy = unknownField(conflictRecord, "strategy");
|
|
1202
|
+
if (strategy !== "client-wins" && strategy !== "manual" && strategy !== "server-wins")
|
|
1203
|
+
throw metadataError(id, `localData.mutations[${index}].conflict.strategy is invalid.`);
|
|
1204
|
+
const maxAttempts = unknownField(conflictRecord, "maxAttempts");
|
|
1205
|
+
if (maxAttempts !== undefined && strategy !== "client-wins")
|
|
1206
|
+
throw metadataError(id, `localData.mutations[${index}].conflict.maxAttempts requires client-wins.`);
|
|
1207
|
+
conflict = {
|
|
1208
|
+
strategy,
|
|
1209
|
+
...maxAttempts === undefined ? {} : {
|
|
1210
|
+
maxAttempts: positiveVersion2(maxAttempts, id, `localData.mutations[${index}].conflict.maxAttempts`)
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
if (protection !== undefined && protection !== "none" && protection !== "required")
|
|
1215
|
+
throw metadataError(id, `localData.mutations[${index}].protection is invalid.`);
|
|
1216
|
+
if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
|
|
1217
|
+
throw metadataError(id, `localData.mutations[${index}].sensitivity is invalid.`);
|
|
1218
|
+
if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
|
|
1219
|
+
throw metadataError(id, `localData.mutations[${index}].onProtectionUnavailable is invalid.`);
|
|
1220
|
+
if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
|
|
1221
|
+
throw metadataError(id, `localData.mutations[${index}].persistence is invalid.`);
|
|
1222
|
+
return {
|
|
1223
|
+
match: nonEmpty(Reflect.get(rule, "match"), id, `localData.mutations[${index}].match`),
|
|
1224
|
+
...conflict ? { conflict } : {},
|
|
1225
|
+
...sensitivity ? { sensitivity } : {},
|
|
1226
|
+
...onProtectionUnavailable ? { onProtectionUnavailable } : {},
|
|
1227
|
+
...persistence ? {
|
|
1228
|
+
persistence
|
|
1229
|
+
} : {},
|
|
1230
|
+
...protection ? { protection } : {}
|
|
1231
|
+
};
|
|
1232
|
+
}) : undefined;
|
|
1233
|
+
const quota = Reflect.get(record, "maxBytesPerNamespace");
|
|
1234
|
+
return {
|
|
1235
|
+
...collections ? { collections } : {},
|
|
1236
|
+
...mutations ? { mutations } : {},
|
|
1237
|
+
...quota === undefined ? {} : {
|
|
1238
|
+
maxBytesPerNamespace: positiveVersion2(quota, id, "localData.maxBytesPerNamespace")
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1241
|
+
}, component = (id, value) => {
|
|
1242
|
+
const record = requireObject(value, id, "localSchema must be an object.");
|
|
1243
|
+
const allowed = new Set([
|
|
1244
|
+
"localData",
|
|
1245
|
+
"migrations",
|
|
1246
|
+
"minimumCompatibleVersion",
|
|
1247
|
+
"version"
|
|
1248
|
+
]);
|
|
1249
|
+
const unsupported = Object.keys(record).find((key) => !allowed.has(key));
|
|
1250
|
+
if (unsupported)
|
|
1251
|
+
throw metadataError(id, `${unsupported} is not supported.`);
|
|
1252
|
+
const version = positiveVersion2(Reflect.get(record, "version"), id, "version");
|
|
1253
|
+
const declaredMinimum = Reflect.get(record, "minimumCompatibleVersion");
|
|
1254
|
+
const minimumCompatibleVersion = declaredMinimum === undefined ? Math.max(1, version - 2) : positiveVersion2(declaredMinimum, id, "minimumCompatibleVersion");
|
|
1255
|
+
const declaredMigrations = Reflect.get(record, "migrations");
|
|
1256
|
+
const declaredLocalData = Reflect.get(record, "localData");
|
|
1257
|
+
if (declaredMigrations !== undefined && !Array.isArray(declaredMigrations))
|
|
1258
|
+
throw metadataError(id, "migrations must be an array.");
|
|
1259
|
+
const migrations = Array.isArray(declaredMigrations) ? declaredMigrations : undefined;
|
|
1260
|
+
return {
|
|
1261
|
+
id,
|
|
1262
|
+
...declaredLocalData === undefined ? {} : { localData: localDataPolicy(declaredLocalData, id) },
|
|
1263
|
+
minimumCompatibleVersion,
|
|
1264
|
+
...Array.isArray(migrations) ? {
|
|
1265
|
+
migrations: migrations.map((entry, index) => migration(entry, id, index))
|
|
1266
|
+
} : {},
|
|
1267
|
+
version
|
|
1268
|
+
};
|
|
1269
|
+
}, dependencyNames = (manifest) => [
|
|
1270
|
+
Reflect.get(manifest, "dependencies"),
|
|
1271
|
+
Reflect.get(manifest, "optionalDependencies"),
|
|
1272
|
+
Reflect.get(manifest, "devDependencies"),
|
|
1273
|
+
Reflect.get(manifest, "peerDependencies")
|
|
1274
|
+
].flatMap((dependencies) => object(dependencies) ? Object.keys(dependencies) : []).filter((name, index, names) => names.indexOf(name) === index).sort(), discoverAbsoluteSyncSchema = (projectRoot) => {
|
|
1275
|
+
const appManifestPath = join6(resolve3(projectRoot), "package.json");
|
|
1276
|
+
const appManifest = manifestAt(appManifestPath);
|
|
1277
|
+
if (!appManifest)
|
|
1278
|
+
return {
|
|
1279
|
+
components: [
|
|
1280
|
+
{
|
|
1281
|
+
id: "@absolutejs/app",
|
|
1282
|
+
minimumCompatibleVersion: 1,
|
|
1283
|
+
version: 1
|
|
1284
|
+
}
|
|
1285
|
+
],
|
|
1286
|
+
sources: []
|
|
1287
|
+
};
|
|
1288
|
+
const appMetadata = localSchemaMetadata(appManifest);
|
|
1289
|
+
const components = [
|
|
1290
|
+
appMetadata === undefined ? { id: "@absolutejs/app", minimumCompatibleVersion: 1, version: 1 } : component("@absolutejs/app", appMetadata)
|
|
1291
|
+
];
|
|
1292
|
+
const sources = [
|
|
1293
|
+
{ id: "@absolutejs/app", manifestPath: appManifestPath }
|
|
1294
|
+
];
|
|
1295
|
+
for (const name of dependencyNames(appManifest)) {
|
|
1296
|
+
const manifestPath = packageManifestPath(projectRoot, name);
|
|
1297
|
+
if (!manifestPath)
|
|
1298
|
+
continue;
|
|
1299
|
+
const manifest = manifestAt(manifestPath);
|
|
1300
|
+
if (!manifest)
|
|
1301
|
+
continue;
|
|
1302
|
+
const metadata = localSchemaMetadata(manifest);
|
|
1303
|
+
if (metadata === undefined)
|
|
1304
|
+
continue;
|
|
1305
|
+
components.push(component(name, metadata));
|
|
1306
|
+
sources.push({ id: name, manifestPath });
|
|
1307
|
+
}
|
|
1308
|
+
components.sort((left, right) => left.id.localeCompare(right.id));
|
|
1309
|
+
sources.sort((left, right) => left.id.localeCompare(right.id));
|
|
1310
|
+
resolveSyncLocalSchemaComponents({}, { components });
|
|
1311
|
+
return { components, sources };
|
|
1312
|
+
};
|
|
1313
|
+
var init_syncSchema = __esm(() => {
|
|
1314
|
+
init_client();
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1317
|
+
// src/mobile/expoProject.ts
|
|
1318
|
+
import {
|
|
1319
|
+
access,
|
|
1320
|
+
cp,
|
|
1321
|
+
mkdir,
|
|
1322
|
+
mkdtemp,
|
|
1323
|
+
readdir,
|
|
1324
|
+
readFile,
|
|
1325
|
+
rename,
|
|
1326
|
+
rm,
|
|
1327
|
+
writeFile
|
|
1328
|
+
} from "fs/promises";
|
|
1329
|
+
import { createHash } from "crypto";
|
|
1330
|
+
import { basename as basename2, dirname as dirname4, join as join7, relative, resolve as resolve4 } from "path";
|
|
1331
|
+
var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
|
|
1332
|
+
`, EXPO_ASSET_EXTENSION = ".absasset", EXPO_PROJECT_MARKER = ".absolutejs-expo-project", exists = async (path) => {
|
|
1333
|
+
try {
|
|
1334
|
+
await access(path);
|
|
1335
|
+
return true;
|
|
1336
|
+
} catch {
|
|
1337
|
+
return false;
|
|
1338
|
+
}
|
|
1339
|
+
}, portableRelative = (from, destination) => {
|
|
1340
|
+
const value = relative(from, destination).replaceAll("\\", "/");
|
|
1341
|
+
return value.startsWith(".") ? value : `./${value}`;
|
|
1342
|
+
}, routeSegments = (route) => route.split("/").filter(Boolean).map((segment) => {
|
|
1343
|
+
if (segment.startsWith(":"))
|
|
1344
|
+
return `[${segment.slice(1)}]`;
|
|
1345
|
+
if (segment === "." || segment === ".." || !/^[A-Za-z0-9._~-]+$/u.test(segment)) {
|
|
1346
|
+
throw new TypeError(`Expo native route ${route} contains an unsupported segment ${segment}.`);
|
|
1347
|
+
}
|
|
1348
|
+
return segment;
|
|
1349
|
+
}), routeFile = (project, route) => join7(project, "app", ...routeSegments(route), "index.tsx"), expoPackage = (auth, sync) => ({
|
|
1350
|
+
dependencies: {
|
|
1351
|
+
...auth ? {
|
|
1352
|
+
"@absolutejs/auth": ABSOLUTE_EXPO_AUTH_CORE_VERSION,
|
|
1353
|
+
[ABSOLUTE_EXPO_AUTH_PACKAGE]: ABSOLUTE_EXPO_AUTH_VERSION
|
|
1354
|
+
} : {},
|
|
1355
|
+
...sync ? {
|
|
1356
|
+
"@absolutejs/sync": ABSOLUTE_EXPO_SYNC_CORE_VERSION,
|
|
1357
|
+
[ABSOLUTE_EXPO_SYNC_PACKAGE]: ABSOLUTE_EXPO_SYNC_VERSION
|
|
1358
|
+
} : {},
|
|
1359
|
+
expo: "~57.0.9",
|
|
1360
|
+
"expo-asset": "~57.0.15",
|
|
1361
|
+
"expo-constants": "~57.0.16",
|
|
1362
|
+
"expo-dev-client": "~57.0.16",
|
|
1363
|
+
"expo-file-system": "~57.0.6",
|
|
1364
|
+
"expo-haptics": "~57.0.2",
|
|
1365
|
+
"expo-linking": "~57.0.8",
|
|
1366
|
+
...sync ? {
|
|
1367
|
+
"expo-background-task": "~57.0.14",
|
|
1368
|
+
"expo-network": "~57.0.1",
|
|
1369
|
+
"expo-sqlite": "~57.0.2",
|
|
1370
|
+
"expo-task-manager": "~57.0.14",
|
|
1371
|
+
"expo-updates": "~57.0.19"
|
|
1372
|
+
} : {},
|
|
1373
|
+
"expo-router": "~57.0.17",
|
|
1374
|
+
...auth ? {
|
|
1375
|
+
"expo-secure-store": "~57.0.2",
|
|
1376
|
+
"expo-web-browser": "~57.0.2"
|
|
1377
|
+
} : {},
|
|
1378
|
+
react: "19.2.3",
|
|
1379
|
+
"react-native": "0.86.3",
|
|
1380
|
+
"react-native-safe-area-context": "~5.7.0",
|
|
1381
|
+
"react-native-screens": "4.26.0",
|
|
1382
|
+
"react-native-webview": "13.16.1"
|
|
1383
|
+
},
|
|
1384
|
+
devDependencies: {
|
|
1385
|
+
"@types/react": "~19.2.2",
|
|
1386
|
+
typescript: "~6.0.3"
|
|
1387
|
+
},
|
|
1388
|
+
main: "expo-router/entry",
|
|
1389
|
+
name: "absolutejs-expo-shell",
|
|
1390
|
+
private: true,
|
|
1391
|
+
scripts: {
|
|
1392
|
+
android: "expo run:android",
|
|
1393
|
+
ios: "expo run:ios",
|
|
1394
|
+
start: "expo start --dev-client"
|
|
1395
|
+
},
|
|
1396
|
+
version: "0.0.0"
|
|
1397
|
+
}), expoAppConfig = (config, auth, sync) => ({
|
|
1398
|
+
expo: {
|
|
1399
|
+
android: {
|
|
1400
|
+
intentFilters: config.deepLinkHosts.map((host2) => ({
|
|
1401
|
+
action: "VIEW",
|
|
1402
|
+
autoVerify: true,
|
|
1403
|
+
category: ["BROWSABLE", "DEFAULT"],
|
|
1404
|
+
data: [{ host: host2, pathPrefix: "/", scheme: "https" }]
|
|
1405
|
+
})),
|
|
1406
|
+
package: config.appId
|
|
1407
|
+
},
|
|
1408
|
+
experiments: { typedRoutes: true },
|
|
1409
|
+
ios: {
|
|
1410
|
+
associatedDomains: config.deepLinkHosts.map((host2) => `applinks:${host2}`),
|
|
1411
|
+
bundleIdentifier: config.appId,
|
|
1412
|
+
...config.iosVersion ? { buildNumber: config.iosVersion } : {}
|
|
1413
|
+
},
|
|
1414
|
+
name: config.appName,
|
|
1415
|
+
plugins: [
|
|
1416
|
+
"expo-router",
|
|
1417
|
+
["expo-dev-client", { launchMode: "most-recent" }],
|
|
1418
|
+
...auth ? ["expo-secure-store"] : [],
|
|
1419
|
+
...sync ? ["expo-sqlite", "expo-background-task", "expo-task-manager"] : []
|
|
1420
|
+
],
|
|
1421
|
+
runtimeVersion: { policy: "appVersion" },
|
|
1422
|
+
scheme: config.deepLinkScheme,
|
|
1423
|
+
slug: config.appId.toLowerCase().replaceAll(".", "-"),
|
|
1424
|
+
version: config.iosVersion ?? "0.1.0"
|
|
1425
|
+
}
|
|
1426
|
+
}), expoDynamicAppConfig, expoDevelopmentCaPlugin, metroConfig = (projectRoot) => `${EXPO_GENERATED_HEADER}const { getDefaultConfig } = require('expo/metro-config');
|
|
1427
|
+
const path = require('node:path');
|
|
1428
|
+
|
|
1429
|
+
const projectRoot = __dirname;
|
|
1430
|
+
const appRoot = ${JSON.stringify(projectRoot)};
|
|
1431
|
+
const config = getDefaultConfig(projectRoot);
|
|
1432
|
+
config.resolver.assetExts.push('absasset');
|
|
1433
|
+
config.resolver.nodeModulesPaths = [
|
|
1434
|
+
path.join(projectRoot, 'node_modules'),
|
|
1435
|
+
path.join(appRoot, 'node_modules')
|
|
1436
|
+
];
|
|
1437
|
+
config.watchFolders = [appRoot];
|
|
1438
|
+
|
|
1439
|
+
module.exports = config;
|
|
1440
|
+
`, layoutSource = (auth, sync) => `${EXPO_GENERATED_HEADER}import { Stack } from 'expo-router';
|
|
1441
|
+
${auth ? `import { useEffect, useState } from 'react';
|
|
1442
|
+
import { startAbsoluteExpoAuth } from '../src/generated/AbsoluteAuth';` : ""}
|
|
1443
|
+
${sync ? "import { startAbsoluteExpoSync } from '../src/generated/AbsoluteSync';" : ""}
|
|
1444
|
+
|
|
1445
|
+
export default function AbsoluteLayout() {
|
|
1446
|
+
${auth ? `const [ready, setReady] = useState(false);
|
|
1447
|
+
useEffect(() => {
|
|
1448
|
+
let active = true;
|
|
1449
|
+
void ${sync ? "startAbsoluteExpoSync" : "startAbsoluteExpoAuth"}().then(() => { if (active) setReady(true); });
|
|
1450
|
+
return () => { active = false; };
|
|
1451
|
+
}, []);
|
|
1452
|
+
if (!ready) return null;` : ""}
|
|
1453
|
+
return <Stack screenOptions={{ headerShown: false }} />;
|
|
1454
|
+
}
|
|
1455
|
+
`, nativeDiagnosticSource, authRuntimeSource = (auth, appId) => {
|
|
1456
|
+
const storageIdentity = createHash("sha256").update(appId).digest("hex").slice(0, 24);
|
|
1457
|
+
return `${EXPO_GENERATED_HEADER}import { createAbsoluteExpoAuthClient } from '@absolutejs/auth-expo';
|
|
1458
|
+
import { createMobileAuthTransport, installAuthClientRuntimeTransport } from '@absolutejs/auth/client/mobile';
|
|
1459
|
+
|
|
1460
|
+
export const absoluteExpoAuth = createAbsoluteExpoAuthClient({
|
|
1461
|
+
allowedOrigins: [${JSON.stringify(auth.issuer)}],
|
|
1462
|
+
clientId: ${JSON.stringify(auth.clientId)},
|
|
1463
|
+
issuer: ${JSON.stringify(auth.issuer)},
|
|
1464
|
+
redirectUri: ${JSON.stringify(auth.redirectUri)},
|
|
1465
|
+
resource: ${JSON.stringify(auth.issuer)},
|
|
1466
|
+
scopes: ${JSON.stringify(auth.scopes)},
|
|
1467
|
+
storagePrefix: ${JSON.stringify(`absolutejs.auth.${storageIdentity}`)}
|
|
1468
|
+
});
|
|
1469
|
+
installAuthClientRuntimeTransport(createMobileAuthTransport(absoluteExpoAuth, { baseUrl: ${JSON.stringify(auth.issuer)} }));
|
|
1470
|
+
|
|
1471
|
+
let currentPrincipal: Awaited<ReturnType<typeof absoluteExpoAuth.principal>> = null;
|
|
1472
|
+
absoluteExpoAuth.onPrincipalChange(principal => {
|
|
1473
|
+
currentPrincipal = principal;
|
|
1474
|
+
});
|
|
1475
|
+
export const getAbsoluteExpoAuthPrincipal = () => currentPrincipal;
|
|
1476
|
+
|
|
1477
|
+
let startPromise: Promise<void> | undefined;
|
|
1478
|
+
export const startAbsoluteExpoAuth = () => {
|
|
1479
|
+
startPromise ??= absoluteExpoAuth.start().then(async () => {
|
|
1480
|
+
currentPrincipal = await absoluteExpoAuth.principal();
|
|
1481
|
+
});
|
|
1482
|
+
|
|
1483
|
+
return startPromise;
|
|
1484
|
+
};
|
|
1485
|
+
`;
|
|
1486
|
+
}, syncRuntimeSource = (config, schema) => {
|
|
1487
|
+
const storageIdentity = createHash("sha256").update(config.appId).digest("hex").slice(0, 24);
|
|
1488
|
+
const backgroundEndpoint = new URL("/__absolute/sync/background", config.productionOrigin).href;
|
|
1489
|
+
const backgroundTask = `${config.appId}.absolutejs.sync`;
|
|
1490
|
+
return `${EXPO_GENERATED_HEADER}import { runHeadlessSync } from '@absolutejs/sync/client/headless';
|
|
1491
|
+
import type { SyncLocalStoreSchemaBundle } from '@absolutejs/sync/client';
|
|
1492
|
+
import { installSyncClientRuntimeTransport } from '@absolutejs/sync/client/runtime';
|
|
1493
|
+
import {
|
|
1494
|
+
createExpoSyncBridgeHost,
|
|
1495
|
+
createExpoSyncLocalStore,
|
|
1496
|
+
createExpoSyncProtection,
|
|
1497
|
+
createExpoSyncSocketBridgeHost,
|
|
1498
|
+
defineExpoSyncBackgroundTask,
|
|
1499
|
+
installExpoSyncLifecycle,
|
|
1500
|
+
registerExpoSyncBackgroundTask
|
|
1501
|
+
} from '@absolutejs/sync-expo';
|
|
1502
|
+
import * as Updates from 'expo-updates';
|
|
1503
|
+
import { absoluteExpoAuth, startAbsoluteExpoAuth } from './AbsoluteAuth';
|
|
1504
|
+
|
|
1505
|
+
const BACKGROUND_TASK = ${JSON.stringify(backgroundTask)};
|
|
1506
|
+
const BACKGROUND_ENDPOINT = ${JSON.stringify(backgroundEndpoint)};
|
|
1507
|
+
const PRODUCTION_ORIGIN = ${JSON.stringify(config.productionOrigin)};
|
|
1508
|
+
const STORAGE_SCHEMA: SyncLocalStoreSchemaBundle = ${JSON.stringify(schema)};
|
|
1509
|
+
const store = createExpoSyncLocalStore({
|
|
1510
|
+
databaseName: ${JSON.stringify(`absolutejs-sync-${storageIdentity}.db`)},
|
|
1511
|
+
protection: createExpoSyncProtection({ storagePrefix: ${JSON.stringify(`absolutejs.sync.${storageIdentity}`)} }),
|
|
1512
|
+
storageSchema: STORAGE_SCHEMA
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
const runBackgroundSync = async () => {
|
|
1516
|
+
await startAbsoluteExpoAuth();
|
|
1517
|
+
const principal = await absoluteExpoAuth.principal();
|
|
1518
|
+
if (!principal) return;
|
|
1519
|
+
await runHeadlessSync({
|
|
1520
|
+
endpoint: BACKGROUND_ENDPOINT,
|
|
1521
|
+
fetch: (url, init) => absoluteExpoAuth.fetch(url, init),
|
|
1522
|
+
namespace: principal.namespace,
|
|
1523
|
+
store
|
|
1524
|
+
});
|
|
1525
|
+
};
|
|
1526
|
+
defineExpoSyncBackgroundTask(BACKGROUND_TASK, runBackgroundSync);
|
|
1527
|
+
|
|
1528
|
+
let activeNamespace: string | undefined;
|
|
1529
|
+
let started = false;
|
|
1530
|
+
let startPromise: Promise<void> | undefined;
|
|
1531
|
+
export const startAbsoluteExpoSync = () => {
|
|
1532
|
+
startPromise ??= (async () => {
|
|
1533
|
+
await startAbsoluteExpoAuth();
|
|
1534
|
+
const principal = await absoluteExpoAuth.principal();
|
|
1535
|
+
activeNamespace = principal?.namespace;
|
|
1536
|
+
installSyncClientRuntimeTransport({
|
|
1537
|
+
...(principal ? { durable: { namespace: principal.namespace, store }, socketTicket: () => absoluteExpoAuth.socketTicket() } : {}),
|
|
1538
|
+
registerClient: client => installExpoSyncLifecycle({ client })
|
|
1539
|
+
});
|
|
1540
|
+
await registerExpoSyncBackgroundTask(BACKGROUND_TASK, { minimumInterval: 15 });
|
|
1541
|
+
started = true;
|
|
1542
|
+
})();
|
|
1543
|
+
|
|
1544
|
+
return startPromise;
|
|
1545
|
+
};
|
|
1546
|
+
|
|
1547
|
+
absoluteExpoAuth.onPrincipalChange(principal => {
|
|
1548
|
+
if (!started || principal?.namespace === activeNamespace) return;
|
|
1549
|
+
void Updates.reloadAsync();
|
|
1550
|
+
});
|
|
1551
|
+
|
|
1552
|
+
export const createAbsoluteExpoSyncBridge = async (
|
|
1553
|
+
emit: (event: 'sync.socket' | 'sync.wake', payload: Record<string, unknown>) => void
|
|
1554
|
+
) => {
|
|
1555
|
+
await startAbsoluteExpoSync();
|
|
1556
|
+
const principal = await absoluteExpoAuth.principal();
|
|
1557
|
+
if (!principal) return {
|
|
1558
|
+
close: () => undefined,
|
|
1559
|
+
request: async () => { throw new Error('Expo Sync requires an authenticated principal.'); }
|
|
1560
|
+
};
|
|
1561
|
+
const transactions = createExpoSyncBridgeHost({ namespace: principal.namespace, store });
|
|
1562
|
+
const sockets = createExpoSyncSocketBridgeHost({
|
|
1563
|
+
allowedOrigin: PRODUCTION_ORIGIN,
|
|
1564
|
+
emit: payload => emit('sync.socket', payload),
|
|
1565
|
+
socketTicket: audience => absoluteExpoAuth.socketTicket(audience)
|
|
1566
|
+
});
|
|
1567
|
+
const removeLifecycle = installExpoSyncLifecycle({
|
|
1568
|
+
client: { reconnect: () => emit('sync.wake', {}) }
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
return {
|
|
1572
|
+
close: async () => {
|
|
1573
|
+
removeLifecycle();
|
|
1574
|
+
await Promise.all([transactions.close(), sockets.close()]);
|
|
1575
|
+
},
|
|
1576
|
+
request: (method: string, params: Record<string, unknown>) =>
|
|
1577
|
+
method.startsWith('sync.socket.')
|
|
1578
|
+
? sockets.request(method, params)
|
|
1579
|
+
: transactions.request(method, params)
|
|
1580
|
+
};
|
|
1581
|
+
};
|
|
1582
|
+
`;
|
|
1583
|
+
}, webHostSource = (config, auth, sync) => {
|
|
1584
|
+
const nativeRoutes = [
|
|
1585
|
+
"/__absolute/native",
|
|
1586
|
+
...Object.keys(config.expoNativeRoutes)
|
|
1050
1587
|
];
|
|
1051
1588
|
return `${EXPO_GENERATED_HEADER}import * as Haptics from 'expo-haptics';
|
|
1052
1589
|
import * as Linking from 'expo-linking';
|
|
@@ -1056,8 +1593,9 @@ import { ActivityIndicator, BackHandler, Platform, StyleSheet, View } from 'reac
|
|
|
1056
1593
|
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
|
|
1057
1594
|
import { materializeAbsoluteWebBundle } from './webAssets';
|
|
1058
1595
|
${auth ? "import { absoluteExpoAuth, getAbsoluteExpoAuthPrincipal, startAbsoluteExpoAuth } from './AbsoluteAuth';" : ""}
|
|
1596
|
+
${sync ? "import { createAbsoluteExpoSyncBridge, startAbsoluteExpoSync } from './AbsoluteSync';" : ""}
|
|
1059
1597
|
|
|
1060
|
-
const BRIDGE_FORMAT =
|
|
1598
|
+
const BRIDGE_FORMAT = 3;
|
|
1061
1599
|
const MAX_MESSAGE_BYTES = 64 * 1024;
|
|
1062
1600
|
const MAX_HTTP_BODY_BYTES = 48 * 1024;
|
|
1063
1601
|
const NATIVE_ROUTES = new Set(${JSON.stringify(nativeRoutes)});
|
|
@@ -1067,6 +1605,7 @@ const DEV_ORIGIN = Platform.OS === 'android'
|
|
|
1067
1605
|
: process.env.EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN;
|
|
1068
1606
|
const HMR_TARGET = Platform.OS === 'android' ? 'expo-android' : 'expo-ios';
|
|
1069
1607
|
const AUTH_ENABLED = ${auth ? "true" : "false"};
|
|
1608
|
+
const SYNC_ENABLED = ${sync ? "true" : "false"};
|
|
1070
1609
|
|
|
1071
1610
|
const bridgeBootstrap = (path: string) => {
|
|
1072
1611
|
const initialPath = DEV_ORIGIN
|
|
@@ -1106,7 +1645,7 @@ const bridgeBootstrap = (path: string) => {
|
|
|
1106
1645
|
},
|
|
1107
1646
|
request(method, params) {
|
|
1108
1647
|
const id = 'web_' + Date.now().toString(36) + '_' + (++sequence).toString(36);
|
|
1109
|
-
send({ format:
|
|
1648
|
+
send({ format: 3, id, kind: 'request', method, params, path: currentPath });
|
|
1110
1649
|
return new Promise((resolve, reject) => {
|
|
1111
1650
|
const timer = setTimeout(() => {
|
|
1112
1651
|
pending.delete(id);
|
|
@@ -1117,7 +1656,7 @@ const bridgeBootstrap = (path: string) => {
|
|
|
1117
1656
|
},
|
|
1118
1657
|
setPath(path) {
|
|
1119
1658
|
currentPath = path;
|
|
1120
|
-
send({ format:
|
|
1659
|
+
send({ format: 3, kind: 'event', event: 'navigation', path });
|
|
1121
1660
|
}
|
|
1122
1661
|
};
|
|
1123
1662
|
if (\${DEV_ORIGIN ? 'true' : 'false'}) {
|
|
@@ -1125,7 +1664,7 @@ const bridgeBootstrap = (path: string) => {
|
|
|
1125
1664
|
const path = location.pathname + location.search + location.hash;
|
|
1126
1665
|
if (path === currentPath) return;
|
|
1127
1666
|
currentPath = path;
|
|
1128
|
-
send({ format:
|
|
1667
|
+
send({ format: 3, kind: 'event', event: 'navigation', path });
|
|
1129
1668
|
};
|
|
1130
1669
|
for (const method of ['pushState', 'replaceState']) {
|
|
1131
1670
|
const original = history[method];
|
|
@@ -1144,9 +1683,9 @@ const bridgeBootstrap = (path: string) => {
|
|
|
1144
1683
|
const url = new URL(anchor.href, location.href);
|
|
1145
1684
|
if (!${JSON.stringify(nativeRoutes)}.includes(url.pathname)) return;
|
|
1146
1685
|
event.preventDefault();
|
|
1147
|
-
send({ format:
|
|
1686
|
+
send({ format: 3, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
|
|
1148
1687
|
}, true);
|
|
1149
|
-
send({ format:
|
|
1688
|
+
send({ format: 3, kind: 'event', event: 'ready', path: currentPath });
|
|
1150
1689
|
})(); true;\`;
|
|
1151
1690
|
};
|
|
1152
1691
|
|
|
@@ -1192,21 +1731,34 @@ const authStatus = async () => {
|
|
|
1192
1731
|
export function AbsoluteWebHost() {
|
|
1193
1732
|
const pathname = usePathname() || '/';
|
|
1194
1733
|
const webView = useRef<WebView>(null);
|
|
1734
|
+
const syncBridge = useRef<{ close(): void | Promise<void>; request(method: string, params: Record<string, unknown>): Promise<unknown> } | undefined>(undefined);
|
|
1195
1735
|
const [indexUri, setIndexUri] = useState<string>();
|
|
1196
1736
|
const [canGoBack, setCanGoBack] = useState(false);
|
|
1197
|
-
const [
|
|
1737
|
+
const [runtimeReady, setRuntimeReady] = useState(!AUTH_ENABLED && !SYNC_ENABLED);
|
|
1198
1738
|
const activeWebPath = useRef(pathname);
|
|
1199
1739
|
|
|
1200
1740
|
useEffect(() => {
|
|
1201
|
-
if (!AUTH_ENABLED) return;
|
|
1741
|
+
if (!AUTH_ENABLED && !SYNC_ENABLED) return;
|
|
1202
1742
|
let active = true;
|
|
1203
1743
|
${auth ? `const stop = absoluteExpoAuth.onPrincipalChange(principal => {
|
|
1204
1744
|
if (!active) return;
|
|
1205
1745
|
const source = JSON.stringify({ event: 'auth.principal', format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload: { principal: principal ? { namespace: principal.namespace } : null } });
|
|
1206
1746
|
webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
|
|
1207
1747
|
});
|
|
1208
|
-
void startAbsoluteExpoAuth().then(() => {
|
|
1209
|
-
|
|
1748
|
+
void ${sync ? "startAbsoluteExpoSync" : "startAbsoluteExpoAuth"}().then(async () => {
|
|
1749
|
+
${sync ? `syncBridge.current = await createAbsoluteExpoSyncBridge((event, payload) => {
|
|
1750
|
+
const source = JSON.stringify({ event, format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload });
|
|
1751
|
+
webView.current?.injectJavaScript(\`globalThis.__absoluteExpoReceive(\${JSON.stringify(source)}); true;\`);
|
|
1752
|
+
});` : ""}
|
|
1753
|
+
if (active) setRuntimeReady(true);
|
|
1754
|
+
});
|
|
1755
|
+
return () => {
|
|
1756
|
+
active = false;
|
|
1757
|
+
stop();
|
|
1758
|
+
const bridge = syncBridge.current;
|
|
1759
|
+
syncBridge.current = undefined;
|
|
1760
|
+
void bridge?.close();
|
|
1761
|
+
};` : ""}
|
|
1210
1762
|
}, []);
|
|
1211
1763
|
|
|
1212
1764
|
useEffect(() => {
|
|
@@ -1268,6 +1820,9 @@ export function AbsoluteWebHost() {
|
|
|
1268
1820
|
respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: null });` : "throw new Error('Expo Auth is not configured.');"}
|
|
1269
1821
|
} else if (message.method === 'auth.status') {
|
|
1270
1822
|
respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await authStatus() });
|
|
1823
|
+
} else if (typeof message.method === 'string' && message.method.startsWith('sync.')) {
|
|
1824
|
+
if (!syncBridge.current) throw new Error('Expo Sync bridge is unavailable.');
|
|
1825
|
+
respond({ format: BRIDGE_FORMAT, id: message.id, kind: 'response', result: await syncBridge.current.request(message.method, message.params as Record<string, unknown>) });
|
|
1271
1826
|
} else {
|
|
1272
1827
|
throw new Error('Expo bridge method is not allowed.');
|
|
1273
1828
|
}
|
|
@@ -1276,7 +1831,7 @@ export function AbsoluteWebHost() {
|
|
|
1276
1831
|
}
|
|
1277
1832
|
};
|
|
1278
1833
|
|
|
1279
|
-
if (!indexUri || !
|
|
1834
|
+
if (!indexUri || !runtimeReady) return <View style={styles.loading}><ActivityIndicator /></View>;
|
|
1280
1835
|
return <WebView
|
|
1281
1836
|
allowFileAccess
|
|
1282
1837
|
allowFileAccessFromFileURLs
|
|
@@ -1298,16 +1853,30 @@ export function AbsoluteWebHost() {
|
|
|
1298
1853
|
|
|
1299
1854
|
const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, justifyContent: 'center' }, web: { flex: 1 } });
|
|
1300
1855
|
`;
|
|
1301
|
-
}, webRouteSource, catchAllRouteSource, nativeWrapperSource = (wrapper, module) => `${EXPO_GENERATED_HEADER}export { default } from ${JSON.stringify(portableRelative(
|
|
1302
|
-
`, expoTsConfig = (projectRoot, project, auth) => ({
|
|
1856
|
+
}, webRouteSource, catchAllRouteSource, nativeWrapperSource = (wrapper, module) => `${EXPO_GENERATED_HEADER}export { default } from ${JSON.stringify(portableRelative(dirname4(wrapper), module).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
|
|
1857
|
+
`, expoTsConfig = (projectRoot, project, auth, sync) => ({
|
|
1303
1858
|
compilerOptions: {
|
|
1304
1859
|
paths: {
|
|
1305
1860
|
...auth ? {
|
|
1306
1861
|
"@absolutejs/auth": [
|
|
1307
1862
|
"./node_modules/@absolutejs/auth/dist/index.d.ts"
|
|
1308
1863
|
],
|
|
1309
|
-
"@absolutejs/auth/*": [
|
|
1310
|
-
"./node_modules/@absolutejs/auth/dist/*"
|
|
1864
|
+
"@absolutejs/auth/*": [
|
|
1865
|
+
"./node_modules/@absolutejs/auth/dist/*"
|
|
1866
|
+
]
|
|
1867
|
+
} : {},
|
|
1868
|
+
...sync ? {
|
|
1869
|
+
"@absolutejs/sync": [
|
|
1870
|
+
"./node_modules/@absolutejs/sync/dist/index.d.ts"
|
|
1871
|
+
],
|
|
1872
|
+
"@absolutejs/sync-expo": [
|
|
1873
|
+
"./node_modules/@absolutejs/sync-expo/dist/index.d.ts"
|
|
1874
|
+
],
|
|
1875
|
+
"@absolutejs/sync-expo/*": [
|
|
1876
|
+
"./node_modules/@absolutejs/sync-expo/dist/*"
|
|
1877
|
+
],
|
|
1878
|
+
"@absolutejs/sync/*": [
|
|
1879
|
+
"./node_modules/@absolutejs/sync/dist/*"
|
|
1311
1880
|
]
|
|
1312
1881
|
} : {},
|
|
1313
1882
|
"*": [
|
|
@@ -1321,7 +1890,7 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
|
|
|
1321
1890
|
},
|
|
1322
1891
|
extends: "expo/tsconfig.base"
|
|
1323
1892
|
}), writeManagedFile = async (path, source, force) => {
|
|
1324
|
-
await mkdir(
|
|
1893
|
+
await mkdir(dirname4(path), { recursive: true });
|
|
1325
1894
|
if (await exists(path)) {
|
|
1326
1895
|
const current = await readFile(path, "utf8");
|
|
1327
1896
|
if (current === source)
|
|
@@ -1338,9 +1907,11 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
|
|
|
1338
1907
|
`, emptyWebAssetsSource, writeAbsoluteExpoProject = async (config, options) => {
|
|
1339
1908
|
if (config.engine !== "expo")
|
|
1340
1909
|
throw new TypeError("Expo project generation requires mobile.engine: expo.");
|
|
1341
|
-
const projectRoot =
|
|
1910
|
+
const projectRoot = resolve4(options.projectRoot);
|
|
1342
1911
|
const project = config.nativeProjectDirectory;
|
|
1343
1912
|
const auth = resolveAbsoluteMobileAuthManifest(projectRoot, config);
|
|
1913
|
+
const syncEnabled = Boolean(auth && projectUsesAbsoluteSync(projectRoot));
|
|
1914
|
+
const syncSchema = syncEnabled ? { components: discoverAbsoluteSyncSchema(projectRoot).components } : undefined;
|
|
1344
1915
|
const routeModules = Object.entries(config.expoNativeRoutes);
|
|
1345
1916
|
const moduleChecks = await Promise.all(routeModules.map(async ([route, module]) => ({
|
|
1346
1917
|
exists: await exists(module),
|
|
@@ -1351,7 +1922,7 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
|
|
|
1351
1922
|
if (missing) {
|
|
1352
1923
|
throw new TypeError(`Expo native route ${missing.route} references missing module ${missing.module}.`);
|
|
1353
1924
|
}
|
|
1354
|
-
const marker =
|
|
1925
|
+
const marker = join7(project, EXPO_PROJECT_MARKER);
|
|
1355
1926
|
if (await exists(project) && !await exists(marker)) {
|
|
1356
1927
|
const entries = await readdir(project);
|
|
1357
1928
|
if (entries.length > 0 && !options.force) {
|
|
@@ -1364,7 +1935,7 @@ const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, jus
|
|
|
1364
1935
|
const authEnabled = Boolean(auth);
|
|
1365
1936
|
const files = new Map([
|
|
1366
1937
|
[
|
|
1367
|
-
|
|
1938
|
+
join7(project, ".gitignore"),
|
|
1368
1939
|
`.expo/
|
|
1369
1940
|
android/
|
|
1370
1941
|
ios/
|
|
@@ -1372,43 +1943,52 @@ node_modules/
|
|
|
1372
1943
|
`
|
|
1373
1944
|
],
|
|
1374
1945
|
[
|
|
1375
|
-
|
|
1376
|
-
jsonSource(expoAppConfig(config, authEnabled))
|
|
1946
|
+
join7(project, "app.json"),
|
|
1947
|
+
jsonSource(expoAppConfig(config, authEnabled, syncEnabled))
|
|
1948
|
+
],
|
|
1949
|
+
[join7(project, "app.config.js"), expoDynamicAppConfig],
|
|
1950
|
+
[
|
|
1951
|
+
join7(project, "package.json"),
|
|
1952
|
+
jsonSource(expoPackage(authEnabled, syncEnabled))
|
|
1377
1953
|
],
|
|
1378
|
-
[
|
|
1379
|
-
[join6(project, "package.json"), jsonSource(expoPackage(authEnabled))],
|
|
1380
|
-
[join6(project, "metro.config.js"), metroConfig(projectRoot)],
|
|
1954
|
+
[join7(project, "metro.config.js"), metroConfig(projectRoot)],
|
|
1381
1955
|
[
|
|
1382
|
-
|
|
1956
|
+
join7(project, "plugins", "withAbsoluteDevelopmentCa.js"),
|
|
1383
1957
|
expoDevelopmentCaPlugin
|
|
1384
1958
|
],
|
|
1385
1959
|
[
|
|
1386
|
-
|
|
1387
|
-
jsonSource(expoTsConfig(projectRoot, project, authEnabled))
|
|
1960
|
+
join7(project, "tsconfig.json"),
|
|
1961
|
+
jsonSource(expoTsConfig(projectRoot, project, authEnabled, syncEnabled))
|
|
1388
1962
|
],
|
|
1389
|
-
[join6(project, "app", "_layout.tsx"), layoutSource(authEnabled)],
|
|
1390
1963
|
[
|
|
1391
|
-
|
|
1964
|
+
join7(project, "app", "_layout.tsx"),
|
|
1965
|
+
layoutSource(authEnabled, syncEnabled)
|
|
1966
|
+
],
|
|
1967
|
+
[
|
|
1968
|
+
join7(project, "app", "__absolute", "native", "index.tsx"),
|
|
1392
1969
|
nativeDiagnosticSource
|
|
1393
1970
|
],
|
|
1394
1971
|
[
|
|
1395
|
-
|
|
1396
|
-
webHostSource(config, auth)
|
|
1972
|
+
join7(project, "src", "generated", "AbsoluteWebHost.tsx"),
|
|
1973
|
+
webHostSource(config, auth, syncEnabled)
|
|
1397
1974
|
]
|
|
1398
1975
|
]);
|
|
1399
1976
|
if (auth) {
|
|
1400
|
-
files.set(
|
|
1977
|
+
files.set(join7(project, "src", "generated", "AbsoluteAuth.ts"), authRuntimeSource(auth, config.appId));
|
|
1978
|
+
}
|
|
1979
|
+
if (syncSchema) {
|
|
1980
|
+
files.set(join7(project, "src", "generated", "AbsoluteSync.ts"), syncRuntimeSource(config, syncSchema));
|
|
1401
1981
|
}
|
|
1402
|
-
const webAssetsPath =
|
|
1982
|
+
const webAssetsPath = join7(project, "src", "generated", "webAssets.ts");
|
|
1403
1983
|
if (!await exists(webAssetsPath)) {
|
|
1404
1984
|
files.set(webAssetsPath, emptyWebAssetsSource);
|
|
1405
1985
|
}
|
|
1406
1986
|
if (!config.expoNativeRoutes["/"]) {
|
|
1407
|
-
files.set(
|
|
1987
|
+
files.set(join7(project, "app", "index.tsx"), webRouteSource);
|
|
1408
1988
|
}
|
|
1409
|
-
files.set(
|
|
1989
|
+
files.set(join7(project, "app", "[...absolute].tsx"), catchAllRouteSource);
|
|
1410
1990
|
for (const [route, module] of routeModules) {
|
|
1411
|
-
const wrapper = route === "/" ?
|
|
1991
|
+
const wrapper = route === "/" ? join7(project, "app", "index.tsx") : routeFile(project, route);
|
|
1412
1992
|
files.set(wrapper, nativeWrapperSource(wrapper, module));
|
|
1413
1993
|
}
|
|
1414
1994
|
const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
|
|
@@ -1417,7 +1997,7 @@ node_modules/
|
|
|
1417
1997
|
}, walkFiles = async (root, directory = root) => {
|
|
1418
1998
|
const entries = await readdir(directory, { withFileTypes: true });
|
|
1419
1999
|
const nested = await Promise.all(entries.map((entry) => {
|
|
1420
|
-
const path =
|
|
2000
|
+
const path = join7(directory, entry.name);
|
|
1421
2001
|
if (entry.isDirectory())
|
|
1422
2002
|
return walkFiles(root, path);
|
|
1423
2003
|
if (entry.isFile())
|
|
@@ -1478,11 +2058,11 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
1478
2058
|
`, syncAbsoluteExpoWebAssets = async (config) => {
|
|
1479
2059
|
if (config.engine !== "expo")
|
|
1480
2060
|
throw new TypeError("Expo asset sync requires mobile.engine: expo.");
|
|
1481
|
-
const marker =
|
|
2061
|
+
const marker = join7(config.nativeProjectDirectory, EXPO_PROJECT_MARKER);
|
|
1482
2062
|
if (!await exists(marker)) {
|
|
1483
2063
|
throw new TypeError("Expo asset sync requires an AbsoluteJS-managed Expo project. Run mobile init first.");
|
|
1484
2064
|
}
|
|
1485
|
-
const manifestPath =
|
|
2065
|
+
const manifestPath = join7(config.bundleDirectory, "absolute-mobile-manifest.json");
|
|
1486
2066
|
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
1487
2067
|
const appBuild = typeof manifest === "object" && manifest !== null && typeof Reflect.get(manifest, "appBuild") === "string" ? String(Reflect.get(manifest, "appBuild")) : undefined;
|
|
1488
2068
|
if (!appBuild)
|
|
@@ -1497,16 +2077,16 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
1497
2077
|
bundleHash.update("\x00");
|
|
1498
2078
|
});
|
|
1499
2079
|
const bundleId = `amexpo_${bundleHash.digest("hex")}`;
|
|
1500
|
-
const destination =
|
|
1501
|
-
await mkdir(
|
|
1502
|
-
const staging = await mkdtemp(
|
|
2080
|
+
const destination = join7(config.nativeProjectDirectory, "assets", "absolute");
|
|
2081
|
+
await mkdir(dirname4(destination), { recursive: true });
|
|
2082
|
+
const staging = await mkdtemp(join7(dirname4(destination), `.${basename2(destination)}.stage-`));
|
|
1503
2083
|
let assets;
|
|
1504
2084
|
try {
|
|
1505
2085
|
assets = await Promise.all(files.map(async (source, index) => {
|
|
1506
2086
|
const name = `${String(index).padStart(6, "0")}${EXPO_ASSET_EXTENSION}`;
|
|
1507
|
-
await cp(source,
|
|
2087
|
+
await cp(source, join7(staging, name));
|
|
1508
2088
|
return {
|
|
1509
|
-
asset: portableRelative(
|
|
2089
|
+
asset: portableRelative(join7(config.nativeProjectDirectory, "src", "generated"), join7(destination, name)),
|
|
1510
2090
|
path: relative(config.bundleDirectory, source).replaceAll("\\", "/")
|
|
1511
2091
|
};
|
|
1512
2092
|
}));
|
|
@@ -1515,12 +2095,13 @@ export const materializeAbsoluteWebBundle = async () => {
|
|
|
1515
2095
|
await rm(staging, { force: true, recursive: true });
|
|
1516
2096
|
throw error;
|
|
1517
2097
|
}
|
|
1518
|
-
const generated =
|
|
2098
|
+
const generated = join7(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
1519
2099
|
await writeManagedFile(generated, assetModuleSource(assets, bundleId), true);
|
|
1520
2100
|
return { appBuild, assets: assets.length, bundleId, path: destination };
|
|
1521
2101
|
};
|
|
1522
2102
|
var init_expoProject = __esm(() => {
|
|
1523
2103
|
init_nativeAuth();
|
|
2104
|
+
init_syncSchema();
|
|
1524
2105
|
expoDynamicAppConfig = `${EXPO_GENERATED_HEADER}const config = require('./app.json');
|
|
1525
2106
|
|
|
1526
2107
|
if (process.env.ABSOLUTE_EXPO_DEVELOPMENT === '1' && process.env.ABSOLUTE_EXPO_DEVELOPMENT_CA_PATH) {
|
|
@@ -1626,14 +2207,14 @@ import {
|
|
|
1626
2207
|
isIP
|
|
1627
2208
|
} from "net";
|
|
1628
2209
|
import { readFile as readFile2 } from "fs/promises";
|
|
1629
|
-
var closeServer = (server) => new Promise((
|
|
2210
|
+
var closeServer = (server) => new Promise((resolve5, reject) => {
|
|
1630
2211
|
server.close((error) => {
|
|
1631
2212
|
if (error)
|
|
1632
2213
|
reject(error);
|
|
1633
2214
|
else
|
|
1634
|
-
|
|
2215
|
+
resolve5();
|
|
1635
2216
|
});
|
|
1636
|
-
}), listen = (server, port) => new Promise((
|
|
2217
|
+
}), listen = (server, port) => new Promise((resolve5, reject) => {
|
|
1637
2218
|
server.once("error", reject);
|
|
1638
2219
|
server.listen(port, "0.0.0.0", () => {
|
|
1639
2220
|
server.off("error", reject);
|
|
@@ -1642,11 +2223,11 @@ var closeServer = (server) => new Promise((resolve4, reject) => {
|
|
|
1642
2223
|
reject(new Error("Could not determine the iOS device helper port."));
|
|
1643
2224
|
return;
|
|
1644
2225
|
}
|
|
1645
|
-
|
|
2226
|
+
resolve5(address.port);
|
|
1646
2227
|
});
|
|
1647
2228
|
}), findEphemeralPort = async () => {
|
|
1648
2229
|
const probe = createTcpServer();
|
|
1649
|
-
const port = await new Promise((
|
|
2230
|
+
const port = await new Promise((resolve5, reject) => {
|
|
1650
2231
|
probe.once("error", reject);
|
|
1651
2232
|
probe.listen(0, "127.0.0.1", () => {
|
|
1652
2233
|
const address = probe.address();
|
|
@@ -1654,7 +2235,7 @@ var closeServer = (server) => new Promise((resolve4, reject) => {
|
|
|
1654
2235
|
reject(new Error("Could not allocate the iOS CA enrollment port."));
|
|
1655
2236
|
return;
|
|
1656
2237
|
}
|
|
1657
|
-
|
|
2238
|
+
resolve5(address.port);
|
|
1658
2239
|
});
|
|
1659
2240
|
});
|
|
1660
2241
|
await closeServer(probe);
|
|
@@ -1669,9 +2250,9 @@ var closeServer = (server) => new Promise((resolve4, reject) => {
|
|
|
1669
2250
|
if (!normalized || normalized.length > 256 || /[\0\r\n]/u.test(normalized))
|
|
1670
2251
|
throw new TypeError("--ios-device requires a valid Xcode device identifier or name.");
|
|
1671
2252
|
return normalized;
|
|
1672
|
-
}, urlForHost = (protocol,
|
|
2253
|
+
}, urlForHost = (protocol, host2, port) => {
|
|
1673
2254
|
const url = new URL(`${protocol}://localhost:${port}`);
|
|
1674
|
-
const normalizedHost = normalizeAbsoluteIosDeviceHost(
|
|
2255
|
+
const normalizedHost = normalizeAbsoluteIosDeviceHost(host2);
|
|
1675
2256
|
url.hostname = isIP(normalizedHost) === 6 ? `[${normalizedHost}]` : normalizedHost;
|
|
1676
2257
|
return url;
|
|
1677
2258
|
}, startAbsoluteIosCaEnrollmentServer = async (options) => {
|
|
@@ -1711,12 +2292,12 @@ var init_iosPhysicalDeviceTransport = () => {};
|
|
|
1711
2292
|
// src/cli/utils.ts
|
|
1712
2293
|
var {$: $2 } = globalThis.Bun;
|
|
1713
2294
|
import { execSync } from "child_process";
|
|
1714
|
-
import { existsSync as existsSync3, readFileSync as
|
|
2295
|
+
import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
|
|
1715
2296
|
import { createServer as createServer3 } from "net";
|
|
1716
|
-
import { resolve as
|
|
2297
|
+
import { resolve as resolve5 } from "path";
|
|
1717
2298
|
var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backend/server.ts", isWSLEnvironment = () => {
|
|
1718
2299
|
try {
|
|
1719
|
-
const release =
|
|
2300
|
+
const release = readFileSync7("/proc/version", "utf-8");
|
|
1720
2301
|
return /microsoft|wsl/i.test(release);
|
|
1721
2302
|
} catch {
|
|
1722
2303
|
return false;
|
|
@@ -1815,7 +2396,7 @@ var COMPOSE_PATH = "db/docker-compose.db.yml", DEFAULT_SERVER_ENTRY = "src/backe
|
|
|
1815
2396
|
}, printHint = () => {
|
|
1816
2397
|
console.log("\x1B[90mpress h + enter to show shortcuts\x1B[0m");
|
|
1817
2398
|
}, readDbScripts = async () => {
|
|
1818
|
-
const pkgPath =
|
|
2399
|
+
const pkgPath = resolve5("package.json");
|
|
1819
2400
|
if (!existsSync3(pkgPath))
|
|
1820
2401
|
return null;
|
|
1821
2402
|
const pkg = await Bun.file(pkgPath).json();
|
|
@@ -1850,7 +2431,7 @@ var init_utils = __esm(() => {
|
|
|
1850
2431
|
// src/mobile/emulatorDoctor.ts
|
|
1851
2432
|
import { access as access3 } from "fs/promises";
|
|
1852
2433
|
import { homedir as homedir3 } from "os";
|
|
1853
|
-
import { join as
|
|
2434
|
+
import { join as join9 } from "path";
|
|
1854
2435
|
var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command) => {
|
|
1855
2436
|
try {
|
|
1856
2437
|
const result = Bun.spawnSync(command, {
|
|
@@ -1893,17 +2474,17 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1893
2474
|
} catch {
|
|
1894
2475
|
return;
|
|
1895
2476
|
}
|
|
1896
|
-
}, absoluteManagedAndroidSdkRoot = (
|
|
1897
|
-
if (
|
|
1898
|
-
return
|
|
2477
|
+
}, absoluteManagedAndroidSdkRoot = (host2, env = process.env) => {
|
|
2478
|
+
if (host2 === "windows") {
|
|
2479
|
+
return join9(env.LOCALAPPDATA ?? join9(homedir3(), "AppData", "Local"), "AbsoluteJS", "Android", "Sdk");
|
|
1899
2480
|
}
|
|
1900
|
-
if (
|
|
2481
|
+
if (host2 === "wsl") {
|
|
1901
2482
|
const localAppData = windowsLocalAppDataFromWsl();
|
|
1902
2483
|
if (localAppData) {
|
|
1903
|
-
return
|
|
2484
|
+
return join9(localAppData, "AbsoluteJS", "Android", "Sdk");
|
|
1904
2485
|
}
|
|
1905
2486
|
}
|
|
1906
|
-
return
|
|
2487
|
+
return join9(homedir3(), ".absolutejs", "android-sdk");
|
|
1907
2488
|
}, pathExists = async (path) => {
|
|
1908
2489
|
try {
|
|
1909
2490
|
await access3(path);
|
|
@@ -1919,18 +2500,18 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1919
2500
|
if (platform2 === "linux" && wsl)
|
|
1920
2501
|
return "wsl";
|
|
1921
2502
|
return "linux";
|
|
1922
|
-
}, executableNames = (
|
|
1923
|
-
if (
|
|
2503
|
+
}, executableNames = (host2, name) => {
|
|
2504
|
+
if (host2 === "wsl")
|
|
1924
2505
|
return [`${name}.exe`, `${name}.bat`, name];
|
|
1925
|
-
if (
|
|
2506
|
+
if (host2 === "windows")
|
|
1926
2507
|
return [name, `${name}.exe`, `${name}.bat`];
|
|
1927
2508
|
return [name];
|
|
1928
|
-
}, findExecutable = async (name, paths, options,
|
|
2509
|
+
}, findExecutable = async (name, paths, options, host2) => {
|
|
1929
2510
|
const existing = await Promise.all(paths.map(async (path) => await options.exists(path) ? path : undefined));
|
|
1930
2511
|
const configured = existing.find((path) => path !== undefined);
|
|
1931
2512
|
if (configured)
|
|
1932
2513
|
return configured;
|
|
1933
|
-
for (const candidate of executableNames(
|
|
2514
|
+
for (const candidate of executableNames(host2, name)) {
|
|
1934
2515
|
const path = options.which(candidate);
|
|
1935
2516
|
if (path)
|
|
1936
2517
|
return path;
|
|
@@ -1950,23 +2531,23 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1950
2531
|
status: "fail"
|
|
1951
2532
|
}, inspectAbsoluteMobileToolchain = async (input = {}) => {
|
|
1952
2533
|
const env = input.env ?? process.env;
|
|
1953
|
-
const
|
|
2534
|
+
const host2 = input.host ?? detectAbsoluteMobileHost();
|
|
1954
2535
|
const exists2 = input.exists ?? pathExists;
|
|
1955
2536
|
const which = input.which ?? ((command) => Bun.which(command));
|
|
1956
2537
|
const capture = input.capture ?? captureCommand;
|
|
1957
|
-
const androidRoot = input.androidRoot === null ? undefined : input.androidRoot ?? env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(
|
|
1958
|
-
const windowsAndroidTools =
|
|
1959
|
-
const android = (segments) => androidRoot ?
|
|
2538
|
+
const androidRoot = input.androidRoot === null ? undefined : input.androidRoot ?? env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2, env);
|
|
2539
|
+
const windowsAndroidTools = host2 === "windows" || host2 === "wsl";
|
|
2540
|
+
const android = (segments) => androidRoot ? join9(androidRoot, ...segments) : undefined;
|
|
1960
2541
|
const paths = (values) => values.filter((value) => Boolean(value));
|
|
1961
2542
|
const adb = await findExecutable("adb", paths([
|
|
1962
2543
|
android(["platform-tools", windowsAndroidTools ? "adb.exe" : "adb"])
|
|
1963
|
-
]), { exists: exists2, which },
|
|
2544
|
+
]), { exists: exists2, which }, host2);
|
|
1964
2545
|
const emulator = await findExecutable("emulator", paths([
|
|
1965
2546
|
android([
|
|
1966
2547
|
"emulator",
|
|
1967
2548
|
windowsAndroidTools ? "emulator.exe" : "emulator"
|
|
1968
2549
|
])
|
|
1969
|
-
]), { exists: exists2, which },
|
|
2550
|
+
]), { exists: exists2, which }, host2);
|
|
1970
2551
|
const sdkmanager = await findExecutable("sdkmanager", paths([
|
|
1971
2552
|
android([
|
|
1972
2553
|
"cmdline-tools",
|
|
@@ -1974,7 +2555,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1974
2555
|
"bin",
|
|
1975
2556
|
windowsAndroidTools ? "sdkmanager.bat" : "sdkmanager"
|
|
1976
2557
|
])
|
|
1977
|
-
]), { exists: exists2, which },
|
|
2558
|
+
]), { exists: exists2, which }, host2);
|
|
1978
2559
|
const avdmanager = await findExecutable("avdmanager", paths([
|
|
1979
2560
|
android([
|
|
1980
2561
|
"cmdline-tools",
|
|
@@ -1982,12 +2563,12 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
1982
2563
|
"bin",
|
|
1983
2564
|
windowsAndroidTools ? "avdmanager.bat" : "avdmanager"
|
|
1984
2565
|
])
|
|
1985
|
-
]), { exists: exists2, which },
|
|
1986
|
-
const java = await findExecutable("java", [], { exists: exists2, which },
|
|
2566
|
+
]), { exists: exists2, which }, host2);
|
|
2567
|
+
const java = await findExecutable("java", [], { exists: exists2, which }, host2);
|
|
1987
2568
|
const checks = [
|
|
1988
2569
|
{
|
|
1989
2570
|
id: "host",
|
|
1990
|
-
label: `Development host: ${
|
|
2571
|
+
label: `Development host: ${host2}`,
|
|
1991
2572
|
platform: "host",
|
|
1992
2573
|
status: "pass"
|
|
1993
2574
|
},
|
|
@@ -2008,7 +2589,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
2008
2589
|
status: hasManagedAvd ? "pass" : "fail"
|
|
2009
2590
|
});
|
|
2010
2591
|
}
|
|
2011
|
-
if (
|
|
2592
|
+
if (host2 === "wsl") {
|
|
2012
2593
|
checks.push({
|
|
2013
2594
|
id: "android.virtualization",
|
|
2014
2595
|
label: adb?.endsWith(".exe") ? "Windows-host Android bridge available to WSL" : "WSL requires a Windows-host emulator bridge or Linux KVM",
|
|
@@ -2016,7 +2597,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
2016
2597
|
remediation: adb?.endsWith(".exe") ? undefined : "Expose the Windows Android SDK adb.exe to WSL, or enable /dev/kvm for a Linux SDK.",
|
|
2017
2598
|
status: adb?.endsWith(".exe") ? "pass" : "warn"
|
|
2018
2599
|
});
|
|
2019
|
-
} else if (
|
|
2600
|
+
} else if (host2 === "linux") {
|
|
2020
2601
|
const hasKvm = await exists2("/dev/kvm");
|
|
2021
2602
|
checks.push({
|
|
2022
2603
|
id: "android.virtualization",
|
|
@@ -2026,7 +2607,7 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
2026
2607
|
status: hasKvm ? "pass" : "warn"
|
|
2027
2608
|
});
|
|
2028
2609
|
}
|
|
2029
|
-
if (
|
|
2610
|
+
if (host2 !== "macos") {
|
|
2030
2611
|
checks.push({
|
|
2031
2612
|
id: "ios.simulator",
|
|
2032
2613
|
label: "iOS Simulator requires macOS and Xcode",
|
|
@@ -2035,8 +2616,8 @@ var ABSOLUTE_ANDROID_AVD_NAME = "AbsoluteJS_API_36", captureCommand = (command)
|
|
|
2035
2616
|
});
|
|
2036
2617
|
return checks;
|
|
2037
2618
|
}
|
|
2038
|
-
const xcrun = await findExecutable("xcrun", [], { exists: exists2, which },
|
|
2039
|
-
const xcodebuild = await findExecutable("xcodebuild", [], { exists: exists2, which },
|
|
2619
|
+
const xcrun = await findExecutable("xcrun", [], { exists: exists2, which }, host2);
|
|
2620
|
+
const xcodebuild = await findExecutable("xcodebuild", [], { exists: exists2, which }, host2);
|
|
2040
2621
|
checks.push(toolCheck("ios.xcrun", "Xcode command runner", "ios", xcrun, "Install Xcode and select it with xcode-select."), toolCheck("ios.xcodebuild", "Xcode build system", "ios", xcodebuild, "Install Xcode and select it with xcode-select."));
|
|
2041
2622
|
if (xcrun) {
|
|
2042
2623
|
const runtimes = capture([
|
|
@@ -2063,7 +2644,7 @@ var init_emulatorDoctor = __esm(() => {
|
|
|
2063
2644
|
|
|
2064
2645
|
// src/mobile/capacitorProject.ts
|
|
2065
2646
|
import { access as access4, readFile as readFile3, rename as rename2, writeFile as writeFile2 } from "fs/promises";
|
|
2066
|
-
import { relative as relative2, resolve as
|
|
2647
|
+
import { relative as relative2, resolve as resolve6 } from "path";
|
|
2067
2648
|
var CONFIG_FILE = "capacitor.config.ts", portableRelative2 = (root, path) => relative2(root, path).replaceAll("\\", "/"), capacitorConfigSource = (config, projectRoot) => `import type { CapacitorConfig } from '@capacitor/cli';
|
|
2068
2649
|
|
|
2069
2650
|
const config: CapacitorConfig = {
|
|
@@ -2087,8 +2668,8 @@ export default config;
|
|
|
2087
2668
|
return false;
|
|
2088
2669
|
}
|
|
2089
2670
|
}, writeAbsoluteCapacitorConfig = async (config, options) => {
|
|
2090
|
-
const projectRoot =
|
|
2091
|
-
const destination =
|
|
2671
|
+
const projectRoot = resolve6(options.projectRoot);
|
|
2672
|
+
const destination = resolve6(projectRoot, CONFIG_FILE);
|
|
2092
2673
|
const source = capacitorConfigSource(config, projectRoot);
|
|
2093
2674
|
if (await exists2(destination)) {
|
|
2094
2675
|
const current = await readFile3(destination, "utf8");
|
|
@@ -2121,11 +2702,11 @@ import {
|
|
|
2121
2702
|
} from "fs/promises";
|
|
2122
2703
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
|
|
2123
2704
|
import {
|
|
2124
|
-
dirname as
|
|
2705
|
+
dirname as dirname5,
|
|
2125
2706
|
isAbsolute,
|
|
2126
|
-
join as
|
|
2707
|
+
join as join10,
|
|
2127
2708
|
relative as relative3,
|
|
2128
|
-
resolve as
|
|
2709
|
+
resolve as resolve7,
|
|
2129
2710
|
sep,
|
|
2130
2711
|
win32
|
|
2131
2712
|
} from "path";
|
|
@@ -2295,21 +2876,21 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2295
2876
|
return;
|
|
2296
2877
|
throw new DOMException("Android development startup was cancelled.", "AbortError");
|
|
2297
2878
|
}, journalPaths = (projectRoot) => {
|
|
2298
|
-
const root =
|
|
2879
|
+
const root = join10(projectRoot, ".absolutejs", "mobile", "dev-session");
|
|
2299
2880
|
return {
|
|
2300
|
-
backup:
|
|
2301
|
-
caBackup:
|
|
2302
|
-
journal:
|
|
2303
|
-
manifestBackup:
|
|
2304
|
-
networkConfigBackup:
|
|
2881
|
+
backup: join10(root, "capacitor.config.backup.json"),
|
|
2882
|
+
caBackup: join10(root, "absolutejs_dev_ca.backup.pem"),
|
|
2883
|
+
journal: join10(root, "journal.json"),
|
|
2884
|
+
manifestBackup: join10(root, "AndroidManifest.backup.xml"),
|
|
2885
|
+
networkConfigBackup: join10(root, "absolutejs_dev_network_security.backup.xml"),
|
|
2305
2886
|
root
|
|
2306
2887
|
};
|
|
2307
2888
|
}, isInside = (root, path) => {
|
|
2308
|
-
const resolvedRoot =
|
|
2309
|
-
const resolvedPath =
|
|
2889
|
+
const resolvedRoot = resolve7(root);
|
|
2890
|
+
const resolvedPath = resolve7(path);
|
|
2310
2891
|
const relativePath = relative3(resolvedRoot, resolvedPath);
|
|
2311
2892
|
return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${sep}`) && !isAbsolute(relativePath);
|
|
2312
|
-
}, isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), nativeCachePath = (projectRoot) =>
|
|
2893
|
+
}, isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), nativeCachePath = (projectRoot) => join10(projectRoot, ".absolutejs", "mobile", "cache", "android-debug.json"), parseNativeCache = (value) => {
|
|
2313
2894
|
if (!isRecord(value))
|
|
2314
2895
|
return null;
|
|
2315
2896
|
const { appId, fingerprint, format, installations } = value;
|
|
@@ -2328,7 +2909,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2328
2909
|
}, readNativeCache = async (projectRoot) => readFile4(nativeCachePath(projectRoot), "utf8").then((source) => parseNativeCache(JSON.parse(source))).catch(() => null), writeNativeCache = async (projectRoot, cache) => {
|
|
2329
2910
|
const destination = nativeCachePath(projectRoot);
|
|
2330
2911
|
const temporary = `${destination}.${process.pid}.${randomUUID2()}.tmp`;
|
|
2331
|
-
await mkdir2(
|
|
2912
|
+
await mkdir2(dirname5(destination), { recursive: true });
|
|
2332
2913
|
try {
|
|
2333
2914
|
await writeFile3(temporary, `${JSON.stringify(cache, null, "\t")}
|
|
2334
2915
|
`, {
|
|
@@ -2341,11 +2922,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2341
2922
|
});
|
|
2342
2923
|
}
|
|
2343
2924
|
}, nativeDependencySources = async (nativeDirectory) => {
|
|
2344
|
-
const settings = await readFile4(
|
|
2925
|
+
const settings = await readFile4(join10(nativeDirectory, "capacitor.settings.gradle"), "utf8");
|
|
2345
2926
|
const pattern = new RegExp(CAPACITOR_PROJECT_DIRECTORY_PATTERN.source, CAPACITOR_PROJECT_DIRECTORY_PATTERN.flags);
|
|
2346
2927
|
const dependencies = [...settings.matchAll(pattern)].map((match) => ({
|
|
2347
2928
|
name: (match[1] ?? "").slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_"),
|
|
2348
|
-
source:
|
|
2929
|
+
source: resolve7(nativeDirectory, match[2] ?? "")
|
|
2349
2930
|
}));
|
|
2350
2931
|
if (dependencies.length === 0) {
|
|
2351
2932
|
throw new Error("Capacitor Android settings did not declare any native dependencies.");
|
|
@@ -2381,7 +2962,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2381
2962
|
}, collectNativeDirectory = async (root, label, directory, ignorePublicBundle) => {
|
|
2382
2963
|
const entries = await readdir2(directory, { withFileTypes: true });
|
|
2383
2964
|
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
2384
|
-
const records = await Promise.all(entries.map((entry) => collectNativePath(root, label,
|
|
2965
|
+
const records = await Promise.all(entries.map((entry) => collectNativePath(root, label, join10(directory, entry.name), entry.isDirectory(), entry.isFile(), entry.isSymbolicLink(), ignorePublicBundle)));
|
|
2385
2966
|
return records.flat();
|
|
2386
2967
|
}, hashNativeTree = async (root, label, ignorePublicBundle) => {
|
|
2387
2968
|
const resolvedRoot = await realpath(root);
|
|
@@ -2434,7 +3015,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2434
3015
|
await rm2(file.path, { force: true });
|
|
2435
3016
|
return;
|
|
2436
3017
|
}
|
|
2437
|
-
await mkdir2(
|
|
3018
|
+
await mkdir2(dirname5(file.path), { recursive: true });
|
|
2438
3019
|
await copyFile(file.backupPath, file.path);
|
|
2439
3020
|
}, repairAbsoluteAndroidDevSession = async (projectRoot) => {
|
|
2440
3021
|
const paths = journalPaths(projectRoot);
|
|
@@ -2447,11 +3028,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2447
3028
|
throw new Error(`Refusing unsafe or invalid mobile dev journal at ${paths.journal}.`);
|
|
2448
3029
|
}
|
|
2449
3030
|
if (await pathExists2(journal.backupPath)) {
|
|
2450
|
-
await mkdir2(
|
|
3031
|
+
await mkdir2(dirname5(journal.nativeConfigPath), { recursive: true });
|
|
2451
3032
|
await copyFile(journal.backupPath, journal.nativeConfigPath);
|
|
2452
3033
|
}
|
|
2453
3034
|
if (journal.manifestBackupPath && journal.nativeManifestPath && await pathExists2(journal.manifestBackupPath)) {
|
|
2454
|
-
await mkdir2(
|
|
3035
|
+
await mkdir2(dirname5(journal.nativeManifestPath), { recursive: true });
|
|
2455
3036
|
await copyFile(journal.manifestBackupPath, journal.nativeManifestPath);
|
|
2456
3037
|
}
|
|
2457
3038
|
await Promise.all((journal.projectedFiles ?? []).map(restoreAndroidProjectedFile));
|
|
@@ -2510,11 +3091,11 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2510
3091
|
await mkdir2(paths.root, { recursive: true });
|
|
2511
3092
|
await writeFile3(paths.backup, source, { flag: "wx" });
|
|
2512
3093
|
await writeFile3(paths.manifestBackup, manifestSource, { flag: "wx" });
|
|
2513
|
-
const resourceRoot =
|
|
2514
|
-
const caPath =
|
|
3094
|
+
const resourceRoot = join10(dirname5(nativeManifestPath), "res");
|
|
3095
|
+
const caPath = join10(resourceRoot, "raw", "absolutejs_dev_ca.pem");
|
|
2515
3096
|
const existingNetworkConfig = manifestSource.match(/android:networkSecurityConfig=["']@xml\/([a-z0-9_]+)["']/u)?.[1];
|
|
2516
3097
|
const networkConfigName = existingNetworkConfig ?? "absolutejs_dev_network_security";
|
|
2517
|
-
const networkConfigPath =
|
|
3098
|
+
const networkConfigPath = join10(resourceRoot, "xml", `${networkConfigName}.xml`);
|
|
2518
3099
|
const backupProjectedFile = async ([path, backupPath]) => {
|
|
2519
3100
|
if (!await pathExists2(path))
|
|
2520
3101
|
return { path };
|
|
@@ -2551,8 +3132,8 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2551
3132
|
`);
|
|
2552
3133
|
if (https && certificateAuthorityPath) {
|
|
2553
3134
|
await Promise.all([
|
|
2554
|
-
mkdir2(
|
|
2555
|
-
mkdir2(
|
|
3135
|
+
mkdir2(dirname5(caPath), { recursive: true }),
|
|
3136
|
+
mkdir2(dirname5(networkConfigPath), { recursive: true })
|
|
2556
3137
|
]);
|
|
2557
3138
|
await copyFile(certificateAuthorityPath, caPath);
|
|
2558
3139
|
const existingNetworkConfigSource = existingNetworkConfig ? await readFile4(networkConfigPath, "utf8") : `<?xml version="1.0" encoding="utf-8"?>
|
|
@@ -2607,12 +3188,12 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2607
3188
|
}
|
|
2608
3189
|
return result.stdout.trim();
|
|
2609
3190
|
}, mirroredCapacitorDependencies = async (project, capture) => {
|
|
2610
|
-
const settingsPath =
|
|
3191
|
+
const settingsPath = join10(project.nativeDirectory, "capacitor.settings.gradle");
|
|
2611
3192
|
const settings = await readFile4(settingsPath, "utf8");
|
|
2612
3193
|
const dependencies = [];
|
|
2613
3194
|
const rewrittenSettings = settings.replace(CAPACITOR_PROJECT_DIRECTORY_PATTERN, (_statement, projectName, sourcePath) => {
|
|
2614
3195
|
const name = projectName.slice(1).replaceAll(/[^a-zA-Z0-9_.-]/gu, "_");
|
|
2615
|
-
const source =
|
|
3196
|
+
const source = resolve7(project.nativeDirectory, sourcePath);
|
|
2616
3197
|
dependencies.push({
|
|
2617
3198
|
name,
|
|
2618
3199
|
windowsSource: windowsPathFromWsl(source, capture)
|
|
@@ -2653,7 +3234,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2653
3234
|
].join("; ");
|
|
2654
3235
|
return Buffer.from(source, "utf16le").toString("base64");
|
|
2655
3236
|
}, gradleArtifactPath = (nativeDirectory, task, windows = false) => {
|
|
2656
|
-
const pathJoin = windows ? win32.join :
|
|
3237
|
+
const pathJoin = windows ? win32.join : join10;
|
|
2657
3238
|
if (task === "assembleDebug") {
|
|
2658
3239
|
return pathJoin(nativeDirectory, "app", "build", "outputs", "apk", "debug", "app-debug.apk");
|
|
2659
3240
|
}
|
|
@@ -2666,7 +3247,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2666
3247
|
if (task !== "assembleRelease" || await pathExists2(primary)) {
|
|
2667
3248
|
return primary;
|
|
2668
3249
|
}
|
|
2669
|
-
return
|
|
3250
|
+
return join10(nativeDirectory, "app", "build", "outputs", "apk", "release", "app-release-unsigned.apk");
|
|
2670
3251
|
}, buildAbsoluteAndroidGradleArtifact = async (options) => {
|
|
2671
3252
|
const { project, task } = options;
|
|
2672
3253
|
const capture = options.capture ?? captureCommand2;
|
|
@@ -2676,7 +3257,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2676
3257
|
if (project.host === "wsl") {
|
|
2677
3258
|
const windowsSource = windowsPathFromWsl(project.nativeDirectory, capture);
|
|
2678
3259
|
const buildId = Bun.hash(project.projectRoot).toString(HASH_RADIX);
|
|
2679
|
-
const managedBuildDirectory =
|
|
3260
|
+
const managedBuildDirectory = resolve7(project.androidRoot, "..", "..", "Builds", `${project.config.appId}-${buildId}`);
|
|
2680
3261
|
const windowsDirectory = windowsPathFromWsl(managedBuildDirectory, capture);
|
|
2681
3262
|
const windowsAndroidRoot = windowsPathFromWsl(project.androidRoot, capture);
|
|
2682
3263
|
const { dependencies, rewrittenSettings } = await mirroredCapacitorDependencies(project, capture);
|
|
@@ -2859,10 +3440,10 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2859
3440
|
"chromium:I"
|
|
2860
3441
|
], { env }, onLine);
|
|
2861
3442
|
}, prepareAbsoluteAndroidDevProject = async (config, options) => {
|
|
2862
|
-
const projectRoot =
|
|
2863
|
-
const
|
|
2864
|
-
const androidRoot = process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(
|
|
2865
|
-
const checks = await inspectAbsoluteMobileToolchain({ androidRoot, host });
|
|
3443
|
+
const projectRoot = resolve7(options.projectRoot);
|
|
3444
|
+
const host2 = detectAbsoluteMobileHost();
|
|
3445
|
+
const androidRoot = process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2);
|
|
3446
|
+
const checks = await inspectAbsoluteMobileToolchain({ androidRoot, host: host2 });
|
|
2866
3447
|
const deviceOnlyChecks = new Set([
|
|
2867
3448
|
"android.avd",
|
|
2868
3449
|
"android.avdmanager",
|
|
@@ -2878,18 +3459,18 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2878
3459
|
if (!adb || options.target !== "device" && !emulator) {
|
|
2879
3460
|
throw new Error("Android SDK tools disappeared after readiness checks.");
|
|
2880
3461
|
}
|
|
2881
|
-
const cap =
|
|
3462
|
+
const cap = join10(projectRoot, "node_modules", ".bin", host2 === "windows" ? "cap.cmd" : "cap");
|
|
2882
3463
|
if (!await pathExists2(cap)) {
|
|
2883
3464
|
throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
|
|
2884
3465
|
}
|
|
2885
3466
|
await writeAbsoluteCapacitorConfig(config, { projectRoot });
|
|
2886
3467
|
await mkdir2(config.bundleDirectory, { recursive: true });
|
|
2887
|
-
const placeholder =
|
|
3468
|
+
const placeholder = join10(config.bundleDirectory, "index.html");
|
|
2888
3469
|
if (!await pathExists2(placeholder)) {
|
|
2889
3470
|
await writeFile3(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
|
|
2890
3471
|
`);
|
|
2891
3472
|
}
|
|
2892
|
-
const nativeDirectory =
|
|
3473
|
+
const nativeDirectory = join10(config.nativeProjectDirectory, "android");
|
|
2893
3474
|
if (!await pathExists2(nativeDirectory)) {
|
|
2894
3475
|
if (!options.createNativeProject) {
|
|
2895
3476
|
throw new Error("Android native project has not been created.");
|
|
@@ -2907,7 +3488,7 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2907
3488
|
cap,
|
|
2908
3489
|
config,
|
|
2909
3490
|
...emulator ? { emulator } : {},
|
|
2910
|
-
host,
|
|
3491
|
+
host: host2,
|
|
2911
3492
|
nativeDirectory,
|
|
2912
3493
|
projectRoot
|
|
2913
3494
|
};
|
|
@@ -2950,8 +3531,8 @@ var ANDROID_BOOT_TIMEOUT_MS = 180000, ANDROID_BOOT_POLL_MS = 1000, DEV_JOURNAL_F
|
|
|
2950
3531
|
await requireSuccess([project.cap, "sync", "android"], "Capacitor Android synchronization", run, { cwd: project.projectRoot, env, signal: options.signal });
|
|
2951
3532
|
throwIfAborted(options.signal);
|
|
2952
3533
|
transition("configuring");
|
|
2953
|
-
const nativeConfigPath =
|
|
2954
|
-
const nativeManifestPath =
|
|
3534
|
+
const nativeConfigPath = join10(project.nativeDirectory, "app", "src", "main", "assets", "capacitor.config.json");
|
|
3535
|
+
const nativeManifestPath = join10(project.nativeDirectory, "app", "src", "main", "AndroidManifest.xml");
|
|
2955
3536
|
let connectedSerial;
|
|
2956
3537
|
let nativeLogs = null;
|
|
2957
3538
|
const closeNativeLogs = async () => {
|
|
@@ -3110,7 +3691,7 @@ var init_androidEmulatorController = __esm(() => {
|
|
|
3110
3691
|
import { createHash as createHash3 } from "crypto";
|
|
3111
3692
|
import { cp as cp2, mkdir as mkdir3, mkdtemp as mkdtemp2, readFile as readFile5, rm as rm3 } from "fs/promises";
|
|
3112
3693
|
import { tmpdir } from "os";
|
|
3113
|
-
import { basename as basename3, join as
|
|
3694
|
+
import { basename as basename3, join as join11 } from "path";
|
|
3114
3695
|
var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION = "15859902", LICENSE_ACCEPTANCE_RESPONSES = 100, COMMAND_LINE_TOOLS, defaultRun = async (command, options = {}) => {
|
|
3115
3696
|
const subprocess = Bun.spawn(command, {
|
|
3116
3697
|
env: options.env,
|
|
@@ -3142,33 +3723,33 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3142
3723
|
exitCode: result.exitCode,
|
|
3143
3724
|
stdout: result.stdout.toString()
|
|
3144
3725
|
};
|
|
3145
|
-
}, commandPath = (root,
|
|
3726
|
+
}, commandPath = (root, host2, tool) => join11(root, "cmdline-tools", "latest", "bin", host2 === "windows" || host2 === "wsl" ? `${tool}.bat` : tool), executablePath = (root, host2, directory, tool) => join11(root, directory, host2 === "windows" || host2 === "wsl" ? `${tool}.exe` : tool), windowsPath = (path) => {
|
|
3146
3727
|
const match = /^\/mnt\/([a-z])\/(.*)$/i.exec(path);
|
|
3147
3728
|
if (!match)
|
|
3148
3729
|
return path;
|
|
3149
3730
|
return `${match[1]?.toUpperCase()}:\\${match[2]?.replaceAll("/", "\\")}`;
|
|
3150
|
-
}, runnableCommand = (
|
|
3151
|
-
if (
|
|
3731
|
+
}, runnableCommand = (host2, path, args) => {
|
|
3732
|
+
if (host2 !== "wsl" || !path.endsWith(".bat"))
|
|
3152
3733
|
return [path, ...args];
|
|
3153
3734
|
return ["cmd.exe", "/d", "/c", windowsPath(path), ...args];
|
|
3154
|
-
}, systemImageFor = (
|
|
3155
|
-
const imageArch =
|
|
3735
|
+
}, systemImageFor = (host2, arch2) => {
|
|
3736
|
+
const imageArch = host2 === "macos" && arch2 === "arm64" ? "arm64-v8a" : "x86_64";
|
|
3156
3737
|
return `system-images;android-${ANDROID_API};google_apis;${imageArch}`;
|
|
3157
3738
|
}, planAbsoluteMobileEmulatorInstall = (platform2, input = {}) => {
|
|
3158
|
-
const
|
|
3739
|
+
const host2 = input.host ?? detectAbsoluteMobileHost();
|
|
3159
3740
|
const env = {
|
|
3160
3741
|
...process.env,
|
|
3161
3742
|
...input.env
|
|
3162
3743
|
};
|
|
3163
|
-
const androidRoot = env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(
|
|
3744
|
+
const androidRoot = env.ANDROID_HOME ?? env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host2, env);
|
|
3164
3745
|
if (platform2 === "ios") {
|
|
3165
3746
|
return {
|
|
3166
3747
|
androidRoot,
|
|
3167
|
-
host,
|
|
3748
|
+
host: host2,
|
|
3168
3749
|
platform: platform2,
|
|
3169
3750
|
steps: [
|
|
3170
3751
|
{
|
|
3171
|
-
detail:
|
|
3752
|
+
detail: host2 === "macos" ? "Use Xcode to download the current iOS Simulator runtime." : "iOS Simulator setup must run on a macOS host.",
|
|
3172
3753
|
id: "ios.runtime",
|
|
3173
3754
|
label: "Install iOS Simulator runtime"
|
|
3174
3755
|
}
|
|
@@ -3177,7 +3758,7 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3177
3758
|
}
|
|
3178
3759
|
return {
|
|
3179
3760
|
androidRoot,
|
|
3180
|
-
host,
|
|
3761
|
+
host: host2,
|
|
3181
3762
|
platform: platform2,
|
|
3182
3763
|
steps: [
|
|
3183
3764
|
{
|
|
@@ -3197,15 +3778,15 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3197
3778
|
}
|
|
3198
3779
|
]
|
|
3199
3780
|
};
|
|
3200
|
-
}, releaseFor = (
|
|
3201
|
-
let platform2 =
|
|
3202
|
-
if (
|
|
3781
|
+
}, releaseFor = (host2, arch2) => {
|
|
3782
|
+
let platform2 = host2;
|
|
3783
|
+
if (host2 === "wsl")
|
|
3203
3784
|
platform2 = "windows";
|
|
3204
|
-
if (
|
|
3785
|
+
if (host2 === "macos")
|
|
3205
3786
|
platform2 = "darwin";
|
|
3206
3787
|
const release = COMMAND_LINE_TOOLS[`${platform2}-${arch2}`];
|
|
3207
3788
|
if (!release) {
|
|
3208
|
-
throw new Error(`Automatic Android command-line-tools installation is not available for ${
|
|
3789
|
+
throw new Error(`Automatic Android command-line-tools installation is not available for ${host2}/${arch2}.`);
|
|
3209
3790
|
}
|
|
3210
3791
|
return release;
|
|
3211
3792
|
}, installCommandLineTools = async (plan, input) => {
|
|
@@ -3216,10 +3797,10 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3216
3797
|
if (digest !== release.sha256) {
|
|
3217
3798
|
throw new Error(`Android command-line-tools checksum mismatch: expected ${release.sha256}, received ${digest}.`);
|
|
3218
3799
|
}
|
|
3219
|
-
const temporary = await mkdtemp2(
|
|
3800
|
+
const temporary = await mkdtemp2(join11(tmpdir(), "absolutejs-android-sdk-"));
|
|
3220
3801
|
try {
|
|
3221
|
-
const archive =
|
|
3222
|
-
const extracted =
|
|
3802
|
+
const archive = join11(temporary, "command-line-tools.zip");
|
|
3803
|
+
const extracted = join11(temporary, "extracted");
|
|
3223
3804
|
await Bun.write(archive, bytes);
|
|
3224
3805
|
await mkdir3(extracted, { recursive: true });
|
|
3225
3806
|
const extraction = plan.host === "windows" ? [
|
|
@@ -3236,12 +3817,12 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3236
3817
|
if (await input.run(extraction) !== 0) {
|
|
3237
3818
|
throw new Error("Failed to extract Android command-line tools.");
|
|
3238
3819
|
}
|
|
3239
|
-
const destination =
|
|
3240
|
-
await mkdir3(
|
|
3820
|
+
const destination = join11(plan.androidRoot, "cmdline-tools", "latest");
|
|
3821
|
+
await mkdir3(join11(plan.androidRoot, "cmdline-tools"), {
|
|
3241
3822
|
recursive: true
|
|
3242
3823
|
});
|
|
3243
3824
|
await rm3(destination, { force: true, recursive: true });
|
|
3244
|
-
await cp2(
|
|
3825
|
+
await cp2(join11(extracted, "cmdline-tools"), destination, {
|
|
3245
3826
|
recursive: true
|
|
3246
3827
|
});
|
|
3247
3828
|
} finally {
|
|
@@ -3251,9 +3832,9 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3251
3832
|
if (await run(command, options) !== 0) {
|
|
3252
3833
|
throw new Error(`${label} failed.`);
|
|
3253
3834
|
}
|
|
3254
|
-
}, installJavaRuntime = async (
|
|
3255
|
-
if (
|
|
3256
|
-
const winget =
|
|
3835
|
+
}, installJavaRuntime = async (host2, run, which) => {
|
|
3836
|
+
if (host2 === "windows" || host2 === "wsl") {
|
|
3837
|
+
const winget = host2 === "wsl" ? "winget.exe" : "winget";
|
|
3257
3838
|
if (!which(winget)) {
|
|
3258
3839
|
throw new Error("Java 21 is required. Install Temurin 21 or make winget available, then run mobile doctor --fix again.");
|
|
3259
3840
|
}
|
|
@@ -3266,10 +3847,10 @@ var ANDROID_API = 36, ANDROID_BUILD_TOOLS = "36.0.0", COMMAND_LINE_TOOLS_VERSION
|
|
|
3266
3847
|
"--accept-package-agreements",
|
|
3267
3848
|
"--accept-source-agreements"
|
|
3268
3849
|
];
|
|
3269
|
-
await ensureCommand(
|
|
3850
|
+
await ensureCommand(host2 === "wsl" ? ["cmd.exe", "/d", "/c", ...command] : command, "Java 21 installation", run);
|
|
3270
3851
|
return;
|
|
3271
3852
|
}
|
|
3272
|
-
if (
|
|
3853
|
+
if (host2 === "macos") {
|
|
3273
3854
|
if (!which("brew")) {
|
|
3274
3855
|
throw new Error("Java 21 is required. Install Homebrew or Temurin 21, then run mobile doctor --fix again.");
|
|
3275
3856
|
}
|
|
@@ -3426,7 +4007,7 @@ import {
|
|
|
3426
4007
|
stat,
|
|
3427
4008
|
writeFile as writeFile4
|
|
3428
4009
|
} from "fs/promises";
|
|
3429
|
-
import { dirname as
|
|
4010
|
+
import { dirname as dirname6, isAbsolute as isAbsolute2, join as join12, relative as relative4, resolve as resolve8, sep as sep2 } from "path";
|
|
3430
4011
|
var developmentTeamArgument = (value) => {
|
|
3431
4012
|
if (value === undefined)
|
|
3432
4013
|
return;
|
|
@@ -3483,7 +4064,7 @@ var developmentTeamArgument = (value) => {
|
|
|
3483
4064
|
}, ignoredFingerprintDirectories, fingerprintFiles = async (root, current = root, options = {}) => {
|
|
3484
4065
|
const entries = await readdir3(current, { withFileTypes: true });
|
|
3485
4066
|
const nested = await Promise.all(entries.sort((left, right) => left.name.localeCompare(right.name)).map(async (entry) => {
|
|
3486
|
-
const path =
|
|
4067
|
+
const path = join12(current, entry.name);
|
|
3487
4068
|
const projectRelative = relative4(root, path).replaceAll("\\", "/");
|
|
3488
4069
|
const ignored = entry.isDirectory() && (ignoredFingerprintDirectories.has(entry.name) || projectRelative === "App/App/public" && options.includePublicBundle !== true);
|
|
3489
4070
|
if (ignored)
|
|
@@ -3505,8 +4086,8 @@ var developmentTeamArgument = (value) => {
|
|
|
3505
4086
|
});
|
|
3506
4087
|
return hasher.digest("hex");
|
|
3507
4088
|
}, safeOutputDirectory = (projectRoot, requested) => {
|
|
3508
|
-
const root =
|
|
3509
|
-
const output =
|
|
4089
|
+
const root = resolve8(projectRoot);
|
|
4090
|
+
const output = resolve8(root, requested ?? ".absolutejs/mobile/releases/ios");
|
|
3510
4091
|
const projectRelative = relative4(root, output);
|
|
3511
4092
|
if (projectRelative === ".." || projectRelative.startsWith(`..${sep2}`) || isAbsolute2(projectRelative)) {
|
|
3512
4093
|
throw new TypeError("mobile build --outdir must remain inside the project.");
|
|
@@ -3517,7 +4098,7 @@ var developmentTeamArgument = (value) => {
|
|
|
3517
4098
|
return;
|
|
3518
4099
|
const entries = await readdir3(root, { withFileTypes: true });
|
|
3519
4100
|
const matches = await Promise.all(entries.map(async (entry) => {
|
|
3520
|
-
const path =
|
|
4101
|
+
const path = join12(root, entry.name);
|
|
3521
4102
|
if (entry.isDirectory() && entry.name.endsWith(extension))
|
|
3522
4103
|
return path;
|
|
3523
4104
|
if (entry.isFile() && entry.name.endsWith(extension))
|
|
@@ -3540,10 +4121,10 @@ var developmentTeamArgument = (value) => {
|
|
|
3540
4121
|
throw new TypeError("iOS build number must be a positive integer.");
|
|
3541
4122
|
return value;
|
|
3542
4123
|
}, installRelease = async (artifactPath, metadata, outputRoot) => {
|
|
3543
|
-
const releaseRoot =
|
|
3544
|
-
const destination =
|
|
4124
|
+
const releaseRoot = join12(outputRoot, metadata.releaseId);
|
|
4125
|
+
const destination = join12(releaseRoot, "App.ipa");
|
|
3545
4126
|
if (await pathExists3(releaseRoot)) {
|
|
3546
|
-
const value = JSON.parse(await readFile6(
|
|
4127
|
+
const value = JSON.parse(await readFile6(join12(releaseRoot, "release.json"), "utf8"));
|
|
3547
4128
|
if (!isRecord2(value) || value.artifact !== "App.ipa" || Object.entries(metadata).some(([key, expected]) => Reflect.get(value, key) !== expected)) {
|
|
3548
4129
|
throw new TypeError(`Immutable iOS release ${metadata.releaseId} does not match its content.`);
|
|
3549
4130
|
}
|
|
@@ -3562,15 +4143,15 @@ var developmentTeamArgument = (value) => {
|
|
|
3562
4143
|
releaseRoot
|
|
3563
4144
|
};
|
|
3564
4145
|
}
|
|
3565
|
-
await mkdir4(
|
|
3566
|
-
const staging = await mkdtemp3(
|
|
4146
|
+
await mkdir4(dirname6(releaseRoot), { recursive: true });
|
|
4147
|
+
const staging = await mkdtemp3(join12(dirname6(releaseRoot), ".ios-stage-"));
|
|
3567
4148
|
try {
|
|
3568
|
-
await copyFile2(artifactPath,
|
|
4149
|
+
await copyFile2(artifactPath, join12(staging, "App.ipa"));
|
|
3569
4150
|
const complete = {
|
|
3570
4151
|
...metadata,
|
|
3571
4152
|
artifact: "App.ipa"
|
|
3572
4153
|
};
|
|
3573
|
-
await writeFile4(
|
|
4154
|
+
await writeFile4(join12(staging, "release.json"), `${JSON.stringify(complete, null, "\t")}
|
|
3574
4155
|
`, { flag: "wx" });
|
|
3575
4156
|
await rename4(staging, releaseRoot);
|
|
3576
4157
|
return { artifactPath: destination, metadata: complete, releaseRoot };
|
|
@@ -3587,22 +4168,22 @@ var developmentTeamArgument = (value) => {
|
|
|
3587
4168
|
const marketingVersion = options.config.iosVersion;
|
|
3588
4169
|
if (!marketingVersion)
|
|
3589
4170
|
throw new TypeError("iOS release builds require mobile.ios.version in absolutejs.config.ts.");
|
|
3590
|
-
const manifest = requireManifest(JSON.parse(await readFile6(
|
|
4171
|
+
const manifest = requireManifest(JSON.parse(await readFile6(join12(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
3591
4172
|
if (manifest.appId !== options.config.appId)
|
|
3592
4173
|
throw new TypeError("Embedded mobile manifest appId does not match mobile.appId.");
|
|
3593
|
-
const nativeDirectory =
|
|
4174
|
+
const nativeDirectory = join12(options.config.nativeProjectDirectory, "ios");
|
|
3594
4175
|
let buildNumber = requireBuildNumber(options.buildNumber);
|
|
3595
4176
|
if (options.prepareBuildNumber) {
|
|
3596
4177
|
const nativeFingerprint = await fingerprintAbsoluteIosNativeProject(nativeDirectory);
|
|
3597
4178
|
const buildIdentity = createHash4("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}\x00${marketingVersion}`).digest("hex");
|
|
3598
4179
|
buildNumber = requireBuildNumber(await options.prepareBuildNumber(buildIdentity));
|
|
3599
4180
|
}
|
|
3600
|
-
const stagingParent =
|
|
4181
|
+
const stagingParent = resolve8(options.projectRoot, ".absolutejs/mobile");
|
|
3601
4182
|
await mkdir4(stagingParent, { recursive: true });
|
|
3602
|
-
const staging = await mkdtemp3(
|
|
3603
|
-
const archivePath =
|
|
3604
|
-
const exportPath =
|
|
3605
|
-
const exportPlist =
|
|
4183
|
+
const staging = await mkdtemp3(join12(stagingParent, ".ios-build-"));
|
|
4184
|
+
const archivePath = join12(staging, "App.xcarchive");
|
|
4185
|
+
const exportPath = join12(staging, "export");
|
|
4186
|
+
const exportPlist = join12(staging, "ExportOptions.plist");
|
|
3606
4187
|
await mkdir4(exportPath, { recursive: true });
|
|
3607
4188
|
await writeFile4(exportPlist, exportOptions());
|
|
3608
4189
|
const run = options.run ?? defaultRun2;
|
|
@@ -3616,7 +4197,7 @@ var developmentTeamArgument = (value) => {
|
|
|
3616
4197
|
const archiveExit = await run([
|
|
3617
4198
|
"xcodebuild",
|
|
3618
4199
|
"-workspace",
|
|
3619
|
-
|
|
4200
|
+
join12(nativeDirectory, "App", "App.xcworkspace"),
|
|
3620
4201
|
"-scheme",
|
|
3621
4202
|
"App",
|
|
3622
4203
|
"-configuration",
|
|
@@ -3630,7 +4211,7 @@ var developmentTeamArgument = (value) => {
|
|
|
3630
4211
|
], { cwd: nativeDirectory });
|
|
3631
4212
|
if (archiveExit !== 0)
|
|
3632
4213
|
throw new TypeError("Xcode failed to archive the iOS app.");
|
|
3633
|
-
const archivedApp = await findByExtension(
|
|
4214
|
+
const archivedApp = await findByExtension(join12(archivePath, "Products", "Applications"), ".app");
|
|
3634
4215
|
const capture = options.capture ?? defaultCapture2;
|
|
3635
4216
|
const signed = archivedApp ? capture([
|
|
3636
4217
|
"codesign",
|
|
@@ -3704,7 +4285,7 @@ import {
|
|
|
3704
4285
|
writeFile as writeFile5
|
|
3705
4286
|
} from "fs/promises";
|
|
3706
4287
|
import { isIP as isIP2 } from "net";
|
|
3707
|
-
import { dirname as
|
|
4288
|
+
import { dirname as dirname7, isAbsolute as isAbsolute3, join as join13, relative as relative5, resolve as resolve9, sep as sep3 } from "path";
|
|
3708
4289
|
var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000, BOOT_POLL_MS = 1000, DEV_JOURNAL_FORMAT2 = 1, NATIVE_CACHE_FORMAT2 = 1, isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), pathExists4 = async (path) => {
|
|
3709
4290
|
try {
|
|
3710
4291
|
await access7(path);
|
|
@@ -3922,15 +4503,15 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
3922
4503
|
const leftPro = left.name.includes("Pro") ? 1 : 0;
|
|
3923
4504
|
return rightPro - leftPro;
|
|
3924
4505
|
})[0], journalPaths2 = (projectRoot) => {
|
|
3925
|
-
const root =
|
|
4506
|
+
const root = join13(projectRoot, ".absolutejs", "mobile", "ios-dev-session");
|
|
3926
4507
|
return {
|
|
3927
|
-
configBackup:
|
|
3928
|
-
infoBackup:
|
|
3929
|
-
journal:
|
|
4508
|
+
configBackup: join13(root, "capacitor-config.backup"),
|
|
4509
|
+
infoBackup: join13(root, "Info.plist.backup"),
|
|
4510
|
+
journal: join13(root, "journal.json"),
|
|
3930
4511
|
root
|
|
3931
4512
|
};
|
|
3932
|
-
}, nativeCachePath2 = (projectRoot) =>
|
|
3933
|
-
const value = relative5(
|
|
4513
|
+
}, nativeCachePath2 = (projectRoot) => join13(projectRoot, ".absolutejs", "mobile", "ios-native-cache.json"), isInside2 = (root, path) => {
|
|
4514
|
+
const value = relative5(resolve9(root), resolve9(path));
|
|
3934
4515
|
return value === "" || !value.startsWith(`..${sep3}`) && value !== ".." && !isAbsolute3(value);
|
|
3935
4516
|
}, parseJournal2 = (value) => {
|
|
3936
4517
|
if (!isRecord3(value) || value.format !== DEV_JOURNAL_FORMAT2)
|
|
@@ -3986,8 +4567,8 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
3986
4567
|
}, writeDevProjection = async (project, port, https, serverHost = "localhost") => {
|
|
3987
4568
|
const paths = journalPaths2(project.projectRoot);
|
|
3988
4569
|
await repairAbsoluteIosDevSession(project.projectRoot);
|
|
3989
|
-
const nativeConfigPath =
|
|
3990
|
-
const infoPath =
|
|
4570
|
+
const nativeConfigPath = join13(project.nativeDirectory, "App", "App", "capacitor.config.json");
|
|
4571
|
+
const infoPath = join13(project.nativeDirectory, "App", "App", "Info.plist");
|
|
3991
4572
|
const [configSource, infoSource] = await Promise.all([
|
|
3992
4573
|
readFile7(nativeConfigPath, "utf8"),
|
|
3993
4574
|
readFile7(infoPath, "utf8")
|
|
@@ -4043,7 +4624,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4043
4624
|
}, readNativeCache2 = (projectRoot) => readFile7(nativeCachePath2(projectRoot), "utf8").then((source) => parseNativeCache2(JSON.parse(source))).catch(() => null), writeNativeCache2 = async (projectRoot, cache) => {
|
|
4044
4625
|
const destination = nativeCachePath2(projectRoot);
|
|
4045
4626
|
const temporary = `${destination}.${process.pid}.${randomUUID3()}.tmp`;
|
|
4046
|
-
await mkdir5(
|
|
4627
|
+
await mkdir5(dirname7(destination), { recursive: true });
|
|
4047
4628
|
try {
|
|
4048
4629
|
await writeFile5(temporary, `${JSON.stringify(cache, null, "\t")}
|
|
4049
4630
|
`, {
|
|
@@ -4148,12 +4729,12 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4148
4729
|
]);
|
|
4149
4730
|
return result.exitCode === 0 && result.stdout.includes(project.config.appId);
|
|
4150
4731
|
}, buildIosDebugApp = async (project, udid, fingerprint, run, signal) => {
|
|
4151
|
-
const derivedDataPath =
|
|
4732
|
+
const derivedDataPath = join13(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
|
|
4152
4733
|
await mkdir5(derivedDataPath, { recursive: true });
|
|
4153
4734
|
await requireSuccess2([
|
|
4154
4735
|
project.xcodebuild,
|
|
4155
4736
|
"-workspace",
|
|
4156
|
-
|
|
4737
|
+
join13(project.nativeDirectory, "App", "App.xcworkspace"),
|
|
4157
4738
|
"-scheme",
|
|
4158
4739
|
"App",
|
|
4159
4740
|
"-configuration",
|
|
@@ -4164,17 +4745,17 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4164
4745
|
derivedDataPath,
|
|
4165
4746
|
"build"
|
|
4166
4747
|
], "iOS simulator build", run, { cwd: project.nativeDirectory, signal });
|
|
4167
|
-
const appPath =
|
|
4748
|
+
const appPath = join13(derivedDataPath, "Build", "Products", "Debug-iphonesimulator", "App.app");
|
|
4168
4749
|
if (!await pathExists4(appPath))
|
|
4169
4750
|
throw new Error(`Xcode did not produce the simulator app at ${appPath}.`);
|
|
4170
4751
|
return appPath;
|
|
4171
4752
|
}, buildPhysicalIosDebugApp = async (project, identifier, run, signal) => {
|
|
4172
|
-
const derivedDataPath =
|
|
4753
|
+
const derivedDataPath = join13(project.projectRoot, ".absolutejs", "mobile", "ios-derived-data", createHash5("sha256").update(project.config.appId).digest("hex").slice(0, 16));
|
|
4173
4754
|
await mkdir5(derivedDataPath, { recursive: true });
|
|
4174
4755
|
await requireSuccess2([
|
|
4175
4756
|
project.xcodebuild,
|
|
4176
4757
|
"-workspace",
|
|
4177
|
-
|
|
4758
|
+
join13(project.nativeDirectory, "App", "App.xcworkspace"),
|
|
4178
4759
|
"-scheme",
|
|
4179
4760
|
"App",
|
|
4180
4761
|
"-configuration",
|
|
@@ -4186,7 +4767,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4186
4767
|
"-allowProvisioningUpdates",
|
|
4187
4768
|
"build"
|
|
4188
4769
|
], "iOS physical-device build (configure automatic signing and a Development Team in Xcode if this is the first run)", run, { cwd: project.nativeDirectory, signal });
|
|
4189
|
-
const appPath =
|
|
4770
|
+
const appPath = join13(derivedDataPath, "Build", "Products", "Debug-iphoneos", "App.app");
|
|
4190
4771
|
if (!await pathExists4(appPath))
|
|
4191
4772
|
throw new Error(`Xcode did not produce the physical-device app at ${appPath}.`);
|
|
4192
4773
|
return appPath;
|
|
@@ -4297,7 +4878,7 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4297
4878
|
if (detectAbsoluteMobileHost() !== "macos")
|
|
4298
4879
|
throw new Error("iOS development requires macOS and Xcode.");
|
|
4299
4880
|
const target = options.target ?? "simulator";
|
|
4300
|
-
const projectRoot =
|
|
4881
|
+
const projectRoot = resolve9(options.projectRoot);
|
|
4301
4882
|
const checks = await inspectAbsoluteMobileToolchain({ host: "macos" });
|
|
4302
4883
|
const failed = checks.filter((check) => check.platform === "ios" && !(target === "device" && check.id === "ios.runtime") && (check.status === "fail" || check.status === "warn"));
|
|
4303
4884
|
if (failed.length > 0)
|
|
@@ -4306,16 +4887,16 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4306
4887
|
const xcodebuild = checks.find((check) => check.id === "ios.xcodebuild")?.path;
|
|
4307
4888
|
if (!xcrun || !xcodebuild)
|
|
4308
4889
|
throw new Error("Xcode tools disappeared after readiness checks.");
|
|
4309
|
-
const cap =
|
|
4890
|
+
const cap = join13(projectRoot, "node_modules", ".bin", "cap");
|
|
4310
4891
|
if (!await pathExists4(cap))
|
|
4311
4892
|
throw new Error("Capacitor CLI is not installed. Run absolute mobile init first.");
|
|
4312
4893
|
await writeAbsoluteCapacitorConfig(config, { projectRoot });
|
|
4313
4894
|
await mkdir5(config.bundleDirectory, { recursive: true });
|
|
4314
|
-
const placeholder =
|
|
4895
|
+
const placeholder = join13(config.bundleDirectory, "index.html");
|
|
4315
4896
|
if (!await pathExists4(placeholder))
|
|
4316
4897
|
await writeFile5(placeholder, `<!doctype html><title>AbsoluteJS mobile development</title>
|
|
4317
4898
|
`);
|
|
4318
|
-
const nativeDirectory =
|
|
4899
|
+
const nativeDirectory = join13(config.nativeProjectDirectory, "ios");
|
|
4319
4900
|
if (!await pathExists4(nativeDirectory)) {
|
|
4320
4901
|
if (!options.createNativeProject)
|
|
4321
4902
|
throw new Error("iOS native project has not been created.");
|
|
@@ -4540,10 +5121,10 @@ var ABSOLUTE_IOS_SIMULATOR_NAME = "AbsoluteJS iPhone", BOOT_TIMEOUT_MS = 180000,
|
|
|
4540
5121
|
screenshot: async (destination) => {
|
|
4541
5122
|
if (deviceIdentifier)
|
|
4542
5123
|
throw new Error("Physical iOS screenshots are captured in Xcode Device Hub; the CLI never records a device screen automatically.");
|
|
4543
|
-
const resolved =
|
|
5124
|
+
const resolved = resolve9(project.projectRoot, destination);
|
|
4544
5125
|
if (!isInside2(project.projectRoot, resolved))
|
|
4545
5126
|
throw new Error("iOS screenshot destination must remain inside the project.");
|
|
4546
|
-
await mkdir5(
|
|
5127
|
+
await mkdir5(dirname7(resolved), { recursive: true });
|
|
4547
5128
|
await requireSuccess2([
|
|
4548
5129
|
project.xcrun,
|
|
4549
5130
|
"simctl",
|
|
@@ -4602,15 +5183,15 @@ import { chmod, mkdir as mkdir6, readFile as readFile8, rename as rename6, write
|
|
|
4602
5183
|
import { homedir as homedir4 } from "os";
|
|
4603
5184
|
import { isIP as isIP3 } from "net";
|
|
4604
5185
|
import {
|
|
4605
|
-
dirname as
|
|
5186
|
+
dirname as dirname8,
|
|
4606
5187
|
isAbsolute as isAbsolute4,
|
|
4607
|
-
join as
|
|
5188
|
+
join as join14,
|
|
4608
5189
|
posix,
|
|
4609
5190
|
relative as relative6,
|
|
4610
5191
|
resolve as resolvePath,
|
|
4611
5192
|
sep as sep4
|
|
4612
5193
|
} from "path";
|
|
4613
|
-
var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000, PROFILE_NAME, SSH_DESTINATION, defaultProfilePath = () =>
|
|
5194
|
+
var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TIMEOUT_MS = 2000, PROFILE_NAME, SSH_DESTINATION, defaultProfilePath = () => join14(homedir4(), ".absolutejs", "mobile", "remote-macs.json"), emptyStore = () => ({
|
|
4614
5195
|
format: PROFILE_FORMAT,
|
|
4615
5196
|
profiles: {}
|
|
4616
5197
|
}), loadStore = async (path = defaultProfilePath()) => {
|
|
@@ -4631,7 +5212,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4631
5212
|
throw error;
|
|
4632
5213
|
}
|
|
4633
5214
|
}, saveStore = async (store, path = defaultProfilePath()) => {
|
|
4634
|
-
await mkdir6(
|
|
5215
|
+
await mkdir6(dirname8(path), { recursive: true });
|
|
4635
5216
|
const temporary = `${path}.${randomUUID4()}.tmp`;
|
|
4636
5217
|
await writeFile6(temporary, `${JSON.stringify(store, null, 2)}
|
|
4637
5218
|
`, {
|
|
@@ -4733,10 +5314,10 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4733
5314
|
"/bin/sh -lc",
|
|
4734
5315
|
shellQuote(script)
|
|
4735
5316
|
]);
|
|
4736
|
-
const
|
|
4737
|
-
if (isIP3(
|
|
5317
|
+
const host2 = requireRemoteSuccess(result, "Remote Mac LAN address discovery").trim();
|
|
5318
|
+
if (isIP3(host2) === 0)
|
|
4738
5319
|
throw new Error("The Remote Mac did not report a device-reachable LAN address.");
|
|
4739
|
-
return
|
|
5320
|
+
return host2;
|
|
4740
5321
|
}, listAbsoluteRemoteMacProfiles = async (profilePath) => {
|
|
4741
5322
|
const store = await loadStore(profilePath);
|
|
4742
5323
|
return {
|
|
@@ -4786,9 +5367,9 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4786
5367
|
throw new TypeError("Remote Expo execution requires mobile.engine: expo.");
|
|
4787
5368
|
return createAbsoluteRemoteIosDevProject(config, projectRoot, profile);
|
|
4788
5369
|
}, createAbsoluteRemoteIosDevProject = (config, projectRoot, profile) => ({
|
|
4789
|
-
cap:
|
|
5370
|
+
cap: join14(resolvePath(projectRoot), "node_modules", ".bin", "cap"),
|
|
4790
5371
|
config,
|
|
4791
|
-
nativeDirectory:
|
|
5372
|
+
nativeDirectory: join14(config.nativeProjectDirectory, "ios"),
|
|
4792
5373
|
profile,
|
|
4793
5374
|
projectRoot: resolvePath(projectRoot),
|
|
4794
5375
|
remote: true,
|
|
@@ -4835,8 +5416,8 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4835
5416
|
return { ...artifact, remotePath, uploaded: true };
|
|
4836
5417
|
}, materializeAbsoluteRemoteMacAgent = async (projectRoot) => {
|
|
4837
5418
|
const shippedCandidates = [
|
|
4838
|
-
|
|
4839
|
-
|
|
5419
|
+
join14(import.meta.dir, "remoteMacAgentEntry.js"),
|
|
5420
|
+
join14(import.meta.dir, "..", "mobile", "remoteMacAgentEntry.js")
|
|
4840
5421
|
];
|
|
4841
5422
|
let path;
|
|
4842
5423
|
for (const candidate of shippedCandidates) {
|
|
@@ -4847,13 +5428,13 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4847
5428
|
}
|
|
4848
5429
|
if (!path) {
|
|
4849
5430
|
const sourceCandidates = [
|
|
4850
|
-
|
|
4851
|
-
|
|
5431
|
+
join14(import.meta.dir, "remoteMacAgentEntry.ts"),
|
|
5432
|
+
join14(import.meta.dir, "..", "..", "src", "mobile", "remoteMacAgentEntry.ts")
|
|
4852
5433
|
];
|
|
4853
5434
|
const source = await sourceCandidates.reduce(async (found, candidate) => await found ?? (await Bun.file(candidate).exists() ? candidate : undefined), Promise.resolve(undefined));
|
|
4854
5435
|
if (!source)
|
|
4855
5436
|
throw new Error("The AbsoluteJS installation does not contain its remote Mac agent artifact.");
|
|
4856
|
-
const outdir =
|
|
5437
|
+
const outdir = join14(resolvePath(projectRoot), ".absolutejs", "mobile", "remote-agent");
|
|
4857
5438
|
await mkdir6(outdir, { recursive: true });
|
|
4858
5439
|
const result = await Bun.build({
|
|
4859
5440
|
entrypoints: [source],
|
|
@@ -4863,7 +5444,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
4863
5444
|
});
|
|
4864
5445
|
if (!result.success)
|
|
4865
5446
|
throw new AggregateError(result.logs, "Failed to build the AbsoluteJS remote Mac agent.");
|
|
4866
|
-
path =
|
|
5447
|
+
path = join14(outdir, "remoteMacAgentEntry.js");
|
|
4867
5448
|
}
|
|
4868
5449
|
const bytes = await Bun.file(path).arrayBuffer();
|
|
4869
5450
|
const sha256 = createHash6("sha256").update(new Uint8Array(bytes)).digest("hex");
|
|
@@ -5084,8 +5665,8 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
5084
5665
|
const pending = new Map;
|
|
5085
5666
|
let resolveReady;
|
|
5086
5667
|
let rejectReady;
|
|
5087
|
-
const readyPromise = new Promise((
|
|
5088
|
-
resolveReady =
|
|
5668
|
+
const readyPromise = new Promise((resolve10, reject) => {
|
|
5669
|
+
resolveReady = resolve10;
|
|
5089
5670
|
rejectReady = reject;
|
|
5090
5671
|
});
|
|
5091
5672
|
const handleEvent = (event) => {
|
|
@@ -5186,7 +5767,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
5186
5767
|
options.log?.(`Remote Mac connected (${options.project.profile.name}); agent ${agent.uploaded ? "uploaded" : "cache hit"}, project synced, and ${expo ? "Expo " : ""}iOS ready in ${totalDuration.toFixed(2)}ms.`);
|
|
5187
5768
|
const request = (commandName) => {
|
|
5188
5769
|
const id = randomUUID4();
|
|
5189
|
-
const response = new Promise((
|
|
5770
|
+
const response = new Promise((resolve10, reject) => pending.set(id, { reject, resolve: resolve10 }));
|
|
5190
5771
|
process2.stdin.write(`${JSON.stringify({ command: commandName, id, v: ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION })}
|
|
5191
5772
|
`);
|
|
5192
5773
|
const flush = async () => {
|
|
@@ -5206,7 +5787,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
5206
5787
|
if (closed)
|
|
5207
5788
|
return;
|
|
5208
5789
|
closed = true;
|
|
5209
|
-
const timeout = () => new Promise((
|
|
5790
|
+
const timeout = () => new Promise((resolve10) => setTimeout(() => resolve10("timeout"), REMOTE_SESSION_CLOSE_TIMEOUT_MS));
|
|
5210
5791
|
await Promise.race([
|
|
5211
5792
|
request("close").catch(() => {
|
|
5212
5793
|
return;
|
|
@@ -5257,7 +5838,7 @@ var PROFILE_FORMAT = 1, REMOTE_STDIN_FLUSH_ATTEMPTS = 3, REMOTE_SESSION_CLOSE_TI
|
|
|
5257
5838
|
const targetRelative = relative6(options.project.projectRoot, target);
|
|
5258
5839
|
if (targetRelative.startsWith("..") || isAbsolute4(targetRelative))
|
|
5259
5840
|
throw new Error("iOS screenshot must remain inside the project.");
|
|
5260
|
-
await mkdir6(
|
|
5841
|
+
await mkdir6(dirname8(target), { recursive: true });
|
|
5261
5842
|
await writeFile6(target, Buffer.from(result.data, "base64"));
|
|
5262
5843
|
return target;
|
|
5263
5844
|
},
|
|
@@ -5296,32 +5877,32 @@ import {
|
|
|
5296
5877
|
copyFileSync,
|
|
5297
5878
|
existsSync as existsSync4,
|
|
5298
5879
|
mkdirSync as mkdirSync4,
|
|
5299
|
-
readFileSync as
|
|
5880
|
+
readFileSync as readFileSync8,
|
|
5300
5881
|
rmSync
|
|
5301
5882
|
} from "fs";
|
|
5302
5883
|
import { X509Certificate as X509Certificate2 } from "crypto";
|
|
5303
5884
|
import { isIP as isIP4 } from "net";
|
|
5304
5885
|
import { platform as platform2 } from "os";
|
|
5305
|
-
import { join as
|
|
5886
|
+
import { join as join15 } from "path";
|
|
5306
5887
|
var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE_HOSTS, CERTIFICATE_HOSTNAME_PATTERN, devLog = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[36m[dev]\x1B[0m ${msg}`), devWarn = (msg) => console.log(`\x1B[2m${new Date().toLocaleTimeString()}\x1B[0m \x1B[33m[dev]\x1B[0m \x1B[33m${msg}\x1B[0m`), certFilesExist = () => existsSync4(CERT_PATH) && existsSync4(KEY_PATH), normalizeDevCertificateHosts = (hosts = []) => {
|
|
5307
5888
|
const normalized = new Set(DEFAULT_CERTIFICATE_HOSTS);
|
|
5308
|
-
for (const
|
|
5309
|
-
const value =
|
|
5889
|
+
for (const host2 of hosts) {
|
|
5890
|
+
const value = host2.trim().toLowerCase();
|
|
5310
5891
|
if (!value || value === "0.0.0.0" || value === "::")
|
|
5311
5892
|
continue;
|
|
5312
5893
|
if (isIP4(value) === 0 && !CERTIFICATE_HOSTNAME_PATTERN.test(value)) {
|
|
5313
|
-
throw new TypeError(`Invalid development certificate host: ${
|
|
5894
|
+
throw new TypeError(`Invalid development certificate host: ${host2}`);
|
|
5314
5895
|
}
|
|
5315
5896
|
normalized.add(value);
|
|
5316
5897
|
}
|
|
5317
5898
|
return [...normalized];
|
|
5318
5899
|
}, certificateIsUsable = (hosts) => {
|
|
5319
5900
|
try {
|
|
5320
|
-
const certPem =
|
|
5901
|
+
const certPem = readFileSync8(CERT_PATH, "utf-8");
|
|
5321
5902
|
const certificate = new X509Certificate2(certPem);
|
|
5322
5903
|
if (new Date(certificate.validTo).getTime() <= Date.now())
|
|
5323
5904
|
return false;
|
|
5324
|
-
return normalizeDevCertificateHosts(hosts).every((
|
|
5905
|
+
return normalizeDevCertificateHosts(hosts).every((host2) => isIP4(host2) ? certificate.checkIP(host2) !== undefined : certificate.checkHost(host2) !== undefined);
|
|
5325
5906
|
} catch {
|
|
5326
5907
|
return false;
|
|
5327
5908
|
}
|
|
@@ -5349,7 +5930,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5349
5930
|
throw new Error(`mkcert failed: ${err}`);
|
|
5350
5931
|
}
|
|
5351
5932
|
}, generateSelfSigned = (hosts = []) => {
|
|
5352
|
-
const subjectAlternativeNames = normalizeDevCertificateHosts(hosts).map((
|
|
5933
|
+
const subjectAlternativeNames = normalizeDevCertificateHosts(hosts).map((host2) => `${isIP4(host2) ? "IP" : "DNS"}:${host2}`).join(",");
|
|
5353
5934
|
const proc = Bun.spawnSync([
|
|
5354
5935
|
"openssl",
|
|
5355
5936
|
"req",
|
|
@@ -5402,8 +5983,8 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5402
5983
|
return null;
|
|
5403
5984
|
try {
|
|
5404
5985
|
return {
|
|
5405
|
-
cert:
|
|
5406
|
-
key:
|
|
5986
|
+
cert: readFileSync8(paths.cert, "utf-8"),
|
|
5987
|
+
key: readFileSync8(paths.key, "utf-8")
|
|
5407
5988
|
};
|
|
5408
5989
|
} catch {
|
|
5409
5990
|
return null;
|
|
@@ -5499,7 +6080,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5499
6080
|
if (platform2() !== "linux")
|
|
5500
6081
|
return false;
|
|
5501
6082
|
try {
|
|
5502
|
-
return /microsoft|wsl/i.test(
|
|
6083
|
+
return /microsoft|wsl/i.test(readFileSync8("/proc/version", "utf-8"));
|
|
5503
6084
|
} catch {
|
|
5504
6085
|
return false;
|
|
5505
6086
|
}
|
|
@@ -5515,7 +6096,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5515
6096
|
}
|
|
5516
6097
|
}, mkcertCaRoot = () => runCapture(["mkcert", "-CAROOT"]), getDevCertificateAuthorityPath = () => {
|
|
5517
6098
|
const caRoot = hasMkcert() ? mkcertCaRoot() : null;
|
|
5518
|
-
const rootCertificate = caRoot ?
|
|
6099
|
+
const rootCertificate = caRoot ? join15(caRoot, "rootCA.pem") : null;
|
|
5519
6100
|
if (rootCertificate && existsSync4(rootCertificate))
|
|
5520
6101
|
return rootCertificate;
|
|
5521
6102
|
if (certFilesExist())
|
|
@@ -5530,13 +6111,13 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5530
6111
|
const caRoot = mkcertCaRoot();
|
|
5531
6112
|
if (!caRoot)
|
|
5532
6113
|
return false;
|
|
5533
|
-
const rootCa =
|
|
6114
|
+
const rootCa = join15(caRoot, "rootCA.pem");
|
|
5534
6115
|
if (!existsSync4(rootCa))
|
|
5535
6116
|
return false;
|
|
5536
6117
|
const winTemp = windowsTempDir();
|
|
5537
6118
|
if (!winTemp)
|
|
5538
6119
|
return false;
|
|
5539
|
-
const staged =
|
|
6120
|
+
const staged = join15(winTemp, "absolutejs-mkcert-rootCA.crt");
|
|
5540
6121
|
try {
|
|
5541
6122
|
copyFileSync(rootCa, staged);
|
|
5542
6123
|
} catch {
|
|
@@ -5572,7 +6153,7 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5572
6153
|
devLog("Trusted the local CA in the Windows store \u2014 Chrome/Edge on Windows now accept dev HTTPS");
|
|
5573
6154
|
} else {
|
|
5574
6155
|
const caRoot = mkcertCaRoot();
|
|
5575
|
-
const hint = caRoot ? toWindowsPath(
|
|
6156
|
+
const hint = caRoot ? toWindowsPath(join15(caRoot, "rootCA.pem")) : null;
|
|
5576
6157
|
devWarn("Could not auto-trust the local CA on Windows; Windows browsers may warn.");
|
|
5577
6158
|
if (hint) {
|
|
5578
6159
|
console.log(` Run in PowerShell: Import-Certificate -FilePath "${hint}" -CertStoreLocation Cert:\\CurrentUser\\Root`);
|
|
@@ -5588,9 +6169,9 @@ var CERT_DIR, CERT_PATH, KEY_PATH, CERT_VALIDITY_DAYS = 365, DEFAULT_CERTIFICATE
|
|
|
5588
6169
|
return true;
|
|
5589
6170
|
};
|
|
5590
6171
|
var init_devCert = __esm(() => {
|
|
5591
|
-
CERT_DIR =
|
|
5592
|
-
CERT_PATH =
|
|
5593
|
-
KEY_PATH =
|
|
6172
|
+
CERT_DIR = join15(process.cwd(), ".absolutejs");
|
|
6173
|
+
CERT_PATH = join15(CERT_DIR, "cert.pem");
|
|
6174
|
+
KEY_PATH = join15(CERT_DIR, "key.pem");
|
|
5594
6175
|
DEFAULT_CERTIFICATE_HOSTS = ["localhost", "127.0.0.1", "::1"];
|
|
5595
6176
|
CERTIFICATE_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])?))*$/u;
|
|
5596
6177
|
});
|
|
@@ -5607,7 +6188,7 @@ __export(exports_eslintChunked, {
|
|
|
5607
6188
|
upstreamRef: () => upstreamRef
|
|
5608
6189
|
});
|
|
5609
6190
|
import { existsSync as existsSync6 } from "fs";
|
|
5610
|
-
import { relative as relative7, resolve as
|
|
6191
|
+
import { relative as relative7, resolve as resolve10 } from "path";
|
|
5611
6192
|
var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAULT_REPORT = ".absolutejs/lint-report.txt", CHILD_HEAP_MB = 4096, DJB2_SEED = 5381, DJB2_MULTIPLIER = 33, MS_PER_SECOND = 1000, SUMMARY_RULE_WIDTH = 60, SUMMARY_COUNT_PAD = 5, PORCELAIN_STATUS_WIDTH = 3, RENAME_ARROW = " -> ", ASCII_ESC = 27, LINTABLE_EXTENSIONS, ANSI_COLOR, stripAnsi = (text) => text.replace(ANSI_COLOR, ""), shardOf = (path, shards) => [...path].reduce((accumulator, character) => (Math.imul(accumulator, DJB2_MULTIPLIER) ^ character.charCodeAt(0)) >>> 0, DJB2_SEED) % shards, gitLines = (cmd, cwd) => Bun.spawnSync(cmd, { cwd }).stdout.toString().split(`
|
|
5612
6193
|
`).map((line) => line.trimEnd()).filter(Boolean), applyChangedBase = (parsed, base) => {
|
|
5613
6194
|
parsed.changedOnly = true;
|
|
@@ -5619,7 +6200,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
|
|
|
5619
6200
|
}, matchesAnyGlob = (file, globs) => globs.some((pattern) => new Bun.Glob(pattern).match(file)), resolveLintSet = (parsed, cwd) => {
|
|
5620
6201
|
const visible = gitVisibleFiles(cwd);
|
|
5621
6202
|
const matched = parsed.globs.length === 0 ? visible.filter((file) => LINTABLE_EXTENSIONS.test(file)) : visible.filter((file) => matchesAnyGlob(file, parsed.globs));
|
|
5622
|
-
return matched.filter((file) => existsSync6(
|
|
6203
|
+
return matched.filter((file) => existsSync6(resolve10(cwd, file))).sort();
|
|
5623
6204
|
}, resolveLintTargets = (args, cwd = process.cwd()) => resolveLintSet(parseChunkedArgs(args), cwd), buildShardChunks = (files, shards, chunkSize) => {
|
|
5624
6205
|
const shardFiles = Array.from({ length: shards }, () => []);
|
|
5625
6206
|
for (const file of files)
|
|
@@ -5641,7 +6222,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
|
|
|
5641
6222
|
"content"
|
|
5642
6223
|
];
|
|
5643
6224
|
const proc = Bun.spawn([
|
|
5644
|
-
|
|
6225
|
+
resolve10(cwd, "node_modules/.bin/eslint"),
|
|
5645
6226
|
"--color",
|
|
5646
6227
|
...hasMaxWarnings ? [] : ["--max-warnings", "0"],
|
|
5647
6228
|
...cacheArgs,
|
|
@@ -5688,7 +6269,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
|
|
|
5688
6269
|
const fingerprint = createEslintCacheFingerprint(cwd);
|
|
5689
6270
|
for (let shard = 0;shard < parsed.shards; shard++)
|
|
5690
6271
|
prepareEslintCache({
|
|
5691
|
-
cacheLocation: relative7(cwd,
|
|
6272
|
+
cacheLocation: relative7(cwd, resolve10(cwd, `${cachePrefix}${shard}`)),
|
|
5692
6273
|
cwd,
|
|
5693
6274
|
fingerprint
|
|
5694
6275
|
});
|
|
@@ -5729,7 +6310,7 @@ var DEFAULT_CHUNK_SIZE = 20, DEFAULT_SHARDS = 4, DEFAULT_CONCURRENCY = 2, DEFAUL
|
|
|
5729
6310
|
const header = `eslint report \u2014 ${files.length} files, ${totalChunks} chunks, ${elapsed}s
|
|
5730
6311
|
${"=".repeat(SUMMARY_RULE_WIDTH)}
|
|
5731
6312
|
`;
|
|
5732
|
-
await Bun.write(
|
|
6313
|
+
await Bun.write(resolve10(cwd, parsed.outFile), header + report + summary);
|
|
5733
6314
|
console.log(summary);
|
|
5734
6315
|
console.log(`Full report written to ${parsed.outFile}`);
|
|
5735
6316
|
if (failedChunks > 0) {
|
|
@@ -5818,12 +6399,12 @@ import { createHash as createHash7 } from "crypto";
|
|
|
5818
6399
|
import {
|
|
5819
6400
|
existsSync as existsSync7,
|
|
5820
6401
|
mkdirSync as mkdirSync5,
|
|
5821
|
-
readFileSync as
|
|
6402
|
+
readFileSync as readFileSync10,
|
|
5822
6403
|
renameSync,
|
|
5823
6404
|
rmSync as rmSync3,
|
|
5824
6405
|
writeFileSync as writeFileSync5
|
|
5825
6406
|
} from "fs";
|
|
5826
|
-
import { dirname as
|
|
6407
|
+
import { dirname as dirname9, relative as relative8, resolve as resolve11 } from "path";
|
|
5827
6408
|
var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION = "1", CACHE_FINGERPRINT_SUFFIX = ".fingerprint", flagValue = (args, flag) => {
|
|
5828
6409
|
const assignment = args.find((arg) => arg.startsWith(`${flag}=`));
|
|
5829
6410
|
if (assignment)
|
|
@@ -5847,20 +6428,20 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5847
6428
|
return false;
|
|
5848
6429
|
}, findEslintConfigPath = (cwd = process.cwd()) => {
|
|
5849
6430
|
for (const name of CONFIG_CANDIDATES) {
|
|
5850
|
-
const candidate =
|
|
6431
|
+
const candidate = resolve11(cwd, name);
|
|
5851
6432
|
if (existsSync7(candidate))
|
|
5852
6433
|
return candidate;
|
|
5853
6434
|
}
|
|
5854
6435
|
return null;
|
|
5855
6436
|
}, fingerprintLocation = (cacheLocation, cwd) => {
|
|
5856
|
-
const absolute =
|
|
5857
|
-
return /[\\/]$/.test(cacheLocation) ?
|
|
6437
|
+
const absolute = resolve11(cwd, cacheLocation);
|
|
6438
|
+
return /[\\/]$/.test(cacheLocation) ? resolve11(absolute, CACHE_FINGERPRINT_SUFFIX.slice(1)) : `${absolute}${CACHE_FINGERPRINT_SUFFIX}`;
|
|
5858
6439
|
}, addFileToFingerprint = (hash, path, label) => {
|
|
5859
6440
|
if (!existsSync7(path))
|
|
5860
6441
|
return;
|
|
5861
6442
|
hash.update(label);
|
|
5862
6443
|
hash.update("\x00");
|
|
5863
|
-
hash.update(
|
|
6444
|
+
hash.update(readFileSync10(path));
|
|
5864
6445
|
hash.update("\x00");
|
|
5865
6446
|
}, packageNameFor = (specifier) => {
|
|
5866
6447
|
if (specifier.startsWith("@"))
|
|
@@ -5870,7 +6451,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5870
6451
|
}, configPackageNames = (configPath2) => {
|
|
5871
6452
|
if (!configPath2)
|
|
5872
6453
|
return [];
|
|
5873
|
-
const source =
|
|
6454
|
+
const source = readFileSync10(configPath2, "utf-8");
|
|
5874
6455
|
const names = new Set;
|
|
5875
6456
|
for (const match of source.matchAll(/(?:from\s+|import\s*(?:\(\s*)?|require\s*\(\s*)(['"])([^'".][^'"]*)\1/g)) {
|
|
5876
6457
|
const [, , specifier] = match;
|
|
@@ -5889,11 +6470,11 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5889
6470
|
return Object.keys(value);
|
|
5890
6471
|
});
|
|
5891
6472
|
}, lintDependencyNames = (cwd, configPath2) => {
|
|
5892
|
-
const manifestPath =
|
|
6473
|
+
const manifestPath = resolve11(cwd, "package.json");
|
|
5893
6474
|
if (!existsSync7(manifestPath))
|
|
5894
6475
|
return configPackageNames(configPath2);
|
|
5895
6476
|
try {
|
|
5896
|
-
const manifest = JSON.parse(
|
|
6477
|
+
const manifest = JSON.parse(readFileSync10(manifestPath, "utf-8"));
|
|
5897
6478
|
const lintPackages = manifestDependencyNames(manifest).filter((name) => /eslint|typescript/.test(name));
|
|
5898
6479
|
return [
|
|
5899
6480
|
...new Set([...lintPackages, ...configPackageNames(configPath2)])
|
|
@@ -5904,10 +6485,10 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5904
6485
|
}, findInstalledManifest = (cwd, dependency) => {
|
|
5905
6486
|
let directory = cwd;
|
|
5906
6487
|
while (true) {
|
|
5907
|
-
const candidate =
|
|
6488
|
+
const candidate = resolve11(directory, "node_modules", dependency, "package.json");
|
|
5908
6489
|
if (existsSync7(candidate))
|
|
5909
6490
|
return candidate;
|
|
5910
|
-
const parent =
|
|
6491
|
+
const parent = dirname9(directory);
|
|
5911
6492
|
if (parent === directory)
|
|
5912
6493
|
return null;
|
|
5913
6494
|
directory = parent;
|
|
@@ -5930,17 +6511,17 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
5930
6511
|
addFileToFingerprint(hash, configPath2, relative8(cwd, configPath2));
|
|
5931
6512
|
return hash.digest("hex");
|
|
5932
6513
|
}, writeFingerprint = (path, fingerprint) => {
|
|
5933
|
-
mkdirSync5(
|
|
6514
|
+
mkdirSync5(dirname9(path), { recursive: true });
|
|
5934
6515
|
const temporary = `${path}.${process.pid}.tmp`;
|
|
5935
6516
|
writeFileSync5(temporary, `${fingerprint}
|
|
5936
6517
|
`);
|
|
5937
6518
|
renameSync(temporary, path);
|
|
5938
6519
|
}, prepareEslintCache = (options) => {
|
|
5939
6520
|
const cwd = options.cwd ?? process.cwd();
|
|
5940
|
-
const cachePath =
|
|
6521
|
+
const cachePath = resolve11(cwd, options.cacheLocation);
|
|
5941
6522
|
const metadataPath = fingerprintLocation(options.cacheLocation, cwd);
|
|
5942
6523
|
const fingerprint = options.fingerprint ?? createEslintCacheFingerprint(cwd);
|
|
5943
|
-
const prior = existsSync7(metadataPath) ?
|
|
6524
|
+
const prior = existsSync7(metadataPath) ? readFileSync10(metadataPath, "utf-8").trim() : null;
|
|
5944
6525
|
if (prior === fingerprint)
|
|
5945
6526
|
return false;
|
|
5946
6527
|
rmSync3(cachePath, { force: true, recursive: true });
|
|
@@ -6028,7 +6609,7 @@ var DEFAULT_CACHE_LOCATION = ".absolutejs/eslint-cache", CACHE_CONTRACT_VERSION
|
|
|
6028
6609
|
return;
|
|
6029
6610
|
let source;
|
|
6030
6611
|
try {
|
|
6031
|
-
source =
|
|
6612
|
+
source = readFileSync10(configPath2, "utf-8");
|
|
6032
6613
|
} catch {
|
|
6033
6614
|
return;
|
|
6034
6615
|
}
|
|
@@ -6067,7 +6648,7 @@ Detected at: ${configPath2}${reset}`);
|
|
|
6067
6648
|
return `${minutes}m ${seconds}s`;
|
|
6068
6649
|
}, handleClearCache = (cacheLocation, cwd = process.cwd()) => {
|
|
6069
6650
|
try {
|
|
6070
|
-
const cachePath =
|
|
6651
|
+
const cachePath = resolve11(cwd, cacheLocation);
|
|
6071
6652
|
const metadataPath = fingerprintLocation(cacheLocation, cwd);
|
|
6072
6653
|
rmSync3(cachePath, { force: true, recursive: true });
|
|
6073
6654
|
rmSync3(metadataPath, { force: true, recursive: true });
|
|
@@ -6096,7 +6677,7 @@ Detected at: ${configPath2}${reset}`);
|
|
|
6096
6677
|
return;
|
|
6097
6678
|
}
|
|
6098
6679
|
if (args.includes("--chunked")) {
|
|
6099
|
-
if (!existsSync7(
|
|
6680
|
+
if (!existsSync7(resolve11("node_modules", ".bin", "eslint"))) {
|
|
6100
6681
|
console.error("\x1B[31m\u2717\x1B[0m ESLint is not installed in this project. Add it (and a flat `eslint.config.*`): bun add -d eslint");
|
|
6101
6682
|
process.exit(1);
|
|
6102
6683
|
}
|
|
@@ -6104,7 +6685,7 @@ Detected at: ${configPath2}${reset}`);
|
|
|
6104
6685
|
await eslintChunked2(args);
|
|
6105
6686
|
return;
|
|
6106
6687
|
}
|
|
6107
|
-
if (!existsSync7(
|
|
6688
|
+
if (!existsSync7(resolve11("node_modules", ".bin", "eslint"))) {
|
|
6108
6689
|
console.error("\x1B[31m\u2717\x1B[0m ESLint is not installed in this project. Add it (and a flat `eslint.config.*`): bun add -d eslint");
|
|
6109
6690
|
process.exit(1);
|
|
6110
6691
|
}
|
|
@@ -6281,21 +6862,21 @@ var stripStringsAndComments = (source) => {
|
|
|
6281
6862
|
};
|
|
6282
6863
|
|
|
6283
6864
|
// src/core/islandManifest.ts
|
|
6284
|
-
var toIslandFrameworkSegment = (framework) => framework[0]?.toUpperCase() + framework.slice(1), getIslandManifestKey = (framework,
|
|
6865
|
+
var toIslandFrameworkSegment = (framework) => framework[0]?.toUpperCase() + framework.slice(1), getIslandManifestKey = (framework, component2) => `Island${toIslandFrameworkSegment(framework)}${component2}`;
|
|
6285
6866
|
|
|
6286
6867
|
// src/core/islands.ts
|
|
6287
|
-
var isRecord4 = (value) => typeof value === "object" && value !== null, getIslandBuildReference = (
|
|
6288
|
-
if (!isIslandComponentDefinition(
|
|
6868
|
+
var isRecord4 = (value) => typeof value === "object" && value !== null, getIslandBuildReference = (component2) => {
|
|
6869
|
+
if (!isIslandComponentDefinition(component2))
|
|
6289
6870
|
return null;
|
|
6290
6871
|
return {
|
|
6291
|
-
export:
|
|
6292
|
-
source:
|
|
6872
|
+
export: component2.export,
|
|
6873
|
+
source: component2.source
|
|
6293
6874
|
};
|
|
6294
6875
|
}, isIslandComponentDefinition = (value) => isRecord4(value) && ("component" in value) && ("source" in value) && typeof value.source === "string";
|
|
6295
6876
|
var init_islands = () => {};
|
|
6296
6877
|
|
|
6297
6878
|
// src/build/islandEntries.ts
|
|
6298
|
-
import { dirname as
|
|
6879
|
+
import { dirname as dirname10, extname, join as join18, relative as relative9, resolve as resolve13 } from "path";
|
|
6299
6880
|
import ts from "typescript";
|
|
6300
6881
|
var frameworks, isRecord5 = (value) => typeof value === "object" && value !== null, resolveRegistryExport = (mod) => {
|
|
6301
6882
|
if (isRecord5(mod.islandRegistry))
|
|
@@ -6307,7 +6888,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6307
6888
|
if (sourcePath.startsWith("file://")) {
|
|
6308
6889
|
return new URL(sourcePath).pathname;
|
|
6309
6890
|
}
|
|
6310
|
-
return
|
|
6891
|
+
return resolve13(dirname10(registryPath), sourcePath);
|
|
6311
6892
|
}, getObjectPropertyName = (name) => {
|
|
6312
6893
|
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
6313
6894
|
return name.text;
|
|
@@ -6350,9 +6931,9 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6350
6931
|
component: reference.source,
|
|
6351
6932
|
export: reference.export,
|
|
6352
6933
|
source: reference.source
|
|
6353
|
-
}), addRegistryEntries = (frameworkNode, framework, imports, definitions,
|
|
6354
|
-
const frameworkRegistry =
|
|
6355
|
-
|
|
6934
|
+
}), addRegistryEntries = (frameworkNode, framework, imports, definitions, registry2) => {
|
|
6935
|
+
const frameworkRegistry = registry2[framework] ?? {};
|
|
6936
|
+
registry2[framework] = frameworkRegistry;
|
|
6356
6937
|
for (const property of frameworkNode.properties) {
|
|
6357
6938
|
if (!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property))
|
|
6358
6939
|
continue;
|
|
@@ -6372,7 +6953,7 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6372
6953
|
framework
|
|
6373
6954
|
});
|
|
6374
6955
|
}
|
|
6375
|
-
}, processDefineIslandRegistry = (node, imports, definitions,
|
|
6956
|
+
}, processDefineIslandRegistry = (node, imports, definitions, registry2) => {
|
|
6376
6957
|
const [firstArg] = node.arguments;
|
|
6377
6958
|
if (!firstArg || !ts.isObjectLiteralExpression(firstArg))
|
|
6378
6959
|
return;
|
|
@@ -6393,13 +6974,13 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6393
6974
|
continue;
|
|
6394
6975
|
if (!ts.isObjectLiteralExpression(property.initializer))
|
|
6395
6976
|
continue;
|
|
6396
|
-
addRegistryEntries(property.initializer, framework, imports, definitions,
|
|
6977
|
+
addRegistryEntries(property.initializer, framework, imports, definitions, registry2);
|
|
6397
6978
|
}
|
|
6398
|
-
}, walkRegistryNode = (node, imports, registryFactoryNames, registryNamespaceNames, definitions,
|
|
6979
|
+
}, walkRegistryNode = (node, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2) => {
|
|
6399
6980
|
if (ts.isCallExpression(node) && isDefineIslandRegistryCall(node.expression, registryFactoryNames, registryNamespaceNames)) {
|
|
6400
|
-
processDefineIslandRegistry(node, imports, definitions,
|
|
6981
|
+
processDefineIslandRegistry(node, imports, definitions, registry2);
|
|
6401
6982
|
}
|
|
6402
|
-
ts.forEachChild(node, (child) => walkRegistryNode(child, imports, registryFactoryNames, registryNamespaceNames, definitions,
|
|
6983
|
+
ts.forEachChild(node, (child) => walkRegistryNode(child, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2));
|
|
6403
6984
|
}, isDefineIslandRegistryCall = (expression, registryFactoryNames, registryNamespaceNames) => {
|
|
6404
6985
|
if (ts.isIdentifier(expression)) {
|
|
6405
6986
|
return registryFactoryNames.has(expression.text);
|
|
@@ -6437,34 +7018,34 @@ var frameworks, isRecord5 = (value) => typeof value === "object" && value !== nu
|
|
|
6437
7018
|
const registryFactoryNames = new Set(["defineIslandRegistry"]);
|
|
6438
7019
|
const registryNamespaceNames = new Set;
|
|
6439
7020
|
const definitions = [];
|
|
6440
|
-
const
|
|
7021
|
+
const registry2 = {};
|
|
6441
7022
|
collectImportDeclarations(sourceFile, registryPath, imports, registryFactoryNames, registryNamespaceNames);
|
|
6442
|
-
walkRegistryNode(sourceFile, imports, registryFactoryNames, registryNamespaceNames, definitions,
|
|
7023
|
+
walkRegistryNode(sourceFile, imports, registryFactoryNames, registryNamespaceNames, definitions, registry2);
|
|
6443
7024
|
return {
|
|
6444
7025
|
definitions,
|
|
6445
7026
|
hasNamedExport: hasIslandRegistryNamedExport(sourceFile),
|
|
6446
|
-
registry
|
|
7027
|
+
registry: registry2
|
|
6447
7028
|
};
|
|
6448
7029
|
}, loadDynamicIslandRegistryBuildInfo = async (resolvedRegistryPath) => {
|
|
6449
7030
|
const registryModule = await import(resolvedRegistryPath);
|
|
6450
|
-
const
|
|
7031
|
+
const registry2 = resolveRegistryExport(registryModule);
|
|
6451
7032
|
const definitions = frameworks.flatMap((framework) => {
|
|
6452
|
-
const frameworkRegistry =
|
|
7033
|
+
const frameworkRegistry = registry2[framework];
|
|
6453
7034
|
if (!isRecord5(frameworkRegistry))
|
|
6454
7035
|
return [];
|
|
6455
|
-
return Object.entries(frameworkRegistry).map(([
|
|
7036
|
+
return Object.entries(frameworkRegistry).map(([component2, value]) => ({
|
|
6456
7037
|
buildReference: getIslandBuildReference(value),
|
|
6457
|
-
component,
|
|
7038
|
+
component: component2,
|
|
6458
7039
|
framework
|
|
6459
7040
|
}));
|
|
6460
7041
|
});
|
|
6461
7042
|
return {
|
|
6462
7043
|
definitions,
|
|
6463
7044
|
hasNamedExport: isRecord5(registryModule.islandRegistry),
|
|
6464
|
-
registry
|
|
7045
|
+
registry: registry2
|
|
6465
7046
|
};
|
|
6466
7047
|
}, loadIslandRegistryBuildInfo = async (registryPath) => {
|
|
6467
|
-
const resolvedRegistryPath =
|
|
7048
|
+
const resolvedRegistryPath = resolve13(registryPath);
|
|
6468
7049
|
const registrySource = Bun.file(resolvedRegistryPath);
|
|
6469
7050
|
const registrySourceText = await registrySource.text();
|
|
6470
7051
|
const parsedInfo = parseIslandRegistryBuildInfo(registrySourceText, resolvedRegistryPath);
|
|
@@ -6998,7 +7579,7 @@ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-
|
|
|
6998
7579
|
// src/mobile/buildRelease.ts
|
|
6999
7580
|
import { createHash as createHash9 } from "crypto";
|
|
7000
7581
|
import { mkdir as mkdir8, readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
|
|
7001
|
-
import { basename as basename7, dirname as
|
|
7582
|
+
import { basename as basename7, dirname as dirname11, extname as extname3, join as join19, relative as relative10, resolve as resolve14 } from "path";
|
|
7002
7583
|
var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATIC_SCRIPT_PATTERN, rewriteStaticScriptPaths = (source, manifest) => source.replace(STATIC_SCRIPT_PATTERN, (match, prefix, path, suffix) => {
|
|
7003
7584
|
if (path.endsWith("/htmx.min.js"))
|
|
7004
7585
|
return match;
|
|
@@ -7006,12 +7587,12 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
|
|
|
7006
7587
|
const builtPath = manifest[key];
|
|
7007
7588
|
return builtPath ? `${prefix}${builtPath}${suffix}` : match;
|
|
7008
7589
|
}), readPageMetadata = (route) => parseAbsoluteMobileBuildPageMetadata(route.hooks?.detail?.[ABSOLUTE_MOBILE_ROUTE_DETAIL]), resolveAssetPath = (buildDirectory, assetPath) => {
|
|
7009
|
-
const resolvedBuildDirectory =
|
|
7010
|
-
const resolvedAsset =
|
|
7590
|
+
const resolvedBuildDirectory = resolve14(buildDirectory);
|
|
7591
|
+
const resolvedAsset = resolve14(assetPath);
|
|
7011
7592
|
if (resolvedAsset.startsWith(`${resolvedBuildDirectory}/`)) {
|
|
7012
7593
|
return resolvedAsset;
|
|
7013
7594
|
}
|
|
7014
|
-
return
|
|
7595
|
+
return join19(buildDirectory, assetPath.replace(/^\/+/, ""));
|
|
7015
7596
|
}, pageFor = async (metadata, manifest, buildDirectory) => {
|
|
7016
7597
|
const assetPath = manifest[metadata.bundleKey];
|
|
7017
7598
|
if (!assetPath) {
|
|
@@ -7022,8 +7603,8 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
|
|
|
7022
7603
|
const source = await readFile9(resolvedAssetPath, "utf8");
|
|
7023
7604
|
const rewritten = rewriteStaticScriptPaths(source, manifest);
|
|
7024
7605
|
const documentHash = sha256(new TextEncoder().encode(rewritten));
|
|
7025
|
-
resolvedAssetPath =
|
|
7026
|
-
await mkdir8(
|
|
7606
|
+
resolvedAssetPath = join19(buildDirectory, ".absolutejs", "mobile-pages", `${documentHash}.html`);
|
|
7607
|
+
await mkdir8(dirname11(resolvedAssetPath), { recursive: true });
|
|
7027
7608
|
await writeFile7(resolvedAssetPath, rewritten);
|
|
7028
7609
|
}
|
|
7029
7610
|
const pageAssetKey = metadata.bundleKey.replace(/Index$/u, "");
|
|
@@ -7036,8 +7617,8 @@ var sha256 = (bytes) => createHash9("sha256").update(bytes).digest("hex"), STATI
|
|
|
7036
7617
|
readFile9(resolvedAssetPath),
|
|
7037
7618
|
resolvedStylePath ? readFile9(resolvedStylePath) : undefined
|
|
7038
7619
|
]);
|
|
7039
|
-
const bundlePath = `/${relative10(
|
|
7040
|
-
const styleBundlePath = resolvedStylePath ? `/${relative10(
|
|
7620
|
+
const bundlePath = `/${relative10(resolve14(buildDirectory), resolvedAssetPath).replaceAll("\\", "/")}`;
|
|
7621
|
+
const styleBundlePath = resolvedStylePath ? `/${relative10(resolve14(buildDirectory), resolvedStylePath).replaceAll("\\", "/")}` : undefined;
|
|
7041
7622
|
return {
|
|
7042
7623
|
bundleHash: sha256(bytes),
|
|
7043
7624
|
bundlePath,
|
|
@@ -7200,7 +7781,7 @@ var init_pageProtocol = __esm(() => {
|
|
|
7200
7781
|
|
|
7201
7782
|
// src/mobile/client.ts
|
|
7202
7783
|
var frameworks5, upgradeReasons;
|
|
7203
|
-
var
|
|
7784
|
+
var init_client2 = __esm(() => {
|
|
7204
7785
|
init_pageProtocol();
|
|
7205
7786
|
frameworks5 = new Set([
|
|
7206
7787
|
"angular",
|
|
@@ -7222,7 +7803,7 @@ var init_client = __esm(() => {
|
|
|
7222
7803
|
// src/mobile/transport.ts
|
|
7223
7804
|
var ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT = 1;
|
|
7224
7805
|
var init_transport = __esm(() => {
|
|
7225
|
-
|
|
7806
|
+
init_client2();
|
|
7226
7807
|
init_pageProtocol();
|
|
7227
7808
|
init_routeMatcher();
|
|
7228
7809
|
});
|
|
@@ -7239,34 +7820,39 @@ import {
|
|
|
7239
7820
|
writeFile as writeFile8
|
|
7240
7821
|
} from "fs/promises";
|
|
7241
7822
|
import { existsSync as existsSync9 } from "fs";
|
|
7242
|
-
import { basename as basename8, dirname as
|
|
7823
|
+
import { basename as basename8, dirname as dirname12, extname as extname4, join as join20, relative as relative11, resolve as resolve15 } from "path";
|
|
7243
7824
|
var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-mobile-bootstrap.js", INDEX_FILE = "index.html", CLIENT_CSS_DEPENDENCY_PATTERN, CLIENT_MARKUP_DEPENDENCY_PATTERN, CAPACITOR_CLIENT_FRAMEWORKS, CLIENT_ASSET_DIRECTORIES, errorHasCode = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code, shellBootstrapModule = () => {
|
|
7244
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7825
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellBootstrap.${extension}`)).find(existsSync9);
|
|
7245
7826
|
if (candidate)
|
|
7246
7827
|
return candidate;
|
|
7247
7828
|
throw new TypeError("AbsoluteJS mobile shell bootstrap module is missing.");
|
|
7248
7829
|
}, shellAuthModule = () => {
|
|
7249
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7830
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellAuth.${extension}`)).find(existsSync9);
|
|
7250
7831
|
if (candidate)
|
|
7251
7832
|
return candidate;
|
|
7252
7833
|
throw new TypeError("AbsoluteJS mobile auth shell module is missing.");
|
|
7253
7834
|
}, shellExpoAuthModule = () => {
|
|
7254
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7835
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoAuth.${extension}`)).find(existsSync9);
|
|
7255
7836
|
if (candidate)
|
|
7256
7837
|
return candidate;
|
|
7257
7838
|
throw new TypeError("AbsoluteJS Expo auth bridge module is missing.");
|
|
7258
7839
|
}, shellSyncModule = () => {
|
|
7259
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7840
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellSync.${extension}`)).find(existsSync9);
|
|
7260
7841
|
if (candidate)
|
|
7261
7842
|
return candidate;
|
|
7262
7843
|
throw new TypeError("AbsoluteJS mobile Sync shell module is missing.");
|
|
7844
|
+
}, shellExpoSyncModule = () => {
|
|
7845
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoSync.${extension}`)).find(existsSync9);
|
|
7846
|
+
if (candidate)
|
|
7847
|
+
return candidate;
|
|
7848
|
+
throw new TypeError("AbsoluteJS Expo Sync bridge module is missing.");
|
|
7263
7849
|
}, shellPushModule = () => {
|
|
7264
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7850
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellPush.${extension}`)).find(existsSync9);
|
|
7265
7851
|
if (candidate)
|
|
7266
7852
|
return candidate;
|
|
7267
7853
|
throw new TypeError("AbsoluteJS mobile push shell module is missing.");
|
|
7268
7854
|
}, shellExpoDevicesModule = () => {
|
|
7269
|
-
const candidate = ["js", "ts"].map((extension) =>
|
|
7855
|
+
const candidate = ["js", "ts"].map((extension) => join20(import.meta.dir, `shellExpoDevices.${extension}`)).find(existsSync9);
|
|
7270
7856
|
if (candidate)
|
|
7271
7857
|
return candidate;
|
|
7272
7858
|
throw new TypeError("AbsoluteJS Expo device bridge module is missing.");
|
|
@@ -7297,8 +7883,8 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
|
|
|
7297
7883
|
</body>
|
|
7298
7884
|
</html>
|
|
7299
7885
|
`, sourceAssetPath = (buildDirectory, bundlePath) => {
|
|
7300
|
-
const root =
|
|
7301
|
-
const asset =
|
|
7886
|
+
const root = resolve15(buildDirectory);
|
|
7887
|
+
const asset = resolve15(root, bundlePath.replace(/^\/+/, ""));
|
|
7302
7888
|
if (!asset.startsWith(`${root}/`)) {
|
|
7303
7889
|
throw new TypeError("Mobile page bundle escaped the build directory.");
|
|
7304
7890
|
}
|
|
@@ -7313,15 +7899,15 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
|
|
|
7313
7899
|
const segments = specifier.split("/");
|
|
7314
7900
|
const packageName = specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? "";
|
|
7315
7901
|
const subpath = specifier.slice(packageName.length);
|
|
7316
|
-
const packageDirectory =
|
|
7317
|
-
const manifest = JSON.parse(await readFile10(
|
|
7902
|
+
const packageDirectory = join20(resolve15(projectRoot), "node_modules", packageName);
|
|
7903
|
+
const manifest = JSON.parse(await readFile10(join20(packageDirectory, "package.json"), "utf8"));
|
|
7318
7904
|
const exports = typeof manifest === "object" && manifest !== null ? Reflect.get(manifest, "exports") : undefined;
|
|
7319
7905
|
const entry = typeof exports === "object" && exports !== null ? Reflect.get(exports, subpath ? `.${subpath}` : ".") : undefined;
|
|
7320
7906
|
const target = importEntryTarget(entry);
|
|
7321
7907
|
if (typeof target !== "string" || !target.startsWith("./"))
|
|
7322
7908
|
throw new TypeError(`${specifier} does not publish an import entry.`);
|
|
7323
|
-
const resolved =
|
|
7324
|
-
if (!resolved.startsWith(`${
|
|
7909
|
+
const resolved = resolve15(packageDirectory, target);
|
|
7910
|
+
if (!resolved.startsWith(`${resolve15(packageDirectory)}/`))
|
|
7325
7911
|
throw new TypeError(`${specifier} has an unsafe import entry.`);
|
|
7326
7912
|
return resolved;
|
|
7327
7913
|
}, buildShellBootstrap = async (staging, auth, sync, storagePrefix, engine, deviceCapabilities, projectRoot) => {
|
|
@@ -7329,10 +7915,11 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
|
|
|
7329
7915
|
const shellCapabilities = capacitor ? deviceCapabilities.capabilities : [];
|
|
7330
7916
|
const modulePath = shellBootstrapModule();
|
|
7331
7917
|
const authFactory = capacitor ? "createAbsoluteMobileShellAuth" : "createAbsoluteExpoShellAuth";
|
|
7918
|
+
const syncFactory = capacitor ? "installAbsoluteMobileShellSync" : "installAbsoluteExpoShellSync";
|
|
7332
7919
|
const authImport = auth ? `import { ${authFactory} } from ${JSON.stringify(capacitor ? shellAuthModule() : shellExpoAuthModule())};
|
|
7333
7920
|
` : "";
|
|
7334
|
-
const options = auth ? `{ createAuth: ${authFactory}${sync ?
|
|
7335
|
-
const syncImport = sync ? `import {
|
|
7921
|
+
const options = auth ? `{ createAuth: ${authFactory}${sync ? `, installSync: ${syncFactory}` : ""} }` : "";
|
|
7922
|
+
const syncImport = sync ? `import { ${syncFactory} } from ${JSON.stringify(capacitor ? shellSyncModule() : shellExpoSyncModule())};
|
|
7336
7923
|
` : "";
|
|
7337
7924
|
const pushIndex = shellCapabilities.indexOf("pushNotifications");
|
|
7338
7925
|
const push = pushIndex !== -1;
|
|
@@ -7341,778 +7928,356 @@ var MANIFEST_FILE = "absolute-mobile-manifest.json", BOOTSTRAP_FILE = "absolute-
|
|
|
7341
7928
|
const capabilityImports = (await Promise.all(shellCapabilities.map(async (name, index) => {
|
|
7342
7929
|
const provider = deviceCapabilities.providers[name];
|
|
7343
7930
|
if (!provider)
|
|
7344
|
-
throw new TypeError(`Missing device capability provider ${name}.`);
|
|
7345
|
-
return `import { ${provider.factory} as absoluteDeviceCapability${index} } from ${JSON.stringify(await resolveProjectImport(projectRoot, provider.module))};`;
|
|
7346
|
-
}))).join(`
|
|
7347
|
-
`);
|
|
7348
|
-
const pushSetup = push ? `const absoluteMobilePush = createAbsoluteMobileShellPush();
|
|
7349
|
-
const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absoluteMobilePush.capabilityOptions);
|
|
7350
|
-
` : "";
|
|
7351
|
-
const capabilityOptions = shellCapabilities.map((name, index) => `${JSON.stringify(name)}: ${name === "pushNotifications" ? "absoluteMobilePushCapability" : `absoluteDeviceCapability${index}()`}`).join(", ");
|
|
7352
|
-
const entryPath =
|
|
7353
|
-
const baseAdapterModule = capacitor ? await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor") : shellExpoDevicesModule();
|
|
7354
|
-
const adapterImport = capacitor ? `import { installCapacitorDeviceAdapterIfNative } from ${JSON.stringify(baseAdapterModule)};` : `import { createAbsoluteExpoBridgeFetch, installAbsoluteExpoWebDeviceAdapter } from ${JSON.stringify(baseAdapterModule)};`;
|
|
7355
|
-
const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : "installAbsoluteExpoWebDeviceAdapter();";
|
|
7356
|
-
let shellOptions = auth ? options : "{ createFetch: createAbsoluteExpoBridgeFetch }";
|
|
7357
|
-
if (capacitor)
|
|
7358
|
-
shellOptions = options;
|
|
7359
|
-
if (push) {
|
|
7360
|
-
shellOptions = `{ createAuth: (config, options) => createAbsoluteMobileShellAuth(config, options), beforeSignOut: absoluteMobilePush.beforeSignOut, connectPush: (auth) => absoluteMobilePush.connect(auth, absoluteMobilePushCapability)${sync ?
|
|
7361
|
-
}
|
|
7362
|
-
await writeFile8(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
|
|
7363
|
-
${adapterImport}
|
|
7364
|
-
${authImport}${syncImport}${pushImport}${capabilityImports}
|
|
7365
|
-
${pushSetup}${adapterInstall}
|
|
7366
|
-
void startAbsoluteMobileShell(${shellOptions});
|
|
7367
|
-
`);
|
|
7368
|
-
const build = await Bun.build({
|
|
7369
|
-
entrypoints: [entryPath],
|
|
7370
|
-
minify: true,
|
|
7371
|
-
outdir: staging,
|
|
7372
|
-
target: "browser"
|
|
7373
|
-
});
|
|
7374
|
-
if (!build.success || build.outputs.length !== 1) {
|
|
7375
|
-
throw new AggregateError(build.logs, "Failed to build the AbsoluteJS Capacitor shell.");
|
|
7376
|
-
}
|
|
7377
|
-
await rename7(build.outputs[0]?.path ?? "", join19(staging, BOOTSTRAP_FILE));
|
|
7378
|
-
await rm6(entryPath, { force: true });
|
|
7379
|
-
}, removePreviousBundle = async (backup, moved) => {
|
|
7380
|
-
if (!moved)
|
|
7381
|
-
return;
|
|
7382
|
-
await rm6(backup, { force: true, recursive: true });
|
|
7383
|
-
}, restorePreviousBundle = async (backup, destination, moved) => {
|
|
7384
|
-
if (!moved)
|
|
7385
|
-
return;
|
|
7386
|
-
await rename7(backup, destination);
|
|
7387
|
-
}, installBundle = async (staging, destination) => {
|
|
7388
|
-
const backup = `${destination}.previous-${crypto.randomUUID()}`;
|
|
7389
|
-
let movedPrevious = false;
|
|
7390
|
-
try {
|
|
7391
|
-
await rename7(destination, backup);
|
|
7392
|
-
movedPrevious = true;
|
|
7393
|
-
} catch (error) {
|
|
7394
|
-
if (!errorHasCode(error, "ENOENT"))
|
|
7395
|
-
throw error;
|
|
7396
|
-
}
|
|
7397
|
-
try {
|
|
7398
|
-
await rename7(staging, destination);
|
|
7399
|
-
await removePreviousBundle(backup, movedPrevious);
|
|
7400
|
-
} catch (error) {
|
|
7401
|
-
await restorePreviousBundle(backup, destination, movedPrevious);
|
|
7402
|
-
throw error;
|
|
7403
|
-
}
|
|
7404
|
-
}, copyClientPage = async (page, buildDirectory, staging, copiedDependencies) => {
|
|
7405
|
-
if (!CAPACITOR_CLIENT_FRAMEWORKS.has(page.framework)) {
|
|
7406
|
-
throw new TypeError(`Capacitor client rendering does not yet support ${page.framework} page ${page.pageId}.`);
|
|
7407
|
-
}
|
|
7408
|
-
const extension = extname4(page.bundlePath) || ".js";
|
|
7409
|
-
const localBundlePath = `./pages/${page.bundleHash}${extension}`;
|
|
7410
|
-
const source = sourceAssetPath(buildDirectory, page.bundlePath);
|
|
7411
|
-
await copyFile4(source, join19(staging, localBundlePath));
|
|
7412
|
-
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copiedDependencies);
|
|
7413
|
-
let localStylePath;
|
|
7414
|
-
if (page.styleBundlePath && page.styleBundleHash) {
|
|
7415
|
-
const styleExtension = extname4(page.styleBundlePath) || ".css";
|
|
7416
|
-
localStylePath = `./styles/${page.styleBundleHash}${styleExtension}`;
|
|
7417
|
-
const styleSource = sourceAssetPath(buildDirectory, page.styleBundlePath);
|
|
7418
|
-
await mkdir9(dirname11(join19(staging, localStylePath)), {
|
|
7419
|
-
recursive: true
|
|
7420
|
-
});
|
|
7421
|
-
await copyFile4(styleSource, join19(staging, localStylePath));
|
|
7422
|
-
await copyAbsoluteClientDependencies(styleSource, buildDirectory, staging, copiedDependencies);
|
|
7423
|
-
}
|
|
7424
|
-
return {
|
|
7425
|
-
...page,
|
|
7426
|
-
localBundlePath,
|
|
7427
|
-
...localStylePath ? { localStylePath } : {}
|
|
7428
|
-
};
|
|
7429
|
-
}, absoluteClientImports = async (sourcePath, buildDirectory) => {
|
|
7430
|
-
const source = await readFile10(sourcePath, "utf8");
|
|
7431
|
-
const extension = extname4(sourcePath).toLowerCase();
|
|
7432
|
-
let scriptLoader;
|
|
7433
|
-
if (extension === ".tsx")
|
|
7434
|
-
scriptLoader = "tsx";
|
|
7435
|
-
else if (extension === ".ts")
|
|
7436
|
-
scriptLoader = "ts";
|
|
7437
|
-
else if (extension === ".jsx")
|
|
7438
|
-
scriptLoader = "jsx";
|
|
7439
|
-
else if ([".js", ".mjs", ".cjs"].includes(extension))
|
|
7440
|
-
scriptLoader = "js";
|
|
7441
|
-
const scriptImports = scriptLoader ? new Bun.Transpiler({ loader: scriptLoader }).scanImports(source).map(({ path }) => path) : [];
|
|
7442
|
-
const cssImports = extension === ".css" ? [...source.matchAll(CLIENT_CSS_DEPENDENCY_PATTERN)].flatMap((match) => match[1] ?? []) : [];
|
|
7443
|
-
const markupImports = extension === ".html" ? [...source.matchAll(CLIENT_MARKUP_DEPENDENCY_PATTERN)].flatMap((match) => match[1] ?? []) : [];
|
|
7444
|
-
return [...scriptImports, ...cssImports, ...markupImports].flatMap((specifier) => {
|
|
7445
|
-
if (!specifier)
|
|
7446
|
-
return [];
|
|
7447
|
-
if (!specifier.startsWith("/") && !specifier.startsWith("./") && !specifier.startsWith("../")) {
|
|
7448
|
-
return [];
|
|
7449
|
-
}
|
|
7450
|
-
const clean = specifier.split(/[?#]/u, 1)[0] ?? specifier;
|
|
7451
|
-
if (clean.startsWith("/"))
|
|
7452
|
-
return [clean];
|
|
7453
|
-
const resolved = resolve14(dirname11(sourcePath), clean);
|
|
7454
|
-
const root = resolve14(buildDirectory);
|
|
7455
|
-
const relativePath = relative11(root, resolved).replaceAll("\\", "/");
|
|
7456
|
-
if (relativePath === ".." || relativePath.startsWith("../")) {
|
|
7457
|
-
throw new TypeError(`Mobile client dependency escaped the build directory: ${specifier}`);
|
|
7458
|
-
}
|
|
7459
|
-
return [`/${relativePath}`];
|
|
7460
|
-
});
|
|
7461
|
-
}, copyAbsoluteClientDependency = async (specifier, buildDirectory, staging, copied) => {
|
|
7462
|
-
if (copied.has(specifier))
|
|
7463
|
-
return;
|
|
7464
|
-
copied.add(specifier);
|
|
7465
|
-
const source = sourceAssetPath(buildDirectory, specifier);
|
|
7466
|
-
const destination = join19(staging, specifier.replace(/^\/+/, ""));
|
|
7467
|
-
await mkdir9(dirname11(destination), { recursive: true });
|
|
7468
|
-
await copyFile4(source, destination);
|
|
7469
|
-
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copied);
|
|
7470
|
-
}, copyAbsoluteClientDependencies = async (sourcePath, buildDirectory, staging, copied) => {
|
|
7471
|
-
const dependencies = await absoluteClientImports(sourcePath, buildDirectory);
|
|
7472
|
-
await Promise.all(dependencies.map((specifier) => copyAbsoluteClientDependency(specifier, buildDirectory, staging, copied)));
|
|
7473
|
-
}, materializeAbsoluteCapacitorWebBundle = async (options) => {
|
|
7474
|
-
if (!resolveAbsoluteMobileRoute(options.artifact.routes, new URL(options.config.entry, "https://absolute.invalid").pathname)) {
|
|
7475
|
-
throw new TypeError(`mobile.entry ${options.config.entry} is not a captured mobile page route.`);
|
|
7476
|
-
}
|
|
7477
|
-
const destination = options.config.bundleDirectory;
|
|
7478
|
-
await mkdir9(dirname11(destination), { recursive: true });
|
|
7479
|
-
const staging = await mkdtemp4(join19(dirname11(destination), `.${basename8(destination)}.stage-`));
|
|
7480
|
-
try {
|
|
7481
|
-
const pageDirectory = join19(staging, "pages");
|
|
7482
|
-
await mkdir9(pageDirectory, { recursive: true });
|
|
7483
|
-
await Promise.all(CLIENT_ASSET_DIRECTORIES.map((directory) => ({
|
|
7484
|
-
destination: join19(staging, directory),
|
|
7485
|
-
source: join19(options.buildDirectory, directory)
|
|
7486
|
-
})).filter(({ source }) => existsSync9(source)).map(({ destination: assetDestination, source }) => cp3(source, assetDestination, { recursive: true })));
|
|
7487
|
-
const copiedDependencies = new Set;
|
|
7488
|
-
const pages = await Promise.all(options.artifact.pages.map((page) => copyClientPage(page, options.buildDirectory, staging, copiedDependencies)));
|
|
7489
|
-
const manifest = {
|
|
7490
|
-
appBuild: options.artifact.appBuild,
|
|
7491
|
-
...options.auth ? { auth: options.auth } : {},
|
|
7492
|
-
appId: options.config.appId,
|
|
7493
|
-
appName: options.config.appName,
|
|
7494
|
-
deepLinkHosts: options.config.deepLinkHosts,
|
|
7495
|
-
deepLinkScheme: options.config.deepLinkScheme,
|
|
7496
|
-
deviceCapabilities: options.deviceCapabilities.capabilities,
|
|
7497
|
-
entry: options.config.entry,
|
|
7498
|
-
format: ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT,
|
|
7499
|
-
pages,
|
|
7500
|
-
productionOrigin: options.config.productionOrigin,
|
|
7501
|
-
routes: options.artifact.routes,
|
|
7502
|
-
runtime: options.artifact.runtime,
|
|
7503
|
-
...options.sync ? {
|
|
7504
|
-
sync: {
|
|
7505
|
-
background: {
|
|
7506
|
-
endpoint: new URL("/__absolute/sync/background", options.config.productionOrigin).href,
|
|
7507
|
-
intervalMinutes: 15
|
|
7508
|
-
},
|
|
7509
|
-
socketTickets: true,
|
|
7510
|
-
storageSchema: options.syncSchema ?? {
|
|
7511
|
-
components: [
|
|
7512
|
-
{ id: "@absolutejs/app", version: 1 }
|
|
7513
|
-
]
|
|
7514
|
-
}
|
|
7515
|
-
}
|
|
7516
|
-
} : {}
|
|
7517
|
-
};
|
|
7518
|
-
await Promise.all([
|
|
7519
|
-
writeFile8(join19(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
7520
|
-
`),
|
|
7521
|
-
writeFile8(join19(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
|
|
7522
|
-
buildShellBootstrap(staging, options.auth !== undefined, options.auth !== undefined && options.sync === true, `absolutejs.${options.auth?.clientId ?? options.config.appId}.`, options.config.engine, options.deviceCapabilities, options.projectRoot)
|
|
7523
|
-
]);
|
|
7524
|
-
await installBundle(staging, destination);
|
|
7525
|
-
return manifest;
|
|
7526
|
-
} catch (error) {
|
|
7527
|
-
await rm6(staging, { force: true, recursive: true });
|
|
7528
|
-
throw error;
|
|
7529
|
-
}
|
|
7530
|
-
};
|
|
7531
|
-
var init_capacitorBundle = __esm(() => {
|
|
7532
|
-
init_routeMatcher();
|
|
7533
|
-
init_transport();
|
|
7534
|
-
CLIENT_CSS_DEPENDENCY_PATTERN = /(?:@import\s+(?:url\(\s*)?|url\(\s*)["']?((?:\/|\.\.\/|\.\/)[^"')\s]+)["']?\s*\)?/gu;
|
|
7535
|
-
CLIENT_MARKUP_DEPENDENCY_PATTERN = /<(?:script\b[^>]*\bsrc|link\b[^>]*\bhref|img\b[^>]*\bsrc|source\b[^>]*\bsrcset)\s*=\s*["']((?:\/|\.\.\/|\.\/)[^"',\s]+)/giu;
|
|
7536
|
-
CAPACITOR_CLIENT_FRAMEWORKS = new Set([
|
|
7537
|
-
"angular",
|
|
7538
|
-
"html",
|
|
7539
|
-
"htmx",
|
|
7540
|
-
"react",
|
|
7541
|
-
"svelte",
|
|
7542
|
-
"vue"
|
|
7543
|
-
]);
|
|
7544
|
-
CLIENT_ASSET_DIRECTORIES = ["assets", "html", "htmx", "indexes"];
|
|
7545
|
-
});
|
|
7546
|
-
|
|
7547
|
-
// src/mobile/artifactStore.ts
|
|
7548
|
-
import { createHash as createHash10 } from "crypto";
|
|
7549
|
-
var DEFAULT_MAX_PRODUCER_BYTES = 134217728, SHA_2562 = "sha256", hashBlob = async (blob) => {
|
|
7550
|
-
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
7551
|
-
return createHash10(SHA_2562).update(bytes).digest("hex");
|
|
7552
|
-
}, verifyAbsoluteMobileCompatibilityProducer = async (release, maxProducerBytes = DEFAULT_MAX_PRODUCER_BYTES) => {
|
|
7553
|
-
const { artifact, producer } = release;
|
|
7554
|
-
if (producer.size !== artifact.producer.bytes || producer.size > maxProducerBytes) {
|
|
7555
|
-
throw new TypeError("Mobile compatibility producer size does not match its artifact.");
|
|
7556
|
-
}
|
|
7557
|
-
if (await hashBlob(producer) !== artifact.producer.bundleHash) {
|
|
7558
|
-
throw new TypeError("Mobile compatibility producer hash does not match its artifact.");
|
|
7559
|
-
}
|
|
7560
|
-
return release;
|
|
7561
|
-
};
|
|
7562
|
-
var init_artifactStore = __esm(() => {
|
|
7563
|
-
init_releaseArtifact();
|
|
7564
|
-
});
|
|
7565
|
-
|
|
7566
|
-
// src/mobile/materializedBundle.ts
|
|
7567
|
-
import { createHash as createHash11 } from "crypto";
|
|
7568
|
-
import {
|
|
7569
|
-
access as access8,
|
|
7570
|
-
mkdir as mkdir10,
|
|
7571
|
-
mkdtemp as mkdtemp5,
|
|
7572
|
-
readFile as readFile11,
|
|
7573
|
-
rename as rename8,
|
|
7574
|
-
rm as rm7,
|
|
7575
|
-
writeFile as writeFile9
|
|
7576
|
-
} from "fs/promises";
|
|
7577
|
-
import { dirname as dirname12, join as join20, resolve as resolvePath3 } from "path";
|
|
7578
|
-
var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "current.json", BUNDLES_DIRECTORY = "bundles", ARTIFACT_FILE = "artifact.json", BUNDLE_ID_PATTERN, isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), errorHasCode2 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code, bundleIdFor = (currentReleaseId, releases) => {
|
|
7579
|
-
const identity = JSON.stringify({
|
|
7580
|
-
currentReleaseId,
|
|
7581
|
-
releases: releases.map(({ releaseId }) => releaseId)
|
|
7582
|
-
});
|
|
7583
|
-
return `amb_${createHash11("sha256").update(identity).digest("hex")}`;
|
|
7584
|
-
}, parseBundleIndex = (value) => {
|
|
7585
|
-
if (!isRecord7(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)) {
|
|
7586
|
-
throw new TypeError("Invalid materialized mobile compatibility bundle.");
|
|
7587
|
-
}
|
|
7588
|
-
const releases = value.releases.map(parseAbsoluteMobileCompatibilityArtifact);
|
|
7589
|
-
const retained = retainAbsoluteMobileCompatibilityArtifacts(releases);
|
|
7590
|
-
if (retained.length !== releases.length || retained.some(({ releaseId }, index) => releaseId !== releases[index]?.releaseId)) {
|
|
7591
|
-
throw new TypeError("Materialized mobile bundle releases are not a retained generation window.");
|
|
7592
|
-
}
|
|
7593
|
-
const expectedBundleId = bundleIdFor(value.currentReleaseId, releases);
|
|
7594
|
-
if (value.bundleId !== expectedBundleId) {
|
|
7595
|
-
throw new TypeError("Materialized mobile bundle integrity failed.");
|
|
7931
|
+
throw new TypeError(`Missing device capability provider ${name}.`);
|
|
7932
|
+
return `import { ${provider.factory} as absoluteDeviceCapability${index} } from ${JSON.stringify(await resolveProjectImport(projectRoot, provider.module))};`;
|
|
7933
|
+
}))).join(`
|
|
7934
|
+
`);
|
|
7935
|
+
const pushSetup = push ? `const absoluteMobilePush = createAbsoluteMobileShellPush();
|
|
7936
|
+
const absoluteMobilePushCapability = absoluteDeviceCapability${pushIndex}(absoluteMobilePush.capabilityOptions);
|
|
7937
|
+
` : "";
|
|
7938
|
+
const capabilityOptions = shellCapabilities.map((name, index) => `${JSON.stringify(name)}: ${name === "pushNotifications" ? "absoluteMobilePushCapability" : `absoluteDeviceCapability${index}()`}`).join(", ");
|
|
7939
|
+
const entryPath = join20(staging, ".absolute-mobile-entry.ts");
|
|
7940
|
+
const baseAdapterModule = capacitor ? await resolveProjectImport(projectRoot, "@absolutejs/devices-capacitor") : shellExpoDevicesModule();
|
|
7941
|
+
const adapterImport = capacitor ? `import { installCapacitorDeviceAdapterIfNative } from ${JSON.stringify(baseAdapterModule)};` : `import { createAbsoluteExpoBridgeFetch, installAbsoluteExpoWebDeviceAdapter } from ${JSON.stringify(baseAdapterModule)};`;
|
|
7942
|
+
const adapterInstall = capacitor ? `installCapacitorDeviceAdapterIfNative({ storagePrefix: ${JSON.stringify(storagePrefix)}${capabilityOptions ? `, ${capabilityOptions}` : ""} });` : "installAbsoluteExpoWebDeviceAdapter();";
|
|
7943
|
+
let shellOptions = auth ? options : "{ createFetch: createAbsoluteExpoBridgeFetch }";
|
|
7944
|
+
if (capacitor)
|
|
7945
|
+
shellOptions = options;
|
|
7946
|
+
if (push) {
|
|
7947
|
+
shellOptions = `{ createAuth: (config, options) => createAbsoluteMobileShellAuth(config, options), beforeSignOut: absoluteMobilePush.beforeSignOut, connectPush: (auth) => absoluteMobilePush.connect(auth, absoluteMobilePushCapability)${sync ? `, installSync: ${syncFactory}` : ""} }`;
|
|
7596
7948
|
}
|
|
7597
|
-
|
|
7598
|
-
|
|
7949
|
+
await writeFile8(entryPath, `import { startAbsoluteMobileShell } from ${JSON.stringify(modulePath)};
|
|
7950
|
+
${adapterImport}
|
|
7951
|
+
${authImport}${syncImport}${pushImport}${capabilityImports}
|
|
7952
|
+
${pushSetup}${adapterInstall}
|
|
7953
|
+
void startAbsoluteMobileShell(${shellOptions});
|
|
7954
|
+
`);
|
|
7955
|
+
const build = await Bun.build({
|
|
7956
|
+
entrypoints: [entryPath],
|
|
7957
|
+
minify: true,
|
|
7958
|
+
outdir: staging,
|
|
7959
|
+
target: "browser"
|
|
7960
|
+
});
|
|
7961
|
+
if (!build.success || build.outputs.length !== 1) {
|
|
7962
|
+
throw new AggregateError(build.logs, "Failed to build the AbsoluteJS Capacitor shell.");
|
|
7599
7963
|
}
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
};
|
|
7606
|
-
},
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
await
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
writeFile9(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
|
|
7614
|
-
]);
|
|
7615
|
-
}, installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
|
|
7616
|
-
const destination = join20(bundlesRoot, bundleId);
|
|
7964
|
+
await rename7(build.outputs[0]?.path ?? "", join20(staging, BOOTSTRAP_FILE));
|
|
7965
|
+
await rm6(entryPath, { force: true });
|
|
7966
|
+
}, removePreviousBundle = async (backup, moved) => {
|
|
7967
|
+
if (!moved)
|
|
7968
|
+
return;
|
|
7969
|
+
await rm6(backup, { force: true, recursive: true });
|
|
7970
|
+
}, restorePreviousBundle = async (backup, destination, moved) => {
|
|
7971
|
+
if (!moved)
|
|
7972
|
+
return;
|
|
7973
|
+
await rename7(backup, destination);
|
|
7974
|
+
}, installBundle = async (staging, destination) => {
|
|
7975
|
+
const backup = `${destination}.previous-${crypto.randomUUID()}`;
|
|
7976
|
+
let movedPrevious = false;
|
|
7617
7977
|
try {
|
|
7618
|
-
await
|
|
7619
|
-
|
|
7978
|
+
await rename7(destination, backup);
|
|
7979
|
+
movedPrevious = true;
|
|
7620
7980
|
} catch (error) {
|
|
7621
|
-
if (!
|
|
7981
|
+
if (!errorHasCode(error, "ENOENT"))
|
|
7622
7982
|
throw error;
|
|
7623
7983
|
}
|
|
7624
|
-
const staging = await mkdtemp5(join20(bundlesRoot, ".stage-"));
|
|
7625
7984
|
try {
|
|
7626
|
-
await
|
|
7627
|
-
await
|
|
7985
|
+
await rename7(staging, destination);
|
|
7986
|
+
await removePreviousBundle(backup, movedPrevious);
|
|
7628
7987
|
} catch (error) {
|
|
7629
|
-
await
|
|
7630
|
-
if (errorHasCode2(error, "EEXIST") || errorHasCode2(error, "ENOTEMPTY")) {
|
|
7631
|
-
return destination;
|
|
7632
|
-
}
|
|
7988
|
+
await restorePreviousBundle(backup, destination, movedPrevious);
|
|
7633
7989
|
throw error;
|
|
7634
7990
|
}
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
const artifacts = retainAbsoluteMobileCompatibilityArtifacts(releases.map(({ artifact }) => artifact));
|
|
7639
|
-
if (artifacts.length !== releases.length) {
|
|
7640
|
-
throw new TypeError("Materialization input must already contain only retained releases.");
|
|
7991
|
+
}, copyClientPage = async (page, buildDirectory, staging, copiedDependencies) => {
|
|
7992
|
+
if (!CAPACITOR_CLIENT_FRAMEWORKS.has(page.framework)) {
|
|
7993
|
+
throw new TypeError(`Capacitor client rendering does not yet support ${page.framework} page ${page.pageId}.`);
|
|
7641
7994
|
}
|
|
7642
|
-
|
|
7643
|
-
|
|
7995
|
+
const extension = extname4(page.bundlePath) || ".js";
|
|
7996
|
+
const localBundlePath = `./pages/${page.bundleHash}${extension}`;
|
|
7997
|
+
const source = sourceAssetPath(buildDirectory, page.bundlePath);
|
|
7998
|
+
await copyFile4(source, join20(staging, localBundlePath));
|
|
7999
|
+
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copiedDependencies);
|
|
8000
|
+
let localStylePath;
|
|
8001
|
+
if (page.styleBundlePath && page.styleBundleHash) {
|
|
8002
|
+
const styleExtension = extname4(page.styleBundlePath) || ".css";
|
|
8003
|
+
localStylePath = `./styles/${page.styleBundleHash}${styleExtension}`;
|
|
8004
|
+
const styleSource = sourceAssetPath(buildDirectory, page.styleBundlePath);
|
|
8005
|
+
await mkdir9(dirname12(join20(staging, localStylePath)), {
|
|
8006
|
+
recursive: true
|
|
8007
|
+
});
|
|
8008
|
+
await copyFile4(styleSource, join20(staging, localStylePath));
|
|
8009
|
+
await copyAbsoluteClientDependencies(styleSource, buildDirectory, staging, copiedDependencies);
|
|
7644
8010
|
}
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
}
|
|
7650
|
-
return release;
|
|
7651
|
-
});
|
|
7652
|
-
const root = resolvePath3(input.root);
|
|
7653
|
-
const bundlesRoot = join20(root, BUNDLES_DIRECTORY);
|
|
7654
|
-
await mkdir10(bundlesRoot, { recursive: true });
|
|
7655
|
-
const bundleId = bundleIdFor(input.currentReleaseId, artifacts);
|
|
7656
|
-
await installImmutableBundle(bundlesRoot, bundleId, orderedReleases);
|
|
7657
|
-
const index = {
|
|
7658
|
-
bundleId,
|
|
7659
|
-
currentReleaseId: input.currentReleaseId,
|
|
7660
|
-
format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
|
|
7661
|
-
releases: artifacts
|
|
8011
|
+
return {
|
|
8012
|
+
...page,
|
|
8013
|
+
localBundlePath,
|
|
8014
|
+
...localStylePath ? { localStylePath } : {}
|
|
7662
8015
|
};
|
|
7663
|
-
|
|
7664
|
-
const
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
return
|
|
7683
|
-
}));
|
|
7684
|
-
} catch (error) {
|
|
7685
|
-
if (errorHasCode2(error, "ENOENT"))
|
|
7686
|
-
return [];
|
|
7687
|
-
throw error;
|
|
7688
|
-
}
|
|
7689
|
-
};
|
|
7690
|
-
var init_materializedBundle = __esm(() => {
|
|
7691
|
-
init_artifactStore();
|
|
7692
|
-
init_releaseArtifact();
|
|
7693
|
-
BUNDLE_ID_PATTERN = /^amb_[a-f0-9]{64}$/;
|
|
7694
|
-
});
|
|
7695
|
-
|
|
7696
|
-
// node_modules/@absolutejs/sync/dist/client/index.js
|
|
7697
|
-
var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")) && Array.isArray(Reflect.get(value, "clients")), registry, SyncLocalDataPolicyError, SyncLocalStoreSchemaError, positiveVersion = (value, label) => {
|
|
7698
|
-
if (!Number.isSafeInteger(value) || value < 1)
|
|
7699
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", `${label} must be a positive safe integer`);
|
|
7700
|
-
return value;
|
|
7701
|
-
}, isSchemaBundle = (schema) => ("components" in schema), validatePolicyMatch = (match, label) => {
|
|
7702
|
-
if (match.length === 0 || match.trim() !== match || /^\*+$/.test(match) || match.includes("**"))
|
|
7703
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.match must be an exact name or a non-empty glob without adjacent wildcards.`);
|
|
7704
|
-
}, validateSyncLocalDataPolicy = (policy, label = "localData") => {
|
|
7705
|
-
if (policy.maxBytesPerNamespace !== undefined && (!Number.isSafeInteger(policy.maxBytesPerNamespace) || policy.maxBytesPerNamespace < 1))
|
|
7706
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.maxBytesPerNamespace must be a positive safe integer.`);
|
|
7707
|
-
for (const [index, rule] of (policy.collections ?? []).entries()) {
|
|
7708
|
-
validatePolicyMatch(rule.match, `${label}.collections[${index}]`);
|
|
7709
|
-
if (rule.maxAgeMs !== undefined && (!Number.isSafeInteger(rule.maxAgeMs) || rule.maxAgeMs < 1))
|
|
7710
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}].maxAgeMs must be a positive safe integer.`);
|
|
7711
|
-
if (rule.persistence === "memory-only" && rule.protection === "required")
|
|
7712
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] cannot require at-rest protection when it is memory-only.`);
|
|
7713
|
-
if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
|
|
7714
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] declares ${rule.sensitivity} data without required protection or memory-only persistence.`);
|
|
7715
|
-
}
|
|
7716
|
-
for (const [index, rule] of (policy.mutations ?? []).entries()) {
|
|
7717
|
-
validatePolicyMatch(rule.match, `${label}.mutations[${index}]`);
|
|
7718
|
-
if (rule.conflict !== undefined && rule.conflict.strategy !== "client-wins" && rule.conflict.strategy !== "manual" && rule.conflict.strategy !== "server-wins")
|
|
7719
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.strategy is invalid.`);
|
|
7720
|
-
if (rule.conflict?.maxAttempts !== undefined && (!Number.isSafeInteger(rule.conflict.maxAttempts) || rule.conflict.maxAttempts < 1))
|
|
7721
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.maxAttempts must be a positive safe integer.`);
|
|
7722
|
-
if (rule.conflict?.maxAttempts !== undefined && rule.conflict.strategy !== "client-wins")
|
|
7723
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}].conflict.maxAttempts is only valid for client-wins.`);
|
|
7724
|
-
if (rule.persistence === "memory-only" && rule.protection === "required")
|
|
7725
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] cannot require at-rest protection when it is memory-only.`);
|
|
7726
|
-
if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
|
|
7727
|
-
throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] declares ${rule.sensitivity} arguments without required protection.`);
|
|
7728
|
-
}
|
|
7729
|
-
return policy;
|
|
7730
|
-
}, normalizeSyncLocalSchemaComponents = (schema = { version: 1 }) => {
|
|
7731
|
-
const components = isSchemaBundle(schema) ? [...schema.components] : [{ ...schema, id: "@absolutejs/app" }];
|
|
7732
|
-
const ids = new Set;
|
|
7733
|
-
for (const component of components) {
|
|
7734
|
-
if (typeof component.id !== "string" || component.id.trim() !== component.id || component.id.length === 0)
|
|
7735
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Sync schema component id must be non-empty and trimmed");
|
|
7736
|
-
if (ids.has(component.id))
|
|
7737
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync schema component "${component.id}" is declared more than once`);
|
|
7738
|
-
ids.add(component.id);
|
|
7739
|
-
if (component.localData)
|
|
7740
|
-
validateSyncLocalDataPolicy(component.localData, `${component.id}.localData`);
|
|
7741
|
-
}
|
|
7742
|
-
return components.sort((a, b) => a.id.localeCompare(b.id));
|
|
7743
|
-
}, resolveSyncLocalSchemaComponents = (storedVersions, schema = { version: 1 }) => {
|
|
7744
|
-
const components = normalizeSyncLocalSchemaComponents(schema).map((component) => {
|
|
7745
|
-
const current = resolveSyncLocalMigrations(component.version, component);
|
|
7746
|
-
return {
|
|
7747
|
-
id: component.id,
|
|
7748
|
-
...resolveSyncLocalMigrations(storedVersions[component.id] ?? current.minimumCompatibleVersion, component)
|
|
7749
|
-
};
|
|
7750
|
-
});
|
|
7751
|
-
const active = new Set(components.map((component) => component.id));
|
|
7752
|
-
const orphanedComponents = Object.keys(storedVersions).filter((id) => !active.has(id)).sort();
|
|
7753
|
-
return { components, orphanedComponents };
|
|
7754
|
-
}, resolveSyncLocalMigrations = (storedVersion, schema = { version: 1 }) => {
|
|
7755
|
-
positiveVersion(storedVersion, "Stored Sync schema version");
|
|
7756
|
-
const targetVersion = positiveVersion(schema.version, "Target Sync schema version");
|
|
7757
|
-
const migrations = [...schema.migrations ?? []].sort((a, b) => a.toVersion - b.toVersion);
|
|
7758
|
-
const versions = new Set;
|
|
7759
|
-
for (const migration of migrations) {
|
|
7760
|
-
positiveVersion(migration.toVersion, "Sync migration toVersion");
|
|
7761
|
-
if (versions.has(migration.toVersion))
|
|
7762
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync migration ${migration.toVersion} is declared more than once`);
|
|
7763
|
-
versions.add(migration.toVersion);
|
|
7764
|
-
}
|
|
7765
|
-
const inferredMinimum = migrations[0] ? migrations[0].toVersion - 1 : targetVersion;
|
|
7766
|
-
const minimumCompatibleVersion = positiveVersion(schema.minimumCompatibleVersion ?? inferredMinimum, "Minimum compatible Sync schema version");
|
|
7767
|
-
if (minimumCompatibleVersion > targetVersion)
|
|
7768
|
-
throw new SyncLocalStoreSchemaError("INVALID_PLAN", "Minimum compatible Sync schema version cannot exceed its target");
|
|
7769
|
-
if (storedVersion > targetVersion)
|
|
7770
|
-
throw new SyncLocalStoreSchemaError("SCHEMA_TOO_NEW", `Stored Sync schema ${storedVersion} is newer than this runtime's schema ${targetVersion}`, { storedVersion, targetVersion });
|
|
7771
|
-
if (storedVersion < minimumCompatibleVersion)
|
|
7772
|
-
throw new SyncLocalStoreSchemaError("SCHEMA_TOO_OLD", `Stored Sync schema ${storedVersion} is older than the minimum compatible schema ${minimumCompatibleVersion}`, { storedVersion, targetVersion });
|
|
7773
|
-
const steps = [];
|
|
7774
|
-
for (let version2 = storedVersion + 1;version2 <= targetVersion; version2++) {
|
|
7775
|
-
const migration = migrations.find((candidate) => candidate.toVersion === version2);
|
|
7776
|
-
if (migration === undefined)
|
|
7777
|
-
throw new SyncLocalStoreSchemaError("MIGRATION_MISSING", `Sync migration ${version2 - 1} -> ${version2} is missing`, { storedVersion, targetVersion });
|
|
7778
|
-
steps.push(migration);
|
|
7779
|
-
}
|
|
7780
|
-
return { minimumCompatibleVersion, steps, targetVersion };
|
|
7781
|
-
};
|
|
7782
|
-
var init_client2 = __esm(() => {
|
|
7783
|
-
RUNTIME_TRANSPORT = Symbol.for("@absolutejs/sync/client-runtime-transport");
|
|
7784
|
-
host = globalThis;
|
|
7785
|
-
registry = (() => {
|
|
7786
|
-
const existing = host[RUNTIME_TRANSPORT];
|
|
7787
|
-
if (isRegistry(existing))
|
|
7788
|
-
return existing;
|
|
7789
|
-
if (typeof existing === "object" && existing !== null && Array.isArray(Reflect.get(existing, "installations"))) {
|
|
7790
|
-
Reflect.set(existing, "clients", []);
|
|
7791
|
-
return existing;
|
|
7792
|
-
}
|
|
7793
|
-
const created = { clients: [], installations: [] };
|
|
7794
|
-
Object.defineProperty(host, RUNTIME_TRANSPORT, {
|
|
7795
|
-
configurable: false,
|
|
7796
|
-
enumerable: false,
|
|
7797
|
-
value: created,
|
|
7798
|
-
writable: false
|
|
7799
|
-
});
|
|
7800
|
-
return created;
|
|
7801
|
-
})();
|
|
7802
|
-
SyncLocalDataPolicyError = class SyncLocalDataPolicyError extends Error {
|
|
7803
|
-
code;
|
|
7804
|
-
constructor(code, message) {
|
|
7805
|
-
super(message);
|
|
7806
|
-
this.name = "SyncLocalDataPolicyError";
|
|
7807
|
-
this.code = code;
|
|
8016
|
+
}, absoluteClientImports = async (sourcePath, buildDirectory) => {
|
|
8017
|
+
const source = await readFile10(sourcePath, "utf8");
|
|
8018
|
+
const extension = extname4(sourcePath).toLowerCase();
|
|
8019
|
+
let scriptLoader;
|
|
8020
|
+
if (extension === ".tsx")
|
|
8021
|
+
scriptLoader = "tsx";
|
|
8022
|
+
else if (extension === ".ts")
|
|
8023
|
+
scriptLoader = "ts";
|
|
8024
|
+
else if (extension === ".jsx")
|
|
8025
|
+
scriptLoader = "jsx";
|
|
8026
|
+
else if ([".js", ".mjs", ".cjs"].includes(extension))
|
|
8027
|
+
scriptLoader = "js";
|
|
8028
|
+
const scriptImports = scriptLoader ? new Bun.Transpiler({ loader: scriptLoader }).scanImports(source).map(({ path }) => path) : [];
|
|
8029
|
+
const cssImports = extension === ".css" ? [...source.matchAll(CLIENT_CSS_DEPENDENCY_PATTERN)].flatMap((match) => match[1] ?? []) : [];
|
|
8030
|
+
const markupImports = extension === ".html" ? [...source.matchAll(CLIENT_MARKUP_DEPENDENCY_PATTERN)].flatMap((match) => match[1] ?? []) : [];
|
|
8031
|
+
return [...scriptImports, ...cssImports, ...markupImports].flatMap((specifier) => {
|
|
8032
|
+
if (!specifier)
|
|
8033
|
+
return [];
|
|
8034
|
+
if (!specifier.startsWith("/") && !specifier.startsWith("./") && !specifier.startsWith("../")) {
|
|
8035
|
+
return [];
|
|
7808
8036
|
}
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
this.code = code;
|
|
7818
|
-
this.storedVersion = versions.storedVersion;
|
|
7819
|
-
this.targetVersion = versions.targetVersion;
|
|
8037
|
+
const clean = specifier.split(/[?#]/u, 1)[0] ?? specifier;
|
|
8038
|
+
if (clean.startsWith("/"))
|
|
8039
|
+
return [clean];
|
|
8040
|
+
const resolved = resolve15(dirname12(sourcePath), clean);
|
|
8041
|
+
const root = resolve15(buildDirectory);
|
|
8042
|
+
const relativePath = relative11(root, resolved).replaceAll("\\", "/");
|
|
8043
|
+
if (relativePath === ".." || relativePath.startsWith("../")) {
|
|
8044
|
+
throw new TypeError(`Mobile client dependency escaped the build directory: ${specifier}`);
|
|
7820
8045
|
}
|
|
7821
|
-
|
|
7822
|
-
});
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
import { readFileSync as readFileSync11 } from "fs";
|
|
7826
|
-
import { dirname as dirname13, join as join21, resolve as resolve15 } from "path";
|
|
7827
|
-
var object = (value) => typeof value === "object" && value !== null && !Array.isArray(value), manifestAt = (path) => {
|
|
7828
|
-
try {
|
|
7829
|
-
const value = JSON.parse(readFileSync11(path, "utf8"));
|
|
7830
|
-
return object(value) ? value : undefined;
|
|
7831
|
-
} catch {
|
|
7832
|
-
return;
|
|
7833
|
-
}
|
|
7834
|
-
}, localSchemaMetadata = (manifest) => {
|
|
7835
|
-
const absolutejs = Reflect.get(manifest, "absolutejs");
|
|
7836
|
-
if (!object(absolutejs))
|
|
7837
|
-
return;
|
|
7838
|
-
const sync = Reflect.get(absolutejs, "sync");
|
|
7839
|
-
if (!object(sync))
|
|
8046
|
+
return [`/${relativePath}`];
|
|
8047
|
+
});
|
|
8048
|
+
}, copyAbsoluteClientDependency = async (specifier, buildDirectory, staging, copied) => {
|
|
8049
|
+
if (copied.has(specifier))
|
|
7840
8050
|
return;
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
8051
|
+
copied.add(specifier);
|
|
8052
|
+
const source = sourceAssetPath(buildDirectory, specifier);
|
|
8053
|
+
const destination = join20(staging, specifier.replace(/^\/+/, ""));
|
|
8054
|
+
await mkdir9(dirname12(destination), { recursive: true });
|
|
8055
|
+
await copyFile4(source, destination);
|
|
8056
|
+
await copyAbsoluteClientDependencies(source, buildDirectory, staging, copied);
|
|
8057
|
+
}, copyAbsoluteClientDependencies = async (sourcePath, buildDirectory, staging, copied) => {
|
|
8058
|
+
const dependencies = await absoluteClientImports(sourcePath, buildDirectory);
|
|
8059
|
+
await Promise.all(dependencies.map((specifier) => copyAbsoluteClientDependency(specifier, buildDirectory, staging, copied)));
|
|
8060
|
+
}, materializeAbsoluteCapacitorWebBundle = async (options) => {
|
|
8061
|
+
if (!resolveAbsoluteMobileRoute(options.artifact.routes, new URL(options.config.entry, "https://absolute.invalid").pathname)) {
|
|
8062
|
+
throw new TypeError(`mobile.entry ${options.config.entry} is not a captured mobile page route.`);
|
|
7853
8063
|
}
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
const field = nonEmpty(Reflect.get(record, "field"), id, `operation ${index}.field`);
|
|
7893
|
-
if (type === "remove-field")
|
|
7894
|
-
return { collection, field, type };
|
|
7895
|
-
if (type === "set-default")
|
|
7896
|
-
return {
|
|
7897
|
-
collection,
|
|
7898
|
-
field,
|
|
7899
|
-
type,
|
|
7900
|
-
value: normalizeJsonValue(Reflect.get(record, "value"), id, `operation ${index}.value`)
|
|
7901
|
-
};
|
|
7902
|
-
throw metadataError(id, `operation ${index}.type is not supported.`);
|
|
7903
|
-
}, migration = (value, id, index) => {
|
|
7904
|
-
const record = requireObject(value, id, `migration ${index} must be an object.`);
|
|
7905
|
-
const allowed = new Set(["operations", "toVersion"]);
|
|
7906
|
-
const unsupported = Object.keys(record).find((key) => !allowed.has(key));
|
|
7907
|
-
if (unsupported)
|
|
7908
|
-
throw metadataError(id, `migration ${index}.${unsupported} is not declarative metadata.`);
|
|
7909
|
-
const declaredOperations = Reflect.get(record, "operations");
|
|
7910
|
-
if (declaredOperations !== undefined && !Array.isArray(declaredOperations))
|
|
7911
|
-
throw metadataError(id, `migration ${index}.operations must be an array.`);
|
|
7912
|
-
const operations = Array.isArray(declaredOperations) ? declaredOperations : [];
|
|
7913
|
-
return {
|
|
7914
|
-
operations: operations.map((entry, operationIndex) => operation(entry, id, operationIndex)),
|
|
7915
|
-
toVersion: positiveVersion2(Reflect.get(record, "toVersion"), id, `migration ${index}.toVersion`)
|
|
7916
|
-
};
|
|
7917
|
-
}, localDataPolicy = (value, id) => {
|
|
7918
|
-
const record = requireObject(value, id, "localData must be an object.");
|
|
7919
|
-
const allowed = new Set([
|
|
7920
|
-
"collections",
|
|
7921
|
-
"maxBytesPerNamespace",
|
|
7922
|
-
"mutations"
|
|
7923
|
-
]);
|
|
7924
|
-
const unsupported = Object.keys(record).find((key) => !allowed.has(key));
|
|
7925
|
-
if (unsupported)
|
|
7926
|
-
throw metadataError(id, `localData.${unsupported} is not supported.`);
|
|
7927
|
-
const collectionRules = Reflect.get(record, "collections");
|
|
7928
|
-
const mutationRules = Reflect.get(record, "mutations");
|
|
7929
|
-
if (collectionRules !== undefined && !Array.isArray(collectionRules))
|
|
7930
|
-
throw metadataError(id, "localData.collections must be an array.");
|
|
7931
|
-
if (mutationRules !== undefined && !Array.isArray(mutationRules))
|
|
7932
|
-
throw metadataError(id, "localData.mutations must be an array.");
|
|
7933
|
-
const collections = Array.isArray(collectionRules) ? collectionRules.map((entry, index) => {
|
|
7934
|
-
const rule = requireObject(entry, id, `localData.collections[${index}] must be an object.`);
|
|
7935
|
-
const allowedRuleKeys = new Set([
|
|
7936
|
-
"evictionPriority",
|
|
7937
|
-
"match",
|
|
7938
|
-
"maxAgeMs",
|
|
7939
|
-
"onProtectionUnavailable",
|
|
7940
|
-
"persistence",
|
|
7941
|
-
"protection",
|
|
7942
|
-
"sensitivity"
|
|
7943
|
-
]);
|
|
7944
|
-
const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
|
|
7945
|
-
if (unsupportedRuleKey)
|
|
7946
|
-
throw metadataError(id, `localData.collections[${index}].${unsupportedRuleKey} is not supported.`);
|
|
7947
|
-
const match = nonEmpty(Reflect.get(rule, "match"), id, `localData.collections[${index}].match`);
|
|
7948
|
-
const persistence = unknownField(rule, "persistence");
|
|
7949
|
-
const sensitivity = unknownField(rule, "sensitivity");
|
|
7950
|
-
const protection = unknownField(rule, "protection");
|
|
7951
|
-
const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
|
|
7952
|
-
const evictionPriority = unknownField(rule, "evictionPriority");
|
|
7953
|
-
const maxAge = unknownField(rule, "maxAgeMs");
|
|
7954
|
-
if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
|
|
7955
|
-
throw metadataError(id, `localData.collections[${index}].persistence is invalid.`);
|
|
7956
|
-
if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
|
|
7957
|
-
throw metadataError(id, `localData.collections[${index}].sensitivity is invalid.`);
|
|
7958
|
-
if (protection !== undefined && protection !== "none" && protection !== "required")
|
|
7959
|
-
throw metadataError(id, `localData.collections[${index}].protection is invalid.`);
|
|
7960
|
-
if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
|
|
7961
|
-
throw metadataError(id, `localData.collections[${index}].onProtectionUnavailable is invalid.`);
|
|
7962
|
-
if (evictionPriority !== undefined && evictionPriority !== "critical" && evictionPriority !== "normal" && evictionPriority !== "disposable")
|
|
7963
|
-
throw metadataError(id, `localData.collections[${index}].evictionPriority is invalid.`);
|
|
7964
|
-
return {
|
|
7965
|
-
match,
|
|
7966
|
-
...sensitivity ? { sensitivity } : {},
|
|
7967
|
-
...persistence ? { persistence } : {},
|
|
7968
|
-
...protection ? { protection } : {},
|
|
7969
|
-
...onProtectionUnavailable ? {
|
|
7970
|
-
onProtectionUnavailable
|
|
7971
|
-
} : {},
|
|
7972
|
-
...evictionPriority ? { evictionPriority } : {},
|
|
7973
|
-
...maxAge === undefined ? {} : {
|
|
7974
|
-
maxAgeMs: positiveVersion2(maxAge, id, `localData.collections[${index}].maxAgeMs`)
|
|
7975
|
-
}
|
|
7976
|
-
};
|
|
7977
|
-
}) : undefined;
|
|
7978
|
-
const mutations = Array.isArray(mutationRules) ? mutationRules.map((entry, index) => {
|
|
7979
|
-
const rule = requireObject(entry, id, `localData.mutations[${index}] must be an object.`);
|
|
7980
|
-
const allowedRuleKeys = new Set([
|
|
7981
|
-
"conflict",
|
|
7982
|
-
"match",
|
|
7983
|
-
"onProtectionUnavailable",
|
|
7984
|
-
"persistence",
|
|
7985
|
-
"protection",
|
|
7986
|
-
"sensitivity"
|
|
7987
|
-
]);
|
|
7988
|
-
const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
|
|
7989
|
-
if (unsupportedRuleKey)
|
|
7990
|
-
throw metadataError(id, `localData.mutations[${index}].${unsupportedRuleKey} is not supported.`);
|
|
7991
|
-
const protection = unknownField(rule, "protection");
|
|
7992
|
-
const sensitivity = unknownField(rule, "sensitivity");
|
|
7993
|
-
const persistence = unknownField(rule, "persistence");
|
|
7994
|
-
const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
|
|
7995
|
-
const declaredConflict = unknownField(rule, "conflict");
|
|
7996
|
-
let conflict;
|
|
7997
|
-
if (declaredConflict !== undefined) {
|
|
7998
|
-
const conflictRecord = requireObject(declaredConflict, id, `localData.mutations[${index}].conflict must be an object.`);
|
|
7999
|
-
const unsupportedConflictKey = Object.keys(conflictRecord).find((key) => key !== "maxAttempts" && key !== "strategy");
|
|
8000
|
-
if (unsupportedConflictKey)
|
|
8001
|
-
throw metadataError(id, `localData.mutations[${index}].conflict.${unsupportedConflictKey} is not supported.`);
|
|
8002
|
-
const strategy = unknownField(conflictRecord, "strategy");
|
|
8003
|
-
if (strategy !== "client-wins" && strategy !== "manual" && strategy !== "server-wins")
|
|
8004
|
-
throw metadataError(id, `localData.mutations[${index}].conflict.strategy is invalid.`);
|
|
8005
|
-
const maxAttempts = unknownField(conflictRecord, "maxAttempts");
|
|
8006
|
-
if (maxAttempts !== undefined && strategy !== "client-wins")
|
|
8007
|
-
throw metadataError(id, `localData.mutations[${index}].conflict.maxAttempts requires client-wins.`);
|
|
8008
|
-
conflict = {
|
|
8009
|
-
strategy,
|
|
8010
|
-
...maxAttempts === undefined ? {} : {
|
|
8011
|
-
maxAttempts: positiveVersion2(maxAttempts, id, `localData.mutations[${index}].conflict.maxAttempts`)
|
|
8064
|
+
const destination = options.config.bundleDirectory;
|
|
8065
|
+
await mkdir9(dirname12(destination), { recursive: true });
|
|
8066
|
+
const staging = await mkdtemp4(join20(dirname12(destination), `.${basename8(destination)}.stage-`));
|
|
8067
|
+
try {
|
|
8068
|
+
const pageDirectory = join20(staging, "pages");
|
|
8069
|
+
await mkdir9(pageDirectory, { recursive: true });
|
|
8070
|
+
await Promise.all(CLIENT_ASSET_DIRECTORIES.map((directory) => ({
|
|
8071
|
+
destination: join20(staging, directory),
|
|
8072
|
+
source: join20(options.buildDirectory, directory)
|
|
8073
|
+
})).filter(({ source }) => existsSync9(source)).map(({ destination: assetDestination, source }) => cp3(source, assetDestination, { recursive: true })));
|
|
8074
|
+
const copiedDependencies = new Set;
|
|
8075
|
+
const pages = await Promise.all(options.artifact.pages.map((page) => copyClientPage(page, options.buildDirectory, staging, copiedDependencies)));
|
|
8076
|
+
const manifest = {
|
|
8077
|
+
appBuild: options.artifact.appBuild,
|
|
8078
|
+
...options.auth ? { auth: options.auth } : {},
|
|
8079
|
+
appId: options.config.appId,
|
|
8080
|
+
appName: options.config.appName,
|
|
8081
|
+
deepLinkHosts: options.config.deepLinkHosts,
|
|
8082
|
+
deepLinkScheme: options.config.deepLinkScheme,
|
|
8083
|
+
deviceCapabilities: options.deviceCapabilities.capabilities,
|
|
8084
|
+
entry: options.config.entry,
|
|
8085
|
+
format: ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT,
|
|
8086
|
+
pages,
|
|
8087
|
+
productionOrigin: options.config.productionOrigin,
|
|
8088
|
+
routes: options.artifact.routes,
|
|
8089
|
+
runtime: options.artifact.runtime,
|
|
8090
|
+
...options.sync ? {
|
|
8091
|
+
sync: {
|
|
8092
|
+
background: {
|
|
8093
|
+
endpoint: new URL("/__absolute/sync/background", options.config.productionOrigin).href,
|
|
8094
|
+
intervalMinutes: 15
|
|
8095
|
+
},
|
|
8096
|
+
socketTickets: true,
|
|
8097
|
+
storageSchema: options.syncSchema ?? {
|
|
8098
|
+
components: [
|
|
8099
|
+
{ id: "@absolutejs/app", version: 1 }
|
|
8100
|
+
]
|
|
8101
|
+
}
|
|
8012
8102
|
}
|
|
8013
|
-
}
|
|
8014
|
-
}
|
|
8015
|
-
if (protection !== undefined && protection !== "none" && protection !== "required")
|
|
8016
|
-
throw metadataError(id, `localData.mutations[${index}].protection is invalid.`);
|
|
8017
|
-
if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
|
|
8018
|
-
throw metadataError(id, `localData.mutations[${index}].sensitivity is invalid.`);
|
|
8019
|
-
if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
|
|
8020
|
-
throw metadataError(id, `localData.mutations[${index}].onProtectionUnavailable is invalid.`);
|
|
8021
|
-
if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
|
|
8022
|
-
throw metadataError(id, `localData.mutations[${index}].persistence is invalid.`);
|
|
8023
|
-
return {
|
|
8024
|
-
match: nonEmpty(Reflect.get(rule, "match"), id, `localData.mutations[${index}].match`),
|
|
8025
|
-
...conflict ? { conflict } : {},
|
|
8026
|
-
...sensitivity ? { sensitivity } : {},
|
|
8027
|
-
...onProtectionUnavailable ? { onProtectionUnavailable } : {},
|
|
8028
|
-
...persistence ? {
|
|
8029
|
-
persistence
|
|
8030
|
-
} : {},
|
|
8031
|
-
...protection ? { protection } : {}
|
|
8103
|
+
} : {}
|
|
8032
8104
|
};
|
|
8033
|
-
|
|
8034
|
-
|
|
8105
|
+
await Promise.all([
|
|
8106
|
+
writeFile8(join20(staging, MANIFEST_FILE), `${JSON.stringify(manifest, null, "\t")}
|
|
8107
|
+
`),
|
|
8108
|
+
writeFile8(join20(staging, INDEX_FILE), indexHtml(options.config.appName, options.config.productionOrigin)),
|
|
8109
|
+
buildShellBootstrap(staging, options.auth !== undefined, options.auth !== undefined && options.sync === true, `absolutejs.${options.auth?.clientId ?? options.config.appId}.`, options.config.engine, options.deviceCapabilities, options.projectRoot)
|
|
8110
|
+
]);
|
|
8111
|
+
await installBundle(staging, destination);
|
|
8112
|
+
return manifest;
|
|
8113
|
+
} catch (error) {
|
|
8114
|
+
await rm6(staging, { force: true, recursive: true });
|
|
8115
|
+
throw error;
|
|
8116
|
+
}
|
|
8117
|
+
};
|
|
8118
|
+
var init_capacitorBundle = __esm(() => {
|
|
8119
|
+
init_routeMatcher();
|
|
8120
|
+
init_transport();
|
|
8121
|
+
CLIENT_CSS_DEPENDENCY_PATTERN = /(?:@import\s+(?:url\(\s*)?|url\(\s*)["']?((?:\/|\.\.\/|\.\/)[^"')\s]+)["']?\s*\)?/gu;
|
|
8122
|
+
CLIENT_MARKUP_DEPENDENCY_PATTERN = /<(?:script\b[^>]*\bsrc|link\b[^>]*\bhref|img\b[^>]*\bsrc|source\b[^>]*\bsrcset)\s*=\s*["']((?:\/|\.\.\/|\.\/)[^"',\s]+)/giu;
|
|
8123
|
+
CAPACITOR_CLIENT_FRAMEWORKS = new Set([
|
|
8124
|
+
"angular",
|
|
8125
|
+
"html",
|
|
8126
|
+
"htmx",
|
|
8127
|
+
"react",
|
|
8128
|
+
"svelte",
|
|
8129
|
+
"vue"
|
|
8130
|
+
]);
|
|
8131
|
+
CLIENT_ASSET_DIRECTORIES = ["assets", "html", "htmx", "indexes"];
|
|
8132
|
+
});
|
|
8133
|
+
|
|
8134
|
+
// src/mobile/artifactStore.ts
|
|
8135
|
+
import { createHash as createHash10 } from "crypto";
|
|
8136
|
+
var DEFAULT_MAX_PRODUCER_BYTES = 134217728, SHA_2562 = "sha256", hashBlob = async (blob) => {
|
|
8137
|
+
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
8138
|
+
return createHash10(SHA_2562).update(bytes).digest("hex");
|
|
8139
|
+
}, verifyAbsoluteMobileCompatibilityProducer = async (release, maxProducerBytes = DEFAULT_MAX_PRODUCER_BYTES) => {
|
|
8140
|
+
const { artifact, producer } = release;
|
|
8141
|
+
if (producer.size !== artifact.producer.bytes || producer.size > maxProducerBytes) {
|
|
8142
|
+
throw new TypeError("Mobile compatibility producer size does not match its artifact.");
|
|
8143
|
+
}
|
|
8144
|
+
if (await hashBlob(producer) !== artifact.producer.bundleHash) {
|
|
8145
|
+
throw new TypeError("Mobile compatibility producer hash does not match its artifact.");
|
|
8146
|
+
}
|
|
8147
|
+
return release;
|
|
8148
|
+
};
|
|
8149
|
+
var init_artifactStore = __esm(() => {
|
|
8150
|
+
init_releaseArtifact();
|
|
8151
|
+
});
|
|
8152
|
+
|
|
8153
|
+
// src/mobile/materializedBundle.ts
|
|
8154
|
+
import { createHash as createHash11 } from "crypto";
|
|
8155
|
+
import {
|
|
8156
|
+
access as access8,
|
|
8157
|
+
mkdir as mkdir10,
|
|
8158
|
+
mkdtemp as mkdtemp5,
|
|
8159
|
+
readFile as readFile11,
|
|
8160
|
+
rename as rename8,
|
|
8161
|
+
rm as rm7,
|
|
8162
|
+
writeFile as writeFile9
|
|
8163
|
+
} from "fs/promises";
|
|
8164
|
+
import { dirname as dirname13, join as join21, resolve as resolvePath3 } from "path";
|
|
8165
|
+
var ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT = 1, CURRENT_BUNDLE_FILE = "current.json", BUNDLES_DIRECTORY = "bundles", ARTIFACT_FILE = "artifact.json", BUNDLE_ID_PATTERN, isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), errorHasCode2 = (error, code) => typeof error === "object" && error !== null && Reflect.get(error, "code") === code, bundleIdFor = (currentReleaseId, releases) => {
|
|
8166
|
+
const identity = JSON.stringify({
|
|
8167
|
+
currentReleaseId,
|
|
8168
|
+
releases: releases.map(({ releaseId }) => releaseId)
|
|
8169
|
+
});
|
|
8170
|
+
return `amb_${createHash11("sha256").update(identity).digest("hex")}`;
|
|
8171
|
+
}, parseBundleIndex = (value) => {
|
|
8172
|
+
if (!isRecord7(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)) {
|
|
8173
|
+
throw new TypeError("Invalid materialized mobile compatibility bundle.");
|
|
8174
|
+
}
|
|
8175
|
+
const releases = value.releases.map(parseAbsoluteMobileCompatibilityArtifact);
|
|
8176
|
+
const retained = retainAbsoluteMobileCompatibilityArtifacts(releases);
|
|
8177
|
+
if (retained.length !== releases.length || retained.some(({ releaseId }, index) => releaseId !== releases[index]?.releaseId)) {
|
|
8178
|
+
throw new TypeError("Materialized mobile bundle releases are not a retained generation window.");
|
|
8179
|
+
}
|
|
8180
|
+
const expectedBundleId = bundleIdFor(value.currentReleaseId, releases);
|
|
8181
|
+
if (value.bundleId !== expectedBundleId) {
|
|
8182
|
+
throw new TypeError("Materialized mobile bundle integrity failed.");
|
|
8183
|
+
}
|
|
8184
|
+
if (releases[0]?.releaseId !== value.currentReleaseId) {
|
|
8185
|
+
throw new TypeError("Materialized mobile bundle current release is not its newest generation.");
|
|
8186
|
+
}
|
|
8035
8187
|
return {
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
}
|
|
8188
|
+
bundleId: value.bundleId,
|
|
8189
|
+
currentReleaseId: value.currentReleaseId,
|
|
8190
|
+
format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
|
|
8191
|
+
releases
|
|
8041
8192
|
};
|
|
8042
|
-
},
|
|
8043
|
-
const
|
|
8044
|
-
const
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
"
|
|
8048
|
-
|
|
8193
|
+
}, writeRelease = async (root, release) => {
|
|
8194
|
+
const directory = join21(root, release.artifact.releaseId);
|
|
8195
|
+
const producerPath = join21(directory, release.artifact.producer.module);
|
|
8196
|
+
await mkdir10(dirname13(producerPath), { recursive: true });
|
|
8197
|
+
await Promise.all([
|
|
8198
|
+
writeFile9(join21(directory, ARTIFACT_FILE), `${JSON.stringify(release.artifact, null, "\t")}
|
|
8199
|
+
`),
|
|
8200
|
+
writeFile9(producerPath, new Uint8Array(await release.producer.arrayBuffer()))
|
|
8049
8201
|
]);
|
|
8050
|
-
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
}
|
|
8068
|
-
|
|
8202
|
+
}, installImmutableBundle = async (bundlesRoot, bundleId, releases) => {
|
|
8203
|
+
const destination = join21(bundlesRoot, bundleId);
|
|
8204
|
+
try {
|
|
8205
|
+
await access8(destination);
|
|
8206
|
+
return destination;
|
|
8207
|
+
} catch (error) {
|
|
8208
|
+
if (!errorHasCode2(error, "ENOENT"))
|
|
8209
|
+
throw error;
|
|
8210
|
+
}
|
|
8211
|
+
const staging = await mkdtemp5(join21(bundlesRoot, ".stage-"));
|
|
8212
|
+
try {
|
|
8213
|
+
await Promise.all(releases.map((release) => writeRelease(staging, release)));
|
|
8214
|
+
await rename8(staging, destination);
|
|
8215
|
+
} catch (error) {
|
|
8216
|
+
await rm7(staging, { force: true, recursive: true });
|
|
8217
|
+
if (errorHasCode2(error, "EEXIST") || errorHasCode2(error, "ENOTEMPTY")) {
|
|
8218
|
+
return destination;
|
|
8219
|
+
}
|
|
8220
|
+
throw error;
|
|
8221
|
+
}
|
|
8222
|
+
return destination;
|
|
8223
|
+
}, materializeAbsoluteMobileCompatibilityBundle = async (input) => {
|
|
8224
|
+
const releases = await Promise.all(input.releases.map((release) => verifyAbsoluteMobileCompatibilityProducer(release)));
|
|
8225
|
+
const artifacts = retainAbsoluteMobileCompatibilityArtifacts(releases.map(({ artifact }) => artifact));
|
|
8226
|
+
if (artifacts.length !== releases.length) {
|
|
8227
|
+
throw new TypeError("Materialization input must already contain only retained releases.");
|
|
8228
|
+
}
|
|
8229
|
+
if (artifacts[0]?.releaseId !== input.currentReleaseId) {
|
|
8230
|
+
throw new TypeError("Materialization current release must be the newest generation.");
|
|
8231
|
+
}
|
|
8232
|
+
const orderedReleases = artifacts.map((artifact) => {
|
|
8233
|
+
const release = releases.find((candidate) => candidate.artifact.releaseId === artifact.releaseId);
|
|
8234
|
+
if (!release) {
|
|
8235
|
+
throw new TypeError("Materialization input is missing a producer.");
|
|
8236
|
+
}
|
|
8237
|
+
return release;
|
|
8238
|
+
});
|
|
8239
|
+
const root = resolvePath3(input.root);
|
|
8240
|
+
const bundlesRoot = join21(root, BUNDLES_DIRECTORY);
|
|
8241
|
+
await mkdir10(bundlesRoot, { recursive: true });
|
|
8242
|
+
const bundleId = bundleIdFor(input.currentReleaseId, artifacts);
|
|
8243
|
+
await installImmutableBundle(bundlesRoot, bundleId, orderedReleases);
|
|
8244
|
+
const index = {
|
|
8245
|
+
bundleId,
|
|
8246
|
+
currentReleaseId: input.currentReleaseId,
|
|
8247
|
+
format: ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
|
|
8248
|
+
releases: artifacts
|
|
8069
8249
|
};
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
const
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
];
|
|
8096
|
-
for (const name of dependencyNames(appManifest)) {
|
|
8097
|
-
const manifestPath = packageManifestPath(projectRoot, name);
|
|
8098
|
-
if (!manifestPath)
|
|
8099
|
-
continue;
|
|
8100
|
-
const manifest = manifestAt(manifestPath);
|
|
8101
|
-
if (!manifest)
|
|
8102
|
-
continue;
|
|
8103
|
-
const metadata = localSchemaMetadata(manifest);
|
|
8104
|
-
if (metadata === undefined)
|
|
8105
|
-
continue;
|
|
8106
|
-
components.push(component(name, metadata));
|
|
8107
|
-
sources.push({ id: name, manifestPath });
|
|
8250
|
+
const pointerPath = join21(root, CURRENT_BUNDLE_FILE);
|
|
8251
|
+
const temporaryPointerPath = join21(root, `.current-${crypto.randomUUID()}.json`);
|
|
8252
|
+
await writeFile9(temporaryPointerPath, `${JSON.stringify(index, null, "\t")}
|
|
8253
|
+
`, { flag: "wx" });
|
|
8254
|
+
await rename8(temporaryPointerPath, pointerPath);
|
|
8255
|
+
return index;
|
|
8256
|
+
}, readAbsoluteMobileMaterializedReleases = async (root) => {
|
|
8257
|
+
const resolvedRoot = resolvePath3(root);
|
|
8258
|
+
try {
|
|
8259
|
+
const serialized = await readFile11(join21(resolvedRoot, CURRENT_BUNDLE_FILE), "utf8");
|
|
8260
|
+
const parsed = JSON.parse(serialized);
|
|
8261
|
+
const index = parseBundleIndex(parsed);
|
|
8262
|
+
const bundleRoot = join21(resolvedRoot, BUNDLES_DIRECTORY, index.bundleId);
|
|
8263
|
+
return Promise.all(index.releases.map(async (artifact) => {
|
|
8264
|
+
const producer = Bun.file(join21(bundleRoot, artifact.releaseId, artifact.producer.module));
|
|
8265
|
+
await verifyAbsoluteMobileCompatibilityProducer({
|
|
8266
|
+
artifact,
|
|
8267
|
+
producer
|
|
8268
|
+
});
|
|
8269
|
+
return { artifact, producer };
|
|
8270
|
+
}));
|
|
8271
|
+
} catch (error) {
|
|
8272
|
+
if (errorHasCode2(error, "ENOENT"))
|
|
8273
|
+
return [];
|
|
8274
|
+
throw error;
|
|
8108
8275
|
}
|
|
8109
|
-
components.sort((left, right) => left.id.localeCompare(right.id));
|
|
8110
|
-
sources.sort((left, right) => left.id.localeCompare(right.id));
|
|
8111
|
-
resolveSyncLocalSchemaComponents({}, { components });
|
|
8112
|
-
return { components, sources };
|
|
8113
8276
|
};
|
|
8114
|
-
var
|
|
8115
|
-
|
|
8277
|
+
var init_materializedBundle = __esm(() => {
|
|
8278
|
+
init_artifactStore();
|
|
8279
|
+
init_releaseArtifact();
|
|
8280
|
+
BUNDLE_ID_PATTERN = /^amb_[a-f0-9]{64}$/;
|
|
8116
8281
|
});
|
|
8117
8282
|
|
|
8118
8283
|
// src/mobile/deviceCapabilities.ts
|
|
@@ -8440,9 +8605,6 @@ var isElysiaApp = (value) => typeof value === "object" && value !== null && type
|
|
|
8440
8605
|
});
|
|
8441
8606
|
const auth = resolveAbsoluteMobileAuthManifest(options.projectRoot, mobile);
|
|
8442
8607
|
const sync = auth !== undefined && projectUsesAbsoluteSync(options.projectRoot);
|
|
8443
|
-
if (mobile.engine === "expo" && sync) {
|
|
8444
|
-
throw new TypeError("Expo mobile Sync is not released yet. Auth and authenticated HTTP are available, but @absolutejs/sync requires @absolutejs/sync-expo for shared durable state.");
|
|
8445
|
-
}
|
|
8446
8608
|
const syncSchema = sync ? discoverAbsoluteSyncSchema(options.projectRoot) : undefined;
|
|
8447
8609
|
const deviceCapabilities = resolveAbsoluteDeviceCapabilityPlan(options.projectRoot);
|
|
8448
8610
|
const usesPush = deviceCapabilities.capabilities.includes("pushNotifications");
|
|
@@ -23054,12 +23216,12 @@ import { spawn as nodeSpawn } from "child_process";
|
|
|
23054
23216
|
import {
|
|
23055
23217
|
createWriteStream,
|
|
23056
23218
|
existsSync as existsSync5,
|
|
23057
|
-
readFileSync as
|
|
23219
|
+
readFileSync as readFileSync9,
|
|
23058
23220
|
rmSync as rmSync2,
|
|
23059
23221
|
writeFileSync as writeFileSync4
|
|
23060
23222
|
} from "fs";
|
|
23061
23223
|
import { tmpdir as tmpdir2 } from "os";
|
|
23062
|
-
import { join as
|
|
23224
|
+
import { join as join16, resolve as resolvePath2 } from "path";
|
|
23063
23225
|
|
|
23064
23226
|
// src/dev/tunnel/client.ts
|
|
23065
23227
|
var RECONNECT_DELAY_MS = 2000;
|
|
@@ -23569,7 +23731,7 @@ init_expoProject();
|
|
|
23569
23731
|
init_iosPhysicalDeviceTransport();
|
|
23570
23732
|
import { spawn } from "child_process";
|
|
23571
23733
|
import { access as access2 } from "fs/promises";
|
|
23572
|
-
import { join as
|
|
23734
|
+
import { join as join8 } from "path";
|
|
23573
23735
|
var METRO_READY_TIMEOUT_MS = 60000;
|
|
23574
23736
|
var PROCESS_CLOSE_TIMEOUT_MS = 2000;
|
|
23575
23737
|
var commandEnvironment = (options) => ({
|
|
@@ -23582,7 +23744,7 @@ var commandEnvironment = (options) => ({
|
|
|
23582
23744
|
...options.metroHost ? { REACT_NATIVE_PACKAGER_HOSTNAME: options.metroHost } : {}
|
|
23583
23745
|
});
|
|
23584
23746
|
var absoluteExpoExecutable = async (project) => {
|
|
23585
|
-
const executable =
|
|
23747
|
+
const executable = join8(project, "node_modules", ".bin", "expo");
|
|
23586
23748
|
try {
|
|
23587
23749
|
await access2(executable);
|
|
23588
23750
|
return executable;
|
|
@@ -23678,18 +23840,18 @@ var stopProcess = async (process2) => {
|
|
|
23678
23840
|
return;
|
|
23679
23841
|
process2.kill("SIGTERM");
|
|
23680
23842
|
await Promise.race([
|
|
23681
|
-
new Promise((
|
|
23682
|
-
new Promise((
|
|
23843
|
+
new Promise((resolve5) => process2.once("exit", () => resolve5())),
|
|
23844
|
+
new Promise((resolve5) => setTimeout(resolve5, PROCESS_CLOSE_TIMEOUT_MS))
|
|
23683
23845
|
]);
|
|
23684
23846
|
if (process2.exitCode === null)
|
|
23685
23847
|
process2.kill("SIGKILL");
|
|
23686
23848
|
};
|
|
23687
|
-
var waitForExit = (process2) => new Promise((
|
|
23849
|
+
var waitForExit = (process2) => new Promise((resolve5) => {
|
|
23688
23850
|
if (process2.exitCode !== null) {
|
|
23689
|
-
|
|
23851
|
+
resolve5(process2.exitCode);
|
|
23690
23852
|
return;
|
|
23691
23853
|
}
|
|
23692
|
-
process2.once("exit", (code) =>
|
|
23854
|
+
process2.once("exit", (code) => resolve5(code ?? 1));
|
|
23693
23855
|
});
|
|
23694
23856
|
var runUtilityCommand = async (run, command, args, options) => {
|
|
23695
23857
|
const child = run(command, args, {
|
|
@@ -23769,9 +23931,9 @@ var startAbsoluteExpoDevSession = async (options) => {
|
|
|
23769
23931
|
}) : undefined;
|
|
23770
23932
|
let metroReady = false;
|
|
23771
23933
|
let resolveMetro;
|
|
23772
|
-
const metroPromise = new Promise((
|
|
23934
|
+
const metroPromise = new Promise((resolve5, reject) => {
|
|
23773
23935
|
if (!metro) {
|
|
23774
|
-
|
|
23936
|
+
resolve5();
|
|
23775
23937
|
return;
|
|
23776
23938
|
}
|
|
23777
23939
|
const timeout = setTimeout(() => {
|
|
@@ -23779,7 +23941,7 @@ var startAbsoluteExpoDevSession = async (options) => {
|
|
|
23779
23941
|
}, METRO_READY_TIMEOUT_MS);
|
|
23780
23942
|
resolveMetro = () => {
|
|
23781
23943
|
clearTimeout(timeout);
|
|
23782
|
-
|
|
23944
|
+
resolve5();
|
|
23783
23945
|
};
|
|
23784
23946
|
metro.once("exit", (code) => {
|
|
23785
23947
|
if (!metroReady) {
|
|
@@ -24237,9 +24399,9 @@ var setupHttpsCert = async (hosts = []) => {
|
|
|
24237
24399
|
await setupCertWithPrompt(ensureDevCert2, setupMkcert2, hosts);
|
|
24238
24400
|
return getDevCertificateAuthorityPath2();
|
|
24239
24401
|
};
|
|
24240
|
-
var mobileReachableHost = (
|
|
24241
|
-
if (
|
|
24242
|
-
return
|
|
24402
|
+
var mobileReachableHost = (host2) => {
|
|
24403
|
+
if (host2 !== "0.0.0.0" && host2 !== "::")
|
|
24404
|
+
return host2;
|
|
24243
24405
|
const address = getLocalIPAddress();
|
|
24244
24406
|
if (address === "localhost") {
|
|
24245
24407
|
throw new Error("No LAN address is available for the selected physical device. Connect this computer to the device network or set dev.host explicitly.");
|
|
@@ -24334,7 +24496,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24334
24496
|
const generated = await writeAbsoluteExpoProject(normalized, {
|
|
24335
24497
|
projectRoot: process.cwd()
|
|
24336
24498
|
});
|
|
24337
|
-
const dependenciesReady = existsSync5(
|
|
24499
|
+
const dependenciesReady = existsSync5(join16(generated.path, "node_modules", "expo", "package.json")) && existsSync5(join16(generated.path, "node_modules", "expo-dev-client", "package.json"));
|
|
24338
24500
|
if (!dependenciesReady) {
|
|
24339
24501
|
const install = await confirmPrompt("Expo development dependencies are missing. Install the pinned SDK 57 development client now?");
|
|
24340
24502
|
if (!install) {
|
|
@@ -24344,7 +24506,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24344
24506
|
cwd: generated.path,
|
|
24345
24507
|
stdio: "inherit"
|
|
24346
24508
|
});
|
|
24347
|
-
const installExit = await new Promise((
|
|
24509
|
+
const installExit = await new Promise((resolve10) => installProcess.once("exit", (code) => resolve10(code ?? 1)));
|
|
24348
24510
|
if (installExit !== 0) {
|
|
24349
24511
|
throw new TypeError(`Expo dependency installation exited with status ${installExit}.`);
|
|
24350
24512
|
}
|
|
@@ -24413,7 +24575,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24413
24575
|
}
|
|
24414
24576
|
}
|
|
24415
24577
|
if (ready) {
|
|
24416
|
-
const nativeDirectory =
|
|
24578
|
+
const nativeDirectory = join16(normalized.nativeProjectDirectory, "android");
|
|
24417
24579
|
let createNativeProject = false;
|
|
24418
24580
|
if (!existsSync5(nativeDirectory)) {
|
|
24419
24581
|
createNativeProject = await confirmPrompt("Create the managed Capacitor Android project now?");
|
|
@@ -24433,7 +24595,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24433
24595
|
if (!remote) {
|
|
24434
24596
|
console.log(cliTag("\x1B[33m", "iOS target skipped. Pair a Mac with `absolute mobile pair mac <name> <user@host>`."));
|
|
24435
24597
|
} else {
|
|
24436
|
-
const nativeDirectory =
|
|
24598
|
+
const nativeDirectory = join16(normalized.nativeProjectDirectory, "ios");
|
|
24437
24599
|
if (!existsSync5(nativeDirectory)) {
|
|
24438
24600
|
console.log(cliTag("\x1B[33m", "The iOS project is missing. Run `absolute mobile init` before remote development."));
|
|
24439
24601
|
} else {
|
|
@@ -24454,7 +24616,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24454
24616
|
}
|
|
24455
24617
|
}
|
|
24456
24618
|
if (ready) {
|
|
24457
|
-
const nativeDirectory =
|
|
24619
|
+
const nativeDirectory = join16(normalized.nativeProjectDirectory, "ios");
|
|
24458
24620
|
let createNativeProject = false;
|
|
24459
24621
|
if (!existsSync5(nativeDirectory)) {
|
|
24460
24622
|
createNativeProject = await confirmPrompt("Create the managed Capacitor iOS project now?");
|
|
@@ -24806,9 +24968,9 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
24806
24968
|
iosDevStart = null;
|
|
24807
24969
|
});
|
|
24808
24970
|
};
|
|
24809
|
-
const absoluteDevOrigin = (
|
|
24971
|
+
const absoluteDevOrigin = (host2) => {
|
|
24810
24972
|
const url = new URL(`${httpsEnabled ? "https" : "http"}://localhost`);
|
|
24811
|
-
url.hostname =
|
|
24973
|
+
url.hostname = host2;
|
|
24812
24974
|
url.port = String(port);
|
|
24813
24975
|
return url.origin;
|
|
24814
24976
|
};
|
|
@@ -25074,8 +25236,8 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
25074
25236
|
});
|
|
25075
25237
|
if (probe && probe.port !== port) {
|
|
25076
25238
|
const { port: nextPort } = probe;
|
|
25077
|
-
const { host } = refreshedDevConfig;
|
|
25078
|
-
const displayHost =
|
|
25239
|
+
const { host: host2 } = refreshedDevConfig;
|
|
25240
|
+
const displayHost = host2 === "0.0.0.0" ? "localhost" : host2;
|
|
25079
25241
|
console.log(cliTag("\x1B[36m", `Port changed in config \u2014 switching to http://${displayHost}:${nextPort}/`));
|
|
25080
25242
|
port = nextPort;
|
|
25081
25243
|
updateLockMetadata(buildDirectory, { port });
|
|
@@ -25090,7 +25252,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
25090
25252
|
for (const name of candidates) {
|
|
25091
25253
|
let text;
|
|
25092
25254
|
try {
|
|
25093
|
-
text =
|
|
25255
|
+
text = readFileSync9(resolvePath2(process.cwd(), name), "utf8");
|
|
25094
25256
|
} catch {
|
|
25095
25257
|
continue;
|
|
25096
25258
|
}
|
|
@@ -25112,7 +25274,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
25112
25274
|
}
|
|
25113
25275
|
return merged;
|
|
25114
25276
|
};
|
|
25115
|
-
const heapPreloadPath =
|
|
25277
|
+
const heapPreloadPath = join16(tmpdir2(), `absolute-heap-${process.pid}.ts`);
|
|
25116
25278
|
let heapSnapshotEnabled = false;
|
|
25117
25279
|
try {
|
|
25118
25280
|
writeFileSync4(heapPreloadPath, DEV_CHILD_PRELOAD);
|
|
@@ -25211,9 +25373,9 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
25211
25373
|
};
|
|
25212
25374
|
try {
|
|
25213
25375
|
const { watch: watch3 } = await import("fs");
|
|
25214
|
-
const { dirname:
|
|
25376
|
+
const { dirname: dirname9 } = await import("path");
|
|
25215
25377
|
const absServerEntry = resolvePath2(serverEntry);
|
|
25216
|
-
const serverEntryDir =
|
|
25378
|
+
const serverEntryDir = dirname9(absServerEntry);
|
|
25217
25379
|
const ROOT_RESTART_DENY = new Set([
|
|
25218
25380
|
"build",
|
|
25219
25381
|
"dist",
|
|
@@ -25245,7 +25407,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
25245
25407
|
if (now - last < 100)
|
|
25246
25408
|
return;
|
|
25247
25409
|
recentlyHandled.set(filename, now);
|
|
25248
|
-
scheduleServerRestart(
|
|
25410
|
+
scheduleServerRestart(join16(serverEntryDir, filename));
|
|
25249
25411
|
};
|
|
25250
25412
|
const recoveryScan = async () => {
|
|
25251
25413
|
let entries;
|
|
@@ -25264,7 +25426,7 @@ var dev = async (serverEntry, configPath2, options = {}) => {
|
|
|
25264
25426
|
continue;
|
|
25265
25427
|
let fileStat;
|
|
25266
25428
|
try {
|
|
25267
|
-
fileStat = statSync(
|
|
25429
|
+
fileStat = statSync(join16(serverEntryDir, entry.name));
|
|
25268
25430
|
} catch {
|
|
25269
25431
|
continue;
|
|
25270
25432
|
}
|
|
@@ -25652,9 +25814,9 @@ init_eslint();
|
|
|
25652
25814
|
init_constants();
|
|
25653
25815
|
init_utils();
|
|
25654
25816
|
import { execSync as execSync2 } from "child_process";
|
|
25655
|
-
import { existsSync as existsSync8, readFileSync as
|
|
25817
|
+
import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
|
|
25656
25818
|
import { arch as arch2, cpus, platform as platform3, totalmem, version } from "os";
|
|
25657
|
-
import { resolve as
|
|
25819
|
+
import { resolve as resolve12 } from "path";
|
|
25658
25820
|
var bold = (str) => `\x1B[1m${str}\x1B[0m`;
|
|
25659
25821
|
var getBinaryVersion = (binary, flag = "--version") => {
|
|
25660
25822
|
try {
|
|
@@ -25674,7 +25836,7 @@ var getPackageVersion = (packageName) => {
|
|
|
25674
25836
|
const pkgPath = __require.resolve(`${packageName}/package.json`, {
|
|
25675
25837
|
paths: [process.cwd()]
|
|
25676
25838
|
});
|
|
25677
|
-
const pkg = JSON.parse(
|
|
25839
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
25678
25840
|
const ver = pkg.version;
|
|
25679
25841
|
return ver;
|
|
25680
25842
|
} catch {
|
|
@@ -25684,8 +25846,8 @@ var getPackageVersion = (packageName) => {
|
|
|
25684
25846
|
var getAbsoluteVersion = () => {
|
|
25685
25847
|
try {
|
|
25686
25848
|
const candidates = [
|
|
25687
|
-
|
|
25688
|
-
|
|
25849
|
+
resolve12(import.meta.dir, "..", "..", "package.json"),
|
|
25850
|
+
resolve12(import.meta.dir, "..", "..", "..", "package.json")
|
|
25689
25851
|
];
|
|
25690
25852
|
const pkgPath = candidates.find((candidate) => existsSync8(candidate));
|
|
25691
25853
|
if (pkgPath)
|
|
@@ -25696,7 +25858,7 @@ var getAbsoluteVersion = () => {
|
|
|
25696
25858
|
return getPackageVersion("@absolutejs/absolute");
|
|
25697
25859
|
};
|
|
25698
25860
|
var readPackageVersion = (pkgPath) => {
|
|
25699
|
-
const pkg = JSON.parse(
|
|
25861
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
|
|
25700
25862
|
const ver = pkg.version;
|
|
25701
25863
|
return ver;
|
|
25702
25864
|
};
|
|
@@ -25798,7 +25960,7 @@ var info = () => {
|
|
|
25798
25960
|
// src/cli/cache.ts
|
|
25799
25961
|
init_constants();
|
|
25800
25962
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
25801
|
-
import { join as
|
|
25963
|
+
import { join as join17 } from "path";
|
|
25802
25964
|
var {Glob } = globalThis.Bun;
|
|
25803
25965
|
var CACHE_DIR = ".absolutejs";
|
|
25804
25966
|
var MAX_FILES_PER_BATCH = 200;
|
|
@@ -25850,7 +26012,7 @@ var hashFiles = async (paths) => {
|
|
|
25850
26012
|
};
|
|
25851
26013
|
var loadCache = async (tool) => {
|
|
25852
26014
|
try {
|
|
25853
|
-
const path =
|
|
26015
|
+
const path = join17(CACHE_DIR, `${tool}.cache.json`);
|
|
25854
26016
|
const data = await Bun.file(path).json();
|
|
25855
26017
|
const result = data;
|
|
25856
26018
|
return result;
|
|
@@ -25897,7 +26059,7 @@ var runTool = async (adapter, args) => {
|
|
|
25897
26059
|
};
|
|
25898
26060
|
var saveCache = async (tool, data) => {
|
|
25899
26061
|
await mkdir7(CACHE_DIR, { recursive: true });
|
|
25900
|
-
const path =
|
|
26062
|
+
const path = join17(CACHE_DIR, `${tool}.cache.json`);
|
|
25901
26063
|
await Bun.write(path, JSON.stringify(data, null, "\t"));
|
|
25902
26064
|
};
|
|
25903
26065
|
|